// Quest system #include "src/quests/bat_invasion_game.nvgt" #include "src/quests/catch_the_boomerang_game.nvgt" #include "src/quests/enchanted_melody_game.nvgt" #include "src/quests/escape_from_hel_game.nvgt" #include "src/quests/skeletal_bard_game.nvgt" const int QUEST_BAT_INVASION = 0; const int QUEST_CATCH_BOOMERANG = 1; const int QUEST_ENCHANTED_MELODY = 2; const int QUEST_ESCAPE_FROM_HEL = 3; const int QUEST_SKELETAL_BARD = 4; const int QUEST_TYPE_COUNT = 5; int[] quest_queue; bool quest_roll_done_today = false; string get_quest_name(int quest_type) { if (quest_type == QUEST_BAT_INVASION) return "Bat Invasion"; if (quest_type == QUEST_CATCH_BOOMERANG) return "Catch the Boomerang"; if (quest_type == QUEST_ENCHANTED_MELODY) return "Enchanted Melody"; if (quest_type == QUEST_ESCAPE_FROM_HEL) return "Escape from Hel"; if (quest_type == QUEST_SKELETAL_BARD) return "Skeletal Bard"; return "Unknown Quest"; } string get_quest_description(int quest_type) { if (quest_type == QUEST_BAT_INVASION) { return "Bat Invasion. Giant killer bats are attacking. Press space to throw when the bat is centered."; } if (quest_type == QUEST_CATCH_BOOMERANG) { return "Catch the Boomerang. Throw and catch the boomerang as it returns for up to 4 points."; } if (quest_type == QUEST_ENCHANTED_MELODY) { return "Enchanted Melody. Repeat the pattern using E R D F or U I J K. Lowest to highest pitch."; } if (quest_type == QUEST_ESCAPE_FROM_HEL) { return "Escape from Hel. Press space to jump over open graves. The pace quickens."; } if (quest_type == QUEST_SKELETAL_BARD) { return "Skeletal Bard. A skeleton named Billy Bones is practicing to become a bard. Count the notes."; } return "Unknown quest."; } int get_quest_chance_from_favor() { int chance = int(favor * QUEST_CHANCE_PER_FAVOR); if (chance < QUEST_MIN_CHANCE && favor >= 1.0) chance = QUEST_MIN_CHANCE; if (chance > 100) chance = 100; return chance; } bool quest_menu_background_tick() { return menu_background_tick(); } void quest_boomerang_hit_sound() { play_player_damage_sound(); } void add_quest(int quest_type) { if (quest_queue.length() >= QUEST_MAX_ACTIVE) return; quest_queue.insert_last(quest_type); notify("A new quest is available: " + get_quest_name(quest_type) + "."); } void attempt_daily_quest() { if (quest_roll_done_today) return; if (favor < 1.0) return; if (world_altars.length() == 0) return; if (quest_queue.length() >= QUEST_MAX_ACTIVE) return; quest_roll_done_today = true; int chance = get_quest_chance_from_favor(); int roll = random(1, 100); if (roll > chance) return; int quest_type = random(0, QUEST_TYPE_COUNT - 1); add_quest(quest_type); } void check_quest_menu() { if (key_pressed(KEY_Q)) { if (x > BASE_END) { speak_with_history("You are not in the base.", true); return; } if (quest_queue.length() == 0) { speak_with_history("No quests available.", true); return; } run_quest_menu(); } } string get_quest_favor_phrase(int score) { if (score <= 2) return "The gods are displeased with your performance."; if (score < QUEST_STONE_SCORE) return "The gods are pleased with your performance."; int extreme_threshold = QUEST_LOG_SCORE - 2; if (score < extreme_threshold) return "The gods are very pleased with your performance."; if (score < QUEST_LOG_SCORE) return "The gods are extremely pleased with your performance."; return "The gods are ultimately pleased with your performance."; } void apply_quest_reward(int score) { double favor_gain = score * QUEST_FAVOR_PER_POINT; if (favor_gain < 0) favor_gain = 0; if (favor_gain > 1.0) favor_gain = 1.0; favor += favor_gain; // Determine quantity based on score // <= 2: 0 // 3-5: 1 // 6-7: 2 // 8-9: 3 // >= 10: 4 int quantity = 0; if (score >= QUEST_LOG_SCORE) quantity = 4; else if (score >= QUEST_LOG_SCORE - 2) quantity = 3; else if (score >= QUEST_STONE_SCORE) quantity = 2; else if (score > 2) quantity = 1; // Select reward item int[] possible_rewards = { ITEM_STICKS, ITEM_VINES, ITEM_REEDS, ITEM_STONES, ITEM_LOGS, ITEM_CLAY, ITEM_MEAT, ITEM_SKINS, ITEM_FEATHERS, ITEM_DOWN, ITEM_FISH, ITEM_SMOKED_FISH, ITEM_HEAL_SCROLL, ITEM_INCENSE, ITEM_BASKET_FOOD }; int reward_item = possible_rewards[random(0, possible_rewards.length() - 1)]; int added_amount = 0; if (quantity > 0) { added_amount = add_to_stack(get_personal_count(reward_item), quantity); add_personal_count(reward_item, added_amount); // Special handling for fish which needs weights if (reward_item == ITEM_FISH) { for (int i = 0; i < added_amount; i++) { add_personal_fish_weight(get_default_fish_weight()); } } } string message = "Quest Complete!\n\nRewards:\n"; message += get_quest_favor_phrase(score) + "\n"; message += "Favor: +" + format_favor(favor_gain) + "\n"; if (added_amount > 0) { message += get_item_display_name(reward_item) + ": +" + added_amount + "\n"; } else if (quantity > 0) { message += "Inventory full, could not receive " + get_item_display_name(reward_item) + ".\n"; } else { message += "No items awarded.\n"; } message += "\nScore: " + score; text_reader(message, "Quest Rewards", true); attempt_pet_offer_from_quest(score); } void run_quest(int quest_type) { p.pause_all(); int score = 0; if (quest_type == QUEST_BAT_INVASION) score = run_bat_invasion(); else if (quest_type == QUEST_CATCH_BOOMERANG) score = run_catch_the_boomerang(); else if (quest_type == QUEST_ENCHANTED_MELODY) score = run_enchanted_melody(); else if (quest_type == QUEST_ESCAPE_FROM_HEL) score = run_escape_from_hel(); else if (quest_type == QUEST_SKELETAL_BARD) score = run_skeletal_bard(); if (return_to_main_menu_requested) { p.resume_all(); return; } apply_quest_reward(score); p.resume_all(); } void run_quest_menu() { speak_with_history("Quest menu.", true); int selection = 0; string[] options; for (uint i = 0; i < quest_queue.length(); i++) { options.insert_last(get_quest_name(quest_queue[i])); } while(true) { wait(5); if (menu_background_tick()) { return; } if (key_pressed(KEY_ESCAPE)) { speak_with_history("Closed.", true); break; } string count_str = " " + (selection + 1) + " of " + options.length(); if (key_pressed(KEY_DOWN)) { play_menu_move_sound(); selection++; if (selection >= options.length()) selection = 0; count_str = " " + (selection + 1) + " of " + options.length(); speak_with_history(options[selection] + count_str, true); } if (key_pressed(KEY_UP)) { play_menu_move_sound(); selection--; if (selection < 0) selection = options.length() - 1; count_str = " " + (selection + 1) + " of " + options.length(); speak_with_history(options[selection] + count_str, true); } if (key_pressed(KEY_RETURN)) { play_menu_select_sound(); int quest_type = quest_queue[selection]; quest_queue.remove_at(selection); run_quest(quest_type); break; } } }