diff options
Diffstat (limited to 'src/plots.c')
-rw-r--r-- | src/plots.c | 473 |
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" |