diff options
Diffstat (limited to 'src/map/npc_chat.c')
-rw-r--r-- | src/map/npc_chat.c | 648 |
1 files changed, 289 insertions, 359 deletions
diff --git a/src/map/npc_chat.c b/src/map/npc_chat.c index 7d3a9a2fa..a1fdae0bc 100644 --- a/src/map/npc_chat.c +++ b/src/map/npc_chat.c @@ -3,27 +3,22 @@ #ifdef PCRE_SUPPORT -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <time.h> - #include "../common/timer.h" #include "../common/malloc.h" -#include "../common/version.h" #include "../common/nullpo.h" #include "../common/showmsg.h" +#include "../common/strlib.h" -#include "map.h" -#include "status.h" -#include "npc.h" -#include "chat.h" -#include "script.h" -#include "battle.h" +#include "map.h" // struct mob_data, struct npc_data +#include "script.h" // set_var() #include "pcre.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + /** * Written by MouseJstr in a vision... (2/21/2005) * @@ -71,24 +66,21 @@ * deletes a pset */ -/* Structure containing all info associated with a single pattern - block */ - +/* Structure containing all info associated with a single pattern block */ struct pcrematch_entry { - struct pcrematch_entry *next_; - char *pattern_; - pcre *pcre_; - pcre_extra *pcre_extra_; - char *label_; + struct pcrematch_entry* next; + char* pattern; + pcre* pcre; + pcre_extra* pcre_extra; + char* label; }; -/* A set of patterns that can be activated and deactived with a single - command */ - +/* A set of patterns that can be activated and deactived with a single command */ struct pcrematch_set { - struct pcrematch_set *next_, *prev_; - struct pcrematch_entry *head_; - int setid_; + struct pcrematch_set* prev; + struct pcrematch_set* next; + struct pcrematch_entry* head; + int setid; }; /* @@ -100,10 +92,9 @@ struct pcrematch_set { * also wanted people to be able to grab this one file to get updates * without having to do a large number of changes. */ - struct npc_parse { - struct pcrematch_set *active_; - struct pcrematch_set *inactive_; + struct pcrematch_set* active; + struct pcrematch_set* inactive; }; @@ -112,63 +103,51 @@ struct npc_parse { * * This does NOT do the list management */ - -void finalize_pcrematch_entry(struct pcrematch_entry *e) +void finalize_pcrematch_entry(struct pcrematch_entry* e) { -//TODO: For some odd reason this causes a already-free'd error under Windows, but not *nix! [Skotlex] -#ifndef _WIN32 - if (e->pcre_) { - free(e->pcre_); - e->pcre_ = NULL; - } -#endif - if (e->pcre_extra_) { - free(e->pcre_extra_); - e->pcre_ = NULL; - } - aFree(e->pattern_); - aFree(e->label_); + pcre_free(e->pcre); + pcre_free(e->pcre_extra); + aFree(e->pattern); + aFree(e->label); } /** * Lookup (and possibly create) a new set of patterns by the set id */ -static struct pcrematch_set * lookup_pcreset(struct npc_data *nd,int setid) +static struct pcrematch_set* lookup_pcreset(struct npc_data* nd, int setid) { - struct pcrematch_set *pcreset; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) - nd->chatdb = npcParse = (struct npc_parse *) - aCalloc(sizeof(struct npc_parse), 1); - - pcreset = npcParse->active_; - - while (pcreset != NULL) { - if (pcreset->setid_ == setid) - break; - pcreset = pcreset->next_; - } - if (pcreset == NULL) - pcreset = npcParse->inactive_; - - while (pcreset != NULL) { - if (pcreset->setid_ == setid) - break; - pcreset = pcreset->next_; - } - - if (pcreset == NULL) { - pcreset = (struct pcrematch_set *) - aCalloc(sizeof(struct pcrematch_set), 1); - pcreset->next_ = npcParse->inactive_; - if (pcreset->next_ != NULL) - pcreset->next_->prev_ = pcreset; - pcreset->prev_ = 0; - npcParse->inactive_ = pcreset; - pcreset->setid_ = setid; - } - - return pcreset; + struct pcrematch_set *pcreset; + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + nd->chatdb = npcParse = (struct npc_parse *) aCalloc(sizeof(struct npc_parse), 1); + + pcreset = npcParse->active; + + while (pcreset != NULL) { + if (pcreset->setid == setid) + break; + pcreset = pcreset->next; + } + if (pcreset == NULL) + pcreset = npcParse->inactive; + + while (pcreset != NULL) { + if (pcreset->setid == setid) + break; + pcreset = pcreset->next; + } + + if (pcreset == NULL) { + pcreset = (struct pcrematch_set *) aCalloc(sizeof(struct pcrematch_set), 1); + pcreset->next = npcParse->inactive; + if (pcreset->next != NULL) + pcreset->next->prev = pcreset; + pcreset->prev = 0; + npcParse->inactive = pcreset; + pcreset->setid = setid; + } + + return pcreset; } /** @@ -176,33 +155,32 @@ static struct pcrematch_set * lookup_pcreset(struct npc_data *nd,int setid) * * if the setid does not exist, this will silently return */ - -static void activate_pcreset(struct npc_data *nd,int setid) +static void activate_pcreset(struct npc_data* nd, int setid) { - struct pcrematch_set *pcreset; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) - return; // Nothing to activate... - pcreset = npcParse->inactive_; - while (pcreset != NULL) { - if (pcreset->setid_ == setid) - break; - pcreset = pcreset->next_; - } - if (pcreset == NULL) - return; // not in inactive list - if (pcreset->next_ != NULL) - pcreset->next_->prev_ = pcreset->prev_; - if (pcreset->prev_ != NULL) - pcreset->prev_->next_ = pcreset->next_; - else - npcParse->inactive_ = pcreset->next_; - - pcreset->prev_ = NULL; - pcreset->next_ = npcParse->active_; - if (pcreset->next_ != NULL) - pcreset->next_->prev_ = pcreset; - npcParse->active_ = pcreset; + struct pcrematch_set *pcreset; + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + return; // Nothing to activate... + pcreset = npcParse->inactive; + while (pcreset != NULL) { + if (pcreset->setid == setid) + break; + pcreset = pcreset->next; + } + if (pcreset == NULL) + return; // not in inactive list + if (pcreset->next != NULL) + pcreset->next->prev = pcreset->prev; + if (pcreset->prev != NULL) + pcreset->prev->next = pcreset->next; + else + npcParse->inactive = pcreset->next; + + pcreset->prev = NULL; + pcreset->next = npcParse->active; + if (pcreset->next != NULL) + pcreset->next->prev = pcreset; + npcParse->active = pcreset; } /** @@ -210,138 +188,133 @@ static void activate_pcreset(struct npc_data *nd,int setid) * * if the setid does not exist, this will silently return */ - -static void deactivate_pcreset(struct npc_data *nd,int setid) +static void deactivate_pcreset(struct npc_data* nd, int setid) { - struct pcrematch_set *pcreset; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) - return; // Nothing to deactivate... - if (setid == -1) { - while(npcParse->active_ != NULL) - deactivate_pcreset(nd, npcParse->active_->setid_); - return; - } - pcreset = npcParse->active_; - while (pcreset != NULL) { - if (pcreset->setid_ == setid) - break; - pcreset = pcreset->next_; - } - if (pcreset == NULL) - return; // not in active list - if (pcreset->next_ != NULL) - pcreset->next_->prev_ = pcreset->prev_; - if (pcreset->prev_ != NULL) - pcreset->prev_->next_ = pcreset->next_; - else - npcParse->active_ = pcreset->next_; - - pcreset->prev_ = NULL; - pcreset->next_ = npcParse->inactive_; - if (pcreset->next_ != NULL) - pcreset->next_->prev_ = pcreset; - npcParse->inactive_ = pcreset; + struct pcrematch_set *pcreset; + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + return; // Nothing to deactivate... + if (setid == -1) { + while(npcParse->active != NULL) + deactivate_pcreset(nd, npcParse->active->setid); + return; + } + pcreset = npcParse->active; + while (pcreset != NULL) { + if (pcreset->setid == setid) + break; + pcreset = pcreset->next; + } + if (pcreset == NULL) + return; // not in active list + if (pcreset->next != NULL) + pcreset->next->prev = pcreset->prev; + if (pcreset->prev != NULL) + pcreset->prev->next = pcreset->next; + else + npcParse->active = pcreset->next; + + pcreset->prev = NULL; + pcreset->next = npcParse->inactive; + if (pcreset->next != NULL) + pcreset->next->prev = pcreset; + npcParse->inactive = pcreset; } /** * delete a set of patterns. */ -static void delete_pcreset(struct npc_data *nd,int setid) +static void delete_pcreset(struct npc_data* nd, int setid) { - int active = 1; - struct pcrematch_set *pcreset; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) - return; // Nothing to deactivate... - pcreset = npcParse->active_; - while (pcreset != NULL) { - if (pcreset->setid_ == setid) - break; - pcreset = pcreset->next_; - } - if (pcreset == NULL) { - active = 0; - pcreset = npcParse->inactive_; - while (pcreset != NULL) { - if (pcreset->setid_ == setid) - break; - pcreset = pcreset->next_; - } - } - if (pcreset == NULL) - return; - - if (pcreset->next_ != NULL) - pcreset->next_->prev_ = pcreset->prev_; - if (pcreset->prev_ != NULL) - pcreset->prev_->next_ = pcreset->next_; - + int active = 1; + struct pcrematch_set *pcreset; + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + return; // Nothing to deactivate... + pcreset = npcParse->active; + while (pcreset != NULL) { + if (pcreset->setid == setid) + break; + pcreset = pcreset->next; + } + if (pcreset == NULL) { + active = 0; + pcreset = npcParse->inactive; + while (pcreset != NULL) { + if (pcreset->setid == setid) + break; + pcreset = pcreset->next; + } + } + if (pcreset == NULL) + return; + + if (pcreset->next != NULL) + pcreset->next->prev = pcreset->prev; + if (pcreset->prev != NULL) + pcreset->prev->next = pcreset->next; + if(active) - npcParse->active_ = pcreset->next_; + npcParse->active = pcreset->next; else - npcParse->inactive_ = pcreset->next_; - - pcreset->prev_ = NULL; - pcreset->next_ = NULL; - - while (pcreset->head_) { - struct pcrematch_entry *n = pcreset->head_->next_; - finalize_pcrematch_entry(pcreset->head_); - aFree(pcreset->head_); // Cleanin' the last ones.. [Lance] - pcreset->head_ = n; - } - + npcParse->inactive = pcreset->next; + + pcreset->prev = NULL; + pcreset->next = NULL; + + while (pcreset->head) { + struct pcrematch_entry* n = pcreset->head->next; + finalize_pcrematch_entry(pcreset->head); + aFree(pcreset->head); // Cleanin' the last ones.. [Lance] + pcreset->head = n; + } + aFree(pcreset); } /** * create a new pattern entry */ -static struct pcrematch_entry *create_pcrematch_entry(struct pcrematch_set * set) +static struct pcrematch_entry* create_pcrematch_entry(struct pcrematch_set* set) { - struct pcrematch_entry * e = (struct pcrematch_entry *) - aCalloc(sizeof(struct pcrematch_entry), 1); - struct pcrematch_entry * last = set->head_; - - // Normally we would have just stuck it at the end of the list but - // this doesn't sink up with peoples usage pattern. They wanted - // the items defined first to have a higher priority then the - // items defined later.. as a result, we have to do some work up - // front.. - - /* if we are the first pattern, stick us at the end */ - if (last == NULL) { - set->head_ = e; - return e; - } - - /* Look for the last entry */ - while (last->next_ != NULL) - last = last->next_; - - last->next_ = e; - e->next_ = NULL; - - return e; + struct pcrematch_entry * e = (struct pcrematch_entry *) aCalloc(sizeof(struct pcrematch_entry), 1); + struct pcrematch_entry * last = set->head; + + // Normally we would have just stuck it at the end of the list but + // this doesn't sink up with peoples usage pattern. They wanted + // the items defined first to have a higher priority then the + // items defined later. as a result, we have to do some work up front. + + /* if we are the first pattern, stick us at the end */ + if (last == NULL) { + set->head = e; + return e; + } + + /* Look for the last entry */ + while (last->next != NULL) + last = last->next; + + last->next = e; + e->next = NULL; + + return e; } /** * define/compile a new pattern */ - -void npc_chat_def_pattern(struct npc_data *nd, int setid, - const char *pattern, const char *label) +void npc_chat_def_pattern(struct npc_data* nd, int setid, const char* pattern, const char* label) { - const char *err; - int erroff; - - struct pcrematch_set * s = lookup_pcreset(nd, setid); - struct pcrematch_entry *e = create_pcrematch_entry(s); - e->pattern_ = aStrdup(pattern); - e->label_ = aStrdup(label); - e->pcre_ = pcre_compile(pattern, PCRE_CASELESS, &err, &erroff, NULL); - e->pcre_extra_ = pcre_study(e->pcre_, 0, &err); + const char *err; + int erroff; + + struct pcrematch_set * s = lookup_pcreset(nd, setid); + struct pcrematch_entry *e = create_pcrematch_entry(s); + e->pattern = aStrdup(pattern); + e->label = aStrdup(label); + e->pcre = pcre_compile(pattern, PCRE_CASELESS, &err, &erroff, NULL); + e->pcre_extra = pcre_study(e->pcre, 0, &err); } /** @@ -350,18 +323,18 @@ void npc_chat_def_pattern(struct npc_data *nd, int setid, * * this could be more efficent but.. how often do you do this? */ -void npc_chat_finalize(struct npc_data *nd) +void npc_chat_finalize(struct npc_data* nd) { - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) - return; - - while(npcParse->active_) - delete_pcreset(nd, npcParse->active_->setid_); - - while(npcParse->inactive_) - delete_pcreset(nd, npcParse->inactive_->setid_); - + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + return; + + while(npcParse->active) + delete_pcreset(nd, npcParse->active->setid); + + while(npcParse->inactive) + delete_pcreset(nd, npcParse->inactive->setid); + // Additional cleaning up [Lance] aFree(npcParse); } @@ -369,158 +342,115 @@ void npc_chat_finalize(struct npc_data *nd) /** * Handler called whenever a global message is spoken in a NPC's area */ -int npc_chat_sub(struct block_list *bl, va_list ap) +int npc_chat_sub(struct block_list* bl, va_list ap) { - struct npc_data *nd = (struct npc_data *)bl; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - char *msg; - int len, pos, i; - struct map_session_data *sd; - struct npc_label_list *lst; - struct pcrematch_set *pcreset; - - // Not interested in anything you might have to say... - if (npcParse == NULL || npcParse->active_ == NULL) - return 0; - - msg = va_arg(ap,char*); - len = va_arg(ap,int); - sd = va_arg(ap,struct map_session_data *); - - // grab the active list - pcreset = npcParse->active_; - - // interate across all active sets - while (pcreset != NULL) { - struct pcrematch_entry *e = pcreset->head_; - // interate across all patterns in that set - while (e != NULL) { - int offsets[20]; - char buf[255]; - // perform pattern match - int r = pcre_exec(e->pcre_, e->pcre_extra_, msg, len, 0, - 0, offsets, sizeof(offsets) / sizeof(offsets[0])); - if (r >= 0) { - // save out the matched strings - switch (r) { - case 10: - memcpy(buf, &msg[offsets[18]], offsets[19]); - buf[offsets[19]] = '\0'; - set_var(sd, "$@p9$", buf); - case 9: - memcpy(buf, &msg[offsets[16]], offsets[17]); - buf[offsets[17]] = '\0'; - set_var(sd, "$@p8$", buf); - case 8: - memcpy(buf, &msg[offsets[14]], offsets[15]); - buf[offsets[15]] = '\0'; - set_var(sd, "$@p7$", buf); - case 7: - memcpy(buf, &msg[offsets[12]], offsets[13]); - buf[offsets[13]] = '\0'; - set_var(sd, "$@p6$", buf); - case 6: - memcpy(buf, &msg[offsets[10]], offsets[11]); - buf[offsets[11]] = '\0'; - set_var(sd, "$@p5$", buf); - case 5: - memcpy(buf, &msg[offsets[8]], offsets[9]); - buf[offsets[9]] = '\0'; - set_var(sd, "$@p4$", buf); - case 4: - memcpy(buf, &msg[offsets[6]], offsets[7]); - buf[offsets[7]] = '\0'; - set_var(sd, "$@p3$", buf); - case 3: - memcpy(buf, &msg[offsets[4]], offsets[5]); - buf[offsets[5]] = '\0'; - set_var(sd, "$@p2$", buf); - case 2: - memcpy(buf, &msg[offsets[2]], offsets[3]); - buf[offsets[3]] = '\0'; - set_var(sd, "$@p1$", buf); - case 1: - memcpy(buf, &msg[offsets[0]], offsets[1]); - buf[offsets[1]] = '\0'; - set_var(sd, "$@p0$", buf); - } - - // find the target label.. this sucks.. - lst=nd->u.scr.label_list; - pos = -1; - for (i = 0; i < nd->u.scr.label_list_num; i++) { - if (strncmp(lst[i].name, e->label_, sizeof(lst[i].name)) == 0) { - pos = lst[i].pos; - break; - } - } - if (pos == -1) { - ShowWarning("Unable to find label: %s", e->label_); - // unable to find label... do something.. - return 0; - } - // run the npc script - run_script(nd->u.scr.script,pos,sd->bl.id,nd->bl.id); - return 0; - } - e = e->next_; - } - pcreset = pcreset->next_; - } - - return 0; + struct npc_data* nd = (struct npc_data *) bl; + struct npc_parse* npcParse = (struct npc_parse *) nd->chatdb; + char* msg; + int len, i; + struct map_session_data* sd; + struct npc_label_list* lst; + struct pcrematch_set* pcreset; + struct pcrematch_entry* e; + + // Not interested in anything you might have to say... + if (npcParse == NULL || npcParse->active == NULL) + return 0; + + msg = va_arg(ap,char*); + len = va_arg(ap,int); + sd = va_arg(ap,struct map_session_data *); + + // iterate across all active sets + for (pcreset = npcParse->active; pcreset != NULL; pcreset = pcreset->next) + { + // interate across all patterns in that set + for (e = pcreset->head; e != NULL; e = e->next) + { + int offsets[2*10 + 10]; // 1/3 reserved for temp space requred by pcre_exec + + // perform pattern match + int r = pcre_exec(e->pcre, e->pcre_extra, msg, len, 0, 0, offsets, ARRAYLENGTH(offsets)); + if (r > 0) + { + // save out the matched strings + for (i = 0; i < r; i++) + { + char var[6], val[255]; + snprintf(var, sizeof(var), "$@p%i$", i); + pcre_copy_substring(msg, offsets, r, i, val, sizeof(val)); + set_var(sd, var, val); + } + + // find the target label.. this sucks.. + lst = nd->u.scr.label_list; + ARR_FIND(0, nd->u.scr.label_list_num, i, strncmp(lst[i].name, e->label, sizeof(lst[i].name)) == 0); + if (i == nd->u.scr.label_list_num) { + ShowWarning("Unable to find label: %s", e->label); + return 0; + } + + // run the npc script + run_script(nd->u.scr.script,lst[i].pos,sd->bl.id,nd->bl.id); + return 0; + } + } + } + + return 0; } -int mob_chat_sub(struct block_list *bl, va_list ap){ +int mob_chat_sub(struct block_list* bl, va_list ap) +{ struct mob_data *md = (struct mob_data *)bl; - if(md->nd){ + if(md->nd) npc_chat_sub(&md->nd->bl, ap); - } + return 0; } // Various script builtins used to support these functions -int buildin_defpattern(struct script_state *st) +int buildin_defpattern(struct script_state* st) { - int setid=conv_num(st,& (st->stack->stack_data[st->start+2])); - const char *pattern=conv_str(st,& (st->stack->stack_data[st->start+3])); - const char *label=conv_str(st,& (st->stack->stack_data[st->start+4])); - struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid); - - npc_chat_def_pattern(nd, setid, pattern, label); - - return 0; + int setid = conv_num(st,& (st->stack->stack_data[st->start+2])); + const char* pattern = conv_str(st,& (st->stack->stack_data[st->start+3])); + const char* label = conv_str(st,& (st->stack->stack_data[st->start+4])); + struct npc_data* nd = (struct npc_data *)map_id2bl(st->oid); + + npc_chat_def_pattern(nd, setid, pattern, label); + + return 0; } -int buildin_activatepset(struct script_state *st) +int buildin_activatepset(struct script_state* st) { - int setid=conv_num(st,& (st->stack->stack_data[st->start+2])); - struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid); - - activate_pcreset(nd, setid); - - return 0; + int setid = conv_num(st,& (st->stack->stack_data[st->start+2])); + struct npc_data* nd = (struct npc_data *)map_id2bl(st->oid); + + activate_pcreset(nd, setid); + + return 0; } -int buildin_deactivatepset(struct script_state *st) +int buildin_deactivatepset(struct script_state* st) { - int setid=conv_num(st,& (st->stack->stack_data[st->start+2])); - struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid); - - deactivate_pcreset(nd, setid); - - return 0; + int setid = conv_num(st,& (st->stack->stack_data[st->start+2])); + struct npc_data* nd = (struct npc_data *)map_id2bl(st->oid); + + deactivate_pcreset(nd, setid); + + return 0; } -int buildin_deletepset(struct script_state *st) +int buildin_deletepset(struct script_state* st) { - int setid=conv_num(st,& (st->stack->stack_data[st->start+2])); - struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid); - - delete_pcreset(nd, setid); - - return 0; + int setid = conv_num(st,& (st->stack->stack_data[st->start+2])); + struct npc_data* nd = (struct npc_data *)map_id2bl(st->oid); + + delete_pcreset(nd, setid); + + return 0; } #endif //PCRE_SUPPORT |