eqemu-server/zone/parser.cpp
2013-02-16 16:14:39 -08:00

1699 lines
42 KiB
C++
Raw Blame History

// Quest Parser written by Wes, Leave this here =P
//Variables causing crash with linked lists (Bad pointers being added to the lists) - Npcs causing crashes with linked lists
#include <iostream>
#include <ctype.h>
using namespace std;
#include <fstream>
using namespace std;
#include <string>
#include <list>
#include <algorithm>
using namespace std;
#include "../common/debug.h"
#include "entity.h"
#include "masterentity.h"
#include "worldserver.h"
#include "net.h"
#include "../common/skills.h"
#include "../common/classes.h"
#include "../common/races.h"
#include "zonedb.h"
#include "spdat.h"
#include "../common/packet_functions.h"
#include "spawn2.h"
#include "zone.h"
#include "event_codes.h"
#include <time.h>
#include "parser.h"
#include "basic_functions.h"
#include "questmgr.h"
extern Zone* zone;
extern WorldServer worldserver;
extern EntityList entity_list;
#define Parser_DEBUG 1
int mindex1 = 0;
const char * charIn3 = "`~1234567890-=!@#$%^&*_+qwertyuiop[]asdfghjkl'zxcvbnm,./QWERTYUIOP|ASDFGHJKL:ZXCVBNM<>?\"\\";
// MYRA - restore missing commands for qst type files & add itemlink
string cmds("if 0|break 1|spawn 6|spawn2 7|settimer 2|stoptimer 1|rebind 4|echo 1|summonitem 1|selfcast 1|zone 1|castspell 2|say 1|emote 1|shout 1|shout2 1|depop 1|exp 1|level 1|safemove 1|rain 1|snow 1|givecash 4|pvp 1|doanim 1|addskill 2|flagcheck 1|me 1|write 2|settarget 2|follow 1|sfollow 1|save 1|setallskill 1|faction 2|settime 2|setguild 2|setsky 1|setstat 2|movepc 5|gmmove 3|movegrp 4|signal 1|attack 1|itemlink 1|setglobal 4|delglobal 1|targlobal 6|setskill 2|setlanguage 2|stop 0|resume 0|start 1|moveto 3|pause 1|addldonpoints 2|");
//end Myra
int GetArgs(string command)
{
string::iterator iterator = cmds.begin();
string buffer;
string cmd;
string argnum;
while (*iterator) {
if (*iterator == ' ')
{
if (buffer.compare(command)==0) {
cmd = buffer;
buffer="";
}
}
else {
if (*iterator != '|')
buffer += *iterator;
}
if (*iterator == '|')
{
if (!cmd.empty()) {
int argnums = atoi(buffer.c_str());
return argnums;
}
else {
buffer="";
}
}
iterator++;
}
return -1;
}
int calc(string calc)
{
string::iterator iterator = calc.begin();
string buffer;
string integer1;
char op = 0;
int returnvalue = 0;
while (*iterator) {
char ch = *iterator;
if(ch >= '0' && ch <= '9') { //If this character is numeric add it to the buffer
buffer += ch;
}
else if(ch == '+' || ch == '-' || ch == '/' || ch == '*') { //otherwise, are we an operator?
int val = atoi(buffer.c_str());
if (!op) { //if this is the first time through, set returnvalue to what we have so far
returnvalue = val;
}
else { //otherwise we've got returnvalue initialized, perform operation on previous numbers
if (buffer.length() == 0) { //Do we have a value?
printf("Parser::calc() Error in syntax: '%s'.\n", calc.c_str());
return 0;
}
//what was the previous op
switch(op)
{
case '+': {
returnvalue += val;
break;
}
case '-': {
returnvalue -= val;
break;
}
case '/': {
if(val == 0)//can't divide by zero
{
printf("Parser::calc() Error, Divide by zero '%s'.\n", calc.c_str());
return 0;
}
returnvalue /= val;
break;
}
case '*': {
returnvalue *= val;
break;
}
};
op = ch; //save current operator and continue parsing
}
buffer=""; //clear buffer now that we're starting on a new number
op = ch;
}
else {
printf("Parser::calc() Error processing '%c'.\n", ch);
return 0;
}
}
return returnvalue;
}
int Parser::numtok(const char *text, char character) {
int returnvalue=0;
for(; *text != '\0'; text++) {
if(*text == character) returnvalue++;
}
return returnvalue;
}
string strlwr(string tmp) {
string res;
transform(tmp.begin(), tmp.end(), res.begin(), (int(*)(int))tolower);
return(res);
}
int strcmp(const string &com, const string &com2) {
return strcmp(com.c_str(),com2.c_str());
}
string gettok(const char *text, char character, int index)
{
string buffer;
int find=0;
for(; *text != '\0'; *text++)
{
if (*text != character)
buffer += *text;
else {
if (find == index)
break;
buffer = "";
find++;
}
}
return buffer;
}
void Parser::MakeVars(string text, uint32 npcid) {
string buffer;
string temp;
int pos = numtok(text.c_str(),' ')+1;
for(int i=0;i<pos;i++)
{
buffer = gettok(text.c_str(),' ',i).c_str();
temp = (string)itoa(i+1); temp += "."; temp += (string)itoa(npcid);
#if Parser_DEBUG>10
printf("Buffer: %s, temp: %s\n",buffer.c_str(),temp.c_str());
#endif
AddVar(temp,buffer);
temp="";
temp=(string)itoa(i+1) + "-." + (string)itoa(npcid);
AddVar(temp,strstr(text.c_str(),buffer.c_str()));
buffer="";
}
}
int Parser::CheckAliases(const char * alias, uint32 npcid, Mob* npcmob, Mob* mob)
{
/* MyListItem <Alias> * Ptr = AliasList.First;
while (Ptr) {
if ( (uint32)Ptr->Data->npcid == npcid) {
for (int i=0; i <= Ptr->Data->index; i++) {
if (!strcmp(strlwr(Ptr->Data->name[i]),alias)) {
CommandEx(Ptr->Data->command[i], npcid, npcmob, mob);
return 1;
}
}
}
Ptr = Ptr->Next;
}
return 0;*/
return 0;
}
int Parser::pcalc(const char * string) {
char temp[100];
memset(temp, 0, sizeof(temp));
char temp2[100];
memset(temp2, 0, sizeof(temp2));
int p =0;
char temp3[100];
memset(temp3, 0, sizeof(temp3));
char temp4[100];
memset(temp4, 0, sizeof(temp4));
while (strrchr(string,'(')) {
strn0cpy(temp,strrchr(string,'('), sizeof(temp));
for ( unsigned int i=0;i < strlen(temp); i++ ) {
if (temp[i] != '(' && temp[i] != ')') {
temp2[p] = temp[i];
p++;
}
else if (temp[i] == ')') {
snprintf(temp3, sizeof(temp3), "(%s)", temp2);
// Replace(string,temp3,itoa(calc(temp2),temp4,10),0);
memset(temp, 0, sizeof(temp));
memset(temp2, 0, sizeof(temp2));
memset(temp3, 0, sizeof(temp3));
memset(temp4, 0, sizeof(temp4));
p=0;
}
}
}
return calc(string);
}
void Parser::MakeParms(const char * str, uint32 npcid) {
char temp[100];
memset(temp, 0, sizeof(temp));
char temp2[100];
memset(temp2, 0, sizeof(temp2));
char temp3[100];
memset(temp3, 0, sizeof(temp3));
int tmpfor = numtok(str, ',')+1;
for ( int i=0; i < tmpfor; i++) {
memset(temp2, 0, sizeof(temp2));
strn0cpy(temp2, gettok(str, ',', i).c_str(), sizeof(temp2));
snprintf(temp, sizeof(temp), "param%s.%d", itoa(i+1 ,temp3, 10),npcid);
AddVar(temp, temp2);
}
}
int Parser::GetItemCount(string itemid, uint32 npcid)
{
string temp;
int a=0;
for (int i=1;i<5;i++)
{
temp = (string)"item" + (string)itoa(i);
if (!GetVar(temp,npcid).compare(itemid))
a++;
temp="";
}
return a;
}
int Parser::HasQuestFile(uint32 npcid)
{
int32 qstID = GetNPCqstID(npcid);
int success=1;
if (qstID==-1)
success = LoadScript(npcid, zone->GetShortName());
if (!success)
return false;
return true;
}
void Parser::Event(QuestEventID event, uint32 npcid, const char * data, NPC* npcmob, Mob* mob, uint32 extradata) {
if (npcid == 0)
return;
if(event >= _LargestEventID)
return;
int32 qstID = GetNPCqstID(npcid);
int success=1;
if (qstID==-1)
success = LoadScript(npcid, zone->GetShortName(),mob);
if (!success)
return;
else
qstID = GetNPCqstID(npcid);
// SCORPIOUS2K - load global variables
if (npcmob->GetQglobal())
{
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
MYSQL_ROW row;
char tmpname[65];
int charid=0;
if (mob && mob->IsClient()) // some events like waypoint and spawn don't have a player involved
{
charid=mob->CastToClient()->CharacterID();
}
else
{
charid=0-npcmob->GetNPCTypeID(); // make char id negative npc id as a fudge
}
AddVar("charid.g",itoa(charid));
database.RunQuery(query, MakeAnyLenString(&query,
"SELECT name,value FROM quest_globals WHERE (npcid=%i || npcid=0) && (charid=%i || charid=0) && (zoneid=%i || zoneid=0) && expdate >= unix_timestamp(now())",
npcmob->GetNPCTypeID(),charid,zone->GetZoneID()), errbuf, &result);
printf("%s\n",query);
printf("%s\n",errbuf);
if (result)
{
printf("Loading global variables for %s\n",npcmob->GetName());
while ((row = mysql_fetch_row(result)))
{
sprintf(tmpname,"%s.g",row[0]);
AddVar(tmpname, row[1]);
}
mysql_free_result(result);
}
if (query)
{
safe_delete_array(query);
query=0;
}
}
if (event == EVENT_TIMER)
{
AddVar("timername.g",data);
}
if (event == EVENT_SIGNAL)
{
AddVar("signal.g",data);
}
uint8 fac = 0;
if (mob && mob->IsClient()) {
AddVar("uguild_id.g", itoa(mob->CastToClient()->GuildID()));
AddVar("uguildrank.g", itoa(mob->CastToClient()->GuildRank()));
}
if (mob && npcmob && mob->IsClient() && npcmob->IsNPC()) {
Client* client = mob->CastToClient();
NPC* npc = npcmob->CastToNPC();
// Need to figure out why one of these casts would fail..
if (client && npc) {
fac = client->GetFactionLevel(client->GetID(), npcmob->GetID(), client->GetRace(), client->GetClass(), DEITY_AGNOSTIC, npc->GetPrimaryFaction(), npcmob);
}
else if (!client) {
cerr << "WARNING: cast failure on mob->CastToClient()" << endl;
}
else if (!npc) {
cerr << "WARNING: cast failure on npcmob->CastToNPC()" << endl;
}
}
if (mob) {
AddVar("name.g", mob->GetName());
AddVar("race.g", GetRaceName(mob->GetRace()));
AddVar("class.g", GetEQClassName(mob->GetClass()));
AddVar("ulevel.g", itoa(mob->GetLevel()));
AddVar("userid.g", itoa(mob->GetID()));
}
if (npcmob)
{
AddVar("mname.g",npcmob->GetName());
}
if (fac) {
AddVar("faction.g", itoa(fac));
}
if (zone) {
// SCORPIOUS2K- added variable zoneid
AddVar("zoneid.g",itoa(zone->GetZoneID()));
AddVar("zoneln.g",zone->GetLongName());
AddVar("zonesn.g",zone->GetShortName());
}
string temp;
#if Parser_DEBUG>10
printf("Data: %s,Id: %i\n",data,npcid);
#endif
switch (event) {
case EVENT_SAY: {
MakeVars(data, npcid);
npcmob->FaceTarget(mob);
SendCommands("event_say", qstID, npcmob, mob);
break;
}
case EVENT_TIMER: {
SendCommands("event_timer", qstID, npcmob, mob);
break;
}
case EVENT_DEATH: {
SendCommands("event_death", qstID, npcmob, mob);
break;
}
case EVENT_ITEM: {
npcmob->FaceTarget(mob);
SendCommands("event_item", qstID, npcmob, mob);
break;
}
case EVENT_SPAWN: {
SendCommands("event_spawn", qstID, npcmob, mob);
break;
}
case EVENT_ATTACK: {
SendCommands("event_attack", qstID, npcmob, mob);
break;
}
case EVENT_COMBAT: {
SendCommands("event_combat", qstID, npcmob, mob);
break;
}
case EVENT_SLAY: {
SendCommands("event_slay", qstID, npcmob, mob);
break;
}
case EVENT_NPC_SLAY: {
SendCommands("event_npc_slay", qstID, npcmob, mob);
break;
}
case EVENT_WAYPOINT_ARRIVE: {
temp = "wp." + (string)itoa(npcid);
AddVar(temp,data);
SendCommands("event_waypoint_arrive", qstID, npcmob, mob);
break;
}
case EVENT_WAYPOINT_DEPART: {
temp = "wp." + (string)itoa(npcid);
AddVar(temp,data);
SendCommands("event_waypoint_depart", qstID, npcmob, mob);
break;
}
case EVENT_SIGNAL: {
SendCommands("event_signal", qstID, npcmob, mob);
break;
}
case EVENT_AGGRO: {
SendCommands("event_aggro", qstID, npcmob, mob);
break;
}
case EVENT_ENTER: {
SendCommands("event_enter", qstID, npcmob, mob);
break;
}
case EVENT_EXIT: {
SendCommands("event_exit", qstID, npcmob, mob);
break;
}
case EVENT_AGGRO_SAY: {
MakeVars(data, npcid);
SendCommands("event_aggro_say", qstID, npcmob, mob);
break;
}
default: {
// should we do anything here?
break;
}
}
DelChatAndItemVars(npcid);
}
Parser::Parser() : DEFAULT_QUEST_PREFIX("default") {
MainList.clear();
pMaxNPCID = database.GetMaxNPCType();
/*pNPCqstID = new int32[pMaxNPCID+1];
for (uint32 i=0; i<pMaxNPCID+1; i++)
pNPCqstID[i] = -1;*/
pNPCqstID = new int32[1];
npcarrayindex=1;
}
Parser::~Parser() {
MainList.clear();
varlist.clear();
AliasList.clear();
safe_delete_array(pNPCqstID);
}
bool Parser::LoadAttempted(uint32 iNPCID) {
if (iNPCID > pMaxNPCID)
return false;
return (bool) (FindNPCQuestID(iNPCID) != 0);
}
uint32 Parser::FindNPCQuestID(int32 npcid){
for(uint32 i=0;i<npcarrayindex;i++)
if(pNPCqstID[i]==npcid)
return i;
return 0;
}
uint32 Parser::AddNPCQuestID(uint32 npcid){
int32* newpNPCqstID= new int32[npcarrayindex+2];
for(uint32 i=0;i<npcarrayindex;i++)
newpNPCqstID[i]=pNPCqstID[i];
newpNPCqstID[npcarrayindex]=npcid;
npcarrayindex++;
safe_delete_array(pNPCqstID);
/* pNPCqstID = new int32[npcarrayindex+1];
for(uint32 j=0;j<npcarrayindex;j++)
pNPCqstID[j]=newpNPCqstID[j];
safe_delete_array(newpNPCqstID);*/
pNPCqstID = newpNPCqstID;
return npcarrayindex-1;
}
bool Parser::SetNPCqstID(uint32 iNPCID, int32 iValue) {
if (iNPCID > pMaxNPCID)
return false;
uint32 idx = FindNPCQuestID(iNPCID);
if(idx)
pNPCqstID[idx] = iValue;
else{
idx=AddNPCQuestID(iNPCID);
pNPCqstID[idx] = iValue;
}
return true;
}
int32 Parser::GetNPCqstID(uint32 iNPCID) {
if (iNPCID > pMaxNPCID || iNPCID == 0)
return -1;
if(uint32 idx=FindNPCQuestID(iNPCID))
return pNPCqstID[idx];
else
return -1;
}
void Parser::ClearCache() {
#if Parser_DEBUG >= 2
cout << "Parser::ClearCache" << endl;
#endif
//for (uint32 i=0; i<pMaxNPCID+1; i++)
// pNPCqstID[i] = -1;
MainList.clear();
safe_delete_array(pNPCqstID);
pNPCqstID = new int32[1];
npcarrayindex=1;
}
void Parser::SendCommands(const char * event, uint32 npcid, NPC* npcmob, Mob* mob) {
iter_events listIt = MainList.begin();
Events *p;
EventList *pp;
while (listIt != MainList.end())
{
p = *listIt;
iter_eventlist listIt2 = p->Event.begin();
if ( p->npcid == npcid ) {
if(mob && mob->IsClient())
quest_manager.StartQuest(npcmob, mob->CastToClient());
else
quest_manager.StartQuest(npcmob, NULL);
while (listIt2 != p->Event.end())
{
pp = *listIt2;
if (pp && !strcmp(strlwr(pp->event.c_str()),strlwr(event))) {
#if Parser_DEBUG>10
printf("PP command: %s\n",pp->command.c_str());
#endif
ParseCommands(pp->command,0,0,npcid,npcmob,mob);
}
listIt2++;
}
quest_manager.EndQuest();
return;
}
listIt++;
}
}
void Parser::scanformat(char *string, const char *format, char arg[10][1024])
{
int increment_arglist = 0;
int argnum = 0;
int i = 0;
char lookfor = 0;
// someone forgot to set string or format
if(!format)
return;
if(!string)
return;
for(;;)
{
// increment while they're the same (and not NULL)
while(*format && *string && *format == *string) {
format++;
string++;
}
// format string is gone
if(!format)
break;
// string is gone while the format string is still there (ERRor)
if(!string)
return;
// the format string HAS to be equal to <20> or else things are messed up
if(*format != '<EFBFBD>')
return;
format++;
lookfor = *format; // copy until we find char after 'y'
format++;
if(!lookfor)
break;
// start on a new arg
if(increment_arglist) {
arg[argnum][i] = 0;
argnum++;
}
increment_arglist = 1; // we found the first crazy y
i = 0; // reset index
while(*string && *string != lookfor)
arg[argnum][i++] = *string++;
string++;
}
// final part of the string
if(increment_arglist) {
arg[argnum][i] = 0;
argnum++;
i = 0;
}
while(*string)
arg[argnum][i++] = *string++;
arg[argnum][i] = 0;
}
void Parser::ClearEventsByNPCID(uint32 iNPCID) {
list<Events*>::iterator iterator = MainList.begin();
Events* p;
while (iterator != MainList.end())
{
p = *iterator;
if (p->npcid == iNPCID) {
p->Event.clear();
return;
}
iterator++;
}
}
void Parser::ClearAliasesByNPCID(uint32 iNPCID) {
/* MyListItem<Alias>* Ptr = AliasList.First;
MyListItem<Alias>* next = 0;
while (Ptr) {
next = Ptr->Next;
if ( (uint32)Ptr->Data->npcid == iNPCID) {
AliasList.DeleteItemAndData(Ptr);
}
Ptr = next;
}*/
}
void Parser::ExCommands(string o_command, string parms, int argnums, uint32 npcid, Mob* other, Mob* mob )
{
char arglist[10][1024];
//Work out the argument list, if there needs to be one
#if Parser_DEBUG>10
printf("Parms: %s\n", parms.c_str());
#endif
if (argnums > 1) {
string buffer;
string::iterator iterator = parms.begin();
int quote=0,alist=0,ignore=0;
while (1) {
if (*iterator == '"') {
if (quote) quote--;
else { quote++; if (buffer.empty()) ignore=1; }
}
if (((*iterator != '"' && *iterator != ',' && *iterator != ' ' && *iterator != ')') || quote) && !ignore) {
buffer+=*iterator;
}
if (ignore && *iterator == '"')ignore--;
if ((*iterator == ',' && !quote)) {
strcpy(arglist[alist],buffer.c_str());
alist++;
buffer="";
}
if (iterator == parms.end())
{
strcpy(arglist[alist],buffer.c_str());
alist++;
break;
}
iterator++;
}
}
else {
string::iterator iterator = parms.begin();
if (*iterator == '"')
{
int quote=0,ignore=0; //once=0
string tmp;
while (iterator != parms.end())
{
if (*iterator == '"')
{
if (quote)quote--;
else quote++;
ignore++;
}
if (!ignore && (quote || (*iterator != '"')))
tmp+=*iterator;
else if (*iterator == '"' && ignore)
ignore--;
iterator++;
}
strcpy(arglist[0],tmp.c_str());
}
else
strcpy(arglist[0],parms.c_str());
}
#if Parser_DEBUG>10
printf("After: %s\n", arglist[0]);
#endif
char command[256];
strncpy(command, o_command.c_str(), 255);
command[255] = 0;
char *cptr = command;
while(*cptr != '\0') {
if(*cptr >= 'A' && *cptr <= 'Z')
*cptr = *cptr + ('a' - 'A');
*cptr++;
}
if (!strcmp(command,"write")) {
quest_manager.write(arglist[0], arglist[1]);
}
else if (!strcmp(command,"me")) {
// MYRA - fixed comma bug for me command
quest_manager.me(parms.c_str());
//end Myra
}
else if (!strcmp(command,"spawn") || !strcmp(command,"spawn2"))
{
float hdng;
if (!strcmp(command,"spawn"))
{
hdng=mob->CastToClient()->GetHeading();
}
else
{
hdng=atof(arglist[6]);
}
quest_manager.spawn2(atoi(arglist[0]), atoi(arglist[1]), 0,
atof(arglist[3]), atof(arglist[4]), atof(arglist[5]), hdng);
}
else if (!strcmp(command,"unique_spawn"))
{
float hdng;
hdng=mob->CastToClient()->GetHeading();
quest_manager.unique_spawn(atoi(arglist[0]), atoi(arglist[1]), 0,
atof(arglist[3]), atof(arglist[4]), atof(arglist[5]), hdng);
}
else if (!strcmp(command,"echo")) {
quest_manager.echo(atoi(arglist[0]), parms.c_str());
}
else if (!strcmp(command,"summonitem")) {
quest_manager.summonitem(atoi(arglist[0]));
}
else if (!strcmp(command,"setstat")) {
quest_manager.setstat(atoi(arglist[0]), atoi(arglist[1]));
}
else if (!strcmp(command,"setanim")) {
quest_manager.setanim(atoi(arglist[0]), atoi(arglist[1]));
}
else if (!strcmp(command,"castspell")) {
quest_manager.castspell(atoi(arglist[1]), atoi(arglist[0]));
}
else if (!strcmp(command,"selfcast")) {
quest_manager.selfcast(atoi(arglist[0]));
}
else if (!strcmp(command,"addloot")) {//Cofruben: add an item to the mob.
quest_manager.addloot(atoi(arglist[0]),atoi(arglist[1]));
}
else if (!strcmp(command,"zone")) {
quest_manager.Zone(arglist[0]);
}
else if (!strcmp(command,"settimer")) {
quest_manager.settimer(arglist[0], atoi(arglist[1]));
}
else if (!strcmp(command,"say")) {
quest_manager.say(parms.c_str());
}
else if (!strcmp(command,"stoptimer")) {
quest_manager.stoptimer(arglist[0]);
}
else if (!strcmp(command,"emote")) {
quest_manager.emote(parms.c_str());
}
else if (!strcmp(command,"shout2")) {
quest_manager.shout2(parms.c_str());
}
else if (!strcmp(command,"shout")) {
quest_manager.shout(parms.c_str());
}
else if (!strcmp(command,"gmsay")) {
quest_manager.shout2(parms.c_str());
}
else if (!strcmp(command,"depop")) {
quest_manager.depop(atoi(arglist[0]));
}
else if (!strcmp(command,"settarget")) {
quest_manager.settarget(arglist[0], atoi(arglist[1]));
}
else if (!strcmp(command,"follow")) {
quest_manager.follow(atoi(arglist[0]), atoi(arglist[1]));
}
else if (!strcmp(command,"sfollow")) {
quest_manager.sfollow();
}
else if (!strcmp(command,"changedeity")) {
quest_manager.changedeity(atoi(arglist[0]));
}
else if (!strcmp(command,"exp")) {
quest_manager.exp(atoi(arglist[0]));
}
else if (!strcmp(command,"level")) {
quest_manager.level(atoi(arglist[0]));
}
else if (!strcmp(command,"traindisc")) {
quest_manager.traindisc(atoi(arglist[0]));
}
else if (!strcmp(command,"safemove")) {
quest_manager.safemove();
}
else if (!strcmp(command,"rain")) {
quest_manager.rain(atoi(arglist[0]));
}
else if (!strcmp(command,"snow")) {
quest_manager.snow(atoi(arglist[0]));
}
else if (!strcmp(command,"surname")) {
quest_manager.surname(arglist[0]);
}
else if (!strcmp(command,"permaclass")) {
quest_manager.permaclass(atoi(arglist[0]));
}
else if (!strcmp(command,"permarace")) {
quest_manager.permarace(atoi(arglist[0]));
}
else if (!strcmp(command,"permagender")) {
quest_manager.permagender(atoi(arglist[0]));
}
else if (!strcmp(command,"scribespells")) {
quest_manager.scribespells(atoi(arglist[0]));
}
else if (!strcmp(command,"traindiscs")) {
quest_manager.traindiscs(atoi(arglist[0]));
}
else if (!strcmp(command,"givecash")) {
quest_manager.givecash(atoi(arglist[0]), atoi(arglist[1]), atoi(arglist[2]), atoi(arglist[3]));
}
else if (!strcmp(command,"pvp")) {
quest_manager.pvp(arglist[0]);
}
else if (!strcmp(command,"movepc")) {
quest_manager.movepc((atoi(arglist[0])),(atof(arglist[1])),(atof(arglist[2])),(atof(arglist[3])),(atof(arglist[4])));
}
else if (!strcmp(command,"gmmove")) {
quest_manager.gmmove(atof(arglist[0]), atof(arglist[1]), atof(arglist[2]));
}
else if (!strcmp(command,"movegrp")) {
quest_manager.movegrp((atoi(arglist[0])),(atof(arglist[1])),(atof(arglist[2])),(atof(arglist[3])));
}
else if (!strcmp(command,"doanim")) {
quest_manager.doanim(atoi(arglist[0]));
}
else if (!strcmp(command,"addskill")) {
quest_manager.addskill(atoi(arglist[0]), atoi(arglist[1]));
}
else if (!strcmp(command,"setlanguage")) {
quest_manager.setlanguage(atoi(arglist[0]), atoi(arglist[1]));
}
else if (!strcmp(command,"setskill")) {
quest_manager.setskill(atoi(arglist[0]), atoi(arglist[1]));
}
else if (!strcmp(command,"setallskill")) {
quest_manager.setallskill(atoi(arglist[0]));
}
else if (!strcmp(command,"attack")) {
quest_manager.attack(arglist[0]);
}
else if (!strcmp(command,"save")) {
quest_manager.save();
}
/*else if (!strcmp(command,"flagcheck")) {
quest_manager.flagcheck(atoi(arglist[0]), atoi(arglist[1]));
}*/
else if (!strcmp(command,"faction")) {
quest_manager.faction(atoi(arglist[0]), atoi(arglist[1]), atoi(arglist[2]));
}
else if (!strcmp(command,"setsky")) {
quest_manager.setsky(atoi(arglist[0]));
}
else if (!strcmp(command,"setguild")) {
quest_manager.setguild(atoi(arglist[0]), atoi(arglist[1]));
}
else if (!strcmp(command,"settime")) {
quest_manager.settime(atoi(arglist[0]), atoi(arglist[1]));
}
else if (!strcmp(command,"itemlink")) {
quest_manager.itemlink(atoi(arglist[0]));
}
else if (!strcmp(command,"signal")) {
quest_manager.signal(atoi(arglist[0]));
}
else if (!strcmp(command,"setglobal")) {
quest_manager.setglobal(arglist[0], arglist[1], atoi(arglist[2]), arglist[3]);
}
else if (!strcmp(command,"targlobal")) {
quest_manager.targlobal(arglist[0], arglist[1], arglist[2], atoi(arglist[3]), atoi(arglist[4]), atoi(arglist[5]));
}
else if (!strcmp(command,"ding")) {
quest_manager.ding();
}
else if (!strcmp(command,"delglobal")) {
quest_manager.delglobal(arglist[0]);
}
else if (!strcmp(command,"rebind")) {
quest_manager.rebind((atoi(arglist[0])),(atof(arglist[1])),(atof(arglist[2])),(atof(arglist[3])));
}
else if (!strcmp(command,"stop")) {
quest_manager.stop();
}
else if (!strcmp(command,"pause")) {
quest_manager.pause(atoi(arglist[0]));
}
else if (!strcmp(command,"moveto")) {
quest_manager.moveto(atof(arglist[0]), atof(arglist[1]), atof(arglist[2]), atof(arglist[3]), atoi(arglist[4]));
}
else if (!strcmp(command,"pathto")) {
quest_manager.pathto(atof(arglist[0]), atof(arglist[1]), atof(arglist[2]));
}
else if (!strcmp(command,"showpath")) {
quest_manager.showpath(atof(arglist[0]), atof(arglist[1]), atof(arglist[2]));
}
else if (!strcmp(command,"showgrid")) {
quest_manager.showgrid(atoi(arglist[0]));
}
else if (!strcmp(command,"toggle_spawn_event")) {
quest_manager.toggle_spawn_event(atoi(arglist[0]),(atoi(arglist[1])!=0),(atoi(arglist[2])!=0));
}
else if (!strcmp(command,"spawn_condition")) {
quest_manager.spawn_condition(arglist[0], 0, atoi(arglist[1]), atoi(arglist[2]));
}
else if (!strcmp(command,"resume")) {
quest_manager.resume();
}
else if (!strcmp(command,"start")) {
quest_manager.start(atoi(arglist[0]));
}
else if (!strcmp(command,"addldonpoints")) {
quest_manager.addldonpoints(atoi(arglist[0]), atoi(arglist[1]));
}
else if (!strcmp(command,"setnexthpevent")) {
quest_manager.setnexthpevent(atoi(arglist[0]));
}
else if (!strcmp(command,"setnextinchpevent")) {
quest_manager.setnextinchpevent(atoi(arglist[0]));
}
else if (!strcmp(command,"clear_zone_flag")) {
quest_manager.clear_zone_flag(atoi(arglist[0]));
}
else if (!strcmp(command,"set_zone_flag")) {
quest_manager.set_zone_flag(atoi(arglist[0]));
}
else if (!strcmp(command,"set_proximity")) {
float v1 = atof(arglist[4]);
float v2 = atof(arglist[5]);
if(v1 == v2) //omitted, or wrong, either way, skip them
quest_manager.set_proximity(atof(arglist[0]), atof(arglist[1]), atof(arglist[2]), atof(arglist[3]));
else
quest_manager.set_proximity(atof(arglist[0]), atof(arglist[1]), atof(arglist[2]), atof(arglist[3]), v1, v2);
}
else if (!strcmp(command,"clear_proximity")) {
quest_manager.clear_proximity();
}
else if (!strcmp(command,"respawn"))
{
quest_manager.respawn(atoi(arglist[0]), atoi(arglist[1]));
}
else
printf("\nUnknown perl function used:%s",command);
}
int Parser::LoadScript(int npcid, const char * zone, Mob* activater)
{
SetNPCqstID(npcid, npcid);
ClearEventsByNPCID(npcid);
ClearAliasesByNPCID(npcid);
//string strnpcid = ("default");
string strnpcid = (DEFAULT_QUEST_PREFIX);
if (npcid)
strnpcid = itoa(npcid);
string filename;
filename = "./quests/" + (string)zone + "/" + (string)strnpcid + ".qst";
string line,buffer,temp;
ifstream file( filename.c_str() );
if (!file)
{
if (npcid) {
SetNPCqstID(npcid, 0);
LoadScript(0, zone);
}
else
SetNPCqstID(0, -1);
}
int quote=0,ignore=0,bracket=0,line_num=0,paren=0;
EventList* event1 = new EventList;
Events * NewEventList = new Events;
while (file && !file.eof())
{
getline(file,line);
string::iterator iterator = line.begin();
while (*iterator)
{
if (iterator[0] == '/' && iterator[1] == '/') break;
if (!ignore && *iterator == '/' && iterator[1] == '*') { ignore++; iterator++; iterator++; }
if (*iterator == '*' && iterator[1] == '/') { ignore--; iterator++; iterator++; }
if (!ignore && (strchr(charIn,*iterator) || quote || paren))
buffer+=*iterator;
if (!ignore)
{
if (*iterator == '{')
{
bracket++;
if (bracket == 1)
{
event1 = new EventList;
NewEventList->npcid = npcid;
buffer.replace(buffer.length()-1,buffer.length(),"");
event1->event = buffer;
buffer="";
}
}
if (*iterator == '}')
{
bracket--;
if (bracket == 0)
{
buffer.replace(buffer.length()-1,buffer.length(),"");
int heh = ParseCommands(buffer,line_num,0,0,0,0,filename);
if (!heh){
safe_delete_array(NewEventList);
return 0;
}
event1->command = buffer;
buffer="";
NewEventList->Event.push_back(event1);
}
if (bracket==-1)
{
if(activater && activater->IsClient())
activater->CastToClient()->Message(10,"Line: %d,File: %s | error C0006: syntax error : too many ')'s",line_num,filename.c_str());
return 0;
}
}
if (*iterator == '"')if(quote)quote--;else quote++;
if (*iterator == '(')paren++;
if (*iterator == ')')paren--;
}
iterator++;
}
line_num++;
}
MainList.push_back(NewEventList);
return 1;
}
void Parser::Replace(string& string1, string repstr, string rep, int all) {
while (string1.find(repstr.c_str()) != string::npos) {
string1.replace(string1.find(repstr.c_str()),repstr.length(),rep.c_str());
if (!all)
break;
}
}
string Parser::GetVar(string varname, uint32 npcid)
{
list<vars*>::iterator iterator = varlist.begin();
vars * p;
string checkfirst;
string checksecond;
checkfirst = varname + (string)"." + (string)itoa(npcid);
checksecond = varname + (string)".g";
while(iterator != varlist.end())
{
p = *iterator;
if (!strcasecmp(p->name.c_str(), checkfirst.c_str()) || !strcasecmp(p->name.c_str(),checksecond.c_str()))
{
printf("GetVar(%s) = '%s'\n", varname.c_str(), p->value.c_str());
return p->value;
}
iterator++;
}
checkfirst="";
checkfirst = "NULL";
return checkfirst;
}
void Parser::DeleteVar(string name)
{
list<vars*>::iterator iterator = varlist.begin();
vars* p;
while(iterator != varlist.end())
{
p = *iterator;
if (!p->name.compare(name))
{
varlist.erase(iterator);
return;
}
iterator++;
}
}
void Parser::DelChatAndItemVars(uint32 npcid)
{
// MyListItem <vars> * Ptr;
string temp;
int i=0;
for (i=0;i<10;i++)
{
temp = (string)itoa(i) + "." + (string)itoa(npcid);
DeleteVar(temp);
temp = (string)itoa(i) + "-." + (string)itoa(npcid);
DeleteVar(temp);
}
for (i=1;i<5;i++)
{
temp = "item"+(string)itoa(i) + "." + (string)itoa(npcid);
DeleteVar(temp);
temp = "item"+(string)itoa(i) + ".stack." + (string)itoa(npcid);
DeleteVar(temp);
}
}
void Parser::AddVar(string varname, string varval)
{
list<vars*>::iterator iterator = varlist.begin();
vars* p;
while(iterator != varlist.end())
{
p = *iterator;
if (!p->name.compare(varname))
{
p->value="";
p->value = varval;
return;
}
iterator++;
}
vars * newvar = new vars;
newvar->name = varname;
newvar->value = varval;
varlist.push_back(newvar);
}
void Parser::HandleVars(string varname, string varparms, string& origstring, string format, uint32 npcid, Mob* mob)
{
string tempvar;
tempvar = GetVar(varname,npcid);
char arglist[10][1024];
string::iterator iterator = varparms.begin();
string buffer;
int quote=0;
int alist=0;
while (*iterator)
{
if (*iterator != '"' && *iterator != ',' && *iterator != ' ' || (quote && *iterator != '"'))
buffer+=*iterator;
if (*iterator == '"')
{
if (quote)quote--;
else quote++;
}
if (*iterator == ',' && !quote)
{
strcpy(arglist[alist],buffer.c_str());
alist++;
buffer="";
}
iterator++;
}
strcpy(arglist[alist],buffer.c_str());
if (!strcmp(strlwr((const char*)varname.c_str()),"mid")) {
int pos=0;
int one = atoi(arglist[1]);
int two = atoi(arglist[2]);
string buffer2;
string find = arglist[0];
string::iterator iterator = find.begin();
while (*iterator)
{
pos++;
if (pos>=one)
buffer2+=*iterator;
if (pos==two)
break;
iterator++;
}
Replace(origstring,format,buffer2.c_str());
}
else if (!strcmp(strlwr((const char*)varname.c_str()),"+")) {
string temp;
temp = (string)" "+format+(string)" ";
Replace(origstring, temp, " REPLACETHISSHIT ",1);
}
else if (!strcmp(strlwr((const char*)varname.c_str()),"replace")) {
string temp;
temp = (string)arglist[0];
Replace(temp, arglist[1], arglist[2],1);
Replace(origstring, format, temp);
}
else if (!strcmp(strlwr(varname.c_str()),"itemcount")) {
string temp;
int o=0;
o = GetItemCount(varparms,npcid);
temp = (string)itoa(o);
Replace(origstring,format,temp,1);
}
else if (!strcmp(strlwr(varname.c_str()),"calc")) {
Replace(origstring,format,itoa(pcalc(varparms.c_str())));
}
else if (!strcmp(strlwr(varname.c_str()),"status") && mob && mob->IsClient()) {
Replace(origstring,format,itoa(mob->CastToClient()->Admin()));
}
else if (!strcmp(strlwr(varname.c_str()),"hasitem") && mob && mob->IsClient()) {
int has=0;
for (int i=0; i<=30;i++) {
if (mob->CastToClient()->GetItemIDAt(i) == (uint32) atoi(varparms.c_str())) {
Replace(origstring,format,"true");
has = 1;
break;
}
}
if (!has)
Replace(origstring,format,"false");
}
else if (!strcmp(strlwr((const char*)varname.c_str()),"read")) {
ifstream file(arglist[0]);
if (file)
{
string line;
int index=0,stop=atoi(arglist[1]);
while (!file.eof())
{
getline(file,line);
if (index == stop)break;
index++;
}
Replace(origstring,format,line);
}
}
else if (!strcmp(strlwr((const char*)varname.c_str()),"npc_status")) {
Mob * tmp;
if (!atoi(varparms.c_str())) {
tmp = entity_list.GetMob(varparms.c_str());
}
else {
tmp = entity_list.GetMobByNpcTypeID(atoi(varparms.c_str()));
}
if (tmp && tmp->GetHP() > 0) Replace(origstring,format,"up");
else Replace(origstring,format,"down");
}
else if (!strcmp(strlwr((const char*)varname.c_str()),"strlen")) {
Replace(origstring,format,itoa(varparms.length()-1));
}
else if (!strcmp(strlwr((const char*)varname.c_str()),"chr")) {
char temp[4];
memset(temp, 0x0, 4);
temp[0] = atoi(varparms.c_str());
Replace(origstring,format,temp);
}
//used_pawn - random implementation.
else if (!strcmp(strlwr((const char*)varname.c_str()),"random")) {
Replace(origstring,format,itoa(MakeRandomInt(0, varparms[0]-1)));
}
else if (!strcmp(strlwr((const char*)varname.c_str()),"asc")) {
Replace(origstring,format,itoa(varparms[0]));
}
else if (!strcmp(strlwr((const char*)varname.c_str()),"gettok")) {
Replace(origstring,format,gettok(arglist[0],arglist[1][0],atoi(arglist[2])));
}
else {
Replace(origstring,format,tempvar);
}
gClient = 0;
}
void Parser::ParseVars(string& text, uint32 npcid, Mob* mob)
{
if (text.find("$") == string::npos && text.find("%") == string::npos)
return;
string buffer2;
string fname;
string parms;
while (text.find("%") != string::npos)
{
string temp;
temp = (string)text.substr(text.find("%")).c_str();
string::iterator iterator = temp.begin();
string buffer;
while (*iterator)
{
if (!strrchr(notin,*iterator))
buffer+=*iterator;
else
{
HandleVars(buffer,0,text,buffer,npcid,mob);
Replace(text,buffer,"testing",0);
break;
}
iterator++;
}
}
while (text.find("$") != string::npos)
{
string temp;
temp = (string)text.substr(text.rfind("$")).c_str();
string::iterator iterator = temp.begin();
int paren=0;
int fin=0;
string buffer;
while (iterator != temp.end())
{
if (!strrchr(notin,*iterator) || paren)
{
if (*iterator != '(' && *iterator != ')')
buffer+=*iterator;
}
else
{
buffer.replace(0,1,"",0);
HandleVars(buffer,"",text,buffer2,npcid,mob);
buffer="";
buffer2="";
break;
}
buffer2+=*iterator;
if (*iterator == '(')
{
paren++;
if (paren == 1)
{
fname = buffer;
buffer="";
}
}
if (*iterator == ')')
{
paren--;
if (paren == 0)
{
parms = buffer;
fname.replace(0,1,"",0);
HandleVars(fname,parms,text,buffer2,npcid,mob);
buffer="";
buffer2="";
parms="";
fname="";
fin=1;
break;
}
}
iterator++;
}
}
}
/*
char * fixstring(char * string)
{
char tmp[255];
memset(tmp,0x0,255);
static char tmp2[255];
memset(tmp2,0x0,255);
int quote=0;
int o=0;
strcpy(tmp,string);
uint32 len = strlen(tmp);
for (uint32 i=0;i<len;i++)
{
if (quote || tmp[i] != ' ') {
tmp2[o] = tmp[i];
o++;
}
if (tmp[i] == '"')
if (quote) quote--;
else quote++;
}
return tmp2;
}*/
int DoCompare(string compare1, string sign, string compare2)
{
#if Parser_DEBUG>10
printf("compare1: %s,sign: %s, compare2: %s\n",compare1.c_str(),sign.c_str(),compare2.c_str());
#endif
if (!strcmp(sign.c_str(),"==")) {
if (strcmp(strlwr((const char*)compare1.c_str()),strlwr((const char*)compare2.c_str())))
return 0;
}
else if (!strcmp(sign.c_str(),"!=")) {
if (!strcmp(strlwr((const char*)compare1.c_str()),strlwr((const char*)compare2.c_str())))
return 0;
}
else if (!strcmp(sign.c_str(),"=~")) {
if (!strstr(strlwr(compare1.c_str()).c_str(),strlwr(compare2.c_str()).c_str()))
return 0;
}
else if (!strcmp(sign.c_str(),"!~")) {
if (strstr(strlwr(compare1.c_str()).c_str(),strlwr(compare2.c_str()).c_str()))
return 0;
}
else if (!strcmp(sign.c_str(),"<")) {
if (atoi(compare1.c_str()) > atoi(compare2.c_str()) || atoi(compare1.c_str()) == atoi(compare2.c_str()))
return 0;
}
else if (!strcmp(sign.c_str(),">")) {
if (atoi(compare1.c_str()) < atoi(compare2.c_str()) || atoi(compare1.c_str()) == atoi(compare2.c_str()))
return 0;
}
else if (!strcmp(sign.c_str(),"<=")) {
if (atoi(compare1.c_str()) > atoi(compare2.c_str()) || atoi(compare1.c_str()) != atoi(compare2.c_str()))
return 0;
}
else if (!strcmp(sign.c_str(),">=")) {
if (atoi(compare1.c_str()) < atoi(compare2.c_str()) || atoi(compare1.c_str()) != atoi(compare2.c_str()))
return 0;
}
return 1;
}
int Parser::ParseIf(string text)
{
string::iterator iterator = text.begin();
string com1,com2,sign,next,buffer;
while (*iterator)
{
if (!strchr(notin,*iterator))
buffer+=*iterator;
if (*iterator == '=' || *iterator == '!' || *iterator == '~')
{
sign+=*iterator;
if (sign.length() == 1)
{
com1 = buffer;
buffer="";
next="";
}
}
if ((*iterator == '<' || *iterator == '>') && iterator[1] != '=')
{
sign+=*iterator;
if (sign.length() == 1)
{
com1 = buffer;
buffer="";
next="";
}
iterator++;
}
if (*iterator == '&' || *iterator == '|')
{
next+=*iterator;
if (next.length() == 1)
{
com2 = buffer;
buffer="";
}
if (next.length() == 2)
{
if (!DoCompare(com1,sign,com2) && strcmp(next.c_str(),"||"))
return 0;
com1="";
sign="";
com2="";
}
}
iterator++;
if (iterator == text.end()) {
com2 = buffer;
//com2.replace(0,1,"");
buffer="";
if (!DoCompare(com1,sign,com2))
return 0;
}
}
return 1;
}
int Parser::ParseCommands(string text, int line, int justcheck, uint32 npcid, Mob* other, Mob* mob, std::string filename)
{
string buffer,command,parms,temp,temp2;
temp2 = text;
ParseVars(temp2,npcid,mob);
int bracket=0,paren=0,lastif=0,last_finished=0,quote=0,escape=0,ignore=0,argnums=0,argit=1;
string::iterator iterator = temp2.begin();
while (iterator != temp2.end())
{
if (*iterator == '\\' && !escape) {
escape++;
}
//"`~1234567890-=!@#$%^&*_+qwertyuiop[]asdfghjkl'zxcvbnm,./QWERTYUIOP|ASDFGHJKL:ZXCVBNM<>?\"\\"
if (!ignore && *iterator != ')' && (strchr(charIn3,*iterator) || quote || escape || paren))
{
buffer+=*iterator;
}
if (*iterator == '"' && !escape && !ignore)
if (quote)quote--;
else quote++;
if (*iterator == ',' && !ignore && !quote && !escape && paren)
argit++;
if (*iterator == '(' && !ignore && !quote && !escape)
{
paren++;
if (paren == 1)
{
if (last_finished)
{
if(mob && mob->IsClient())
mob->CastToClient()->Message(10,"Line: %d,File: %s | error C0008: syntax error : missing ';' before function '%s'", line, filename.c_str(), command.c_str());
return 0;
}
command = buffer;
if(!strcmp(strlwr(command.c_str()),"break") && other)
return 1;
buffer="";
argnums = GetArgs(command);
#if Parser_DEBUG>10
if(mob && mob->IsClient())
mob->CastToClient()->Message(10,"Command: %s, Num Args: %i\n",command.c_str(),argnums);
#endif
if (argnums == -1)
{
if(mob && mob->IsClient())
mob->CastToClient()->Message(10,"Line: %d,File: %s | error C0007: '%s' : Unknown function", line, filename.c_str(), command.c_str());
return 0;
}
}
}
else if (*iterator == ')' && !ignore && !quote && !escape)
{
paren--;
if (paren == 0)
{
lastif=0,quote=0,escape=0,ignore=0;
parms = buffer;
buffer="";
if (!strcmp(strlwr((const char*)command.c_str()),"if")) { last_finished=0; }
else {
last_finished=1;
}
}
if (paren<0)
{
if(mob && mob->IsClient())
mob->CastToClient()->Message(10,"Line: %d,File: %s | error C0006: syntax error : too many ')'s",line,filename.c_str() );
return 0;
}
}
else if (*iterator == '{' && !escape)
{
bracket++;
if (!ignore) {
if (!strcmp(strlwr((const char*)command.c_str()),"if")) {
lastif = ParseIf(parms);
#if Parser_DEBUG>10
if(mob && mob->IsClient())
mob->CastToClient()->Message(10,"Parms: %s\n",parms.c_str());
#endif
if (!lastif) ignore=1;
else ignore=0;
}
}
}
else if (*iterator == '}' && !escape)
{
bracket--;
if (last_finished)
{
if(mob && mob->IsClient())
mob->CastToClient()->Message(10,"Line: %d,File: %s | error C0008: syntax error : missing ';' before '}'", line,filename.c_str() );
return 0;
}
if (bracket<0)
{
if(mob && mob->IsClient())
mob->CastToClient()->Message(10,"Line: %d,File: %s | error C0006: syntax error : too many '}'s",line, filename.c_str() );
return 0;
}
if (bracket == 0)
{
if (!ignore) lastif=1;
else lastif=0;
lastif=0,last_finished=0,quote=0,escape=0,ignore=0,argnums=0,argit=1;
}
}
else if (*iterator == ';' && !escape && !ignore && !quote)
{
if (last_finished)
{
last_finished=0;
if (argnums != 1 && argnums!=argit)
{
if(mob && mob->IsClient())
mob->CastToClient()->Message(10,"Line: %d, File: %s | error C0001: '%s' : function does not take %d parameter(s)", line, filename.c_str(), command.c_str(), argit);
return 0;
}
if (!justcheck)
ExCommands((const char*)command.c_str(),(const char*)parms.c_str(),argnums, npcid, other, mob);
argit=1;
}
else {
if(mob && mob->IsClient())
mob->CastToClient()->Message(10,"Line: %d,File: %s | error C0002: '%s' :syntax error : '(' %d '('s still not closed.", line, filename.c_str(), command.c_str(), paren);
}
}
if (escape) escape--;
iterator++;
}
if (last_finished)
{
if(mob && mob->IsClient())
mob->CastToClient()->Message(10,"Line: %d,File: %s | error C0008: syntax error : missing ';' before '}'", line, filename.c_str() );
return 0;
}
return 1;
}
void Parser::ReloadQuests(bool with_timers) {
ClearCache();
}