* Fixed a deallocation mistake and some buffer overflows in npc_chat.c after doing rtfm@pcre.txt (all caused by incorrect usage of pcre api)
* Removed underscores in npc_chat.c's variable names (easier to read) * Reindented the whole thing (used spaces half of the time ._.) * Moved npc pcre-data deallocation from npc_remove_map to npc_unload git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@11036 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
parent
1518e0240b
commit
97e812dda1
@ -3,6 +3,11 @@ Date Added
|
||||
AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
|
||||
IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
|
||||
|
||||
2007/08/18
|
||||
* Fixed a deallocation mistake and some buffer overflows in npc_chat.c
|
||||
after doing rtfm@pcre.txt (all caused by incorrect usage of pcre api)
|
||||
* Removed underscores in npc_chat.c's variable names (easier to read)
|
||||
* Moved npc pcre-data deallocation from npc_remove_map to npc_unload
|
||||
2007/08/17
|
||||
* Implemented the official dual-wield aspd equation [ultramage]
|
||||
- using 0.7 instead of 0.66 as modifier (so aspd will be lower now)
|
||||
|
@ -1,13 +1,13 @@
|
||||
// Athena charcommand Configuration file.
|
||||
// Translated by Peter Kieser <pfak@telus.net>
|
||||
|
||||
// Set here the symbol that you want to use for your commands
|
||||
// Only 1 character is get (default is '#'). You can set any character,
|
||||
// except control-character (0x00-0x1f), '%' (party chat speaking),
|
||||
// '/' (standard ragnarok GM commands) and '@' (Standard GM Commands)
|
||||
// With default character, all commands begin by a '#', example: #save SomePlayer
|
||||
// The symbol that will be used to recognize commands.
|
||||
// You can set any one character, except control-characters (0x00-0x1f),
|
||||
// '%', '$' (party/guild chat speaking) and '/' (standard client commands).
|
||||
// The symbol must be different from from the standard GM command symbol.
|
||||
command_symbol: #
|
||||
|
||||
|
||||
//--------------------------
|
||||
// 0: normal player commands
|
||||
// None for security purposes.
|
||||
@ -25,85 +25,86 @@ command_symbol: #
|
||||
// 40: Sub-GM commands
|
||||
|
||||
|
||||
//View the items in a character's cart
|
||||
// View the items in a character's cart
|
||||
cartlist: 40
|
||||
|
||||
//Apply an effect onto another character
|
||||
// Apply an effect onto another character
|
||||
effect: 40
|
||||
|
||||
//View the exp of a character
|
||||
// View the exp of a character
|
||||
exp: 40
|
||||
|
||||
//List a chacter's items
|
||||
// List a chacter's items
|
||||
itemlist: 40
|
||||
|
||||
//View the jail time remaining
|
||||
// View the jail time remaining
|
||||
jailtime: 40
|
||||
|
||||
//Refresh a character
|
||||
// Refresh a character
|
||||
refresh: 40
|
||||
|
||||
//List a chacter's stats
|
||||
// List a chacter's stats
|
||||
stats: 40
|
||||
|
||||
//List a chacter's storage items
|
||||
// List a chacter's storage items
|
||||
storagelist: 40
|
||||
|
||||
//---------------------
|
||||
// 50: Sub-GM+ commands
|
||||
|
||||
//Change a character's clothing color
|
||||
// Change a character's clothing color
|
||||
dye: 50
|
||||
|
||||
//Give another character a fake name
|
||||
// Give another character a fake name
|
||||
fakename: 50
|
||||
|
||||
//Open the hatch dialog for a character
|
||||
// Open the hatch dialog for a character
|
||||
hatch: 50
|
||||
|
||||
//Change a character's hair color
|
||||
// Change a character's hair color
|
||||
hcolor: 50
|
||||
haircolor: 50
|
||||
|
||||
//Change a character's hair style
|
||||
// Change a character's hair style
|
||||
hstyle: 50
|
||||
hairstyle: 50
|
||||
|
||||
// Changes character's model
|
||||
model: 50
|
||||
|
||||
//Give or remove a peco from a character
|
||||
// Give or remove a peco from a character
|
||||
mount: 50
|
||||
mountpeco: 50
|
||||
|
||||
//Make another character's pet friendly/not
|
||||
// Make another character's pet friendly/not
|
||||
petfriendly: 50
|
||||
|
||||
//Rename another character's pet
|
||||
// Rename another character's pet
|
||||
petrename: 50
|
||||
|
||||
//Change a character's size
|
||||
// Change a character's size
|
||||
size: 50
|
||||
|
||||
//----------------
|
||||
// 60: GM commands
|
||||
|
||||
//Resurrects a dead character
|
||||
// Resurrects a dead character
|
||||
alive: 60
|
||||
revive: 60
|
||||
|
||||
//Give a player all the skills available to him/her
|
||||
// Give a player all the skills available to him/her
|
||||
allskill: 60
|
||||
allskills: 60
|
||||
skillall: 60
|
||||
skillsall: 60
|
||||
|
||||
//Give a character the maximum possible stats
|
||||
// Give a character the maximum possible stats
|
||||
allstat: 60
|
||||
allstats: 60
|
||||
statall: 60
|
||||
statsall: 60
|
||||
|
||||
//Change another character's base level (3 same commands)
|
||||
// Change another character's base level (3 same commands)
|
||||
blvl: 60
|
||||
blevel: 60
|
||||
baselvl: 60
|
||||
@ -112,118 +113,118 @@ baselevel: 60
|
||||
// Changes the sex of an online player (all characters on the account)
|
||||
changesex: 60
|
||||
|
||||
//Delete items from a character
|
||||
// Delete items from a character
|
||||
delitem: 60
|
||||
|
||||
//Disguise a character
|
||||
// Disguise a character
|
||||
disguise: 60
|
||||
undisguise: 60
|
||||
|
||||
//Resets another character's designated maps
|
||||
// Resets another character's designated maps
|
||||
feelreset: 60
|
||||
|
||||
//Change the guild level for a character's guild
|
||||
// Change the guild level for a character's guild
|
||||
glvl: 60
|
||||
glevel: 60
|
||||
guildlvl: 60
|
||||
guildlevel: 60
|
||||
|
||||
//Open guild storage for a character
|
||||
// Open guild storage for a character
|
||||
gstorage: 60
|
||||
|
||||
//Heal a character
|
||||
// Heal a character
|
||||
heal: 60
|
||||
|
||||
//Invoke GM Hide on a character
|
||||
// Invoke GM Hide on a character
|
||||
hide: 60
|
||||
|
||||
//Increase a character's homunculus' level
|
||||
// Increase a character's homunculus' level
|
||||
hlvl: 60
|
||||
hlevel: 60
|
||||
homlvl: 60
|
||||
homlevel: 60
|
||||
|
||||
//Evolve a character's homunculus
|
||||
// Evolve a character's homunculus
|
||||
homevolve: 60
|
||||
homevolution: 60
|
||||
|
||||
//Change a character's homunculus' friendly value
|
||||
// Change a character's homunculus' friendly value
|
||||
homfriendly: 60
|
||||
|
||||
//Change a character's homunculus' hunger value
|
||||
// Change a character's homunculus' hunger value
|
||||
homhungry: 60
|
||||
|
||||
//View a character's homunculus' stats
|
||||
// View a character's homunculus' stats
|
||||
hominfo: 40
|
||||
|
||||
//Give another character an item
|
||||
// Give another character an item
|
||||
item: 60
|
||||
|
||||
//Create a specific item (with cards, refines, etc
|
||||
// Create a specific item (with cards, refines, etc
|
||||
item2: 60
|
||||
|
||||
//Remove all of a character's possessions
|
||||
// Remove all of a character's possessions
|
||||
itemreset: 60
|
||||
|
||||
//Change another character's job (2 same commands)
|
||||
// Change another character's job (2 same commands)
|
||||
job: 60
|
||||
jobchange: 60
|
||||
|
||||
//Change another character's job level (3 same commands)
|
||||
// Change another character's job level (3 same commands)
|
||||
jlvl: 60
|
||||
jlevel: 60
|
||||
joblvl: 60
|
||||
joblevel: 60
|
||||
|
||||
//Allow a character to attack anybody
|
||||
// Allow a character to attack anybody
|
||||
killer: 60
|
||||
|
||||
//Make a character killable by anybody
|
||||
// Make a character killable by anybody
|
||||
killable: 60
|
||||
|
||||
//Return a character to their respawn point
|
||||
// Return a character to their respawn point
|
||||
load: 60
|
||||
|
||||
//Take away a character's platinum skill
|
||||
// Take away a character's platinum skill
|
||||
lostskill: 60
|
||||
|
||||
//Make a character immune to monsters
|
||||
// Make a character immune to monsters
|
||||
monsterignore: 60
|
||||
|
||||
//Apply a certain option to another character
|
||||
// Apply a certain option to another character
|
||||
option: 60
|
||||
|
||||
//Change a character's pet's hungry value
|
||||
// Change a character's pet's hungry value
|
||||
pethungry: 60
|
||||
|
||||
//Produce forged equipment on a character (as if he/she was a blacksmith)
|
||||
// Produce forged equipment on a character (as if he/she was a blacksmith)
|
||||
produce: 60
|
||||
|
||||
//Give another character a platinum skill
|
||||
// Give another character a platinum skill
|
||||
questskill: 60
|
||||
|
||||
//Performs a stat and skill reset on someone else.
|
||||
// Performs a stat and skill reset on someone else.
|
||||
reset: 60
|
||||
|
||||
//Save another character
|
||||
// Save another character
|
||||
save: 60
|
||||
|
||||
// Gives another character skill points
|
||||
skpoint: 60
|
||||
|
||||
//Change a character's walking speed
|
||||
// Change a character's walking speed
|
||||
speed: 60
|
||||
|
||||
//Give another character spiritball effect
|
||||
// Give another character spiritball effect
|
||||
spiritball: 60
|
||||
|
||||
//Open storage for a character
|
||||
// Open storage for a character
|
||||
storage: 60
|
||||
|
||||
// Gives another character status points
|
||||
stpoint: 60
|
||||
|
||||
//Change a character's stats
|
||||
// Change a character's stats
|
||||
str: 60
|
||||
agi: 60
|
||||
vit: 60
|
||||
@ -243,10 +244,10 @@ rura+: 60
|
||||
//----------------------
|
||||
// 80: GM Chief commands
|
||||
|
||||
//Refine a character's equipment
|
||||
// Refine a character's equipment
|
||||
refine: 80
|
||||
|
||||
//Give another character zeny
|
||||
// Give another character zeny
|
||||
zeny: 80
|
||||
|
||||
//---------------------------
|
||||
|
@ -844,7 +844,7 @@ struct npc_data {
|
||||
int eventtimer[MAX_EVENTTIMER];
|
||||
short arenaflag;
|
||||
|
||||
void *chatdb;
|
||||
void* chatdb; // pointer to a npc_parse struct (see npc_chat.c)
|
||||
struct npc_data *master_nd;
|
||||
|
||||
union {
|
||||
|
@ -1441,9 +1441,6 @@ int npc_remove_map(struct npc_data* nd)
|
||||
if(nd->bl.prev == NULL || nd->bl.m < 0)
|
||||
return 1; //Not assigned to a map.
|
||||
m = nd->bl.m;
|
||||
#ifdef PCRE_SUPPORT
|
||||
npc_chat_finalize(nd);
|
||||
#endif
|
||||
clif_clearunit_area(&nd->bl,2);
|
||||
//Remove corresponding NPC CELLs
|
||||
if (nd->bl.subtype == WARP) {
|
||||
@ -1513,6 +1510,10 @@ int npc_unload(struct npc_data* nd)
|
||||
if (nd->chat_id) // remove npc chatroom object and kick users
|
||||
chat_deletenpcchat(nd);
|
||||
|
||||
#ifdef PCRE_SUPPORT
|
||||
npc_chat_finalize(nd); // deallocate npc PCRE data structures
|
||||
#endif
|
||||
|
||||
if (nd->bl.subtype == SCRIPT) {
|
||||
ev_db->foreach(ev_db,npc_unload_ev,nd->exname); //Clean up all events related.
|
||||
if (nd->u.scr.timerid != -1) {
|
||||
|
@ -4,6 +4,8 @@
|
||||
#ifndef _NPC_H_
|
||||
#define _NPC_H_
|
||||
|
||||
#include "map.h" // TBL_NPC
|
||||
|
||||
#define START_NPC_NUM 110000000
|
||||
|
||||
#define WARP_CLASS 45
|
||||
|
@ -3,26 +3,21 @@
|
||||
|
||||
#ifdef PCRE_SUPPORT
|
||||
|
||||
#include "../common/timer.h"
|
||||
#include "../common/malloc.h"
|
||||
#include "../common/nullpo.h"
|
||||
#include "../common/showmsg.h"
|
||||
#include "../common/strlib.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>
|
||||
#include <time.h>
|
||||
|
||||
#include "../common/timer.h"
|
||||
#include "../common/malloc.h"
|
||||
#include "../common/version.h"
|
||||
#include "../common/nullpo.h"
|
||||
#include "../common/showmsg.h"
|
||||
|
||||
#include "map.h"
|
||||
#include "status.h"
|
||||
#include "npc.h"
|
||||
#include "chat.h"
|
||||
#include "script.h"
|
||||
#include "battle.h"
|
||||
|
||||
#include "pcre.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
|
||||
|
Loading…
x
Reference in New Issue
Block a user