summaryrefslogtreecommitdiff
path: root/src/plots.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plots.c')
-rw-r--r--src/plots.c473
1 files changed, 473 insertions, 0 deletions
diff --git a/src/plots.c b/src/plots.c
new file mode 100644
index 00000000..8588a96b
--- /dev/null
+++ b/src/plots.c
@@ -0,0 +1,473 @@
+/* File: plots.c */
+
+/* Purpose: plots & quests */
+
+/*
+ * Copyright (c) 2001 James E. Wilson, Robert A. Koeneke, DarkGod
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "angband.h"
+
+#include "lua/lua.h"
+#include "tolua.h"
+extern lua_State* L;
+
+/* #define DEBUG_HOOK */
+
+/******** Hooks stuff *********/
+FILE *hook_file;
+
+#define MAX_ARGS 50
+
+static hooks_chain *hooks_heads[MAX_HOOKS];
+
+/* Wipe hooks and init them with quest hooks */
+void wipe_hooks()
+{
+ int i;
+
+ for (i = 0; i < MAX_HOOKS; i++)
+ {
+ hooks_heads[i] = NULL;
+ }
+}
+void init_hooks()
+{
+ int i;
+
+ for (i = 0; i < MAX_Q_IDX_INIT; i++)
+ {
+ if ((quest[i].type == HOOK_TYPE_C) && (quest[i].init != NULL)) quest[i].init(i);
+ }
+}
+
+void dump_hooks(int h_idx)
+{
+ int min = 0, max = MAX_HOOKS, i;
+
+ if (h_idx != -1)
+ {
+ min = h_idx;
+ max = h_idx + 1;
+ }
+
+ for (i = min; i < max; i++)
+ {
+ hooks_chain *c = hooks_heads[i];
+
+ /* Find it */
+ while (c != NULL)
+ {
+ msg_format("%s(%s)", c->name, (c->type == HOOK_TYPE_C) ? "C" : "Lua");
+
+ c = c->next;
+ }
+ }
+}
+
+/* Check a hook */
+bool check_hook(int h_idx)
+{
+ hooks_chain *c = hooks_heads[h_idx];
+
+ return (c != NULL);
+}
+
+/* Add a hook */
+hooks_chain* add_hook(int h_idx, hook_type hook, cptr name)
+{
+ hooks_chain *new, *c = hooks_heads[h_idx];
+
+ /* Find it */
+ while ((c != NULL) && (strcmp(c->name, name)))
+ {
+ c = c->next;
+ }
+
+ /* If not already in the list, add it */
+ if (c == NULL)
+ {
+ MAKE(new, hooks_chain);
+ new->hook = hook;
+ sprintf(new->name, name);
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK ADD: %s", name);
+ if (take_notes) add_note(format("HOOK ADD: %s", name), 'D');
+#endif
+ new->next = hooks_heads[h_idx];
+ hooks_heads[h_idx] = new;
+ return (new);
+ }
+ else return (c);
+}
+
+void add_hook_script(int h_idx, char *script, cptr name)
+{
+ hooks_chain *c = add_hook(h_idx, NULL, name);
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK LUA ADD: %s : %s", name, script);
+#endif
+ sprintf(c->script, "%s", script);
+ c->type = HOOK_TYPE_LUA;
+}
+
+/* Remove a hook */
+void del_hook(int h_idx, hook_type hook)
+{
+ hooks_chain *c = hooks_heads[h_idx], *p = NULL;
+
+ /* Find it */
+ while ((c != NULL) && (c->hook != hook))
+ {
+ p = c;
+ c = c->next;
+ }
+
+ /* Remove it */
+ if (c != NULL)
+ {
+ if (p == NULL)
+ {
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK DEL: %s", c->name);
+ if (take_notes) add_note(format("HOOK DEL: %s", c->name), 'D');
+#endif
+ hooks_heads[h_idx] = c->next;
+ FREE(c, hooks_chain);
+ }
+ else
+ {
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK DEL: %s", c->name);
+ if (take_notes) add_note(format("HOOK DEL: %s", c->name), 'D');
+#endif
+ p->next = c->next;
+ FREE(c, hooks_chain);
+ }
+ }
+}
+
+void del_hook_name(int h_idx, cptr name)
+{
+ hooks_chain *c = hooks_heads[h_idx], *p = NULL;
+
+ /* Find it */
+ while ((c != NULL) && (strcmp(c->name, name)))
+ {
+ p = c;
+ c = c->next;
+ }
+
+ /* Remove it */
+ if (c != NULL)
+ {
+ if (p == NULL)
+ {
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK DEL: %s", c->name);
+ if (take_notes) add_note(format("HOOK DEL: %s", c->name), 'D');
+#endif
+ hooks_heads[h_idx] = c->next;
+ FREE(c, hooks_chain);
+ }
+ else
+ {
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK DEL: %s", c->name);
+ if (take_notes) add_note(format("HOOK DEL: %s", c->name), 'D');
+#endif
+ p->next = c->next;
+ FREE(c, hooks_chain);
+ }
+ }
+}
+
+/* get the next argument */
+static hook_return param_pile[MAX_ARGS];
+static int get_next_arg_pos = 0;
+static int get_next_arg_pile_pos = 0;
+s32b get_next_arg(char *fmt)
+{
+ while (TRUE)
+ {
+ switch (fmt[get_next_arg_pos++])
+ {
+ case 'd':
+ case 'l':
+ return (param_pile[get_next_arg_pile_pos++].num);
+ case ')':
+ get_next_arg_pos--;
+ return 0;
+ case '(':
+ case ',':
+ break;
+ }
+ }
+}
+char* get_next_arg_str(char *fmt)
+{
+ while (TRUE)
+ {
+ switch (fmt[get_next_arg_pos++])
+ {
+ case 's':
+ return (char*)(param_pile[get_next_arg_pile_pos++].str);
+ case ')':
+ get_next_arg_pos--;
+ return 0;
+ case '(':
+ case ',':
+ break;
+ }
+ }
+}
+
+/* Actually process the hooks */
+int process_hooks_restart = FALSE;
+hook_return process_hooks_return[20];
+static bool vprocess_hooks_return (int h_idx, char *ret, char *fmt, va_list *ap)
+{
+ hooks_chain *c = hooks_heads[h_idx];
+ va_list real_ap;
+
+ while (c != NULL)
+ {
+#ifdef DEBUG_HOOK
+ if (wizard) cmsg_format(TERM_VIOLET, "HOOK: %s", c->name);
+ if (take_notes) add_note(format("HOOK PROCESS: %s", c->name), 'D');
+#endif
+ if (c->type == HOOK_TYPE_C)
+ {
+ int i = 0, nb = 0;
+
+ /* Push all args in the pile */
+ i = 0;
+ COPY(&real_ap, ap, va_list);
+ while (fmt[i])
+ {
+ switch (fmt[i])
+ {
+ case 'O':
+ param_pile[nb++].o_ptr = va_arg(real_ap, object_type *);
+ break;
+ case 's':
+ param_pile[nb++].str = va_arg(real_ap, char *);
+ break;
+ case 'd':
+ case 'l':
+ param_pile[nb++].num = va_arg(real_ap, s32b);
+ break;
+ case '(':
+ case ')':
+ case ',':
+ break;
+ }
+ i++;
+ }
+
+ get_next_arg_pos = 0;
+ get_next_arg_pile_pos = 0;
+ if (c->hook(fmt))
+ {
+ return TRUE;
+ }
+
+ /* Should we restart ? */
+ if (process_hooks_restart)
+ {
+ c = hooks_heads[h_idx];
+ process_hooks_restart = FALSE;
+ }
+ else
+ {
+ c = c->next;
+ }
+ }
+ else if (c->type == HOOK_TYPE_LUA)
+ {
+ int i = 0, nb = 0, nbr = 1;
+ int oldtop = lua_gettop(L), size;
+
+ /* Push the function */
+ lua_getglobal(L, c->script);
+
+ /* Push and count the arguments */
+ COPY(&real_ap, ap, va_list);
+ while (fmt[i])
+ {
+ switch (fmt[i++])
+ {
+ case 'd':
+ case 'l':
+ tolua_pushnumber(L, va_arg(real_ap, s32b));
+ nb++;
+ break;
+ case 's':
+ tolua_pushstring(L, va_arg(real_ap, char*));
+ nb++;
+ break;
+ case 'O':
+ tolua_pushusertype(L, (void*)va_arg(real_ap, object_type*), tolua_tag(L, "object_type"));
+ nb++;
+ break;
+ case 'M':
+ tolua_pushusertype(L, (void*)va_arg(real_ap, monster_type*), tolua_tag(L, "monster_type"));
+ nb++;
+ break;
+ case '(':
+ case ')':
+ case ',':
+ break;
+ }
+ }
+
+ /* Count returns */
+ nbr += strlen(ret);
+
+ /* Call the function */
+ if (lua_call(L, nb, nbr))
+ {
+ cmsg_format(TERM_VIOLET, "ERROR in lua_call while calling '%s' lua hook script. Breaking the hook chain now.", c->script);
+ return FALSE;
+ }
+
+ /* Number of returned values, SHOULD be the same as nbr, but I'm paranoid */
+ size = lua_gettop(L) - oldtop;
+
+ /* get the extra returns if needed */
+ for (i = 0; i < nbr - 1; i++)
+ {
+ if ((ret[i] == 'd') || (ret[i] == 'l'))
+ {
+ if (lua_isnumber(L, ( -size) + 1 + i)) process_hooks_return[i].num = tolua_getnumber(L, ( -size) + 1 + i, 0);
+ else process_hooks_return[i].num = 0;
+ }
+ else if (ret[i] == 's')
+ {
+ if (lua_isstring(L, ( -size) + 1 + i)) process_hooks_return[i].str = tolua_getstring(L, ( -size) + 1 + i, "");
+ else process_hooks_return[i].str = NULL;
+ }
+ else if (ret[i] == 'O')
+ {
+ if (tolua_istype(L, ( -size) + 1 + i, tolua_tag(L, "object_type"), 0))
+ process_hooks_return[i].o_ptr = (object_type*)tolua_getuserdata(L, ( -size) + 1 + i, NULL);
+ else
+ process_hooks_return[i].o_ptr = NULL;
+ }
+ else if (ret[i] == 'M')
+ {
+ if (tolua_istype(L, ( -size) + 1 + i, tolua_tag(L, "monster_type"), 0))
+ process_hooks_return[i].m_ptr = (monster_type*)tolua_getuserdata(L, ( -size) + 1 + i, NULL);
+ else
+ process_hooks_return[i].m_ptr = NULL;
+ }
+ else process_hooks_return[i].num = 0;
+ }
+
+ /* Get the basic return(continue or stop the hook chain) */
+ if (tolua_getnumber(L, -size, 0))
+ {
+ lua_settop(L, oldtop);
+ return (TRUE);
+ }
+ if (process_hooks_restart)
+ {
+ c = hooks_heads[h_idx];
+ process_hooks_restart = FALSE;
+ }
+ else
+ c = c->next;
+ lua_settop(L, oldtop);
+ }
+ else
+ {
+ msg_format("Unkown hook type %d, name %s", c->type, c->name);
+ }
+ }
+
+ return FALSE;
+}
+
+bool process_hooks_ret(int h_idx, char *ret, char *fmt, ...)
+{
+ va_list ap;
+ bool r;
+
+ va_start(ap, fmt);
+ r = vprocess_hooks_return (h_idx, ret, fmt, &ap);
+ va_end(ap);
+ return (r);
+}
+
+bool process_hooks(int h_idx, char *fmt, ...)
+{
+ va_list ap;
+ bool ret;
+
+ va_start(ap, fmt);
+ ret = vprocess_hooks_return (h_idx, "", fmt, &ap);
+ va_end(ap);
+ return (ret);
+}
+
+/******** Plots & Quest stuff ********/
+
+static void quest_describe(int q_idx)
+{
+ int i = 0;
+
+ while ((i < 10) && (quest[q_idx].desc[i][0] != '\0'))
+ {
+ cmsg_print(TERM_YELLOW, quest[q_idx].desc[i++]);
+ }
+}
+
+/* Catch-all quest hook */
+bool quest_null_hook(int q)
+{
+ /* Do nothing */
+ return (FALSE);
+}
+
+/************************** Random Quests *************************/
+#include "q_rand.c"
+
+/**************************** Main plot ***************************/
+#include "q_main.c"
+#include "q_one.c"
+#include "q_ultrag.c"
+#include "q_ultrae.c"
+
+/**************************** Bree plot ***************************/
+#include "q_thief.c"
+#include "q_hobbit.c"
+#include "q_troll.c"
+#include "q_wight.c"
+#include "q_nazgul.c"
+#include "q_shroom.c"
+
+/*************************** Lorien plot **************************/
+#include "q_wolves.c"
+#include "q_spider.c"
+#include "q_poison.c"
+
+/************************** Gondolin plot *************************/
+#include "q_dragons.c"
+#include "q_eol.c"
+#include "q_nirna.c"
+#include "q_invas.c"
+
+/************************* Minas Anor plot ************************/
+#include "q_haunted.c"
+#include "q_betwen.c"
+
+/************************* Khazad-dum plot ************************/
+#include "q_evil.c"
+
+/*************************** Other plot ***************************/
+#include "q_narsil.c"
+#include "q_thrain.c"