summaryrefslogtreecommitdiff
path: root/src/q_fireprof.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/q_fireprof.cc')
-rw-r--r--src/q_fireprof.cc577
1 files changed, 577 insertions, 0 deletions
diff --git a/src/q_fireprof.cc b/src/q_fireprof.cc
new file mode 100644
index 00000000..021cf2fb
--- /dev/null
+++ b/src/q_fireprof.cc
@@ -0,0 +1,577 @@
+#include "q_fireprof.hpp"
+
+#include "cave_type.hpp"
+#include "feature_type.hpp"
+#include "hook_get_in.hpp"
+#include "hooks.hpp"
+#include "lua_bind.hpp"
+#include "object1.hpp"
+#include "object2.hpp"
+#include "object_type.hpp"
+#include "player_type.hpp"
+#include "quark.hpp"
+#include "tables.hpp"
+#include "traps.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+
+#define cquest (quest[QUEST_FIREPROOF])
+
+#define print_hook(fmt,...) do { fprintf(hook_file, fmt, ##__VA_ARGS__); } while (0)
+
+/*
+ * Per-module "settings"
+ */
+typedef struct fireproof_settings fireproof_settings;
+struct fireproof_settings
+{
+ byte tval; /* tval of object to use. */
+ cptr tval_name; /* descriptive name of tval */
+ cptr tval_name_plural; /* descriptive name of tval (plural) */
+ byte sval_max; /* max sval of object to use; sval will be 1<=X<=sval_max. */
+ s32b total_points; /* total number of points awarded */
+};
+
+static fireproof_settings const *fireproof_get_settings()
+{
+ static fireproof_settings fireproof_settings =
+ { TV_RUNE2, "rune", "runes", 5, 24 };
+ return &fireproof_settings;
+}
+
+/* These constants are how many 'points' each type of item will take
+ * up. So currently, you can fireproof 3 books, 4 staves or 12
+ * scrolls. */
+#define FIREPROOF_BOOK_POINTS 4
+#define FIREPROOF_STAFF_POINTS 3
+#define FIREPROOF_SCROLL_POINTS 1
+
+static s32b get_item_points_remaining()
+{
+ fireproof_settings const *settings = fireproof_get_settings();
+ return settings->total_points - cquest.data[0];
+}
+
+static void set_item_points_remaining(s32b v)
+{
+ fireproof_settings const *settings = fireproof_get_settings();
+ cquest.data[0] = settings->total_points - v;
+}
+
+static void fireproof_set_sval(int sval_max)
+{
+ cquest.data[1] = sval_max;
+}
+
+static int fireproof_get_sval()
+{
+ return cquest.data[1];
+}
+
+static bool item_tester_hook_eligible(object_type const *o_ptr)
+{
+ /* check it's the 'marked' item */
+ return ((o_ptr->tval == fireproof_get_settings()->tval) &&
+ (o_ptr->sval == fireproof_get_sval()) &&
+ (o_ptr->pval2 == fireproof_get_sval()));
+}
+
+static object_filter_t const &item_tester_hook_proofable()
+{
+ using namespace object_filter;
+ static auto instance = And(
+ // Must be the correct item base type
+ Or(
+ TVal(TV_BOOK),
+ TVal(TV_SCROLL),
+ TVal(TV_STAFF)),
+ // Must NOT already be fireproof
+ Not(
+ HasFlag3(TR3_IGNORE_FIRE)));
+ return instance;
+}
+
+/*
+ * This function makes sure the player has enough 'points' left to fireproof stuff.
+ */
+static bool_ fireproof_enough_points(object_type *o_ptr, int *stack)
+{
+ int item_value;
+
+ /* are the items in a stack? */
+ if (o_ptr->number > 1)
+ {
+ /* how many to fireproof? */
+ *stack = get_quantity("How many would you like fireproofed?", o_ptr->number);
+ }
+ else
+ {
+ *stack = 1;
+ }
+
+ /* check for item type and multiply number in the stack by the
+ * amount of points per item of that type */
+ switch (o_ptr->tval)
+ {
+ case TV_BOOK:
+ item_value = FIREPROOF_BOOK_POINTS * (*stack);
+ break;
+ case TV_STAFF:
+ item_value = FIREPROOF_STAFF_POINTS * (*stack);
+ break;
+ case TV_SCROLL:
+ item_value = FIREPROOF_SCROLL_POINTS * (*stack);
+ break;
+ default:
+ assert(FALSE);
+ }
+
+ /* do we have enough points? */
+ if (item_value > get_item_points_remaining())
+ {
+ msg_print("I do not have enough fireproofing material for that.");
+ return FALSE;
+ }
+ else
+ {
+ /* if so then subtract those points before we do the fireproofing */
+ set_item_points_remaining(get_item_points_remaining() - item_value);
+ }
+
+ /* Used all the points? the quest is completely rewarded. */
+ if (get_item_points_remaining() == 0)
+ {
+ cquest.status = QUEST_STATUS_REWARDED;
+ }
+
+ return TRUE;
+}
+
+static bool_ fireproof()
+{
+ int item;
+ if (!get_item(&item,
+ "Which item shall I fireproof?",
+ "You have no more items I can fireproof, come back when you have some.",
+ USE_INVEN,
+ item_tester_hook_proofable()))
+ {
+ return FALSE;
+ }
+
+ /* get the object type from the number */
+ object_type *obj2 = get_object(item);
+
+ /* check we have enough points (if we 'got' an item) */
+ int stack = 0;
+ if (!fireproof_enough_points(obj2, &stack))
+ {
+ return FALSE;
+ }
+
+ /* Do the actual fireproofing */
+ {
+ bool_ carry_it;
+ object_type *obj3;
+ object_type obj_forge;
+ s32b oldpval, oldpval2, oldpval3;
+
+ /* are we part of the items from a stack? */
+ if (obj2->number != stack) {
+
+ /* make a new object to handle */
+ object_copy(&obj_forge, obj2);
+
+ /* give it the right number of items */
+ obj_forge.number = stack;
+
+ /* adjust for number of items in pack not to be fireproofed */
+ obj2->number = obj2->number - stack;
+ obj3 = &obj_forge;
+
+ /* we'll need to add this to the inventory after fireproofing */
+ carry_it = TRUE;
+ }
+ else
+ {
+ /* use the whole stack */
+ obj3 = obj2;
+
+ /* we'll be dealing this while it's still in the inventory */
+ carry_it = FALSE;
+ }
+
+ /* make it fireproof */
+ obj3->name2 = 149;
+
+ /* apply it, making sure the pvals don't change with
+ * apply_magic (it would change the type of book!) */
+ oldpval = obj3->pval;
+ oldpval2 = obj3->pval2;
+ oldpval3 = obj3->pval3;
+ apply_magic(obj3, -1, FALSE, FALSE, FALSE);
+ obj3->pval = oldpval;
+ obj3->pval2 = oldpval2;
+ obj3->pval3 = oldpval3;
+
+ /* put it in the inventory if it's only part of a stack */
+ if (carry_it == TRUE)
+ {
+ inven_carry(obj3, TRUE);
+ }
+
+ /* id and notice it */
+ object_known(obj3);
+ object_aware(obj3);
+
+ return TRUE;
+ }
+}
+
+
+void quest_fireproof_building(bool_ *paid, bool_ *recreate)
+{
+ fireproof_settings const *settings = fireproof_get_settings();
+ int num_books, num_staff, num_scroll;
+
+ num_books = get_item_points_remaining() / FIREPROOF_BOOK_POINTS;
+ num_staff = get_item_points_remaining() / FIREPROOF_STAFF_POINTS;
+ num_scroll = get_item_points_remaining() / FIREPROOF_SCROLL_POINTS;
+
+ /* the quest hasn't been requested already, right? */
+ if (cquest.status == QUEST_STATUS_UNTAKEN)
+ {
+ /* quest has been taken now */
+ cquest.status = QUEST_STATUS_TAKEN;
+
+ /* issue instructions */
+ msg_format("I need a very special %s for a spell I am"
+ " working on. I am too old to ", settings->tval_name);
+ msg_print("fetch it myself. Please bring it back to me. You can find it north of here.");
+ msg_print("Be careful with it, it's fragile and might be destroyed easily.");
+
+ *paid = FALSE;
+ *recreate = TRUE;
+ }
+
+ /* if quest completed (item was retrieved) */
+ else if (cquest.status == QUEST_STATUS_COMPLETED)
+ {
+ char p[512];
+ char pni[512];
+ int item_idx;
+ int ret;
+
+ /* generate prompt strings */
+ snprintf(p , sizeof(p) , "Which %s?", settings->tval_name);
+ snprintf(pni, sizeof(pni), "You have no %s to return", settings->tval_name_plural);
+
+ /* ask for item */
+ ret = get_item(&item_idx, p, pni, USE_INVEN, item_tester_hook_eligible);
+
+ /* didn't get the item? */
+ if (!ret)
+ {
+ return;
+ }
+
+ /* got the item! */
+ else
+ {
+ int items;
+
+ /* take item */
+ inc_stack_size_ex(item_idx, -1, OPTIMIZE, NO_DESCRIBE);
+
+ msg_print(format("Great! Let me fireproof some of your items in thanks. I can do %d books, ", num_books));
+ msg_print(format("%d staves, or %d scrolls.", num_staff, num_scroll));
+
+ /* how many items to proof? */
+ items = get_item_points_remaining();
+
+ /* repeat till up to 3 (value defined as constant) books fireproofed */
+ while (items > 0)
+ {
+ ret = fireproof();
+
+ /* don't loop the fireproof if there's nothing to fireproof */
+ if (ret == FALSE)
+ {
+ break;
+ }
+
+ /* subtract item points */
+ items = get_item_points_remaining();
+ }
+
+ /* have they all been done? */
+ if (get_item_points_remaining() == 0)
+ {
+ /* mark quest to make sure no more quests are given */
+ cquest.status = QUEST_STATUS_REWARDED;
+ }
+ else
+ {
+ /* mark in preparation of anymore books to fireproof */
+ cquest.status = QUEST_STATUS_FINISHED;
+ }
+ }
+ }
+
+ /* if the player asks for a quest when they already have it, but haven't failed it, give them some extra instructions */
+ else if (cquest.status == QUEST_STATUS_TAKEN)
+ {
+ msg_format("The %s is in a cave just behind the shop.",
+ settings->tval_name);
+ }
+
+ /* ok not all books have been fireproofed... lets do the rest */
+ else if (cquest.status == QUEST_STATUS_FINISHED)
+ {
+
+ /* how many books still to proof? */
+ int items = get_item_points_remaining();
+
+ /* repeat as necessary */
+ while (items > 0)
+ {
+ int ret = fireproof();
+
+ /* don't loop the fireproof if there's nothing to fireproof */
+ if (ret == FALSE)
+ {
+ break;
+ }
+ else
+ {
+ /* have they all been done? */
+ if (get_item_points_remaining() == 0)
+ {
+ cquest.status = QUEST_STATUS_REWARDED;
+ }
+ }
+
+ /* subtract item points */
+ items = get_item_points_remaining();
+ }
+
+ }
+
+ /* quest failed or completed, then give no more quests */
+ else if ((cquest.status == QUEST_STATUS_FAILED) ||
+ (cquest.status == QUEST_STATUS_REWARDED))
+ {
+ msg_print("I have no more quests for you");
+ }
+}
+
+static bool_ fireproof_get_hook(void *, void *in_, void *)
+{
+ struct hook_get_in *in = static_cast<struct hook_get_in *>(in_);
+ object_type *o_ptr = in->o_ptr;
+
+ /* check that player is in the quest, haven't picked up the
+ * item already, and check that it's the real item and not another one
+ * generated via random object placement */
+ if ((p_ptr->inside_quest == QUEST_FIREPROOF) &&
+ (cquest.status != QUEST_STATUS_COMPLETED) &&
+ (o_ptr->pval2 == fireproof_get_sval()))
+ {
+ /* ok mark the quest 'completed' */
+ cquest.status = QUEST_STATUS_COMPLETED;
+ cmsg_print(TERM_YELLOW, "Fine! Looks like you've found it.");
+ }
+
+ return FALSE;
+}
+
+static bool_ fireproof_stair_hook(void *, void *, void *)
+{
+ /* only ask this if player about to go up stairs of quest and
+ * hasn't retrieved item */
+ if ((p_ptr->inside_quest != QUEST_FIREPROOF) ||
+ (cquest.status == QUEST_STATUS_COMPLETED))
+ {
+ return FALSE;
+ }
+ else
+ {
+ bool_ ret;
+
+ if (cave[p_ptr->py][p_ptr->px].feat != FEAT_LESS)
+ {
+ return FALSE;
+ }
+
+ /* flush all pending input */
+ flush();
+
+ /* confirm */
+ ret = get_check("Really abandon the quest?");
+
+ /* if yes, then */
+ if (ret == TRUE)
+ {
+ /* fail the quest */
+ cquest.status = QUEST_STATUS_FAILED;
+ return FALSE;
+ }
+ else
+ {
+ /* if no, they stay in the quest */
+ return TRUE;
+ }
+ }
+}
+
+bool_ quest_fireproof_describe(FILE *hook_file)
+{
+ fireproof_settings const *settings = fireproof_get_settings();
+ int num_books, num_staff, num_scroll;
+ int status = cquest.status;
+
+ num_books = get_item_points_remaining() / FIREPROOF_BOOK_POINTS;
+ num_staff = get_item_points_remaining() / FIREPROOF_STAFF_POINTS;
+ num_scroll = get_item_points_remaining() / FIREPROOF_SCROLL_POINTS;
+
+ if (status == QUEST_STATUS_TAKEN)
+ {
+ /* Quest taken */
+ print_hook("#####yAn Old Mages Quest!\n");
+ print_hook("Retrieve the strange %s for the old mage "
+ "in Lothlorien.\n", settings->tval_name);
+ print_hook("\n");
+ }
+ else if (status == QUEST_STATUS_COMPLETED)
+ {
+ /* essence retrieved, not taken to mage */
+ print_hook("#####yAn Old Mages Quest!\n");
+ print_hook("You have retrieved the %s for the old "
+ "mage in Lothlorien. Perhaps you \n", settings->tval_name);
+ print_hook("should see about a reward.\n");
+ print_hook("\n");
+ }
+ else if ((status == QUEST_STATUS_FINISHED) &&
+ (get_item_points_remaining() > 0))
+ {
+ /* essence returned, not all books fireproofed */
+ print_hook("#####yAn Old Mages Quest!\n");
+ print_hook("You have retrieved the %s for the old "
+ "mage in Lothlorien. He will still \n", settings->tval_name);
+ print_hook("fireproof %d book(s) or %d staff/staves "
+ "or %d scroll(s) for you.\n",
+ num_books, num_staff, num_scroll);
+ print_hook("\n");
+ }
+
+ return TRUE;
+}
+
+static bool_ fireproof_gen_hook(void *, void *, void *)
+{
+ fireproof_settings const *settings = fireproof_get_settings();
+
+ /* Only if player doing this quest */
+ if (p_ptr->inside_quest != QUEST_FIREPROOF)
+ {
+ return FALSE;
+ }
+
+ /* Go ahead */
+ {
+ int traps, trap_y, trap_x;
+
+ /* load the map */
+ {
+ int x0 = 2;
+ int y0 = 2;
+ load_map("fireprof.map", &y0, &x0);
+ }
+
+ /* no teleport */
+ dungeon_flags2 = DF2_NO_TELEPORT;
+
+ /* determine type of item */
+ fireproof_set_sval(randint(settings->sval_max));
+
+ /* create essence */
+ {
+ int x, y;
+ object_type forge;
+
+ object_prep(&forge, lookup_kind(settings->tval, fireproof_get_sval()));
+
+ /* mark item */
+ forge.pval2 = fireproof_get_sval();
+ forge.note = quark_add("quest");
+
+ /* roll for co-ordinates in top half of map */
+ y = randint(3) + 2;
+ x = randint(45) + 2;
+
+ /* drop it */
+ drop_near(&forge, -1, y, x);
+ }
+
+ /* how many traps to generate */
+ traps = rand_range(10, 30);
+
+ /* generate the traps */
+ while (traps > 0)
+ {
+ int tries = 0, trap_level = 0;
+
+ /* make sure it's a safe place */
+ while (tries == 0)
+ {
+ /* get grid coordinates */
+ trap_y = randint(19) + 2;
+ trap_x = randint(45) + 2;
+ cave_type *c_ptr = &cave[trap_y][trap_x];
+
+ /* are the coordinates on a stair, or a wall? */
+ if (((f_info[c_ptr->feat].flags1 & FF1_PERMANENT) != 0) ||
+ ((f_info[c_ptr->feat].flags1 & FF1_FLOOR) == 0))
+ {
+ /* try again */
+ tries = 0;
+ }
+ else
+ {
+ /* not a stair, then stop this 'while' */
+ tries = 1;
+ }
+ }
+
+ /* randomise level of trap */
+ trap_level = rand_range(20, 40);
+
+ /* put the trap there */
+ place_trap_leveled(trap_y, trap_x, trap_level);
+
+ /* that's one less trap to place */
+ traps = traps - 1;
+ }
+
+ return TRUE;
+ }
+}
+
+bool_ quest_fireproof_init_hook(int q)
+{
+ /* Only need hooks if the quest is unfinished. */
+ if ((cquest.status >= QUEST_STATUS_UNTAKEN) &&
+ (cquest.status < QUEST_STATUS_FINISHED))
+ {
+ add_hook_new(HOOK_GEN_QUEST, fireproof_gen_hook , "fireproof_gen_hook", NULL);
+ add_hook_new(HOOK_GET , fireproof_get_hook , "fireproof_get_hook", NULL);
+ add_hook_new(HOOK_STAIR , fireproof_stair_hook, "fireproof_stair_hook", NULL);
+ }
+
+ return FALSE;
+}
+
+#undef print_hook