mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
1860 lines
43 KiB
C++
1860 lines
43 KiB
C++
/* EQEMu: Everquest Server Emulator
|
|
Copyright (C) 2001-2004 EQEMu Development Team (http://eqemu.org)
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
are required to give you total support for your newly bought product;
|
|
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
#include "../common/debug.h"
|
|
#include <iostream>
|
|
using namespace std;
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <signal.h>
|
|
#include <time.h>
|
|
#ifdef _CRTDBG_MAP_ALLOC
|
|
#undef new
|
|
#endif
|
|
#include <fstream>
|
|
#ifdef _CRTDBG_MAP_ALLOC
|
|
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
|
#endif
|
|
using namespace std;
|
|
#ifdef WIN32
|
|
#include <conio.h>
|
|
#define snprintf _snprintf
|
|
#define vsnprintf _vsnprintf
|
|
#define strncasecmp _strnicmp
|
|
#define strcasecmp _stricmp
|
|
#endif
|
|
|
|
bool spells_loaded = false;
|
|
volatile bool RunLoops = true;
|
|
extern volatile bool ZoneLoaded;
|
|
#ifdef SHAREMEM
|
|
#include "../common/EMuShareMem.h"
|
|
extern LoadEMuShareMemDLL EMuShareMemDLL;
|
|
#ifndef WIN32
|
|
#include <sys/types.h>
|
|
#include <sys/ipc.h>
|
|
#include <sys/sem.h>
|
|
#include <sys/shm.h>
|
|
#ifndef FREEBSD
|
|
union semun {
|
|
int val;
|
|
struct semid_ds *buf;
|
|
ushort *array;
|
|
struct seminfo *__buf;
|
|
void *__pad;
|
|
};
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "../common/queue.h"
|
|
#include "../common/timer.h"
|
|
#include "../common/eq_stream.h"
|
|
#include "../common/eq_packet_structs.h"
|
|
#include "../common/Mutex.h"
|
|
#include "../common/version.h"
|
|
#include "../common/files.h"
|
|
#include "../common/eqemu_error.h"
|
|
#include "../common/packet_dump_file.h"
|
|
|
|
#include "masterentity.h"
|
|
#include "worldserver.h"
|
|
#include "net.h"
|
|
#include "spdat.h"
|
|
#include "zone.h"
|
|
#include "command.h"
|
|
#include "parser.h"
|
|
#include "embparser.h"
|
|
|
|
|
|
#ifndef NEW_LoadSPDat
|
|
void LoadSPDat(SPDat_Spell_Struct** SpellsPointer) {
|
|
//FILE *fp;
|
|
//cout << "Beginning Spells memset." << endl;
|
|
int u;
|
|
//for (u = 0; u < SPDAT_RECORDS; u++)
|
|
//{ //cout << u << ' ';
|
|
memset((char*) &spells,0,sizeof(SPDat_Spell_Struct)*SPDAT_RECORDS);
|
|
//}
|
|
//cout << "Memset finished\n";
|
|
char temp=' ';
|
|
int tempid=0;
|
|
char token[64]="";
|
|
int a = 0;
|
|
char sep='^';
|
|
LogFile->write(EQEMuLog::Normal, "If this is the last message you see, you forgot to move spells_en.txt from your EQ dir to this dir.");
|
|
|
|
#ifdef FREEBSD
|
|
#error ifstreams seem to break BSD...
|
|
#endif
|
|
ifstream in;in.open(SPELLS_FILE);
|
|
|
|
if(!in.is_open()){
|
|
LogFile->write(EQEMuLog::Error, "File '%s' not found in same directory as zone.exe, spell loading FAILED!", SPELLS_FILE);
|
|
return;
|
|
}
|
|
//while(!in.eof())
|
|
//{in >> temp;}
|
|
//for(int x =0; x< spellsen_size; x++)
|
|
// memset((char*) &spells[x],0,sizeof(SPDat_Spell_Struct));
|
|
while(tempid <= SPDAT_RECORDS-1)
|
|
{
|
|
//if(tempid>3490)
|
|
//{
|
|
// cout << "BLEH";
|
|
// getch();
|
|
//}
|
|
|
|
//in.getline(&temp, 624);
|
|
in.get(temp);
|
|
while(chrcmpI(&temp, &sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;//cout << temp<< ' ';
|
|
in.get(temp);
|
|
}
|
|
tempid=atoi(token);
|
|
if(tempid>=SPDAT_RECORDS)
|
|
break;
|
|
//cout << "TempID: " << tempid << endl;
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
strncpy(spells[tempid].name,token,a);
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
//cout << spells[tempid].name << '^';
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
strncpy(spells[tempid].player_1,token,a);
|
|
//cout << spells[tempid].player_1 << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
strncpy(spells[tempid].teleport_zone,token,a);
|
|
//cout << spells[tempid].teleport_zone << '^';
|
|
a=0;
|
|
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
strncpy(spells[tempid].you_cast,token,a);
|
|
//cout << spells[tempid].you_cast << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
strncpy(spells[tempid].other_casts,token,a);
|
|
//cout << spells[tempid].other_casts << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
strncpy(spells[tempid].cast_on_you,token,a);
|
|
//cout << spells[tempid].cast_on_you << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
strncpy(spells[tempid].cast_on_other,token,a);
|
|
//cout << spells[tempid].cast_on_other << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
strncpy(spells[tempid].spell_fades,token,a);
|
|
//cout << spells[tempid].spell_fades << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].range=atof(token);
|
|
//cout << spells[tempid].range << '^';
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].aoerange=atof(token);
|
|
//cout << spells[tempid].aoerange << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].pushback=atof(token);
|
|
//cout << spells[tempid].pushback << '^';
|
|
a=0;
|
|
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].pushup=atof(token);
|
|
//cout << spells[tempid].pushup << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].cast_time=atoi(token);
|
|
|
|
//cout << spells[tempid].cast_time << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].recovery_time=atoi(token);
|
|
//cout << spells[tempid].recovery_time << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].recast_time=atoi(token);
|
|
//cout << spells[tempid].recast_time << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].buffdurationformula=atoi(token);
|
|
//cout << spells[tempid].buffdurationformula << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].buffduration=atoi(token);
|
|
//cout << spells[tempid].buffduration << '^';
|
|
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].ImpactDuration=atoi(token);
|
|
//cout << spells[tempid].ImpactDuration<< '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].mana=atoi(token);
|
|
//cout << spells[tempid].mana << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
int y;
|
|
for(y=0; y< 12;y++)
|
|
{
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].base[y]=atoi(token);
|
|
//cout << spells[tempid].base[y] << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
|
|
}
|
|
for(y=0; y< 12;y++)
|
|
{
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].max[y]=atoi(token);
|
|
//cout << spells[tempid].max[y] << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
}
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].icon=atoi(token);
|
|
//cout << spells[tempid].icon << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].memicon=atoi(token);
|
|
//cout << spells[tempid].memicon << '^';
|
|
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
for(y=0; y< 4;y++)
|
|
{
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].components[y]=atoi(token);
|
|
//cout << spells[tempid].components[y] << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
}
|
|
for(y=0; y< 4;y++)
|
|
{
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].component_counts[y]=atoi(token);//atoi(token);
|
|
//cout << spells[tempid].component_counts[y] << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
}
|
|
for(y=0; y< 4;y++)
|
|
{
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].NoexpendReagent[y]=atoi(token); //NoExpend Reagent
|
|
//cout << spells[tempid].NoexpendReagent[y] << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
}
|
|
for(y=0; y< 12;y++)
|
|
{
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].formula[y]=atoi(token);
|
|
//cout << spells[tempid].formula[y] << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
}
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
|
|
spells[tempid].LightType=atoi(token);
|
|
//cout << spells[tempid].LightType << '^';
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].goodEffect=atoi(token);
|
|
//cout << spells[tempid].goodEffect << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].Activated=atoi(token);
|
|
//cout << spells[tempid].Activated << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].resisttype=atoi(token);
|
|
//cout << spells[tempid].resisttype << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
for(y=0; y< 12;y++)
|
|
{
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].effectid[y]=atoi(token);
|
|
//cout << spells[tempid].effectid[y] << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
}
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].targettype=atoi(token);
|
|
//cout << spells[tempid].targettype << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].basediff=atoi(token);
|
|
//cout << spells[tempid].basediff<< '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
|
|
token[u]=(char)0;
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].skill=atoi(token);
|
|
//cout << spells[tempid].skill << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].zonetype=atoi(token);
|
|
//cout << spells[tempid].zonetype << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].EnvironmentType=atoi(token);
|
|
//cout << spells[tempid].EnvironmentType << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].TimeOfDay=atoi(token);
|
|
//cout << spells[tempid].TimeOfDay << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
for(y=0; y< 15;y++)
|
|
{
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].classes[y]= atoi(token);
|
|
//cout << spells[tempid].classes[y] << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
} //cout << "end class";
|
|
/*for(y=0; y< 3;y++)
|
|
{
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].unknown1[y]=atoi(token);
|
|
cout << spells[tempid].unknown1[y] << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
}
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].unknown2=atoi(token);
|
|
cout << spells[tempid].unknown2 << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
*/
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].CastingAnim=atoi(token);
|
|
//cout << spells[tempid].CastingAnim << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].TargetAnim=atoi(token);
|
|
//cout << spells[tempid].TargetAnim << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].TravelType=atoi(token);
|
|
//cout << spells[tempid].TravelType << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].SpellAffectIndex=atoi(token);
|
|
//cout << spells[tempid].SpellAffectIndex << '^';
|
|
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
for(y=0; y< 23;y++)
|
|
{
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].Spacing2[y]=atoi(token);
|
|
//cout << spells[tempid].base[y] << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
}
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].ResistDiff=atoi(token);
|
|
//cout << spells[tempid].ResistDiff << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
in.get(temp);
|
|
for(y=0; y< 2;y++)
|
|
{
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].Spacing3[y]=atoi(token);
|
|
//cout << spells[tempid].base[y] << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
}
|
|
|
|
in.get(temp);
|
|
while(chrcmpI(&temp,&sep))
|
|
{
|
|
strncat(token,&temp,1);
|
|
a++;
|
|
in.get(temp);
|
|
}
|
|
spells[tempid].RecourseLink = atoi(token);
|
|
//cout << spells[tempid].RecourseLink << '^';
|
|
a=0;
|
|
for(u=0;u<64;u++)
|
|
token[u]=(char)0;
|
|
|
|
while(temp!='\n')
|
|
in.get(temp);
|
|
|
|
//cout << endl;
|
|
if(tempid==SPDAT_RECORDS-1) break;
|
|
}
|
|
//for(u=0;u< SPDAT_RECORDS;u++)
|
|
// cout << u << ' ' << spells[u].name << '^';
|
|
|
|
spells_loaded = true;
|
|
cout << "Spells loaded.\n";
|
|
in.close();
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
/*void EntityList::SendAATimer(uint32 charid,UseAA_Struct* uaa){
|
|
Client* client2=this->GetClientByCharID(charid);
|
|
if(!client2){
|
|
LogFile->write(EQEMuLog::Error, "Error in SendAATimer: Couldnt find character!");
|
|
return;
|
|
}
|
|
client2->SendAATimer(uaa);
|
|
}
|
|
|
|
void ZoneDatabase::UpdateAndDeleteAATimers(uint32 charid){
|
|
char errbuf[MYSQL_ERRMSG_SIZE];
|
|
char *query = 0;
|
|
char *query2 = 0;
|
|
|
|
if (!RunQuery(query, MakeAnyLenString(&query, "delete from aa_timers where charid=%i and UNIX_TIMESTAMP(now())>=end",charid), errbuf)) {
|
|
LogFile->write(EQEMuLog::Error, "UpdateAATimers query '%s' %s", query, errbuf);
|
|
}
|
|
if (!RunQuery(query2, MakeAnyLenString(&query2, "update aa_timers set end=end-(UNIX_TIMESTAMP(now())-begin),begin=UNIX_TIMESTAMP(now()) where charid=%i",charid), errbuf)) {
|
|
LogFile->write(EQEMuLog::Error, "UpdateAATimers query '%s' %s", query2, errbuf);
|
|
}
|
|
safe_delete_array(query);
|
|
safe_delete_array(query2);
|
|
}
|
|
|
|
void ZoneDatabase::UpdateTimersClientConnected(uint32 charid){
|
|
char errbuf[MYSQL_ERRMSG_SIZE];
|
|
char *query = 0;
|
|
if (!RunQuery(query, MakeAnyLenString(&query, "update aa_timers set end=(UNIX_TIMESTAMP(now())+(end-begin)),begin=UNIX_TIMESTAMP(now()) where charid=%i",charid), errbuf)) {
|
|
LogFile->write(EQEMuLog::Error, "UpdateAATimers query '%s' %s", query, errbuf);
|
|
}
|
|
safe_delete_array(query);
|
|
}
|
|
|
|
void ZoneDatabase::GetAATimers(uint32 charid){
|
|
char errbuf[MYSQL_ERRMSG_SIZE];
|
|
char *query = 0;
|
|
MYSQL_RES *result;
|
|
MYSQL_ROW row;
|
|
|
|
if (RunQuery(query, MakeAnyLenString(&query, "SELECT ability,begin,end from aa_timers WHERE charid=%i", charid), errbuf, &result)) {
|
|
while( ( row = mysql_fetch_row(result) ) ){
|
|
UseAA_Struct* uaa=new UseAA_Struct();
|
|
uaa->ability=atoi(row[0]);
|
|
uaa->begin=atoi(row[1]);
|
|
uaa->end=atoi(row[2]);
|
|
entity_list.SendAATimer(charid,uaa);
|
|
safe_delete(uaa);
|
|
}
|
|
mysql_free_result(result);
|
|
}
|
|
else {
|
|
LogFile->write(EQEMuLog::Error, "Database::GetAATimers query '%s' %s", query, errbuf);
|
|
}
|
|
safe_delete_array(query);
|
|
}
|
|
|
|
uint32 ZoneDatabase::GetTimerRemaining(uint32 charid,uint32 ability){
|
|
char errbuf[MYSQL_ERRMSG_SIZE];
|
|
char *query = 0;
|
|
MYSQL_RES *result;
|
|
MYSQL_ROW row;
|
|
uint32 remain=0;
|
|
if (RunQuery(query, MakeAnyLenString(&query, "SELECT end-begin from aa_timers WHERE charid=%i and ability=%i", charid,ability), errbuf, &result)) {
|
|
if((row=mysql_fetch_row(result))){
|
|
remain=atoi(row[0]);
|
|
}
|
|
mysql_free_result(result);
|
|
}
|
|
else {
|
|
LogFile->write(EQEMuLog::Error, "Database::GetTimerRemaining query '%s' %s", query, errbuf);
|
|
}
|
|
safe_delete_array(query);
|
|
return remain;
|
|
}
|
|
|
|
void ZoneDatabase::UpdateAATimers(uint32 charid,uint32 endtime,uint32 begintime,uint32 ability){
|
|
char errbuf[MYSQL_ERRMSG_SIZE];
|
|
char *query = 0;
|
|
if(begintime==0){
|
|
if (!RunQuery(query, MakeAnyLenString(&query, "replace into aa_timers (charid,end,begin,ability) values(%i,UNIX_TIMESTAMP(now())+%i,UNIX_TIMESTAMP(now()),%i)",charid,endtime,ability), errbuf)) {
|
|
LogFile->write(EQEMuLog::Error, "UpdateAATimers query '%s' %s", query, errbuf);
|
|
}
|
|
}
|
|
else{
|
|
if (!RunQuery(query, MakeAnyLenString(&query, "replace into aa_timers (charid,end,begin,ability) values(%i,%i,%i,%i)",charid,endtime,begintime,ability), errbuf)) {
|
|
LogFile->write(EQEMuLog::Error, "UpdateAATimers query '%s' %s", query, errbuf);
|
|
}
|
|
}
|
|
safe_delete_array(query);
|
|
}*/
|
|
|
|
/*
|
|
uint16 Client::GetCombinedAC_TEST() {
|
|
int ac1;
|
|
|
|
ac1 = GetRawItemAC();
|
|
if (m_pp.class_ != WIZARD && m_pp.class_ != MAGICIAN && m_pp.class_ != NECROMANCER && m_pp.class_ != ENCHANTER) {
|
|
ac1 = ac1*4/3;
|
|
}
|
|
ac1 += GetSkill(DEFENSE)/3;
|
|
if (GetAGI() > 70) {
|
|
ac1 += GetAGI()/20;
|
|
}
|
|
|
|
int ac2;
|
|
|
|
ac2 = GetRawItemAC();
|
|
if (m_pp.class_ != WIZARD && m_pp.class_ != MAGICIAN && m_pp.class_ != NECROMANCER && m_pp.class_ != ENCHANTER) {
|
|
ac2 = ac2*4/3;
|
|
}
|
|
ac2 += GetSkill(DEFENSE)*400/255;
|
|
|
|
int combined_ac = (ac1+ac2)*1000/847;
|
|
return combined_ac;
|
|
float combined_ac = ((float)ac1+(float)ac2)*1000.0f/847.0f;
|
|
return (uint16) combined_ac;//*10.0f)-10;
|
|
}
|
|
*/
|
|
|
|
|
|
/*bool Client::GetIncreaseSpellDurationItem(uint16 &spell_id, char *itemname)
|
|
{
|
|
for (int i=0; i<22; i++) {
|
|
const ItemInst* inst = m_inv[i];
|
|
if (!inst || !inst->IsType(ItemTypeCommon))
|
|
continue;
|
|
|
|
const Item_Struct* item = inst->GetItem();
|
|
if (item->FocusId && (item->FocusId != 0xFFFF)) {
|
|
if (IsIncreaseDurationSpell(item->FocusId)) {
|
|
spell_id = item->FocusId;
|
|
if (itemname)
|
|
strcpy(itemname, item->Name);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Client::GetReduceManaCostItem(uint16 &spell_id, char *itemname)
|
|
{
|
|
for (int i=0; i<22; i++) {
|
|
const ItemInst* inst = m_inv[i];
|
|
if (!inst || !inst->IsType(ItemTypeCommon))
|
|
continue;
|
|
|
|
const Item_Struct* item = inst->GetItem();
|
|
if (item->FocusId && (item->FocusId != 0xFFFF)) {
|
|
if (IsReduceManaSpell(item->FocusId)) {
|
|
spell_id = item->FocusId;
|
|
if (itemname)
|
|
strcpy(itemname, item->Name);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Client::GetReduceCastTimeItem(uint16 &spell_id, char *itemname)
|
|
{
|
|
for (int i=0; i<22; i++) {
|
|
const ItemInst* inst = m_inv[i];
|
|
if (!inst || !inst->IsType(ItemTypeCommon))
|
|
continue;
|
|
|
|
const Item_Struct* item = inst->GetItem();
|
|
if (item->FocusId && (item->FocusId != 0xFFFF)) {
|
|
if (IsReduceCastTimeSpell(item->FocusId)) {
|
|
spell_id = item->FocusId;
|
|
if (itemname)
|
|
strcpy(itemname, item->Name);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Client::GetExtendedRangeItem(uint16 &spell_id, char *itemname)
|
|
{
|
|
for (int i=0; i<22; i++) {
|
|
const ItemInst* inst = m_inv[i];
|
|
if (!inst || !inst->IsType(ItemTypeCommon))
|
|
continue;
|
|
|
|
const Item_Struct* item = inst->GetItem();
|
|
if (item->FocusId && (item->FocusId != 0xFFFF)) {
|
|
if (IsExtRangeSpell(item->FocusId)) {
|
|
spell_id = item->FocusId;
|
|
if (itemname)
|
|
strcpy(itemname, item->Name);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Client::GetImprovedHealingItem(uint16 &spell_id, char *itemname)
|
|
{
|
|
for (int i=0; i<22; i++) {
|
|
const ItemInst* inst = m_inv[i];
|
|
if (!inst || !inst->IsType(ItemTypeCommon))
|
|
continue;
|
|
|
|
const Item_Struct* item = inst->GetItem();
|
|
if (item->FocusId && (item->FocusId != 0xFFFF)) {
|
|
if (IsImprovedHealingSpell(item->FocusId)) {
|
|
spell_id = item->FocusId;
|
|
if (itemname)
|
|
strcpy(itemname, item->Name);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Client::GetImprovedDamageItem(uint16 &spell_id, char *itemname)
|
|
{
|
|
for (int i=0; i<22; i++) {
|
|
const ItemInst* inst = m_inv[i];
|
|
if (!inst || !inst->IsType(ItemTypeCommon))
|
|
continue;
|
|
|
|
const Item_Struct* item = inst->GetItem();
|
|
if (item->FocusId && (item->FocusId != 0xFFFF)) {
|
|
if (IsImprovedDamageSpell(item->FocusId)) {
|
|
spell_id = item->FocusId;
|
|
if (itemname)
|
|
strcpy(itemname, item->Name);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int32 Client::GenericFocus(uint16 spell_id, uint16 modspellid)
|
|
{
|
|
int modifier = 100, i;
|
|
const SPDat_Spell_Struct &spell = spells[spell_id];
|
|
const SPDat_Spell_Struct &modspell = spells[modspellid];
|
|
|
|
for (i = 0; i < EFFECT_COUNT; i++)
|
|
{
|
|
if(IsBlankSpellEffect(modspellid, i))
|
|
continue;
|
|
switch( spells[modspellid].effectid[i] )
|
|
{
|
|
case SE_LimitMaxLevel:
|
|
if (spell.classes[(GetClass()%16) - 1] > modspell.base[i])
|
|
return 100;
|
|
break;
|
|
case SE_LimitMinLevel:
|
|
if (spell.classes[(GetClass()%16) - 1] < modspell.base[i])
|
|
return 100;
|
|
break;
|
|
case SE_IncreaseRange:
|
|
modifier += modspell.base[i];
|
|
break;
|
|
case SE_IncreaseSpellHaste:
|
|
modifier -= modspell.base[i];
|
|
break;
|
|
case SE_IncreaseSpellDuration:
|
|
modifier += modspell.base[i];
|
|
break;
|
|
case SE_LimitSpell:
|
|
// negative sign means exclude
|
|
// positive sign means include
|
|
if (modspell.base[i] < 0)
|
|
{
|
|
if (modspell.base[i] * (-1) == spell_id)
|
|
return 100;
|
|
}
|
|
else
|
|
{
|
|
if (spells[modspellid].base[i] != spell_id)
|
|
return 100;
|
|
}
|
|
break;
|
|
case SE_LimitEffect:
|
|
switch( spells[modspellid].base[i] )
|
|
{
|
|
case -147:
|
|
if (IsPercentalHealSpell(spell_id))
|
|
return 100;
|
|
break;
|
|
case -101:
|
|
if (IsCHDurationSpell(spell_id))
|
|
return 100;
|
|
break;
|
|
case -40:
|
|
if (IsInvulnerabilitySpell(spell_id))
|
|
return 100;
|
|
break;
|
|
case -32:
|
|
if (IsSummonItemSpell(spell_id))
|
|
return 100;
|
|
break;
|
|
case 0:
|
|
if (!IsEffectHitpointsSpell(spell_id))
|
|
return 100;
|
|
break;
|
|
case 33:
|
|
if (!IsSummonPetSpell(spell_id))
|
|
return 100;
|
|
break;
|
|
case 36:
|
|
if (!IsPoisonCounterSpell(spell_id))
|
|
return 100;
|
|
break;
|
|
case 71:
|
|
if (!IsSummonSkeletonSpell(spell_id))
|
|
return 100;
|
|
break;
|
|
default:
|
|
LogFile->write(EQEMuLog::Normal, "GenericFocus: unknown limit effect %d", spells[modspellid].base[i]);
|
|
}
|
|
break;
|
|
case SE_LimitCastTime:
|
|
if (modspell.base[i] > (int16)spell.cast_time)
|
|
return 100;
|
|
break;
|
|
case SE_LimitSpellType:
|
|
switch( spells[modspellid].base[i] )
|
|
{
|
|
case 0:
|
|
if (!IsDetrimentalSpell(spell_id))
|
|
return 100;
|
|
break;
|
|
case 1:
|
|
if (!IsBeneficialSpell(spell_id))
|
|
return 100;
|
|
break;
|
|
default:
|
|
LogFile->write(EQEMuLog::Normal, "GenericFocus: unknown limit spelltype %d", spells[modspellid].base[i]);
|
|
}
|
|
break;
|
|
case SE_LimitMinDur:
|
|
if (modspell.base[i] > CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration))
|
|
return 100;
|
|
break;
|
|
case SE_ImprovedDamage:
|
|
case SE_ImprovedHeal:
|
|
modifier += modspell.base[i];
|
|
break;
|
|
case SE_ReduceManaCost:
|
|
modifier -= modspell.base[i];
|
|
break;
|
|
default:
|
|
LogFile->write(EQEMuLog::Normal, "GenericFocus: unknown effectid %d", modspell.effectid[i]);
|
|
}
|
|
}
|
|
|
|
return modifier;
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
/*void Client::Discipline(ClientDiscipline_Struct* disc_in, Mob* tar) {
|
|
Message(0, "Disc packet id=%d, %x,%x,%x", disc_in->disc_id, disc_in->unknown3[0], disc_in->unknown3[1], disc_in->unknown3[2]);
|
|
if (!p_timers.Expired(&database, pTimerDisciplineReuse)) {
|
|
char val1[20]={0};
|
|
char val2[20]={0};
|
|
uint32 remain = p_timers.GetRemainingTime(pTimerDisciplineReuse);
|
|
Message_StringID(0,DISCIPLINE_CANUSEIN,ConvertArray((remain)/60,val1),ConvertArray(remain%60,val2));
|
|
//Message(0,"You can use a new discipline in %i minutes %i seconds.", (disc_timer.GetRemainingTime()/1000)/60, disc_timer.GetRemainingTime()/1000%60);
|
|
return;
|
|
}
|
|
|
|
//reuse times are a little messes up, they should scale down somehow
|
|
//as you gain in levels, but im not sure how, so its just a lvl 60 bonus right now
|
|
|
|
//should change this to check classes better.
|
|
|
|
//both in seconds, converted at the end.
|
|
uint32 duration = 0;
|
|
uint32 reuse = 0;
|
|
|
|
switch(disc_in->disc_id){
|
|
// Shared?
|
|
case discResistant: { // Resistant
|
|
// 1 minute duration
|
|
// 1 hour reuse
|
|
// +3 to +10 to resists
|
|
if (GetLevel()<=29)
|
|
return;
|
|
duration = 60;
|
|
reuse = 60*60;
|
|
entity_list.MessageClose(this, false, 100, 0, "%s has become more resistant!", GetName());
|
|
break;
|
|
}
|
|
case discFearless: { // Fearless
|
|
// 11 second duration
|
|
// 1 hour reuse
|
|
// 100% fear immunity
|
|
if (GetLevel()<=39)
|
|
return;
|
|
duration = 11;
|
|
reuse = 60*60;
|
|
entity_list.MessageClose_StringID(this, false, 100, 0, DISCIPLINE_FEARLESS, GetName());
|
|
//entity_list.MessageClose(this, false, 100, 0, "%s becomes fearless!", GetName());
|
|
break;
|
|
}
|
|
case discWhirlwind: { // Counterattack/Whirlwind/Furious
|
|
// warrior level 56
|
|
// rogue/monk level 53
|
|
// 9 second duration
|
|
// 1 hour reuse
|
|
if ((GetClass() == WARRIOR && GetLevel() <= 56)
|
|
||(GetLevel() <= 53)
|
|
) return;
|
|
duration = 9;
|
|
reuse = 60*60;
|
|
entity_list.MessageClose(this, false, 100, 0, "%s\'s face becomes twisted with fury!", GetName());
|
|
break;
|
|
}
|
|
case discFellstrike: { // Duelist/Innerflame/Fellstrike
|
|
// monk level 56
|
|
// rogue level 59
|
|
// warrior level 58
|
|
// 12 second duration
|
|
// 30 minute reuse
|
|
// min 4*base hand/weapon damage
|
|
if ((GetClass() == MONK && GetLevel() <= 55)
|
|
||(GetClass() == WARRIOR && GetLevel() <= 58)
|
|
||(GetClass() == ROGUE && GetLevel() <= 59)
|
|
) return;
|
|
duration = 12;
|
|
reuse = 60*30;
|
|
entity_list.MessageClose(this, false, 100, 0, "%s\'s muscles bulge with force of will!", GetName());
|
|
break;
|
|
}
|
|
case discBlindingSpeed: { // Blindingspeed/Hundredfist
|
|
// rogue level 58
|
|
// monk level 57
|
|
// 15 second duration
|
|
// 30 minute reuse
|
|
if ((GetClass() == MONK && GetLevel() <= 58)
|
|
||(GetClass() == ROGUE && GetLevel() <= 57)
|
|
) return;
|
|
//disc_timer.Start(1000*60*30);
|
|
//disc_elapse.Start(1000*15);
|
|
duration = 15;
|
|
reuse = 60*30;
|
|
Message(0, "This discipline not implemented..");
|
|
break;
|
|
}
|
|
case discDeadeye: { // Deadeye/Charge
|
|
// warrior level 53
|
|
// rogue level 54
|
|
// 14 second duration
|
|
// 30 minute reuse
|
|
if ((GetClass() == WARRIOR && GetLevel() <= 53)
|
|
||(GetClass() == ROGUE && GetLevel() <= 54)
|
|
) return;
|
|
duration = 14;
|
|
reuse = 60*30;
|
|
entity_list.MessageClose(this, false, 100, 0, "%s feels unstopable!", GetName());
|
|
break;
|
|
}
|
|
// Warrior
|
|
case discEvasive: { // Evasive
|
|
// level 52
|
|
// 3 minute duration
|
|
// 15 minute reuse
|
|
// +35% avoidance
|
|
// -15% out
|
|
duration = 3*60;
|
|
reuse = 15*60;
|
|
break;
|
|
}
|
|
case discMightystrike: { // Mightystrike
|
|
// level 54
|
|
// 10 second duration
|
|
// 1 hour reuse
|
|
// Auto crit
|
|
duration = 10;
|
|
reuse = 60*60;
|
|
break;
|
|
}
|
|
case discDefensive: { // Defensive
|
|
// level 55
|
|
// 3 minute duration
|
|
// 15 minute reuse, 10 after 60
|
|
// +35% mitigation
|
|
// -15% out
|
|
duration = 3*60;
|
|
if(level > 59)
|
|
reuse = 10*60;
|
|
else
|
|
reuse = 15*60;
|
|
break;
|
|
}
|
|
case discPrecise: { // Precise
|
|
// level 57
|
|
// 3 minute duration
|
|
// 30 minute reuse
|
|
// -15% avoidance
|
|
// +35% out
|
|
duration = 3*60;
|
|
reuse = 30*60;
|
|
break;
|
|
}
|
|
case discAggressive: { // Aggressive
|
|
// level 60
|
|
// 3 minute duration
|
|
// 27 minute reuse
|
|
// -15% mitigation
|
|
// +35% out
|
|
duration = 3*60;
|
|
reuse = 27*60;
|
|
break;
|
|
}
|
|
// Monk
|
|
case discStonestance: { // Stonestance
|
|
// level 51
|
|
duration = 12;
|
|
if(level > 59)
|
|
reuse = 3*60;
|
|
else
|
|
reuse = 12*60;
|
|
break;
|
|
}
|
|
case discThunderkick: { // Thunderkick
|
|
// level 52
|
|
if(level > 59)
|
|
reuse = 1*60;
|
|
else
|
|
reuse = 7*60;
|
|
duration = 5*60; //hack for now, checked in combat and expired once used.
|
|
break;
|
|
}
|
|
case discVoidance: { // Voidance
|
|
// level 54
|
|
if(level > 59)
|
|
reuse = 54*60;
|
|
else
|
|
reuse = 60*60;
|
|
duration = 8;
|
|
break;
|
|
}
|
|
case discSilentfist: { // Silentfist
|
|
// level 59
|
|
// 6-7 minute reuse
|
|
// Dragon punch damage bonus
|
|
// Chance to stun
|
|
if(level > 59)
|
|
reuse = 6*60;
|
|
else
|
|
reuse = 7*60;
|
|
duration = 5*60; //hack for now, checked in combat and expired once used.
|
|
break;
|
|
}
|
|
case discAshenhand: { // Ashenhand
|
|
// level 60
|
|
// 72 minute reuse
|
|
// Eagle Strike damage bonus
|
|
// Chance to slay
|
|
reuse = 72*60;
|
|
duration = 5*60; //hack for now, checked in combat and expired once used.
|
|
break;
|
|
}
|
|
// Rogue
|
|
case discNimble: { // Nimble
|
|
// level 55
|
|
// 12 second duration
|
|
// 30 minute reuse
|
|
// Auto dodge
|
|
if(level > 59)
|
|
reuse = 25*60;
|
|
else
|
|
reuse = 30*60;
|
|
duration = 12;
|
|
break;
|
|
}
|
|
case discKinesthetics: { // Kinesthetics
|
|
// level 57
|
|
// 18 second duration
|
|
// 30,27 minute reuse
|
|
// Auto dualwield
|
|
// Auto double attack
|
|
if(level > 59)
|
|
reuse = 27*60;
|
|
else
|
|
reuse = 30*60;
|
|
duration = 18;
|
|
break;
|
|
}
|
|
// Paladin
|
|
case discHolyforge: { // Holyforge
|
|
// level 55
|
|
// 2 minute duration
|
|
// 72 minute reuse
|
|
// Crit/Crip undead
|
|
// +15% to crit chance
|
|
if(level > 59)
|
|
reuse = 65*60;
|
|
else
|
|
reuse = 72*60;
|
|
duration = 5*60;
|
|
break;
|
|
}
|
|
case discSanctification: { // Sanctification
|
|
// level 60
|
|
// 10 second duration
|
|
// 72 minute reuse
|
|
// Spell immunity
|
|
reuse = 72*60;
|
|
duration = 15;
|
|
break;
|
|
}
|
|
// Ranger
|
|
case discTrueshot: { // Trueshot
|
|
// level 55
|
|
// 2 minute duration
|
|
// 72 minute reuse
|
|
// Max to two times max bow damage
|
|
// +15% to hit
|
|
if(level > 59)
|
|
reuse = 67*60;
|
|
else
|
|
reuse = 72*60;
|
|
duration = 2*60;
|
|
break;
|
|
}
|
|
case discWeaponshield: { // Weaponshield
|
|
// level 60
|
|
// 15 second duration
|
|
// 72 minute reuse
|
|
// auto parry
|
|
reuse = 72*60;
|
|
duration = 20;
|
|
break;
|
|
}
|
|
// Bard
|
|
case discDeftdance: { // Deftdance
|
|
// level 55
|
|
// 10 second duration
|
|
// 72 minute reuse
|
|
// auto dodge
|
|
// auto dualwield
|
|
if(level > 59)
|
|
reuse = 67*60;
|
|
else
|
|
reuse = 72*60;
|
|
duration = 10;
|
|
break;
|
|
}
|
|
case discPuretone: { // Puretone
|
|
// level 60
|
|
// 2 minute duration
|
|
// 72 minute reuse
|
|
// Auto instrument
|
|
reuse = 72*60;
|
|
duration = 4*60;
|
|
break;
|
|
}
|
|
// Shadow knight
|
|
case discUnholyAura: { // Unholy
|
|
// level 55
|
|
// 72 minute reuse
|
|
// +25% to harmtouch
|
|
// -300 to resist
|
|
if(level > 59)
|
|
reuse = 67*60;
|
|
else
|
|
reuse = 72*60;
|
|
duration = 5*60; //hack for now, checked in combat and expired once used.
|
|
break;
|
|
}
|
|
case discLeechCurse: { // Leech curse
|
|
// level 60
|
|
// 15 second duration
|
|
// 72 minute reuse
|
|
// Heal self for each point of melee damage done
|
|
reuse = 72*60;
|
|
duration = 15;
|
|
break;
|
|
}
|
|
// Default
|
|
case 0:{ // Timer request
|
|
break;
|
|
}
|
|
default:
|
|
LogFile->write(EQEMuLog::Error, "Unknown Discipline requested by client: %s class: %i Disciline:%i", GetName(), class_,disc_in->disc_id);
|
|
return;
|
|
}
|
|
|
|
if(reuse != 0) {
|
|
p_timers.Start(pTimerDisciplineReuse, reuse);
|
|
//nonpersistent timer for the 'discipline ready' message
|
|
disc_timer.Start(1000*reuse);
|
|
}
|
|
if(duration != 0)
|
|
disc_elapse.Start(1000*duration);
|
|
|
|
disc_inuse = disc_in->disc_id;
|
|
}*/
|
|
|
|
#if 0 // solar: this is old code
|
|
/*void EntityList::AESpell(Mob* caster, Mob* center, float dist, uint16 spell_id, bool group)
|
|
{
|
|
LinkedListIterator<Mob*> iterator(mob_list);
|
|
iterator.Reset();
|
|
while(iterator.MoreElements()) {
|
|
Mob* mob = iterator.GetData();
|
|
if (group){
|
|
// Client casting group spell with out target group buffs enabled
|
|
// Skip non group members
|
|
if (caster->IsClient()
|
|
&& !caster->CastToClient()->TGB()
|
|
&& GetGroupByMob(mob) != 0
|
|
&& !GetGroupByMob(mob)->IsGroupMember(caster)
|
|
) {
|
|
LogFile->write(EQEMuLog::Debug, "Group spell skipping %s", mob->GetName());
|
|
iterator.Advance();
|
|
continue;
|
|
}
|
|
// Client casting group spell with target group buffs enabled
|
|
else if (caster->IsClient()
|
|
&& caster->CastToClient()->TGB()
|
|
&& GetGroupByMob(mob) != 0
|
|
&& GetGroupByMob(mob)->IsGroupMember(caster)
|
|
){
|
|
LogFile->write(EQEMuLog::Debug, "Group spell TGB on %s's Group", mob->GetName());
|
|
GetGroupByMob(mob)->CastGroupSpell(caster, spell_id);
|
|
iterator.Advance();
|
|
continue;
|
|
}
|
|
else if (caster->IsClient()
|
|
&& caster->CastToClient()->TGB()
|
|
&& GetGroupByMob(mob) == 0
|
|
&& mob == center
|
|
){
|
|
LogFile->write(EQEMuLog::Debug, "Group spell TGB on %s", mob->GetName());
|
|
caster->SpellOnTarget(spell_id, mob);
|
|
return;
|
|
}
|
|
}
|
|
if (
|
|
mob->DistNoZ(*center) <= dist
|
|
&& !(mob->IsClient() && mob->CastToClient()->GMHideMe())
|
|
&& !mob->IsCorpse()
|
|
) {
|
|
//cout << "AE Spell Hit: t=" << iterator.GetData()->GetName() << ", d=" << iterator.GetData()->CastToMob()->DistNoRoot(center) << ", x=" << iterator.GetData()->CastToMob()->GetX() << ", y=" << iterator.GetData()->CastToMob()->GetY() << endl;
|
|
if (caster == mob) {
|
|
// Caster gets the first hit, already handled in spells.cpp
|
|
}
|
|
#ifdef IPC
|
|
else if(caster->IsNPC() && !caster->CastToNPC()->IsInteractive()) {
|
|
#else
|
|
else if(caster->IsNPC()) {
|
|
#endif
|
|
// Npc
|
|
if (caster->IsAttackAllowed(mob) && spells[spell_id].targettype != ST_AEBard) {
|
|
//printf("NPC Spell casted on %s\n", mob->GetName());
|
|
caster->SpellOnTarget(spell_id, mob);
|
|
}
|
|
else if (mob->IsAIControlled() && spells[spell_id].targettype == ST_AEBard) {
|
|
//printf("NPC mgb/aebard spell casted on %s\n", mob->GetName());
|
|
caster->SpellOnTarget(spell_id, mob);
|
|
}
|
|
else {
|
|
//printf("NPC AE, fall thru. spell_id:%i, Target type:%x\n", spell_id, spells[spell_id].targettype);
|
|
}
|
|
}
|
|
#ifdef IPC
|
|
else if(caster->IsNPC() && caster->CastToNPC()->IsInteractive()) {
|
|
// Interactive npc
|
|
if (caster->IsAttackAllowed(mob) && spells[spell_id].targettype != ST_AEBard && spells[spell_id].targettype != ST_GroupTeleport) {
|
|
//printf("IPC Spell casted on %s\n", mob->GetName());
|
|
caster->SpellOnTarget(spell_id, mob);
|
|
}
|
|
else if (!mob->IsAIControlled() && (spells[spell_id].targettype == ST_AEBard||group) && mob->CastToClient()->GetPVP() == caster->CastToClient()->GetPVP()) {
|
|
if (group && GetGroupByMob(mob) != GetGroupByMob(caster)) {
|
|
iterator.Advance();
|
|
continue;
|
|
}
|
|
//printf("IPC mgb/aebard spell casted on %s\n", mob->GetName());
|
|
caster->SpellOnTarget(spell_id, mob);
|
|
}
|
|
else {
|
|
//printf("NPC AE, fall thru. spell_id:%i, Target type:%x\n", spell_id, spells[spell_id].targettype);
|
|
}
|
|
}
|
|
#endif
|
|
else if (caster->IsClient() && !(caster->CastToClient()->IsBecomeNPC())) {
|
|
// Client
|
|
if (caster->IsAttackAllowed(mob) && spells[spell_id].targettype != ST_AEBard){
|
|
//printf("Client Spell casted on %s\n", mob->GetName());
|
|
caster->SpellOnTarget(spell_id, mob);
|
|
}
|
|
else if(spells[spell_id].targettype == ST_GroupTeleport && mob->IsClient() && mob->isgrouped && caster->isgrouped && entity_list.GetGroupByMob(caster))
|
|
{
|
|
Group* caster_group = entity_list.GetGroupByMob(caster);
|
|
if(caster_group != 0 && caster_group->IsGroupMember(mob))
|
|
caster->SpellOnTarget(spell_id,mob);
|
|
}
|
|
else if (mob->IsClient() && (spells[spell_id].targettype == ST_AEBard||group) && mob->CastToClient()->GetPVP() == caster->CastToClient()->GetPVP()) {
|
|
if (group && GetGroupByMob(mob) != GetGroupByMob(caster)) {
|
|
iterator.Advance();
|
|
continue;
|
|
}
|
|
else if (mob->IsClient() && spells[spell_id].targettype == ST_AEBard && mob->CastToClient()->GetPVP() == caster->CastToClient()->GetPVP())
|
|
caster->SpellOnTarget(spell_id, mob);
|
|
#ifdef IPC
|
|
else if (mob->IsNPC() && mob->CastToNPC()->IsInteractive()) {
|
|
if (group && GetGroupByMob(mob) != GetGroupByMob(caster))
|
|
continue;
|
|
caster->SpellOnTarget(spell_id, mob);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
else if (caster->IsClient()) {
|
|
// Client BecomeNPC
|
|
caster->SpellOnTarget(spell_id, mob);
|
|
}
|
|
}
|
|
iterator.Advance();
|
|
}
|
|
}*/
|
|
#endif // solar: old code
|
|
|
|
/*#if 0
|
|
// Queries the loottable: adds item & coin to the npc
|
|
void ZoneDatabase::AddLootTableToNPC(uint32 loottable_id, ItemList* itemlist, uint32* copper, uint32* silver, uint32* gold, uint32* plat) {
|
|
char errbuf[MYSQL_ERRMSG_SIZE];
|
|
char *query = 0;
|
|
MYSQL_RES *result;
|
|
MYSQL_ROW row;
|
|
*copper = 0;
|
|
*silver = 0;
|
|
*gold = 0;
|
|
*plat = 0;
|
|
|
|
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id, mincash, maxcash, avgcoin FROM loottable WHERE id=%i", loottable_id), errbuf, &result)) {
|
|
safe_delete_array(query);
|
|
if (mysql_num_rows(result) == 1) {
|
|
row = mysql_fetch_row(result);
|
|
uint32 mincash = atoi(row[1]);
|
|
uint32 maxcash = atoi(row[2]);
|
|
if (mincash > maxcash) {
|
|
cerr << "Error in loottable #" << row[0] << ": mincash > maxcash" << endl;
|
|
}
|
|
else if (maxcash != 0) {
|
|
uint32 cash = 0;
|
|
if (mincash == maxcash)
|
|
cash = mincash;
|
|
else
|
|
cash = (rand() % (maxcash - mincash)) + mincash;
|
|
if (cash != 0) {
|
|
uint32 coinavg = atoi(row[3]);
|
|
if (coinavg != 0) {
|
|
uint32 mincoin = (uint32) (coinavg * 0.75 + 1);
|
|
uint32 maxcoin = (uint32) (coinavg * 1.25 + 1);
|
|
*copper = (rand() % (maxcoin - mincoin)) + mincoin - 1;
|
|
*silver = (rand() % (maxcoin - mincoin)) + mincoin - 1;
|
|
*gold = (rand() % (maxcoin - mincoin)) + mincoin - 1;
|
|
cash -= *copper;
|
|
cash -= *silver * 10;
|
|
cash -= *gold * 10;
|
|
}
|
|
*plat = cash / 1000;
|
|
cash -= *plat * 1000;
|
|
uint32 gold2 = cash / 100;
|
|
cash -= gold2 * 100;
|
|
uint32 silver2 = cash / 10;
|
|
cash -= silver2 * 10;
|
|
*gold += gold2;
|
|
*silver += silver2;
|
|
*copper += cash;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
mysql_free_result(result);
|
|
return;
|
|
}
|
|
mysql_free_result(result);
|
|
}
|
|
else
|
|
{
|
|
cerr << "Error in AddLootTableToNPC get coin query '" << query << "' " << errbuf << endl;
|
|
safe_delete_array(query);
|
|
return;
|
|
}
|
|
|
|
if (RunQuery(query, MakeAnyLenString(&query, "SELECT loottable_id, lootdrop_id, multiplier, probability FROM loottable_entries WHERE loottable_id=%i", loottable_id), errbuf, &result)) {
|
|
safe_delete_array(query);
|
|
while ((row = mysql_fetch_row(result))) {
|
|
int multiplier = atoi(row[2]);
|
|
for (int i = 1; i <= multiplier; i++) {
|
|
if ( ((rand()%1)*100) < atoi(row[3])) {
|
|
AddLootDropToNPC(atoi(row[1]), itemlist);
|
|
}
|
|
}
|
|
}
|
|
mysql_free_result(result);
|
|
}
|
|
else {
|
|
cerr << "Error in AddLootTableToNPC get items query '" << query << "' " << errbuf << endl;
|
|
safe_delete_array(query);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Called by AddLootTableToNPC
|
|
// maxdrops = size of the array npcd
|
|
void ZoneDatabase::AddLootDropToNPC(uint32 lootdrop_id, ItemList* itemlist) {
|
|
char errbuf[MYSQL_ERRMSG_SIZE];
|
|
char *query = 0;
|
|
MYSQL_RES *result;
|
|
MYSQL_ROW row;
|
|
|
|
// This is Wiz's updated Pool Looting functionality. Eventually, the database format should be moved over to use this
|
|
// or implemented to support both methods. (A unique identifier in lootable_entries indicates to roll for a pool item
|
|
// in another table.
|
|
#ifdef POOLLOOTING
|
|
uint32 chancepool = 0;
|
|
uint32 items[50];
|
|
uint32 itemchance[50];
|
|
uint16 itemcharges[50];
|
|
uint8 i = 0;
|
|
|
|
for (int m=0;m < 50;m++)
|
|
{
|
|
items[m]=0;
|
|
itemchance[m]=0;
|
|
itemcharges[m]=0;
|
|
}
|
|
|
|
if (RunQuery(query, MakeAnyLenString(&query, "SELECT lootdrop_id, item_id, item_charges, equip_item, chance FROM lootdrop_entries WHERE lootdrop_id=%i order by chance desc", lootdrop_id), errbuf, &result))
|
|
{
|
|
safe_delete_array(query);
|
|
while (row = mysql_fetch_row(result))
|
|
{
|
|
items[i] = atoi(row[1]);
|
|
itemchance[i] = atoi(row[4]) + chancepool;
|
|
itemcharges[i] = atoi(row[2]);
|
|
chancepool += atoi(row[4]);
|
|
i++;
|
|
}
|
|
uint32 res;
|
|
i = 0;
|
|
|
|
if (chancepool!=0) //avoid divide by zero if some mobs have 0 for chancepool
|
|
{
|
|
res = rand()%chancepool;
|
|
}
|
|
else
|
|
{
|
|
res = 0;
|
|
}
|
|
|
|
while (items[i] != 0)
|
|
{
|
|
if (res <= itemchance[i])
|
|
break;
|
|
else
|
|
i++;
|
|
}
|
|
const Item_Struct* dbitem = database.GetItem(items[i]);
|
|
if (dbitem == 0)
|
|
{
|
|
LogFile->write(EQEMuLog::Error, "AddLootDropToNPC: dbitem=0, item#=%i, lootdrop_id=%i", items[i], lootdrop_id);
|
|
}
|
|
else
|
|
{
|
|
//printf("Adding item2: %i",item->item_id);
|
|
//cout << "Adding item to Mob" << endl;
|
|
ServerLootItem_Struct* item = new ServerLootItem_Struct;
|
|
item->item_id = dbitem->ItemNumber;
|
|
item->charges = itemcharges[i];
|
|
item->equipSlot = 0;
|
|
(*itemlist).Append(item);
|
|
}
|
|
mysql_free_result(result);
|
|
}
|
|
#else
|
|
if (RunQuery(query, MakeAnyLenString(&query, "SELECT lootdrop_id, item_id, item_charges, equip_item, chance FROM lootdrop_entries WHERE lootdrop_id=%i order by chance desc", lootdrop_id), errbuf, &result))
|
|
{
|
|
safe_delete_array(query);
|
|
while ((row = mysql_fetch_row(result)))
|
|
{
|
|
uint8 LootDropMod=1; // place holder till I put it in a database variable to make it configurable.
|
|
if( (rand()%100) < ((atoi(row[4]) * LootDropMod)) )
|
|
{
|
|
uint32 itemid = atoi(row[1]);
|
|
const Item_Struct* dbitem = database.GetItem(itemid);
|
|
if (dbitem == 0)
|
|
{
|
|
LogFile->write(EQEMuLog::Error, "AddLootDropToNPC: dbitem=0, item#=%i, lootdrop_id=%i", itemid, lootdrop_id);
|
|
}
|
|
else
|
|
{
|
|
printf("Adding item: %i",item->ItemNumber);
|
|
ServerLootItem_Struct* item = new ServerLootItem_Struct;
|
|
item->item_id = dbitem->item_id;
|
|
item->charges = atoi(row[2]);
|
|
item->equipSlot = 0;
|
|
(*itemlist).Append(item);
|
|
}
|
|
|
|
//mysql_free_result(result);
|
|
//return;
|
|
}
|
|
}
|
|
mysql_free_result(result);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
LogFile->write(EQEMuLog::Error, "Error in AddLootDropToNPC query '%s' %s", query, errbuf);
|
|
safe_delete_array(query);
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
#endif*/
|