From 2490251446e13ab0e89d3af1c13cf4d606777728 Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Fri, 22 May 2026 17:34:38 +0200 Subject: [PATCH 01/14] Enlightened Journey initial commit. --- Server/data/configs/npc_spawns.json | 36 +- .../handlers/item/EmptyOptionListener.kt | 3 +- .../content/global/skill/farming/Patch.kt | 4 +- .../content/global/skill/farming/Plantable.kt | 3 +- .../skill/farming/UseWithPatchHandler.kt | 9 +- .../global/skill/farming/timers/CropGrowth.kt | 4 +- .../balloon/BalloonAssistantsDialogue.kt | 67 ++ .../travel/balloon/BalloonCrashSites.kt | 242 +++++ .../travel/balloon/BalloonFlightInterface.kt | 538 ++++++++++ .../travel/balloon/BalloonFlightRoutes.kt | 222 ++++ .../travel/balloon/BalloonFlightScreens.kt | 814 +++++++++++++++ .../travel/balloon/BalloonTravelInterface.kt | 386 +++++++ .../cutscene/BalloonConstructionCutscene.kt | 71 ++ .../cutscene/BalloonExperimentCutscene.kt | 97 ++ .../SecondBalloonExperimentCutscene.kt | 107 ++ .../dialogue/AugusteDialogue.kt | 980 ++++++++++++++++++ .../quest/EnlightenedJourney.kt | 325 ++++++ .../quest/EnlightenedJourneyListeners.kt | 159 +++ .../core/game/dialogue/FacialExpression.java | 2 + .../system/command/sets/AudioCommandSet.kt | 27 + 20 files changed, 4085 insertions(+), 11 deletions(-) create mode 100644 Server/src/main/content/global/travel/balloon/BalloonAssistantsDialogue.kt create mode 100644 Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt create mode 100644 Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt create mode 100644 Server/src/main/content/global/travel/balloon/BalloonFlightRoutes.kt create mode 100644 Server/src/main/content/global/travel/balloon/BalloonFlightScreens.kt create mode 100644 Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt create mode 100644 Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt create mode 100644 Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt create mode 100644 Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt create mode 100644 Server/src/main/content/region/misc/quest/enlightenedjourney/dialogue/AugusteDialogue.kt create mode 100644 Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourney.kt create mode 100644 Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt diff --git a/Server/data/configs/npc_spawns.json b/Server/data/configs/npc_spawns.json index 77ef33f02..ee8028b79 100644 --- a/Server/data/configs/npc_spawns.json +++ b/Server/data/configs/npc_spawns.json @@ -157,7 +157,7 @@ }, { "npc_id": "47", - "loc_data": "{2821,3170,0,1,1}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3341,3267,0,1,5}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3001,3202,0,1,5}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" + "loc_data": "{2821,3170,0,1,1}-{3341,3267,0,1,5}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3001,3202,0,1,5}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" }, { "npc_id": "48", @@ -8611,17 +8611,45 @@ "npc_id": "5049", "loc_data": "{2808,3355,0,1,6}-" }, + { + "npc_id": "5051", + "loc_data": "{1800,4893,0,0,4}-" + }, + { + "npc_id": "5052", + "loc_data": "{1842,4921,0,0,7}-" + }, { "npc_id": "5062", - "loc_data": "{2927,3410,0,0,0}-" + "loc_data": "{2938,3421,0,1,6}-" }, { "npc_id": "5063", - "loc_data": "{2460,3108,0,1,3}-" + "loc_data": "{2462,3109,0,1,6}-" + }, + { + "npc_id": "5064", + "loc_data": "{2480,3458,0,1,6}-" }, { "npc_id": "5065", - "loc_data": "{2925,3303,0,0,0}-" + "loc_data": "{2925,3303,0,1,0}-" + }, + { + "npc_id": "5066", + "loc_data": "{3298,3482,0,1,6}-" + }, + { + "npc_id": "5067", + "loc_data": "{1799,4889,0,1,4}-" + }, + { + "npc_id": "5068", + "loc_data": "{1807,4889,0,1,3}-" + }, + { + "npc_id": "5069", + "loc_data": "{1807,4893,0,1,3}-" }, { "npc_id": "5070", diff --git a/Server/src/main/content/global/handlers/item/EmptyOptionListener.kt b/Server/src/main/content/global/handlers/item/EmptyOptionListener.kt index 71239cc7c..6cca82bfe 100644 --- a/Server/src/main/content/global/handlers/item/EmptyOptionListener.kt +++ b/Server/src/main/content/global/handlers/item/EmptyOptionListener.kt @@ -80,7 +80,8 @@ class EmptyOptionListener : InteractionListener { BURNT_GNOMEBOWL(Items.BURNT_GNOMEBOWL_2175, Items.GNOMEBOWL_MOULD_2166, "You empty the contents of the gnomebowl onto the floor."), BURNT_EGG(Items.BURNT_EGG_7090, Items.BOWL_1923, "You empty the contents of the bowl onto the floor."), BURNT_ONION(Items.BURNT_ONION_7092, Items.BOWL_1923, "You empty the contents of the bowl onto the floor."), - BURNT_MUSHROOM(Items.BURNT_MUSHROOM_7094, Items.BOWL_1923, "You empty the contents of the bowl onto the floor."); + BURNT_MUSHROOM(Items.BURNT_MUSHROOM_7094, Items.BOWL_1923, "You empty the contents of the bowl onto the floor."), + SANDBAG(Items.SANDBAG_9943, Items.EMPTY_SACK_5418, "You empty the sandbag."); companion object { var emptyItemMap = HashMap() diff --git a/Server/src/main/content/global/skill/farming/Patch.kt b/Server/src/main/content/global/skill/farming/Patch.kt index b2235419e..c9504aff0 100644 --- a/Server/src/main/content/global/skill/farming/Patch.kt +++ b/Server/src/main/content/global/skill/farming/Patch.kt @@ -27,7 +27,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl harvestAmt = when (plantable) { Plantable.LIMPWURT_SEED, Plantable.WOAD_SEED -> 3 Plantable.MUSHROOM_SPORE -> 6 - Plantable.WILLOW_SAPLING -> 0 + Plantable.WILLOW_SAPLING, Plantable.AUGUSTES_SAPLING -> 0 else -> 1 } if(plantable != null @@ -451,7 +451,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl // restocking their fruit should take 40 minutes per fruit minutes = 40 } - else if(plantable == Plantable.WILLOW_SAPLING && isGrown()) { + else if((plantable == Plantable.WILLOW_SAPLING || plantable == Plantable.AUGUSTES_SAPLING) && isGrown()) { // Willow Branches grow back in only 5 minutes minutes = 5 } diff --git a/Server/src/main/content/global/skill/farming/Plantable.kt b/Server/src/main/content/global/skill/farming/Plantable.kt index 6d08d9386..3f344a00d 100644 --- a/Server/src/main/content/global/skill/farming/Plantable.kt +++ b/Server/src/main/content/global/skill/farming/Plantable.kt @@ -82,7 +82,8 @@ enum class Plantable(val itemID: Int, val displayName: String, val value: Int, v CACTUS_SEED(Items.CACTUS_SEED_5280, "cactus seed", 8, 7, 66.5, 25.0, 374.0, 55, PatchType.CACTUS_PATCH, Items.CACTUS_SPINE_6016), EVIL_TURNIP_SEED(Items.EVIL_TURNIP_SEED_12148, "evil turnip seed", 4, 1, 41.0, 46.0, 0.0, 42, PatchType.EVIL_TURNIP_PATCH, Items.EVIL_TURNIP_12134), CALQUAT_SAPLING(Items.CALQUAT_SAPLING_5503, "calquat tree sapling", 4, 8, 130.5, 48.5, 12096.0, 72, PatchType.CALQUAT_TREE_PATCH, Items.CALQUAT_FRUIT_5980, Item(Items.POISON_IVY_BERRIES_6018, 8)), - SPIRIT_SAPLING(Items.SPIRIT_SAPLING_5375, "spirit tree sapling", 8, 12, 199.5, 0.0, 19301.0, 83, PatchType.SPIRIT_TREE_PATCH, 0, Item(Items.MONKEY_NUTS_4012, 5), null, Item(Items.MONKEY_BAR_4014, 1), Item(Items.GROUND_TOOTH_9082, 1) ) + SPIRIT_SAPLING(Items.SPIRIT_SAPLING_5375, "spirit tree sapling", 8, 12, 199.5, 0.0, 19301.0, 83, PatchType.SPIRIT_TREE_PATCH, 0, Item(Items.MONKEY_NUTS_4012, 5), null, Item(Items.MONKEY_BAR_4014, 1), Item(Items.GROUND_TOOTH_9082, 1)), + AUGUSTES_SAPLING(Items.AUGUSTES_SAPLING_9932, "Auguste's sapling", 15, 6, 25.0, 0.0, 1456.5, 30, PatchType.TREE_PATCH, Items.WILLOW_ROOTS_6045, Item(Items.APPLES5_5386)), ; constructor(itemID: Int, displayName: String, value: Int, stages: Int, plantingXP: Double, harvestXP: Double, checkHealthXP: Double, requiredLevel: Int, applicablePatch: PatchType, harvestItem: Int, protectionFlower: Plantable) diff --git a/Server/src/main/content/global/skill/farming/UseWithPatchHandler.kt b/Server/src/main/content/global/skill/farming/UseWithPatchHandler.kt index e443ad061..e420a894c 100644 --- a/Server/src/main/content/global/skill/farming/UseWithPatchHandler.kt +++ b/Server/src/main/content/global/skill/farming/UseWithPatchHandler.kt @@ -13,6 +13,7 @@ import core.tools.StringUtils import core.tools.prependArticle import org.rs09.consts.Sounds import content.data.Quests +import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney class UseWithPatchHandler : InteractionListener { val RAKE = Items.RAKE_5341 @@ -89,7 +90,7 @@ class UseWithPatchHandler : InteractionListener { return true } }) - } else if (p.plantable == Plantable.WILLOW_SAPLING && p.harvestAmt > 0) { + } else if ((p.plantable == Plantable.WILLOW_SAPLING || p.plantable == Plantable.AUGUSTES_SAPLING) && p.harvestAmt > 0) { val pulse = CropHarvester.harvestPulse(player, with, Items.WILLOW_BRANCH_5933) ?: return@onUseWith false submitIndividualPulse(player, pulse) } @@ -293,6 +294,10 @@ class UseWithPatchHandler : InteractionListener { if (plantable == Plantable.JUTE_SEED && patch == FarmingPatch.MCGRUBOR_HOPS && !player.achievementDiaryManager.hasCompletedTask(DiaryType.SEERS_VILLAGE, 0, 7)) { player.achievementDiaryManager.finishTask(player, DiaryType.SEERS_VILLAGE, 0, 7) } + if (plantable == Plantable.AUGUSTES_SAPLING) { + setAttribute(player, EnlightenedJourney.ATTRIBUTE_SAPLING_PLANTED, true) + sendMessage(player, "You have now planted Auguste's sapling. He will not give you any more.") + } p.plant(plantable) rewardXP(player, Skills.FARMING, plantable.plantingXP) p.setNewHarvestAmount() @@ -311,6 +316,8 @@ class UseWithPatchHandler : InteractionListener { val patchName = p.patch.type.displayName() if (plantable == Plantable.SCARECROW) { sendMessage(player, "You place the scarecrow in the $patchName.") + } else if (plantable == Plantable.AUGUSTES_SAPLING) { + sendMessage(player, "You plant the special willow sapling in the tree patch.") } else { sendMessage(player, "You plant $itemAmount $itemName in the $patchName.") } diff --git a/Server/src/main/content/global/skill/farming/timers/CropGrowth.kt b/Server/src/main/content/global/skill/farming/timers/CropGrowth.kt index 3cc14cd55..a6ec03ac3 100644 --- a/Server/src/main/content/global/skill/farming/timers/CropGrowth.kt +++ b/Server/src/main/content/global/skill/farming/timers/CropGrowth.kt @@ -57,7 +57,7 @@ class CropGrowth : PersistTimer (500, "farming:crops", isSoft = true) { private fun runOfflineCatchupLogic() { for ((_, patch) in patchMap) { val type = patch.patch.type - val shouldPlayCatchup = !patch.isGrown() || (type == PatchType.BUSH_PATCH && patch.getFruitOrBerryCount() < 4) || (type == PatchType.FRUIT_TREE_PATCH && patch.getFruitOrBerryCount() < 6) || (patch.plantable == Plantable.WILLOW_SAPLING && patch.harvestAmt < 6) + val shouldPlayCatchup = !patch.isGrown() || (type == PatchType.BUSH_PATCH && patch.getFruitOrBerryCount() < 4) || (type == PatchType.FRUIT_TREE_PATCH && patch.getFruitOrBerryCount() < 6) || ((patch.plantable == Plantable.WILLOW_SAPLING || patch.plantable == Plantable.AUGUSTES_SAPLING) && patch.harvestAmt < 6) if (shouldPlayCatchup && !patch.isDead && !patch.isChoppedFruitTree()) { var stagesToSimulate = if (!patch.isGrown()) { if (patch.isWeedy() || patch.isEmptyAndWeeded()) patch.currentGrowthStage % 4 @@ -69,7 +69,7 @@ class CropGrowth : PersistTimer (500, "farming:crops", isSoft = true) { stagesToSimulate += Math.min(4, 4 - patch.getFruitOrBerryCount()) if (type == PatchType.FRUIT_TREE_PATCH) stagesToSimulate += Math.min(6, 6 - patch.getFruitOrBerryCount()) - if (patch.plantable == Plantable.WILLOW_SAPLING) + if (patch.plantable == Plantable.WILLOW_SAPLING || patch.plantable == Plantable.AUGUSTES_SAPLING) stagesToSimulate += Math.min(6, 6 - patch.harvestAmt) } diff --git a/Server/src/main/content/global/travel/balloon/BalloonAssistantsDialogue.kt b/Server/src/main/content/global/travel/balloon/BalloonAssistantsDialogue.kt new file mode 100644 index 000000000..4b7a9bd3c --- /dev/null +++ b/Server/src/main/content/global/travel/balloon/BalloonAssistantsDialogue.kt @@ -0,0 +1,67 @@ +package content.global.travel.balloon + +import core.game.dialogue.DialogueLabeller +import core.game.dialogue.DialogueOption + +/** + * Dialogue for the balloon transport assistants. + * @author Edith + */ + +class BalloonAssistantsDialogue(private val start: BalloonTravelLocation) : DialogueLabeller() { + override fun addConversation() { + npc("Do you want to use the balloon? Just so you know, some locations require special logs and high Firemaking skills.") + options( + DialogueOption("yes_fly_balloon", "Yes.", "Yes."), + DialogueOption("no_fly_balloon", "No.", "No."), + DialogueOption("who_are_you", "Who are you?", "Who are you?") + ) + + label("yes_fly_balloon") + exec { player, _ -> + BalloonTravelInterface.open(player, start) + } + + label("who_are_you") + exec { player, _ -> + when (start) { + BalloonTravelLocation.TAVERLEY -> loadLabel(player, "who_stan") + BalloonTravelLocation.CRAFTING_GUILD -> loadLabel(player, "who_brock") + BalloonTravelLocation.VARROCK -> loadLabel(player, "who_serf") + BalloonTravelLocation.CASTLE_WARS -> loadLabel(player, "who_marrow") + BalloonTravelLocation.GRAND_TREE -> loadLabel(player, "who_le_smith") + else -> return@exec + } + } + + label("who_stan") + npc("I am Stan. Auguste hired me to look after this balloon. I make sure people are prepared to fly.") + goto("ask_fly") + + label("who_brock") + npc("I am Assistant Brock. I serve under Auguste as his number two assistant.") + goto("ask_fly") + + label("who_serf") + npc("I am a serf. Assistant Serf to you! Auguste freed me and gave me this job.") + goto("ask_fly") + + label("who_marrow") + npc("I am Assistant Marrow. I'm working here part time while I study to be a doctor.") + goto("ask_fly") + + label("who_le_smith") + npc("I am Assistant Le Smith. I used to work as a glider pilot, but they kicked me off.") + player("Why?") + npc("They said I was too full of hot air.") + goto("ask_fly") + + label("ask_fly") + npc("Do you want to use the balloon?") + options( + DialogueOption("yes_fly_balloon", "Yes.", "Yes."), + DialogueOption("no_fly_balloon", "No.", "No.") + ) + } + +} \ No newline at end of file diff --git a/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt b/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt new file mode 100644 index 000000000..cdf910f03 --- /dev/null +++ b/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt @@ -0,0 +1,242 @@ +package content.global.travel.balloon + +import core.api.closeInterface +import core.api.closeOverlay +import core.api.closeTabInterface +import core.api.getAttribute +import core.api.openOverlay +import core.api.playAudio +import core.api.removeAttribute +import core.api.sendMessage +import core.api.sendPlayerDialogue +import core.api.setAttribute +import core.api.submitIndividualPulse +import core.api.teleport +import core.api.unlock +import core.game.dialogue.DialogueLabeller +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.node.entity.player.Player +import core.game.system.task.Pulse +import core.game.world.map.Location +import core.game.world.update.flag.context.Animation +import core.net.packet.PacketRepository +import core.net.packet.context.MinimapStateContext +import core.net.packet.out.MinimapState +import org.rs09.consts.Components + +/** + * Handles balloon crash site travel and dialogue. + * @author Edith + */ + +object BalloonCrashSites { + const val SCENERY_OCEAN_PLANK = 19126 + const val SCENERY_WOODLAND_DIRT = 19125 + + const val NPC_OCEAN_AUGUSTE = 5051 + const val NPC_WOODLAND_AUGUSTE = 5052 + + private const val SOUND_CRASH = 3244 + private const val RENDER_ANIMATION_SWIM = 188 + + private val OCEAN_CRASH_LANDING = Location.create(1805, 4889, 0) + private val OCEAN_CRASH_FACE_LOCATION = Location.create(1804, 4889, 0) + private val OCEAN_CRASH_EXIT = Location.create(2867, 3368, 0) + private val OCEAN_CRASH_EXIT_FACE_LOCATION = Location.create(2866, 3368, 0) + + private val WOODLAND_CRASH_LANDING = Location.create(1844, 4920, 0) + private val WOODLAND_CRASH_FACE_LOCATION = Location.create(1843, 4921, 0) + private val WOODLAND_FALADOR_EXIT = Location.create(3068, 3358, 0) + private val WOODLAND_FALADOR_EXIT_FACE_LOCATION = Location.create(3068, 3357, 0) + private val WOODLAND_ARDOUGNE_EXIT = Location.create(2625, 3243, 0) + private val WOODLAND_ARDOUGNE_EXIT_FACE_LOCATION = Location.create(2625, 3242, 0) + + private const val ATTRIBUTE_WOODLAND_EXIT = "/save:enlightenedjourney_woodland_crash_exit" + + enum class WoodlandExit { + FALADOR, + ARDOUGNE + } + + + fun returnToEntrana(player: Player) { + val exit = Location.create(player.location) + fadeTransition(player) { + closeFlightInterface(player) + teleport(player, exit) + sendMessage(player, "You bail, but land safely on Entrana.") + } + } + + fun crashAtOceanSite(player: Player) { + playAudio(player, SOUND_CRASH) + fadeTransition(player) { + closeFlightInterface(player) + teleport(player, OCEAN_CRASH_LANDING) + oceanSwimmingAnimations(player) + player.faceLocation(OCEAN_CRASH_FACE_LOCATION) + sendMessage(player, "The balloon crashes.") + } + } + + fun leaveOceanCrashSite(player: Player) { + sendMessage(player, "You climb onto the plank and swim to shore.") + fadeTransition(player, fadeToBlack = true) { + player.appearance.setAnimations() + player.appearance.sync() + teleport(player, OCEAN_CRASH_EXIT) + player.faceLocation(OCEAN_CRASH_EXIT_FACE_LOCATION) + sendMessage(player, "You manage to swim back to shore.") + } + } + + fun crashAtWoodlandSite(player: Player, exit: WoodlandExit) { + playAudio(player, SOUND_CRASH) + setAttribute(player, ATTRIBUTE_WOODLAND_EXIT, exit.name) + fadeTransition(player) { + closeFlightInterface(player) + teleport(player, WOODLAND_CRASH_LANDING) + player.faceLocation(WOODLAND_CRASH_FACE_LOCATION) + sendMessage(player, "The balloon crashes.") + } + } + + fun leaveWoodlandCrashSite(player: Player) { + val exit = getWoodlandExit(player) + sendMessage(player, "You walk away from the crash site.") + fadeTransition(player, fadeToBlack = true) { + when (exit) { + WoodlandExit.FALADOR -> { + teleport(player, WOODLAND_FALADOR_EXIT) + player.faceLocation(WOODLAND_FALADOR_EXIT_FACE_LOCATION) + sendPlayerDialogue(player, "The crash must have really sent us off course; I'm near Falador!") + } + + WoodlandExit.ARDOUGNE -> { + teleport(player, WOODLAND_ARDOUGNE_EXIT) + // TODO: Placeholder message, find 09 source. + sendPlayerDialogue(player, "The crash must have really sent us off course; I'm near Ardougne!") + } + } + removeAttribute(player, ATTRIBUTE_WOODLAND_EXIT) + } + } + + private fun getWoodlandExit(player: Player): WoodlandExit { + return when (getAttribute(player, ATTRIBUTE_WOODLAND_EXIT, WoodlandExit.FALADOR.name)) { + WoodlandExit.ARDOUGNE.name -> WoodlandExit.ARDOUGNE + else -> WoodlandExit.FALADOR + } + } + + private fun closeFlightInterface(player: Player) { + closeInterface(player) + closeTabInterface(player) + player.interfaceManager.restoreTabs() + PacketRepository.send(MinimapState::class.java, MinimapStateContext(player, 0)) + } + + private fun fadeTransition(player: Player, fadeToBlack: Boolean = false, whileBlack: () -> Unit) { + if (fadeToBlack) { + player.lock() + openOverlay(player, Components.FADE_TO_BLACK_120) + submitIndividualPulse(player, object : Pulse() { + var counter = 0 + override fun pulse(): Boolean { + when (counter++) { + 4 -> { + whileBlack() + closeOverlay(player) + openOverlay(player, Components.FADE_FROM_BLACK_170) + } + + 7 -> { + closeOverlay(player) + unlock(player) + return true + } + } + return false + } + }) + return + } + whileBlack() + closeOverlay(player) + openOverlay(player, Components.FADE_FROM_BLACK_170) + submitIndividualPulse(player, object : Pulse() { + var counter = 0 + + override fun pulse(): Boolean { + when (counter++) { + 3 -> { + closeOverlay(player) + unlock(player) + return true + } + } + return false + } + }) + } + + private fun oceanSwimmingAnimations(player: Player) { + player.appearance.setAnimations(Animation(RENDER_ANIMATION_SWIM)) + player.appearance.sync() + } + +} + +class BalloonCrashSiteListener : InteractionListener { + override fun defineListeners() { + on(BalloonCrashSites.SCENERY_OCEAN_PLANK, IntType.SCENERY, "use") { player, _ -> + BalloonCrashSites.leaveOceanCrashSite(player) + return@on true + } + + on(BalloonCrashSites.SCENERY_WOODLAND_DIRT, IntType.SCENERY, "leave") { player, _ -> + BalloonCrashSites.leaveWoodlandCrashSite(player) + return@on true + } + + on(BalloonCrashSites.NPC_OCEAN_AUGUSTE, IntType.NPC, "talk-to") { player, node -> + DialogueLabeller.open(player, BalloonCrashDialogue(), node.asNpc()) + return@on true + } + + on(BalloonCrashSites.NPC_WOODLAND_AUGUSTE, IntType.NPC, "talk-to") { player, node -> + DialogueLabeller.open(player, BalloonCrashDialogue(), node.asNpc()) + return@on true + } + + } +} + +class BalloonCrashDialogue : DialogueLabeller() { + override fun addConversation() { + assignToIds(BalloonCrashSites.NPC_OCEAN_AUGUSTE) + + exec { player, npc -> + when (npc.id) { + BalloonCrashSites.NPC_OCEAN_AUGUSTE -> loadLabel(player, "ocean_crash") + BalloonCrashSites.NPC_WOODLAND_AUGUSTE -> loadLabel(player, "woodland_crash") + } + } + + label("ocean_crash") + npc("Great Scott! Ocean! Ahhh!") + player("What happened?") + npc("Crashed, off course. Ocean! Oh dear... I feel very...") + player("Contemplative? Concerned for your life? Desperate?") + npc("No...more along the lines of ill...You might want to swim away now. Use the plank...") + player("How are you going to get back? What about the balloon?") + npc("I'm sure a fishing trawler will come by and give me a lift. Don't worry, I shall return.") + + label("woodland_crash") + npc("Well, that didn't go as planned.") + player("So what now? How will we get the balloon back?") + npc("I'll have to get one of the monks to come pick it up. You head back on your own; just follow the path. I'll meet you back at Entrana.") + } + +} \ No newline at end of file diff --git a/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt new file mode 100644 index 000000000..c469aeda9 --- /dev/null +++ b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt @@ -0,0 +1,538 @@ +package content.global.travel.balloon + +import content.data.Quests +import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney +import core.api.closeInterface +import core.api.closeOverlay +import core.api.closeTabInterface +import core.api.getAttribute +import core.api.openInterface +import core.api.openOverlay +import core.api.openSingleTab +import core.api.playAudio +import core.api.removeAttribute +import core.api.sendMessage +import core.api.setAttribute +import core.api.setQuestStage +import core.api.setVarbit +import core.api.submitIndividualPulse +import core.api.teleport +import core.api.unlock +import core.game.interaction.InterfaceListener +import core.game.node.entity.player.Player +import core.game.system.task.Pulse +import core.game.world.map.Location +import core.net.packet.PacketRepository +import core.net.packet.context.MinimapStateContext +import core.net.packet.out.MinimapState +import core.plugin.Initializable +import org.rs09.consts.Components +import kotlin.math.abs + +/** + * Handles the balloon flight minigame interface. + * @author Edith + */ + +/** Balloon movement when the player presses one of the balloon controls. */ +private data class BalloonMove(val east: Int, val vertical: Int) + +/** Crash destinations for when the player bails or enters an incorrect route input. */ +private enum class BalloonCrashLocation { + ENTRANA, + OCEAN, + WOODLAND_FALADOR, + WOODLAND_ARDOUGNE +} + +@Initializable +class BalloonFlightInterface : InterfaceListener { + + companion object { + private const val BALLOON_FLIGHT_INTERFACE = 470 + private const val BALLOON_CONTROL_INTERFACE = 471 + + private const val ATTRIBUTE_BALLOON_TOP = "enlightenedjourney_balloon_top" + private const val ATTRIBUTE_BALLOON_BOTTOM = "enlightenedjourney_balloon_bottom" + + private const val ATTRIBUTE_FLIGHT_PROGRESS = "enlightenedjourney_balloon_flight_progress" + private const val ATTRIBUTE_FLIGHT_SCREEN = "enlightenedjourney_balloon_flight_screen" + private const val ATTRIBUTE_FLIGHT_DESTINATION = "enlightenedjourney_balloon_flight_destination" + + private const val SOUND_SANDBAG = 3249 + private const val SOUND_BURN_LOG = 3251 + private const val SOUND_RELAX = 3247 + private const val SOUND_ROPE = 3242 + private const val SOUND_RED_ROPE = 3239 + // cant find source material for using these two: + // zep_construct=3248 + // zep_hammering_1=3250 + + + private const val MUSIC_FLOATING_FREE = 206 + + private val controlMoves = mapOf( + BalloonFlightRoutes.BUTTON_SANDBAG to BalloonMove(1, -2), + BalloonFlightRoutes.BUTTON_BURN_LOG to BalloonMove(1, -1), + BalloonFlightRoutes.BUTTON_RELAX to BalloonMove(1, 0), + BalloonFlightRoutes.BUTTON_NORMAL_ROPE to BalloonMove(1, 1), + BalloonFlightRoutes.BUTTON_RED_ROPE to BalloonMove(1, 2) + ) + + /** Quest flight from Entrana to Taverley. */ + fun startQuestFlight(player: Player) { + val startPosition = BalloonFlightRoutes.getStartPosition(BalloonTravelLocation.TAVERLEY) + setAttribute(player, ATTRIBUTE_FLIGHT_DESTINATION, BalloonTravelLocation.TAVERLEY) + setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) + setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, 1) + setBalloonPosition(player, startPosition.top, startPosition.bottom) + closeInterface(player) + hideGameTabs(player) + hideMinimap(player) + player.musicPlayer.unlock(MUSIC_FLOATING_FREE) + openInterface(player, BALLOON_FLIGHT_INTERFACE) + } + + /** Post-quest flight from Entrana to a new unlockable destination. */ + fun startUnlockFlight(player: Player, destination: BalloonTravelLocation) { + val startPosition = BalloonFlightRoutes.getStartPosition(destination) + setAttribute(player, ATTRIBUTE_FLIGHT_DESTINATION, destination) + setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) + setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, 1) + setBalloonPosition(player, startPosition.top, startPosition.bottom) + closeInterface(player) + hideGameTabs(player) + hideMinimap(player) + player.musicPlayer.unlock(MUSIC_FLOATING_FREE) + openInterface(player, BALLOON_FLIGHT_INTERFACE) + } + + private fun getFlightDestination(player: Player): BalloonTravelLocation { + return getAttribute(player, ATTRIBUTE_FLIGHT_DESTINATION, BalloonTravelLocation.TAVERLEY) + } + + private fun getScreenPosition(destination: BalloonTravelLocation, screen: Int): BalloonPosition { + return when (destination) { + BalloonTravelLocation.TAVERLEY -> when (screen) { + 1 -> BalloonFlightRoutes.TAVERLEY_START + 2 -> BalloonFlightRoutes.TAVERLEY_SECOND + 3 -> BalloonFlightRoutes.TAVERLEY_THIRD + else -> BalloonFlightRoutes.TAVERLEY_START + } + + BalloonTravelLocation.CRAFTING_GUILD -> when (screen) { + 1 -> BalloonFlightRoutes.CRAFTING_GUILD_START + 2 -> BalloonFlightRoutes.CRAFTING_GUILD_SECOND + 3 -> BalloonFlightRoutes.CRAFTING_GUILD_THIRD + else -> BalloonFlightRoutes.CRAFTING_GUILD_START + } + + BalloonTravelLocation.VARROCK -> when (screen) { + 1 -> BalloonFlightRoutes.VARROCK_START + 2 -> BalloonFlightRoutes.VARROCK_SECOND + 3 -> BalloonFlightRoutes.VARROCK_THIRD + else -> BalloonFlightRoutes.VARROCK_START + } + + BalloonTravelLocation.CASTLE_WARS -> when (screen) { + 1 -> BalloonFlightRoutes.CASTLE_WARS_START + 2 -> BalloonFlightRoutes.CASTLE_WARS_SECOND + 3 -> BalloonFlightRoutes.CASTLE_WARS_THIRD + else -> BalloonFlightRoutes.CASTLE_WARS_START + } + + BalloonTravelLocation.GRAND_TREE -> when (screen) { + 1 -> BalloonFlightRoutes.GRAND_TREE_START + 2 -> BalloonFlightRoutes.GRAND_TREE_SECOND + 3 -> BalloonFlightRoutes.GRAND_TREE_THIRD + else -> BalloonFlightRoutes.GRAND_TREE_START + } + + else -> BalloonFlightRoutes.TAVERLEY_START + } + } + + private fun handleBalloonCrash(player: Player, location: BalloonCrashLocation) { + when (location) { + BalloonCrashLocation.ENTRANA -> BalloonCrashSites.returnToEntrana(player) + BalloonCrashLocation.OCEAN -> BalloonCrashSites.crashAtOceanSite(player) + BalloonCrashLocation.WOODLAND_FALADOR -> BalloonCrashSites.crashAtWoodlandSite( + player, + BalloonCrashSites.WoodlandExit.FALADOR + ) + + BalloonCrashLocation.WOODLAND_ARDOUGNE -> BalloonCrashSites.crashAtWoodlandSite( + player, + BalloonCrashSites.WoodlandExit.ARDOUGNE + ) + } + } + + private fun setBalloonPosition(player: Player, topChild: Int, bottomChild: Int) { + setAttribute(player, ATTRIBUTE_BALLOON_TOP, topChild) + setAttribute(player, ATTRIBUTE_BALLOON_BOTTOM, bottomChild) + } + + /** Moves the balloon model on the interface according to the selected control. */ + private fun moveBalloon(player: Player, move: BalloonMove) { + val startPosition = BalloonFlightRoutes.getStartPosition(getFlightDestination(player)) + val oldTop = getAttribute(player, ATTRIBUTE_BALLOON_TOP, startPosition.top) + val oldBottom = getAttribute(player, ATTRIBUTE_BALLOON_BOTTOM, startPosition.bottom) + var newTop = oldTop + var newBottom = oldBottom + + if (newBottom == 98) { + newBottom += 2 + } + + newTop += move.east + newBottom += move.east + + repeat(abs(move.vertical)) { + if (move.vertical < 0) { + newTop = moveNorth(newTop) + newBottom = moveNorth(newBottom) + } else { + newTop = moveSouth(newTop) + newBottom = moveSouth(newBottom) + } + } + + if (move.vertical < 0 && newTop - newBottom == 21) { + newBottom += 1 + } + + BalloonFlightScreens.clearBalloon(player, oldTop, oldBottom) + setBalloonPosition(player, newTop, newBottom) + BalloonFlightScreens.drawBalloon(player, newTop, newBottom) + } + + private fun moveNorth(child: Int) = child + if (child >= 111) 20 else 19 + private fun moveSouth(child: Int) = child - 20 + + /** Handles a control button press and either advances, lands or crashes the route. */ + private fun handleRouteButton(player: Player, buttonId: Int) { + val destination = getFlightDestination(player) + val screen = getAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, 1) + + if (buttonId == BalloonFlightRoutes.BUTTON_BAIL) { + handleBalloonCrash(player, getCrashLocation(destination, screen)) + return + } + + val route = BalloonFlightRoutes.getSequence(destination, screen) + val progress = getAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) + val expectedButton = route.getOrNull(progress) + val move = controlMoves[buttonId] + + if (buttonId != expectedButton || move == null) { + handleBalloonCrash(player, getCrashLocation(destination, screen)) + return + } + playControlSound(player, buttonId) + moveBalloon(player, move) + if (progress + 1 >= route.size) { + advanceFlightScreen(player, destination, screen) + } else { + setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, progress + 1) + } + } + + private fun advanceFlightScreen(player: Player, destination: BalloonTravelLocation, screen: Int) { + when (destination) { + BalloonTravelLocation.TAVERLEY -> advanceTaverleyScreen(player, screen) + BalloonTravelLocation.CRAFTING_GUILD -> advanceCraftingGuildScreen(player, screen) + BalloonTravelLocation.VARROCK -> advanceVarrockScreen(player, screen) + BalloonTravelLocation.CASTLE_WARS -> advanceCastleWarsScreen(player, screen) + BalloonTravelLocation.GRAND_TREE -> advanceGrandTreeScreen(player, screen) + else -> {} + } + } + + private fun drawFlightScreen(player: Player, destination: BalloonTravelLocation, screen: Int) { + BalloonFlightScreens.draw(player, destination, screen) + } + + private fun getCrashLocation(destination: BalloonTravelLocation, screen: Int): BalloonCrashLocation { + return when (destination) { + BalloonTravelLocation.TAVERLEY -> getTaverleyCrashLocation(screen) + BalloonTravelLocation.CRAFTING_GUILD -> getCraftingGuildCrashLocation(screen) + BalloonTravelLocation.VARROCK -> getVarrockCrashLocation(screen) + BalloonTravelLocation.CASTLE_WARS -> getCastleWarsCrashLocation(screen) + BalloonTravelLocation.GRAND_TREE -> getGrandTreeCrashLocation(screen) + else -> getTaverleyCrashLocation(screen) + } + } + + private fun advanceTaverleyScreen(player: Player, screen: Int) { + when (screen) { + 1 -> startTaverleyScreen(player, 2, BalloonFlightRoutes.TAVERLEY_SECOND) + 2 -> startTaverleyScreen(player, 3, BalloonFlightRoutes.TAVERLEY_THIRD) + 3 -> landInTaverley(player) + } + } + + private fun startTaverleyScreen(player: Player, screen: Int, position: BalloonPosition) { + BalloonFlightScreens.clear(player) + BalloonFlightScreens.draw(player, BalloonTravelLocation.TAVERLEY, screen) + setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, screen) + setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) + setBalloonPosition(player, position.top, position.bottom) + BalloonFlightScreens.drawBalloon(player, position.top, position.bottom) + } + + private fun landInTaverley(player: Player) { + fadeTransition(player) { + clearFlightAttributes(player) + closeInterface(player) + closeTabInterface(player) + showGameTabs(player) + showMinimap(player) + teleport(player, BalloonFlightRoutes.TAVERLEY_LANDING) + player.faceLocation(Location.create(2941, 3421, 0)) + sendMessage(player, "You arrive safely in Taverley.") + setVarbit(player, EnlightenedJourney.VARBIT_TAVERLEY_BALLOON, 1, true) + setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, EnlightenedJourney.STAGE_CLAIM_REWARD) + } + } + + private fun getTaverleyCrashLocation(screen: Int): BalloonCrashLocation { + return when (screen) { + 1 -> BalloonCrashLocation.ENTRANA + 2 -> BalloonCrashLocation.OCEAN + else -> BalloonCrashLocation.WOODLAND_FALADOR + } + } + + private fun advanceCraftingGuildScreen(player: Player, screen: Int) { + when (screen) { + 1 -> startCraftingGuildScreen(player, 2, BalloonFlightRoutes.CRAFTING_GUILD_SECOND) + 2 -> startCraftingGuildScreen(player, 3, BalloonFlightRoutes.CRAFTING_GUILD_THIRD) + 3 -> landAtCraftingGuild(player) + } + } + + private fun startCraftingGuildScreen(player: Player, screen: Int, position: BalloonPosition) { + BalloonFlightScreens.clear(player) + BalloonFlightScreens.draw(player, BalloonTravelLocation.CRAFTING_GUILD, screen) + setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, screen) + setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) + setBalloonPosition(player, position.top, position.bottom) + BalloonFlightScreens.drawBalloon(player, position.top, position.bottom) + } + + private fun landAtCraftingGuild(player: Player) { + fadeTransition(player) { + clearFlightAttributes(player) + closeInterface(player) + closeTabInterface(player) + showGameTabs(player) + showMinimap(player) + teleport(player, BalloonFlightRoutes.CRAFTING_GUILD_LANDING) + BalloonTravelInterface.unlockDestination(player, BalloonTravelLocation.CRAFTING_GUILD) + } + } + + private fun getCraftingGuildCrashLocation(screen: Int): BalloonCrashLocation { + return when (screen) { + 1 -> BalloonCrashLocation.ENTRANA + 2 -> BalloonCrashLocation.OCEAN + else -> BalloonCrashLocation.WOODLAND_FALADOR + } + } + + private fun advanceVarrockScreen(player: Player, screen: Int) { + when (screen) { + 1 -> startVarrockScreen(player, 2, BalloonFlightRoutes.VARROCK_SECOND) + 2 -> startVarrockScreen(player, 3, BalloonFlightRoutes.VARROCK_THIRD) + 3 -> landAtVarrock(player) + } + } + + private fun startVarrockScreen(player: Player, screen: Int, position: BalloonPosition) { + BalloonFlightScreens.clear(player) + BalloonFlightScreens.draw(player, BalloonTravelLocation.VARROCK, screen) + setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, screen) + setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) + setBalloonPosition(player, position.top, position.bottom) + BalloonFlightScreens.drawBalloon(player, position.top, position.bottom) + } + + private fun landAtVarrock(player: Player) { + fadeTransition(player) { + clearFlightAttributes(player) + closeInterface(player) + closeTabInterface(player) + showGameTabs(player) + showMinimap(player) + teleport(player, BalloonFlightRoutes.VARROCK_LANDING) + BalloonTravelInterface.unlockDestination(player, BalloonTravelLocation.VARROCK) + } + } + + private fun getVarrockCrashLocation(screen: Int): BalloonCrashLocation { + return when (screen) { + 1 -> BalloonCrashLocation.ENTRANA + else -> BalloonCrashLocation.WOODLAND_FALADOR + } + } + + private fun advanceCastleWarsScreen(player: Player, screen: Int) { + when (screen) { + 1 -> startCastleWarsScreen(player, 2, BalloonFlightRoutes.CASTLE_WARS_SECOND) + 2 -> startCastleWarsScreen(player, 3, BalloonFlightRoutes.CASTLE_WARS_THIRD) + 3 -> landAtCastleWars(player) + } + } + + private fun startCastleWarsScreen(player: Player, screen: Int, position: BalloonPosition) { + BalloonFlightScreens.clear(player) + BalloonFlightScreens.draw(player, BalloonTravelLocation.CASTLE_WARS, screen) + setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, screen) + setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) + setBalloonPosition(player, position.top, position.bottom) + BalloonFlightScreens.drawBalloon(player, position.top, position.bottom) + } + + private fun landAtCastleWars(player: Player) { + fadeTransition(player) { + clearFlightAttributes(player) + closeInterface(player) + closeTabInterface(player) + showGameTabs(player) + showMinimap(player) + teleport(player, BalloonFlightRoutes.CASTLE_WARS_LANDING) + BalloonTravelInterface.unlockDestination(player, BalloonTravelLocation.CASTLE_WARS) + } + } + + private fun getCastleWarsCrashLocation(screen: Int): BalloonCrashLocation { + return when (screen) { + 1, 2 -> BalloonCrashLocation.OCEAN + else -> BalloonCrashLocation.WOODLAND_ARDOUGNE + } + } + + private fun advanceGrandTreeScreen(player: Player, screen: Int) { + when (screen) { + 1 -> startGrandTreeScreen(player, 2, BalloonFlightRoutes.GRAND_TREE_SECOND) + 2 -> startGrandTreeScreen(player, 3, BalloonFlightRoutes.GRAND_TREE_THIRD) + 3 -> landAtGrandTree(player) + } + } + + private fun startGrandTreeScreen(player: Player, screen: Int, position: BalloonPosition) { + BalloonFlightScreens.clear(player) + BalloonFlightScreens.draw(player, BalloonTravelLocation.GRAND_TREE, screen) + setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, screen) + setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) + setBalloonPosition(player, position.top, position.bottom) + BalloonFlightScreens.drawBalloon(player, position.top, position.bottom) + } + + private fun landAtGrandTree(player: Player) { + fadeTransition(player) { + clearFlightAttributes(player) + closeInterface(player) + closeTabInterface(player) + showGameTabs(player) + showMinimap(player) + teleport(player, BalloonFlightRoutes.GRAND_TREE_LANDING) + BalloonTravelInterface.unlockDestination(player, BalloonTravelLocation.GRAND_TREE) + } + } + + private fun getGrandTreeCrashLocation(screen: Int): BalloonCrashLocation { + return when (screen) { + 1 -> BalloonCrashLocation.OCEAN + else -> BalloonCrashLocation.WOODLAND_ARDOUGNE + } + } + + private fun clearFlightAttributes(player: Player) { + removeAttribute(player, ATTRIBUTE_BALLOON_TOP) + removeAttribute(player, ATTRIBUTE_BALLOON_BOTTOM) + removeAttribute(player, ATTRIBUTE_FLIGHT_DESTINATION) + removeAttribute(player, ATTRIBUTE_FLIGHT_SCREEN) + removeAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS) + } + + private fun playControlSound(player: Player, buttonId: Int) { + val sound = when (buttonId) { + BalloonFlightRoutes.BUTTON_SANDBAG -> SOUND_SANDBAG + BalloonFlightRoutes.BUTTON_BURN_LOG -> SOUND_BURN_LOG + BalloonFlightRoutes.BUTTON_RELAX -> SOUND_RELAX + BalloonFlightRoutes.BUTTON_NORMAL_ROPE -> SOUND_ROPE + BalloonFlightRoutes.BUTTON_RED_ROPE -> SOUND_RED_ROPE + else -> return + } + playAudio(player, sound) + } + + private fun hideMinimap(player: Player) { + PacketRepository.send(MinimapState::class.java, MinimapStateContext(player, 2)) + } + + private fun showMinimap(player: Player) { + PacketRepository.send(MinimapState::class.java, MinimapStateContext(player, 0)) + } + + private fun hideGameTabs(player: Player) { + player.interfaceManager.removeTabs(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) + } + + private fun showGameTabs(player: Player) { + player.interfaceManager.restoreTabs() + } + + private fun fadeTransition(player: Player, whileBlack: () -> Unit) { + whileBlack() + closeOverlay(player) + openOverlay(player, Components.FADE_FROM_BLACK_170) + submitIndividualPulse(player, object : Pulse() { + var counter = 0 + override fun pulse(): Boolean { + when (counter++) { + 3 -> { + closeOverlay(player) + unlock(player) + return true + } + } + return false + } + }) + } + + } + + override fun defineInterfaceListeners() { + onOpen(BALLOON_FLIGHT_INTERFACE) { player, _ -> + val destination = getFlightDestination(player) + val screen = getAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, 1) + val startPosition = getScreenPosition(destination, screen) + player.lock() + openSingleTab(player, BALLOON_CONTROL_INTERFACE) + BalloonFlightScreens.clear(player) + drawFlightScreen(player, destination, screen) + BalloonFlightScreens.drawBalloon(player, startPosition.top, startPosition.bottom) + openOverlay(player, 333) + true + } + + onClose(BALLOON_FLIGHT_INTERFACE) { player, _ -> + BalloonFlightScreens.clear(player) + clearFlightAttributes(player) + closeTabInterface(player) + showGameTabs(player) + showMinimap(player) + true + } + + on(BALLOON_CONTROL_INTERFACE) { player, _, _, buttonId, _, _ -> + handleRouteButton(player, buttonId) + true + } + } + +} \ No newline at end of file diff --git a/Server/src/main/content/global/travel/balloon/BalloonFlightRoutes.kt b/Server/src/main/content/global/travel/balloon/BalloonFlightRoutes.kt new file mode 100644 index 000000000..0a688f1c3 --- /dev/null +++ b/Server/src/main/content/global/travel/balloon/BalloonFlightRoutes.kt @@ -0,0 +1,222 @@ +package content.global.travel.balloon + +import core.game.world.map.Location + +/** + * Flight route values used by the balloon flight minigame. + * @author Edith + */ + +data class BalloonPosition(val top: Int, val bottom: Int) + +object BalloonFlightRoutes { + const val BUTTON_SANDBAG = 4 + const val BUTTON_RELAX = 5 + const val BUTTON_NORMAL_ROPE = 6 + const val BUTTON_BAIL = 8 + const val BUTTON_BURN_LOG = 9 + const val BUTTON_RED_ROPE = 10 + + /** Child slots used by the top and bottom balloon models. */ + val TAVERLEY_START = BalloonPosition(118, 99) + val TAVERLEY_SECOND = BalloonPosition(119, 98) + val TAVERLEY_THIRD = BalloonPosition(179, 159) + + val CRAFTING_GUILD_START = BalloonPosition(178, 158) + val CRAFTING_GUILD_SECOND = BalloonPosition(159, 139) + val CRAFTING_GUILD_THIRD = BalloonPosition(159, 139) + + val VARROCK_START = BalloonPosition(138, 118) + val VARROCK_SECOND = BalloonPosition(179, 159) + val VARROCK_THIRD = BalloonPosition(179, 159) + + val CASTLE_WARS_START = BalloonPosition(118, 99) + val CASTLE_WARS_SECOND = BalloonPosition(199, 179) + val CASTLE_WARS_THIRD = BalloonPosition(159, 139) + + val GRAND_TREE_START = BalloonPosition(178, 158) + val GRAND_TREE_SECOND = BalloonPosition(159, 139) + val GRAND_TREE_THIRD = BalloonPosition(159, 139) + + /** Player landing locations. */ + val TAVERLEY_LANDING = Location.create(2941, 3420, 0) + val CRAFTING_GUILD_LANDING = Location.create(2924, 3303, 0) + val VARROCK_LANDING = Location.create(3298, 3481, 0) + val CASTLE_WARS_LANDING = Location.create(2462, 3108, 0) + val GRAND_TREE_LANDING = Location.create(2480, 3458, 0) + + private val taverleyRouteFirstScreen = listOf( + BUTTON_SANDBAG, BUTTON_BURN_LOG, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RED_ROPE, BUTTON_RELAX, BUTTON_RELAX, BUTTON_NORMAL_ROPE, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX + ) + + private val taverleyRouteSecondScreen = listOf( + BUTTON_BURN_LOG, BUTTON_RELAX, BUTTON_BURN_LOG, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_BURN_LOG, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX + ) + + private val taverleyRouteThirdScreen = listOf( + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RED_ROPE, BUTTON_NORMAL_ROPE, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_BURN_LOG, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_NORMAL_ROPE + ) + + private val craftingGuildRouteFirstScreen = listOf( + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_BURN_LOG, BUTTON_BURN_LOG, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RED_ROPE, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_BURN_LOG, BUTTON_RED_ROPE, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_NORMAL_ROPE, BUTTON_RELAX, BUTTON_BURN_LOG, BUTTON_RELAX + ) + + private val craftingGuildRouteSecondScreen = listOf( + BUTTON_RELAX, BUTTON_NORMAL_ROPE, BUTTON_RELAX, BUTTON_BURN_LOG, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_NORMAL_ROPE, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_BURN_LOG, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX + ) + + private val craftingGuildRouteThirdScreen = listOf( + BUTTON_RELAX, BUTTON_RELAX, BUTTON_SANDBAG, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RED_ROPE, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_NORMAL_ROPE, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_NORMAL_ROPE + ) + + private val varrockRouteFirstScreen = listOf( + BUTTON_BURN_LOG, BUTTON_BURN_LOG, BUTTON_BURN_LOG, BUTTON_BURN_LOG, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_NORMAL_ROPE, BUTTON_NORMAL_ROPE, BUTTON_NORMAL_ROPE, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_NORMAL_ROPE, BUTTON_BURN_LOG, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_NORMAL_ROPE, BUTTON_BURN_LOG, BUTTON_BURN_LOG, BUTTON_RELAX, BUTTON_RELAX + ) + + private val varrockRouteSecondScreen = listOf( + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_BURN_LOG, BUTTON_BURN_LOG, BUTTON_NORMAL_ROPE, BUTTON_NORMAL_ROPE, + BUTTON_NORMAL_ROPE, BUTTON_NORMAL_ROPE, BUTTON_RELAX, BUTTON_RELAX, BUTTON_SANDBAG, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX + ) + + private val varrockRouteThirdScreen = listOf( + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_SANDBAG, BUTTON_RELAX, + BUTTON_NORMAL_ROPE, BUTTON_NORMAL_ROPE, BUTTON_SANDBAG, BUTTON_RELAX, BUTTON_NORMAL_ROPE, + BUTTON_NORMAL_ROPE, BUTTON_SANDBAG, BUTTON_RELAX, BUTTON_RED_ROPE, BUTTON_RELAX, + BUTTON_RED_ROPE, BUTTON_RELAX, BUTTON_NORMAL_ROPE + ) + + private val castleWarsRouteFirstScreen = listOf( + BUTTON_SANDBAG, BUTTON_SANDBAG, BUTTON_BURN_LOG, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RED_ROPE, BUTTON_BURN_LOG, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RED_ROPE, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_BURN_LOG, BUTTON_BURN_LOG, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX + ) + + private val castleWarsRouteSecondScreen = listOf( + BUTTON_BURN_LOG, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RED_ROPE, BUTTON_NORMAL_ROPE, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_SANDBAG, BUTTON_RELAX, BUTTON_NORMAL_ROPE, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_NORMAL_ROPE, BUTTON_RELAX + ) + + private val castleWarsRouteThirdScreen = listOf( + BUTTON_BURN_LOG, BUTTON_RELAX, BUTTON_RELAX, BUTTON_NORMAL_ROPE, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_BURN_LOG, BUTTON_RED_ROPE, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_SANDBAG, BUTTON_RED_ROPE, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_NORMAL_ROPE + ) + + private val grandTreeRouteFirstScreen = listOf( + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_NORMAL_ROPE, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX + ) + + private val grandTreeRouteSecondScreen = listOf( + BUTTON_BURN_LOG, BUTTON_NORMAL_ROPE, BUTTON_BURN_LOG, BUTTON_NORMAL_ROPE, BUTTON_BURN_LOG, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_BURN_LOG, BUTTON_NORMAL_ROPE, BUTTON_RELAX, + BUTTON_SANDBAG, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RED_ROPE, BUTTON_RELAX, + BUTTON_NORMAL_ROPE, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX + ) + + private val grandTreeRouteThirdScreen = listOf( + BUTTON_BURN_LOG, BUTTON_BURN_LOG, BUTTON_BURN_LOG, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_NORMAL_ROPE, BUTTON_BURN_LOG, BUTTON_RELAX, BUTTON_RELAX, BUTTON_RELAX, + BUTTON_RELAX, BUTTON_RELAX, BUTTON_RED_ROPE, BUTTON_RELAX, BUTTON_RED_ROPE, + BUTTON_NORMAL_ROPE, BUTTON_RELAX, BUTTON_RELAX, BUTTON_NORMAL_ROPE + ) + + /** Gets the matching button sequence for the selected route and current flight screen. */ + fun getSequence(destination: BalloonTravelLocation, screen: Int): List { + return when (destination) { + BalloonTravelLocation.TAVERLEY -> getTaverleySequence(screen) + BalloonTravelLocation.CRAFTING_GUILD -> getCraftingGuildSequence(screen) + BalloonTravelLocation.VARROCK -> getVarrockSequence(screen) + BalloonTravelLocation.CASTLE_WARS -> getCastleWarsSequence(screen) + BalloonTravelLocation.GRAND_TREE -> getGrandTreeSequence(screen) + else -> emptyList() + } + } + + /** Gets the starting child slots for the balloon models on the first screen of a route. */ + fun getStartPosition(destination: BalloonTravelLocation): BalloonPosition { + return when (destination) { + BalloonTravelLocation.TAVERLEY -> TAVERLEY_START + BalloonTravelLocation.CRAFTING_GUILD -> CRAFTING_GUILD_START + BalloonTravelLocation.VARROCK -> VARROCK_START + BalloonTravelLocation.CASTLE_WARS -> CASTLE_WARS_START + BalloonTravelLocation.GRAND_TREE -> GRAND_TREE_START + else -> TAVERLEY_START + } + } + + private fun getTaverleySequence(screen: Int): List { + return when (screen) { + 1 -> taverleyRouteFirstScreen + 2 -> taverleyRouteSecondScreen + 3 -> taverleyRouteThirdScreen + else -> emptyList() + } + } + + private fun getCraftingGuildSequence(screen: Int): List { + return when (screen) { + 1 -> craftingGuildRouteFirstScreen + 2 -> craftingGuildRouteSecondScreen + 3 -> craftingGuildRouteThirdScreen + else -> emptyList() + } + } + + private fun getVarrockSequence(screen: Int): List { + return when (screen) { + 1 -> varrockRouteFirstScreen + 2 -> varrockRouteSecondScreen + 3 -> varrockRouteThirdScreen + else -> emptyList() + } + } + + private fun getCastleWarsSequence(screen: Int): List { + return when (screen) { + 1 -> castleWarsRouteFirstScreen + 2 -> castleWarsRouteSecondScreen + 3 -> castleWarsRouteThirdScreen + else -> emptyList() + } + } + + private fun getGrandTreeSequence(screen: Int): List { + return when (screen) { + 1 -> grandTreeRouteFirstScreen + 2 -> grandTreeRouteSecondScreen + 3 -> grandTreeRouteThirdScreen + else -> emptyList() + } + } + +} \ No newline at end of file diff --git a/Server/src/main/content/global/travel/balloon/BalloonFlightScreens.kt b/Server/src/main/content/global/travel/balloon/BalloonFlightScreens.kt new file mode 100644 index 000000000..5d0e19cc1 --- /dev/null +++ b/Server/src/main/content/global/travel/balloon/BalloonFlightScreens.kt @@ -0,0 +1,814 @@ +package content.global.travel.balloon + +import core.api.sendAnimationOnInterface +import core.game.node.entity.player.Player + +/** + * Draws the scenery and balloon models for the balloon flight minigame interface. + * @author Edith + */ + +object BalloonFlightScreens { + private const val BALLOON_FLIGHT_INTERFACE = 470 + + private const val MODEL_WHITE_BIRD = 19779 + private const val MODEL_BROWN_BIRD = 19780 + private const val ANIMATION_BIRD = 341 + private const val MODEL_CLOUD_ANOMALY = 19781 + private const val ANIMATION_CLOUD_ANOMALY = 5141 + private const val MODEL_BALLOON_TOP = 19517 + private const val MODEL_BALLOON_BOTTOM = 19518 + + /** Clears all model child slots used by the flight interface. */ + fun clear(player: Player) { + for (child in 78..237) { + player.packetDispatch.sendModelOnInterface(-1, BALLOON_FLIGHT_INTERFACE, child, 0) + } + } + + /** Draws the scenery for the selected route and screen. */ + fun draw(player: Player, destination: BalloonTravelLocation, screen: Int) { + when (destination) { + BalloonTravelLocation.TAVERLEY -> drawTaverleyScreen(player, screen) + BalloonTravelLocation.CRAFTING_GUILD -> drawCraftingGuildScreen(player, screen) + BalloonTravelLocation.VARROCK -> drawVarrockScreen(player, screen) + BalloonTravelLocation.CASTLE_WARS -> drawCastleWarsScreen(player, screen) + BalloonTravelLocation.GRAND_TREE -> drawGrandTreeScreen(player, screen) + else -> {} + } + } + + /** Draws the top and bottom balloon models at the given child slots. */ + fun drawBalloon(player: Player, topChild: Int, bottomChild: Int) { + player.packetDispatch.sendModelOnInterface(MODEL_BALLOON_TOP, BALLOON_FLIGHT_INTERFACE, topChild, 2576) + resetModelAngle(player, topChild) + player.packetDispatch.sendModelOnInterface(MODEL_BALLOON_BOTTOM, BALLOON_FLIGHT_INTERFACE, bottomChild, 2576) + resetModelAngle(player, bottomChild) + } + + /** Clears the top and bottom balloon models at the given child slots. */ + fun clearBalloon(player: Player, topChild: Int, bottomChild: Int) { + player.packetDispatch.sendModelOnInterface(-1, BALLOON_FLIGHT_INTERFACE, topChild, 0) + player.packetDispatch.sendModelOnInterface(-1, BALLOON_FLIGHT_INTERFACE, bottomChild, 0) + } + + private fun resetModelAngle(player: Player, child: Int) { + player.packetDispatch.sendAngleOnInterface(BALLOON_FLIGHT_INTERFACE, child, 2576, 0, 0) + } + + private fun drawModels(player: Player, model: Int, vararg children: Int) { + for (child in children) { + player.packetDispatch.sendModelOnInterface(model, BALLOON_FLIGHT_INTERFACE, child, 2576) + resetModelAngle(player, child) + } + } + + private fun drawAnimatedModels( + player: Player, + model: Int, + animation: Int, + zoom: Int, + pitch: Int, + yaw: Int, + vararg children: Int + ) { + for (child in children) { + player.packetDispatch.sendModelOnInterface(model, BALLOON_FLIGHT_INTERFACE, child, zoom) + player.packetDispatch.sendAngleOnInterface(BALLOON_FLIGHT_INTERFACE, child, zoom, pitch, yaw) + sendAnimationOnInterface(player, animation, BALLOON_FLIGHT_INTERFACE, child) + } + } + + private fun drawTaverleyScreen(player: Player, screen: Int) { + when (screen) { + 1 -> drawTaverleyScreenOne(player) + 2 -> drawTaverleyScreenTwo(player) + 3 -> drawTaverleyScreenThree(player) + } + } + + private fun drawTaverleyScreenOne(player: Player) { + // Ground + drawModels(player, 19558, 40) + drawModels(player, 19559, 45) + drawModels(player, 19560, 50) + drawModels(player, 19561, 55) + + // Trees + drawModels(player, 19580, 123) + drawModels(player, 19578, 124) + drawModels(player, 19582, 125) + drawModels(player, 19579, 103) + drawModels(player, 19576, 104) + drawModels(player, 19581, 105) + drawModels(player, 19575, 83) + drawModels(player, 19574, 84) + drawModels(player, 19577, 85) + drawModels(player, 19521, 102, 107, 106, 109) + drawModels(player, 19519, 82, 87, 86, 89) + drawModels(player, 19522, 91, 92) + drawModels(player, 19570, 127, 128) + drawModels(player, 19569, 107, 108) + drawModels(player, 19568, 87, 88) + + // Clouds + drawModels(player, 19525, 155, 210, 227, 172) + drawModels(player, 19524, 211, 212, 228, 173) + drawModels(player, 19526, 156, 213, 229, 174) + + // Launch base + drawModels(player, 19572, 78) + + // Birds + drawAnimatedModels(player, MODEL_BROWN_BIRD, ANIMATION_BIRD, 2567, 100, 300, 145, 148, 177, 209) + + // Cloud anomaly + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 175, 230) + } + + private fun drawTaverleyScreenTwo(player: Player) { + // Ground + drawModels(player, 19562, 40) + drawModels(player, 19563, 45) + drawModels(player, 19564, 50) + drawModels(player, 19565, 55) + + // Clouds + drawModels(player, 19526, 158) + + // Palm tree + drawModels(player, 19551, 83) + drawModels(player, 19553, 84) + drawModels(player, 19552, 103) + drawModels(player, 19527, 123) + + // Rock + drawModels(player, 19616, 90) + + // Trees + drawModels(player, 19530, 111, 112) + drawModels(player, 19523, 91, 92) + drawModels(player, 19570, 133) + drawModels(player, 19569, 113) + drawModels(player, 19568, 93) + + // Building + drawModels(player, 19534, 154) + drawModels(player, 19533, 134) + drawModels(player, 19532, 114) + drawModels(player, 19531, 94) + drawModels(player, 19544, 155) + drawModels(player, 19543, 135) + drawModels(player, 19542, 115) + drawModels(player, 19541, 95) + drawModels(player, 19545, 156) + drawModels(player, 19546, 136) + drawModels(player, 19540, 116) + drawModels(player, 19539, 96) + drawModels(player, 19550, 157) + drawModels(player, 19549, 137) + drawModels(player, 19548, 117) + drawModels(player, 19547, 97) + + // Clouds + drawModels(player, 19525, 180, 201, 186) + drawModels(player, 19524, 202, 187) + drawModels(player, 19526, 181, 203, 188) + + // Birds + drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 161, 179, 185, 204, 219) + } + + private fun drawTaverleyScreenThree(player: Player) { + // Ground + drawModels(player, 19566, 40) + drawModels(player, 19554, 45) + drawModels(player, 19555, 50) + drawModels(player, 19556, 55) + + // Building + drawModels(player, 19538, 138) + drawModels(player, 19537, 118) + drawModels(player, 19536, 99) + drawModels(player, 19535, 78) + + // Trees + drawModels(player, 19580, 119) + drawModels(player, 19578, 120) + drawModels(player, 19582, 121) + drawModels(player, 19579, 98) + drawModels(player, 19576, 100) + drawModels(player, 19581, 101) + drawModels(player, 19575, 79) + drawModels(player, 19574, 80) + drawModels(player, 19577, 81) + drawModels(player, 19521, 102, 103, 113) + drawModels(player, 19519, 82, 83, 93) + drawModels(player, 19522, 84, 85, 92) + drawModels(player, 19570, 126) + drawModels(player, 19569, 106) + drawModels(player, 19568, 86) + + // Landing base + drawModels(player, 19567, 97) + + // Clouds + drawModels(player, 19525, 168, 174, 212) + drawModels(player, 19524, 169, 170, 175, 213) + drawModels(player, 19526, 171, 176, 214) + + // Birds + drawAnimatedModels(player, MODEL_BROWN_BIRD, ANIMATION_BIRD, 2567, 100, 300, 146, 151, 192, 207, 208, 215) + + // Cloud anomaly + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 191) + } + + private fun drawCraftingGuildScreen(player: Player, screen: Int) { + when (screen) { + 1 -> drawCraftingGuildScreenOne(player) + 2 -> drawCraftingGuildScreenTwo(player) + 3 -> drawCraftingGuildScreenThree(player) + } + } + + private fun drawCraftingGuildScreenOne(player: Player) { + // Ground + drawModels(player, 19558, 40) + drawModels(player, 19559, 45) + drawModels(player, 19604, 50) + drawModels(player, 19605, 55) + + // Launch base + drawModels(player, 19572, 138) + + // Mountain + drawModels(player, 19607, 118) + drawModels(player, 19611, 119) + drawModels(player, 19608, 98, 99) + drawModels(player, 19612, 100) + drawModels(player, 19609, 78, 79, 80) + drawModels(player, 19613, 81) + + // Trees + drawModels(player, 19570, 122, 124, 133, 137) + drawModels(player, 19569, 102, 104, 113, 117) + drawModels(player, 19568, 82, 84, 93, 97) + drawModels(player, 19521, 103, 116) + drawModels(player, 19519, 83, 96) + + // Building + drawModels(player, 19618, 128) + drawModels(player, 19633, 108) + drawModels(player, 19630, 88) + drawModels(player, 19619, 129) + drawModels(player, 19603, 109) + drawModels(player, 19602, 89) + drawModels(player, 19620, 130) + drawModels(player, 19629, 110) + drawModels(player, 19628, 90) + drawModels(player, 19621, 131) + drawModels(player, 19632, 111) + drawModels(player, 19631, 91) + + // Birds + drawAnimatedModels(player, MODEL_BROWN_BIRD, ANIMATION_BIRD, 2567, 100, 300, 220, 221, 206, 175, 151, 171, 148) + + // Cloud anomaly + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 183) + + // Clouds + drawModels(player, 19525, 162, 192, 233) + drawModels(player, 19524, 163, 193, 234) + drawModels(player, 19526, 164, 194, 235) + } + + private fun drawCraftingGuildScreenTwo(player: Player) { + // Ground + drawModels(player, 19606, 40) + drawModels(player, 19561, 45) + drawModels(player, 19562, 50, 55) + + // Clouds + drawModels(player, 19525, 168, 200, 193, 205) + drawModels(player, 19524, 169, 201, 206, 194) + drawModels(player, 19526, 170, 202, 207, 195) + + // Trees + drawModels(player, 19521, 99) + drawModels(player, 19519, 78) + drawModels(player, 19570, 119) + drawModels(player, 19569, 98) + drawModels(player, 19568, 79) + + // Ship + drawModels(player, 19625, 103) + drawModels(player, 19623, 83) + drawModels(player, 19626, 124) + drawModels(player, 19627, 104) + drawModels(player, 19624, 84) + + // Rocks + drawModels(player, 19617, 107, 109, 112) + drawModels(player, 19615, 87, 89, 92) + drawModels(player, 19616, 96) + + // Shark + drawModels(player, 19717, 97) + + // Birds + drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 161, 187, 216, 217, 171) + + // Cloud anomaly + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 127, 132, 188) + } + + private fun drawCraftingGuildScreenThree(player: Player) { + // Ground + drawModels(player, 19595, 40) + drawModels(player, 19596, 45) + drawModels(player, 19597, 50) + drawModels(player, 19598, 55) + + // Landing base + drawModels(player, 19567, 97) + + // Rocks + drawModels(player, 19616, 79, 84) + drawModels(player, 19617, 100) + drawModels(player, 19615, 80) + + // Shark + drawModels(player, 19717, 78) + + // Trees + drawModels(player, 19601, 123, 130) + drawModels(player, 19600, 103, 110) + drawModels(player, 19599, 83, 90) + drawModels(player, 19521, 105, 107, 108) + drawModels(player, 19519, 85, 87, 88) + drawModels(player, 19522, 86) + drawModels(player, 19622, 89) + + // Clouds + drawModels(player, 19526, 198, 224, 168, 175, 230, 212) + drawModels(player, 19525, 222, 166, 173, 228, 210) + drawModels(player, 19524, 223, 167, 174, 229, 211) + + // Birds + drawAnimatedModels(player, MODEL_BROWN_BIRD, ANIMATION_BIRD, 2567, 100, 300, 199, 120, 163, 209) + + // Cloud anomaly + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 143, 104) + } + + private fun drawVarrockScreen(player: Player, screen: Int) { + when (screen) { + 1 -> drawVarrockScreenOne(player) + 2 -> drawVarrockScreenTwo(player) + 3 -> drawVarrockScreenThree(player) + } + } + + private fun drawVarrockScreenOne(player: Player) { + // Ground + drawModels(player, 19731, 40) + drawModels(player, 19735, 45) + drawModels(player, 19736, 50) + drawModels(player, 19737, 55) + + // Launch base + drawModels(player, 19572, 99) + + // Hill + drawModels(player, 19607, 78) + drawModels(player, 19611, 79) + + // Trees + drawModels(player, 19570, 120, 135, 137) + drawModels(player, 19569, 100, 115, 117) + drawModels(player, 19568, 80, 95, 97) + drawModels(player, 19616, 83, 86) + drawModels(player, 19529, 127, 129, 131) + drawModels(player, 19528, 107, 109, 111) + drawModels(player, 19523, 87, 88, 89, 90, 91) + drawModels(player, 19530, 108, 110) + drawModels(player, 19521, 113, 114) + drawModels(player, 19519, 93, 94) + + // Clouds + drawModels(player, 19525, 198, 144, 206, 188, 193) + drawModels(player, 19524, 199, 145, 207, 189, 194) + drawModels(player, 19526, 200, 146, 208, 190, 195) + + // Birds + drawAnimatedModels( + player, + MODEL_WHITE_BIRD, + ANIMATION_BIRD, + 2567, + 100, + 300, + 122, + 161, + 163, + 170, + 174, + 157, + 216, + 232 + ) + } + + private fun drawVarrockScreenTwo(player: Player) { + // Ground + drawModels(player, 19738, 40) + drawModels(player, 19739, 45) + drawModels(player, 19740, 50) + drawModels(player, 19741, 55) + + // Birds + drawAnimatedModels(player, MODEL_BROWN_BIRD, ANIMATION_BIRD, 2567, 100, 300, 139, 218, 214, 209, 190, 214, 154) + + // Trees + drawModels(player, 19570, 119, 122, 134, 135, 137) + drawModels(player, 19569, 98, 102, 114, 115, 117) + drawModels(player, 19568, 79, 82, 94, 95, 97) + drawModels(player, 19521, 101, 103, 113) + drawModels(player, 19519, 81, 83, 93) + + // Clouds + drawModels(player, 19525, 200, 224, 171, 215) + drawModels(player, 19524, 201, 225, 172, 216) + drawModels(player, 19526, 202, 226, 173, 217) + + // Building + drawModels(player, 19753, 85) + drawModels(player, 19744, 105, 125) + drawModels(player, 19749, 145) + drawModels(player, 19760, 86, 88) + drawModels(player, 19763, 106) + drawModels(player, 19745, 126, 128) + drawModels(player, 19750, 146) + drawModels(player, 19755, 166) + drawModels(player, 19759, 87) + drawModels(player, 19764, 107) + drawModels(player, 19746, 127) + drawModels(player, 19751, 147) + drawModels(player, 19756, 167) + drawModels(player, 19765, 108) + drawModels(player, 19752, 148) + drawModels(player, 19757, 168) + drawModels(player, 19761, 89) + drawModels(player, 19743, 109, 129) + drawModels(player, 19754, 149) + + // Cloud anomaly + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 187, 192, 236) + } + + private fun drawVarrockScreenThree(player: Player) { + // Ground + drawModels(player, 19742, 40) + drawModels(player, 19732, 45) + drawModels(player, 19733, 50) + drawModels(player, 19734, 55) + + // Trees + drawModels(player, 19570, 119, 120) + drawModels(player, 19569, 98, 100) + drawModels(player, 19568, 79, 80) + drawModels(player, 19521, 101) + drawModels(player, 19519, 81) + + // Birds + drawAnimatedModels(player, MODEL_BROWN_BIRD, ANIMATION_BIRD, 2567, 100, 300, 141, 199, 225, 230) + + // Clouds + drawModels(player, 19526, 198, 202) + drawModels(player, 19525, 201) + + // Building + drawModels(player, 19729, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94) + drawModels(player, 19729, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114) + drawModels(player, 19729, 123, 124, 126, 127, 129, 130, 132, 133, 134) + drawModels(player, 19730, 125, 128, 131) + drawModels(player, 19724, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154) + drawModels(player, 19725, 163, 167, 171) + drawModels(player, 19726, 164, 168, 172) + drawModels(player, 19727, 183, 187, 191) + drawModels(player, 19728, 184, 188, 192) + + // Landing base + drawModels(player, 19567, 97) + } + + private fun drawCastleWarsScreen(player: Player, screen: Int) { + when (screen) { + 1 -> drawCastleWarsScreenOne(player) + 2 -> drawCastleWarsScreenTwo(player) + 3 -> drawCastleWarsScreenThree(player) + } + } + + private fun drawCastleWarsScreenOne(player: Player) { + // Ground + drawModels(player, 19583, 40) + drawModels(player, 19588, 45, 50) + drawModels(player, 19589, 55) + + // Launch base + drawModels(player, 19572, 78) + + // Trees + drawModels(player, 19570, 120) + drawModels(player, 19569, 100) + drawModels(player, 19568, 80) + + // Rocks + drawModels(player, 19616, 83, 84, 93) + drawModels(player, 19615, 85, 92) + drawModels(player, 19617, 105, 112) + + // Shark + drawModels(player, 19717, 97) + + // Clouds + drawModels(player, 19525, 227, 181, 164, 169, 212, 175) + drawModels(player, 19524, 228, 182, 165, 213, 176) + drawModels(player, 19526, 229, 183, 166, 170, 214, 177) + + // Birds + drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 140, 147, 207, 130, 193, 136) + } + + private fun drawCastleWarsScreenTwo(player: Player) { + // Ground + drawModels(player, 19590, 40) + drawModels(player, 19591, 45) + drawModels(player, 19592, 50) + drawModels(player, 19593, 55) + + // Trees + drawModels(player, 19568, 95) + drawModels(player, 19569, 115) + drawModels(player, 19570, 135) + drawModels(player, 19519, 87, 88) + drawModels(player, 19521, 107, 108) + drawModels(player, 19575, 89) + drawModels(player, 19574, 90) + drawModels(player, 19577, 91) + drawModels(player, 19579, 109) + drawModels(player, 19576, 110) + drawModels(player, 19581, 111) + drawModels(player, 19580, 129) + drawModels(player, 19578, 130) + drawModels(player, 19582, 131) + drawModels(player, 19599, 92, 96) + drawModels(player, 19600, 112, 116) + drawModels(player, 19601, 132, 136) + drawModels(player, 19639, 93) + drawModels(player, 19640, 113) + drawModels(player, 19641, 133) + drawModels(player, 19642, 153) + drawModels(player, 19643, 173) + + // Rocks + drawModels(player, 19616, 85, 86) + + // Shark + drawModels(player, 19717, 79) + + // Clouds + drawModels(player, 19525, 140, 180, 189, 203, 215, 228) + drawModels(player, 19524, 141, 158, 190, 204, 216, 229, 230) + drawModels(player, 19526, 142, 159, 181, 191, 205, 217, 231) + + // Cloud anomaly + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 152, 156) + + // Birds + drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 118, 197) + } + + private fun drawCastleWarsScreenThree(player: Player) { + // Ground + drawModels(player, 19594, 40) + drawModels(player, 19584, 45) + drawModels(player, 19585, 50) + drawModels(player, 19586, 55) + + // Landing base + drawModels(player, 19567, 97) + + // Trees + drawModels(player, 19599, 78, 86, 87) + drawModels(player, 19600, 99, 106, 107) + drawModels(player, 19601, 118, 126, 127) + drawModels(player, 19568, 80, 93) + drawModels(player, 19569, 100, 113) + drawModels(player, 19570, 120, 133) + drawModels(player, 19575, 83) + drawModels(player, 19574, 84) + drawModels(player, 19577, 85) + drawModels(player, 19579, 103) + drawModels(player, 19576, 104) + drawModels(player, 19581, 105) + drawModels(player, 19580, 123) + drawModels(player, 19578, 124) + drawModels(player, 19582, 125) + drawModels(player, 19519, 92) + drawModels(player, 19521, 112) + + // Clouds + drawModels(player, 19525, 170, 183, 208, 215, 222) + drawModels(player, 19524, 171, 184, 185, 198, 209, 210, 216) + drawModels(player, 19526, 172, 186, 199, 211, 217, 223) + + // Birds + drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 140, 153, 179) + + // Cloud anomaly + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 138, 147) + } + + private fun drawGrandTreeScreen(player: Player, screen: Int) { + when (screen) { + 1 -> drawGrandTreeScreenOne(player) + 2 -> drawGrandTreeScreenTwo(player) + 3 -> drawGrandTreeScreenThree(player) + } + } + + private fun drawGrandTreeScreenOne(player: Player) { + // Ground + drawModels(player, 19560, 40) + drawModels(player, 19561, 45) + drawModels(player, 19562, 50, 55) + + // Launch base + drawModels(player, 19572, 138) + + // Mountain + drawModels(player, 19607, 118) + drawModels(player, 19611, 119) + drawModels(player, 19608, 98, 99) + drawModels(player, 19612, 100) + drawModels(player, 19609, 78, 79, 80) + drawModels(player, 19613, 81) + + // Rocks + drawModels(player, 19616, 93, 97) + drawModels(player, 19615, 84, 90) + drawModels(player, 19617, 104, 110) + drawModels(player, 19622, 89) + + // Shark + drawModels(player, 19717, 85, 94) + + // Clouds + drawModels(player, 19525, 186, 192, 201, 230) + drawModels(player, 19524, 187, 193, 194, 202, 231) + drawModels(player, 19526, 188, 195, 203, 232) + + // Birds + drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 191, 229, 237, 144, 130) + + // Cloud anomaly + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 214) + } + + private fun drawGrandTreeScreenTwo(player: Player) { + // Ground + drawModels(player, 19634, 40) + drawModels(player, 19636, 45) + drawModels(player, 19637, 50) + drawModels(player, 19638, 55) + + // Trees + drawModels(player, 19522, 79) + drawModels(player, 19639, 80, 82, 84, 87, 92) + drawModels(player, 19640, 100, 102, 104, 107, 112) + drawModels(player, 19641, 127, 132) + drawModels(player, 19642, 120, 122, 124, 147, 152) + drawModels(player, 19643, 140, 142, 144, 167, 172) + drawModels(player, 19519, 81, 83, 91) + drawModels(player, 19521, 101, 103, 111) + drawModels(player, 19575, 88) + drawModels(player, 19574, 89) + drawModels(player, 19577, 90) + drawModels(player, 19579, 108) + drawModels(player, 19576, 109) + drawModels(player, 19581, 110) + drawModels(player, 19580, 128) + drawModels(player, 19578, 129) + drawModels(player, 19582, 130) + drawModels(player, 19599, 94, 95) + drawModels(player, 19600, 114, 115) + drawModels(player, 19601, 134, 135) + drawModels(player, 19523, 96, 97) + drawModels(player, 19529, 116, 117) + + // Clouds + drawModels(player, 19525, 191, 200, 203, 208, 214) + drawModels(player, 19524, 204, 215, 216) + drawModels(player, 19526, 192, 201, 205, 209, 217) + + // Birds + drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 219, 183, 154, 196, 197, 149, 150) + + // Cloud anomaly + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 181, 220, 224, 228) + } + + private fun drawGrandTreeScreenThree(player: Player) { + // Ground + drawModels(player, 19713, 40) + drawModels(player, 19714, 45) + drawModels(player, 19715, 50) + drawModels(player, 19716, 55) + + // Landing base + drawModels(player, 19567, 97) + + // Waterfall + drawModels(player, 19644, 87) + drawModels(player, 19645, 88) + drawModels(player, 19646, 89) + drawModels(player, 19647, 90) + drawModels(player, 19648, 91) + drawModels(player, 19649, 92) + drawModels(player, 19650, 99) + drawModels(player, 19651, 98) + drawModels(player, 19652, 100) + drawModels(player, 19653, 101) + drawModels(player, 19654, 78) + drawModels(player, 19655, 102) + drawModels(player, 19656, 103) + drawModels(player, 19657, 104) + drawModels(player, 19658, 105) + drawModels(player, 19659, 106) + drawModels(player, 19660, 107, 108) + drawModels(player, 19661, 109) + drawModels(player, 19662, 110) + drawModels(player, 19663, 111) + drawModels(player, 19664, 112) + drawModels(player, 19665, 79) + drawModels(player, 19666, 120) + drawModels(player, 19667, 121) + drawModels(player, 19668, 122) + drawModels(player, 19669, 123) + drawModels(player, 19670, 124) + drawModels(player, 19671, 125) + drawModels(player, 19672, 126) + drawModels(player, 19673, 127) + drawModels(player, 19674, 128) + drawModels(player, 19675, 129) + drawModels(player, 19676, 80) + drawModels(player, 19677, 130) + drawModels(player, 19678, 131) + drawModels(player, 19679, 132) + drawModels(player, 19680, 140) + drawModels(player, 19681, 141) + drawModels(player, 19682, 142) + drawModels(player, 19683, 143) + drawModels(player, 19684, 144) + drawModels(player, 19685, 145) + drawModels(player, 19686, 146) + drawModels(player, 19687, 81) + drawModels(player, 19688, 147) + drawModels(player, 19689, 148) + drawModels(player, 19690, 149) + drawModels(player, 19691, 150) + drawModels(player, 19692, 151) + drawModels(player, 19693, 161) + drawModels(player, 19694, 162) + drawModels(player, 19695, 163) + drawModels(player, 19696, 164) + drawModels(player, 19697, 165) + drawModels(player, 19698, 82) + drawModels(player, 19699, 166) + drawModels(player, 19700, 167) + drawModels(player, 19701, 168) + drawModels(player, 19702, 169) + drawModels(player, 19703, 170) + drawModels(player, 19704, 182) + drawModels(player, 19705, 183) + drawModels(player, 19706, 187) + drawModels(player, 19707, 188) + drawModels(player, 19708, 189) + drawModels(player, 19709, 83) + drawModels(player, 19710, 84) + drawModels(player, 19711, 85) + drawModels(player, 19712, 86) + + // Clouds + drawModels(player, 19525, 174, 198, 212) + drawModels(player, 19524, 199, 213) + drawModels(player, 19526, 175, 200, 214) + + // Birds + drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 178, 225) + } + +} \ No newline at end of file diff --git a/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt new file mode 100644 index 000000000..e909c4b18 --- /dev/null +++ b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt @@ -0,0 +1,386 @@ +package content.global.travel.balloon + +import content.data.Quests +import content.region.misc.quest.enlightenedjourney.dialogue.AugusteDialogueFile +import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney +import core.api.amountInInventory +import core.api.animateInterface +import core.api.animationDuration +import core.api.closeInterface +import core.api.findLocalNPC +import core.api.getAttribute +import core.api.getStatLevel +import core.api.getVarbit +import core.api.isQuestComplete +import core.api.lock +import core.api.openDialogue +import core.api.openInterface +import core.api.queueScript +import core.api.removeItem +import core.api.rewardXP +import core.api.sendMessage +import core.api.setAttribute +import core.api.setComponentVisibility +import core.api.setVarbit +import core.api.stopExecuting +import core.api.teleport +import core.api.unlock +import core.cache.def.impl.ItemDefinition +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.interaction.InterfaceListener +import core.game.interaction.QueueStrength +import core.game.node.entity.player.Player +import core.game.node.entity.skill.Skills +import core.game.node.item.Item +import core.game.world.map.Location +import core.game.world.update.flag.context.Animation +import core.plugin.Initializable +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +/** + * Handles the balloon transportation map interface. + * @author Edith + */ + +private const val ASSISTANT_STAN_WRAPPER = 5062 +private const val ASSISTANT_MARROW_WRAPPER = 5063 +private const val ASSISTANT_LE_SMITH_WRAPPER = 5064 +private const val ASSISTANT_BROCK_WRAPPER = 5065 +private const val ASSISTANT_SERF_WRAPPER = 5066 + +private val BALLOON_VISIBLE_NPCS = intArrayOf( + NPCs.AUGUSTE_5049, + NPCs.ASSISTANT_STAN_5057, + NPCs.ASSISTANT_MARROW_5055, + NPCs.ASSISTANT_LE_SMITH_5056, + NPCs.ASSISTANT_BROCK_5054, + NPCs.ASSISTANT_SERF_5053 +) + +private val BALLOON_ASSISTANT_NPCS = intArrayOf( + NPCs.ASSISTANT_STAN_5057, + NPCs.ASSISTANT_MARROW_5055, + NPCs.ASSISTANT_LE_SMITH_5056, + NPCs.ASSISTANT_BROCK_5054, + NPCs.ASSISTANT_SERF_5053 +) + +private val BALLOON_BASKET_LOCS = intArrayOf(19128, 19129) + +@Initializable +class BalloonTravelInterface : InterfaceListener, InteractionListener { + + companion object { + private const val BALLOON_MAP_INTERFACE = 469 + private const val BALLOON_MAP_MODEL = 12 + + private const val ATTRIBUTE_BALLOON_START = "balloon_travel_start" + + /** Opens the balloon map interface. */ + fun open(player: Player, start: BalloonTravelLocation) { + setAttribute(player, ATTRIBUTE_BALLOON_START, start) + openInterface(player, BALLOON_MAP_INTERFACE) + setComponentVisibility(player, BALLOON_MAP_INTERFACE, start.mapComponent, false) + } + + /** Checks the saved route unlock state. */ + private fun hasRouteUnlocked(player: Player, destination: BalloonTravelLocation): Boolean { + return getVarbit(player, destination.varbit) > 0 + } + + /** Checks if the player can use an unlocked route. */ + private fun canUseRoute(player: Player, destination: BalloonTravelLocation): Boolean { + if (!hasRouteUnlocked(player, destination)) { + return false + } + + if (getStatLevel(player, Skills.FIREMAKING) < destination.requiredFiremakingLevel) { + sendMessage( + player, + "You require a Firemaking level of ${destination.requiredFiremakingLevel} to travel there." + ) + return false + } + + if (amountInInventory(player, destination.log) < 1) { + sendMessage(player, "You need some logs to fuel the balloon.") + return false + } + if (destination == BalloonTravelLocation.ENTRANA) { + if (!ItemDefinition.canEnterEntrana(player)) { + sendMessage( + player, + "I'm sorry, no weapons or armour may be worn to Entrana. Come back when you have laid them down." + ) + return false + } + sendMessage(player, "You are quickly searched.") + } + return true + } + + private fun canAttemptRouteUnlock( + player: Player, + start: BalloonTravelLocation, + destination: BalloonTravelLocation + ): Boolean { + if (start != BalloonTravelLocation.ENTRANA) { + return false + } + + if (destination == BalloonTravelLocation.ENTRANA || destination == BalloonTravelLocation.TAVERLEY) { + return false + } + + if (getStatLevel(player, Skills.FIREMAKING) < destination.requiredFiremakingLevel) { + sendMessage( + player, + "You require a Firemaking level of ${destination.requiredFiremakingLevel} to travel there." + ) + return false + } + + if (amountInInventory(player, destination.log) < destination.unlockLogAmount) { + sendMessage(player, "You need some logs to fuel the balloon.") + return false + } + return true + } + + /** Completes a normal balloon trip. */ + private fun balloonTravel(player: Player, start: BalloonTravelLocation, destination: BalloonTravelLocation) { + if (removeItem(player, Item(destination.log, 1))) { + val animation = BalloonTravelLocation.getMapAnimation(start, destination) + val duration = animationDuration(Animation(animation)) + + lock(player, duration) + setComponentVisibility(player, BALLOON_MAP_INTERFACE, start.mapComponent, true) + setComponentVisibility(player, BALLOON_MAP_INTERFACE, BALLOON_MAP_MODEL, false) + animateInterface(player, BALLOON_MAP_INTERFACE, BALLOON_MAP_MODEL, animation) + + queueScript(player, duration, QueueStrength.SOFT) { + closeInterface(player) + teleport(player, destination.destination) + unlock(player) + return@queueScript stopExecuting(player) + } + } + } + + private fun unlockRoute(player: Player, destination: BalloonTravelLocation) { + if (removeItem(player, Item(destination.log, destination.unlockLogAmount))) { + BalloonFlightInterface.startUnlockFlight(player, destination) + } + } + + fun unlockDestination(player: Player, destination: BalloonTravelLocation) { + if (hasRouteUnlocked(player, destination)) { + return + } + + setVarbit(player, destination.varbit, 1, true) + rewardXP(player, Skills.FIREMAKING, 2000.0) + } + + } + + override fun defineInterfaceListeners() { + on(BALLOON_MAP_INTERFACE) { player, _, _, selectId, _, _ -> + val destination = BalloonTravelLocation.fromSelectId(selectId) ?: return@on false + val start = getAttribute(player, ATTRIBUTE_BALLOON_START, BalloonTravelLocation.ENTRANA) + + if (destination == start) { + return@on true + } + + if (hasRouteUnlocked(player, destination)) { + if (canUseRoute(player, destination)) { + balloonTravel(player, start, destination) + } + return@on true + } + + if (canAttemptRouteUnlock(player, start, destination)) { + unlockRoute(player, destination) + return@on true + } + + return@on true + } + } + + override fun defineListeners() { + on(BALLOON_VISIBLE_NPCS, IntType.NPC, "fly") { player, node -> + if (!isQuestComplete(player, Quests.ENLIGHTENED_JOURNEY)) { + return@on true + } + + val start = BalloonTravelLocation.fromNpcId(node.id) ?: return@on false + open(player, start) + return@on true + } + + on(BALLOON_ASSISTANT_NPCS, IntType.NPC, "talk-to") { player, node -> + if (!isQuestComplete(player, Quests.ENLIGHTENED_JOURNEY)) { + return@on true + } + + val start = BalloonTravelLocation.fromNpcId(node.id) ?: return@on false + openDialogue(player, BalloonAssistantsDialogue(start), node.asNpc()) + return@on true + } + + on(BALLOON_BASKET_LOCS, IntType.SCENERY, "use") { player, node -> + val start = BalloonTravelLocation.fromSceneryId(node.asScenery().wrapper.id) ?: return@on false + val routeNpc = findLocalNPC(player, start.npc) ?: return@on true + + if (routeNpc.getShownNPC(player).id == NPCs.AUGUSTE_5049) { + openDialogue(player, AugusteDialogueFile(), routeNpc) + } else { + if (!isQuestComplete(player, Quests.ENLIGHTENED_JOURNEY)) { + return@on true + } + openDialogue(player, BalloonAssistantsDialogue(start), routeNpc) + } + return@on true + } + } +} + +/** Balloon locations used by the transportation map. */ +enum class BalloonTravelLocation( + val selection: Int, + val mapComponent: Int, + val destination: Location, + val log: Int, + val unlockLogAmount: Int, + val requiredFiremakingLevel: Int, + val varbit: Int, + val npc: Int, + val scenery: Int +) { + CASTLE_WARS( + 14, + 24, + Location.create(2462, 3108, 0), + Items.YEW_LOGS_1515, + 10, + 50, + EnlightenedJourney.VARBIT_CASTLEWARS_BALLOON, + ASSISTANT_MARROW_WRAPPER, + 19137, + ), + GRAND_TREE( + 15, + 23, + Location.create(2480, 3458, 0), + Items.MAGIC_LOGS_1513, + 3, + 60, + EnlightenedJourney.VARBIT_GRANDTREE_BALLOON, + ASSISTANT_LE_SMITH_WRAPPER, + 19139, + ), + CRAFTING_GUILD( + 16, + 20, + Location.create(2924, 3303, 0), + Items.OAK_LOGS_1521, + 10, + 30, + EnlightenedJourney.VARBIT_CRAFTINGGUILD_BALLOON, + ASSISTANT_BROCK_WRAPPER, + 19141, + ), + ENTRANA( + 17, + 25, + Location.create(2809, 3356, 0), + Items.LOGS_1511, + 1, + 20, + EnlightenedJourney.VARBIT_ENTRANA_BALLOON, + NPCs.AUGUSTE_5049, + 19133, + ), + TAVERLEY( + 18, + 22, + Location.create(2941, 3420, 0), + Items.LOGS_1511, + 1, + 20, + EnlightenedJourney.VARBIT_TAVERLEY_BALLOON, + ASSISTANT_STAN_WRAPPER, + 19135, + ), + VARROCK( + 19, + 21, + Location.create(3298, 3481, 0), + Items.WILLOW_LOGS_1519, + 10, + 40, + EnlightenedJourney.VARBIT_VARROCK_BALLOON, + ASSISTANT_SERF_WRAPPER, + 19143, + ); + + companion object { + private val selectionMap = values().associateBy { it.selection } + private val npcMap = values().associateBy { it.npc } + private val sceneryMap = values().associateBy { it.scenery } + + private val mapAnimation = mapOf( + ENTRANA to TAVERLEY to 5110, + TAVERLEY to ENTRANA to 5111, + ENTRANA to CRAFTING_GUILD to 5112, + CRAFTING_GUILD to ENTRANA to 5113, + ENTRANA to VARROCK to 5114, + VARROCK to ENTRANA to 5115, + ENTRANA to GRAND_TREE to 5116, + GRAND_TREE to ENTRANA to 5117, + ENTRANA to CASTLE_WARS to 5118, + CASTLE_WARS to ENTRANA to 5119, + VARROCK to CRAFTING_GUILD to 5120, + CRAFTING_GUILD to VARROCK to 5121, + VARROCK to TAVERLEY to 5122, + TAVERLEY to VARROCK to 5123, + TAVERLEY to CRAFTING_GUILD to 5124, + CRAFTING_GUILD to TAVERLEY to 5125, + TAVERLEY to CASTLE_WARS to 5126, + CASTLE_WARS to TAVERLEY to 5127, + CRAFTING_GUILD to CASTLE_WARS to 5128, + CASTLE_WARS to CRAFTING_GUILD to 5129, + VARROCK to CASTLE_WARS to 5130, + CASTLE_WARS to VARROCK to 5131, + GRAND_TREE to CASTLE_WARS to 5132, + CASTLE_WARS to GRAND_TREE to 5133, + GRAND_TREE to CRAFTING_GUILD to 5134, + CRAFTING_GUILD to GRAND_TREE to 5135, + TAVERLEY to GRAND_TREE to 5136, + GRAND_TREE to TAVERLEY to 5137, + VARROCK to GRAND_TREE to 5138, + GRAND_TREE to VARROCK to 5139 + ) + + fun getMapAnimation(start: BalloonTravelLocation, destination: BalloonTravelLocation): Int { + return mapAnimation[start to destination] ?: 0 + } + + fun fromSelectId(selectId: Int): BalloonTravelLocation? { + return selectionMap[selectId] + } + + fun fromNpcId(npc: Int): BalloonTravelLocation? { + return npcMap[npc] + } + + fun fromSceneryId(scenery: Int): BalloonTravelLocation? { + return sceneryMap[scenery] + } + } + +} \ No newline at end of file diff --git a/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt b/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt new file mode 100644 index 000000000..b5b7a5e45 --- /dev/null +++ b/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt @@ -0,0 +1,71 @@ +package content.region.misc.quest.enlightenedjourney.cutscene + +import content.data.Quests +import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_FLIGHT +import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.VARBIT_ENTRANA_BALLOON +import core.api.face +import core.api.setQuestStage +import core.api.setVarbit +import core.game.activity.Cutscene +import core.game.node.entity.player.Player +import core.game.world.map.Direction +import core.game.world.map.Location +import core.net.packet.PacketRepository +import core.net.packet.context.MusicContext +import core.net.packet.out.MusicPacket +import org.rs09.consts.NPCs + +/** + * Enlightened Journey cutscene where the main balloon is constructed. + * @author Edith + */ + +class BalloonConstructionCutscene(player: Player) : Cutscene(player) { + override fun setup() { + setExit(Location.create(player.location)) + loadRegion(11060) + addNPC(NPCs.AUGUSTE_5049, 57, 26, Direction.WEST) + } + + override fun runStage(stage: Int) { + when (stage) { + 0 -> { + fadeToBlack() + timedUpdate(6) + } + + 1 -> { + teleport(player, 56, 26, 0) + moveCamera(41, 25, 2000) + rotateCamera(56, 27) + val obj = getObject(55, 26)!! + face(player, obj.location) + fadeFromBlack() + PacketRepository.send(MusicPacket::class.java, MusicContext(player, 116, true)) + setVarbit(player, VARBIT_ENTRANA_BALLOON, 2, true) + timedUpdate(5) + } + + 2 -> { + move(getNPC(NPCs.AUGUSTE_5049)!!, 56, 27) + timedUpdate(1) + } + + 3 -> { + moveCamera(39, 25, 200, 2) + timedUpdate(3) + } + + 4 -> { + moveCamera(38, 24, 2000, 2) + timedUpdate(3) + } + + 5 -> { + end { + setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, STAGE_FLIGHT) + } + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt b/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt new file mode 100644 index 000000000..7404b443c --- /dev/null +++ b/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt @@ -0,0 +1,97 @@ +package content.region.misc.quest.enlightenedjourney.cutscene + +import content.data.Quests +import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_FIRST_EXPERIMENT +import core.api.face +import core.api.setQuestStage +import core.api.visualize +import core.game.activity.Cutscene +import core.game.dialogue.FacialExpression +import core.game.node.entity.impl.Projectile +import core.game.node.entity.player.Player +import core.game.world.map.Direction +import core.game.world.map.Location +import core.net.packet.PacketRepository +import core.net.packet.context.MusicContext +import core.net.packet.out.MusicPacket +import org.rs09.consts.NPCs + +/** + * Enlightened Journey cutscene where the balloon catches on fire. + * @author Edith + */ + +class BalloonExperimentCutscene(player: Player) : Cutscene(player) { + override fun setup() { + setExit(Location.create(player.location)) + loadRegion(11060) + } + + override fun runStage(stage: Int) { + when (stage) { + 0 -> { + fadeToBlack() + timedUpdate(6) + } + + 1 -> { + teleport(player, 56, 27, 0) + face(player, Location.create(440, 25, 0)) + moveCamera(58, 30, 350) + rotateCamera(54, 18, 400) + addNPC(NPCs.AUGUSTE_5049, 57, 27, Direction.SOUTH_WEST) + fadeFromBlack() + PacketRepository.send(MusicPacket::class.java, MusicContext(player, 116, true)) + timedUpdate(6) + } + + 2 -> { + visualize(player, 5142, 877) + timedUpdate(2) + } + + 3 -> { + Projectile + .create(player, null, 879, 45, 45, 1, 70, 0) + .transform( + player, + player.location.transform(Direction.SOUTH, player.direction.ordinal + 1), + false, + 70, + 140 + ) + .send() + timedUpdate(3) + } + + 4 -> { + moveCamera(63, 29, 600) + rotateCamera(55, 23, 600) + timedUpdate(3) + } + + 5 -> { + face(getNPC(NPCs.AUGUSTE_5049)!!, player, 2) + face(player, getNPC(NPCs.AUGUSTE_5049)!!, 2) + timedUpdate(2) + } + + 6 -> dialogueUpdate(NPCs.AUGUSTE_5049, FacialExpression.HAPPY, "That was perfect. My hypothesis was right!") + 7 -> playerDialogueUpdate(FacialExpression.HALF_WORRIED, "Did you not see the burning?") + 8 -> dialogueUpdate(NPCs.AUGUSTE_5049, FacialExpression.HAPPY, "One more test. Then we shall proceed.") + 9 -> playerDialogueUpdate(FacialExpression.HALF_WORRIED, "Burning? Fire? Hello?") + 10 -> dialogueUpdate( + NPCs.AUGUSTE_5049, + FacialExpression.HAPPY, + "We shall meekly go! No...no...it needs to sound grander. We shall cautiously go..." + ) + + 11 -> playerDialogueUpdate(FacialExpression.HALF_WORRIED, "We're doomed.") + 12 -> { + end { + setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, STAGE_FIRST_EXPERIMENT) + } + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt b/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt new file mode 100644 index 000000000..a8a55faf6 --- /dev/null +++ b/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt @@ -0,0 +1,107 @@ +package content.region.misc.quest.enlightenedjourney.cutscene + +import content.data.Quests +import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_SECOND_EXPERIMENT +import core.api.animate +import core.api.face +import core.api.sendChat +import core.api.setQuestStage +import core.api.visualize +import core.game.activity.Cutscene +import core.game.dialogue.FacialExpression +import core.game.node.entity.impl.Projectile +import core.game.node.entity.player.Player +import core.game.world.map.Direction +import core.game.world.map.Location +import core.net.packet.PacketRepository +import core.net.packet.context.MusicContext +import core.net.packet.out.MusicPacket +import org.rs09.consts.NPCs + +/** + * Enlightened Journey cutscene where the balloon catches on fire AND is chased by the four stooges. + * @author Edith + */ + +class SecondBalloonExperimentCutscene(player: Player) : Cutscene(player) { + + override fun setup() { + setExit(Location.create(player.location)) + loadRegion(11060) + } + + override fun runStage(stage: Int) { + when (stage) { + 0 -> { + fadeToBlack() + timedUpdate(6) + } + + 1 -> { + teleport(player, 56, 27, 0) + face(player, Location.create(440, 25, 0)) + moveCamera(58, 30, 350) + rotateCamera(54, 18, 400) + addNPC(NPCs.AUGUSTE_5049, 57, 27, Direction.SOUTH_WEST) + fadeFromBlack() + PacketRepository.send(MusicPacket::class.java, MusicContext(player, 116, true)) + timedUpdate(6) + } + + 2 -> { + visualize(player, 5142, 877) + timedUpdate(2) + } + + 3 -> { + Projectile + .create(player, null, 879, 45, 45, 1, 70, 0) + .transform( + player, + player.location.transform(Direction.SOUTH, player.direction.ordinal + 1), + false, + 70, + 140 + ) + .send() + timedUpdate(3) + } + + 4 -> { + addNPC(NPCs.BOB_5058, 58, 23, Direction.WEST) + addNPC(NPCs.CURLY_5059, 59, 24, Direction.WEST) + addNPC(NPCs.MOE_5060, 60, 23, Direction.WEST) + addNPC(NPCs.LARRY_5061, 59, 22, Direction.WEST) + moveCamera(63, 23, 600) + rotateCamera(57, 24, 400, 1000) + timedUpdate(4) + } + + 5 -> { + move(getNPC(NPCs.BOB_5058)!!, 53, 23) + move(getNPC(NPCs.CURLY_5059)!!, 53, 24) + move(getNPC(NPCs.MOE_5060)!!, 54, 23) + move(getNPC(NPCs.LARRY_5061)!!, 53, 22) + sendChat(getNPC(NPCs.BOB_5058)!!, "Destroy the floating thing!") + timedUpdate(5) + } + + 6 -> { + moveCamera(56, 23, 400, 1000) + rotateCamera(56, 27, 200, 1000) + timedUpdate(1) + } + + 7 -> { + animate(player, 2113) + playerDialogueUpdate(FacialExpression.NEUTRAL, "Well, that went down like a lead balloon.") + } + + 8 -> { + end { + setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, STAGE_SECOND_EXPERIMENT) + } + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/misc/quest/enlightenedjourney/dialogue/AugusteDialogue.kt b/Server/src/main/content/region/misc/quest/enlightenedjourney/dialogue/AugusteDialogue.kt new file mode 100644 index 000000000..9f2412690 --- /dev/null +++ b/Server/src/main/content/region/misc/quest/enlightenedjourney/dialogue/AugusteDialogue.kt @@ -0,0 +1,980 @@ +package content.region.misc.quest.enlightenedjourney.dialogue + +import content.data.Quests +import content.global.travel.balloon.BalloonFlightInterface +import content.global.travel.balloon.BalloonTravelInterface +import content.global.travel.balloon.BalloonTravelLocation +import content.region.misc.quest.enlightenedjourney.cutscene.BalloonExperimentCutscene +import content.region.misc.quest.enlightenedjourney.cutscene.SecondBalloonExperimentCutscene +import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney +import core.api.addItem +import core.api.amountInBank +import core.api.amountInInventory +import core.api.finishQuest +import core.api.freeSlots +import core.api.getAttribute +import core.api.getQuest +import core.api.getQuestStage +import core.api.hasAnItem +import core.api.inEquipment +import core.api.openDialogue +import core.api.openInterface +import core.api.removeItem +import core.api.sendMessage +import core.api.setAttribute +import core.api.setQuestStage +import core.api.teleport +import core.cache.def.impl.ItemDefinition +import core.game.dialogue.DialogueLabeller +import core.game.dialogue.DialogueOption +import core.game.dialogue.DialoguePlugin +import core.game.dialogue.FacialExpression +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.node.entity.player.Player +import core.game.node.item.Item +import core.game.world.map.Location +import core.plugin.Initializable +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +/** + * Dialogue between Auguste and the player for the Enlightened Journey quest. + * @author Edith + */ + +@Initializable +class AugusteDialogue(player: Player? = null) : DialoguePlugin(player) { + override fun newInstance(player: Player): DialoguePlugin { + return AugusteDialogue(player) + } + + override fun handle(interfaceId: Int, buttonId: Int): Boolean { + openDialogue(player, AugusteDialogueFile(), npc) + return false + } + + override fun getIds(): IntArray { + return intArrayOf(NPCs.AUGUSTE_5049) + } +} + +class AugusteTalkListener : InteractionListener { + override fun defineListeners() { + on(NPCs.AUGUSTE_5049, IntType.NPC, "talk-to") { player, node -> + openDialogue(player, AugusteDialogueFile(), node.asNpc()) + return@on true + } + } +} + +private fun checkAllItemsDelivered(player: Player) { + val allDelivered = getAttribute(player, EnlightenedJourney.ATTRIBUTE_YELLOW_DYE_DELIVERED, false) && + getAttribute(player, EnlightenedJourney.ATTRIBUTE_RED_DYE_DELIVERED, false) && + getAttribute(player, EnlightenedJourney.ATTRIBUTE_SANDBAGS_DELIVERED, false) && + getAttribute(player, EnlightenedJourney.ATTRIBUTE_SILK_DELIVERED, false) && + getAttribute(player, EnlightenedJourney.ATTRIBUTE_BOWL_DELIVERED, false) + if (allDelivered) { + setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, EnlightenedJourney.STAGE_WILLOW_BASKET) + } +} + +private fun questStageLabel(stage: Int) = "quest_stage_$stage" + +private fun hasBomberCap(player: Player): Boolean { + return hasAnItem(player, arrayOf(Items.BOMBER_CAP_9945, Items.CAP_AND_GOGGLES_9946), false).exists() +} + +private fun hasBomberJacket(player: Player): Boolean { + return hasAnItem(player, Items.BOMBER_JACKET_9944).exists() +} + +private fun hasLostBomberReward(player: Player): Boolean { + return !hasBomberCap(player) || !hasBomberJacket(player) +} + +private fun hasCapAndGoggles(player: Player): Boolean { + val hasCap = amountInInventory(player, Items.BOMBER_CAP_9945) >= 1 || inEquipment(player, Items.BOMBER_CAP_9945) + val hasGoggles = amountInInventory(player, Items.GNOME_GOGGLES_9472) >= 1 || inEquipment(player, Items.GNOME_GOGGLES_9472) + return hasCap && hasGoggles +} + +class AugusteDialogueFile : DialogueLabeller() { + override fun addConversation() { + assignToIds(NPCs.AUGUSTE_5049) + exec { player, _ -> + loadLabel(player, "quest_stage_" + getQuestStage(player, Quests.ENLIGHTENED_JOURNEY)) + } + + label("quest_stage_0") + npc(FacialExpression.HAPPY, "Greetings! Would you like to be my number one accomplice? I mean, assistant?") + player(FacialExpression.ASKING, "Who are you?") + npc(FacialExpression.HAPPY, "I am Auguste. I am going to be the first balloonist in all of Gielinor!") + player(FacialExpression.HALF_THINKING, "Balloo-what? I thought only monks lived on Entrana.") + npc( + FacialExpression.SUSPICIOUS, + "Well, they do...I was a monk. But I'm so sick of living on this island! I want to explore new frontiers!" + ) + player(FacialExpression.LAUGH, "And go where no man has gone before?") + npc(FacialExpression.HAPPY, "Maybe! That sounds good. I was thinking just over to Taverley, though.") + player(FacialExpression.ASKING, "Why not take the boat then?") + npc(FacialExpression.ANGRY, "Ugh! Ocean! Don't talk to me about the ocean...oh dear...I think I feel ill.") + player( + FacialExpression.AMAZED_TALKING, + "Whoa, ok, no ocean. How exactly are you going to get off the island, then?" + ) + npc( + FacialExpression.NEUTRAL, + "I have devised a new way to travel. But I need an assistant balloonist to help me build my design." + ) + npc(FacialExpression.HALF_ASKING, "Are you an experienced adventurer willing to help me?") + options( + DialogueOption("sign_me_up", "Yes! Sign me up.", "Yes! Sign me up.", FacialExpression.FRIENDLY), + DialogueOption("not_right_now", "Not right now.", "Not right now.") + ) + + label("sign_me_up") + exec { player, _ -> + if (!getQuest(player, Quests.ENLIGHTENED_JOURNEY).hasRequirements(player)) { + loadLabel(player, "requirements_not_met") + } + } + npc(FacialExpression.HAPPY, "Wonderful! Let's get started.") + player(FacialExpression.HALF_THINKING, "Wait. I still don't know exactly what we're doing.") + npc( + FacialExpression.AMAZED_TALKING, + "Of course, of course, how foolish of me. Well, we are going to make a balloon." + ) + player(FacialExpression.HALF_THINKING, "Which is what exactly?") + npc(FacialExpression.HAPPY, "Let me show you!") + exec { player, _ -> + openInterface(player, 472) + setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, EnlightenedJourney.STAGE_QUEST_STARTED) + } + + label("requirements_not_met") + exec { player, _ -> + sendMessage(player, "You do not meet the requirements to start : 'Enlightened Journey'.") + } + + label(questStageLabel(EnlightenedJourney.STAGE_QUEST_STARTED)) + player(FacialExpression.LAUGH, "How exactly do you plan to get to Taverley in that? How will it work?") + npc(FacialExpression.FRIENDLY, "Have you noticed how ashes float above fires for long periods of time?") + goto("ashes_float") + + label("ashes_float") + options( + DialogueOption( + "whats_your_point", + "Umm, yes. What's your point?", + "What's your point?", + FacialExpression.THINKING + ), + DialogueOption( + "cant_see_detail", + "Err, no. I can't see that kind of detail.", + "Err, no. I can't see that kind of detail." + ) + ) + + label("cant_see_detail") + npc("You don't? Oh...well...it's just, they rise, you know, from the fire... Maybe you should pay more attention to things!") + goto("ashes_float") + + label("whats_your_point") + npc(FacialExpression.HAPPY, "Don't you see? It's the hot air! It rises, taking the ashes with it.") + npc( + FacialExpression.HAPPY, + "I had this epiphany while I was at the glass blower's house. If we pump hot air into an envelope it will rise because it is lighter than the cold air around it." + ) + player(FacialExpression.HALF_THINKING, "Come again?") + npc("We are going to sew a big sack and light a fire under it. Once the sack fills with hot air it will begin to rise, taking us along with it in the basket.") + player(FacialExpression.HALF_WORRIED, "You seem pretty confident about this. Have you tested it?") + npc( + FacialExpression.SAD_TALKING, + "Well, no. You see, I don't have the materials here to make any test balloons." + ) + npc(FacialExpression.HAPPY, "That's where you come in!") + npc(FacialExpression.HAPPY, "You are going to collect materials for two test runs of the balloon.") + npc( + FacialExpression.HAPPY, + "You will need to get three sheets of papyrus, one ball of wool, one full sack of potatoes, and one unlit candle." + ) + player(FacialExpression.THINKING, "What am I supposed to do with all that junk?") + npc("When you have all of it, bring it to me and I'll explain what to do next. Any questions?") + player("Where do I get all this stuff?") + npc( + FacialExpression.ANGRY, + "You're the adventurer, you should know! Think of logical places, like, churches; they have tons of candles." + ) + exec { player, _ -> + setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, EnlightenedJourney.STAGE_GATHER_MATERIALS) + } + + + label(questStageLabel(EnlightenedJourney.STAGE_GATHER_MATERIALS)) + npc(FacialExpression.ASKING, "Have you gotten the materials?") + options( + DialogueOption("are_materials_gathered?", "Yes.", "Yes.", FacialExpression.HAPPY), + DialogueOption("failure_not_option", "No.", "No."), + DialogueOption("what_materials_needed", "What do I need to get again?", "What do I need to get again?") + ) + + label("are_materials_gathered?") + exec { player, _ -> + if (amountInInventory(player, Items.PAPYRUS_970) >= 3 + && amountInInventory(player, Items.BALL_OF_WOOL_1759) >= 1 + && amountInInventory(player, Items.POTATOES10_5438) >= 1 + && amountInInventory(player, Items.CANDLE_36) >= 1 + ) { + setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, EnlightenedJourney.STAGE_ORIGAMI_BALLOON) + loadLabel(player, "materials_are_gathered") + } else { + loadLabel(player, "missing_materials") + } + } + + label("failure_not_option") + npc("Failure is not an option.") + + label("what_materials_needed") + npc("You will need to get three sheets of papyrus, one ball of wool, one full sack of potatoes, and one unlit candle.") + + label("missing_materials") + exec { player, _ -> + val papyrus = amountInInventory(player, Items.PAPYRUS_970) + val wool = amountInInventory(player, Items.BALL_OF_WOOL_1759) >= 1 + val potatoes = amountInInventory(player, Items.POTATOES10_5438) >= 1 + val candle = amountInInventory(player, Items.CANDLE_36) >= 1 + + val hasAllPapyrus = papyrus >= 3 + val hasSomePapyrus = papyrus in 1..2 + val hasNoPapyrus = papyrus == 0 + + when { + hasNoPapyrus && !wool && !potatoes && !candle -> loadLabel(player, "missing_all_materials") + hasSomePapyrus && wool && potatoes && candle -> loadLabel(player, "missing_more_papyrus") + hasAllPapyrus && !wool && potatoes && candle -> loadLabel(player, "missing_wool") + hasAllPapyrus && wool && potatoes && !candle -> loadLabel(player, "missing_candle") + hasAllPapyrus && wool && !potatoes && candle -> loadLabel(player, "missing_potatoes") + !hasAllPapyrus && !wool && potatoes && candle -> loadLabel(player, "missing_papyrus_and_wool") + !hasAllPapyrus && wool && potatoes && !candle -> loadLabel(player, "missing_papyrus_and_candle") + !hasAllPapyrus && wool && !potatoes && candle -> loadLabel(player, "missing_papyrus_and_potatoes") + hasAllPapyrus && !wool && potatoes && !candle -> loadLabel(player, "missing_wool_and_candle") + hasAllPapyrus && !wool && !potatoes && candle -> loadLabel(player, "missing_wool_and_potatoes") + hasAllPapyrus && wool && !potatoes && !candle -> loadLabel(player, "missing_candle_and_potatoes") + !hasAllPapyrus && !wool && potatoes && !candle -> loadLabel(player, "missing_wool_papyrus_and_candle") + !hasAllPapyrus && !wool && !potatoes && candle -> loadLabel(player, "missing_wool_papyrus_and_potatoes") + !hasAllPapyrus && wool && !potatoes && !candle -> loadLabel( + player, + "missing_papyrus_potatoes_and_candle" + ) + + hasAllPapyrus && !wool && !potatoes && !candle -> loadLabel(player, "missing_wool_candle_and_potatoes") + } + } + + label("missing_all_materials") + npc(FacialExpression.SAD_TALKING, "You don't seem to have any of the materials.") + npc( + FacialExpression.SAD_TALKING, + "You need a ball of wool, three sheets of papyrus, an unlit candle, and a full sack of potatoes." + ) + + label("missing_more_papyrus") + npc(FacialExpression.SAD_TALKING, "You need more papyrus.") + + label("missing_wool") + npc(FacialExpression.SAD_TALKING, "You need a ball of wool.") + + label("missing_candle") + npc(FacialExpression.SAD_TALKING, "You need an unlit candle.") + + label("missing_potatoes") + npc(FacialExpression.SAD_TALKING, "You need a full sack of potatoes.") + + label("missing_papyrus_and_wool") + npc(FacialExpression.SAD_TALKING, "You need more papyrus and a ball of wool.") + + label("missing_papyrus_and_candle") + npc(FacialExpression.SAD_TALKING, "You need papyrus and an unlit candle.") + + label("missing_papyrus_and_potatoes") + npc(FacialExpression.SAD_TALKING, "You need more papyrus and a full sack of potatoes.") + + label("missing_wool_and_candle") + npc(FacialExpression.SAD_TALKING, "You need a ball of wool and an unlit candle.") + + label("missing_wool_and_potatoes") + npc(FacialExpression.SAD_TALKING, "You need a ball of wool and a full sack of potatoes.") + + label("missing_candle_and_potatoes") + npc(FacialExpression.SAD_TALKING, "You need an unlit candle and a full sack of potatoes.") + + label("missing_wool_papyrus_and_candle") + npc(FacialExpression.SAD_TALKING, "You need a ball of wool, an unlit candle, and papyrus.") + + label("missing_wool_papyrus_and_potatoes") + npc(FacialExpression.SAD_TALKING, "You need a ball of wool, papyrus, and a full sack of potatoes.") + + label("missing_papyrus_potatoes_and_candle") + npc(FacialExpression.SAD_TALKING, "You need more papyrus, a full sack of potatoes, and an unlit candle.") + + label("missing_wool_candle_and_potatoes") + npc(FacialExpression.SAD_TALKING, "You need a ball of wool, an unlit candle, and a full sack of potatoes.") + + label("materials_are_gathered") + npc(FacialExpression.HAPPY, "Good, you have everything! Now, I need you to create an origami balloon.") + player(FacialExpression.HALF_THINKING, "How do you make the origami balloon?") + npc( + FacialExpression.HAPPY, + "First, use the papyrus on the ball of wool. The papyrus is folded into an origami box and the yarn will support the heat source." + ) + npc( + FacialExpression.HAPPY, + "Next, add the unlit candle to the balloon structure. It will act as the heat source." + ) + npc(FacialExpression.HAPPY, "Once you have done that let me know and we will begin our experiment.") + + label(questStageLabel(EnlightenedJourney.STAGE_ORIGAMI_BALLOON)) + exec { player, _ -> + if (amountInInventory(player, Items.ORIGAMI_BALLOON_9934) >= 1) { + loadLabel(player, "first_experiment") + } else { + loadLabel(player, "no_origami_balloon") + } + } + + label("no_origami_balloon") + player("How do you make the origami balloon?") + npc("First, use the papyrus on the ball of wool. The papyrus is folded into an origami box and the yarn will support the heat source.") + npc("Next, add the unlit candle to the balloon structure. It will act as the heat source.") + npc("Once you have done that let me know and we will begin our experiment.") + + label("first_experiment") + player(FacialExpression.HAPPY, "I finished the origami balloon!") + npc(FacialExpression.HAPPY, "Wonderful! I'll take that, and we'll conduct our first experiment.") + exec { player, _ -> + removeItem(player, Item(Items.ORIGAMI_BALLOON_9934, 1)) + BalloonExperimentCutscene(player).start() + } + + label(questStageLabel(EnlightenedJourney.STAGE_FIRST_EXPERIMENT)) + npc(FacialExpression.HAPPY, "Do you have the other two sheets of papyrus and a full sack of potatoes?") + options( + DialogueOption("has_second_materials", "Yes, I have them here.", "Yes, I have them here."), + DialogueOption("misplaced_second_materials", "Oh, I've misplaced them.", "Oh, I've misplaced them.") + ) + + label("has_second_materials") + exec { player, _ -> + val hasPapyrus = amountInInventory(player, Items.PAPYRUS_970) >= 2 + val hasPotatoes = amountInInventory(player, Items.POTATOES10_5438) >= 1 + when { + hasPapyrus && hasPotatoes -> loadLabel(player, "second_experiment") + !hasPapyrus && hasPotatoes -> loadLabel(player, "missing_papyrus_second") + hasPapyrus && !hasPotatoes -> loadLabel(player, "missing_potatoes_second") + else -> loadLabel(player, "missing_both_second") + } + } + + label("misplaced_second_materials") + npc("Failure is not an option.") + + label("missing_papyrus_second") + npc(FacialExpression.SAD_TALKING, "You need more papyrus.") + + label("missing_potatoes_second") + npc(FacialExpression.SAD_TALKING, "You need a full sack of potatoes.") + + label("missing_both_second") + npc(FacialExpression.SAD_TALKING, "You need a full sack of potatoes and more papyrus.") + + label("second_experiment") + npc(FacialExpression.HAPPY, "Commendable. If I may have those, I will construct this experiment.") + exec { player, _ -> + removeItem(player, Item(Items.PAPYRUS_970, 2)) + removeItem(player, Item(Items.POTATOES10_5438, 1)) + SecondBalloonExperimentCutscene(player).start() + } + + label(questStageLabel(EnlightenedJourney.STAGE_SECOND_EXPERIMENT)) + player(FacialExpression.HALF_THINKING, "Those peasants... where did they come from?") + npc("Ahh, the flash mob phenomenon. Many have hypothesized that they are beings of great power sent to smite those who question the gods.") + player(FacialExpression.HALF_THINKING, "And this isn't worrying because...?") + npc(FacialExpression.HAPPY, "Don't worry! I know exactly what I'm doing.") + npc(FacialExpression.HAPPY, "Those experiments went extraordinarily well.") + player(FacialExpression.HALF_WORRIED, "Was I the ONLY one who saw them burning?", "BURNING???") + npc( + FacialExpression.HAPPY, + "Yes, very well indeed. Now we will start building the balloon that will carry us off the island." + ) + npc(FacialExpression.HAPPY, "This task will be much greater than the last two. I hope you are prepared for it.") + player("This is madness.") + npc(FacialExpression.HAPPY, "You need to get the following items:") + npc(FacialExpression.HAPPY, "Yellow dye", "Red dye", "Ten pieces of silk", "A clay bowl") + npc(FacialExpression.HAPPY, "and eight sandbags.") + npc( + FacialExpression.HAPPY, + "Sandbags can be made by getting empty sacks and filling them at the sand pit here on Entrana." + ) + npc( + FacialExpression.HAPPY, + "However, there are other sand pits around the world that will work as well; there is one in Yanille, Rellekka, and Zanaris." + ) + npc("You can bring items back to me as you get them, while you are waiting for the tree to grow.") + player(FacialExpression.HALF_THINKING, "What tree?") + npc("I am going to give you a willow sapling and a basket of apples. You must plant the willow sapling at a tree patch.") + npc("If you give the basket of apples to the gardener near the patch, he will look after the tree for you while it grows.") + npc("Don't lose the sapling! It took me a long time to save up enough for one. If you do, you'll have to pay me 30,000 coins for a new one.") + npc("Once the tree is fully grown, cut twelve branches from it using secateurs. Bring the branches back here and use them on the metal frame on the platform to create the basket.") + npc(FacialExpression.HAPPY, "Here you go. Now be very careful not to lose it!") + exec { player, _ -> + addItem(player, Items.AUGUSTES_SAPLING_9932) + addItem(player, Items.APPLES5_5386) + setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, EnlightenedJourney.STAGE_MAIN_BALLOON) + } + + label(questStageLabel(EnlightenedJourney.STAGE_MAIN_BALLOON)) + npc(FacialExpression.HAPPY, "Do you have anything for me?") + options( + DialogueOption( + "yes_give_items", + "Yes, I want to give you some items.", + "Yes, I want to give you some items." + ), + DialogueOption( + "trouble_finding_items", + "I'm having trouble finding some items.", + "I'm having trouble finding some items." + ), + DialogueOption( + "lost_sapling_check", + "I have lost my willow sapling. Can I buy a replacement?", + "I have lost my willow sapling. Can I buy a replacement?", + optionIf = { player, _ -> + !getAttribute(player, EnlightenedJourney.ATTRIBUTE_SAPLING_PLANTED, false) + }), + ) + + label("yes_give_items") + options( + DialogueOption( + "give_dye", "Dye.", "Here's the dye.", FacialExpression.NEUTRAL, false, + optionIf = { player, _ -> + !getAttribute(player, EnlightenedJourney.ATTRIBUTE_YELLOW_DYE_DELIVERED, false) || + !getAttribute(player, EnlightenedJourney.ATTRIBUTE_RED_DYE_DELIVERED, false) + }), + DialogueOption( + "give_sandbags", "Sandbags.", "Here are the sandbags.", FacialExpression.NEUTRAL, false, + optionIf = { player, _ -> + !getAttribute(player, EnlightenedJourney.ATTRIBUTE_SANDBAGS_DELIVERED, false) + }), + DialogueOption( + "give_silk", "Silk.", "Here's the silk.", FacialExpression.NEUTRAL, false, + optionIf = { player, _ -> + !getAttribute(player, EnlightenedJourney.ATTRIBUTE_SILK_DELIVERED, false) + }), + DialogueOption( + "give_bowl", "Bowl.", "Here's the bowl.", FacialExpression.NEUTRAL, false, + optionIf = { player, _ -> + !getAttribute(player, EnlightenedJourney.ATTRIBUTE_BOWL_DELIVERED, false) + }), + DialogueOption("never_mind", "Never mind.", "Never mind."), + ) + + label("noted_item") + npc(FacialExpression.SAD, "What am I supposed to do with a note? I can't make a balloon from notes!") + goto("yes_give_items") + + label("give_dye") + exec { player, _ -> + val hasNoted = amountInInventory(player, Items.YELLOW_DYE_1766) >= 1 || + amountInInventory(player, Items.RED_DYE_1764) >= 1 + val hasYellow = amountInInventory(player, Items.YELLOW_DYE_1765) >= 1 + val hasRed = amountInInventory(player, Items.RED_DYE_1763) >= 1 + when { + hasYellow && hasRed -> loadLabel(player, "give_both_dyes") + hasYellow -> loadLabel(player, "give_yellow_dye") + hasRed -> loadLabel(player, "give_red_dye") + hasNoted -> loadLabel(player, "noted_item") + else -> loadLabel(player, "no_dye") + } + } + + label("give_both_dyes") + npc(FacialExpression.HAPPY, "Ah, wonderful, yellow dye. Thank you.") + exec { player, _ -> + removeItem(player, Item(Items.YELLOW_DYE_1765, 1)) + setAttribute(player, EnlightenedJourney.ATTRIBUTE_YELLOW_DYE_DELIVERED, true) + checkAllItemsDelivered(player) + } + npc(FacialExpression.HAPPY, "Red dye. Thank you.") + exec { player, _ -> + removeItem(player, Item(Items.RED_DYE_1763, 1)) + setAttribute(player, EnlightenedJourney.ATTRIBUTE_RED_DYE_DELIVERED, true) + checkAllItemsDelivered(player) + loadLabel(player, "yes_give_items") + } + + label("give_yellow_dye") + npc(FacialExpression.HAPPY, "Ah, wonderful, yellow dye. Thank you.") + exec { player, _ -> + removeItem(player, Item(Items.YELLOW_DYE_1765, 1)) + setAttribute(player, EnlightenedJourney.ATTRIBUTE_YELLOW_DYE_DELIVERED, true) + checkAllItemsDelivered(player) + loadLabel(player, "yes_give_items") + } + + label("give_red_dye") + npc(FacialExpression.HAPPY, "Red dye! Thank you.") + exec { player, _ -> + removeItem(player, Item(Items.RED_DYE_1763, 1)) + setAttribute(player, EnlightenedJourney.ATTRIBUTE_RED_DYE_DELIVERED, true) + checkAllItemsDelivered(player) + loadLabel(player, "yes_give_items") + } + + label("no_dye") + npc("You don't have any dye with you.") + npc("I need red and yellow dye for the balloon.") + goto("yes_give_items") + + label("give_sandbags") + exec { player, _ -> + val hasSandbags = amountInInventory(player, Items.SANDBAG_9943) >= 8 + when { + hasSandbags -> loadLabel(player, "take_sandbags") + else -> loadLabel(player, "not_enough_sandbags") + } + } + + label("take_sandbags") + npc(FacialExpression.HAPPY, "Sandbags, thank you. This will allow us to change height.") + exec { player, _ -> + removeItem(player, Item(Items.SANDBAG_9943, 8)) + setAttribute(player, EnlightenedJourney.ATTRIBUTE_SANDBAGS_DELIVERED, true) + checkAllItemsDelivered(player) + loadLabel(player, "yes_give_items") + } + + label("not_enough_sandbags") + npc(FacialExpression.SAD, "You don't have enough sandbags. Please bring me eight.") + npc( + FacialExpression.HAPPY, + "Sandbags can be made by getting empty sacks and filling them at the sandpit here on Entrana." + ) + npc(FacialExpression.HAPPY, "However, there are other sand pits around the world that will work as well.") + goto("yes_give_items") + + label("give_silk") + exec { player, _ -> + val hasEnough = amountInInventory(player, Items.SILK_950) >= 10 + val hasNoted = amountInInventory(player, Items.SILK_951) >= 1 + + when { + hasEnough -> loadLabel(player, "take_silk") + hasNoted -> loadLabel(player, "noted_item") + else -> loadLabel(player, "not_enough_silk") + } + } + + label("take_silk") + npc(FacialExpression.HAPPY, "Silk for the balloon, thank you.") + exec { player, _ -> + removeItem(player, Item(Items.SILK_950, 10)) + setAttribute(player, EnlightenedJourney.ATTRIBUTE_SILK_DELIVERED, true) + checkAllItemsDelivered(player) + loadLabel(player, "yes_give_items") + } + + label("not_enough_silk") + npc("You don't have enough silk. Please bring me ten pieces.") + goto("yes_give_items") + + label("give_bowl") + exec { player, _ -> + val hasBowl = amountInInventory(player, Items.BOWL_1923) >= 1 + val hasNoted = amountInInventory(player, Items.BOWL_1924) >= 1 + + when { + hasBowl -> loadLabel(player, "take_bowl") + hasNoted -> loadLabel(player, "noted_item") + else -> loadLabel(player, "no_bowl") + } + } + + label("take_bowl") + npc( + FacialExpression.HAPPY, + "Ah the bowl. This will be used to hold the fuel while it heats the air in the balloon." + ) + exec { player, _ -> + removeItem(player, Item(Items.BOWL_1923, 1)) + setAttribute(player, EnlightenedJourney.ATTRIBUTE_BOWL_DELIVERED, true) + checkAllItemsDelivered(player) + loadLabel(player, "yes_give_items") + } + + label("no_bowl") + npc("I need a plain clay-fired bowl; they're quite ease to come by.") //"ease" seems to be an authentic typo. + goto("yes_give_items") + + label("lost_sapling_check") + exec { player, _ -> + val hasSapling = amountInInventory(player, Items.AUGUSTES_SAPLING_9932) >= 1 || + amountInBank(player, Items.AUGUSTES_SAPLING_9932) >= 1 || + getAttribute(player, EnlightenedJourney.ATTRIBUTE_SAPLING_PLANTED, false) + if (hasSapling) { + loadLabel(player, "dont_be_greedy") + } else { + loadLabel(player, "sapling_replacement_offer") + } + } + + label("dont_be_greedy") + npc("You already have one! Don't be greedy.") + + label("sapling_replacement_offer") + npc("It will cost you 30,000 gold coins to replace it, do you want to pay that?") + options( + DialogueOption("sapling_replacement_yes", "Yes.", "Yes."), + DialogueOption("sapling_replacement_no", "No way!", "No way!"), + ) + + label("sapling_replacement_yes") + exec { player, _ -> + if (amountInInventory(player, Items.COINS_995) >= 30000) { + loadLabel(player, "sapling_replacement_success") + } else { + loadLabel(player, "sapling_replacement_failure") + } + } + + label("sapling_replacement_success") + npc("Here you go. Now be very careful not to lose it again!") + exec { player, _ -> + removeItem(player, Item(Items.COINS_995, 30000)) + addItem(player, Items.AUGUSTES_SAPLING_9932, 1) + } + + //fallback, no source for what happens when the player has insufficient funds. + label("sapling_replacement_failure") + exec { player, _ -> + sendMessage(player, "You need 30,000 coins.") + } + + label("trouble_finding_items") + npc("What do you need help with?") + options( + DialogueOption( + "hint_dye", "Dye.", skipPlayer = true, + optionIf = { player, _ -> + !getAttribute(player, EnlightenedJourney.ATTRIBUTE_YELLOW_DYE_DELIVERED, false) || + !getAttribute(player, EnlightenedJourney.ATTRIBUTE_RED_DYE_DELIVERED, false) + }), + DialogueOption( + "hint_sandbags", "Sandbags.", skipPlayer = true, + optionIf = { player, _ -> + !getAttribute(player, EnlightenedJourney.ATTRIBUTE_SANDBAGS_DELIVERED, false) + }), + DialogueOption( + "hint_silk", "Silk.", skipPlayer = true, + optionIf = { player, _ -> + !getAttribute(player, EnlightenedJourney.ATTRIBUTE_SILK_DELIVERED, false) + }), + DialogueOption( + "hint_bowl", "Bowl.", skipPlayer = true, + optionIf = { player, _ -> + !getAttribute(player, EnlightenedJourney.ATTRIBUTE_BOWL_DELIVERED, false) + }), + DialogueOption("never_mind", "Never mind.", skipPlayer = true) + ) + + label("hint_dye") + npc("I was told a while ago that there was a witch who made dye in Draynor Village. Maybe you should start by looking there.") + + label("hint_sandbags") + npc("Sandbags can be made by getting empty sacks and filling them at the sandpit here on Entrana.") + npc("However, there are other sand pits around the world that will work as well; there is one in Yanille, Rellekka, and Zanaris.") + + label("hint_silk") + npc("Hmm, I believe silk is imported from the desert. Perhaps someone there can tell you where to find it.") + + label("hint_bowl") + npc("I think there is a spare one in the glass blower's house. I rent a room from him there, so I don't think he'll mind you taking it.") + + label(questStageLabel(EnlightenedJourney.STAGE_WILLOW_BASKET)) + npc( + FacialExpression.HAPPY, + "You just need to build the basket and I can finish the balloon! How are you getting on with the willow?" + ) + options( + DialogueOption( + "lost_sapling_check", + "I have lost my willow sapling. Can I buy a replacement?", + "I have lost my willow sapling. Can I buy a replacement?", + optionIf = { player, _ -> + !getAttribute(player, EnlightenedJourney.ATTRIBUTE_SAPLING_PLANTED, false) + }), + DialogueOption( + "build_the_basket", + "What do I do again?", + "What do I do again?", + FacialExpression.HALF_THINKING + ), + DialogueOption("fine_thanks", "Fine thanks.", "Fine thanks."), + ) + + label("build_the_basket") + npc( + FacialExpression.HAPPY, + "Use the willow sapling I gave you to grow a willow tree. Cut twelve branches from it using secateurs. Use the branches on the platform here." + ) + + label(questStageLabel(EnlightenedJourney.STAGE_FLIGHT)) + npc(FacialExpression.HAPPY, "Well, let's get going!") + options( + DialogueOption("wait_tell_me", "Wait; tell me what we're doing.", "Wait; tell me what we're doing."), + DialogueOption("maiden_voyage", "Okay.", "Okay."), + DialogueOption("not_ready", "No, I'm not ready.", "No, I'm not ready.") + ) + + label("wait_tell_me") + npc("Theoretically, we are ready for the maiden voyage.") + player("Theoretically?") + npc("Well, of course. With you piloting I am sure we will survive.") + player("WHAT!? This is your balloon! Why aren't you going to pilot it? And what do mean 'survive'? You never said anything about me flying this bird!") + npc("Don't be silly. I'm not going to pilot it. We will be safe in the basket, the only thing we will lose are the logs. You will pilot it, won't you?") + player("Fine, I will. So how do I control the balloon?") + npc("Wonderful! Let me explain my hypothesis on how to control a balloon.") + player("Oh no, not another hypothesis!") + npc("The balloon needs ten normal logs for fuel. I believe the balloon will be controlled based on weight, so you must not have more than 40kg with you.") + npc("Also, I seem to have lost my tinderbox, do you think you could bring one? We need it to light the fire.") + player("And here, I thought all the legwork was done. Fine, I'll bring a tinderbox.") + npc("Right! So, the balloon mechanics.") + npc("Your prime direction will always be to land the balloon on the target at the end of our route. I've written to some friends in Taverley who have kindly painted one on the ground there.") + npc("We must avoid everything, because the balloon is very fragile. Even clouds will be dangerous! But if my calculations are correct, we will be able to squeeze through some surprising spaces, if you pilot it well.") + npc("Those sandbags you made earlier will give the balloon a big lift when dropped, whereas adding the logs will only make it rise a little bit. But don't use them up too quickly! We have no way of replenishing them.") + npc("If you do run out of logs and sandbags you will not be able to go up any longer. Just make the best of it and hope we can make it to our destination without going upwards.") + npc("I've added two ropes, the red one is an emergency rope, it will let the hot air out of the balloon and we will drop quickly. The other rope will only drop us a little.") + npc("If we get into tribb...beg your pardon, trouble, in all likelihood we will crash. But do not fear! We should be fine. Just make sure you come back to Entrana so we can try again.") + npc("If it all goes horribly wrong, you can always bail. If we're still over Entrana, we can land quickly and try again. However, once past the island, we will crash.") + npc("Are you ready to go?") + options( + DialogueOption("maiden_voyage", "Okay.", "Okay."), + DialogueOption("not_ready", "No, I'm not ready.", "No, I'm not ready.") + ) + + label("maiden_voyage") + exec { player, _ -> + when { + player.settings.weight > 40.0 -> loadLabel(player, "maiden_voyage_heavy") + amountInInventory(player, Items.TINDERBOX_590) < 1 -> loadLabel(player, "maiden_voyage_tinderbox") + amountInInventory(player, Items.LOGS_1511) < 10 -> loadLabel(player, "maiden_voyage_logs") + else -> loadLabel(player, "maiden_voyage_start") + } + } + + label("maiden_voyage_heavy") + npc("You have too much weight in your bag. You may only bring 40kg of weight.") + + label("maiden_voyage_tinderbox") + npc("You need a tinderbox.") + + label("maiden_voyage_logs") + npc("You don't have enough logs. You need ten normal logs.") + + label("maiden_voyage_start") + exec { player, _ -> + if (removeItem(player, Item(Items.LOGS_1511, 10))) { + BalloonFlightInterface.startQuestFlight(player) + } else { + loadLabel(player, "maiden_voyage_logs") + } + } + + label(questStageLabel(EnlightenedJourney.STAGE_CLAIM_REWARD)) + npc( + FacialExpression.HAPPY, + "We have travelled in a way that no man has travelled before! The next step will be to go where no men have gone before." + ) + npc(FacialExpression.HAPPY, "@name, it has been a privilege flying with you.") + npc( + FacialExpression.HAPPY, + "For all your hard work, I give you this jacket and cap for future ballooning adventures." + ) + exec { player, _ -> + if (freeSlots(player) < 2) { + loadLabel(player, "reward_no_space") + } else { + finishQuest(player, Quests.ENLIGHTENED_JOURNEY) + } + } + + label("reward_no_space") + npc("You don't have enough space in your inventory. Speak to me again when you do.") + + label(questStageLabel(EnlightenedJourney.STAGE_COMPLETE)) + exec { player, talkingNpc -> + if (talkingNpc.originalId == 5062) { + loadLabel(player, "post_quest_taverley") + } else { + loadLabel(player, "post_quest_entrana") + } + } + + label("post_quest_taverley") + player("So what are you going to do now?") + npc("I am considering starting a balloon enterprise. People all over Gielinor will be able to travel in a new, exciting way.") + npc("As my first assistant, you will always be welcome to use a balloon. You'll have to bring your own fuel, though.") + player("Thanks!") + npc("I will base my operations in Entrana. If you'd like to travel to new places, come see me there.") + npc("Do you want to use the balloon? Just so you know, some locations require special logs and high Firemaking skills.") + options( + DialogueOption("post_quest_yes", "Yes.", "Yes."), + DialogueOption("post_quest_no", "No.", "No."), + DialogueOption( + "post_quest_origami", + "Could you tell me how to make an origami balloon?", + "Could you tell me how to make an origami balloon?" + ) + ) + + label("post_quest_yes") + npc("Weapons are not allowed on Entrana. I must search you first.") + line("You are quickly searched.") + exec { player, _ -> + if (ItemDefinition.canEnterEntrana(player)) { + loadLabel(player, "enter_entrana_allowed") + } else { + loadLabel(player, "enter_entrana_disallowed") + } + } + + label("enter_entrana_allowed") + exec { player, _ -> + teleport(player, Location.create(2808, 3354, 0)) + } + + label("enter_entrana_disallowed") + npc("I'm sorry, no weapons or armour may be worn to Entrana. Come back when you have laid them down.") + + label("post_quest_origami") + npc("First, use the papyrus on the ball of wool. The papyrus is folded into an origami box and the yarn will support the heat source.") + npc("Next, add the unlit candle to the balloon structure. It will act as the heat source.") + npc("Now you have an origami balloon!") + npc("If you use your origami balloon with any dye, you can change the colour.") + npc("You can release the balloon and watch it float in the air, just use a tinderbox on it.") + + label("post_quest_entrana") + exec { player, _ -> + if (getAttribute(player, EnlightenedJourney.ATTRIBUTE_AUGUSTE_POST_EXPLANATION, false)) { + loadLabel(player, "post_quest_options") + } else { + loadLabel(player, "post_quest_greeting") + } + } + + label("post_quest_greeting") + npc("Hello, @name. It is good to see you again. My enterprise has grown since we last met. I've expanded all over Gielinor!") + npc("If you'd like to go to a new location, you will have to help fly the balloon again. Some of the routes are very dangerous!") + npc("But each route you complete will earn you Firemaking experience.") + npc("Once you've opened a route, it only costs 1 log of the corresponding type to travel there again, from any location you've already opened!") + npc("I have also hired assistants to watch over the balloons at each new location we go to. They will help you get where you want to go.") + exec { player, _ -> + setAttribute(player, EnlightenedJourney.ATTRIBUTE_AUGUSTE_POST_EXPLANATION, true) + } + goto("post_quest_options") + + label("post_quest_options") + npc("Do you want to use the balloon? Just so you know, some locations require special logs and high Firemaking skills.") + options( + DialogueOption("yes_fly_balloon", "Yes.", "Yes."), + DialogueOption("post_quest_no", "No.", "No."), + DialogueOption("post_quest_origami", "Could you tell me how to make an origami balloon?", "Could you tell me how to make an origami balloon?"), + DialogueOption("replace_bomber_clothes", "Could you replace some items for me?", "Could you replace some items for me?") { player, _ -> hasLostBomberReward(player) }, + DialogueOption("combine_cap_goggles", "Could you combine my cap and goggles?", "Could you combine my cap and goggles?") { player, _ -> hasCapAndGoggles(player) } + ) + + label("replace_bomber_clothes") + exec { player, _ -> + if (hasBomberCap(player)) { + loadLabel(player, "bomber_cap_owned") + } else if (freeSlots(player) < 1) { + loadLabel(player, "bomber_cap_no_space") + } else { + loadLabel(player, "bomber_cap_replace") + } + } + + label("bomber_cap_owned") + npc("You still seem to have your cap.") + goto("replace_bomber_jacket") + + label("bomber_cap_no_space") + npc("You don't have enough free space for your cap.") + goto("replace_bomber_jacket") + + label("bomber_cap_replace") + npc("Here's your cap. Try to keep better track of it.") + exec { player, _ -> + addItem(player, Items.BOMBER_CAP_9945) + } + goto("replace_bomber_jacket") + + label("replace_bomber_jacket") + exec { player, _ -> + if (hasBomberJacket(player)) { + loadLabel(player, "bomber_jacket_owned") + } else if (freeSlots(player) < 1) { + loadLabel(player, "bomber_jacket_no_space") + } else { + loadLabel(player, "bomber_jacket_replace") + } + } + + label("bomber_jacket_owned") + npc("You don't need a new jacket; you still have your original one.") + + label("bomber_jacket_no_space") + npc("You don't have enough free space for your jacket.") + + label("bomber_jacket_replace") + npc("Here's your jacket, to keep you warm during flight.") + exec { player, _ -> + addItem(player, Items.BOMBER_JACKET_9944) + } + + label("combine_cap_goggles") + exec { player, _ -> + if (inEquipment(player, Items.BOMBER_CAP_9945) || inEquipment(player, Items.GNOME_GOGGLES_9472)) { + loadLabel(player, "combine_cap_goggles_worn") + } else if (amountInInventory(player, Items.BOMBER_CAP_9945) < 1 || amountInInventory(player, Items.GNOME_GOGGLES_9472) < 1) { + loadLabel(player, "combine_cap_goggles_no_space") + } else { + loadLabel(player, "combine_cap_goggles_success") + } + } + + label("combine_cap_goggles_worn") + npc("I can't combine them if you are wearing them.") + + label("combine_cap_goggles_no_space") + npc("You don't have enough free space for the cap and goggles.") + + label("combine_cap_goggles_success") + npc("There you go! You look like a true airship pilot now.") + exec { player, _ -> + removeItem(player, Item(Items.BOMBER_CAP_9945, 1)) + removeItem(player, Item(Items.GNOME_GOGGLES_9472, 1)) + addItem(player, Items.CAP_AND_GOGGLES_9946, 1) + } + + label("yes_fly_balloon") + exec { player, _ -> + BalloonTravelInterface.open(player, BalloonTravelLocation.ENTRANA) + } + + } +} diff --git a/Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourney.kt b/Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourney.kt new file mode 100644 index 000000000..79ec6e695 --- /dev/null +++ b/Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourney.kt @@ -0,0 +1,325 @@ +package content.region.misc.quest.enlightenedjourney.quest + +import content.data.Quests +import core.api.addItemOrDrop +import core.api.getAttribute +import core.api.getQuestStage +import core.api.getStatLevel +import core.api.inInventory +import core.api.removeAttribute +import core.api.rewardXP +import core.api.setVarbit +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 + +/** + * Enlightened Journey quest. + * @author Edith + */ + +@Initializable +class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, VARBIT_QUEST_PROGRESS, 0, 1, 200) { + + companion object { + val questName = Quests.ENLIGHTENED_JOURNEY + + /** Quest progress varbit used for the quests tab. Red = not started, Yellow = in progress, Green = completed. */ + const val VARBIT_QUEST_PROGRESS = 2866 + + /** Entrana balloon scenery state varbit. */ + const val VARBIT_ENTRANA_BALLOON = 2867 + + /** Taverley balloon route unlock state. */ + const val VARBIT_TAVERLEY_BALLOON = 2868 + + /** Completing a ballooning route unlocks the respective destination. */ + const val VARBIT_CASTLEWARS_BALLOON = 2869 + const val VARBIT_GRANDTREE_BALLOON = 2870 + const val VARBIT_CRAFTINGGUILD_BALLOON = 2871 + const val VARBIT_VARROCK_BALLOON = 2872 + + /** Attributes used during the quest. */ + const val ATTRIBUTE_YELLOW_DYE_DELIVERED = "/save:enlightenedjourney_yellow_dye_delivered" + const val ATTRIBUTE_RED_DYE_DELIVERED = "/save:enlightenedjourney_red_dye_delivered" + const val ATTRIBUTE_SANDBAGS_DELIVERED = "/save:enlightenedjourney_sandbags_delivered" + const val ATTRIBUTE_SILK_DELIVERED = "/save:enlightenedjourney_silk_delivered" + const val ATTRIBUTE_BOWL_DELIVERED = "/save:enlightenedjourney_bowl_delivered" + const val ATTRIBUTE_SAPLING_PLANTED = "/save:enlightenedjourney_sapling_planted" + + /** Player has started the quest and Auguste is explaining what a "balloo-what?" is. */ + const val STAGE_QUEST_STARTED = 5 + + /** Player has agreed to help Auguste and needs to gather the materials for the first balloon experiment. */ + const val STAGE_GATHER_MATERIALS = 10 + + /** Player has gathered the first experiment materials and needs to make an origami balloon. */ + const val STAGE_ORIGAMI_BALLOON = 20 + + /** Player has made an origami balloon and needs to give it to Auguste for the first balloon experiment. */ + const val STAGE_FIRST_EXPERIMENT = 30 + + /** Player has completed the first balloon experiment and needs to prepare the second balloon experiment. */ + const val STAGE_SECOND_EXPERIMENT = 40 + + /** Player has completed both balloon experiments and needs to gather the materials for the main balloon. */ + const val STAGE_MAIN_BALLOON = 50 + + /** Player has delivered the main balloon materials to Auguste and needs to prepare the willow basket. */ + const val STAGE_WILLOW_BASKET = 60 + + /** Player has built the main balloon and needs to fly it to Taverley. */ + const val STAGE_FLIGHT = 70 + + /** Player has flown the balloon to Taverley and can now claim the quest reward from Auguste. */ + const val STAGE_CLAIM_REWARD = 80 + + /** Player has completed Enlightened Journey. */ + const val STAGE_COMPLETE = 100 + + /** Taverley balloon NPC state: Auguste "returns" to Entrana and Assistant Stan now manages the route from Taverley. */ + const val ATTRIBUTE_TAVERLEY_AUGUSTE_REPLACED = "/save:enlightenedjourney_taverley_auguste_replaced" + + /** Player has heard Augustes post-quest explanation of the expanded balloon network. */ + const val ATTRIBUTE_AUGUSTE_POST_EXPLANATION = "/save:enlightenedjourney_auguste_post_explanation" + } + + override fun drawJournal(player: Player, stage: Int) { + super.drawJournal(player, stage) + var line = 12 + + if (stage == 0) { + line(player, "I can start this quest by speaking to !!Auguste?? on !!Entrana??.", line++) + line(player, "Minimum Requirements:", line++) + line(player, "Level 36 Crafting", line++, getStatLevel(player, Skills.CRAFTING) >= 36) + line(player, "Level 30 Farming", line++, getStatLevel(player, Skills.FARMING) >= 30) + line(player, "Level 20 Firemaking", line++, getStatLevel(player, Skills.FIREMAKING) >= 20) + line(player, "20 Quest Points", line, core.api.getQuestPoints(player) >= 20) + } + + if (stage >= STAGE_QUEST_STARTED) { + line( + player, + "I have agreed to help Auguste build an !!air balloon??.", + line++, + stage > STAGE_GATHER_MATERIALS + ) + line(player, "I have no idea what he's talking about.", line++, stage > STAGE_GATHER_MATERIALS) + line( + player, + "Auguste thinks if he pumps hot air into a sack it will rise and", + line++, + stage > STAGE_GATHER_MATERIALS + ) + line(player, "take us along with it.", line++, stage > STAGE_GATHER_MATERIALS) + line( + player, + "But we're going to run some tests first. Thank goodness.", + line++, + stage > STAGE_GATHER_MATERIALS + ) + line++ + } + + if (stage >= STAGE_GATHER_MATERIALS) { + line(player, "I need to gather the materials Auguste required:", line++, stage > STAGE_GATHER_MATERIALS) + line( + player, "three sheets of papyrus", line++, stage > STAGE_GATHER_MATERIALS || inInventory( + player, + Items.PAPYRUS_970, + 3 + ) + ) + line( + player, "a ball of wool", line++, stage > STAGE_GATHER_MATERIALS || inInventory( + player, + Items.BALL_OF_WOOL_1759 + ) + ) + line( + player, "a full sack of potatoes", line++, stage > STAGE_GATHER_MATERIALS || inInventory( + player, + Items.POTATOES10_5438 + ) + ) + line( + player, "one unlit candle.", line++, stage > STAGE_GATHER_MATERIALS || inInventory( + player, + Items.CANDLE_36 + ) + ) + line++ + } + + if (stage >= STAGE_ORIGAMI_BALLOON) { + line( + player, "I made an !!origami balloon??.", line++, stage > STAGE_ORIGAMI_BALLOON || inInventory( + player, + Items.ORIGAMI_BALLOON_9934 + ) + ) + line(player, "Auguste said I could make these any time I want if", line++, stage > STAGE_ORIGAMI_BALLOON) + line(player, "I have the materials.", line++, stage > STAGE_ORIGAMI_BALLOON) + line++ + } + + if (stage >= STAGE_FIRST_EXPERIMENT) { + line(player, "Auguste conducted the first experiment.", line++, stage > STAGE_FIRST_EXPERIMENT) + line(player, "There was an awful lot of fire.", line++, stage > STAGE_FIRST_EXPERIMENT) + line++ + } + + if (stage >= STAGE_SECOND_EXPERIMENT) { + line(player, "Auguste conducted the second experiment.", line++, stage > STAGE_SECOND_EXPERIMENT) + line( + player, + "A flash mob appeared. They seem to have a grudge against", + line++, + stage > STAGE_SECOND_EXPERIMENT + ) + line(player, "science.", line++, stage > STAGE_SECOND_EXPERIMENT) + line++ + } + + if (stage >= STAGE_MAIN_BALLOON) { + line( + player, + "I need to gather the supplies for Auguste's main balloon:", + line++, + stage > STAGE_MAIN_BALLOON + ) + line(player, "red dye", line++, stage > STAGE_MAIN_BALLOON || inInventory(player, Items.RED_DYE_1763)) + line(player, "yellow dye", line++, stage > STAGE_MAIN_BALLOON || inInventory(player, Items.YELLOW_DYE_1765)) + line( + player, "ten pieces of silk", line++, stage > STAGE_MAIN_BALLOON || inInventory( + player, + Items.SILK_950, + 10 + ) + ) + line(player, "a bowl", line++, stage > STAGE_MAIN_BALLOON || inInventory(player, Items.BOWL_1923)) + line( + player, "eight sandbags", line++, stage > STAGE_MAIN_BALLOON || inInventory( + player, + Items.SANDBAG_9943, + 8 + ) + ) + line++ + } + + if (stage >= STAGE_WILLOW_BASKET) { + line(player, "I need to make the basket for the balloon:", line++, stage > STAGE_WILLOW_BASKET) + line( + player, "twelve willow branches", line++, stage > STAGE_WILLOW_BASKET || inInventory( + player, + Items.WILLOW_BRANCH_5933, + 12 + ) + ) + line++ + } + + if (stage >= STAGE_FLIGHT) { + line(player, "I gave Auguste all the supplies and made the basket for the", line++, stage > STAGE_FLIGHT) + line(player, "balloon.", line++, stage > STAGE_FLIGHT) + line(player, "The balloon is all made and looks impressive!", line++, stage > STAGE_FLIGHT) + line(player, "Let's hope it doesn't end the way the experiments did.", line++, stage > STAGE_FLIGHT) + line++ + } + + if (stage >= STAGE_CLAIM_REWARD) { + line(player, "Whew! We survived our first balloon flight.", line++, stage > STAGE_CLAIM_REWARD) + line(player, "We successfully flew the first balloon to !!Taverley??!", line++, stage > STAGE_CLAIM_REWARD) + line++ + } + + if (stage >= STAGE_COMPLETE) { + line(player, "QUEST COMPLETE!", line++) + line++ + line(player, "I can now make !!Origami balloons??.", line++) + line(player, "I can also use the !!balloon transport system??.", line++) + line(player, "To go to new locations I should speak to !!Auguste?? on", line++) + line(player, "!!Entrana??.", line) + } + } + + override fun hasRequirements(player: Player): Boolean { + return getStatLevel(player, Skills.CRAFTING) >= 36 && + getStatLevel(player, Skills.FARMING) >= 30 && + getStatLevel(player, Skills.FIREMAKING) >= 20 && + core.api.getQuestPoints(player) >= 20 + } + + override fun finish(player: Player) { + super.finish(player) + var line = 10 + + player.packetDispatch.sendString("You have completed Enlightened Journey!", 277, 4) + player.packetDispatch.sendItemZoomOnInterface(Items.BOMBER_CAP_9945, 230, 277, 5) + + drawReward(player, "1 Quest Point", line++) + drawReward(player, "2,000 Crafting XP", line++) + drawReward(player, "3,000 Farming XP", line++) + drawReward(player, "1,500 Woodcutting XP", line++) + drawReward(player, "4,000 Firemaking XP", line++) + drawReward(player, "Balloon Transport System", line++) + drawReward(player, "Origami Balloons", line) + + rewardXP(player, Skills.CRAFTING, 2000.0) + rewardXP(player, Skills.FARMING, 3000.0) + rewardXP(player, Skills.WOODCUTTING, 1500.0) + rewardXP(player, Skills.FIREMAKING, 4000.0) + + addItemOrDrop(player, Items.BOMBER_JACKET_9944) + addItemOrDrop(player, Items.BOMBER_CAP_9945) + + setVarbit(player, VARBIT_QUEST_PROGRESS, 200, true) + setVarbit(player, VARBIT_ENTRANA_BALLOON, 2, true) + setVarbit(player, VARBIT_TAVERLEY_BALLOON, 1, true) + } + + override fun reset(player: Player) { + setVarbit(player, VARBIT_QUEST_PROGRESS, 0, true) + setVarbit(player, VARBIT_ENTRANA_BALLOON, 0, true) + setVarbit(player, VARBIT_TAVERLEY_BALLOON, 0, true) + setVarbit(player, VARBIT_CASTLEWARS_BALLOON, 0, true) + setVarbit(player, VARBIT_GRANDTREE_BALLOON, 0, true) + setVarbit(player, VARBIT_CRAFTINGGUILD_BALLOON, 0, true) + setVarbit(player, VARBIT_VARROCK_BALLOON, 0, true) + removeAttribute(player, ATTRIBUTE_YELLOW_DYE_DELIVERED) + removeAttribute(player, ATTRIBUTE_RED_DYE_DELIVERED) + removeAttribute(player, ATTRIBUTE_SANDBAGS_DELIVERED) + removeAttribute(player, ATTRIBUTE_SILK_DELIVERED) + removeAttribute(player, ATTRIBUTE_BOWL_DELIVERED) + removeAttribute(player, ATTRIBUTE_SAPLING_PLANTED) + removeAttribute(player, ATTRIBUTE_TAVERLEY_AUGUSTE_REPLACED) + removeAttribute(player, ATTRIBUTE_AUGUSTE_POST_EXPLANATION) + } + + override fun updateVarps(player: Player) { + val stage = getQuestStage(player, questName) + + setVarbit( + player, VARBIT_QUEST_PROGRESS, when { + stage >= STAGE_COMPLETE -> 200 + stage > 0 -> 1 + else -> 0 + }, true + ) + + setVarbit(player, VARBIT_ENTRANA_BALLOON, if (stage >= STAGE_FLIGHT) 2 else 0, true) + val taverleyBalloonState = when { + stage >= STAGE_COMPLETE && getAttribute(player, ATTRIBUTE_TAVERLEY_AUGUSTE_REPLACED, false) -> 2 + stage >= STAGE_CLAIM_REWARD -> 1 + else -> 0 + } + setVarbit(player, VARBIT_TAVERLEY_BALLOON, taverleyBalloonState, true) + } + + override fun newInstance(`object`: Any?): Quest { + return this + } +} diff --git a/Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt b/Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt new file mode 100644 index 000000000..9e1d500a4 --- /dev/null +++ b/Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt @@ -0,0 +1,159 @@ +package content.region.misc.quest.enlightenedjourney.quest + +import content.data.Quests +import content.region.misc.quest.enlightenedjourney.cutscene.BalloonConstructionCutscene +import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_WILLOW_BASKET +import core.api.MapArea +import core.api.addItem +import core.api.amountInInventory +import core.api.animate +import core.api.freeSlots +import core.api.getQuestStage +import core.api.openDialogue +import core.api.removeItem +import core.api.rewardXP +import core.api.sendMessage +import core.api.setAttribute +import core.game.dialogue.DialogueFile +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.node.entity.Entity +import core.game.node.entity.player.Player +import core.game.node.entity.skill.Skills +import core.game.node.item.Item +import core.game.world.map.zone.ZoneBorders +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +/** + * Listeners for the Enlightened Journey quest. + * @author Edith + */ + +class EnlightenedJourneyListeners : InteractionListener, MapArea { + + override fun defineListeners() { + /** Make balloon structure. */ + onUseWith(IntType.ITEM, Items.PAPYRUS_970, Items.BALL_OF_WOOL_1759) { player, _, _ -> + if (getQuestStage(player, Quests.ENLIGHTENED_JOURNEY) < EnlightenedJourney.STAGE_ORIGAMI_BALLOON) { + return@onUseWith false + } + if (amountInInventory(player, Items.PAPYRUS_970) >= 1 && + amountInInventory(player, Items.BALL_OF_WOOL_1759) >= 1 + ) { + removeItem(player, Item(Items.PAPYRUS_970, 1)) + removeItem(player, Item(Items.BALL_OF_WOOL_1759, 1)) + addItem(player, Items.BALLOON_STRUCTURE_9933, 1) + sendMessage(player, "You create the origami balloon structure.") + } + return@onUseWith true + } + + /** Make origami balloon. */ + onUseWith(IntType.ITEM, Items.CANDLE_36, Items.BALLOON_STRUCTURE_9933) { player, _, _ -> + if (getQuestStage(player, Quests.ENLIGHTENED_JOURNEY) < EnlightenedJourney.STAGE_ORIGAMI_BALLOON) { + return@onUseWith false + } + if (amountInInventory(player, Items.CANDLE_36) >= 1 && + amountInInventory(player, Items.BALLOON_STRUCTURE_9933) >= 1 + ) { + removeItem(player, Item(Items.CANDLE_36, 1)) + removeItem(player, Item(Items.BALLOON_STRUCTURE_9933, 1)) + addItem(player, Items.ORIGAMI_BALLOON_9934, 1) + rewardXP(player, Skills.CRAFTING, 35.0) + sendMessage(player, "You create an origami balloon.") + } + return@onUseWith true + } + + /** Make sandbag from sandpit. Entrana/Zanaris, Rellekka, Yanille. */ + onUseWith(IntType.SCENERY, Items.EMPTY_SACK_5418, 2645, 4373, 10814) { player, _, _ -> + if (removeItem(player, Item(Items.EMPTY_SACK_5418, 1))) { + animate(player, 5155) + addItem(player, Items.SANDBAG_9943, 1) + sendMessage(player, "You fill the bag with sand.") + } + return@onUseWith true + } + + /** Make sandbag from bucket of sand. */ + onUseWith(IntType.ITEM, Items.EMPTY_SACK_5418, Items.BUCKET_OF_SAND_1783) { player, _, _ -> + if (amountInInventory(player, Items.EMPTY_SACK_5418) >= 1 && amountInInventory( + player, + Items.BUCKET_OF_SAND_1783 + ) >= 1 + ) { + removeItem(player, Item(Items.EMPTY_SACK_5418, 1)) + removeItem(player, Item(Items.BUCKET_OF_SAND_1783, 1)) + addItem(player, Items.SANDBAG_9943, 1) + addItem(player, Items.BUCKET_1925, 1) + sendMessage(player, "You fill the bag with sand.") + } + return@onUseWith true + } + + /** Using willow branches on the basket frame to construct the Entrana balloon. */ + onUseWith(IntType.SCENERY, Items.WILLOW_BRANCH_5933, 19132) { player, _, _ -> + if (getQuestStage(player, Quests.ENLIGHTENED_JOURNEY) != STAGE_WILLOW_BASKET) { + return@onUseWith false + } + if (amountInInventory(player, Items.WILLOW_BRANCH_5933) < 12) { + sendMessage(player, "You do not have enough willow branches.") + return@onUseWith true + } + openDialogue(player, BalloonConstructionDialogue()) + return@onUseWith true + } + + /** Split cap and goggles back into bomber cap and gnome goggles. */ + on(Items.CAP_AND_GOGGLES_9946, IntType.ITEM, "split") { player, _ -> + if (freeSlots(player) < 1) { + sendMessage(player, "You need some free inventory space to do that.") + return@on true + } + + if (removeItem(player, Item(Items.CAP_AND_GOGGLES_9946, 1))) { + addItem(player, Items.BOMBER_CAP_9945, 1) + addItem(player, Items.GNOME_GOGGLES_9472, 1) + } + return@on true + } + } + + override fun defineAreaBorders(): Array { + return arrayOf(ZoneBorders(2909, 3388, 2973, 3452, 0)) + } + + override fun areaLeave(entity: Entity, logout: Boolean) { + val player = entity as? Player ?: return + + if (getQuestStage(player, Quests.ENLIGHTENED_JOURNEY) >= EnlightenedJourney.STAGE_COMPLETE) { + setAttribute(player, EnlightenedJourney.ATTRIBUTE_TAVERLEY_AUGUSTE_REPLACED, true) + } + } + +} + +class BalloonConstructionDialogue : DialogueFile() { + override fun handle(componentID: Int, buttonID: Int) { + when (stage) { + 0 -> npc( + NPCs.AUGUSTE_5049, + "Great! Let me just put it together and we'll be ready", + "to lift off! Speak to me again in a moment." + ).also { stage++ } + + 1 -> { + if (amountInInventory(player!!, Items.WILLOW_BRANCH_5933) < 12) { + sendMessage(player!!, "You do not have enough willow branches.") + end() + return + } + if (removeItem(player!!, Item(Items.WILLOW_BRANCH_5933, 12))) { + end() + BalloonConstructionCutscene(player!!).start() + } + } + } + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/dialogue/FacialExpression.java b/Server/src/main/core/game/dialogue/FacialExpression.java index 8b4f2eb8c..a42df4bb7 100644 --- a/Server/src/main/core/game/dialogue/FacialExpression.java +++ b/Server/src/main/core/game/dialogue/FacialExpression.java @@ -53,10 +53,12 @@ public enum FacialExpression { WORRIED(9743), HALF_WORRIED(9745), //Not on the wiki, first half of worried AMAZED(9746), + AMAZED_TALKING(9749), EXTREMELY_SHOCKED(9750), GUILTY(9758), HALF_GUILTY(9760), //Not on the wiki, first half of guilty SAD(9761), + SAD_TALKING(9764), CRYING(9765), HALF_CRYING(9768), //Not on the wiki, but plays the first half of the crying animation AFRAID(9772), diff --git a/Server/src/main/core/game/system/command/sets/AudioCommandSet.kt b/Server/src/main/core/game/system/command/sets/AudioCommandSet.kt index 70e797b0c..0c4217b69 100644 --- a/Server/src/main/core/game/system/command/sets/AudioCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/AudioCommandSet.kt @@ -1,7 +1,11 @@ package core.game.system.command.sets +import core.api.delayScript import core.api.playAudio import core.api.playGlobalAudio +import core.api.queueScript +import core.api.stopExecuting +import core.game.interaction.QueueStrength import core.game.node.entity.player.link.music.MusicEntry import core.game.system.command.Privilege import core.game.world.map.Location @@ -44,6 +48,29 @@ class MusicCommandSet : CommandSet(Privilege.STANDARD){ notify(player,"Now playing jingle $id") } + define("jingles", Privilege.ADMIN, "::jingles From Jingle ID To Jingle ID (opt) Duration Per Jingle", "Plays jingles from the From ID to the To ID, with a delay of 5 between each, unless specified otherwise") { player, args -> + + if (args.size < 3) { + reject(player, "Syntax error: ::jingles <(opt) Duration Per Jingle>") + return@define + } + val jingleFrom = args[1].toInt() + val jingleTo = args[2].toInt() + val jingleDelay = (args.getOrNull(3) ?: "5").toInt() + + queueScript(player, 1, QueueStrength.WEAK) { stage: Int -> + val jingleId = jingleFrom + stage + PacketRepository.send(MusicPacket::class.java, MusicContext(player, jingleId, true)) + notify(player, "Now playing jingle $jingleId") + + if (jingleId == jingleTo) { + return@queueScript stopExecuting(player) + } + + return@queueScript delayScript(player, jingleDelay) + } + } + /** * Command that lets you play a song via the ID instead of the song name * this is mostly useful for custom tracks that aren't in the ingame From 418c326ec142a1824781ecbefde0b3eeba321edb Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Fri, 22 May 2026 23:40:56 +0200 Subject: [PATCH 02/14] Hooked up Varrock achievement diary --- .../global/travel/balloon/BalloonTravelInterface.kt | 12 ++++++++++++ .../node/entity/player/link/diary/DiaryType.java | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt index e909c4b18..d723ec3e0 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt @@ -3,6 +3,7 @@ package content.global.travel.balloon import content.data.Quests import content.region.misc.quest.enlightenedjourney.dialogue.AugusteDialogueFile import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney +import content.region.misthalin.varrock.diary.VarrockAchivementDiary.Companion.MediumTasks.HOTAIR_BALLOON_TRAVEL_SOMEWHERE import core.api.amountInInventory import core.api.animateInterface import core.api.animationDuration @@ -31,6 +32,7 @@ import core.game.interaction.InteractionListener import core.game.interaction.InterfaceListener import core.game.interaction.QueueStrength import core.game.node.entity.player.Player +import core.game.node.entity.player.link.diary.DiaryType import core.game.node.entity.skill.Skills import core.game.node.item.Item import core.game.world.map.Location @@ -50,6 +52,8 @@ private const val ASSISTANT_LE_SMITH_WRAPPER = 5064 private const val ASSISTANT_BROCK_WRAPPER = 5065 private const val ASSISTANT_SERF_WRAPPER = 5066 +private const val VARROCK_MEDIUM_DIARY = 1 + private val BALLOON_VISIBLE_NPCS = intArrayOf( NPCs.AUGUSTE_5049, NPCs.ASSISTANT_STAN_5057, @@ -163,6 +167,14 @@ class BalloonTravelInterface : InterfaceListener, InteractionListener { queueScript(player, duration, QueueStrength.SOFT) { closeInterface(player) teleport(player, destination.destination) + if (start == BalloonTravelLocation.VARROCK) { + player.achievementDiaryManager.finishTask( + player, + DiaryType.VARROCK, + VARROCK_MEDIUM_DIARY, + HOTAIR_BALLOON_TRAVEL_SOMEWHERE + ) + } unlock(player) return@queueScript stopExecuting(player) } diff --git a/Server/src/main/core/game/node/entity/player/link/diary/DiaryType.java b/Server/src/main/core/game/node/entity/player/link/diary/DiaryType.java index dbbb06e81..ce225efe0 100644 --- a/Server/src/main/core/game/node/entity/player/link/diary/DiaryType.java +++ b/Server/src/main/core/game/node/entity/player/link/diary/DiaryType.java @@ -125,7 +125,7 @@ public enum DiaryType { "Get a Slayer task from Vannaka", "Buy twenty mahogany planks from the Sawmill Operator in one

transaction", "Pick a fruit from the White Tree", // TODO Garden of Tranquility - "Use the hot air balloon to travel from Varrock to somewhere

else", // TODO Enlightened Journey + "Use the hot air balloon to travel from Varrock to somewhere

else", "Get a cat training medal from Gertrude", // TODO need rat catchers and cats fixed "Dial to the fairy ring west of Varrock", "Browse through Oziach's Armour Shop" From ed2e13827b2af00949758bd5d104737250975997 Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Sat, 23 May 2026 17:01:15 +0200 Subject: [PATCH 03/14] Added zone restrictions for crash sites --- .../travel/balloon/BalloonCrashSites.kt | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt b/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt index cdf910f03..12d449738 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt @@ -1,9 +1,11 @@ package content.global.travel.balloon +import core.api.MapArea import core.api.closeInterface import core.api.closeOverlay import core.api.closeTabInterface import core.api.getAttribute +import core.api.getRegionBorders import core.api.openOverlay import core.api.playAudio import core.api.removeAttribute @@ -19,6 +21,8 @@ import core.game.interaction.InteractionListener import core.game.node.entity.player.Player import core.game.system.task.Pulse import core.game.world.map.Location +import core.game.world.map.zone.ZoneBorders +import core.game.world.map.zone.ZoneRestriction import core.game.world.update.flag.context.Animation import core.net.packet.PacketRepository import core.net.packet.context.MinimapStateContext @@ -31,6 +35,7 @@ import org.rs09.consts.Components */ object BalloonCrashSites { + const val CRASH_SITE_REGION = 7244 const val SCENERY_OCEAN_PLANK = 19126 const val SCENERY_WOODLAND_DIRT = 19125 @@ -115,6 +120,7 @@ object BalloonCrashSites { WoodlandExit.ARDOUGNE -> { teleport(player, WOODLAND_ARDOUGNE_EXIT) + player.faceLocation(WOODLAND_ARDOUGNE_EXIT_FACE_LOCATION) // TODO: Placeholder message, find 09 source. sendPlayerDialogue(player, "The crash must have really sent us off course; I'm near Ardougne!") } @@ -188,7 +194,7 @@ object BalloonCrashSites { } -class BalloonCrashSiteListener : InteractionListener { +class BalloonCrashSiteListener : InteractionListener, MapArea { override fun defineListeners() { on(BalloonCrashSites.SCENERY_OCEAN_PLANK, IntType.SCENERY, "use") { player, _ -> BalloonCrashSites.leaveOceanCrashSite(player) @@ -211,6 +217,14 @@ class BalloonCrashSiteListener : InteractionListener { } } + + override fun defineAreaBorders(): Array { + return arrayOf(getRegionBorders(BalloonCrashSites.CRASH_SITE_REGION)) + } + + override fun getRestrictions(): Array { + return arrayOf(ZoneRestriction.TELEPORT) + } } class BalloonCrashDialogue : DialogueLabeller() { @@ -225,18 +239,18 @@ class BalloonCrashDialogue : DialogueLabeller() { } label("ocean_crash") - npc("Great Scott! Ocean! Ahhh!") - player("What happened?") - npc("Crashed, off course. Ocean! Oh dear... I feel very...") - player("Contemplative? Concerned for your life? Desperate?") - npc("No...more along the lines of ill...You might want to swim away now. Use the plank...") - player("How are you going to get back? What about the balloon?") - npc("I'm sure a fishing trawler will come by and give me a lift. Don't worry, I shall return.") + npc("Great Scott! Ocean! Ahhh!") + player("What happened?") + npc("Crashed, off course. Ocean! Oh dear... I feel very...") + player("Contemplative? Concerned for your life? Desperate?") + npc("No...more along the lines of ill...You might want to swim away now. Use the plank...") + player("How are you going to get back? What about the balloon?") + npc("I'm sure a fishing trawler will come by and give me a lift. Don't worry, I shall return.") label("woodland_crash") - npc("Well, that didn't go as planned.") - player("So what now? How will we get the balloon back?") - npc("I'll have to get one of the monks to come pick it up. You head back on your own; just follow the path. I'll meet you back at Entrana.") + npc("Well, that didn't go as planned.") + player("So what now? How will we get the balloon back?") + npc("I'll have to get one of the monks to come pick it up. You head back on your own; just follow the path. I'll meet you back at Entrana.") } } \ No newline at end of file From 624ee69b0684fb9de98c5a18daac214105284af7 Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Mon, 6 Jul 2026 14:20:23 +0200 Subject: [PATCH 04/14] Following fixes: Refactored and moved directory. Rebuilt jsons. Empty labels goto nowhere. Cleaned up weird indentations. Cutscenes end "without fade." --- Server/data/configs/npc_spawns.json | 2 +- .../skill/farming/UseWithPatchHandler.kt | 2 +- .../balloon/BalloonAssistantsDialogue.kt | 4 +- .../travel/balloon/BalloonFlightInterface.kt | 2 +- .../travel/balloon/BalloonTravelInterface.kt | 4 +- .../cutscene/BalloonConstructionCutscene.kt | 14 +- .../cutscene/BalloonExperimentCutscene.kt | 14 +- .../SecondBalloonExperimentCutscene.kt | 12 +- .../dialogue/AugusteDialogue.kt | 187 +++++------------- .../quest/EnlightenedJourney.kt | 101 ++-------- .../quest/EnlightenedJourneyListeners.kt | 19 +- 11 files changed, 112 insertions(+), 249 deletions(-) rename Server/src/main/content/region/misc/{ => entrana}/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt (80%) rename Server/src/main/content/region/misc/{ => entrana}/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt (90%) rename Server/src/main/content/region/misc/{ => entrana}/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt (90%) rename Server/src/main/content/region/misc/{ => entrana}/quest/enlightenedjourney/dialogue/AugusteDialogue.kt (85%) rename Server/src/main/content/region/misc/{ => entrana}/quest/enlightenedjourney/quest/EnlightenedJourney.kt (77%) rename Server/src/main/content/region/misc/{ => entrana}/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt (90%) diff --git a/Server/data/configs/npc_spawns.json b/Server/data/configs/npc_spawns.json index ee8028b79..50e91a604 100644 --- a/Server/data/configs/npc_spawns.json +++ b/Server/data/configs/npc_spawns.json @@ -157,7 +157,7 @@ }, { "npc_id": "47", - "loc_data": "{2821,3170,0,1,1}-{3341,3267,0,1,5}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3001,3202,0,1,5}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" + "loc_data": "{2821,3170,0,1,1}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3341,3267,0,1,5}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3001,3202,0,1,5}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" }, { "npc_id": "48", diff --git a/Server/src/main/content/global/skill/farming/UseWithPatchHandler.kt b/Server/src/main/content/global/skill/farming/UseWithPatchHandler.kt index e420a894c..5c5b9c086 100644 --- a/Server/src/main/content/global/skill/farming/UseWithPatchHandler.kt +++ b/Server/src/main/content/global/skill/farming/UseWithPatchHandler.kt @@ -13,7 +13,7 @@ import core.tools.StringUtils import core.tools.prependArticle import org.rs09.consts.Sounds import content.data.Quests -import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney +import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney class UseWithPatchHandler : InteractionListener { val RAKE = Items.RAKE_5341 diff --git a/Server/src/main/content/global/travel/balloon/BalloonAssistantsDialogue.kt b/Server/src/main/content/global/travel/balloon/BalloonAssistantsDialogue.kt index 4b7a9bd3c..ca8f14ad2 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonAssistantsDialogue.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonAssistantsDialogue.kt @@ -13,7 +13,7 @@ class BalloonAssistantsDialogue(private val start: BalloonTravelLocation) : Dial npc("Do you want to use the balloon? Just so you know, some locations require special logs and high Firemaking skills.") options( DialogueOption("yes_fly_balloon", "Yes.", "Yes."), - DialogueOption("no_fly_balloon", "No.", "No."), + DialogueOption("nowhere", "No.", "No."), DialogueOption("who_are_you", "Who are you?", "Who are you?") ) @@ -60,7 +60,7 @@ class BalloonAssistantsDialogue(private val start: BalloonTravelLocation) : Dial npc("Do you want to use the balloon?") options( DialogueOption("yes_fly_balloon", "Yes.", "Yes."), - DialogueOption("no_fly_balloon", "No.", "No.") + DialogueOption("nowhere", "No.", "No.") ) } diff --git a/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt index c469aeda9..1a1515b0f 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt @@ -1,7 +1,7 @@ package content.global.travel.balloon import content.data.Quests -import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney +import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney import core.api.closeInterface import core.api.closeOverlay import core.api.closeTabInterface diff --git a/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt index d723ec3e0..1adcb2dbd 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt @@ -1,8 +1,8 @@ package content.global.travel.balloon import content.data.Quests -import content.region.misc.quest.enlightenedjourney.dialogue.AugusteDialogueFile -import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney +import content.region.misc.entrana.quest.enlightenedjourney.dialogue.AugusteDialogueFile +import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney import content.region.misthalin.varrock.diary.VarrockAchivementDiary.Companion.MediumTasks.HOTAIR_BALLOON_TRAVEL_SOMEWHERE import core.api.amountInInventory import core.api.animateInterface diff --git a/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt similarity index 80% rename from Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt rename to Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt index b5b7a5e45..b0be90c57 100644 --- a/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt @@ -1,8 +1,8 @@ -package content.region.misc.quest.enlightenedjourney.cutscene +package content.region.misc.entrana.quest.enlightenedjourney.cutscene import content.data.Quests -import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_FLIGHT -import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.VARBIT_ENTRANA_BALLOON +import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_FLIGHT +import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.VARBIT_ENTRANA_BALLOON import core.api.face import core.api.setQuestStage import core.api.setVarbit @@ -62,7 +62,13 @@ class BalloonConstructionCutscene(player: Player) : Cutscene(player) { } 5 -> { - end { + fadeToBlack() + timedUpdate(3) + } + + 6 -> { + endWithoutFade { + fadeFromBlack() setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, STAGE_FLIGHT) } } diff --git a/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt similarity index 90% rename from Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt rename to Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt index 7404b443c..69c54db4c 100644 --- a/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt @@ -1,7 +1,7 @@ -package content.region.misc.quest.enlightenedjourney.cutscene +package content.region.misc.entrana.quest.enlightenedjourney.cutscene import content.data.Quests -import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_FIRST_EXPERIMENT +import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_FIRST_EXPERIMENT import core.api.face import core.api.setQuestStage import core.api.visualize @@ -85,10 +85,16 @@ class BalloonExperimentCutscene(player: Player) : Cutscene(player) { FacialExpression.HAPPY, "We shall meekly go! No...no...it needs to sound grander. We shall cautiously go..." ) - 11 -> playerDialogueUpdate(FacialExpression.HALF_WORRIED, "We're doomed.") + 12 -> { - end { + fadeToBlack() + timedUpdate(3) + } + + 13 -> { + endWithoutFade { + fadeFromBlack() setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, STAGE_FIRST_EXPERIMENT) } } diff --git a/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt similarity index 90% rename from Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt rename to Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt index a8a55faf6..b625cd2c3 100644 --- a/Server/src/main/content/region/misc/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt @@ -1,7 +1,7 @@ -package content.region.misc.quest.enlightenedjourney.cutscene +package content.region.misc.entrana.quest.enlightenedjourney.cutscene import content.data.Quests -import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_SECOND_EXPERIMENT +import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_SECOND_EXPERIMENT import core.api.animate import core.api.face import core.api.sendChat @@ -98,7 +98,13 @@ class SecondBalloonExperimentCutscene(player: Player) : Cutscene(player) { } 8 -> { - end { + fadeToBlack() + timedUpdate(3) + } + + 9 -> { + endWithoutFade { + fadeFromBlack() setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, STAGE_SECOND_EXPERIMENT) } } diff --git a/Server/src/main/content/region/misc/quest/enlightenedjourney/dialogue/AugusteDialogue.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/dialogue/AugusteDialogue.kt similarity index 85% rename from Server/src/main/content/region/misc/quest/enlightenedjourney/dialogue/AugusteDialogue.kt rename to Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/dialogue/AugusteDialogue.kt index 9f2412690..97e3512e8 100644 --- a/Server/src/main/content/region/misc/quest/enlightenedjourney/dialogue/AugusteDialogue.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/dialogue/AugusteDialogue.kt @@ -1,12 +1,12 @@ -package content.region.misc.quest.enlightenedjourney.dialogue +package content.region.misc.entrana.quest.enlightenedjourney.dialogue import content.data.Quests import content.global.travel.balloon.BalloonFlightInterface import content.global.travel.balloon.BalloonTravelInterface import content.global.travel.balloon.BalloonTravelLocation -import content.region.misc.quest.enlightenedjourney.cutscene.BalloonExperimentCutscene -import content.region.misc.quest.enlightenedjourney.cutscene.SecondBalloonExperimentCutscene -import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney +import content.region.misc.entrana.quest.enlightenedjourney.cutscene.BalloonExperimentCutscene +import content.region.misc.entrana.quest.enlightenedjourney.cutscene.SecondBalloonExperimentCutscene +import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney import core.api.addItem import core.api.amountInBank import core.api.amountInInventory @@ -111,26 +111,17 @@ class AugusteDialogueFile : DialogueLabeller() { player(FacialExpression.ASKING, "Who are you?") npc(FacialExpression.HAPPY, "I am Auguste. I am going to be the first balloonist in all of Gielinor!") player(FacialExpression.HALF_THINKING, "Balloo-what? I thought only monks lived on Entrana.") - npc( - FacialExpression.SUSPICIOUS, - "Well, they do...I was a monk. But I'm so sick of living on this island! I want to explore new frontiers!" - ) + npc(FacialExpression.SUSPICIOUS, "Well, they do...I was a monk. But I'm so sick of living on this island! I want to explore new frontiers!") player(FacialExpression.LAUGH, "And go where no man has gone before?") npc(FacialExpression.HAPPY, "Maybe! That sounds good. I was thinking just over to Taverley, though.") player(FacialExpression.ASKING, "Why not take the boat then?") npc(FacialExpression.ANGRY, "Ugh! Ocean! Don't talk to me about the ocean...oh dear...I think I feel ill.") - player( - FacialExpression.AMAZED_TALKING, - "Whoa, ok, no ocean. How exactly are you going to get off the island, then?" - ) - npc( - FacialExpression.NEUTRAL, - "I have devised a new way to travel. But I need an assistant balloonist to help me build my design." - ) + player(FacialExpression.AMAZED_TALKING, "Whoa, ok, no ocean. How exactly are you going to get off the island, then?") + npc(FacialExpression.NEUTRAL, "I have devised a new way to travel. But I need an assistant balloonist to help me build my design.") npc(FacialExpression.HALF_ASKING, "Are you an experienced adventurer willing to help me?") options( DialogueOption("sign_me_up", "Yes! Sign me up.", "Yes! Sign me up.", FacialExpression.FRIENDLY), - DialogueOption("not_right_now", "Not right now.", "Not right now.") + DialogueOption("nowhere", "Not right now.", "Not right now.") ) label("sign_me_up") @@ -141,10 +132,7 @@ class AugusteDialogueFile : DialogueLabeller() { } npc(FacialExpression.HAPPY, "Wonderful! Let's get started.") player(FacialExpression.HALF_THINKING, "Wait. I still don't know exactly what we're doing.") - npc( - FacialExpression.AMAZED_TALKING, - "Of course, of course, how foolish of me. Well, we are going to make a balloon." - ) + npc(FacialExpression.AMAZED_TALKING, "Of course, of course, how foolish of me. Well, we are going to make a balloon.") player(FacialExpression.HALF_THINKING, "Which is what exactly?") npc(FacialExpression.HAPPY, "Let me show you!") exec { player, _ -> @@ -157,7 +145,7 @@ class AugusteDialogueFile : DialogueLabeller() { sendMessage(player, "You do not meet the requirements to start : 'Enlightened Journey'.") } - label(questStageLabel(EnlightenedJourney.STAGE_QUEST_STARTED)) + label(questStageLabel(EnlightenedJourney.STAGE_QUEST_STARTED)) player(FacialExpression.LAUGH, "How exactly do you plan to get to Taverley in that? How will it work?") npc(FacialExpression.FRIENDLY, "Have you noticed how ashes float above fires for long periods of time?") goto("ashes_float") @@ -183,42 +171,30 @@ class AugusteDialogueFile : DialogueLabeller() { label("whats_your_point") npc(FacialExpression.HAPPY, "Don't you see? It's the hot air! It rises, taking the ashes with it.") - npc( - FacialExpression.HAPPY, - "I had this epiphany while I was at the glass blower's house. If we pump hot air into an envelope it will rise because it is lighter than the cold air around it." - ) + npc(FacialExpression.HAPPY, "I had this epiphany while I was at the glass blower's house. If we pump hot air into an envelope it will rise because it is lighter than the cold air around it.") player(FacialExpression.HALF_THINKING, "Come again?") npc("We are going to sew a big sack and light a fire under it. Once the sack fills with hot air it will begin to rise, taking us along with it in the basket.") player(FacialExpression.HALF_WORRIED, "You seem pretty confident about this. Have you tested it?") - npc( - FacialExpression.SAD_TALKING, - "Well, no. You see, I don't have the materials here to make any test balloons." - ) + npc(FacialExpression.SAD_TALKING, "Well, no. You see, I don't have the materials here to make any test balloons.") npc(FacialExpression.HAPPY, "That's where you come in!") npc(FacialExpression.HAPPY, "You are going to collect materials for two test runs of the balloon.") - npc( - FacialExpression.HAPPY, - "You will need to get three sheets of papyrus, one ball of wool, one full sack of potatoes, and one unlit candle." - ) + npc(FacialExpression.HAPPY, "You will need to get three sheets of papyrus, one ball of wool, one full sack of potatoes, and one unlit candle.") player(FacialExpression.THINKING, "What am I supposed to do with all that junk?") npc("When you have all of it, bring it to me and I'll explain what to do next. Any questions?") player("Where do I get all this stuff?") - npc( - FacialExpression.ANGRY, - "You're the adventurer, you should know! Think of logical places, like, churches; they have tons of candles." - ) + npc(FacialExpression.ANGRY, "You're the adventurer, you should know! Think of logical places, like, churches; they have tons of candles.") exec { player, _ -> setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, EnlightenedJourney.STAGE_GATHER_MATERIALS) } label(questStageLabel(EnlightenedJourney.STAGE_GATHER_MATERIALS)) - npc(FacialExpression.ASKING, "Have you gotten the materials?") - options( - DialogueOption("are_materials_gathered?", "Yes.", "Yes.", FacialExpression.HAPPY), - DialogueOption("failure_not_option", "No.", "No."), - DialogueOption("what_materials_needed", "What do I need to get again?", "What do I need to get again?") - ) + npc(FacialExpression.ASKING, "Have you gotten the materials?") + options( + DialogueOption("are_materials_gathered?", "Yes.", "Yes.", FacialExpression.HAPPY), + DialogueOption("failure_not_option", "No.", "No."), + DialogueOption("what_materials_needed", "What do I need to get again?", "What do I need to get again?") + ) label("are_materials_gathered?") exec { player, _ -> @@ -276,10 +252,7 @@ class AugusteDialogueFile : DialogueLabeller() { label("missing_all_materials") npc(FacialExpression.SAD_TALKING, "You don't seem to have any of the materials.") - npc( - FacialExpression.SAD_TALKING, - "You need a ball of wool, three sheets of papyrus, an unlit candle, and a full sack of potatoes." - ) + npc(FacialExpression.SAD_TALKING, "You need a ball of wool, three sheets of papyrus, an unlit candle, and a full sack of potatoes.") label("missing_more_papyrus") npc(FacialExpression.SAD_TALKING, "You need more papyrus.") @@ -326,17 +299,11 @@ class AugusteDialogueFile : DialogueLabeller() { label("materials_are_gathered") npc(FacialExpression.HAPPY, "Good, you have everything! Now, I need you to create an origami balloon.") player(FacialExpression.HALF_THINKING, "How do you make the origami balloon?") - npc( - FacialExpression.HAPPY, - "First, use the papyrus on the ball of wool. The papyrus is folded into an origami box and the yarn will support the heat source." - ) - npc( - FacialExpression.HAPPY, - "Next, add the unlit candle to the balloon structure. It will act as the heat source." - ) + npc(FacialExpression.HAPPY, "First, use the papyrus on the ball of wool. The papyrus is folded into an origami box and the yarn will support the heat source.") + npc(FacialExpression.HAPPY, "Next, add the unlit candle to the balloon structure. It will act as the heat source.") npc(FacialExpression.HAPPY, "Once you have done that let me know and we will begin our experiment.") - label(questStageLabel(EnlightenedJourney.STAGE_ORIGAMI_BALLOON)) + label(questStageLabel(EnlightenedJourney.STAGE_ORIGAMI_BALLOON)) exec { player, _ -> if (amountInInventory(player, Items.ORIGAMI_BALLOON_9934) >= 1) { loadLabel(player, "first_experiment") @@ -359,7 +326,7 @@ class AugusteDialogueFile : DialogueLabeller() { BalloonExperimentCutscene(player).start() } - label(questStageLabel(EnlightenedJourney.STAGE_FIRST_EXPERIMENT)) + label(questStageLabel(EnlightenedJourney.STAGE_FIRST_EXPERIMENT)) npc(FacialExpression.HAPPY, "Do you have the other two sheets of papyrus and a full sack of potatoes?") options( DialogueOption("has_second_materials", "Yes, I have them here.", "Yes, I have them here."), @@ -391,37 +358,28 @@ class AugusteDialogueFile : DialogueLabeller() { npc(FacialExpression.SAD_TALKING, "You need a full sack of potatoes and more papyrus.") label("second_experiment") - npc(FacialExpression.HAPPY, "Commendable. If I may have those, I will construct this experiment.") + npc(FacialExpression.HAPPY, "Commendable. If I may have those, I will construct this experiment.") exec { player, _ -> removeItem(player, Item(Items.PAPYRUS_970, 2)) removeItem(player, Item(Items.POTATOES10_5438, 1)) SecondBalloonExperimentCutscene(player).start() } - label(questStageLabel(EnlightenedJourney.STAGE_SECOND_EXPERIMENT)) + label(questStageLabel(EnlightenedJourney.STAGE_SECOND_EXPERIMENT)) player(FacialExpression.HALF_THINKING, "Those peasants... where did they come from?") npc("Ahh, the flash mob phenomenon. Many have hypothesized that they are beings of great power sent to smite those who question the gods.") player(FacialExpression.HALF_THINKING, "And this isn't worrying because...?") npc(FacialExpression.HAPPY, "Don't worry! I know exactly what I'm doing.") npc(FacialExpression.HAPPY, "Those experiments went extraordinarily well.") player(FacialExpression.HALF_WORRIED, "Was I the ONLY one who saw them burning?", "BURNING???") - npc( - FacialExpression.HAPPY, - "Yes, very well indeed. Now we will start building the balloon that will carry us off the island." - ) + npc(FacialExpression.HAPPY, "Yes, very well indeed. Now we will start building the balloon that will carry us off the island.") npc(FacialExpression.HAPPY, "This task will be much greater than the last two. I hope you are prepared for it.") player("This is madness.") npc(FacialExpression.HAPPY, "You need to get the following items:") npc(FacialExpression.HAPPY, "Yellow dye", "Red dye", "Ten pieces of silk", "A clay bowl") npc(FacialExpression.HAPPY, "and eight sandbags.") - npc( - FacialExpression.HAPPY, - "Sandbags can be made by getting empty sacks and filling them at the sand pit here on Entrana." - ) - npc( - FacialExpression.HAPPY, - "However, there are other sand pits around the world that will work as well; there is one in Yanille, Rellekka, and Zanaris." - ) + npc(FacialExpression.HAPPY, "Sandbags can be made by getting empty sacks and filling them at the sand pit here on Entrana.") + npc(FacialExpression.HAPPY, "However, there are other sand pits around the world that will work as well; there is one in Yanille, Rellekka, and Zanaris.") npc("You can bring items back to me as you get them, while you are waiting for the tree to grow.") player(FacialExpression.HALF_THINKING, "What tree?") npc("I am going to give you a willow sapling and a basket of apples. You must plant the willow sapling at a tree patch.") @@ -435,23 +393,12 @@ class AugusteDialogueFile : DialogueLabeller() { setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, EnlightenedJourney.STAGE_MAIN_BALLOON) } - label(questStageLabel(EnlightenedJourney.STAGE_MAIN_BALLOON)) + label(questStageLabel(EnlightenedJourney.STAGE_MAIN_BALLOON)) npc(FacialExpression.HAPPY, "Do you have anything for me?") options( - DialogueOption( - "yes_give_items", - "Yes, I want to give you some items.", - "Yes, I want to give you some items." - ), - DialogueOption( - "trouble_finding_items", - "I'm having trouble finding some items.", - "I'm having trouble finding some items." - ), - DialogueOption( - "lost_sapling_check", - "I have lost my willow sapling. Can I buy a replacement?", - "I have lost my willow sapling. Can I buy a replacement?", + DialogueOption("yes_give_items", "Yes, I want to give you some items.", "Yes, I want to give you some items."), + DialogueOption("trouble_finding_items", "I'm having trouble finding some items.", "I'm having trouble finding some items."), + DialogueOption("lost_sapling_check", "I have lost my willow sapling. Can I buy a replacement?", "I have lost my willow sapling. Can I buy a replacement?", optionIf = { player, _ -> !getAttribute(player, EnlightenedJourney.ATTRIBUTE_SAPLING_PLANTED, false) }), @@ -480,7 +427,7 @@ class AugusteDialogueFile : DialogueLabeller() { optionIf = { player, _ -> !getAttribute(player, EnlightenedJourney.ATTRIBUTE_BOWL_DELIVERED, false) }), - DialogueOption("never_mind", "Never mind.", "Never mind."), + DialogueOption("nowhere", "Never mind.", "Never mind."), ) label("noted_item") @@ -560,10 +507,7 @@ class AugusteDialogueFile : DialogueLabeller() { label("not_enough_sandbags") npc(FacialExpression.SAD, "You don't have enough sandbags. Please bring me eight.") - npc( - FacialExpression.HAPPY, - "Sandbags can be made by getting empty sacks and filling them at the sandpit here on Entrana." - ) + npc(FacialExpression.HAPPY, "Sandbags can be made by getting empty sacks and filling them at the sandpit here on Entrana.") npc(FacialExpression.HAPPY, "However, there are other sand pits around the world that will work as well.") goto("yes_give_items") @@ -605,10 +549,7 @@ class AugusteDialogueFile : DialogueLabeller() { } label("take_bowl") - npc( - FacialExpression.HAPPY, - "Ah the bowl. This will be used to hold the fuel while it heats the air in the balloon." - ) + npc(FacialExpression.HAPPY, "Ah the bowl. This will be used to hold the fuel while it heats the air in the balloon.") exec { player, _ -> removeItem(player, Item(Items.BOWL_1923, 1)) setAttribute(player, EnlightenedJourney.ATTRIBUTE_BOWL_DELIVERED, true) @@ -639,7 +580,7 @@ class AugusteDialogueFile : DialogueLabeller() { npc("It will cost you 30,000 gold coins to replace it, do you want to pay that?") options( DialogueOption("sapling_replacement_yes", "Yes.", "Yes."), - DialogueOption("sapling_replacement_no", "No way!", "No way!"), + DialogueOption("nowhere", "No way!", "No way!"), ) label("sapling_replacement_yes") @@ -688,7 +629,7 @@ class AugusteDialogueFile : DialogueLabeller() { optionIf = { player, _ -> !getAttribute(player, EnlightenedJourney.ATTRIBUTE_BOWL_DELIVERED, false) }), - DialogueOption("never_mind", "Never mind.", skipPlayer = true) + DialogueOption("nowhere", "Never mind.", skipPlayer = true) ) label("hint_dye") @@ -704,40 +645,26 @@ class AugusteDialogueFile : DialogueLabeller() { label("hint_bowl") npc("I think there is a spare one in the glass blower's house. I rent a room from him there, so I don't think he'll mind you taking it.") - label(questStageLabel(EnlightenedJourney.STAGE_WILLOW_BASKET)) - npc( - FacialExpression.HAPPY, - "You just need to build the basket and I can finish the balloon! How are you getting on with the willow?" - ) + label(questStageLabel(EnlightenedJourney.STAGE_WILLOW_BASKET)) + npc(FacialExpression.HAPPY, "You just need to build the basket and I can finish the balloon! How are you getting on with the willow?") options( - DialogueOption( - "lost_sapling_check", - "I have lost my willow sapling. Can I buy a replacement?", - "I have lost my willow sapling. Can I buy a replacement?", + DialogueOption("lost_sapling_check", "I have lost my willow sapling. Can I buy a replacement?", "I have lost my willow sapling. Can I buy a replacement?", optionIf = { player, _ -> !getAttribute(player, EnlightenedJourney.ATTRIBUTE_SAPLING_PLANTED, false) }), - DialogueOption( - "build_the_basket", - "What do I do again?", - "What do I do again?", - FacialExpression.HALF_THINKING - ), - DialogueOption("fine_thanks", "Fine thanks.", "Fine thanks."), + DialogueOption("build_the_basket", "What do I do again?", "What do I do again?", FacialExpression.HALF_THINKING), + DialogueOption("nowhere", "Fine thanks.", "Fine thanks."), ) label("build_the_basket") - npc( - FacialExpression.HAPPY, - "Use the willow sapling I gave you to grow a willow tree. Cut twelve branches from it using secateurs. Use the branches on the platform here." - ) + npc(FacialExpression.HAPPY, "Use the willow sapling I gave you to grow a willow tree. Cut twelve branches from it using secateurs. Use the branches on the platform here.") - label(questStageLabel(EnlightenedJourney.STAGE_FLIGHT)) + label(questStageLabel(EnlightenedJourney.STAGE_FLIGHT)) npc(FacialExpression.HAPPY, "Well, let's get going!") options( DialogueOption("wait_tell_me", "Wait; tell me what we're doing.", "Wait; tell me what we're doing."), DialogueOption("maiden_voyage", "Okay.", "Okay."), - DialogueOption("not_ready", "No, I'm not ready.", "No, I'm not ready.") + DialogueOption("nowhere", "No, I'm not ready.", "No, I'm not ready.") ) label("wait_tell_me") @@ -763,7 +690,7 @@ class AugusteDialogueFile : DialogueLabeller() { npc("Are you ready to go?") options( DialogueOption("maiden_voyage", "Okay.", "Okay."), - DialogueOption("not_ready", "No, I'm not ready.", "No, I'm not ready.") + DialogueOption("nowhere", "No, I'm not ready.", "No, I'm not ready.") ) label("maiden_voyage") @@ -794,16 +721,10 @@ class AugusteDialogueFile : DialogueLabeller() { } } - label(questStageLabel(EnlightenedJourney.STAGE_CLAIM_REWARD)) - npc( - FacialExpression.HAPPY, - "We have travelled in a way that no man has travelled before! The next step will be to go where no men have gone before." - ) + label(questStageLabel(EnlightenedJourney.STAGE_CLAIM_REWARD)) + npc(FacialExpression.HAPPY, "We have travelled in a way that no man has travelled before! The next step will be to go where no men have gone before.") npc(FacialExpression.HAPPY, "@name, it has been a privilege flying with you.") - npc( - FacialExpression.HAPPY, - "For all your hard work, I give you this jacket and cap for future ballooning adventures." - ) + npc(FacialExpression.HAPPY, "For all your hard work, I give you this jacket and cap for future ballooning adventures.") exec { player, _ -> if (freeSlots(player) < 2) { loadLabel(player, "reward_no_space") @@ -815,7 +736,7 @@ class AugusteDialogueFile : DialogueLabeller() { label("reward_no_space") npc("You don't have enough space in your inventory. Speak to me again when you do.") - label(questStageLabel(EnlightenedJourney.STAGE_COMPLETE)) + label(questStageLabel(EnlightenedJourney.STAGE_COMPLETE)) exec { player, talkingNpc -> if (talkingNpc.originalId == 5062) { loadLabel(player, "post_quest_taverley") @@ -833,7 +754,7 @@ class AugusteDialogueFile : DialogueLabeller() { npc("Do you want to use the balloon? Just so you know, some locations require special logs and high Firemaking skills.") options( DialogueOption("post_quest_yes", "Yes.", "Yes."), - DialogueOption("post_quest_no", "No.", "No."), + DialogueOption("nowhere", "No.", "No."), DialogueOption( "post_quest_origami", "Could you tell me how to make an origami balloon?", @@ -891,7 +812,7 @@ class AugusteDialogueFile : DialogueLabeller() { npc("Do you want to use the balloon? Just so you know, some locations require special logs and high Firemaking skills.") options( DialogueOption("yes_fly_balloon", "Yes.", "Yes."), - DialogueOption("post_quest_no", "No.", "No."), + DialogueOption("nowhere", "No.", "No."), DialogueOption("post_quest_origami", "Could you tell me how to make an origami balloon?", "Could you tell me how to make an origami balloon?"), DialogueOption("replace_bomber_clothes", "Could you replace some items for me?", "Could you replace some items for me?") { player, _ -> hasLostBomberReward(player) }, DialogueOption("combine_cap_goggles", "Could you combine my cap and goggles?", "Could you combine my cap and goggles?") { player, _ -> hasCapAndGoggles(player) } diff --git a/Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourney.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt similarity index 77% rename from Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourney.kt rename to Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt index 79ec6e695..995765792 100644 --- a/Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourney.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt @@ -1,4 +1,4 @@ -package content.region.misc.quest.enlightenedjourney.quest +package content.region.misc.entrana.quest.enlightenedjourney.quest import content.data.Quests import core.api.addItemOrDrop @@ -26,7 +26,7 @@ class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, VARBI companion object { val questName = Quests.ENLIGHTENED_JOURNEY - /** Quest progress varbit used for the quests tab. Red = not started, Yellow = in progress, Green = completed. */ + /** Quest progress varbit used for the quests tab. 0 = not started, 1 = in progress, 200 = completed. */ const val VARBIT_QUEST_PROGRESS = 2866 /** Entrana balloon scenery state varbit. */ @@ -100,66 +100,25 @@ class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, VARBI } if (stage >= STAGE_QUEST_STARTED) { - line( - player, - "I have agreed to help Auguste build an !!air balloon??.", - line++, - stage > STAGE_GATHER_MATERIALS - ) + line(player, "I have agreed to help Auguste build an !!air balloon??.", line++, stage > STAGE_GATHER_MATERIALS) line(player, "I have no idea what he's talking about.", line++, stage > STAGE_GATHER_MATERIALS) - line( - player, - "Auguste thinks if he pumps hot air into a sack it will rise and", - line++, - stage > STAGE_GATHER_MATERIALS - ) + line(player, "Auguste thinks if he pumps hot air into a sack it will rise and", line++, stage > STAGE_GATHER_MATERIALS) line(player, "take us along with it.", line++, stage > STAGE_GATHER_MATERIALS) - line( - player, - "But we're going to run some tests first. Thank goodness.", - line++, - stage > STAGE_GATHER_MATERIALS - ) + line(player, "But we're going to run some tests first. Thank goodness.", line++, stage > STAGE_GATHER_MATERIALS) line++ } if (stage >= STAGE_GATHER_MATERIALS) { line(player, "I need to gather the materials Auguste required:", line++, stage > STAGE_GATHER_MATERIALS) - line( - player, "three sheets of papyrus", line++, stage > STAGE_GATHER_MATERIALS || inInventory( - player, - Items.PAPYRUS_970, - 3 - ) - ) - line( - player, "a ball of wool", line++, stage > STAGE_GATHER_MATERIALS || inInventory( - player, - Items.BALL_OF_WOOL_1759 - ) - ) - line( - player, "a full sack of potatoes", line++, stage > STAGE_GATHER_MATERIALS || inInventory( - player, - Items.POTATOES10_5438 - ) - ) - line( - player, "one unlit candle.", line++, stage > STAGE_GATHER_MATERIALS || inInventory( - player, - Items.CANDLE_36 - ) - ) + line(player, "three sheets of papyrus", line++, stage > STAGE_GATHER_MATERIALS || inInventory(player, Items.PAPYRUS_970, 3)) + line(player, "a ball of wool", line++, stage > STAGE_GATHER_MATERIALS || inInventory(player, Items.BALL_OF_WOOL_1759)) + line(player, "a full sack of potatoes", line++, stage > STAGE_GATHER_MATERIALS || inInventory(player, Items.POTATOES10_5438)) + line(player, "one unlit candle.", line++, stage > STAGE_GATHER_MATERIALS || inInventory(player, Items.CANDLE_36)) line++ } if (stage >= STAGE_ORIGAMI_BALLOON) { - line( - player, "I made an !!origami balloon??.", line++, stage > STAGE_ORIGAMI_BALLOON || inInventory( - player, - Items.ORIGAMI_BALLOON_9934 - ) - ) + line(player, "I made an !!origami balloon??.", line++, stage > STAGE_ORIGAMI_BALLOON || inInventory(player, Items.ORIGAMI_BALLOON_9934)) line(player, "Auguste said I could make these any time I want if", line++, stage > STAGE_ORIGAMI_BALLOON) line(player, "I have the materials.", line++, stage > STAGE_ORIGAMI_BALLOON) line++ @@ -173,52 +132,24 @@ class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, VARBI if (stage >= STAGE_SECOND_EXPERIMENT) { line(player, "Auguste conducted the second experiment.", line++, stage > STAGE_SECOND_EXPERIMENT) - line( - player, - "A flash mob appeared. They seem to have a grudge against", - line++, - stage > STAGE_SECOND_EXPERIMENT - ) + line(player, "A flash mob appeared. They seem to have a grudge against", line++, stage > STAGE_SECOND_EXPERIMENT) line(player, "science.", line++, stage > STAGE_SECOND_EXPERIMENT) line++ } if (stage >= STAGE_MAIN_BALLOON) { - line( - player, - "I need to gather the supplies for Auguste's main balloon:", - line++, - stage > STAGE_MAIN_BALLOON - ) + line(player, "I need to gather the supplies for Auguste's main balloon:", line++, stage > STAGE_MAIN_BALLOON) line(player, "red dye", line++, stage > STAGE_MAIN_BALLOON || inInventory(player, Items.RED_DYE_1763)) line(player, "yellow dye", line++, stage > STAGE_MAIN_BALLOON || inInventory(player, Items.YELLOW_DYE_1765)) - line( - player, "ten pieces of silk", line++, stage > STAGE_MAIN_BALLOON || inInventory( - player, - Items.SILK_950, - 10 - ) - ) + line(player, "ten pieces of silk", line++, stage > STAGE_MAIN_BALLOON || inInventory(player, Items.SILK_950, 10)) line(player, "a bowl", line++, stage > STAGE_MAIN_BALLOON || inInventory(player, Items.BOWL_1923)) - line( - player, "eight sandbags", line++, stage > STAGE_MAIN_BALLOON || inInventory( - player, - Items.SANDBAG_9943, - 8 - ) - ) + line(player, "eight sandbags", line++, stage > STAGE_MAIN_BALLOON || inInventory(player, Items.SANDBAG_9943, 8)) line++ } if (stage >= STAGE_WILLOW_BASKET) { line(player, "I need to make the basket for the balloon:", line++, stage > STAGE_WILLOW_BASKET) - line( - player, "twelve willow branches", line++, stage > STAGE_WILLOW_BASKET || inInventory( - player, - Items.WILLOW_BRANCH_5933, - 12 - ) - ) + line(player, "twelve willow branches", line++, stage > STAGE_WILLOW_BASKET || inInventory(player, Items.WILLOW_BRANCH_5933, 12)) line++ } @@ -237,7 +168,7 @@ class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, VARBI } if (stage >= STAGE_COMPLETE) { - line(player, "QUEST COMPLETE!", line++) + line(player, "%%QUEST COMPLETE!&&", line++) line++ line(player, "I can now make !!Origami balloons??.", line++) line(player, "I can also use the !!balloon transport system??.", line++) diff --git a/Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt similarity index 90% rename from Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt rename to Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt index 9e1d500a4..0161b7319 100644 --- a/Server/src/main/content/region/misc/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt @@ -1,8 +1,8 @@ -package content.region.misc.quest.enlightenedjourney.quest +package content.region.misc.entrana.quest.enlightenedjourney.quest import content.data.Quests -import content.region.misc.quest.enlightenedjourney.cutscene.BalloonConstructionCutscene -import content.region.misc.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_WILLOW_BASKET +import content.region.misc.entrana.quest.enlightenedjourney.cutscene.BalloonConstructionCutscene +import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_WILLOW_BASKET import core.api.MapArea import core.api.addItem import core.api.amountInInventory @@ -78,11 +78,7 @@ class EnlightenedJourneyListeners : InteractionListener, MapArea { /** Make sandbag from bucket of sand. */ onUseWith(IntType.ITEM, Items.EMPTY_SACK_5418, Items.BUCKET_OF_SAND_1783) { player, _, _ -> - if (amountInInventory(player, Items.EMPTY_SACK_5418) >= 1 && amountInInventory( - player, - Items.BUCKET_OF_SAND_1783 - ) >= 1 - ) { + if (amountInInventory(player, Items.EMPTY_SACK_5418) >= 1 && amountInInventory(player, Items.BUCKET_OF_SAND_1783) >= 1) { removeItem(player, Item(Items.EMPTY_SACK_5418, 1)) removeItem(player, Item(Items.BUCKET_OF_SAND_1783, 1)) addItem(player, Items.SANDBAG_9943, 1) @@ -137,11 +133,8 @@ class EnlightenedJourneyListeners : InteractionListener, MapArea { class BalloonConstructionDialogue : DialogueFile() { override fun handle(componentID: Int, buttonID: Int) { when (stage) { - 0 -> npc( - NPCs.AUGUSTE_5049, - "Great! Let me just put it together and we'll be ready", - "to lift off! Speak to me again in a moment." - ).also { stage++ } + 0 -> npc(NPCs.AUGUSTE_5049, "Great! Let me just put it together and we'll be ready", + "for lift off! Speak to me again in a moment.").also { stage++ } 1 -> { if (amountInInventory(player!!, Items.WILLOW_BRANCH_5933) < 12) { From a741ab7f0667e052806d66e488b3df54ff9df6bf Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Mon, 6 Jul 2026 19:18:25 +0200 Subject: [PATCH 05/14] ContentAPI --- .../item/withobject/SandSourceListener.kt | 3 +- .../travel/balloon/BalloonCrashSites.kt | 67 ++++++++----------- .../travel/balloon/BalloonFlightInterface.kt | 40 +++++------ .../travel/balloon/BalloonTravelInterface.kt | 6 +- .../cutscene/BalloonConstructionCutscene.kt | 6 +- .../cutscene/BalloonExperimentCutscene.kt | 6 +- .../SecondBalloonExperimentCutscene.kt | 6 +- .../quest/EnlightenedJourney.kt | 45 +++++++------ .../quest/EnlightenedJourneyListeners.kt | 12 +++- 9 files changed, 92 insertions(+), 99 deletions(-) diff --git a/Server/src/main/content/global/handlers/item/withobject/SandSourceListener.kt b/Server/src/main/content/global/handlers/item/withobject/SandSourceListener.kt index bbde6bc21..6d35c62e7 100644 --- a/Server/src/main/content/global/handlers/item/withobject/SandSourceListener.kt +++ b/Server/src/main/content/global/handlers/item/withobject/SandSourceListener.kt @@ -20,7 +20,8 @@ class SandSourceListener : InteractionListener { private val SAND_PITS = intArrayOf( Scenery.SAND_PIT_2645, Scenery.SAND_PIT_4373, - Scenery.SANDPIT_10814 + Scenery.SANDPIT_10814, + Scenery.SANDPIT_22726 ) } diff --git a/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt b/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt index 12d449738..e51bdba99 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt @@ -4,22 +4,25 @@ import core.api.MapArea import core.api.closeInterface import core.api.closeOverlay import core.api.closeTabInterface +import core.api.delayScript +import core.api.face import core.api.getAttribute import core.api.getRegionBorders import core.api.openOverlay import core.api.playAudio +import core.api.queueScript import core.api.removeAttribute import core.api.sendMessage import core.api.sendPlayerDialogue import core.api.setAttribute -import core.api.submitIndividualPulse +import core.api.stopExecuting import core.api.teleport import core.api.unlock import core.game.dialogue.DialogueLabeller import core.game.interaction.IntType import core.game.interaction.InteractionListener +import core.game.interaction.QueueStrength import core.game.node.entity.player.Player -import core.game.system.task.Pulse import core.game.world.map.Location import core.game.world.map.zone.ZoneBorders import core.game.world.map.zone.ZoneRestriction @@ -80,7 +83,7 @@ object BalloonCrashSites { closeFlightInterface(player) teleport(player, OCEAN_CRASH_LANDING) oceanSwimmingAnimations(player) - player.faceLocation(OCEAN_CRASH_FACE_LOCATION) + face(player, OCEAN_CRASH_FACE_LOCATION) sendMessage(player, "The balloon crashes.") } } @@ -91,7 +94,7 @@ object BalloonCrashSites { player.appearance.setAnimations() player.appearance.sync() teleport(player, OCEAN_CRASH_EXIT) - player.faceLocation(OCEAN_CRASH_EXIT_FACE_LOCATION) + face(player, OCEAN_CRASH_EXIT_FACE_LOCATION) sendMessage(player, "You manage to swim back to shore.") } } @@ -102,7 +105,7 @@ object BalloonCrashSites { fadeTransition(player) { closeFlightInterface(player) teleport(player, WOODLAND_CRASH_LANDING) - player.faceLocation(WOODLAND_CRASH_FACE_LOCATION) + face(player, WOODLAND_CRASH_FACE_LOCATION) sendMessage(player, "The balloon crashes.") } } @@ -114,13 +117,13 @@ object BalloonCrashSites { when (exit) { WoodlandExit.FALADOR -> { teleport(player, WOODLAND_FALADOR_EXIT) - player.faceLocation(WOODLAND_FALADOR_EXIT_FACE_LOCATION) + face(player, WOODLAND_FALADOR_EXIT_FACE_LOCATION) sendPlayerDialogue(player, "The crash must have really sent us off course; I'm near Falador!") } WoodlandExit.ARDOUGNE -> { teleport(player, WOODLAND_ARDOUGNE_EXIT) - player.faceLocation(WOODLAND_ARDOUGNE_EXIT_FACE_LOCATION) + face(player, WOODLAND_ARDOUGNE_EXIT_FACE_LOCATION) // TODO: Placeholder message, find 09 source. sendPlayerDialogue(player, "The crash must have really sent us off course; I'm near Ardougne!") } @@ -147,44 +150,32 @@ object BalloonCrashSites { if (fadeToBlack) { player.lock() openOverlay(player, Components.FADE_TO_BLACK_120) - submitIndividualPulse(player, object : Pulse() { - var counter = 0 - override fun pulse(): Boolean { - when (counter++) { - 4 -> { - whileBlack() - closeOverlay(player) - openOverlay(player, Components.FADE_FROM_BLACK_170) - } - - 7 -> { - closeOverlay(player) - unlock(player) - return true - } + queueScript(player, 4, QueueStrength.SOFT) { stage -> + when (stage) { + 0 -> { + whileBlack() + closeOverlay(player) + openOverlay(player, Components.FADE_FROM_BLACK_170) + return@queueScript delayScript(player, 3) + } + + else -> { + closeOverlay(player) + unlock(player) + return@queueScript stopExecuting(player) } - return false } - }) + } return } whileBlack() closeOverlay(player) openOverlay(player, Components.FADE_FROM_BLACK_170) - submitIndividualPulse(player, object : Pulse() { - var counter = 0 - - override fun pulse(): Boolean { - when (counter++) { - 3 -> { - closeOverlay(player) - unlock(player) - return true - } - } - return false - } - }) + queueScript(player, 3, QueueStrength.SOFT) { + closeOverlay(player) + unlock(player) + return@queueScript stopExecuting(player) + } } private fun oceanSwimmingAnimations(player: Player) { diff --git a/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt index 1a1515b0f..c8ad3fcc8 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt @@ -5,22 +5,24 @@ import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJou import core.api.closeInterface import core.api.closeOverlay import core.api.closeTabInterface +import core.api.face import core.api.getAttribute import core.api.openInterface import core.api.openOverlay import core.api.openSingleTab import core.api.playAudio -import core.api.removeAttribute +import core.api.queueScript +import core.api.removeAttributes import core.api.sendMessage import core.api.setAttribute import core.api.setQuestStage import core.api.setVarbit -import core.api.submitIndividualPulse +import core.api.stopExecuting import core.api.teleport import core.api.unlock import core.game.interaction.InterfaceListener +import core.game.interaction.QueueStrength import core.game.node.entity.player.Player -import core.game.system.task.Pulse import core.game.world.map.Location import core.net.packet.PacketRepository import core.net.packet.context.MinimapStateContext @@ -289,7 +291,7 @@ class BalloonFlightInterface : InterfaceListener { showGameTabs(player) showMinimap(player) teleport(player, BalloonFlightRoutes.TAVERLEY_LANDING) - player.faceLocation(Location.create(2941, 3421, 0)) + face(player, Location.create(2941, 3421, 0)) sendMessage(player, "You arrive safely in Taverley.") setVarbit(player, EnlightenedJourney.VARBIT_TAVERLEY_BALLOON, 1, true) setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, EnlightenedJourney.STAGE_CLAIM_REWARD) @@ -450,11 +452,13 @@ class BalloonFlightInterface : InterfaceListener { } private fun clearFlightAttributes(player: Player) { - removeAttribute(player, ATTRIBUTE_BALLOON_TOP) - removeAttribute(player, ATTRIBUTE_BALLOON_BOTTOM) - removeAttribute(player, ATTRIBUTE_FLIGHT_DESTINATION) - removeAttribute(player, ATTRIBUTE_FLIGHT_SCREEN) - removeAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS) + removeAttributes( + player, ATTRIBUTE_BALLOON_TOP, + ATTRIBUTE_BALLOON_BOTTOM, + ATTRIBUTE_FLIGHT_DESTINATION, + ATTRIBUTE_FLIGHT_SCREEN, + ATTRIBUTE_FLIGHT_PROGRESS + ) } private fun playControlSound(player: Player, buttonId: Int) { @@ -489,19 +493,11 @@ class BalloonFlightInterface : InterfaceListener { whileBlack() closeOverlay(player) openOverlay(player, Components.FADE_FROM_BLACK_170) - submitIndividualPulse(player, object : Pulse() { - var counter = 0 - override fun pulse(): Boolean { - when (counter++) { - 3 -> { - closeOverlay(player) - unlock(player) - return true - } - } - return false - } - }) + queueScript(player, 3, QueueStrength.SOFT) { + closeOverlay(player) + unlock(player) + return@queueScript stopExecuting(player) + } } } diff --git a/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt index 1adcb2dbd..cd8ebdf71 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt @@ -10,8 +10,8 @@ import core.api.animationDuration import core.api.closeInterface import core.api.findLocalNPC import core.api.getAttribute -import core.api.getStatLevel import core.api.getVarbit +import core.api.hasLevelStat import core.api.isQuestComplete import core.api.lock import core.api.openDialogue @@ -100,7 +100,7 @@ class BalloonTravelInterface : InterfaceListener, InteractionListener { return false } - if (getStatLevel(player, Skills.FIREMAKING) < destination.requiredFiremakingLevel) { + if (!hasLevelStat(player, Skills.FIREMAKING, destination.requiredFiremakingLevel)) { sendMessage( player, "You require a Firemaking level of ${destination.requiredFiremakingLevel} to travel there." @@ -138,7 +138,7 @@ class BalloonTravelInterface : InterfaceListener, InteractionListener { return false } - if (getStatLevel(player, Skills.FIREMAKING) < destination.requiredFiremakingLevel) { + if (!hasLevelStat(player, Skills.FIREMAKING, destination.requiredFiremakingLevel)) { sendMessage( player, "You require a Firemaking level of ${destination.requiredFiremakingLevel} to travel there." diff --git a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt index b0be90c57..bb4dfe000 100644 --- a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt @@ -4,15 +4,13 @@ import content.data.Quests import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_FLIGHT import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.VARBIT_ENTRANA_BALLOON import core.api.face +import core.api.playJingle import core.api.setQuestStage import core.api.setVarbit import core.game.activity.Cutscene import core.game.node.entity.player.Player import core.game.world.map.Direction import core.game.world.map.Location -import core.net.packet.PacketRepository -import core.net.packet.context.MusicContext -import core.net.packet.out.MusicPacket import org.rs09.consts.NPCs /** @@ -41,7 +39,7 @@ class BalloonConstructionCutscene(player: Player) : Cutscene(player) { val obj = getObject(55, 26)!! face(player, obj.location) fadeFromBlack() - PacketRepository.send(MusicPacket::class.java, MusicContext(player, 116, true)) + playJingle(player, 116) setVarbit(player, VARBIT_ENTRANA_BALLOON, 2, true) timedUpdate(5) } diff --git a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt index 69c54db4c..f7e8ef402 100644 --- a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt @@ -3,6 +3,7 @@ package content.region.misc.entrana.quest.enlightenedjourney.cutscene import content.data.Quests import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_FIRST_EXPERIMENT import core.api.face +import core.api.playJingle import core.api.setQuestStage import core.api.visualize import core.game.activity.Cutscene @@ -11,9 +12,6 @@ import core.game.node.entity.impl.Projectile import core.game.node.entity.player.Player import core.game.world.map.Direction import core.game.world.map.Location -import core.net.packet.PacketRepository -import core.net.packet.context.MusicContext -import core.net.packet.out.MusicPacket import org.rs09.consts.NPCs /** @@ -41,7 +39,7 @@ class BalloonExperimentCutscene(player: Player) : Cutscene(player) { rotateCamera(54, 18, 400) addNPC(NPCs.AUGUSTE_5049, 57, 27, Direction.SOUTH_WEST) fadeFromBlack() - PacketRepository.send(MusicPacket::class.java, MusicContext(player, 116, true)) + playJingle(player, 116) timedUpdate(6) } diff --git a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt index b625cd2c3..49151dcab 100644 --- a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt @@ -4,6 +4,7 @@ import content.data.Quests import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_SECOND_EXPERIMENT import core.api.animate import core.api.face +import core.api.playJingle import core.api.sendChat import core.api.setQuestStage import core.api.visualize @@ -13,9 +14,6 @@ import core.game.node.entity.impl.Projectile import core.game.node.entity.player.Player import core.game.world.map.Direction import core.game.world.map.Location -import core.net.packet.PacketRepository -import core.net.packet.context.MusicContext -import core.net.packet.out.MusicPacket import org.rs09.consts.NPCs /** @@ -44,7 +42,7 @@ class SecondBalloonExperimentCutscene(player: Player) : Cutscene(player) { rotateCamera(54, 18, 400) addNPC(NPCs.AUGUSTE_5049, 57, 27, Direction.SOUTH_WEST) fadeFromBlack() - PacketRepository.send(MusicPacket::class.java, MusicContext(player, 116, true)) + playJingle(player, 116) timedUpdate(6) } diff --git a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt index 995765792..50b1ee9f6 100644 --- a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt @@ -3,11 +3,14 @@ package content.region.misc.entrana.quest.enlightenedjourney.quest import content.data.Quests import core.api.addItemOrDrop import core.api.getAttribute +import core.api.getQuestPoints import core.api.getQuestStage -import core.api.getStatLevel +import core.api.hasLevelStat import core.api.inInventory -import core.api.removeAttribute +import core.api.removeAttributes import core.api.rewardXP +import core.api.sendItemZoomOnInterface +import core.api.setInterfaceText import core.api.setVarbit import core.game.node.entity.player.Player import core.game.node.entity.player.link.quest.Quest @@ -93,10 +96,10 @@ class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, VARBI if (stage == 0) { line(player, "I can start this quest by speaking to !!Auguste?? on !!Entrana??.", line++) line(player, "Minimum Requirements:", line++) - line(player, "Level 36 Crafting", line++, getStatLevel(player, Skills.CRAFTING) >= 36) - line(player, "Level 30 Farming", line++, getStatLevel(player, Skills.FARMING) >= 30) - line(player, "Level 20 Firemaking", line++, getStatLevel(player, Skills.FIREMAKING) >= 20) - line(player, "20 Quest Points", line, core.api.getQuestPoints(player) >= 20) + line(player, "Level 36 Crafting", line++, hasLevelStat(player, Skills.CRAFTING, 36)) + line(player, "Level 30 Farming", line++, hasLevelStat(player, Skills.FARMING, 30)) + line(player, "Level 20 Firemaking", line++, hasLevelStat(player, Skills.FIREMAKING, 20)) + line(player, "20 Quest Points", line, getQuestPoints(player) >= 20) } if (stage >= STAGE_QUEST_STARTED) { @@ -178,18 +181,18 @@ class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, VARBI } override fun hasRequirements(player: Player): Boolean { - return getStatLevel(player, Skills.CRAFTING) >= 36 && - getStatLevel(player, Skills.FARMING) >= 30 && - getStatLevel(player, Skills.FIREMAKING) >= 20 && - core.api.getQuestPoints(player) >= 20 + return hasLevelStat(player, Skills.CRAFTING, 36) && + hasLevelStat(player, Skills.FARMING, 30) && + hasLevelStat(player, Skills.FIREMAKING, 20) && + getQuestPoints(player) >= 20 } override fun finish(player: Player) { super.finish(player) var line = 10 - player.packetDispatch.sendString("You have completed Enlightened Journey!", 277, 4) - player.packetDispatch.sendItemZoomOnInterface(Items.BOMBER_CAP_9945, 230, 277, 5) + setInterfaceText(player, "You have completed Enlightened Journey!", 277, 4) + sendItemZoomOnInterface(player, 277, 5, Items.BOMBER_CAP_9945) drawReward(player, "1 Quest Point", line++) drawReward(player, "2,000 Crafting XP", line++) @@ -220,14 +223,16 @@ class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, VARBI setVarbit(player, VARBIT_GRANDTREE_BALLOON, 0, true) setVarbit(player, VARBIT_CRAFTINGGUILD_BALLOON, 0, true) setVarbit(player, VARBIT_VARROCK_BALLOON, 0, true) - removeAttribute(player, ATTRIBUTE_YELLOW_DYE_DELIVERED) - removeAttribute(player, ATTRIBUTE_RED_DYE_DELIVERED) - removeAttribute(player, ATTRIBUTE_SANDBAGS_DELIVERED) - removeAttribute(player, ATTRIBUTE_SILK_DELIVERED) - removeAttribute(player, ATTRIBUTE_BOWL_DELIVERED) - removeAttribute(player, ATTRIBUTE_SAPLING_PLANTED) - removeAttribute(player, ATTRIBUTE_TAVERLEY_AUGUSTE_REPLACED) - removeAttribute(player, ATTRIBUTE_AUGUSTE_POST_EXPLANATION) + removeAttributes( + player, ATTRIBUTE_YELLOW_DYE_DELIVERED, + ATTRIBUTE_RED_DYE_DELIVERED, + ATTRIBUTE_SANDBAGS_DELIVERED, + ATTRIBUTE_SILK_DELIVERED, + ATTRIBUTE_BOWL_DELIVERED, + ATTRIBUTE_SAPLING_PLANTED, + ATTRIBUTE_TAVERLEY_AUGUSTE_REPLACED, + ATTRIBUTE_AUGUSTE_POST_EXPLANATION + ) } override fun updateVarps(player: Player) { diff --git a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt index 0161b7319..9260e55ba 100644 --- a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt @@ -24,6 +24,7 @@ import core.game.node.item.Item import core.game.world.map.zone.ZoneBorders import org.rs09.consts.Items import org.rs09.consts.NPCs +import org.rs09.consts.Scenery /** * Listeners for the Enlightened Journey quest. @@ -66,8 +67,13 @@ class EnlightenedJourneyListeners : InteractionListener, MapArea { return@onUseWith true } - /** Make sandbag from sandpit. Entrana/Zanaris, Rellekka, Yanille. */ - onUseWith(IntType.SCENERY, Items.EMPTY_SACK_5418, 2645, 4373, 10814) { player, _, _ -> + /** Make sandbag from sandpit. Entrana/Zanaris, Rellekka, Yanille, Dorgesh-Kaan. */ + onUseWith(IntType.SCENERY, Items.EMPTY_SACK_5418, + Scenery.SAND_PIT_2645, + Scenery.SAND_PIT_4373, + Scenery.SANDPIT_10814, + Scenery.SANDPIT_22726 + ) { player, _, _ -> if (removeItem(player, Item(Items.EMPTY_SACK_5418, 1))) { animate(player, 5155) addItem(player, Items.SANDBAG_9943, 1) @@ -89,7 +95,7 @@ class EnlightenedJourneyListeners : InteractionListener, MapArea { } /** Using willow branches on the basket frame to construct the Entrana balloon. */ - onUseWith(IntType.SCENERY, Items.WILLOW_BRANCH_5933, 19132) { player, _, _ -> + onUseWith(IntType.SCENERY, Items.WILLOW_BRANCH_5933, Scenery.BASKET_19132) { player, _, _ -> if (getQuestStage(player, Quests.ENLIGHTENED_JOURNEY) != STAGE_WILLOW_BASKET) { return@onUseWith false } From 3f8a844d1dfe073b59a006eb2bb6ed738878bf40 Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Mon, 6 Jul 2026 20:39:21 +0200 Subject: [PATCH 06/14] Fixed the following: Auguste dialogue cleaned up and no longer hangs. Assist. dialogue cleaned up. Varbit constants. Constant suffix. --- .../balloon/BalloonAssistantsDialogue.kt | 12 +- .../travel/balloon/BalloonFlightInterface.kt | 2 +- .../travel/balloon/BalloonTravelInterface.kt | 16 +- .../cutscene/BalloonConstructionCutscene.kt | 5 +- .../dialogue/AugusteDialogue.kt | 156 ++++++++++-------- .../quest/EnlightenedJourney.kt | 69 ++++---- 6 files changed, 142 insertions(+), 118 deletions(-) diff --git a/Server/src/main/content/global/travel/balloon/BalloonAssistantsDialogue.kt b/Server/src/main/content/global/travel/balloon/BalloonAssistantsDialogue.kt index ca8f14ad2..69cc72da2 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonAssistantsDialogue.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonAssistantsDialogue.kt @@ -12,9 +12,9 @@ class BalloonAssistantsDialogue(private val start: BalloonTravelLocation) : Dial override fun addConversation() { npc("Do you want to use the balloon? Just so you know, some locations require special logs and high Firemaking skills.") options( - DialogueOption("yes_fly_balloon", "Yes.", "Yes."), - DialogueOption("nowhere", "No.", "No."), - DialogueOption("who_are_you", "Who are you?", "Who are you?") + DialogueOption("yes_fly_balloon", "Yes."), + DialogueOption("nowhere", "No."), + DialogueOption("who_are_you", "Who are you?") ) label("yes_fly_balloon") @@ -59,9 +59,9 @@ class BalloonAssistantsDialogue(private val start: BalloonTravelLocation) : Dial label("ask_fly") npc("Do you want to use the balloon?") options( - DialogueOption("yes_fly_balloon", "Yes.", "Yes."), - DialogueOption("nowhere", "No.", "No.") + DialogueOption("yes_fly_balloon", "Yes."), + DialogueOption("nowhere", "No.") ) - } + } } \ No newline at end of file diff --git a/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt index c8ad3fcc8..9ae93527a 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt @@ -293,7 +293,7 @@ class BalloonFlightInterface : InterfaceListener { teleport(player, BalloonFlightRoutes.TAVERLEY_LANDING) face(player, Location.create(2941, 3421, 0)) sendMessage(player, "You arrive safely in Taverley.") - setVarbit(player, EnlightenedJourney.VARBIT_TAVERLEY_BALLOON, 1, true) + setVarbit(player, EnlightenedJourney.VARBIT_TAVERLEY_BALLOON_2868, EnlightenedJourney.TAVERLEY_BALLOON_AUGUSTE_1, true) setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, EnlightenedJourney.STAGE_CLAIM_REWARD) } } diff --git a/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt index cd8ebdf71..81580306c 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt @@ -91,7 +91,7 @@ class BalloonTravelInterface : InterfaceListener, InteractionListener { /** Checks the saved route unlock state. */ private fun hasRouteUnlocked(player: Player, destination: BalloonTravelLocation): Boolean { - return getVarbit(player, destination.varbit) > 0 + return getVarbit(player, destination.varbit) > EnlightenedJourney.BALLOON_ROUTE_LOCKED_0 } /** Checks if the player can use an unlocked route. */ @@ -192,7 +192,7 @@ class BalloonTravelInterface : InterfaceListener, InteractionListener { return } - setVarbit(player, destination.varbit, 1, true) + setVarbit(player, destination.varbit, EnlightenedJourney.BALLOON_ROUTE_UNLOCKED_1, true) rewardXP(player, Skills.FIREMAKING, 2000.0) } @@ -280,7 +280,7 @@ enum class BalloonTravelLocation( Items.YEW_LOGS_1515, 10, 50, - EnlightenedJourney.VARBIT_CASTLEWARS_BALLOON, + EnlightenedJourney.VARBIT_CASTLEWARS_BALLOON_2869, ASSISTANT_MARROW_WRAPPER, 19137, ), @@ -291,7 +291,7 @@ enum class BalloonTravelLocation( Items.MAGIC_LOGS_1513, 3, 60, - EnlightenedJourney.VARBIT_GRANDTREE_BALLOON, + EnlightenedJourney.VARBIT_GRANDTREE_BALLOON_2870, ASSISTANT_LE_SMITH_WRAPPER, 19139, ), @@ -302,7 +302,7 @@ enum class BalloonTravelLocation( Items.OAK_LOGS_1521, 10, 30, - EnlightenedJourney.VARBIT_CRAFTINGGUILD_BALLOON, + EnlightenedJourney.VARBIT_CRAFTINGGUILD_BALLOON_2871, ASSISTANT_BROCK_WRAPPER, 19141, ), @@ -313,7 +313,7 @@ enum class BalloonTravelLocation( Items.LOGS_1511, 1, 20, - EnlightenedJourney.VARBIT_ENTRANA_BALLOON, + EnlightenedJourney.VARBIT_ENTRANA_BALLOON_2867, NPCs.AUGUSTE_5049, 19133, ), @@ -324,7 +324,7 @@ enum class BalloonTravelLocation( Items.LOGS_1511, 1, 20, - EnlightenedJourney.VARBIT_TAVERLEY_BALLOON, + EnlightenedJourney.VARBIT_TAVERLEY_BALLOON_2868, ASSISTANT_STAN_WRAPPER, 19135, ), @@ -335,7 +335,7 @@ enum class BalloonTravelLocation( Items.WILLOW_LOGS_1519, 10, 40, - EnlightenedJourney.VARBIT_VARROCK_BALLOON, + EnlightenedJourney.VARBIT_VARROCK_BALLOON_2872, ASSISTANT_SERF_WRAPPER, 19143, ); diff --git a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt index bb4dfe000..b75efabae 100644 --- a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt @@ -1,8 +1,9 @@ package content.region.misc.entrana.quest.enlightenedjourney.cutscene import content.data.Quests +import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.ENTRANA_BALLOON_COMPLETE_2 import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_FLIGHT -import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.VARBIT_ENTRANA_BALLOON +import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.VARBIT_ENTRANA_BALLOON_2867 import core.api.face import core.api.playJingle import core.api.setQuestStage @@ -40,7 +41,7 @@ class BalloonConstructionCutscene(player: Player) : Cutscene(player) { face(player, obj.location) fadeFromBlack() playJingle(player, 116) - setVarbit(player, VARBIT_ENTRANA_BALLOON, 2, true) + setVarbit(player, VARBIT_ENTRANA_BALLOON_2867, ENTRANA_BALLOON_COMPLETE_2, true) timedUpdate(5) } diff --git a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/dialogue/AugusteDialogue.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/dialogue/AugusteDialogue.kt index 97e3512e8..3ea226325 100644 --- a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/dialogue/AugusteDialogue.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/dialogue/AugusteDialogue.kt @@ -68,7 +68,7 @@ class AugusteTalkListener : InteractionListener { } } -private fun checkAllItemsDelivered(player: Player) { +private fun checkAllItemsDelivered(player: Player): Boolean { val allDelivered = getAttribute(player, EnlightenedJourney.ATTRIBUTE_YELLOW_DYE_DELIVERED, false) && getAttribute(player, EnlightenedJourney.ATTRIBUTE_RED_DYE_DELIVERED, false) && getAttribute(player, EnlightenedJourney.ATTRIBUTE_SANDBAGS_DELIVERED, false) && @@ -77,6 +77,7 @@ private fun checkAllItemsDelivered(player: Player) { if (allDelivered) { setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, EnlightenedJourney.STAGE_WILLOW_BASKET) } + return allDelivered } private fun questStageLabel(stage: Int) = "quest_stage_$stage" @@ -120,8 +121,8 @@ class AugusteDialogueFile : DialogueLabeller() { npc(FacialExpression.NEUTRAL, "I have devised a new way to travel. But I need an assistant balloonist to help me build my design.") npc(FacialExpression.HALF_ASKING, "Are you an experienced adventurer willing to help me?") options( - DialogueOption("sign_me_up", "Yes! Sign me up.", "Yes! Sign me up.", FacialExpression.FRIENDLY), - DialogueOption("nowhere", "Not right now.", "Not right now.") + DialogueOption("sign_me_up", "Yes! Sign me up.", expression = FacialExpression.FRIENDLY), + DialogueOption("nowhere", "Not right now.") ) label("sign_me_up") @@ -152,17 +153,8 @@ class AugusteDialogueFile : DialogueLabeller() { label("ashes_float") options( - DialogueOption( - "whats_your_point", - "Umm, yes. What's your point?", - "What's your point?", - FacialExpression.THINKING - ), - DialogueOption( - "cant_see_detail", - "Err, no. I can't see that kind of detail.", - "Err, no. I can't see that kind of detail." - ) + DialogueOption("whats_your_point", "Umm, yes. What's your point?", "What's your point?", FacialExpression.THINKING), + DialogueOption("cant_see_detail", "Err, no. I can't see that kind of detail.") ) label("cant_see_detail") @@ -191,9 +183,9 @@ class AugusteDialogueFile : DialogueLabeller() { label(questStageLabel(EnlightenedJourney.STAGE_GATHER_MATERIALS)) npc(FacialExpression.ASKING, "Have you gotten the materials?") options( - DialogueOption("are_materials_gathered?", "Yes.", "Yes.", FacialExpression.HAPPY), - DialogueOption("failure_not_option", "No.", "No."), - DialogueOption("what_materials_needed", "What do I need to get again?", "What do I need to get again?") + DialogueOption("are_materials_gathered?", "Yes.", expression = FacialExpression.HAPPY), + DialogueOption("failure_not_option", "No."), + DialogueOption("what_materials_needed", "What do I need to get again?") ) label("are_materials_gathered?") @@ -229,7 +221,8 @@ class AugusteDialogueFile : DialogueLabeller() { when { hasNoPapyrus && !wool && !potatoes && !candle -> loadLabel(player, "missing_all_materials") - hasSomePapyrus && wool && potatoes && candle -> loadLabel(player, "missing_more_papyrus") + hasSomePapyrus && !wool && !potatoes && !candle -> loadLabel(player, "missing_papyrus_wool_candle_and_potatoes") + !hasAllPapyrus && wool && potatoes && candle -> loadLabel(player, "missing_more_papyrus") hasAllPapyrus && !wool && potatoes && candle -> loadLabel(player, "missing_wool") hasAllPapyrus && wool && potatoes && !candle -> loadLabel(player, "missing_candle") hasAllPapyrus && wool && !potatoes && candle -> loadLabel(player, "missing_potatoes") @@ -241,11 +234,7 @@ class AugusteDialogueFile : DialogueLabeller() { hasAllPapyrus && wool && !potatoes && !candle -> loadLabel(player, "missing_candle_and_potatoes") !hasAllPapyrus && !wool && potatoes && !candle -> loadLabel(player, "missing_wool_papyrus_and_candle") !hasAllPapyrus && !wool && !potatoes && candle -> loadLabel(player, "missing_wool_papyrus_and_potatoes") - !hasAllPapyrus && wool && !potatoes && !candle -> loadLabel( - player, - "missing_papyrus_potatoes_and_candle" - ) - + !hasAllPapyrus && wool && !potatoes && !candle -> loadLabel(player, "missing_papyrus_potatoes_and_candle") hasAllPapyrus && !wool && !potatoes && !candle -> loadLabel(player, "missing_wool_candle_and_potatoes") } } @@ -257,6 +246,9 @@ class AugusteDialogueFile : DialogueLabeller() { label("missing_more_papyrus") npc(FacialExpression.SAD_TALKING, "You need more papyrus.") + label("missing_papyrus_wool_candle_and_potatoes") + npc(FacialExpression.SAD_TALKING, "You need more papyrus, a ball of wool, an unlit candle, and a full sack of potatoes.") + label("missing_wool") npc(FacialExpression.SAD_TALKING, "You need a ball of wool.") @@ -329,8 +321,8 @@ class AugusteDialogueFile : DialogueLabeller() { label(questStageLabel(EnlightenedJourney.STAGE_FIRST_EXPERIMENT)) npc(FacialExpression.HAPPY, "Do you have the other two sheets of papyrus and a full sack of potatoes?") options( - DialogueOption("has_second_materials", "Yes, I have them here.", "Yes, I have them here."), - DialogueOption("misplaced_second_materials", "Oh, I've misplaced them.", "Oh, I've misplaced them.") + DialogueOption("has_second_materials", "Yes, I have them here."), + DialogueOption("misplaced_second_materials", "Oh, I've misplaced them.") ) label("has_second_materials") @@ -396,9 +388,9 @@ class AugusteDialogueFile : DialogueLabeller() { label(questStageLabel(EnlightenedJourney.STAGE_MAIN_BALLOON)) npc(FacialExpression.HAPPY, "Do you have anything for me?") options( - DialogueOption("yes_give_items", "Yes, I want to give you some items.", "Yes, I want to give you some items."), - DialogueOption("trouble_finding_items", "I'm having trouble finding some items.", "I'm having trouble finding some items."), - DialogueOption("lost_sapling_check", "I have lost my willow sapling. Can I buy a replacement?", "I have lost my willow sapling. Can I buy a replacement?", + DialogueOption("yes_give_items", "Yes, I want to give you some items."), + DialogueOption("trouble_finding_items", "I'm having trouble finding some items."), + DialogueOption("lost_sapling_check", "I have lost my willow sapling. Can I buy a replacement?", optionIf = { player, _ -> !getAttribute(player, EnlightenedJourney.ATTRIBUTE_SAPLING_PLANTED, false) }), @@ -427,19 +419,26 @@ class AugusteDialogueFile : DialogueLabeller() { optionIf = { player, _ -> !getAttribute(player, EnlightenedJourney.ATTRIBUTE_BOWL_DELIVERED, false) }), - DialogueOption("nowhere", "Never mind.", "Never mind."), + DialogueOption("nowhere", "Never mind."), ) + label("all_items_delivered") + npc(FacialExpression.HAPPY, "That's the last of it!") + goto(questStageLabel(EnlightenedJourney.STAGE_WILLOW_BASKET)) + label("noted_item") npc(FacialExpression.SAD, "What am I supposed to do with a note? I can't make a balloon from notes!") goto("yes_give_items") label("give_dye") exec { player, _ -> - val hasNoted = amountInInventory(player, Items.YELLOW_DYE_1766) >= 1 || - amountInInventory(player, Items.RED_DYE_1764) >= 1 - val hasYellow = amountInInventory(player, Items.YELLOW_DYE_1765) >= 1 - val hasRed = amountInInventory(player, Items.RED_DYE_1763) >= 1 + val needsYellow = !getAttribute(player, EnlightenedJourney.ATTRIBUTE_YELLOW_DYE_DELIVERED, false) + val needsRed = !getAttribute(player, EnlightenedJourney.ATTRIBUTE_RED_DYE_DELIVERED, false) + + val hasNoted = (needsYellow && amountInInventory(player, Items.YELLOW_DYE_1766) >= 1) || + (needsRed && amountInInventory(player, Items.RED_DYE_1764) >= 1) + val hasYellow = needsYellow && amountInInventory(player, Items.YELLOW_DYE_1765) >= 1 + val hasRed = needsRed && amountInInventory(player, Items.RED_DYE_1763) >= 1 when { hasYellow && hasRed -> loadLabel(player, "give_both_dyes") hasYellow -> loadLabel(player, "give_yellow_dye") @@ -454,14 +453,16 @@ class AugusteDialogueFile : DialogueLabeller() { exec { player, _ -> removeItem(player, Item(Items.YELLOW_DYE_1765, 1)) setAttribute(player, EnlightenedJourney.ATTRIBUTE_YELLOW_DYE_DELIVERED, true) - checkAllItemsDelivered(player) } npc(FacialExpression.HAPPY, "Red dye. Thank you.") exec { player, _ -> removeItem(player, Item(Items.RED_DYE_1763, 1)) setAttribute(player, EnlightenedJourney.ATTRIBUTE_RED_DYE_DELIVERED, true) - checkAllItemsDelivered(player) - loadLabel(player, "yes_give_items") + if (checkAllItemsDelivered(player)) { + loadLabel(player, "all_items_delivered") + } else { + loadLabel(player, "yes_give_items") + } } label("give_yellow_dye") @@ -469,8 +470,11 @@ class AugusteDialogueFile : DialogueLabeller() { exec { player, _ -> removeItem(player, Item(Items.YELLOW_DYE_1765, 1)) setAttribute(player, EnlightenedJourney.ATTRIBUTE_YELLOW_DYE_DELIVERED, true) - checkAllItemsDelivered(player) - loadLabel(player, "yes_give_items") + if (checkAllItemsDelivered(player)) { + loadLabel(player, "all_items_delivered") + } else { + loadLabel(player, "yes_give_items") + } } label("give_red_dye") @@ -478,8 +482,11 @@ class AugusteDialogueFile : DialogueLabeller() { exec { player, _ -> removeItem(player, Item(Items.RED_DYE_1763, 1)) setAttribute(player, EnlightenedJourney.ATTRIBUTE_RED_DYE_DELIVERED, true) - checkAllItemsDelivered(player) - loadLabel(player, "yes_give_items") + if (checkAllItemsDelivered(player)) { + loadLabel(player, "all_items_delivered") + } else { + loadLabel(player, "yes_give_items") + } } label("no_dye") @@ -501,8 +508,11 @@ class AugusteDialogueFile : DialogueLabeller() { exec { player, _ -> removeItem(player, Item(Items.SANDBAG_9943, 8)) setAttribute(player, EnlightenedJourney.ATTRIBUTE_SANDBAGS_DELIVERED, true) - checkAllItemsDelivered(player) - loadLabel(player, "yes_give_items") + if (checkAllItemsDelivered(player)) { + loadLabel(player, "all_items_delivered") + } else { + loadLabel(player, "yes_give_items") + } } label("not_enough_sandbags") @@ -528,8 +538,11 @@ class AugusteDialogueFile : DialogueLabeller() { exec { player, _ -> removeItem(player, Item(Items.SILK_950, 10)) setAttribute(player, EnlightenedJourney.ATTRIBUTE_SILK_DELIVERED, true) - checkAllItemsDelivered(player) - loadLabel(player, "yes_give_items") + if (checkAllItemsDelivered(player)) { + loadLabel(player, "all_items_delivered") + } else { + loadLabel(player, "yes_give_items") + } } label("not_enough_silk") @@ -553,8 +566,11 @@ class AugusteDialogueFile : DialogueLabeller() { exec { player, _ -> removeItem(player, Item(Items.BOWL_1923, 1)) setAttribute(player, EnlightenedJourney.ATTRIBUTE_BOWL_DELIVERED, true) - checkAllItemsDelivered(player) - loadLabel(player, "yes_give_items") + if (checkAllItemsDelivered(player)) { + loadLabel(player, "all_items_delivered") + } else { + loadLabel(player, "yes_give_items") + } } label("no_bowl") @@ -579,8 +595,8 @@ class AugusteDialogueFile : DialogueLabeller() { label("sapling_replacement_offer") npc("It will cost you 30,000 gold coins to replace it, do you want to pay that?") options( - DialogueOption("sapling_replacement_yes", "Yes.", "Yes."), - DialogueOption("nowhere", "No way!", "No way!"), + DialogueOption("sapling_replacement_yes", "Yes."), + DialogueOption("nowhere", "No way!"), ) label("sapling_replacement_yes") @@ -594,10 +610,10 @@ class AugusteDialogueFile : DialogueLabeller() { label("sapling_replacement_success") npc("Here you go. Now be very careful not to lose it again!") - exec { player, _ -> - removeItem(player, Item(Items.COINS_995, 30000)) - addItem(player, Items.AUGUSTES_SAPLING_9932, 1) - } + exec { player, _ -> + removeItem(player, Item(Items.COINS_995, 30000)) + addItem(player, Items.AUGUSTES_SAPLING_9932, 1) + } //fallback, no source for what happens when the player has insufficient funds. label("sapling_replacement_failure") @@ -648,12 +664,12 @@ class AugusteDialogueFile : DialogueLabeller() { label(questStageLabel(EnlightenedJourney.STAGE_WILLOW_BASKET)) npc(FacialExpression.HAPPY, "You just need to build the basket and I can finish the balloon! How are you getting on with the willow?") options( - DialogueOption("lost_sapling_check", "I have lost my willow sapling. Can I buy a replacement?", "I have lost my willow sapling. Can I buy a replacement?", + DialogueOption("lost_sapling_check", "I have lost my willow sapling. Can I buy a replacement?", optionIf = { player, _ -> !getAttribute(player, EnlightenedJourney.ATTRIBUTE_SAPLING_PLANTED, false) }), - DialogueOption("build_the_basket", "What do I do again?", "What do I do again?", FacialExpression.HALF_THINKING), - DialogueOption("nowhere", "Fine thanks.", "Fine thanks."), + DialogueOption("build_the_basket", "What do I do again?", expression = FacialExpression.HALF_THINKING), + DialogueOption("nowhere", "Fine thanks."), ) label("build_the_basket") @@ -662,9 +678,9 @@ class AugusteDialogueFile : DialogueLabeller() { label(questStageLabel(EnlightenedJourney.STAGE_FLIGHT)) npc(FacialExpression.HAPPY, "Well, let's get going!") options( - DialogueOption("wait_tell_me", "Wait; tell me what we're doing.", "Wait; tell me what we're doing."), - DialogueOption("maiden_voyage", "Okay.", "Okay."), - DialogueOption("nowhere", "No, I'm not ready.", "No, I'm not ready.") + DialogueOption("wait_tell_me", "Wait; tell me what we're doing."), + DialogueOption("maiden_voyage", "Okay."), + DialogueOption("nowhere", "No, I'm not ready.") ) label("wait_tell_me") @@ -689,8 +705,8 @@ class AugusteDialogueFile : DialogueLabeller() { npc("If it all goes horribly wrong, you can always bail. If we're still over Entrana, we can land quickly and try again. However, once past the island, we will crash.") npc("Are you ready to go?") options( - DialogueOption("maiden_voyage", "Okay.", "Okay."), - DialogueOption("nowhere", "No, I'm not ready.", "No, I'm not ready.") + DialogueOption("maiden_voyage", "Okay."), + DialogueOption("nowhere", "No, I'm not ready.") ) label("maiden_voyage") @@ -753,13 +769,9 @@ class AugusteDialogueFile : DialogueLabeller() { npc("I will base my operations in Entrana. If you'd like to travel to new places, come see me there.") npc("Do you want to use the balloon? Just so you know, some locations require special logs and high Firemaking skills.") options( - DialogueOption("post_quest_yes", "Yes.", "Yes."), - DialogueOption("nowhere", "No.", "No."), - DialogueOption( - "post_quest_origami", - "Could you tell me how to make an origami balloon?", - "Could you tell me how to make an origami balloon?" - ) + DialogueOption("post_quest_yes", "Yes."), + DialogueOption("nowhere", "No."), + DialogueOption("post_quest_origami", "Could you tell me how to make an origami balloon?") ) label("post_quest_yes") @@ -811,11 +823,11 @@ class AugusteDialogueFile : DialogueLabeller() { label("post_quest_options") npc("Do you want to use the balloon? Just so you know, some locations require special logs and high Firemaking skills.") options( - DialogueOption("yes_fly_balloon", "Yes.", "Yes."), - DialogueOption("nowhere", "No.", "No."), - DialogueOption("post_quest_origami", "Could you tell me how to make an origami balloon?", "Could you tell me how to make an origami balloon?"), - DialogueOption("replace_bomber_clothes", "Could you replace some items for me?", "Could you replace some items for me?") { player, _ -> hasLostBomberReward(player) }, - DialogueOption("combine_cap_goggles", "Could you combine my cap and goggles?", "Could you combine my cap and goggles?") { player, _ -> hasCapAndGoggles(player) } + DialogueOption("yes_fly_balloon", "Yes."), + DialogueOption("nowhere", "No."), + DialogueOption("post_quest_origami", "Could you tell me how to make an origami balloon?"), + DialogueOption("replace_bomber_clothes", "Could you replace some items for me?") { player, _ -> hasLostBomberReward(player) }, + DialogueOption("combine_cap_goggles", "Could you combine my cap and goggles?") { player, _ -> hasCapAndGoggles(player) } ) label("replace_bomber_clothes") diff --git a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt index 50b1ee9f6..23748d4ee 100644 --- a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt @@ -24,25 +24,36 @@ import org.rs09.consts.Items */ @Initializable -class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, VARBIT_QUEST_PROGRESS, 0, 1, 200) { +class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, + VARBIT_QUEST_PROGRESS_2866, QUEST_PROGRESS_NOT_STARTED_0, QUEST_PROGRESS_STARTED_1, QUEST_PROGRESS_COMPLETED_200) { companion object { val questName = Quests.ENLIGHTENED_JOURNEY - /** Quest progress varbit used for the quests tab. 0 = not started, 1 = in progress, 200 = completed. */ - const val VARBIT_QUEST_PROGRESS = 2866 + /** Quest progress varbit and states used by the quest tab. */ + const val VARBIT_QUEST_PROGRESS_2866 = 2866 + const val QUEST_PROGRESS_NOT_STARTED_0 = 0 + const val QUEST_PROGRESS_STARTED_1 = 1 + const val QUEST_PROGRESS_COMPLETED_200 = 200 /** Entrana balloon scenery state varbit. */ - const val VARBIT_ENTRANA_BALLOON = 2867 + const val VARBIT_ENTRANA_BALLOON_2867 = 2867 + const val ENTRANA_BALLOON_COMPLETE_2 = 2 - /** Taverley balloon route unlock state. */ - const val VARBIT_TAVERLEY_BALLOON = 2868 + /** Taverley balloon scenery and NPC state varbit. */ + const val VARBIT_TAVERLEY_BALLOON_2868 = 2868 + const val TAVERLEY_BALLOON_AUGUSTE_1 = 1 + const val TAVERLEY_BALLOON_STAN_2 = 2 + + /** Standard balloon route states. */ + const val BALLOON_ROUTE_LOCKED_0 = 0 + const val BALLOON_ROUTE_UNLOCKED_1 = 1 /** Completing a ballooning route unlocks the respective destination. */ - const val VARBIT_CASTLEWARS_BALLOON = 2869 - const val VARBIT_GRANDTREE_BALLOON = 2870 - const val VARBIT_CRAFTINGGUILD_BALLOON = 2871 - const val VARBIT_VARROCK_BALLOON = 2872 + const val VARBIT_CASTLEWARS_BALLOON_2869 = 2869 + const val VARBIT_GRANDTREE_BALLOON_2870 = 2870 + const val VARBIT_CRAFTINGGUILD_BALLOON_2871 = 2871 + const val VARBIT_VARROCK_BALLOON_2872 = 2872 /** Attributes used during the quest. */ const val ATTRIBUTE_YELLOW_DYE_DELIVERED = "/save:enlightenedjourney_yellow_dye_delivered" @@ -210,19 +221,19 @@ class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, VARBI addItemOrDrop(player, Items.BOMBER_JACKET_9944) addItemOrDrop(player, Items.BOMBER_CAP_9945) - setVarbit(player, VARBIT_QUEST_PROGRESS, 200, true) - setVarbit(player, VARBIT_ENTRANA_BALLOON, 2, true) - setVarbit(player, VARBIT_TAVERLEY_BALLOON, 1, true) + setVarbit(player, VARBIT_QUEST_PROGRESS_2866, QUEST_PROGRESS_COMPLETED_200, true) + setVarbit(player, VARBIT_ENTRANA_BALLOON_2867, ENTRANA_BALLOON_COMPLETE_2, true) + setVarbit(player, VARBIT_TAVERLEY_BALLOON_2868, TAVERLEY_BALLOON_AUGUSTE_1, true) } override fun reset(player: Player) { - setVarbit(player, VARBIT_QUEST_PROGRESS, 0, true) - setVarbit(player, VARBIT_ENTRANA_BALLOON, 0, true) - setVarbit(player, VARBIT_TAVERLEY_BALLOON, 0, true) - setVarbit(player, VARBIT_CASTLEWARS_BALLOON, 0, true) - setVarbit(player, VARBIT_GRANDTREE_BALLOON, 0, true) - setVarbit(player, VARBIT_CRAFTINGGUILD_BALLOON, 0, true) - setVarbit(player, VARBIT_VARROCK_BALLOON, 0, true) + setVarbit(player, VARBIT_QUEST_PROGRESS_2866, QUEST_PROGRESS_NOT_STARTED_0, true) + setVarbit(player, VARBIT_ENTRANA_BALLOON_2867, BALLOON_ROUTE_LOCKED_0, true) + setVarbit(player, VARBIT_TAVERLEY_BALLOON_2868, BALLOON_ROUTE_LOCKED_0, true) + setVarbit(player, VARBIT_CASTLEWARS_BALLOON_2869, BALLOON_ROUTE_LOCKED_0, true) + setVarbit(player, VARBIT_GRANDTREE_BALLOON_2870, BALLOON_ROUTE_LOCKED_0, true) + setVarbit(player, VARBIT_CRAFTINGGUILD_BALLOON_2871, BALLOON_ROUTE_LOCKED_0, true) + setVarbit(player, VARBIT_VARROCK_BALLOON_2872, BALLOON_ROUTE_LOCKED_0, true) removeAttributes( player, ATTRIBUTE_YELLOW_DYE_DELIVERED, ATTRIBUTE_RED_DYE_DELIVERED, @@ -239,20 +250,20 @@ class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, VARBI val stage = getQuestStage(player, questName) setVarbit( - player, VARBIT_QUEST_PROGRESS, when { - stage >= STAGE_COMPLETE -> 200 - stage > 0 -> 1 - else -> 0 + player, VARBIT_QUEST_PROGRESS_2866, when { + stage >= STAGE_COMPLETE -> QUEST_PROGRESS_COMPLETED_200 + stage > 0 -> QUEST_PROGRESS_STARTED_1 + else -> QUEST_PROGRESS_NOT_STARTED_0 }, true ) - setVarbit(player, VARBIT_ENTRANA_BALLOON, if (stage >= STAGE_FLIGHT) 2 else 0, true) + setVarbit(player, VARBIT_ENTRANA_BALLOON_2867, if (stage >= STAGE_FLIGHT) ENTRANA_BALLOON_COMPLETE_2 else BALLOON_ROUTE_LOCKED_0, true) val taverleyBalloonState = when { - stage >= STAGE_COMPLETE && getAttribute(player, ATTRIBUTE_TAVERLEY_AUGUSTE_REPLACED, false) -> 2 - stage >= STAGE_CLAIM_REWARD -> 1 - else -> 0 + stage >= STAGE_COMPLETE && getAttribute(player, ATTRIBUTE_TAVERLEY_AUGUSTE_REPLACED, false) -> TAVERLEY_BALLOON_STAN_2 + stage >= STAGE_CLAIM_REWARD -> TAVERLEY_BALLOON_AUGUSTE_1 + else -> BALLOON_ROUTE_LOCKED_0 } - setVarbit(player, VARBIT_TAVERLEY_BALLOON, taverleyBalloonState, true) + setVarbit(player, VARBIT_TAVERLEY_BALLOON_2868, taverleyBalloonState, true) } override fun newInstance(`object`: Any?): Quest { From 37b8ff82b970ac6ddab45b900877c3ec30553428 Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Tue, 7 Jul 2026 13:45:13 +0200 Subject: [PATCH 07/14] i forgor to rebase the json --- Server/data/configs/npc_configs.json | 36 ++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/Server/data/configs/npc_configs.json b/Server/data/configs/npc_configs.json index 44c10bdcb..9fd067311 100644 --- a/Server/data/configs/npc_configs.json +++ b/Server/data/configs/npc_configs.json @@ -54811,19 +54811,23 @@ }, { "id": "5049", - "name": "Auguste" + "name": "Auguste", + "examine": "Balloonist extraordinaire." }, { "id": "5050", - "name": "Auguste" + "name": "Auguste", + "examine": "" }, { "id": "5051", - "name": "Auguste" + "name": "Auguste", + "examine": "Balloonist extraordinaire." }, { "id": "5052", - "name": "Auguste" + "name": "Auguste", + "examine": "Balloonist extraordinaire." }, { "id": "5053", @@ -54863,7 +54867,23 @@ }, { "id": "5062", - "name": "Shark" + "name": "Auguste/Asst. Stan wrapper" + }, + { + "id": "5063", + "name": "Asst. Marrow wrapper" + }, + { + "id": "5064", + "name": "Asst. Le Smith wrapper" + }, + { + "id": "5065", + "name": "Asst. Brock wrapper" + }, + { + "id": "5066", + "name": "Asst. Serf wrapper" }, { "id": "5067", @@ -54883,11 +54903,13 @@ }, { "id": "5068", - "name": "Shark" + "name": "Shark", + "examine": "Time to run away..." }, { "id": "5069", - "name": "Shark" + "name": "Shark", + "examine": "Time to run away..." }, { "id": "5070", From 0734c04745beddd9ba44b1f05385ddb379b0ad78 Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Tue, 7 Jul 2026 18:53:24 +0200 Subject: [PATCH 08/14] today i drew: Constant suffix where it makes sense. Examine texts. Journal overhaul. Bowl spawn. --- Server/data/configs/ground_spawns.json | 2 +- Server/data/configs/npc_configs.json | 15 ++-- .../travel/balloon/BalloonCrashSites.kt | 36 ++++---- .../travel/balloon/BalloonFlightInterface.kt | 42 ++++----- .../travel/balloon/BalloonFlightScreens.kt | 88 +++++++++---------- .../travel/balloon/BalloonTravelInterface.kt | 37 ++++---- .../quest/EnlightenedJourney.kt | 63 +++++++------ 7 files changed, 149 insertions(+), 134 deletions(-) diff --git a/Server/data/configs/ground_spawns.json b/Server/data/configs/ground_spawns.json index 1893b6df3..a84f7bd97 100644 --- a/Server/data/configs/ground_spawns.json +++ b/Server/data/configs/ground_spawns.json @@ -457,7 +457,7 @@ }, { "item_id": "1923", - "loc_data": "{1,3208,3214,0,80}-{1,3140,3452,1,90}-" + "loc_data": "{1,3208,3214,0,80}-{1,2816,3351,1,80}-{1,3140,3452,1,90}-" }, { "item_id": "1925", diff --git a/Server/data/configs/npc_configs.json b/Server/data/configs/npc_configs.json index 9fd067311..014274748 100644 --- a/Server/data/configs/npc_configs.json +++ b/Server/data/configs/npc_configs.json @@ -54831,23 +54831,28 @@ }, { "id": "5053", - "name": "Assistant Serf" + "name": "Assistant Serf", + "examine": "A helpful assistant." }, { "id": "5054", - "name": "Assistant Brock" + "name": "Assistant Brock", + "examine": "A helpful assistant." }, { "id": "5055", - "name": "Assistant Marrow" + "name": "Assistant Marrow", + "examine": "A helpful assistant." }, { "id": "5056", - "name": "Assistant Le Smith" + "name": "Assistant Le Smith", + "examine": "A helpful assistant." }, { "id": "5057", - "name": "Assistant Stan" + "name": "Assistant Stan", + "examine": "A helpful assistant." }, { "id": "5058", diff --git a/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt b/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt index e51bdba99..690da7806 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt @@ -38,15 +38,15 @@ import org.rs09.consts.Components */ object BalloonCrashSites { - const val CRASH_SITE_REGION = 7244 - const val SCENERY_OCEAN_PLANK = 19126 - const val SCENERY_WOODLAND_DIRT = 19125 + const val CRASH_SITE_REGION_7244 = 7244 + const val SCENERY_OCEAN_PLANK_19126 = 19126 + const val SCENERY_WOODLAND_DIRT_19125 = 19125 - const val NPC_OCEAN_AUGUSTE = 5051 - const val NPC_WOODLAND_AUGUSTE = 5052 + const val NPC_OCEAN_AUGUSTE_5051 = 5051 + const val NPC_WOODLAND_AUGUSTE_5052 = 5052 - private const val SOUND_CRASH = 3244 - private const val RENDER_ANIMATION_SWIM = 188 + private const val SOUND_CRASH_3244 = 3244 + private const val RENDER_ANIMATION_SWIM_188 = 188 private val OCEAN_CRASH_LANDING = Location.create(1805, 4889, 0) private val OCEAN_CRASH_FACE_LOCATION = Location.create(1804, 4889, 0) @@ -78,7 +78,7 @@ object BalloonCrashSites { } fun crashAtOceanSite(player: Player) { - playAudio(player, SOUND_CRASH) + playAudio(player, SOUND_CRASH_3244) fadeTransition(player) { closeFlightInterface(player) teleport(player, OCEAN_CRASH_LANDING) @@ -100,7 +100,7 @@ object BalloonCrashSites { } fun crashAtWoodlandSite(player: Player, exit: WoodlandExit) { - playAudio(player, SOUND_CRASH) + playAudio(player, SOUND_CRASH_3244) setAttribute(player, ATTRIBUTE_WOODLAND_EXIT, exit.name) fadeTransition(player) { closeFlightInterface(player) @@ -179,7 +179,7 @@ object BalloonCrashSites { } private fun oceanSwimmingAnimations(player: Player) { - player.appearance.setAnimations(Animation(RENDER_ANIMATION_SWIM)) + player.appearance.setAnimations(Animation(RENDER_ANIMATION_SWIM_188)) player.appearance.sync() } @@ -187,22 +187,22 @@ object BalloonCrashSites { class BalloonCrashSiteListener : InteractionListener, MapArea { override fun defineListeners() { - on(BalloonCrashSites.SCENERY_OCEAN_PLANK, IntType.SCENERY, "use") { player, _ -> + on(BalloonCrashSites.SCENERY_OCEAN_PLANK_19126, IntType.SCENERY, "use") { player, _ -> BalloonCrashSites.leaveOceanCrashSite(player) return@on true } - on(BalloonCrashSites.SCENERY_WOODLAND_DIRT, IntType.SCENERY, "leave") { player, _ -> + on(BalloonCrashSites.SCENERY_WOODLAND_DIRT_19125, IntType.SCENERY, "leave") { player, _ -> BalloonCrashSites.leaveWoodlandCrashSite(player) return@on true } - on(BalloonCrashSites.NPC_OCEAN_AUGUSTE, IntType.NPC, "talk-to") { player, node -> + on(BalloonCrashSites.NPC_OCEAN_AUGUSTE_5051, IntType.NPC, "talk-to") { player, node -> DialogueLabeller.open(player, BalloonCrashDialogue(), node.asNpc()) return@on true } - on(BalloonCrashSites.NPC_WOODLAND_AUGUSTE, IntType.NPC, "talk-to") { player, node -> + on(BalloonCrashSites.NPC_WOODLAND_AUGUSTE_5052, IntType.NPC, "talk-to") { player, node -> DialogueLabeller.open(player, BalloonCrashDialogue(), node.asNpc()) return@on true } @@ -210,7 +210,7 @@ class BalloonCrashSiteListener : InteractionListener, MapArea { } override fun defineAreaBorders(): Array { - return arrayOf(getRegionBorders(BalloonCrashSites.CRASH_SITE_REGION)) + return arrayOf(getRegionBorders(BalloonCrashSites.CRASH_SITE_REGION_7244)) } override fun getRestrictions(): Array { @@ -220,12 +220,12 @@ class BalloonCrashSiteListener : InteractionListener, MapArea { class BalloonCrashDialogue : DialogueLabeller() { override fun addConversation() { - assignToIds(BalloonCrashSites.NPC_OCEAN_AUGUSTE) + assignToIds(BalloonCrashSites.NPC_OCEAN_AUGUSTE_5051) exec { player, npc -> when (npc.id) { - BalloonCrashSites.NPC_OCEAN_AUGUSTE -> loadLabel(player, "ocean_crash") - BalloonCrashSites.NPC_WOODLAND_AUGUSTE -> loadLabel(player, "woodland_crash") + BalloonCrashSites.NPC_OCEAN_AUGUSTE_5051 -> loadLabel(player, "ocean_crash") + BalloonCrashSites.NPC_WOODLAND_AUGUSTE_5052 -> loadLabel(player, "woodland_crash") } } diff --git a/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt index 9ae93527a..eded3b846 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt @@ -51,8 +51,8 @@ private enum class BalloonCrashLocation { class BalloonFlightInterface : InterfaceListener { companion object { - private const val BALLOON_FLIGHT_INTERFACE = 470 - private const val BALLOON_CONTROL_INTERFACE = 471 + private const val BALLOON_FLIGHT_INTERFACE_470 = 470 + private const val BALLOON_CONTROL_INTERFACE_471 = 471 private const val ATTRIBUTE_BALLOON_TOP = "enlightenedjourney_balloon_top" private const val ATTRIBUTE_BALLOON_BOTTOM = "enlightenedjourney_balloon_bottom" @@ -61,17 +61,17 @@ class BalloonFlightInterface : InterfaceListener { private const val ATTRIBUTE_FLIGHT_SCREEN = "enlightenedjourney_balloon_flight_screen" private const val ATTRIBUTE_FLIGHT_DESTINATION = "enlightenedjourney_balloon_flight_destination" - private const val SOUND_SANDBAG = 3249 - private const val SOUND_BURN_LOG = 3251 - private const val SOUND_RELAX = 3247 - private const val SOUND_ROPE = 3242 - private const val SOUND_RED_ROPE = 3239 + private const val SOUND_SANDBAG_3249 = 3249 + private const val SOUND_BURN_LOG_3251 = 3251 + private const val SOUND_RELAX_3247 = 3247 + private const val SOUND_ROPE_3242 = 3242 + private const val SOUND_RED_ROPE_3239 = 3239 // cant find source material for using these two: // zep_construct=3248 // zep_hammering_1=3250 - private const val MUSIC_FLOATING_FREE = 206 + private const val MUSIC_FLOATING_FREE_206 = 206 private val controlMoves = mapOf( BalloonFlightRoutes.BUTTON_SANDBAG to BalloonMove(1, -2), @@ -91,8 +91,8 @@ class BalloonFlightInterface : InterfaceListener { closeInterface(player) hideGameTabs(player) hideMinimap(player) - player.musicPlayer.unlock(MUSIC_FLOATING_FREE) - openInterface(player, BALLOON_FLIGHT_INTERFACE) + player.musicPlayer.unlock(MUSIC_FLOATING_FREE_206) + openInterface(player, BALLOON_FLIGHT_INTERFACE_470) } /** Post-quest flight from Entrana to a new unlockable destination. */ @@ -105,8 +105,8 @@ class BalloonFlightInterface : InterfaceListener { closeInterface(player) hideGameTabs(player) hideMinimap(player) - player.musicPlayer.unlock(MUSIC_FLOATING_FREE) - openInterface(player, BALLOON_FLIGHT_INTERFACE) + player.musicPlayer.unlock(MUSIC_FLOATING_FREE_206) + openInterface(player, BALLOON_FLIGHT_INTERFACE_470) } private fun getFlightDestination(player: Player): BalloonTravelLocation { @@ -463,11 +463,11 @@ class BalloonFlightInterface : InterfaceListener { private fun playControlSound(player: Player, buttonId: Int) { val sound = when (buttonId) { - BalloonFlightRoutes.BUTTON_SANDBAG -> SOUND_SANDBAG - BalloonFlightRoutes.BUTTON_BURN_LOG -> SOUND_BURN_LOG - BalloonFlightRoutes.BUTTON_RELAX -> SOUND_RELAX - BalloonFlightRoutes.BUTTON_NORMAL_ROPE -> SOUND_ROPE - BalloonFlightRoutes.BUTTON_RED_ROPE -> SOUND_RED_ROPE + BalloonFlightRoutes.BUTTON_SANDBAG -> SOUND_SANDBAG_3249 + BalloonFlightRoutes.BUTTON_BURN_LOG -> SOUND_BURN_LOG_3251 + BalloonFlightRoutes.BUTTON_RELAX -> SOUND_RELAX_3247 + BalloonFlightRoutes.BUTTON_NORMAL_ROPE -> SOUND_ROPE_3242 + BalloonFlightRoutes.BUTTON_RED_ROPE -> SOUND_RED_ROPE_3239 else -> return } playAudio(player, sound) @@ -503,12 +503,12 @@ class BalloonFlightInterface : InterfaceListener { } override fun defineInterfaceListeners() { - onOpen(BALLOON_FLIGHT_INTERFACE) { player, _ -> + onOpen(BALLOON_FLIGHT_INTERFACE_470) { player, _ -> val destination = getFlightDestination(player) val screen = getAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, 1) val startPosition = getScreenPosition(destination, screen) player.lock() - openSingleTab(player, BALLOON_CONTROL_INTERFACE) + openSingleTab(player, BALLOON_CONTROL_INTERFACE_471) BalloonFlightScreens.clear(player) drawFlightScreen(player, destination, screen) BalloonFlightScreens.drawBalloon(player, startPosition.top, startPosition.bottom) @@ -516,7 +516,7 @@ class BalloonFlightInterface : InterfaceListener { true } - onClose(BALLOON_FLIGHT_INTERFACE) { player, _ -> + onClose(BALLOON_FLIGHT_INTERFACE_470) { player, _ -> BalloonFlightScreens.clear(player) clearFlightAttributes(player) closeTabInterface(player) @@ -525,7 +525,7 @@ class BalloonFlightInterface : InterfaceListener { true } - on(BALLOON_CONTROL_INTERFACE) { player, _, _, buttonId, _, _ -> + on(BALLOON_CONTROL_INTERFACE_471) { player, _, _, buttonId, _, _ -> handleRouteButton(player, buttonId) true } diff --git a/Server/src/main/content/global/travel/balloon/BalloonFlightScreens.kt b/Server/src/main/content/global/travel/balloon/BalloonFlightScreens.kt index 5d0e19cc1..4bff34984 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonFlightScreens.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonFlightScreens.kt @@ -9,20 +9,20 @@ import core.game.node.entity.player.Player */ object BalloonFlightScreens { - private const val BALLOON_FLIGHT_INTERFACE = 470 + private const val BALLOON_FLIGHT_INTERFACE_470 = 470 - private const val MODEL_WHITE_BIRD = 19779 - private const val MODEL_BROWN_BIRD = 19780 - private const val ANIMATION_BIRD = 341 - private const val MODEL_CLOUD_ANOMALY = 19781 - private const val ANIMATION_CLOUD_ANOMALY = 5141 - private const val MODEL_BALLOON_TOP = 19517 - private const val MODEL_BALLOON_BOTTOM = 19518 + private const val MODEL_WHITE_BIRD_19779 = 19779 + private const val MODEL_BROWN_BIRD_19780 = 19780 + private const val ANIMATION_BIRD_341 = 341 + private const val MODEL_CLOUD_ANOMALY_19781 = 19781 + private const val ANIMATION_CLOUD_ANOMALY_5141 = 5141 + private const val MODEL_BALLOON_TOP_19517 = 19517 + private const val MODEL_BALLOON_BOTTOM_19518 = 19518 /** Clears all model child slots used by the flight interface. */ fun clear(player: Player) { for (child in 78..237) { - player.packetDispatch.sendModelOnInterface(-1, BALLOON_FLIGHT_INTERFACE, child, 0) + player.packetDispatch.sendModelOnInterface(-1, BALLOON_FLIGHT_INTERFACE_470, child, 0) } } @@ -40,25 +40,25 @@ object BalloonFlightScreens { /** Draws the top and bottom balloon models at the given child slots. */ fun drawBalloon(player: Player, topChild: Int, bottomChild: Int) { - player.packetDispatch.sendModelOnInterface(MODEL_BALLOON_TOP, BALLOON_FLIGHT_INTERFACE, topChild, 2576) + player.packetDispatch.sendModelOnInterface(MODEL_BALLOON_TOP_19517, BALLOON_FLIGHT_INTERFACE_470, topChild, 2576) resetModelAngle(player, topChild) - player.packetDispatch.sendModelOnInterface(MODEL_BALLOON_BOTTOM, BALLOON_FLIGHT_INTERFACE, bottomChild, 2576) + player.packetDispatch.sendModelOnInterface(MODEL_BALLOON_BOTTOM_19518, BALLOON_FLIGHT_INTERFACE_470, bottomChild, 2576) resetModelAngle(player, bottomChild) } /** Clears the top and bottom balloon models at the given child slots. */ fun clearBalloon(player: Player, topChild: Int, bottomChild: Int) { - player.packetDispatch.sendModelOnInterface(-1, BALLOON_FLIGHT_INTERFACE, topChild, 0) - player.packetDispatch.sendModelOnInterface(-1, BALLOON_FLIGHT_INTERFACE, bottomChild, 0) + player.packetDispatch.sendModelOnInterface(-1, BALLOON_FLIGHT_INTERFACE_470, topChild, 0) + player.packetDispatch.sendModelOnInterface(-1, BALLOON_FLIGHT_INTERFACE_470, bottomChild, 0) } private fun resetModelAngle(player: Player, child: Int) { - player.packetDispatch.sendAngleOnInterface(BALLOON_FLIGHT_INTERFACE, child, 2576, 0, 0) + player.packetDispatch.sendAngleOnInterface(BALLOON_FLIGHT_INTERFACE_470, child, 2576, 0, 0) } private fun drawModels(player: Player, model: Int, vararg children: Int) { for (child in children) { - player.packetDispatch.sendModelOnInterface(model, BALLOON_FLIGHT_INTERFACE, child, 2576) + player.packetDispatch.sendModelOnInterface(model, BALLOON_FLIGHT_INTERFACE_470, child, 2576) resetModelAngle(player, child) } } @@ -73,9 +73,9 @@ object BalloonFlightScreens { vararg children: Int ) { for (child in children) { - player.packetDispatch.sendModelOnInterface(model, BALLOON_FLIGHT_INTERFACE, child, zoom) - player.packetDispatch.sendAngleOnInterface(BALLOON_FLIGHT_INTERFACE, child, zoom, pitch, yaw) - sendAnimationOnInterface(player, animation, BALLOON_FLIGHT_INTERFACE, child) + player.packetDispatch.sendModelOnInterface(model, BALLOON_FLIGHT_INTERFACE_470, child, zoom) + player.packetDispatch.sendAngleOnInterface(BALLOON_FLIGHT_INTERFACE_470, child, zoom, pitch, yaw) + sendAnimationOnInterface(player, animation, BALLOON_FLIGHT_INTERFACE_470, child) } } @@ -120,10 +120,10 @@ object BalloonFlightScreens { drawModels(player, 19572, 78) // Birds - drawAnimatedModels(player, MODEL_BROWN_BIRD, ANIMATION_BIRD, 2567, 100, 300, 145, 148, 177, 209) + drawAnimatedModels(player, MODEL_BROWN_BIRD_19780, ANIMATION_BIRD_341, 2567, 100, 300, 145, 148, 177, 209) // Cloud anomaly - drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 175, 230) + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY_19781, ANIMATION_CLOUD_ANOMALY_5141, 2567, 0, 300, 175, 230) } private fun drawTaverleyScreenTwo(player: Player) { @@ -176,7 +176,7 @@ object BalloonFlightScreens { drawModels(player, 19526, 181, 203, 188) // Birds - drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 161, 179, 185, 204, 219) + drawAnimatedModels(player, MODEL_WHITE_BIRD_19779, ANIMATION_BIRD_341, 2567, 100, 300, 161, 179, 185, 204, 219) } private fun drawTaverleyScreenThree(player: Player) { @@ -218,10 +218,10 @@ object BalloonFlightScreens { drawModels(player, 19526, 171, 176, 214) // Birds - drawAnimatedModels(player, MODEL_BROWN_BIRD, ANIMATION_BIRD, 2567, 100, 300, 146, 151, 192, 207, 208, 215) + drawAnimatedModels(player, MODEL_BROWN_BIRD_19780, ANIMATION_BIRD_341, 2567, 100, 300, 146, 151, 192, 207, 208, 215) // Cloud anomaly - drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 191) + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY_19781, ANIMATION_CLOUD_ANOMALY_5141, 2567, 0, 300, 191) } private fun drawCraftingGuildScreen(player: Player, screen: Int) { @@ -272,10 +272,10 @@ object BalloonFlightScreens { drawModels(player, 19631, 91) // Birds - drawAnimatedModels(player, MODEL_BROWN_BIRD, ANIMATION_BIRD, 2567, 100, 300, 220, 221, 206, 175, 151, 171, 148) + drawAnimatedModels(player, MODEL_BROWN_BIRD_19780, ANIMATION_BIRD_341, 2567, 100, 300, 220, 221, 206, 175, 151, 171, 148) // Cloud anomaly - drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 183) + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY_19781, ANIMATION_CLOUD_ANOMALY_5141, 2567, 0, 300, 183) // Clouds drawModels(player, 19525, 162, 192, 233) @@ -317,10 +317,10 @@ object BalloonFlightScreens { drawModels(player, 19717, 97) // Birds - drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 161, 187, 216, 217, 171) + drawAnimatedModels(player, MODEL_WHITE_BIRD_19779, ANIMATION_BIRD_341, 2567, 100, 300, 161, 187, 216, 217, 171) // Cloud anomaly - drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 127, 132, 188) + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY_19781, ANIMATION_CLOUD_ANOMALY_5141, 2567, 0, 300, 127, 132, 188) } private fun drawCraftingGuildScreenThree(player: Player) { @@ -356,10 +356,10 @@ object BalloonFlightScreens { drawModels(player, 19524, 223, 167, 174, 229, 211) // Birds - drawAnimatedModels(player, MODEL_BROWN_BIRD, ANIMATION_BIRD, 2567, 100, 300, 199, 120, 163, 209) + drawAnimatedModels(player, MODEL_BROWN_BIRD_19780, ANIMATION_BIRD_341, 2567, 100, 300, 199, 120, 163, 209) // Cloud anomaly - drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 143, 104) + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY_19781, ANIMATION_CLOUD_ANOMALY_5141, 2567, 0, 300, 143, 104) } private fun drawVarrockScreen(player: Player, screen: Int) { @@ -404,8 +404,8 @@ object BalloonFlightScreens { // Birds drawAnimatedModels( player, - MODEL_WHITE_BIRD, - ANIMATION_BIRD, + MODEL_WHITE_BIRD_19779, + ANIMATION_BIRD_341, 2567, 100, 300, @@ -428,7 +428,7 @@ object BalloonFlightScreens { drawModels(player, 19741, 55) // Birds - drawAnimatedModels(player, MODEL_BROWN_BIRD, ANIMATION_BIRD, 2567, 100, 300, 139, 218, 214, 209, 190, 214, 154) + drawAnimatedModels(player, MODEL_BROWN_BIRD_19780, ANIMATION_BIRD_341, 2567, 100, 300, 139, 218, 214, 209, 190, 214, 154) // Trees drawModels(player, 19570, 119, 122, 134, 135, 137) @@ -464,7 +464,7 @@ object BalloonFlightScreens { drawModels(player, 19754, 149) // Cloud anomaly - drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 187, 192, 236) + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY_19781, ANIMATION_CLOUD_ANOMALY_5141, 2567, 0, 300, 187, 192, 236) } private fun drawVarrockScreenThree(player: Player) { @@ -482,7 +482,7 @@ object BalloonFlightScreens { drawModels(player, 19519, 81) // Birds - drawAnimatedModels(player, MODEL_BROWN_BIRD, ANIMATION_BIRD, 2567, 100, 300, 141, 199, 225, 230) + drawAnimatedModels(player, MODEL_BROWN_BIRD_19780, ANIMATION_BIRD_341, 2567, 100, 300, 141, 199, 225, 230) // Clouds drawModels(player, 19526, 198, 202) @@ -539,7 +539,7 @@ object BalloonFlightScreens { drawModels(player, 19526, 229, 183, 166, 170, 214, 177) // Birds - drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 140, 147, 207, 130, 193, 136) + drawAnimatedModels(player, MODEL_WHITE_BIRD_19779, ANIMATION_BIRD_341, 2567, 100, 300, 140, 147, 207, 130, 193, 136) } private fun drawCastleWarsScreenTwo(player: Player) { @@ -585,10 +585,10 @@ object BalloonFlightScreens { drawModels(player, 19526, 142, 159, 181, 191, 205, 217, 231) // Cloud anomaly - drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 152, 156) + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY_19781, ANIMATION_CLOUD_ANOMALY_5141, 2567, 0, 300, 152, 156) // Birds - drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 118, 197) + drawAnimatedModels(player, MODEL_WHITE_BIRD_19779, ANIMATION_BIRD_341, 2567, 100, 300, 118, 197) } private fun drawCastleWarsScreenThree(player: Player) { @@ -626,10 +626,10 @@ object BalloonFlightScreens { drawModels(player, 19526, 172, 186, 199, 211, 217, 223) // Birds - drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 140, 153, 179) + drawAnimatedModels(player, MODEL_WHITE_BIRD_19779, ANIMATION_BIRD_341, 2567, 100, 300, 140, 153, 179) // Cloud anomaly - drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 138, 147) + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY_19781, ANIMATION_CLOUD_ANOMALY_5141, 2567, 0, 300, 138, 147) } private fun drawGrandTreeScreen(player: Player, screen: Int) { @@ -672,10 +672,10 @@ object BalloonFlightScreens { drawModels(player, 19526, 188, 195, 203, 232) // Birds - drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 191, 229, 237, 144, 130) + drawAnimatedModels(player, MODEL_WHITE_BIRD_19779, ANIMATION_BIRD_341, 2567, 100, 300, 191, 229, 237, 144, 130) // Cloud anomaly - drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 214) + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY_19781, ANIMATION_CLOUD_ANOMALY_5141, 2567, 0, 300, 214) } private fun drawGrandTreeScreenTwo(player: Player) { @@ -715,10 +715,10 @@ object BalloonFlightScreens { drawModels(player, 19526, 192, 201, 205, 209, 217) // Birds - drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 219, 183, 154, 196, 197, 149, 150) + drawAnimatedModels(player, MODEL_WHITE_BIRD_19779, ANIMATION_BIRD_341, 2567, 100, 300, 219, 183, 154, 196, 197, 149, 150) // Cloud anomaly - drawAnimatedModels(player, MODEL_CLOUD_ANOMALY, ANIMATION_CLOUD_ANOMALY, 2567, 0, 300, 181, 220, 224, 228) + drawAnimatedModels(player, MODEL_CLOUD_ANOMALY_19781, ANIMATION_CLOUD_ANOMALY_5141, 2567, 0, 300, 181, 220, 224, 228) } private fun drawGrandTreeScreenThree(player: Player) { @@ -808,7 +808,7 @@ object BalloonFlightScreens { drawModels(player, 19526, 175, 200, 214) // Birds - drawAnimatedModels(player, MODEL_WHITE_BIRD, ANIMATION_BIRD, 2567, 100, 300, 178, 225) + drawAnimatedModels(player, MODEL_WHITE_BIRD_19779, ANIMATION_BIRD_341, 2567, 100, 300, 178, 225) } } \ No newline at end of file diff --git a/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt index 81580306c..81bfd59d5 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt @@ -46,11 +46,11 @@ import org.rs09.consts.NPCs * @author Edith */ -private const val ASSISTANT_STAN_WRAPPER = 5062 -private const val ASSISTANT_MARROW_WRAPPER = 5063 -private const val ASSISTANT_LE_SMITH_WRAPPER = 5064 -private const val ASSISTANT_BROCK_WRAPPER = 5065 -private const val ASSISTANT_SERF_WRAPPER = 5066 +private const val ASSISTANT_STAN_WRAPPER_5062 = 5062 +private const val ASSISTANT_MARROW_WRAPPER_5063 = 5063 +private const val ASSISTANT_LE_SMITH_WRAPPER_5064 = 5064 +private const val ASSISTANT_BROCK_WRAPPER_5065 = 5065 +private const val ASSISTANT_SERF_WRAPPER_5066 = 5066 private const val VARROCK_MEDIUM_DIARY = 1 @@ -77,16 +77,16 @@ private val BALLOON_BASKET_LOCS = intArrayOf(19128, 19129) class BalloonTravelInterface : InterfaceListener, InteractionListener { companion object { - private const val BALLOON_MAP_INTERFACE = 469 - private const val BALLOON_MAP_MODEL = 12 + private const val BALLOON_MAP_INTERFACE_469 = 469 + private const val BALLOON_MAP_MODEL_12 = 12 private const val ATTRIBUTE_BALLOON_START = "balloon_travel_start" /** Opens the balloon map interface. */ fun open(player: Player, start: BalloonTravelLocation) { setAttribute(player, ATTRIBUTE_BALLOON_START, start) - openInterface(player, BALLOON_MAP_INTERFACE) - setComponentVisibility(player, BALLOON_MAP_INTERFACE, start.mapComponent, false) + openInterface(player, BALLOON_MAP_INTERFACE_469) + setComponentVisibility(player, BALLOON_MAP_INTERFACE_469, start.mapComponent, false) } /** Checks the saved route unlock state. */ @@ -160,9 +160,9 @@ class BalloonTravelInterface : InterfaceListener, InteractionListener { val duration = animationDuration(Animation(animation)) lock(player, duration) - setComponentVisibility(player, BALLOON_MAP_INTERFACE, start.mapComponent, true) - setComponentVisibility(player, BALLOON_MAP_INTERFACE, BALLOON_MAP_MODEL, false) - animateInterface(player, BALLOON_MAP_INTERFACE, BALLOON_MAP_MODEL, animation) + setComponentVisibility(player, BALLOON_MAP_INTERFACE_469, start.mapComponent, true) + setComponentVisibility(player, BALLOON_MAP_INTERFACE_469, BALLOON_MAP_MODEL_12, false) + animateInterface(player, BALLOON_MAP_INTERFACE_469, BALLOON_MAP_MODEL_12, animation) queueScript(player, duration, QueueStrength.SOFT) { closeInterface(player) @@ -199,7 +199,7 @@ class BalloonTravelInterface : InterfaceListener, InteractionListener { } override fun defineInterfaceListeners() { - on(BALLOON_MAP_INTERFACE) { player, _, _, selectId, _, _ -> + on(BALLOON_MAP_INTERFACE_469) { player, _, _, selectId, _, _ -> val destination = BalloonTravelLocation.fromSelectId(selectId) ?: return@on false val start = getAttribute(player, ATTRIBUTE_BALLOON_START, BalloonTravelLocation.ENTRANA) @@ -226,6 +226,7 @@ class BalloonTravelInterface : InterfaceListener, InteractionListener { override fun defineListeners() { on(BALLOON_VISIBLE_NPCS, IntType.NPC, "fly") { player, node -> if (!isQuestComplete(player, Quests.ENLIGHTENED_JOURNEY)) { + sendMessage(player, "You should speak to Auguste first.") return@on true } @@ -281,7 +282,7 @@ enum class BalloonTravelLocation( 10, 50, EnlightenedJourney.VARBIT_CASTLEWARS_BALLOON_2869, - ASSISTANT_MARROW_WRAPPER, + ASSISTANT_MARROW_WRAPPER_5063, 19137, ), GRAND_TREE( @@ -292,7 +293,7 @@ enum class BalloonTravelLocation( 3, 60, EnlightenedJourney.VARBIT_GRANDTREE_BALLOON_2870, - ASSISTANT_LE_SMITH_WRAPPER, + ASSISTANT_LE_SMITH_WRAPPER_5064, 19139, ), CRAFTING_GUILD( @@ -303,7 +304,7 @@ enum class BalloonTravelLocation( 10, 30, EnlightenedJourney.VARBIT_CRAFTINGGUILD_BALLOON_2871, - ASSISTANT_BROCK_WRAPPER, + ASSISTANT_BROCK_WRAPPER_5065, 19141, ), ENTRANA( @@ -325,7 +326,7 @@ enum class BalloonTravelLocation( 1, 20, EnlightenedJourney.VARBIT_TAVERLEY_BALLOON_2868, - ASSISTANT_STAN_WRAPPER, + ASSISTANT_STAN_WRAPPER_5062, 19135, ), VARROCK( @@ -336,7 +337,7 @@ enum class BalloonTravelLocation( 10, 40, EnlightenedJourney.VARBIT_VARROCK_BALLOON_2872, - ASSISTANT_SERF_WRAPPER, + ASSISTANT_SERF_WRAPPER_5066, 19143, ); diff --git a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt index 23748d4ee..3b39482de 100644 --- a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourney.kt @@ -114,57 +114,67 @@ class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, } if (stage >= STAGE_QUEST_STARTED) { - line(player, "I have agreed to help Auguste build an !!air balloon??.", line++, stage > STAGE_GATHER_MATERIALS) - line(player, "I have no idea what he's talking about.", line++, stage > STAGE_GATHER_MATERIALS) - line(player, "Auguste thinks if he pumps hot air into a sack it will rise and", line++, stage > STAGE_GATHER_MATERIALS) - line(player, "take us along with it.", line++, stage > STAGE_GATHER_MATERIALS) - line(player, "But we're going to run some tests first. Thank goodness.", line++, stage > STAGE_GATHER_MATERIALS) - line++ + line(player, "I have agreed to help Auguste build an !!air balloon??.", line++, stage > STAGE_QUEST_STARTED) + line(player, "I have no idea what he's talking about.", line++, stage > STAGE_QUEST_STARTED) + line(player, "Auguste thinks if he pumps hot air into a sack it will rise and", line++, stage > STAGE_QUEST_STARTED) + line(player, "take us along with it.", line++, stage > STAGE_QUEST_STARTED) + line(player, "But we're going to run some tests first. Thank goodness.", line++, stage > STAGE_QUEST_STARTED) } - if (stage >= STAGE_GATHER_MATERIALS) { + if (stage in STAGE_GATHER_MATERIALS until STAGE_ORIGAMI_BALLOON) { line(player, "I need to gather the materials Auguste required:", line++, stage > STAGE_GATHER_MATERIALS) line(player, "three sheets of papyrus", line++, stage > STAGE_GATHER_MATERIALS || inInventory(player, Items.PAPYRUS_970, 3)) line(player, "a ball of wool", line++, stage > STAGE_GATHER_MATERIALS || inInventory(player, Items.BALL_OF_WOOL_1759)) line(player, "a full sack of potatoes", line++, stage > STAGE_GATHER_MATERIALS || inInventory(player, Items.POTATOES10_5438)) line(player, "one unlit candle.", line++, stage > STAGE_GATHER_MATERIALS || inInventory(player, Items.CANDLE_36)) - line++ } if (stage >= STAGE_ORIGAMI_BALLOON) { - line(player, "I made an !!origami balloon??.", line++, stage > STAGE_ORIGAMI_BALLOON || inInventory(player, Items.ORIGAMI_BALLOON_9934)) - line(player, "Auguste said I could make these any time I want if", line++, stage > STAGE_ORIGAMI_BALLOON) - line(player, "I have the materials.", line++, stage > STAGE_ORIGAMI_BALLOON) - line++ + line(player, "I gathered all the materials Auguste required:", line++, true) + line(player, "three sheets of papyrus, a ball of wool,", line++, true) + line(player, "a full sack of potatoes and one unlit candle.", line++, true) + } + + if (stage in STAGE_ORIGAMI_BALLOON until STAGE_FIRST_EXPERIMENT) { + line(player, "I need to make the first test balloon with the ball of wool,", line++) + line(player, "a sheet of papyrus and an unlit candle and then give it to", line++) + line(player, "Auguste.", line++) + } + + if (stage >= STAGE_FIRST_EXPERIMENT) { + line(player, "I made an !!origami balloon??.", line++, true) + line(player, "Auguste said I could make these any time I want if", line++, true) + line(player, "I have the materials.", line++, true) } if (stage >= STAGE_FIRST_EXPERIMENT) { line(player, "Auguste conducted the first experiment.", line++, stage > STAGE_FIRST_EXPERIMENT) line(player, "There was an awful lot of fire.", line++, stage > STAGE_FIRST_EXPERIMENT) - line++ + } + + if (stage in STAGE_FIRST_EXPERIMENT until STAGE_SECOND_EXPERIMENT) { + line(player, "I need to give Auguste two sheets of papyrus and a full", line++) + line(player, "sack of potatoes.", line++) } if (stage >= STAGE_SECOND_EXPERIMENT) { line(player, "Auguste conducted the second experiment.", line++, stage > STAGE_SECOND_EXPERIMENT) line(player, "A flash mob appeared. They seem to have a grudge against", line++, stage > STAGE_SECOND_EXPERIMENT) line(player, "science.", line++, stage > STAGE_SECOND_EXPERIMENT) - line++ } - if (stage >= STAGE_MAIN_BALLOON) { - line(player, "I need to gather the supplies for Auguste's main balloon:", line++, stage > STAGE_MAIN_BALLOON) - line(player, "red dye", line++, stage > STAGE_MAIN_BALLOON || inInventory(player, Items.RED_DYE_1763)) - line(player, "yellow dye", line++, stage > STAGE_MAIN_BALLOON || inInventory(player, Items.YELLOW_DYE_1765)) - line(player, "ten pieces of silk", line++, stage > STAGE_MAIN_BALLOON || inInventory(player, Items.SILK_950, 10)) - line(player, "a bowl", line++, stage > STAGE_MAIN_BALLOON || inInventory(player, Items.BOWL_1923)) - line(player, "eight sandbags", line++, stage > STAGE_MAIN_BALLOON || inInventory(player, Items.SANDBAG_9943, 8)) - line++ + if (stage in STAGE_MAIN_BALLOON until STAGE_WILLOW_BASKET) { + line(player, "I need to gather the supplies for Auguste's main balloon:", line++) + line(player, "red dye", line++, getAttribute(player, ATTRIBUTE_RED_DYE_DELIVERED, false) || inInventory(player, Items.RED_DYE_1763)) + line(player, "yellow dye", line++, getAttribute(player, ATTRIBUTE_YELLOW_DYE_DELIVERED, false) || inInventory(player, Items.YELLOW_DYE_1765)) + line(player, "ten pieces of silk", line++, getAttribute(player, ATTRIBUTE_SILK_DELIVERED, false) || inInventory(player, Items.SILK_950, 10)) + line(player, "a bowl", line++, getAttribute(player, ATTRIBUTE_BOWL_DELIVERED, false) || inInventory(player, Items.BOWL_1923)) + line(player, "eight sandbags", line++, getAttribute(player, ATTRIBUTE_SANDBAGS_DELIVERED, false) || inInventory(player, Items.SANDBAG_9943, 8)) } - if (stage >= STAGE_WILLOW_BASKET) { - line(player, "I need to make the basket for the balloon:", line++, stage > STAGE_WILLOW_BASKET) - line(player, "twelve willow branches", line++, stage > STAGE_WILLOW_BASKET || inInventory(player, Items.WILLOW_BRANCH_5933, 12)) - line++ + if (stage in STAGE_WILLOW_BASKET until STAGE_FLIGHT) { + line(player, "I've given all the materials to Auguste, now I just need to", line++) + line(player, "use the 12 willow branches to build the basket.", line++) } if (stage >= STAGE_FLIGHT) { @@ -172,7 +182,6 @@ class EnlightenedJourney : Quest(Quests.ENLIGHTENED_JOURNEY, 55, 54, 1, 0, line(player, "balloon.", line++, stage > STAGE_FLIGHT) line(player, "The balloon is all made and looks impressive!", line++, stage > STAGE_FLIGHT) line(player, "Let's hope it doesn't end the way the experiments did.", line++, stage > STAGE_FLIGHT) - line++ } if (stage >= STAGE_CLAIM_REWARD) { From 673e011127820e3b0f7d38719f596587d2b61419 Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Wed, 8 Jul 2026 00:45:35 +0200 Subject: [PATCH 09/14] this onion has many layers: Completely overhauled balloon minigame to use a grid system. Overhauled crash sites SHARK PATROL UWU a bunch of other shit i forgot --- Server/data/configs/npc_spawns.json | 8 +- .../travel/balloon/BalloonCrashSites.kt | 90 ++++--- .../travel/balloon/BalloonFlightGrid.kt | 219 +++++++++++++++++ .../travel/balloon/BalloonFlightInterface.kt | 225 +++++++++--------- .../travel/balloon/BalloonFlightRoutes.kt | 38 ++- .../travel/balloon/BalloonFlightScreens.kt | 18 +- .../travel/balloon/OceanCrashSharkPatrol.kt | 62 +++++ 7 files changed, 485 insertions(+), 175 deletions(-) create mode 100644 Server/src/main/content/global/travel/balloon/BalloonFlightGrid.kt create mode 100644 Server/src/main/content/global/travel/balloon/OceanCrashSharkPatrol.kt diff --git a/Server/data/configs/npc_spawns.json b/Server/data/configs/npc_spawns.json index 50e91a604..f8a68a451 100644 --- a/Server/data/configs/npc_spawns.json +++ b/Server/data/configs/npc_spawns.json @@ -157,7 +157,7 @@ }, { "npc_id": "47", - "loc_data": "{2821,3170,0,1,1}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3341,3267,0,1,5}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3001,3202,0,1,5}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" + "loc_data": "{2821,3170,0,1,1}-{3341,3267,0,1,5}-{3076,3282,0,1,5}-{3089,3266,0,1,4}-{3091,3266,0,1,4}-{3097,3364,0,1,3}-{3102,3363,0,1,5}-{3127,3487,0,1,4}-{3125,3486,0,1,6}-{3127,3486,0,1,4}-{2339,9356,0,1,0}-{2354,9390,0,1,0}-{2361,9403,0,1,0}-{2362,9347,0,1,0}-{2603,9480,0,1,1}-{2600,9477,0,1,0}-{2579,9496,0,1,4}-{2580,9508,0,1,0}-{2571,9522,0,1,4}-{2565,9505,0,1,1}-{2566,9510,0,1,6}-{2594,9497,0,1,4}-{2852,9642,0,1,6}-{2858,9632,0,1,3}-{2568,9620,0,1,0}-{2573,9612,0,1,0}-{2579,9631,0,1,0}-{2580,9600,0,1,0}-{2580,9614,0,1,0}-{2580,9620,0,1,0}-{2580,9626,0,1,0}-{2583,9632,0,1,0}-{2584,9625,0,1,0}-{2584,9637,0,1,0}-{2589,9644,0,1,0}-{2590,9601,0,1,0}-{2590,9638,0,1,0}-{2591,9601,0,1,0}-{2591,9621,0,1,0}-{2594,9636,0,1,0}-{2594,9644,0,1,0}-{2597,9604,0,1,0}-{2607,9615,0,1,0}-{2608,9628,0,1,0}-{2614,9651,0,1,0}-{2614,9656,0,1,0}-{2615,9647,0,1,0}-{2615,9661,0,1,0}-{2616,9633,0,1,0}-{2618,9630,0,1,0}-{3108,9754,0,1,5}-{3110,9754,0,1,5}-{3108,9750,0,1,5}-{2592,9831,0,1,3}-{2588,9825,0,1,6}-{2583,9829,0,1,4}-{2581,9841,0,1,0}-{2597,9823,0,1,2}-{2579,9805,0,1,3}-{2576,9804,0,1,0}-{2573,9805,0,1,5}-{2571,9808,0,1,3}-{2576,9810,0,1,2}-{2587,9802,0,1,2}-{2592,9800,0,1,4}-{2596,9805,0,1,6}-{2601,9802,0,1,5}-{2585,9801,0,1,7}-{2594,9803,0,1,0}-{2590,9806,0,1,3}-{2612,9808,0,1,6}-{2604,9810,0,1,6}-{2579,9821,0,1,2}-{2576,9812,0,1,6}-{2580,9813,0,1,6}-{2600,9813,0,1,4}-{2599,9809,0,1,4}-{3158,3226,0,1,5}-{3160,3202,0,1,4}-{3192,3203,0,1,0}-{3194,3204,0,1,0}-{3196,3206,0,1,0}-{3197,3204,0,1,0}-{2654,9640,0,1,6}-{2655,9637,0,1,4}-{2656,9639,0,1,7}-{2651,9636,0,1,5}-{2648,9637,0,1,4}-{2651,9642,0,1,1}-{2654,9640,0,1,0}-{2654,9635,0,1,6}-{2655,9635,0,1,3}-{2664,9626,0,1,6}-{2664,9624,0,1,1}-{2661,9623,0,1,1}-{2663,9623,0,1,3}-{2664,9626,0,1,6}-{2930,9699,0,1,0}-{2933,9697,0,1,0}-{2932,9685,0,1,0}-{2930,9693,0,1,0}-{3235,3224,0,1,3}-{3229,3220,0,1,4}-{3211,3211,0,1,3}-{3225,3220,0,1,1}-{3237,3215,0,1,5}-{3211,3210,0,1,7}-{3227,3220,0,1,7}-{3233,3227,0,1,5}-{3227,3210,0,1,6}-{3228,3222,0,1,4}-{3229,3226,0,1,0}-{3236,3217,0,1,4}-{3259,3230,0,1,4}-{3233,3237,0,1,7}-{3205,3204,0,1,0}-{3206,3204,0,1,0}-{3205,3203,0,1,0}-{3206,3202,0,1,0}-{3207,3202,0,1,0}-{3208,3203,0,1,0}-{3001,3202,0,1,5}-{3243,3687,0,1,5}-{3249,3669,0,1,3}-{3252,3675,0,1,4}-{3252,3680,0,1,3}-{3259,3683,0,1,0}-{3475,9840,0,1,6}-{3481,9842,0,1,1}-{3486,9843,0,1,7}-{3483,9824,0,1,4}-{3496,9808,0,0,5}-{3490,9815,0,1,1}-{3478,9834,0,0,3}-{3490,9824,0,1,4}-{3225,9862,0,1,4}-{3222,9861,0,1,6}-{3220,9860,0,1,6}-{3219,9865,0,1,6}-{3237,9862,0,1,4}-{2536,2982,0,1,3}-{2531,2980,0,1,0}-{2522,2981,0,1,4}-{2545,2989,0,1,4}-{2523,2970,0,1,2}-{3026,3174,0,1,5}-{3019,3176,0,1,7}-{2801,3158,0,1,2}-{2514,3193,0,1,6}-{2518,3192,0,1,3}-{2507,3181,0,1,3}-{2508,3178,0,1,6}-{2511,3183,0,1,3}-{2515,3182,0,1,1}-{3021,3205,0,1,6}-{3019,3292,0,1,7}-{3018,3295,0,1,7}-{2531,3325,0,1,3}-{2530,3327,0,1,5}-{2521,3331,0,1,3}-{2526,3328,0,1,3}-{2523,3331,0,1,4}-{2523,3334,0,1,1}-{2531,3329,0,1,5}-{2532,3333,0,1,5}-{3276,9871,0,1,1}-{3277,9871,0,1,3}-" }, { "npc_id": "48", @@ -8641,15 +8641,15 @@ }, { "npc_id": "5067", - "loc_data": "{1799,4889,0,1,4}-" + "loc_data": "{1799,4885,0,0,3}-" }, { "npc_id": "5068", - "loc_data": "{1807,4889,0,1,3}-" + "loc_data": "{1805,4885,0,0,3}-" }, { "npc_id": "5069", - "loc_data": "{1807,4893,0,1,3}-" + "loc_data": "{1807,4893,0,0,6}-" }, { "npc_id": "5070", diff --git a/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt b/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt index 690da7806..6415e606e 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonCrashSites.kt @@ -8,20 +8,25 @@ import core.api.delayScript import core.api.face import core.api.getAttribute import core.api.getRegionBorders +import core.api.inBorders +import core.api.openDialogue import core.api.openOverlay import core.api.playAudio import core.api.queueScript import core.api.removeAttribute -import core.api.sendMessage +import core.api.sendDialogue import core.api.sendPlayerDialogue import core.api.setAttribute import core.api.stopExecuting import core.api.teleport import core.api.unlock +import core.game.dialogue.DialogueFile import core.game.dialogue.DialogueLabeller +import core.game.dialogue.FacialExpression 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.player.Player import core.game.world.map.Location import core.game.world.map.zone.ZoneBorders @@ -73,7 +78,7 @@ object BalloonCrashSites { fadeTransition(player) { closeFlightInterface(player) teleport(player, exit) - sendMessage(player, "You bail, but land safely on Entrana.") + sendDialogue(player, "You bail, but land safely on Entrana.") } } @@ -82,21 +87,23 @@ object BalloonCrashSites { fadeTransition(player) { closeFlightInterface(player) teleport(player, OCEAN_CRASH_LANDING) - oceanSwimmingAnimations(player) + oceanSwimmingAnimation(player) face(player, OCEAN_CRASH_FACE_LOCATION) - sendMessage(player, "The balloon crashes.") + sendDialogue(player, "The balloon crashes.") } } fun leaveOceanCrashSite(player: Player) { - sendMessage(player, "You climb onto the plank and swim to shore.") - fadeTransition(player, fadeToBlack = true) { - player.appearance.setAnimations() - player.appearance.sync() - teleport(player, OCEAN_CRASH_EXIT) - face(player, OCEAN_CRASH_EXIT_FACE_LOCATION) - sendMessage(player, "You manage to swim back to shore.") - } + player.appearance.setAnimations() + player.appearance.sync() + teleport(player, OCEAN_CRASH_EXIT) + face(player, OCEAN_CRASH_EXIT_FACE_LOCATION) + sendDialogue(player, "You manage to swim back to shore.") + } + + fun oceanSwimmingAnimation(player: Player) { + player.appearance.setAnimations(Animation(RENDER_ANIMATION_SWIM_188)) + player.appearance.sync() } fun crashAtWoodlandSite(player: Player, exit: WoodlandExit) { @@ -106,13 +113,12 @@ object BalloonCrashSites { closeFlightInterface(player) teleport(player, WOODLAND_CRASH_LANDING) face(player, WOODLAND_CRASH_FACE_LOCATION) - sendMessage(player, "The balloon crashes.") + sendDialogue(player, "The balloon crashes.") } } fun leaveWoodlandCrashSite(player: Player) { val exit = getWoodlandExit(player) - sendMessage(player, "You walk away from the crash site.") fadeTransition(player, fadeToBlack = true) { when (exit) { WoodlandExit.FALADOR -> { @@ -177,23 +183,21 @@ object BalloonCrashSites { return@queueScript stopExecuting(player) } } - - private fun oceanSwimmingAnimations(player: Player) { - player.appearance.setAnimations(Animation(RENDER_ANIMATION_SWIM_188)) - player.appearance.sync() - } - } class BalloonCrashSiteListener : InteractionListener, MapArea { override fun defineListeners() { on(BalloonCrashSites.SCENERY_OCEAN_PLANK_19126, IntType.SCENERY, "use") { player, _ -> - BalloonCrashSites.leaveOceanCrashSite(player) + openDialogue(player, BalloonCrashExitDialogue("You climb onto the plank and swim to shore.") { + BalloonCrashSites.leaveOceanCrashSite(it) + }) return@on true } on(BalloonCrashSites.SCENERY_WOODLAND_DIRT_19125, IntType.SCENERY, "leave") { player, _ -> - BalloonCrashSites.leaveWoodlandCrashSite(player) + openDialogue(player, BalloonCrashExitDialogue("You walk away from the crash site.") { + BalloonCrashSites.leaveWoodlandCrashSite(it) + }) return@on true } @@ -209,6 +213,15 @@ class BalloonCrashSiteListener : InteractionListener, MapArea { } + override fun areaEnter(entity: Entity) { + if (entity !is Player || !inBorders(entity, 1795, 4883, 1810, 4898)) return + + queueScript(entity, 0, QueueStrength.SOFT) { + BalloonCrashSites.oceanSwimmingAnimation(entity) + return@queueScript stopExecuting(entity) + } + } + override fun defineAreaBorders(): Array { return arrayOf(getRegionBorders(BalloonCrashSites.CRASH_SITE_REGION_7244)) } @@ -218,6 +231,20 @@ class BalloonCrashSiteListener : InteractionListener, MapArea { } } +/** Displays a crash site exit message and continues the exit after the player clicks Continue. */ +private class BalloonCrashExitDialogue(private val message: String, private val onContinue: (Player) -> Unit) : DialogueFile() { + override fun handle(componentID: Int, buttonID: Int) { + when (stage) { + 0 -> sendDialogue(player!!, message).also { stage++ } + 1 -> { + val player = player!! + end() + onContinue(player) + } + } + } +} + class BalloonCrashDialogue : DialogueLabeller() { override fun addConversation() { assignToIds(BalloonCrashSites.NPC_OCEAN_AUGUSTE_5051) @@ -230,18 +257,17 @@ class BalloonCrashDialogue : DialogueLabeller() { } label("ocean_crash") - npc("Great Scott! Ocean! Ahhh!") - player("What happened?") - npc("Crashed, off course. Ocean! Oh dear... I feel very...") - player("Contemplative? Concerned for your life? Desperate?") - npc("No...more along the lines of ill...You might want to swim away now. Use the plank...") - player("How are you going to get back? What about the balloon?") - npc("I'm sure a fishing trawler will come by and give me a lift. Don't worry, I shall return.") + npc(FacialExpression.SCARED, "Great Scott! Ocean! Ahhh!") + player(FacialExpression.SCARED, "What happened?") + npc(FacialExpression.SCARED, "Crashed, off course. Ocean! Oh dear... I feel very...") + player(FacialExpression.ASKING, "Contemplative? Concerned for your life? Desperate?") + npc(FacialExpression.SCARED, "No...more along the lines of ill...You might want to swim away now. Use the plank...") + player(FacialExpression.SCARED, "How are you going to get back? What about the balloon?") + npc(FacialExpression.THINKING, "I'm sure a fishing trawler will come by and give me a lift. Don't worry, I shall return.") label("woodland_crash") - npc("Well, that didn't go as planned.") + npc(FacialExpression.ANGRY, "Well, that didn't go as planned.") player("So what now? How will we get the balloon back?") - npc("I'll have to get one of the monks to come pick it up. You head back on your own; just follow the path. I'll meet you back at Entrana.") + npc(FacialExpression.SAD, "I'll have to get one of the monks to come pick it up. You head back on your own; just follow the path. I'll meet you back at Entrana.") } - } \ No newline at end of file diff --git a/Server/src/main/content/global/travel/balloon/BalloonFlightGrid.kt b/Server/src/main/content/global/travel/balloon/BalloonFlightGrid.kt new file mode 100644 index 000000000..56fb98a67 --- /dev/null +++ b/Server/src/main/content/global/travel/balloon/BalloonFlightGrid.kt @@ -0,0 +1,219 @@ +package content.global.travel.balloon + +/** Row and column within the balloon interface grid, starting from the top-left. */ +data class BalloonGridPosition(val row: Int, val column: Int) + +/** + * Defines the interface grid and collision points for the balloon minigame. + * @author Edith + */ +object BalloonFlightGrid { + private const val GRID_ROWS = 13 + private const val GRID_COLUMNS = 20 + private const val TOP_LEFT_GRID_CHILD = 258 + private val FLIGHT_AREA_ROWS = 2..9 + + const val SCREEN_ONE = 1 + const val SCREEN_TWO = 2 + const val SCREEN_THREE = 3 + + private val childGrid = Array(GRID_ROWS) { row -> + IntArray(GRID_COLUMNS) { column -> TOP_LEFT_GRID_CHILD - row * GRID_COLUMNS + column } + }.apply { + // Children 98 and 99 are reversed in interface 470. + this[8][0] = 99 + this[8][1] = 98 + } + + /** Interface model children that cause a collision on each flight screen. */ + private val collisionGrids = mapOf( + BalloonTravelLocation.TAVERLEY to mapOf( + SCREEN_ONE to setOf( + 78, 82, 83, 84, 85, 86, 87, 88, 89, 91, + 92, 102, 103, 104, 105, 106, 107, 108, 109, 123, + 124, 125, 127, 128, 145, 148, 155, 156, 172, 173, + 174, 175, 177, 209, 210, 211, 212, 213, 227, 228, + 229, 230 + ), + SCREEN_TWO to setOf( + 83, 84, 90, 91, 92, 93, 94, 95, 96, 97, + 103, 111, 112, 113, 114, 115, 116, 117, 123, 133, + 134, 135, 136, 137, 154, 155, 156, 157, 158, 161, + 179, 180, 181, 185, 186, 187, 188, 201, 202, 203, + 204, 219 + ), + SCREEN_THREE to setOf( + 78, 79, 80, 81, 82, 83, 84, 85, 86, 92, + 93, 97, 98, 99, 100, 101, 102, 103, 106, 113, + 118, 119, 120, 121, 126, 138, 146, 151, 168, 169, + 170, 171, 174, 175, 176, 191, 192, 207, 208, 212, + 213, 214, 215 + ) + ), + BalloonTravelLocation.CRAFTING_GUILD to mapOf( + SCREEN_ONE to setOf( + 78, 79, 80, 81, 82, 83, 84, 88, 89, 90, + 91, 93, 96, 97, 98, 99, 100, 102, 103, 104, + 108, 109, 110, 111, 113, 116, 117, 118, 119, 122, + 124, 128, 129, 130, 131, 133, 137, 138, 148, 151, + 162, 163, 164, 171, 175, 183, 192, 193, 194, 206, + 220, 221, 233, 234, 235 + ), + SCREEN_TWO to setOf( + 78, 79, 83, 84, 87, 89, 92, 96, 97, 98, + 99, 103, 104, 107, 109, 112, 119, 124, 127, 132, + 161, 168, 169, 170, 171, 187, 188, 193, 194, 195, + 200, 201, 202, 205, 206, 207, 216, 217 + ), + SCREEN_THREE to setOf( + 78, 79, 80, 83, 84, 85, 86, 87, 88, 89, + 90, 97, 100, 103, 104, 105, 107, 108, 110, 120, + 123, 130, 143, 163, 166, 167, 168, 173, 174, 175, + 198, 199, 209, 210, 211, 212, 222, 223, 224, 228, + 229, 230 + ) + ), + BalloonTravelLocation.VARROCK to mapOf( + SCREEN_ONE to setOf( + 78, 79, 80, 83, 86, 87, 88, 89, 90, 91, + 93, 94, 95, 97, 99, 100, 107, 108, 109, 110, + 111, 113, 114, 115, 117, 120, 122, 127, 129, 131, + 135, 137, 144, 145, 146, 157, 161, 163, 170, 174, + 188, 189, 190, 193, 194, 195, 198, 199, 200, 206, + 207, 208, 216, 232 + ), + SCREEN_TWO to setOf( + 79, 81, 82, 83, 85, 86, 87, 88, 89, 93, + 94, 95, 97, 98, 101, 102, 103, 105, 106, 107, + 108, 109, 113, 114, 115, 117, 119, 122, 125, 126, + 127, 128, 129, 134, 135, 137, 139, 145, 146, 147, + 148, 149, 154, 166, 167, 168, 171, 172, 173, 187, + 190, 192, 200, 201, 202, 209, 214, 215, 216, 217, + 218, 224, 225, 226, 236 + ), + SCREEN_THREE to setOf( + 79, 80, 81, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 97, 98, 100, 101, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 119, 120, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 141, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 163, 164, + 167, 168, 171, 172, 183, 184, 187, 188, 191, 192, + 198, 199, 201, 202, 225, 230 + ) + ), + BalloonTravelLocation.CASTLE_WARS to mapOf( + SCREEN_ONE to setOf( + 78, 80, 83, 84, 85, 92, 93, 97, 100, 105, + 112, 120, 130, 136, 140, 147, 164, 165, 166, 169, + 170, 175, 176, 177, 181, 182, 183, 193, 207, 212, + 213, 214, 227, 228, 229 + ), + SCREEN_TWO to setOf( + 79, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 95, 96, 107, 108, 109, 110, 111, 112, 113, 115, + 116, 118, 129, 130, 131, 132, 133, 135, 136, 140, + 141, 142, 152, 153, 156, 158, 159, 173, 180, 181, + 189, 190, 191, 197, 203, 204, 205, 215, 216, 217, + 228, 229, 230, 231 + ), + SCREEN_THREE to setOf( + 78, 80, 83, 84, 85, 86, 87, 92, 93, 97, + 99, 100, 103, 104, 105, 106, 107, 112, 113, 118, + 120, 123, 124, 125, 126, 127, 133, 138, 140, 147, + 153, 170, 171, 172, 179, 183, 184, 185, 186, 198, + 199, 208, 209, 210, 211, 215, 216, 217, 222, 223 + ) + ), + BalloonTravelLocation.GRAND_TREE to mapOf( + SCREEN_ONE to setOf( + 78, 79, 80, 81, 84, 85, 89, 90, 93, 94, + 97, 98, 99, 100, 104, 110, 118, 119, 130, 138, + 144, 186, 187, 188, 191, 192, 193, 194, 195, 201, + 202, 203, 214, 229, 230, 231, 232, 237 + ), + SCREEN_TWO to setOf( + 79, 80, 81, 82, 83, 84, 87, 88, 89, 90, + 91, 92, 94, 95, 96, 97, 100, 101, 102, 103, + 104, 107, 108, 109, 110, 111, 112, 114, 115, 116, + 117, 120, 122, 124, 127, 128, 129, 130, 132, 134, + 135, 140, 142, 144, 147, 149, 150, 152, 154, 167, + 172, 181, 183, 191, 192, 196, 197, 200, 201, 203, + 204, 205, 208, 209, 214, 215, 216, 217, 219, 220, + 224, 228 + ), + SCREEN_THREE to setOf( + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 140, 141, 142, 143, 144, 145, + 146, 147, 148, 149, 150, 151, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 174, 175, 178, 182, + 183, 187, 188, 189, 198, 199, 200, 212, 213, 214, + 225 + ) + ) + ) + + /** Grid columns for crashing over ocean. */ + private val oceanColumns = mapOf( + BalloonTravelLocation.TAVERLEY to mapOf( + SCREEN_ONE to 17..19, + SCREEN_TWO to 0..7 + ), + BalloonTravelLocation.CRAFTING_GUILD to mapOf( + SCREEN_TWO to 4..19, + SCREEN_THREE to 0..2 + ), + BalloonTravelLocation.VARROCK to mapOf( + SCREEN_ONE to 2..6 + ), + BalloonTravelLocation.CASTLE_WARS to mapOf( + SCREEN_ONE to 4..19, + SCREEN_TWO to 0..5 + ), + BalloonTravelLocation.GRAND_TREE to mapOf( + SCREEN_ONE to 4..19 + ) + ) + + /** Checks whether balloon position is above the ocean. */ + fun isOverOcean(destination: BalloonTravelLocation, screen: Int, position: BalloonGridPosition): Boolean { + return oceanColumns[destination]?.get(screen)?.contains(position.column) == true + } + + /** Gets the interface child occupied by a grid position. */ + fun getGridChild(position: BalloonGridPosition): Int? { + if (position.row !in childGrid.indices) { + return null + } + if (position.column !in childGrid[position.row].indices) { + return null + } + return childGrid[position.row][position.column] + } + + /** Checks whether a grid position is inside the flight area. */ + fun isInFlightArea(position: BalloonGridPosition): Boolean { + return position.row in FLIGHT_AREA_ROWS && position.column in 0 until GRID_COLUMNS + } + + /** Checks whether either part of the balloon collides with the flight boundary or a model. */ + fun willBalloonCollide(destination: BalloonTravelLocation, screen: Int, position: BalloonGridPosition): Boolean { + val topPosition = position.copy(row = position.row - 1) + + if (position.column == GRID_COLUMNS) { + return topPosition.row !in FLIGHT_AREA_ROWS || position.row !in FLIGHT_AREA_ROWS + } + + if (!isInFlightArea(topPosition) || !isInFlightArea(position)) { + return true + } + + val collisionChildren = collisionGrids[destination]?.get(screen) ?: return true + val topChild = getGridChild(topPosition) ?: return true + val bottomChild = getGridChild(position) ?: return true + return topChild in collisionChildren || bottomChild in collisionChildren + } +} \ No newline at end of file diff --git a/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt index eded3b846..ef5bb1197 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt @@ -7,6 +7,7 @@ import core.api.closeOverlay import core.api.closeTabInterface import core.api.face import core.api.getAttribute +import core.api.getVarbit import core.api.openInterface import core.api.openOverlay import core.api.openSingleTab @@ -29,7 +30,6 @@ import core.net.packet.context.MinimapStateContext import core.net.packet.out.MinimapState import core.plugin.Initializable import org.rs09.consts.Components -import kotlin.math.abs /** * Handles the balloon flight minigame interface. @@ -54,13 +54,18 @@ class BalloonFlightInterface : InterfaceListener { private const val BALLOON_FLIGHT_INTERFACE_470 = 470 private const val BALLOON_CONTROL_INTERFACE_471 = 471 - private const val ATTRIBUTE_BALLOON_TOP = "enlightenedjourney_balloon_top" - private const val ATTRIBUTE_BALLOON_BOTTOM = "enlightenedjourney_balloon_bottom" + private const val ATTRIBUTE_BALLOON_ROW = "enlightenedjourney_balloon_row" + private const val ATTRIBUTE_BALLOON_COLUMN = "enlightenedjourney_balloon_column" private const val ATTRIBUTE_FLIGHT_PROGRESS = "enlightenedjourney_balloon_flight_progress" private const val ATTRIBUTE_FLIGHT_SCREEN = "enlightenedjourney_balloon_flight_screen" private const val ATTRIBUTE_FLIGHT_DESTINATION = "enlightenedjourney_balloon_flight_destination" + private const val VARBIT_SANDBAGS_REMAINING_2880 = 2880 + private const val VARBIT_LOGS_REMAINING_2881 = 2881 + private const val STARTING_SANDBAGS = 8 + private const val STARTING_LOGS = 10 + private const val SOUND_SANDBAG_3249 = 3249 private const val SOUND_BURN_LOG_3251 = 3251 private const val SOUND_RELAX_3247 = 3247 @@ -87,7 +92,8 @@ class BalloonFlightInterface : InterfaceListener { setAttribute(player, ATTRIBUTE_FLIGHT_DESTINATION, BalloonTravelLocation.TAVERLEY) setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, 1) - setBalloonPosition(player, startPosition.top, startPosition.bottom) + setBalloonPosition(player, startPosition) + updateFlightSupplies(player) closeInterface(player) hideGameTabs(player) hideMinimap(player) @@ -101,7 +107,8 @@ class BalloonFlightInterface : InterfaceListener { setAttribute(player, ATTRIBUTE_FLIGHT_DESTINATION, destination) setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, 1) - setBalloonPosition(player, startPosition.top, startPosition.bottom) + setBalloonPosition(player, startPosition) + updateFlightSupplies(player) closeInterface(player) hideGameTabs(player) hideMinimap(player) @@ -113,7 +120,7 @@ class BalloonFlightInterface : InterfaceListener { return getAttribute(player, ATTRIBUTE_FLIGHT_DESTINATION, BalloonTravelLocation.TAVERLEY) } - private fun getScreenPosition(destination: BalloonTravelLocation, screen: Int): BalloonPosition { + private fun getScreenPosition(destination: BalloonTravelLocation, screen: Int): BalloonGridPosition { return when (destination) { BalloonTravelLocation.TAVERLEY -> when (screen) { 1 -> BalloonFlightRoutes.TAVERLEY_START @@ -170,70 +177,85 @@ class BalloonFlightInterface : InterfaceListener { } } - private fun setBalloonPosition(player: Player, topChild: Int, bottomChild: Int) { - setAttribute(player, ATTRIBUTE_BALLOON_TOP, topChild) - setAttribute(player, ATTRIBUTE_BALLOON_BOTTOM, bottomChild) + private fun setBalloonPosition(player: Player, position: BalloonGridPosition) { + setAttribute(player, ATTRIBUTE_BALLOON_ROW, position.row) + setAttribute(player, ATTRIBUTE_BALLOON_COLUMN, position.column) } - /** Moves the balloon model on the interface according to the selected control. */ - private fun moveBalloon(player: Player, move: BalloonMove) { - val startPosition = BalloonFlightRoutes.getStartPosition(getFlightDestination(player)) - val oldTop = getAttribute(player, ATTRIBUTE_BALLOON_TOP, startPosition.top) - val oldBottom = getAttribute(player, ATTRIBUTE_BALLOON_BOTTOM, startPosition.bottom) - var newTop = oldTop - var newBottom = oldBottom - - if (newBottom == 98) { - newBottom += 2 - } - - newTop += move.east - newBottom += move.east - - repeat(abs(move.vertical)) { - if (move.vertical < 0) { - newTop = moveNorth(newTop) - newBottom = moveNorth(newBottom) - } else { - newTop = moveSouth(newTop) - newBottom = moveSouth(newBottom) - } - } - - if (move.vertical < 0 && newTop - newBottom == 21) { - newBottom += 1 - } - - BalloonFlightScreens.clearBalloon(player, oldTop, oldBottom) - setBalloonPosition(player, newTop, newBottom) - BalloonFlightScreens.drawBalloon(player, newTop, newBottom) + private fun getBalloonPosition(player: Player, destination: BalloonTravelLocation, screen: Int): BalloonGridPosition { + val startPosition = getScreenPosition(destination, screen) + return BalloonGridPosition( + getAttribute(player, ATTRIBUTE_BALLOON_ROW, startPosition.row), + getAttribute(player, ATTRIBUTE_BALLOON_COLUMN, startPosition.column) + ) } - private fun moveNorth(child: Int) = child + if (child >= 111) 20 else 19 - private fun moveSouth(child: Int) = child - 20 + /** Moves the balloon model on the interface according to the selected control, or returns false if it would collide. */ + private fun moveBalloon(player: Player, move: BalloonMove): Boolean { + val destination = getFlightDestination(player) + val screen = getAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, 1) + val oldPosition = getBalloonPosition(player, destination, screen) + val newPosition = oldPosition.copy(row = oldPosition.row + move.vertical, column = oldPosition.column + move.east) + + if (BalloonFlightGrid.willBalloonCollide(destination, screen, newPosition)) { + handleBalloonCrash(player, getCrashLocation(destination, screen, newPosition)) + return false + } + + BalloonFlightScreens.clearBalloon(player, oldPosition) + setBalloonPosition(player, newPosition) + BalloonFlightScreens.drawBalloon(player, newPosition) + return true + } + + /** Sets the starting amount of sandbags and logs, and deducts them when used. */ + private fun updateFlightSupplies(player: Player, buttonId: Int? = null): Boolean { + if (buttonId == null) { + setVarbit(player, VARBIT_SANDBAGS_REMAINING_2880, STARTING_SANDBAGS, true) + setVarbit(player, VARBIT_LOGS_REMAINING_2881, STARTING_LOGS, true) + return true + } + + val varbit = when (buttonId) { + BalloonFlightRoutes.BUTTON_SANDBAG -> VARBIT_SANDBAGS_REMAINING_2880 + BalloonFlightRoutes.BUTTON_BURN_LOG -> VARBIT_LOGS_REMAINING_2881 + else -> return true + } + + val remaining = getVarbit(player, varbit) + if (remaining <= 0) { + return false + } + + setVarbit(player, varbit, remaining - 1, true) + return true + } /** Handles a control button press and either advances, lands or crashes the route. */ - private fun handleRouteButton(player: Player, buttonId: Int) { + private fun handleControlButton(player: Player, buttonId: Int) { val destination = getFlightDestination(player) val screen = getAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, 1) if (buttonId == BalloonFlightRoutes.BUTTON_BAIL) { - handleBalloonCrash(player, getCrashLocation(destination, screen)) + val position = getBalloonPosition(player, destination, screen) + handleBalloonCrash(player, getCrashLocation(destination, screen, position)) return } - val route = BalloonFlightRoutes.getSequence(destination, screen) + val move = controlMoves[buttonId] ?: return + val routeLength = BalloonFlightRoutes.getSequence(destination, screen).size val progress = getAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) - val expectedButton = route.getOrNull(progress) - val move = controlMoves[buttonId] - if (buttonId != expectedButton || move == null) { - handleBalloonCrash(player, getCrashLocation(destination, screen)) + if (!updateFlightSupplies(player, buttonId)) { return } + playControlSound(player, buttonId) - moveBalloon(player, move) - if (progress + 1 >= route.size) { + if (!moveBalloon(player, move)) { + return + } + + if (progress + 1 >= routeLength) { advanceFlightScreen(player, destination, screen) } else { setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, progress + 1) @@ -255,14 +277,24 @@ class BalloonFlightInterface : InterfaceListener { BalloonFlightScreens.draw(player, destination, screen) } - private fun getCrashLocation(destination: BalloonTravelLocation, screen: Int): BalloonCrashLocation { + private fun getCrashLocation(destination: BalloonTravelLocation, screen: Int, position: BalloonGridPosition): BalloonCrashLocation { + if (BalloonFlightGrid.isOverOcean(destination, screen, position)) { + return BalloonCrashLocation.OCEAN + } + + if (screen == BalloonFlightGrid.SCREEN_ONE) { + return BalloonCrashLocation.ENTRANA + } + return when (destination) { - BalloonTravelLocation.TAVERLEY -> getTaverleyCrashLocation(screen) - BalloonTravelLocation.CRAFTING_GUILD -> getCraftingGuildCrashLocation(screen) - BalloonTravelLocation.VARROCK -> getVarrockCrashLocation(screen) - BalloonTravelLocation.CASTLE_WARS -> getCastleWarsCrashLocation(screen) - BalloonTravelLocation.GRAND_TREE -> getGrandTreeCrashLocation(screen) - else -> getTaverleyCrashLocation(screen) + BalloonTravelLocation.TAVERLEY, + BalloonTravelLocation.CRAFTING_GUILD, + BalloonTravelLocation.VARROCK -> BalloonCrashLocation.WOODLAND_FALADOR + + BalloonTravelLocation.CASTLE_WARS, + BalloonTravelLocation.GRAND_TREE -> BalloonCrashLocation.WOODLAND_ARDOUGNE + + else -> BalloonCrashLocation.ENTRANA } } @@ -274,13 +306,13 @@ class BalloonFlightInterface : InterfaceListener { } } - private fun startTaverleyScreen(player: Player, screen: Int, position: BalloonPosition) { + private fun startTaverleyScreen(player: Player, screen: Int, position: BalloonGridPosition) { BalloonFlightScreens.clear(player) BalloonFlightScreens.draw(player, BalloonTravelLocation.TAVERLEY, screen) setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, screen) setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) - setBalloonPosition(player, position.top, position.bottom) - BalloonFlightScreens.drawBalloon(player, position.top, position.bottom) + setBalloonPosition(player, position) + BalloonFlightScreens.drawBalloon(player, position) } private fun landInTaverley(player: Player) { @@ -298,14 +330,6 @@ class BalloonFlightInterface : InterfaceListener { } } - private fun getTaverleyCrashLocation(screen: Int): BalloonCrashLocation { - return when (screen) { - 1 -> BalloonCrashLocation.ENTRANA - 2 -> BalloonCrashLocation.OCEAN - else -> BalloonCrashLocation.WOODLAND_FALADOR - } - } - private fun advanceCraftingGuildScreen(player: Player, screen: Int) { when (screen) { 1 -> startCraftingGuildScreen(player, 2, BalloonFlightRoutes.CRAFTING_GUILD_SECOND) @@ -314,13 +338,13 @@ class BalloonFlightInterface : InterfaceListener { } } - private fun startCraftingGuildScreen(player: Player, screen: Int, position: BalloonPosition) { + private fun startCraftingGuildScreen(player: Player, screen: Int, position: BalloonGridPosition) { BalloonFlightScreens.clear(player) BalloonFlightScreens.draw(player, BalloonTravelLocation.CRAFTING_GUILD, screen) setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, screen) setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) - setBalloonPosition(player, position.top, position.bottom) - BalloonFlightScreens.drawBalloon(player, position.top, position.bottom) + setBalloonPosition(player, position) + BalloonFlightScreens.drawBalloon(player, position) } private fun landAtCraftingGuild(player: Player) { @@ -335,14 +359,6 @@ class BalloonFlightInterface : InterfaceListener { } } - private fun getCraftingGuildCrashLocation(screen: Int): BalloonCrashLocation { - return when (screen) { - 1 -> BalloonCrashLocation.ENTRANA - 2 -> BalloonCrashLocation.OCEAN - else -> BalloonCrashLocation.WOODLAND_FALADOR - } - } - private fun advanceVarrockScreen(player: Player, screen: Int) { when (screen) { 1 -> startVarrockScreen(player, 2, BalloonFlightRoutes.VARROCK_SECOND) @@ -351,13 +367,13 @@ class BalloonFlightInterface : InterfaceListener { } } - private fun startVarrockScreen(player: Player, screen: Int, position: BalloonPosition) { + private fun startVarrockScreen(player: Player, screen: Int, position: BalloonGridPosition) { BalloonFlightScreens.clear(player) BalloonFlightScreens.draw(player, BalloonTravelLocation.VARROCK, screen) setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, screen) setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) - setBalloonPosition(player, position.top, position.bottom) - BalloonFlightScreens.drawBalloon(player, position.top, position.bottom) + setBalloonPosition(player, position) + BalloonFlightScreens.drawBalloon(player, position) } private fun landAtVarrock(player: Player) { @@ -372,13 +388,6 @@ class BalloonFlightInterface : InterfaceListener { } } - private fun getVarrockCrashLocation(screen: Int): BalloonCrashLocation { - return when (screen) { - 1 -> BalloonCrashLocation.ENTRANA - else -> BalloonCrashLocation.WOODLAND_FALADOR - } - } - private fun advanceCastleWarsScreen(player: Player, screen: Int) { when (screen) { 1 -> startCastleWarsScreen(player, 2, BalloonFlightRoutes.CASTLE_WARS_SECOND) @@ -387,13 +396,13 @@ class BalloonFlightInterface : InterfaceListener { } } - private fun startCastleWarsScreen(player: Player, screen: Int, position: BalloonPosition) { + private fun startCastleWarsScreen(player: Player, screen: Int, position: BalloonGridPosition) { BalloonFlightScreens.clear(player) BalloonFlightScreens.draw(player, BalloonTravelLocation.CASTLE_WARS, screen) setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, screen) setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) - setBalloonPosition(player, position.top, position.bottom) - BalloonFlightScreens.drawBalloon(player, position.top, position.bottom) + setBalloonPosition(player, position) + BalloonFlightScreens.drawBalloon(player, position) } private fun landAtCastleWars(player: Player) { @@ -408,13 +417,6 @@ class BalloonFlightInterface : InterfaceListener { } } - private fun getCastleWarsCrashLocation(screen: Int): BalloonCrashLocation { - return when (screen) { - 1, 2 -> BalloonCrashLocation.OCEAN - else -> BalloonCrashLocation.WOODLAND_ARDOUGNE - } - } - private fun advanceGrandTreeScreen(player: Player, screen: Int) { when (screen) { 1 -> startGrandTreeScreen(player, 2, BalloonFlightRoutes.GRAND_TREE_SECOND) @@ -423,13 +425,13 @@ class BalloonFlightInterface : InterfaceListener { } } - private fun startGrandTreeScreen(player: Player, screen: Int, position: BalloonPosition) { + private fun startGrandTreeScreen(player: Player, screen: Int, position: BalloonGridPosition) { BalloonFlightScreens.clear(player) BalloonFlightScreens.draw(player, BalloonTravelLocation.GRAND_TREE, screen) setAttribute(player, ATTRIBUTE_FLIGHT_SCREEN, screen) setAttribute(player, ATTRIBUTE_FLIGHT_PROGRESS, 0) - setBalloonPosition(player, position.top, position.bottom) - BalloonFlightScreens.drawBalloon(player, position.top, position.bottom) + setBalloonPosition(player, position) + BalloonFlightScreens.drawBalloon(player, position) } private fun landAtGrandTree(player: Player) { @@ -444,17 +446,10 @@ class BalloonFlightInterface : InterfaceListener { } } - private fun getGrandTreeCrashLocation(screen: Int): BalloonCrashLocation { - return when (screen) { - 1 -> BalloonCrashLocation.OCEAN - else -> BalloonCrashLocation.WOODLAND_ARDOUGNE - } - } - private fun clearFlightAttributes(player: Player) { removeAttributes( - player, ATTRIBUTE_BALLOON_TOP, - ATTRIBUTE_BALLOON_BOTTOM, + player, ATTRIBUTE_BALLOON_ROW, + ATTRIBUTE_BALLOON_COLUMN, ATTRIBUTE_FLIGHT_DESTINATION, ATTRIBUTE_FLIGHT_SCREEN, ATTRIBUTE_FLIGHT_PROGRESS @@ -511,7 +506,7 @@ class BalloonFlightInterface : InterfaceListener { openSingleTab(player, BALLOON_CONTROL_INTERFACE_471) BalloonFlightScreens.clear(player) drawFlightScreen(player, destination, screen) - BalloonFlightScreens.drawBalloon(player, startPosition.top, startPosition.bottom) + BalloonFlightScreens.drawBalloon(player, startPosition) openOverlay(player, 333) true } @@ -526,7 +521,7 @@ class BalloonFlightInterface : InterfaceListener { } on(BALLOON_CONTROL_INTERFACE_471) { player, _, _, buttonId, _, _ -> - handleRouteButton(player, buttonId) + handleControlButton(player, buttonId) true } } diff --git a/Server/src/main/content/global/travel/balloon/BalloonFlightRoutes.kt b/Server/src/main/content/global/travel/balloon/BalloonFlightRoutes.kt index 0a688f1c3..7bea83a6a 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonFlightRoutes.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonFlightRoutes.kt @@ -7,8 +7,6 @@ import core.game.world.map.Location * @author Edith */ -data class BalloonPosition(val top: Int, val bottom: Int) - object BalloonFlightRoutes { const val BUTTON_SANDBAG = 4 const val BUTTON_RELAX = 5 @@ -17,26 +15,26 @@ object BalloonFlightRoutes { const val BUTTON_BURN_LOG = 9 const val BUTTON_RED_ROPE = 10 - /** Child slots used by the top and bottom balloon models. */ - val TAVERLEY_START = BalloonPosition(118, 99) - val TAVERLEY_SECOND = BalloonPosition(119, 98) - val TAVERLEY_THIRD = BalloonPosition(179, 159) + /** Balloon starting grid positions for each flight screen. */ + val TAVERLEY_START = BalloonGridPosition(8, 0) + val TAVERLEY_SECOND = BalloonGridPosition(8, 1) + val TAVERLEY_THIRD = BalloonGridPosition(5, 1) - val CRAFTING_GUILD_START = BalloonPosition(178, 158) - val CRAFTING_GUILD_SECOND = BalloonPosition(159, 139) - val CRAFTING_GUILD_THIRD = BalloonPosition(159, 139) + val CRAFTING_GUILD_START = BalloonGridPosition(5, 0) + val CRAFTING_GUILD_SECOND = BalloonGridPosition(6, 1) + val CRAFTING_GUILD_THIRD = BalloonGridPosition(6, 1) - val VARROCK_START = BalloonPosition(138, 118) - val VARROCK_SECOND = BalloonPosition(179, 159) - val VARROCK_THIRD = BalloonPosition(179, 159) + val VARROCK_START = BalloonGridPosition(7, 0) + val VARROCK_SECOND = BalloonGridPosition(5, 1) + val VARROCK_THIRD = BalloonGridPosition(5, 1) - val CASTLE_WARS_START = BalloonPosition(118, 99) - val CASTLE_WARS_SECOND = BalloonPosition(199, 179) - val CASTLE_WARS_THIRD = BalloonPosition(159, 139) + val CASTLE_WARS_START = BalloonGridPosition(8, 0) + val CASTLE_WARS_SECOND = BalloonGridPosition(4, 1) + val CASTLE_WARS_THIRD = BalloonGridPosition(6, 1) - val GRAND_TREE_START = BalloonPosition(178, 158) - val GRAND_TREE_SECOND = BalloonPosition(159, 139) - val GRAND_TREE_THIRD = BalloonPosition(159, 139) + val GRAND_TREE_START = BalloonGridPosition(5, 0) + val GRAND_TREE_SECOND = BalloonGridPosition(6, 1) + val GRAND_TREE_THIRD = BalloonGridPosition(6, 1) /** Player landing locations. */ val TAVERLEY_LANDING = Location.create(2941, 3420, 0) @@ -162,8 +160,8 @@ object BalloonFlightRoutes { } } - /** Gets the starting child slots for the balloon models on the first screen of a route. */ - fun getStartPosition(destination: BalloonTravelLocation): BalloonPosition { + /** Gets the starting grid position for the balloon models on the first screen of a route. */ + fun getStartPosition(destination: BalloonTravelLocation): BalloonGridPosition { return when (destination) { BalloonTravelLocation.TAVERLEY -> TAVERLEY_START BalloonTravelLocation.CRAFTING_GUILD -> CRAFTING_GUILD_START diff --git a/Server/src/main/content/global/travel/balloon/BalloonFlightScreens.kt b/Server/src/main/content/global/travel/balloon/BalloonFlightScreens.kt index 4bff34984..411857a3c 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonFlightScreens.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonFlightScreens.kt @@ -38,20 +38,30 @@ object BalloonFlightScreens { } } - /** Draws the top and bottom balloon models at the given child slots. */ - fun drawBalloon(player: Player, topChild: Int, bottomChild: Int) { + /** Draws the top and bottom balloon models at the given grid position. */ + fun drawBalloon(player: Player, position: BalloonGridPosition) { + val (topChild, bottomChild) = getBalloonChildren(position) ?: return player.packetDispatch.sendModelOnInterface(MODEL_BALLOON_TOP_19517, BALLOON_FLIGHT_INTERFACE_470, topChild, 2576) resetModelAngle(player, topChild) player.packetDispatch.sendModelOnInterface(MODEL_BALLOON_BOTTOM_19518, BALLOON_FLIGHT_INTERFACE_470, bottomChild, 2576) resetModelAngle(player, bottomChild) } - /** Clears the top and bottom balloon models at the given child slots. */ - fun clearBalloon(player: Player, topChild: Int, bottomChild: Int) { + /** Clears the top and bottom balloon models at the given grid position. */ + fun clearBalloon(player: Player, position: BalloonGridPosition) { + val (topChild, bottomChild) = getBalloonChildren(position) ?: return player.packetDispatch.sendModelOnInterface(-1, BALLOON_FLIGHT_INTERFACE_470, topChild, 0) player.packetDispatch.sendModelOnInterface(-1, BALLOON_FLIGHT_INTERFACE_470, bottomChild, 0) } + /** Gets the top and bottom interface children for a balloon grid position. */ + private fun getBalloonChildren(position: BalloonGridPosition): Pair? { + val topPosition = position.copy(row = position.row - 1) + val topChild = BalloonFlightGrid.getGridChild(topPosition) ?: return null + val bottomChild = BalloonFlightGrid.getGridChild(position) ?: return null + return topChild to bottomChild + } + private fun resetModelAngle(player: Player, child: Int) { player.packetDispatch.sendAngleOnInterface(BALLOON_FLIGHT_INTERFACE_470, child, 2576, 0, 0) } diff --git a/Server/src/main/content/global/travel/balloon/OceanCrashSharkPatrol.kt b/Server/src/main/content/global/travel/balloon/OceanCrashSharkPatrol.kt new file mode 100644 index 000000000..0ac049cd3 --- /dev/null +++ b/Server/src/main/content/global/travel/balloon/OceanCrashSharkPatrol.kt @@ -0,0 +1,62 @@ +package content.global.travel.balloon + +import core.api.getAttribute +import core.api.setAttribute +import core.game.node.entity.npc.NPC +import core.game.node.entity.npc.NPCBehavior +import core.game.world.map.Location +import org.rs09.consts.NPCs + +/** + * Makes the sharks in the ocean crash site swim around in a clockwise patrol. + * All three should have their own slightly different route instead of a shared one but honestly I cba. + * @author Edith + */ +class OceanCrashSharkPatrol : NPCBehavior(NPCs.SHARK_5067, NPCs.SHARK_5068, NPCs.SHARK_5069) { + companion object { + private const val ATTRIBUTE_NEXT_WAYPOINT = "balloon_shark_next_waypoint" + + private fun route(vararg coordinates: Pair) = + Array(coordinates.size) { Location.create(coordinates[it].first, coordinates[it].second) } + + private val PATROL_ROUTE = route( + 1799 to 4885, + 1798 to 4886, + 1797 to 4887, + 1797 to 4892, + 1798 to 4893, + 1798 to 4894, + 1799 to 4894, + 1803 to 4894, + 1804 to 4893, + 1805 to 4893, + 1807 to 4893, + 1807 to 4887, + 1806 to 4886, + 1805 to 4885 + ) + } + + override fun onCreation(self: NPC) { + val startingWaypoint = PATROL_ROUTE.indexOf(self.location) + val nextWaypoint = if (startingWaypoint == -1) 0 else (startingWaypoint + 1) % PATROL_ROUTE.size + setAttribute(self, ATTRIBUTE_NEXT_WAYPOINT, nextWaypoint) + } + + override fun tick(self: NPC): Boolean { + if (!self.walkingQueue.hasPath()) { + var nextWaypoint = getAttribute(self, ATTRIBUTE_NEXT_WAYPOINT, 0) + + if (self.location == PATROL_ROUTE[nextWaypoint]) { + nextWaypoint = (nextWaypoint + 1) % PATROL_ROUTE.size + setAttribute(self, ATTRIBUTE_NEXT_WAYPOINT, nextWaypoint) + } + + val destination = PATROL_ROUTE[nextWaypoint] + self.walkingQueue.reset() + self.walkingQueue.addPath(destination.x, destination.y) + } + + return false + } +} \ No newline at end of file From 63af11240a02c3a34a65e95e7897a2670c44fc2b Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Fri, 10 Jul 2026 16:20:19 +0200 Subject: [PATCH 10/14] sound overhaul for origami & balloon minigame --- .../travel/balloon/BalloonFlightInterface.kt | 31 +++++++++---------- .../quest/EnlightenedJourneyListeners.kt | 6 ++++ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt index ef5bb1197..47ff84faa 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonFlightInterface.kt @@ -66,15 +66,13 @@ class BalloonFlightInterface : InterfaceListener { private const val STARTING_SANDBAGS = 8 private const val STARTING_LOGS = 10 + private const val SOUND_RED_ROPE_3239 = 3239 + private const val SOUND_WIND_3240 = 3240 + private const val SOUND_ROPE_3242 = 3242 + private const val SOUND_BALLOON_MOVE_3246 = 3246 + private const val SOUND_RELAX_3247 = 3247 private const val SOUND_SANDBAG_3249 = 3249 private const val SOUND_BURN_LOG_3251 = 3251 - private const val SOUND_RELAX_3247 = 3247 - private const val SOUND_ROPE_3242 = 3242 - private const val SOUND_RED_ROPE_3239 = 3239 - // cant find source material for using these two: - // zep_construct=3248 - // zep_hammering_1=3250 - private const val MUSIC_FLOATING_FREE_206 = 206 @@ -250,7 +248,7 @@ class BalloonFlightInterface : InterfaceListener { return } - playControlSound(player, buttonId) + playControlSounds(player, buttonId) if (!moveBalloon(player, move)) { return } @@ -456,16 +454,17 @@ class BalloonFlightInterface : InterfaceListener { ) } - private fun playControlSound(player: Player, buttonId: Int) { - val sound = when (buttonId) { - BalloonFlightRoutes.BUTTON_SANDBAG -> SOUND_SANDBAG_3249 - BalloonFlightRoutes.BUTTON_BURN_LOG -> SOUND_BURN_LOG_3251 - BalloonFlightRoutes.BUTTON_RELAX -> SOUND_RELAX_3247 - BalloonFlightRoutes.BUTTON_NORMAL_ROPE -> SOUND_ROPE_3242 - BalloonFlightRoutes.BUTTON_RED_ROPE -> SOUND_RED_ROPE_3239 + private fun playControlSounds(player: Player, buttonId: Int) { + val sounds = when (buttonId) { + BalloonFlightRoutes.BUTTON_SANDBAG -> intArrayOf(SOUND_SANDBAG_3249) + BalloonFlightRoutes.BUTTON_BURN_LOG -> intArrayOf(SOUND_BURN_LOG_3251) + BalloonFlightRoutes.BUTTON_RELAX -> intArrayOf(SOUND_BALLOON_MOVE_3246, SOUND_RELAX_3247) + BalloonFlightRoutes.BUTTON_NORMAL_ROPE -> intArrayOf(SOUND_ROPE_3242, SOUND_WIND_3240) + BalloonFlightRoutes.BUTTON_RED_ROPE -> intArrayOf(SOUND_RED_ROPE_3239) else -> return } - playAudio(player, sound) + + sounds.forEach { playAudio(player, it) } } private fun hideMinimap(player: Player) { diff --git a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt index 9260e55ba..13f7e2c79 100644 --- a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/quest/EnlightenedJourneyListeners.kt @@ -10,6 +10,7 @@ import core.api.animate import core.api.freeSlots import core.api.getQuestStage import core.api.openDialogue +import core.api.playAudio import core.api.removeItem import core.api.rewardXP import core.api.sendMessage @@ -32,6 +33,9 @@ import org.rs09.consts.Scenery */ class EnlightenedJourneyListeners : InteractionListener, MapArea { + companion object { + private const val SOUND_CONSTRUCT_3248 = 3248 + } override fun defineListeners() { /** Make balloon structure. */ @@ -45,6 +49,7 @@ class EnlightenedJourneyListeners : InteractionListener, MapArea { removeItem(player, Item(Items.PAPYRUS_970, 1)) removeItem(player, Item(Items.BALL_OF_WOOL_1759, 1)) addItem(player, Items.BALLOON_STRUCTURE_9933, 1) + playAudio(player, SOUND_CONSTRUCT_3248) sendMessage(player, "You create the origami balloon structure.") } return@onUseWith true @@ -61,6 +66,7 @@ class EnlightenedJourneyListeners : InteractionListener, MapArea { removeItem(player, Item(Items.CANDLE_36, 1)) removeItem(player, Item(Items.BALLOON_STRUCTURE_9933, 1)) addItem(player, Items.ORIGAMI_BALLOON_9934, 1) + playAudio(player, SOUND_CONSTRUCT_3248) rewardXP(player, Skills.CRAFTING, 35.0) sendMessage(player, "You create an origami balloon.") } From 7f1b1ef685b61e45c645d1291aa941c2e0e26340 Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Fri, 10 Jul 2026 19:22:28 +0200 Subject: [PATCH 11/14] Total cutscene overhaul --- .../cutscene/BalloonConstructionCutscene.kt | 31 +++--- .../cutscene/BalloonExperimentCutscene.kt | 79 +++++++++----- .../SecondBalloonExperimentCutscene.kt | 103 ++++++++++++------ 3 files changed, 137 insertions(+), 76 deletions(-) diff --git a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt index b75efabae..65f4caf07 100644 --- a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonConstructionCutscene.kt @@ -20,44 +20,47 @@ import org.rs09.consts.NPCs */ class BalloonConstructionCutscene(player: Player) : Cutscene(player) { + companion object { + private const val REGION_ENTRANA_11060 = 11060 + private const val JINGLE_A_HOT_AIR_JOURNEY_116 = 116 + } + override fun setup() { setExit(Location.create(player.location)) - loadRegion(11060) - addNPC(NPCs.AUGUSTE_5049, 57, 26, Direction.WEST) + loadRegion(REGION_ENTRANA_11060) } override fun runStage(stage: Int) { when (stage) { 0 -> { fadeToBlack() - timedUpdate(6) + timedUpdate(5) } 1 -> { teleport(player, 56, 26, 0) - moveCamera(41, 25, 2000) - rotateCamera(56, 27) - val obj = getObject(55, 26)!! - face(player, obj.location) - fadeFromBlack() - playJingle(player, 116) + face(player, base.transform(55, 26, 0)) + addNPC(NPCs.AUGUSTE_5049, 57, 27, Direction.SOUTH) + moveCamera(48, 25, 1100) + rotateCamera(60, 31) setVarbit(player, VARBIT_ENTRANA_BALLOON_2867, ENTRANA_BALLOON_COMPLETE_2, true) timedUpdate(5) } 2 -> { + fadeFromBlack() move(getNPC(NPCs.AUGUSTE_5049)!!, 56, 27) - timedUpdate(1) + timedUpdate(2) } 3 -> { - moveCamera(39, 25, 200, 2) - timedUpdate(3) + playJingle(player, JINGLE_A_HOT_AIR_JOURNEY_116) + timedUpdate(2) } 4 -> { - moveCamera(38, 24, 2000, 2) - timedUpdate(3) + moveCamera(39, 20, 2000, 8) + timedUpdate(6) } 5 -> { diff --git a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt index f7e8ef402..5aa7276bb 100644 --- a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/BalloonExperimentCutscene.kt @@ -3,6 +3,7 @@ package content.region.misc.entrana.quest.enlightenedjourney.cutscene import content.data.Quests import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_FIRST_EXPERIMENT import core.api.face +import core.api.playAudio import core.api.playJingle import core.api.setQuestStage import core.api.visualize @@ -20,69 +21,95 @@ import org.rs09.consts.NPCs */ class BalloonExperimentCutscene(player: Player) : Cutscene(player) { + companion object { + private const val REGION_ENTRANA_11060 = 11060 + private const val JINGLE_A_HOT_AIR_JOURNEY_116 = 116 + private const val SOUND_ORIGAMI_BALLOON_BURNS_3243 = 3243 + private const val SOUND_RELEASE_BALLOON_3245 = 3245 + private const val ANIMATION_RELEASE_ORIGAMI_BALLOON_5142 = 5142 + private const val GRAPHIC_RELEASE_ORIGAMI_BALLOON_880 = 880 + private const val GRAPHIC_FLYING_ORIGAMI_BALLOON_882 = 882 + } + override fun setup() { setExit(Location.create(player.location)) - loadRegion(11060) + loadRegion(REGION_ENTRANA_11060) } override fun runStage(stage: Int) { when (stage) { 0 -> { fadeToBlack() - timedUpdate(6) + timedUpdate(5) } 1 -> { teleport(player, 56, 27, 0) - face(player, Location.create(440, 25, 0)) - moveCamera(58, 30, 350) - rotateCamera(54, 18, 400) + face(player, base.transform(56, 25, 0)) addNPC(NPCs.AUGUSTE_5049, 57, 27, Direction.SOUTH_WEST) - fadeFromBlack() - playJingle(player, 116) - timedUpdate(6) + moveCamera(58, 30, 400) + rotateCamera(50, 6) + timedUpdate(5) } 2 -> { - visualize(player, 5142, 877) + fadeFromBlack() timedUpdate(2) } 3 -> { - Projectile - .create(player, null, 879, 45, 45, 1, 70, 0) - .transform( - player, - player.location.transform(Direction.SOUTH, player.direction.ordinal + 1), - false, - 70, - 140 - ) - .send() + visualize(player, ANIMATION_RELEASE_ORIGAMI_BALLOON_5142, GRAPHIC_RELEASE_ORIGAMI_BALLOON_880) + playAudio(player, SOUND_RELEASE_BALLOON_3245) + playJingle(player, JINGLE_A_HOT_AIR_JOURNEY_116) timedUpdate(3) } 4 -> { - moveCamera(63, 29, 600) - rotateCamera(55, 23, 600) - timedUpdate(3) + val origamiBalloonStart = base.transform(56, 26, 0) + val origamiBalloonEnd = base.transform(56, 21, 0) + + Projectile + .create( + origamiBalloonStart, + origamiBalloonEnd, + GRAPHIC_FLYING_ORIGAMI_BALLOON_882, + 0, + 50, + 0, + 250, + 0, + 0 + ) + .send() + + moveCamera(63, 22, 500, 8) + rotateCamera(47, 26, speed = 8) + timedUpdate(7) } 5 -> { - face(getNPC(NPCs.AUGUSTE_5049)!!, player, 2) - face(player, getNPC(NPCs.AUGUSTE_5049)!!, 2) - timedUpdate(2) + face(player, getNPC(NPCs.AUGUSTE_5049)!!) + dialogueUpdate(NPCs.AUGUSTE_5049, FacialExpression.HAPPY, "That was perfect. My hypothesis was right!") + timedUpdate(1) + } + + 6 -> { + playAudio(player, SOUND_ORIGAMI_BALLOON_BURNS_3243) + face(getNPC(NPCs.AUGUSTE_5049)!!, player) } - 6 -> dialogueUpdate(NPCs.AUGUSTE_5049, FacialExpression.HAPPY, "That was perfect. My hypothesis was right!") 7 -> playerDialogueUpdate(FacialExpression.HALF_WORRIED, "Did you not see the burning?") + 8 -> dialogueUpdate(NPCs.AUGUSTE_5049, FacialExpression.HAPPY, "One more test. Then we shall proceed.") + 9 -> playerDialogueUpdate(FacialExpression.HALF_WORRIED, "Burning? Fire? Hello?") + 10 -> dialogueUpdate( NPCs.AUGUSTE_5049, FacialExpression.HAPPY, "We shall meekly go! No...no...it needs to sound grander. We shall cautiously go..." ) + 11 -> playerDialogueUpdate(FacialExpression.HALF_WORRIED, "We're doomed.") 12 -> { diff --git a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt index 49151dcab..64955fd67 100644 --- a/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt +++ b/Server/src/main/content/region/misc/entrana/quest/enlightenedjourney/cutscene/SecondBalloonExperimentCutscene.kt @@ -4,8 +4,10 @@ import content.data.Quests import content.region.misc.entrana.quest.enlightenedjourney.quest.EnlightenedJourney.Companion.STAGE_SECOND_EXPERIMENT import core.api.animate import core.api.face +import core.api.playAudio import core.api.playJingle import core.api.sendChat +import core.api.sendGraphics import core.api.setQuestStage import core.api.visualize import core.game.activity.Cutscene @@ -14,6 +16,7 @@ import core.game.node.entity.impl.Projectile import core.game.node.entity.player.Player import core.game.world.map.Direction import core.game.world.map.Location +import core.game.world.update.flag.context.Graphics import org.rs09.consts.NPCs /** @@ -22,85 +25,113 @@ import org.rs09.consts.NPCs */ class SecondBalloonExperimentCutscene(player: Player) : Cutscene(player) { + companion object { + private const val REGION_ENTRANA_11060 = 11060 + private const val JINGLE_A_HOT_AIR_JOURNEY_116 = 116 + private const val SOUND_ORIGAMI_BALLOON_BURNS_3243 = 3243 + private const val SOUND_RELEASE_BALLOON_3245 = 3245 + private const val ANIMATION_RELEASE_ORIGAMI_BALLOON_5142 = 5142 + private const val GRAPHIC_RELEASE_BIGGER_ORIGAMI_BALLOON_877 = 877 + private const val GRAPHIC_FLYING_BIGGER_ORIGAMI_BALLOON_878 = 878 + private const val GRAPHIC_BURNING_BIGGER_ORIGAMI_BALLOON_879 = 879 + } override fun setup() { setExit(Location.create(player.location)) - loadRegion(11060) + loadRegion(REGION_ENTRANA_11060) } override fun runStage(stage: Int) { when (stage) { 0 -> { fadeToBlack() - timedUpdate(6) + timedUpdate(5) } 1 -> { teleport(player, 56, 27, 0) - face(player, Location.create(440, 25, 0)) - moveCamera(58, 30, 350) - rotateCamera(54, 18, 400) + face(player, base.transform(56, 28, 0)) addNPC(NPCs.AUGUSTE_5049, 57, 27, Direction.SOUTH_WEST) - fadeFromBlack() - playJingle(player, 116) - timedUpdate(6) + moveCamera(58, 30, 400) + rotateCamera(50, 6) + timedUpdate(5) } 2 -> { - visualize(player, 5142, 877) + fadeFromBlack() timedUpdate(2) } 3 -> { - Projectile - .create(player, null, 879, 45, 45, 1, 70, 0) - .transform( - player, - player.location.transform(Direction.SOUTH, player.direction.ordinal + 1), - false, - 70, - 140 - ) - .send() + face(player, base.transform(56, 26, 0)) + visualize(player, ANIMATION_RELEASE_ORIGAMI_BALLOON_5142, GRAPHIC_RELEASE_BIGGER_ORIGAMI_BALLOON_877) + playAudio(player, SOUND_RELEASE_BALLOON_3245) + playJingle(player, JINGLE_A_HOT_AIR_JOURNEY_116) timedUpdate(3) } 4 -> { - addNPC(NPCs.BOB_5058, 58, 23, Direction.WEST) - addNPC(NPCs.CURLY_5059, 59, 24, Direction.WEST) - addNPC(NPCs.MOE_5060, 60, 23, Direction.WEST) - addNPC(NPCs.LARRY_5061, 59, 22, Direction.WEST) - moveCamera(63, 23, 600) - rotateCamera(57, 24, 400, 1000) - timedUpdate(4) + val origamiBalloonStart = base.transform(56, 27, 0) + val origamiBalloonEnd = base.transform(56, 21, 0) + + Projectile + .create( + origamiBalloonStart, + origamiBalloonEnd, + GRAPHIC_FLYING_BIGGER_ORIGAMI_BALLOON_878, + 50, + 50, + 0, + 250, + 0, + 0 + ) + .send() + + moveCamera(63, 22, 550, 8) + rotateCamera(47, 26, speed = 8) + addNPC(NPCs.BOB_5058, 60, 22, Direction.WEST) + addNPC(NPCs.CURLY_5059, 61, 23, Direction.WEST) + addNPC(NPCs.MOE_5060, 62, 22, Direction.WEST) + addNPC(NPCs.LARRY_5061, 61, 21, Direction.WEST) + timedUpdate(3) } 5 -> { - move(getNPC(NPCs.BOB_5058)!!, 53, 23) - move(getNPC(NPCs.CURLY_5059)!!, 53, 24) - move(getNPC(NPCs.MOE_5060)!!, 54, 23) - move(getNPC(NPCs.LARRY_5061)!!, 53, 22) - sendChat(getNPC(NPCs.BOB_5058)!!, "Destroy the floating thing!") + move(getNPC(NPCs.BOB_5058)!!, 53, 22) + move(getNPC(NPCs.CURLY_5059)!!, 54, 23) + move(getNPC(NPCs.MOE_5060)!!, 55, 22) + move(getNPC(NPCs.LARRY_5061)!!, 54, 21) timedUpdate(5) } 6 -> { - moveCamera(56, 23, 400, 1000) - rotateCamera(56, 27, 200, 1000) - timedUpdate(1) + sendChat(getNPC(NPCs.BOB_5058)!!, "Destroy the floating thing!") + sendGraphics( + Graphics(GRAPHIC_BURNING_BIGGER_ORIGAMI_BALLOON_879, 200, 0), + base.transform(56, 21, 0) + ) + playAudio(player, SOUND_ORIGAMI_BALLOON_BURNS_3243) + timedUpdate(3) } 7 -> { + moveCamera(56, 23, 450) + rotateCamera(57, 32) + timedUpdate(1) + } + + 8 -> { animate(player, 2113) playerDialogueUpdate(FacialExpression.NEUTRAL, "Well, that went down like a lead balloon.") } - 8 -> { + 9 -> { fadeToBlack() timedUpdate(3) } - 9 -> { + 10 -> { endWithoutFade { fadeFromBlack() setQuestStage(player, Quests.ENLIGHTENED_JOURNEY, STAGE_SECOND_EXPERIMENT) From c52948489f996315efb7f14e78fb5e372e5d52d7 Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Sun, 26 Jul 2026 07:54:39 +0200 Subject: [PATCH 12/14] jingle and dialogue box added --- .../travel/balloon/BalloonTravelInterface.kt | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt index 81bfd59d5..d006b3261 100644 --- a/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt +++ b/Server/src/main/content/global/travel/balloon/BalloonTravelInterface.kt @@ -16,9 +16,11 @@ import core.api.isQuestComplete import core.api.lock import core.api.openDialogue import core.api.openInterface +import core.api.playJingle import core.api.queueScript import core.api.removeItem import core.api.rewardXP +import core.api.sendDialogue import core.api.sendMessage import core.api.setAttribute import core.api.setComponentVisibility @@ -27,6 +29,7 @@ import core.api.stopExecuting import core.api.teleport import core.api.unlock import core.cache.def.impl.ItemDefinition +import core.game.dialogue.DialogueFile import core.game.interaction.IntType import core.game.interaction.InteractionListener import core.game.interaction.InterfaceListener @@ -77,6 +80,7 @@ private val BALLOON_BASKET_LOCS = intArrayOf(19128, 19129) class BalloonTravelInterface : InterfaceListener, InteractionListener { companion object { + private const val JINGLE_A_HOT_AIR_JOURNEY_118 = 118 private const val BALLOON_MAP_INTERFACE_469 = 469 private const val BALLOON_MAP_MODEL_12 = 12 @@ -160,6 +164,7 @@ class BalloonTravelInterface : InterfaceListener, InteractionListener { val duration = animationDuration(Animation(animation)) lock(player, duration) + playJingle(player, JINGLE_A_HOT_AIR_JOURNEY_118) setComponentVisibility(player, BALLOON_MAP_INTERFACE_469, start.mapComponent, true) setComponentVisibility(player, BALLOON_MAP_INTERFACE_469, BALLOON_MAP_MODEL_12, false) animateInterface(player, BALLOON_MAP_INTERFACE_469, BALLOON_MAP_MODEL_12, animation) @@ -182,9 +187,8 @@ class BalloonTravelInterface : InterfaceListener, InteractionListener { } private fun unlockRoute(player: Player, destination: BalloonTravelLocation) { - if (removeItem(player, Item(destination.log, destination.unlockLogAmount))) { - BalloonFlightInterface.startUnlockFlight(player, destination) - } + closeInterface(player) + openDialogue(player, BalloonBoardingDialogue(destination)) } fun unlockDestination(player: Player, destination: BalloonTravelLocation) { @@ -396,4 +400,22 @@ enum class BalloonTravelLocation( } } -} \ No newline at end of file +} + +private class BalloonBoardingDialogue(private val destination: BalloonTravelLocation) : DialogueFile() { + override fun handle(componentID: Int, buttonID: Int) { + when (stage) { + 0 -> sendDialogue(player!!, "You board the balloon.").also { stage++ } + + 1 -> { + if (removeItem(player!!, Item(destination.log, destination.unlockLogAmount))) { + end() + BalloonFlightInterface.startUnlockFlight(player!!, destination) + } else { + end() + sendMessage(player!!, "You need some logs to fuel the balloon.") + } + } + } + } +} From aa9e245901e237d975ab12db085ccd0f2e5c1ed7 Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Sun, 26 Jul 2026 07:57:21 +0200 Subject: [PATCH 13/14] use full names even tho they dont fit in zaros --- Server/data/configs/npc_configs.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Server/data/configs/npc_configs.json b/Server/data/configs/npc_configs.json index 014274748..8a470270f 100644 --- a/Server/data/configs/npc_configs.json +++ b/Server/data/configs/npc_configs.json @@ -54872,23 +54872,23 @@ }, { "id": "5062", - "name": "Auguste/Asst. Stan wrapper" + "name": "Auguste/Assistant Stan wrapper" }, { "id": "5063", - "name": "Asst. Marrow wrapper" + "name": "Assistant Marrow wrapper" }, { "id": "5064", - "name": "Asst. Le Smith wrapper" + "name": "Assistant Le Smith wrapper" }, { "id": "5065", - "name": "Asst. Brock wrapper" + "name": "Assistant Brock wrapper" }, { "id": "5066", - "name": "Asst. Serf wrapper" + "name": "Assistant Serf wrapper" }, { "id": "5067", From f2e794b6c7ed1cd21251cced4aaf638ba3f93055 Mon Sep 17 00:00:00 2001 From: psyopcutie Date: Wed, 29 Jul 2026 11:43:09 +0200 Subject: [PATCH 14/14] move jingles command to other branch --- .../system/command/sets/AudioCommandSet.kt | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/Server/src/main/core/game/system/command/sets/AudioCommandSet.kt b/Server/src/main/core/game/system/command/sets/AudioCommandSet.kt index 0c4217b69..e5a4fb522 100644 --- a/Server/src/main/core/game/system/command/sets/AudioCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/AudioCommandSet.kt @@ -48,29 +48,6 @@ class MusicCommandSet : CommandSet(Privilege.STANDARD){ notify(player,"Now playing jingle $id") } - define("jingles", Privilege.ADMIN, "::jingles From Jingle ID To Jingle ID (opt) Duration Per Jingle", "Plays jingles from the From ID to the To ID, with a delay of 5 between each, unless specified otherwise") { player, args -> - - if (args.size < 3) { - reject(player, "Syntax error: ::jingles <(opt) Duration Per Jingle>") - return@define - } - val jingleFrom = args[1].toInt() - val jingleTo = args[2].toInt() - val jingleDelay = (args.getOrNull(3) ?: "5").toInt() - - queueScript(player, 1, QueueStrength.WEAK) { stage: Int -> - val jingleId = jingleFrom + stage - PacketRepository.send(MusicPacket::class.java, MusicContext(player, jingleId, true)) - notify(player, "Now playing jingle $jingleId") - - if (jingleId == jingleTo) { - return@queueScript stopExecuting(player) - } - - return@queueScript delayScript(player, jingleDelay) - } - } - /** * Command that lets you play a song via the ID instead of the song name * this is mostly useful for custom tracks that aren't in the ingame