1
0

EQ2Emu Source Base July 2024

This commit is contained in:
Emagi 2024-07-22 08:52:28 -04:00
parent 9e433b82c6
commit 89194da149
260 changed files with 180526 additions and 0 deletions

View File

@ -0,0 +1,20 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Character.h"

View File

@ -0,0 +1,25 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _EQ2_CHARACTER_
#define _EQ2_CHARACTER_
class Character{
};
#endif

View File

@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EQ2 Login", "Login.vcxproj", "{BE2C1914-FCCC-4F65-A7DD-105142B36104}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
EQ2Login|Win32 = EQ2Login|Win32
MiniLogin Release|Win32 = MiniLogin Release|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.Debug|Win32.ActiveCfg = EQ2Login|Win32
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.Debug|Win32.Build.0 = EQ2Login|Win32
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.EQ2Login|Win32.ActiveCfg = EQ2Login|Win32
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.EQ2Login|Win32.Build.0 = EQ2Login|Win32
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.MiniLogin Release|Win32.ActiveCfg = EQ2Login|Win32
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.MiniLogin Release|Win32.Build.0 = EQ2Login|Win32
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.Release|Win32.ActiveCfg = EQ2Login|Win32
{BE2C1914-FCCC-4F65-A7DD-105142B36104}.Release|Win32.Build.0 = EQ2Login|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Binary file not shown.

File diff suppressed because it is too large Load Diff

253
source/LoginServer/LWorld.h Normal file
View File

@ -0,0 +1,253 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
*/
#ifndef LWORLD_H
#define LWORLD_H
#include "../common/Mutex.h"
#define ERROR_BADPASSWORD "Bad password"
#define INVALID_ACCOUNT "Invalid Server Account."
#define ERROR_BADVERSION "Incorrect version"
#define ERROR_UNNAMED "Unnamed servers not allowed to connect to full login servers"
#define ERROR_NOTMASTER "Not a master server"
#define ERROR_NOTMESH "Not a mesh server"
#define ERROR_GHOST "Ghost kick"
#define ERROR_UnknownServerType "Unknown Server Type"
#define ERROR_BADNAME_SERVER "Bad server name, name may not contain the word \"Server\" (case sensitive)"
#define ERROR_BADNAME "Bad server name. Unknown reason."
#define WORLD_NAME_SUFFIX " Server"
#include <boost/algorithm/string.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/beast/http.hpp>
#include <sstream>
#include <string>
#include <iostream>
namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
#include "../common/linked_list.h"
#include "../WorldServer/MutexList.h"
#include "../WorldServer/MutexMap.h"
#include "../common/timer.h"
#include "../common/types.h"
#include "../common/queue.h"
#include "../common/servertalk.h"
#include "../common/TCPConnection.h"
#include "client.h"
#define MAX_UPDATE_COUNT 20
#define MAX_LOGIN_APPEARANCE_COUNT 100
#ifdef WIN32
void ServerUpdateLoop(void* tmp);
#else
void* ServerUpdateLoop(void* tmp);
#endif
enum ConType { UnknownW, World, Chat, Login };
class LWorld
{
public:
LWorld(TCPConnection* in_con, bool OutgoingLoginUplink = false, int32 iIP = 0, int16 iPort = 0, bool iNeverKick = false);
LWorld(int32 in_accountid, char* in_accountname, char* in_worldname, int32 in_admin_id);
LWorld(TCPConnection* in_RemoteLink, int32 in_ip, int32 in_RemoteID, int32 in_accountid, char* in_accountname, char* in_worldname, char* in_address, sint32 in_status, int32 in_adminid, bool in_showdown, int8 in_authlevel, bool in_placeholder, int32 iLinkWorldID);
~LWorld();
static bool CheckServerName(const char* name);
bool Process();
void SendPacket(ServerPacket* pack);
void Message(const char* to, const char* message, ...);
bool SetupWorld(char* in_worldname, char* in_worldaddress, char* in_account, char* in_password, char* in_version);
void UpdateStatus(sint32 in_status, sint32 in_players, sint32 in_zones, int8 in_level) {
// we don't want the server list to update unless something has changed
if(status != in_status || num_players != in_players || num_zones != in_zones || world_max_level != in_level)
{
status = in_status;
num_players = in_players;
num_zones = in_zones;
world_max_level = in_level;
UpdateWorldList();
}
}
void UpdateWorldList(LWorld* to = 0);
void SetRemoteInfo(int32 in_ip, int32 in_accountid, char* in_account, char* in_name, char* in_address, int32 in_status, int32 in_adminid, sint32 in_players, sint32 in_zones);
inline bool IsPlaceholder() { return pPlaceholder; }
inline int32 GetAccountID() { return accountid; }
inline char* GetAccount() { return account; }
inline char* GetAddress() { return address; }
inline int16 GetClientPort() { return pClientPort; }
inline bool IsAddressIP() { return isaddressip; }
inline char* GetName() { return worldname; }
inline sint32 GetStatus() { return status; }
bool IsLocked() { return status==-2; }
inline int32 GetIP() { return ip; }
inline int16 GetPort() { return port; }
inline int32 GetID() { return ID; }
inline int32 GetAdmin() { return admin_id; }
inline bool ShowDown() { return pshowdown; }
inline bool ShowDownActive(){ return show_down_active; }
void ShowDownActive(bool show){ show_down_active = show; }
void ShowDown(bool show){ pshowdown = show; }
inline bool Connected() { return pConnected; }
int8 GetWorldStatus();
void ChangeToPlaceholder();
void Kick(const char* message = ERROR_GHOST, bool iSetKickedFlag = true);
inline bool IsKicked() { return kicked; }
inline bool IsNeverKick() { return pNeverKick; }
inline ConType GetType() { return ptype; }
inline bool IsOutgoingUplink() { return OutgoingUplink; }
inline TCPConnection* GetLink() { return Link; }
inline int32 GetRemoteID() { return RemoteID; }
inline int32 GetLinkWorldID() { return LinkWorldID; }
inline sint32 GetZoneNum() { return num_zones; }
inline sint32 GetPlayerNum() { return num_players; }
void SetID(int32 new_id) { ID = new_id; }
void SendDeleteCharacter( int32 char_id, int32 account_id );
bool IsDevelServer(){ return devel_server; }
inline int8 GetMaxWorldLevel() { return world_max_level; }
bool IsInit;
protected:
friend class LWorldList;
TCPConnection* Link;
Timer* pReconnectTimer;
Timer* pStatsTimer;
private:
int32 ID;
int32 ip;
char IPAddr[64];
int16 port;
bool kicked;
bool pNeverKick;
bool pPlaceholder;
bool devel_server;
int32 accountid;
char account[30];
char address[250];
bool isAuthenticated;
int16 pClientPort;
bool isaddressip;
char worldname[200];
sint32 status;
int32 admin_id;
bool pshowdown;
bool show_down_active;
ConType ptype;
bool OutgoingUplink;
bool pConnected;
sint32 num_players;
sint32 num_zones;
int32 RemoteID;
int32 LinkWorldID;
int8 world_max_level;
};
class LWorldList
{
public:
LWorldList();
~LWorldList();
LWorld* FindByID(int32 WorldID);
LWorld* FindByIP(int32 ip);
LWorld* FindByAddress(char* address);
LWorld* FindByLink(TCPConnection* in_link, int32 in_id);
LWorld* FindByAccount(int32 in_accountid, ConType in_type = World);
void Add(LWorld* worldserver);
void AddInitiateWorld ( LWorld* world );
void Process();
void ReceiveData();
void SendPacket(ServerPacket* pack, LWorld* butnotme = 0);
void SendPacketLocal(ServerPacket* pack, LWorld* butnotme = 0);
void SendPacketLogin(ServerPacket* pack, LWorld* butnotme = 0);
void SendWorldChanged(int32 server_id, bool sendtoallclients=false, Client* sendto = 0);
vector<PacketStruct*>* GetServerListUpdate(int16 version);
EQ2Packet* MakeServerListPacket(int8 lsadmin, int16 version);
void UpdateWorldList(LWorld* to = 0);
void UpdateWorldStats();
void KickGhost(ConType in_type, int32 in_accountid = 0, LWorld* ButNotMe = 0);
void KickGhostIP(int32 ip, LWorld* NotMe = 0, int16 iClientPort = 0);
void RemoveByLink(TCPConnection* in_link, int32 in_id = 0, LWorld* ButNotMe = 0);
void RemoveByID(int32 in_id);
void SendWorldStatus(LWorld* chat, char* adminname);
void ConnectUplink();
bool Init();
void InitWorlds();
void Shutdown();
bool WriteXML();
int32 GetCount(ConType type);
void PopulateWorldList(http::response<http::string_body>& res);
void ListWorldsToConsole();
//devn00b temp
void AddServerEquipmentUpdates(LWorld* world, map<int32, LoginEquipmentUpdate> updates);
void ProcessLSEquipUpdates();
void RequestServerEquipUpdates(LWorld* world);
void SetUpdateServerList ( bool var ) { UpdateServerList = var; }
bool ContinueServerUpdates(){ return server_update_thread; }
void ResetServerUpdates(){server_update_thread = true;}
void ProcessServerUpdates();
void RequestServerUpdates(LWorld* world);
void AddServerZoneUpdates(LWorld* world, map<int32, LoginZoneUpdate> updates);
protected:
friend class LWorld;
int32 GetNextID() { return NextID++; }
private:
Mutex MWorldMap;
map<int32, map<int32, bool> > zone_updates_already_used; //used to determine if someone is trying to DOS us
MutexMap<int32, int32> zone_update_timeouts;
MutexMap<int32, int32> awaiting_zone_update;
MutexMap<LWorld*, int32> last_updated;
MutexMap<int32, map<int32, LoginZoneUpdate> > server_zone_updates;
bool server_update_thread;
int32 NextID;
LinkedList<LWorld*> list;
map<int32,LWorld*> worldmap;
TCPServer* tcplistener;
TCPConnection* OutLink;
//devn00b temp
// JohnAdams: login appearances, copied from above
map<int32, map<int32, bool> > equip_updates_already_used;
MutexMap<int32, int32> equip_update_timeouts;
MutexMap<int32, int32> awaiting_equip_update;
MutexMap<LWorld*, int32> last_equip_updated;
MutexMap<int32, map<int32, LoginEquipmentUpdate> > server_equip_updates;
//
///
// holds the world server list so we don't have to create it for every character
// logging in
map<int32,EQ2Packet*> ServerListData;
bool UpdateServerList;
};
#endif

View File

@ -0,0 +1,447 @@
# Microsoft Developer Studio Project File - Name="Login" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=Login - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "Login.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "Login.mak" CFG="Login - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Login - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "Login - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE "Login - Win32 MiniLogin" (based on "Win32 (x86) Console Application")
!MESSAGE "Login - Win32 PublicLogin" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "Login - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "../Build"
# PROP Intermediate_Dir "../Build/Login"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MT /w /W0 /GX /Zi /O2 /Ob2 /D "LOGINCRYPTO" /D "INVERSEXY" /D _WIN32_WINNT=0x0400 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo /o"../Build/Login/Login.bsc"
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib /nologo /subsystem:console /map:"../Build/Login.map" /debug /machine:I386
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "Login - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Login___Win32_Debug"
# PROP BASE Intermediate_Dir "Login___Win32_Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "../build/login/Debug"
# PROP Intermediate_Dir "../build/login/debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /Gm /GX /ZI /Od /D "LOGINCRYPTO" /D "INVERSEXY" /D _WIN32_WINNT=0x0400 /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"LIBCMT" /out:"../build/login/Debug/LoginDebug.exe" /pdbtype:sept
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "Login - Win32 MiniLogin"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Login___Win32_MiniLogin"
# PROP BASE Intermediate_Dir "Login___Win32_MiniLogin"
# PROP BASE Ignore_Export_Lib 0
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "../Build"
# PROP Intermediate_Dir "../Build/MiniLogin"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /w /W0 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "BUILD_FOR_WINDOWS" /FR /YX /FD /c
# ADD CPP /nologo /MT /w /W0 /GX /O2 /Ob2 /D _WIN32_WINNT=0x0400 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "MINILOGIN" /FR /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo /o"../Build/Login/Login.bsc"
# ADD BSC32 /nologo /o"../Build/MiniLogin/Login.bsc"
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib /nologo /subsystem:console /machine:I386
# SUBTRACT BASE LINK32 /pdb:none
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib /nologo /subsystem:console /machine:I386 /out:"../Build/MiniLogin.exe"
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "Login - Win32 PublicLogin"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Login___Win32_PublicLogin"
# PROP BASE Intermediate_Dir "Login___Win32_PublicLogin"
# PROP BASE Ignore_Export_Lib 0
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "../Build"
# PROP Intermediate_Dir "../Build/PublicLogin"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /w /W0 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "BUILD_FOR_WINDOWS" /FR /YX /FD /c
# ADD CPP /nologo /MT /w /W0 /GX /O2 /Ob2 /D _WIN32_WINNT=0x0400 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "PUBLICLOGIN" /FR /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo /o"../Build/Login/Login.bsc"
# ADD BSC32 /nologo /o"../Build/Login/Login.bsc"
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib /nologo /subsystem:console /machine:I386
# SUBTRACT BASE LINK32 /pdb:none
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib /nologo /subsystem:console /machine:I386 /out:"../Build/PublicLogin.exe"
# SUBTRACT LINK32 /pdb:none
!ENDIF
# Begin Target
# Name "Login - Win32 Release"
# Name "Login - Win32 Debug"
# Name "Login - Win32 MiniLogin"
# Name "Login - Win32 PublicLogin"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\client.cpp
# End Source File
# Begin Source File
SOURCE=.\EQCrypto.cpp
!IF "$(CFG)" == "Login - Win32 Release"
!ELSEIF "$(CFG)" == "Login - Win32 Debug"
!ELSEIF "$(CFG)" == "Login - Win32 MiniLogin"
# PROP Exclude_From_Build 1
!ELSEIF "$(CFG)" == "Login - Win32 PublicLogin"
# PROP Exclude_From_Build 1
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\logindatabase.cpp
!IF "$(CFG)" == "Login - Win32 Release"
!ELSEIF "$(CFG)" == "Login - Win32 Debug"
!ELSEIF "$(CFG)" == "Login - Win32 MiniLogin"
# PROP Exclude_From_Build 1
!ELSEIF "$(CFG)" == "Login - Win32 PublicLogin"
!ENDIF
# End Source File
# Begin Source File
SOURCE=.\LWorld.cpp
# End Source File
# Begin Source File
SOURCE=.\net.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\client.h
# End Source File
# Begin Source File
SOURCE=.\EQCrypto.h
# End Source File
# Begin Source File
SOURCE=.\login_opcodes.h
# End Source File
# Begin Source File
SOURCE=.\login_structs.h
# End Source File
# Begin Source File
SOURCE=.\LWorld.h
# End Source File
# Begin Source File
SOURCE=.\net.h
# End Source File
# End Group
# Begin Group "Common Source Files"
# PROP Default_Filter ".cpp"
# Begin Source File
SOURCE=..\common\crc32.cpp
# End Source File
# Begin Source File
SOURCE=..\common\database.cpp
!IF "$(CFG)" == "Login - Win32 Release"
!ELSEIF "$(CFG)" == "Login - Win32 Debug"
!ELSEIF "$(CFG)" == "Login - Win32 MiniLogin"
# PROP Exclude_From_Build 1
!ELSEIF "$(CFG)" == "Login - Win32 PublicLogin"
!ENDIF
# End Source File
# Begin Source File
SOURCE=..\common\dbcore.cpp
# End Source File
# Begin Source File
SOURCE=..\common\DBMemLeak.cpp
# End Source File
# Begin Source File
SOURCE=..\common\debug.cpp
# End Source File
# Begin Source File
SOURCE=..\common\EQNetwork.cpp
# End Source File
# Begin Source File
SOURCE=..\common\md5.cpp
# End Source File
# Begin Source File
SOURCE=..\common\MiscFunctions.cpp
# End Source File
# Begin Source File
SOURCE=..\common\Mutex.cpp
# End Source File
# Begin Source File
SOURCE=..\common\packet_dump.cpp
# End Source File
# Begin Source File
SOURCE=..\common\packet_functions.cpp
# End Source File
# Begin Source File
SOURCE=..\common\TCPConnection.cpp
# End Source File
# Begin Source File
SOURCE=..\common\timer.cpp
# End Source File
# End Group
# Begin Group "Common Header Files"
# PROP Default_Filter ".h"
# Begin Source File
SOURCE=..\common\classes.h
# End Source File
# Begin Source File
SOURCE=..\common\crc32.h
# End Source File
# Begin Source File
SOURCE=..\common\database.h
# End Source File
# Begin Source File
SOURCE=..\common\DBMemLeak.h
# End Source File
# Begin Source File
SOURCE=..\common\debug.h
# End Source File
# Begin Source File
SOURCE=..\common\deity.h
# End Source File
# Begin Source File
SOURCE=..\common\eq_opcodes.h
# End Source File
# Begin Source File
SOURCE=..\common\eq_packet_structs.h
# End Source File
# Begin Source File
SOURCE=..\common\EQCheckTable.h
# End Source File
# Begin Source File
SOURCE=..\common\EQFragment.h
# End Source File
# Begin Source File
SOURCE=..\common\EQNetwork.h
# End Source File
# Begin Source File
SOURCE=..\common\EQOpcodes.h
# End Source File
# Begin Source File
SOURCE=..\common\EQPacket.h
# End Source File
# Begin Source File
SOURCE=..\common\EQPacketManager.h
# End Source File
# Begin Source File
SOURCE=..\common\errmsg.h
# End Source File
# Begin Source File
SOURCE=..\common\Guilds.h
# End Source File
# Begin Source File
SOURCE=..\common\linked_list.h
# End Source File
# Begin Source File
SOURCE=..\common\md5.h
# End Source File
# Begin Source File
SOURCE=..\common\MiscFunctions.h
# End Source File
# Begin Source File
SOURCE=..\common\moremath.h
# End Source File
# Begin Source File
SOURCE=..\common\Mutex.h
# End Source File
# Begin Source File
SOURCE=..\common\packet_dump.h
# End Source File
# Begin Source File
SOURCE=..\common\packet_dump_file.h
# End Source File
# Begin Source File
SOURCE=..\common\packet_functions.h
# End Source File
# Begin Source File
SOURCE=..\common\queue.h
# End Source File
# Begin Source File
SOURCE=..\common\queues.h
# End Source File
# Begin Source File
SOURCE=..\common\races.h
# End Source File
# Begin Source File
SOURCE=..\common\Seperator.h
# End Source File
# Begin Source File
SOURCE=..\common\servertalk.h
# End Source File
# Begin Source File
SOURCE=..\common\TCPConnection.h
# End Source File
# Begin Source File
SOURCE=..\common\timer.h
# End Source File
# Begin Source File
SOURCE=..\common\types.h
# End Source File
# Begin Source File
SOURCE=..\common\version.h
# End Source File
# End Group
# Begin Group "Text Files"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\Protocol.txt
# End Source File
# Begin Source File
SOURCE=.\Tables.txt
# End Source File
# Begin Source File
SOURCE=.\ThanksTo.txt
# End Source File
# End Group
# End Target
# End Project

View File

@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "Login"=.\Login.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@ -0,0 +1,542 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="EQ2 Login"
ProjectGUID="{BE2C1914-FCCC-4F65-A7DD-105142B36104}"
RootNamespace="EQ2 Login"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="EQ2Login|Win32"
OutputDirectory=".\../Build"
IntermediateDirectory=".\../Build/EQ2Login"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TypeLibraryName=".\../Build/Login.tlb"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/D EQDEBUG=5"
Optimization="0"
InlineFunctionExpansion="0"
PreprocessorDefinitions="_WIN32_WINNT=0x0400,WIN32,NDEBUG,_CONSOLE,LOGIN, EQ2, EQN_DEBUG,_CRT_SECURE_NO_DEPRECATE"
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\../Build/EQ2Login/Login.pch"
AssemblerListingLocation=".\../Build/EQ2Login/"
ObjectFile=".\../Build/EQ2Login/"
ProgramDataBaseFileName=".\../Build/EQ2Login/"
BrowseInformation="1"
SuppressStartupBanner="true"
DebugInformationFormat="4"
CompileAs="2"
ShowIncludes="false"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib"
OutputFile="../Build/EQ2Login.exe"
LinkIncremental="2"
SuppressStartupBanner="true"
IgnoreAllDefaultLibraries="false"
IgnoreDefaultLibraryNames="libcmtd;msvcrt"
GenerateDebugInformation="true"
ProgramDatabaseFile=".\../Build/Eq2Login.pdb"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="MiniLogin Release|Win32"
OutputDirectory="$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TypeLibraryName=".\../Build/Login.tlb"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/D EQDEBUG=5"
Optimization="2"
InlineFunctionExpansion="0"
FavorSizeOrSpeed="1"
PreprocessorDefinitions="_WIN32_WINNT=0x0400,WIN32,NDEBUG,_CONSOLE,LOGIN, EQ2, EQN_DEBUG,_CRT_SECURE_NO_DEPRECATE,MINILOGIN"
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\../Build/EQ2Login/Login.pch"
AssemblerListingLocation=".\../Build/EQ2Login/"
ObjectFile=".\../Build/EQ2Login/"
ProgramDataBaseFileName=".\../Build/EQ2Login/"
BrowseInformation="1"
SuppressStartupBanner="true"
DebugInformationFormat="0"
CompileAs="2"
ShowIncludes="false"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
AdditionalDependencies="odbc32.lib odbccp32.lib wsock32.lib zlib.lib mysqlclient.lib"
OutputFile="../Build/EQ2MiniLogin.exe"
LinkIncremental="2"
SuppressStartupBanner="true"
IgnoreAllDefaultLibraries="false"
IgnoreDefaultLibraryNames="libcmtd;msvcrt"
GenerateDebugInformation="false"
ProgramDatabaseFile=".\../Build/Eq2Login.pdb"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
<File
RelativePath=".\client.cpp"
>
</File>
<File
RelativePath=".\LoginAccount.cpp"
>
</File>
<File
RelativePath=".\LoginDatabase.cpp"
>
</File>
<File
RelativePath=".\LWorld.cpp"
>
</File>
<File
RelativePath=".\net.cpp"
>
</File>
<File
RelativePath=".\PacketHeaders.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl"
>
<File
RelativePath=".\client.h"
>
</File>
<File
RelativePath=".\login_opcodes.h"
>
</File>
<File
RelativePath=".\login_structs.h"
>
</File>
<File
RelativePath=".\LoginAccount.h"
>
</File>
<File
RelativePath=".\LoginDatabase.h"
>
</File>
<File
RelativePath=".\LWorld.h"
>
</File>
<File
RelativePath=".\net.h"
>
</File>
<File
RelativePath=".\PacketHeaders.h"
>
</File>
</Filter>
<Filter
Name="Common Source Files"
Filter=".cpp"
>
<File
RelativePath=".\Character.cpp"
>
</File>
<File
RelativePath="..\common\Condition.cpp"
>
</File>
<File
RelativePath="..\common\ConfigReader.cpp"
>
</File>
<File
RelativePath="..\common\CRC16.cpp"
>
</File>
<File
RelativePath="..\common\Crypto.cpp"
>
</File>
<File
RelativePath="..\common\database.cpp"
>
</File>
<File
RelativePath="..\common\dbcore.cpp"
>
</File>
<File
RelativePath="..\common\debug.cpp"
>
</File>
<File
RelativePath="..\common\emu_opcodes.cpp"
>
</File>
<File
RelativePath="..\common\EQEMuError.cpp"
>
</File>
<File
RelativePath="..\common\EQPacket.cpp"
>
</File>
<File
RelativePath="..\common\EQStream.cpp"
>
</File>
<File
RelativePath="..\common\EQStreamFactory.cpp"
>
</File>
<File
RelativePath="..\common\misc.cpp"
>
</File>
<File
RelativePath="..\common\MiscFunctions.cpp"
>
</File>
<File
RelativePath="..\common\Mutex.cpp"
>
</File>
<File
RelativePath="..\common\opcodemgr.cpp"
>
</File>
<File
RelativePath="..\common\packet_dump.cpp"
>
</File>
<File
RelativePath="..\common\packet_functions.cpp"
>
</File>
<File
RelativePath="..\common\PacketStruct.cpp"
>
</File>
<File
RelativePath="..\common\RC4.cpp"
>
</File>
<File
RelativePath="..\common\TCPConnection.cpp"
>
</File>
<File
RelativePath="..\common\timer.cpp"
>
</File>
<File
RelativePath="..\common\xmlParser.cpp"
>
</File>
</Filter>
<Filter
Name="Common Header Files"
Filter=".h"
>
<File
RelativePath=".\Character.h"
>
</File>
<File
RelativePath="..\common\Condition.h"
>
</File>
<File
RelativePath="..\common\ConfigReader.h"
>
</File>
<File
RelativePath="..\common\CRC16.h"
>
</File>
<File
RelativePath="..\common\Crypto.h"
>
</File>
<File
RelativePath="..\common\database.h"
>
</File>
<File
RelativePath="..\common\DataBuffer.h"
>
</File>
<File
RelativePath="..\common\dbcore.h"
>
</File>
<File
RelativePath="..\common\debug.h"
>
</File>
<File
RelativePath="..\common\emu_opcodes.h"
>
</File>
<File
RelativePath="..\common\EQ2_Common_Structs.h"
>
</File>
<File
RelativePath="..\common\EQEMuError.h"
>
</File>
<File
RelativePath="..\common\EQPacket.h"
>
</File>
<File
RelativePath="..\common\EQStream.h"
>
</File>
<File
RelativePath="..\common\EQStreamFactory.h"
>
</File>
<File
RelativePath="..\common\GlobalHeaders.h"
>
</File>
<File
RelativePath="..\common\linked_list.h"
>
</File>
<File
RelativePath="..\common\login_oplist.h"
>
</File>
<File
RelativePath="..\common\misc.h"
>
</File>
<File
RelativePath="..\common\MiscFunctions.h"
>
</File>
<File
RelativePath="..\common\Mutex.h"
>
</File>
<File
RelativePath="..\common\op_codes.h"
>
</File>
<File
RelativePath="..\common\opcodemgr.h"
>
</File>
<File
RelativePath="..\common\packet_dump.h"
>
</File>
<File
RelativePath="..\common\packet_functions.h"
>
</File>
<File
RelativePath="..\common\PacketStruct.h"
>
</File>
<File
RelativePath="..\common\queue.h"
>
</File>
<File
RelativePath="..\common\RC4.h"
>
</File>
<File
RelativePath="..\common\seperator.h"
>
</File>
<File
RelativePath="..\common\servertalk.h"
>
</File>
<File
RelativePath="..\common\TCPConnection.h"
>
</File>
<File
RelativePath="..\common\timer.h"
>
</File>
<File
RelativePath="..\common\types.h"
>
</File>
<File
RelativePath="..\common\version.h"
>
</File>
<File
RelativePath="..\common\xmlParser.h"
>
</File>
</Filter>
<Filter
Name="World Files"
>
<File
RelativePath="..\World\MutexHelper.h"
>
</File>
<File
RelativePath="..\World\MutexList.h"
>
</File>
<File
RelativePath="..\World\MutexMap.h"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="EQ2Login|x64">
<Configuration>EQ2Login</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectName>EQ2Login</ProjectName>
<ProjectGuid>{BE2C1914-FCCC-4F65-A7DD-105142B36104}</ProjectGuid>
<RootNamespace>EQ2 Login</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='EQ2Login|x64'">
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='EQ2Login|x64'">
<IncludePath>$(SolutionDir)..\source\depends\mariadb-10.1.19\include;$(SolutionDir)..\source\depends\zlib\include;$(SolutionDir)..\source\depends\recastnavigation\Detour\Include;$(SolutionDir)..\source\depends\boost_1_72_0\;$(SolutionDir)..\source\depends\glm\;$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
<LibraryPath>$(SolutionDir)..\source\depends\recastnavigation\RecastDemo\Build\vs2019\lib\Debug;$(SolutionDir)..\source\depends\mariadb-10.1.19\lib\64-debug;$(SolutionDir)..\source\depends\zlib\lib;$(SolutionDir)..\source\depends\boost_1_72_0\lib64-msvc-14.2;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64</LibraryPath>
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)loginserver\</OutDir>
<IntDir>.\$(ProjectName)__Debug64\</IntDir>
<TargetName>$(ProjectName)__Debug64</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='EQ2Login|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<PreprocessorDefinitions>_WIN32_WINNT=0x0400;WIN32;NDEBUG;_CONSOLE;LOGIN; EQ2; EQN_DEBUG;_CRT_SECURE_NO_DEPRECATE;_HAS_STD_BYTE=0
;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<FunctionLevelLinking>false</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeaderFile />
<PrecompiledHeaderOutputFile />
<ProgramDataBaseFileName>$(IntDir)</ProgramDataBaseFileName>
<BrowseInformation />
<BrowseInformationFile />
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<AdditionalDependencies>odbc32.lib;odbccp32.lib;ws2_32.lib;zlib.lib;mysqlclient.lib;DebugUtils.lib;Detour.lib;DetourCrowd.lib;DetourTileCache.lib;Recast.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>LIBCMT;LIBC;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention />
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\common\DatabaseNew.cpp" />
<ClCompile Include="..\common\DatabaseResult.cpp" />
<ClCompile Include="..\common\Log.cpp" />
<ClCompile Include="client.cpp" />
<ClCompile Include="LoginAccount.cpp" />
<ClCompile Include="LoginDatabase.cpp" />
<ClCompile Include="LWorld.cpp" />
<ClCompile Include="net.cpp" />
<ClCompile Include="PacketHeaders.cpp" />
<ClCompile Include="Character.cpp" />
<ClCompile Include="..\common\Condition.cpp" />
<ClCompile Include="..\common\ConfigReader.cpp" />
<ClCompile Include="..\common\CRC16.cpp" />
<ClCompile Include="..\common\Crypto.cpp" />
<ClCompile Include="..\common\database.cpp" />
<ClCompile Include="..\common\dbcore.cpp" />
<ClCompile Include="..\common\debug.cpp" />
<ClCompile Include="..\common\emu_opcodes.cpp" />
<ClCompile Include="..\common\EQEMuError.cpp" />
<ClCompile Include="..\common\EQPacket.cpp" />
<ClCompile Include="..\common\EQStream.cpp" />
<ClCompile Include="..\common\EQStreamFactory.cpp" />
<ClCompile Include="..\common\misc.cpp" />
<ClCompile Include="..\common\MiscFunctions.cpp" />
<ClCompile Include="..\common\Mutex.cpp" />
<ClCompile Include="..\common\opcodemgr.cpp" />
<ClCompile Include="..\common\packet_dump.cpp" />
<ClCompile Include="..\common\packet_functions.cpp" />
<ClCompile Include="..\common\PacketStruct.cpp" />
<ClCompile Include="..\common\RC4.cpp" />
<ClCompile Include="..\common\TCPConnection.cpp" />
<ClCompile Include="..\common\timer.cpp" />
<ClCompile Include="..\common\xmlParser.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\common\DatabaseNew.h" />
<ClInclude Include="..\common\DatabaseResult.h" />
<ClInclude Include="..\common\Log.h" />
<ClInclude Include="..\common\LogTypes.h" />
<ClInclude Include="client.h" />
<ClInclude Include="login_opcodes.h" />
<ClInclude Include="login_structs.h" />
<ClInclude Include="LoginAccount.h" />
<ClInclude Include="LoginDatabase.h" />
<ClInclude Include="LWorld.h" />
<ClInclude Include="net.h" />
<ClInclude Include="PacketHeaders.h" />
<ClInclude Include="Character.h" />
<ClInclude Include="..\common\Condition.h" />
<ClInclude Include="..\common\ConfigReader.h" />
<ClInclude Include="..\common\CRC16.h" />
<ClInclude Include="..\common\Crypto.h" />
<ClInclude Include="..\common\database.h" />
<ClInclude Include="..\common\DataBuffer.h" />
<ClInclude Include="..\common\dbcore.h" />
<ClInclude Include="..\common\debug.h" />
<ClInclude Include="..\common\emu_opcodes.h" />
<ClInclude Include="..\common\EQ2_Common_Structs.h" />
<ClInclude Include="..\common\EQEMuError.h" />
<ClInclude Include="..\common\EQPacket.h" />
<ClInclude Include="..\common\EQStream.h" />
<ClInclude Include="..\common\EQStreamFactory.h" />
<ClInclude Include="..\common\GlobalHeaders.h" />
<ClInclude Include="..\common\linked_list.h" />
<ClInclude Include="..\common\login_oplist.h" />
<ClInclude Include="..\common\misc.h" />
<ClInclude Include="..\common\MiscFunctions.h" />
<ClInclude Include="..\common\Mutex.h" />
<ClInclude Include="..\common\op_codes.h" />
<ClInclude Include="..\common\opcodemgr.h" />
<ClInclude Include="..\common\packet_dump.h" />
<ClInclude Include="..\common\packet_functions.h" />
<ClInclude Include="..\common\PacketStruct.h" />
<ClInclude Include="..\common\queue.h" />
<ClInclude Include="..\common\RC4.h" />
<ClInclude Include="..\common\seperator.h" />
<ClInclude Include="..\common\servertalk.h" />
<ClInclude Include="..\common\TCPConnection.h" />
<ClInclude Include="..\common\timer.h" />
<ClInclude Include="..\common\types.h" />
<ClInclude Include="..\common\version.h" />
<ClInclude Include="..\common\xmlParser.h" />
<ClInclude Include="..\World\MutexHelper.h" />
<ClInclude Include="..\World\MutexList.h" />
<ClInclude Include="..\World\MutexMap.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,277 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{bfe8d6b0-594f-4b55-9f95-101bbcf4069c}</UniqueIdentifier>
<Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{d65b2760-468c-4206-a19a-48323a50ba5a}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl</Extensions>
</Filter>
<Filter Include="Common Source Files">
<UniqueIdentifier>{27b769a5-0972-4e9e-b78c-09ad3341579c}</UniqueIdentifier>
<Extensions>.cpp</Extensions>
</Filter>
<Filter Include="Common Header Files">
<UniqueIdentifier>{11757e5a-691c-49c9-a627-df027ad58326}</UniqueIdentifier>
<Extensions>.h</Extensions>
</Filter>
<Filter Include="World Files">
<UniqueIdentifier>{99e7f9f9-abcd-4abf-8200-a4b5a467788c}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="client.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="LoginAccount.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="LoginDatabase.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="LWorld.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="net.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="PacketHeaders.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Character.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\Condition.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\ConfigReader.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\CRC16.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\Crypto.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\database.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\dbcore.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\debug.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\emu_opcodes.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\EQEMuError.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\EQPacket.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\EQStream.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\EQStreamFactory.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\misc.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\MiscFunctions.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\Mutex.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\opcodemgr.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\packet_dump.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\packet_functions.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\PacketStruct.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\RC4.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\TCPConnection.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\timer.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\xmlParser.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\Log.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\DatabaseNew.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
<ClCompile Include="..\common\DatabaseResult.cpp">
<Filter>Common Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="client.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="login_opcodes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="login_structs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="LoginAccount.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="LoginDatabase.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="LWorld.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="net.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PacketHeaders.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Character.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\Condition.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\ConfigReader.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\CRC16.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\Crypto.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\database.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\DataBuffer.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\dbcore.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\debug.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\emu_opcodes.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\EQ2_Common_Structs.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\EQEMuError.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\EQPacket.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\EQStream.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\EQStreamFactory.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\GlobalHeaders.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\linked_list.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\login_oplist.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\misc.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\MiscFunctions.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\Mutex.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\op_codes.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\opcodemgr.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\packet_dump.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\packet_functions.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\PacketStruct.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\queue.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\RC4.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\seperator.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\servertalk.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\TCPConnection.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\timer.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\types.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\version.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\xmlParser.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\World\MutexHelper.h">
<Filter>World Files</Filter>
</ClInclude>
<ClInclude Include="..\World\MutexList.h">
<Filter>World Files</Filter>
</ClInclude>
<ClInclude Include="..\World\MutexMap.h">
<Filter>World Files</Filter>
</ClInclude>
<ClInclude Include="..\common\Log.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\LogTypes.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\DatabaseNew.h">
<Filter>Common Header Files</Filter>
</ClInclude>
<ClInclude Include="..\common\DatabaseResult.h">
<Filter>Common Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>

View File

@ -0,0 +1,58 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
*/
#include "LoginAccount.h"
LoginAccount::LoginAccount(){
}
LoginAccount::~LoginAccount(){
vector<CharSelectProfile*>::iterator iter;
for(iter = charlist.begin(); iter != charlist.end(); iter++){
safe_delete(*iter);
}
}
void LoginAccount::flushCharacters ( )
{
vector<CharSelectProfile*>::iterator iter;
for(iter = charlist.begin(); iter != charlist.end(); iter++){
safe_delete(*iter);
}
charlist.clear ( );
}
CharSelectProfile* LoginAccount::getCharacter(char* name){
vector<CharSelectProfile*>::iterator char_iterator;
CharSelectProfile* profile = 0;
EQ2_16BitString temp;
for(char_iterator = charlist.begin(); char_iterator != charlist.end(); char_iterator++){
profile = *char_iterator;
temp = profile->packet->getType_EQ2_16BitString_ByName("name");
if(strcmp(temp.data.c_str(), name)==0)
return profile;
}
return 0;
}
void LoginAccount::removeCharacter(char* name, int16 version){
vector<CharSelectProfile*>::iterator iter;
CharSelectProfile* profile = 0;
EQ2_16BitString temp;
for(iter = charlist.begin(); iter != charlist.end(); iter++){
profile = *iter;
temp = profile->packet->getType_EQ2_16BitString_ByName("name");
if(strcmp(temp.data.c_str(), name)==0){
if(version <= 561) {
profile->deleted = true; // workaround for char select crash on old clients
}
else {
safe_delete(*iter);
charlist.erase(iter);
}
return;
}
}
}

View File

@ -0,0 +1,54 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
*/
#ifndef _LOGINACCOUNT_
#define _LOGINACCOUNT_
#include <iostream>
#include <string>
#include <vector>
#include "../common/linked_list.h"
#include "PacketHeaders.h"
#include "../common/PacketStruct.h"
using namespace std;
class LoginAccount {
public:
LoginAccount();
LoginAccount(int32 id, const char* in_name, const char* in_pass){
account_id = id;
strcpy(name, in_name);
strcpy(password, in_pass);
}
~LoginAccount();
bool SaveAccount(LoginAccount* acct);
vector<CharSelectProfile*> charlist;
void setName(const char* in_name) { strcpy(name, in_name); }
void setPassword(const char* in_pass) { strcpy(password, in_pass); }
void setAuthenticated(bool in_auth) { authenticated=in_auth; }
void setAccountID(int32 id){ account_id = id; }
void addCharacter(CharSelectProfile* profile){
charlist.push_back(profile);
}
void removeCharacter(PacketStruct* profile);
void removeCharacter(char* name, int16 version);
void serializeCharacter(uchar* buffer, CharSelectProfile* profile);
void flushCharacters ( );
CharSelectProfile* getCharacter(char* name);
int32 getLoginAccountID(){ return account_id; }
char* getLoginName() { return name; }
char* getLoginPassword() { return password; }
bool getLoginAuthenticated() { return authenticated; }
private:
int32 account_id;
char name[32];
char password[32];
bool authenticated;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
*/
#ifndef EQ2LOGIN_EMU_DATABASE_H
#define EQ2LOGIN_EMU_DATABASE_H
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <winsock.h>
#include <windows.h>
#endif
#include <mysql.h>
#include <string>
#include <vector>
#include "../common/database.h"
#include "../common/DatabaseNew.h"
#include "../common/types.h"
#include "../common/MiscFunctions.h"
#include "../common/servertalk.h"
#include "../common/Mutex.h"
#include "PacketHeaders.h"
#include "LoginAccount.h"
#include "LWorld.h"
#include "../common/PacketStruct.h"
using namespace std;
#pragma pack()
class LoginDatabase : public Database
{
public:
void FixBugReport();
void UpdateAccountIPAddress(int32 account_id, int32 address);
void UpdateWorldIPAddress(int32 world_id, int32 address);
void SaveBugReport(int32 world_id, char* category, char* subcategory, char* causes_crash, char* reproducible, char* summary, char* description, char* version, char* player, int32 account_id, char* spawn_name, int32 spawn_id, int32 zone_id);
LoginAccount* LoadAccount(const char* name, const char* password, bool attemptAccountCreation=true);
int32 GetAccountIDByName(const char* name);
int32 CheckServerAccount(char* name, char* passwd);
bool IsServerAccountDisabled(char* name);
bool IsIPBanned(char* ipaddr);
void GetServerAccounts(vector<LWorld*>* server_list);
char* GetServerAccountName(int32 id);
bool VerifyDelete(int32 account_id, int32 character_id, const char* name);
void SetServerZoneDescriptions(int32 server_id, map<int32, LoginZoneUpdate> zone_descriptions);
int32 GetServer(int32 accountID, int32 charID, string name);
void LoadCharacters(LoginAccount* acct, int16 version);
void CheckCharacterTimeStamps(LoginAccount* acct);
string GetCharacterName(int32 char_id , int32 server_id, int32 account_id);
void SaveCharacterColors(int32 char_id, char* type, EQ2_Color color);
void SaveCharacterFloats(int32 char_id, char* type, float float1, float float2, float float3, float multiplier=100.0f);
int16 GetAppearanceID(string name);
void DeactivateCharID(int32 server_id, int32 char_id, int32 exception_id);
int32 SaveCharacter(PacketStruct* create, LoginAccount* acct, int32 world_charid, int32 client_version);
void LoadAppearanceData(int32 char_id, PacketStruct* char_select_packet);
bool UpdateCharacterTimeStamp(int32 account_id, int32 character_id, int32 timestamp_update, int32 server_id);
bool UpdateCharacterLevel(int32 account_id, int32 character_id, int8 in_level, int32 server_id);
bool UpdateCharacterRace(int32 account_id, int32 character_id, int16 in_racetype, int8 in_race, int32 server_id);
bool UpdateCharacterClass(int32 account_id, int32 character_id, int8 in_class, int32 server_id);
bool UpdateCharacterZone(int32 account_id, int32 character_id, int32 zone_id, int32 server_id);
bool UpdateCharacterGender(int32 account_id, int32 character_id, int8 in_gender, int32 server_id);
int32 GetRaceID(char* name);
void UpdateRaceID(char* name);
bool DeleteCharacter(int32 account_id, int32 character_id, int32 server_id);
void SaveClientLog(const char* type, const char* message, const char* player_name, int16 version);
bool CheckVersion(char* version);
void GetLatestTableVersions(LatestTableVersions* table_versions);
TableQuery* GetLatestTableQuery(int32 server_ip, char* name, int16 version);
bool VerifyDataTable(char* name);
sint16 GetDataVersion(char* name);
void SetZoneInformation(int32 server_id, int32 zone_id, int32 version, PacketStruct* packet);
string GetZoneDescription(char* name);
string GetColumnNames(char* name);
TableDataQuery* GetTableDataQuery(int32 server_ip, char* name, int16 version);
void UpdateWorldServerStats( LWorld* world, sint32 status);
bool ResetWorldServerStatsConnectedTime( LWorld* world );
void RemoveOldWorldServerStats();
void ResetWorldStats();
//devn00b temp
bool ConnectNewDatabase();
void SetServerEquipmentAppearances(int32 server_id, map<int32, LoginEquipmentUpdate> equip_updates); // JohnAdams: login appearances
int32 GetLoginCharacterIDFromWorldCharID(int32 server_id, int32 char_id); // JohnAdams: login appearances
void RemoveDeletedCharacterData();
int8 GetMaxCharsSetting();
int16 GetAccountBonus(int32 acct_id);
void UpdateWorldVersion(int32 world_id, char* version);
void UpdateAccountClientDataVersion(int32 account_id, int16 version);
void SaveCharacterPicture(int32 account_id, int32 character_id, int32 server_id, int16 picture_size, uchar* picture);
DatabaseNew dbLogin;
};
#endif

View File

@ -0,0 +1,88 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
*/
#include "PacketHeaders.h"
#include "../common/MiscFunctions.h"
#include "LoginDatabase.h"
#include "LWorld.h"
extern LWorldList world_list;
extern LoginDatabase database;
void LS_DeleteCharacterRequest::loadData(EQApplicationPacket* packet){
InitializeLoadData(packet->pBuffer, packet->size);
LoadData(character_number);
LoadData(server_id);
LoadData(spacer);
LoadDataString(name);
}
EQ2Packet* LS_CharSelectList::serialize(int16 version){
Clear();
AddData(num_characters);
AddData(char_data);
if (version <= 561) {
LS_CharListAccountInfoEarlyClient account_info;
account_info.account_id = account_id;
account_info.unknown1 = 0xFFFFFFFF;
account_info.unknown2 = 0;
account_info.maxchars = 7; //live has a max of 7 on gold accounts base.
account_info.unknown4 = 0;
AddData(account_info);
}
else {
LS_CharListAccountInfo account_info;
account_info.account_id = account_id;
account_info.unknown1 = 0xFFFFFFFF;
account_info.unknown2 = 0;
account_info.maxchars = database.GetMaxCharsSetting();
account_info.vet_adv_bonus = database.GetAccountBonus(account_id);
account_info.vet_trade_bonus = 0;
account_info.unknown4 = 0;
for (int i = 0; i < 3; i++)
account_info.unknown5[i] = 0xFFFFFFFF;
account_info.unknown5[3] = 0;
AddData(account_info);
}
return new EQ2Packet(OP_AllCharactersDescReplyMsg, getData(), getDataSize());
}
void LS_CharSelectList::addChar(uchar* data, int16 size){
char_data.append((char*)data, size);
}
void LS_CharSelectList::loadData(int32 account, vector<CharSelectProfile*> charlist, int16 version){
vector<CharSelectProfile*>::iterator itr;
account_id = account;
num_characters = 0;
char_data = "";
CharSelectProfile* character = 0;
for(itr = charlist.begin();itr != charlist.end();itr++){
character = *itr;
int32 serverID = character->packet->getType_int32_ByName("server_id");
if(character->deleted) { // workaround for old clients <= 561 that crash if you delete a char (Doesn't refresh the char panel correctly)
character->packet->setDataByName("name", "(deleted)");
character->packet->setDataByName("charid", 0xFFFFFFFF);
character->packet->setDataByName("name", 0xFFFFFFFF);
character->packet->setDataByName("server_id", 0xFFFFFFFF);
character->packet->setDataByName("created_date", 0xFFFFFFFF);
character->packet->setDataByName("unknown1", 0xFFFFFFFF);
character->packet->setDataByName("unknown2", 0xFFFFFFFF);
character->packet->setDataByName("flags", 0xFF);
}
else if(serverID == 0 || !world_list.FindByID(serverID))
continue;
num_characters++;
character->SaveData(version);
addChar(character->getData(), character->getDataSize());
}
}
void CharSelectProfile::SaveData(int16 in_version){
Clear();
AddData(*packet->serializeString());
}

View File

@ -0,0 +1,61 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
*/
#ifndef __PACKET_HEADERS__
#define __PACKET_HEADERS__
#include "../common/types.h"
#include "../common/EQPacket.h"
#include "../common/EQ2_Common_Structs.h"
#include "login_structs.h"
#include "../common/DataBuffer.h"
#include "../common/GlobalHeaders.h"
#include "../common/ConfigReader.h"
#include <vector>
extern ConfigReader configReader;
class CharSelectProfile : public DataBuffer{
public:
CharSelectProfile(int16 version){
deleted = false;
packet = configReader.getStruct("CharSelectProfile",version);
for(int8 i=0;i<24;i++){
packet->setEquipmentByName("equip",0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,i);
}
}
~CharSelectProfile(){
safe_delete(packet);
}
PacketStruct* packet;
void SaveData(int16 in_version);
void Data();
int16 size;
bool deleted;
};
class LS_CharSelectList : public DataBuffer {
public:
int8 num_characters;
int32 account_id;
EQ2Packet* serialize(int16 version);
void addChar(uchar* data, int16 size);
string char_data;
void loadData(int32 account, vector<CharSelectProfile*> charlist, int16 version);
};
class LS_DeleteCharacterRequest : public DataBuffer{
public:
int32 character_number;
int32 server_id;
int32 spacer;
EQ2_16BitString name;
void loadData(EQApplicationPacket* packet);
};
#endif

View File

@ -0,0 +1,64 @@
#include "../net.h"
#include "../LWorld.h"
#include <boost/algorithm/string.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
extern ClientList client_list;
extern LWorldList world_list;
extern NetConnection net;
void NetConnection::Web_loginhandle_status(const http::request<http::string_body>& req, http::response<http::string_body>& res) {
res.set(http::field::content_type, "application/json");
boost::property_tree::ptree pt;
pt.put("web_status", "online");
pt.put("login_status", net.login_running ? "online" : "offline");
pt.put("login_uptime", (getCurrentTimestamp() - net.login_uptime));
auto [days, hours, minutes, seconds] = convertTimestampDuration((getCurrentTimestamp() - net.login_uptime));
std::string uptime_str("Days: " + std::to_string(days) + ", " + "Hours: " + std::to_string(hours) + ", " + "Minutes: " + std::to_string(minutes) + ", " + "Seconds: " + std::to_string(seconds));
pt.put("login_uptime_string", uptime_str);
pt.put("world_count", world_list.GetCount(ConType::World));
pt.put("client_count", net.numclients);
std::ostringstream oss;
boost::property_tree::write_json(oss, pt);
std::string json = oss.str();
res.body() = json;
res.prepare_payload();
}
void NetConnection::Web_loginhandle_worlds(const http::request<http::string_body>& req, http::response<http::string_body>& res) {
world_list.PopulateWorldList(res);
}
void LWorldList::PopulateWorldList(http::response<http::string_body>& res) {
struct in_addr in;
res.set(http::field::content_type, "application/json");
boost::property_tree::ptree maintree;
std::ostringstream oss;
map<int32,LWorld*>::iterator map_list;
for( map_list = worldmap.begin(); map_list != worldmap.end(); map_list++) {
LWorld* world = map_list->second;
in.s_addr = world->GetIP();
if (world->GetType() == World) {
boost::property_tree::ptree pt;
pt.put("id", world->GetID());
pt.put("world_name", world->GetName());
pt.put("status", (world->GetStatus() == 1) ? "online" : "offline");
pt.put("ip_addr", inet_ntoa(in));
maintree.add_child("WorldServer", pt);
}
}
boost::property_tree::write_json(oss, maintree);
std::string json = oss.str();
res.body() = json;
res.prepare_payload();
}

Binary file not shown.

View File

@ -0,0 +1,813 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
*/
#include "../common/debug.h"
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock.h>
#include <process.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
#include <string.h>
#include <iomanip>
#include <stdlib.h>
#include <assert.h>
#include "net.h"
#include "client.h"
#include "../common/EQStream.h"
#include "../common/packet_dump.h"
#include "../common/packet_functions.h"
#include "../common/emu_opcodes.h"
#include "../common/MiscFunctions.h"
#include "LWorld.h"
#include "LoginDatabase.h"
#include "../common/ConfigReader.h"
#include "../common/Log.h"
extern NetConnection net;
extern LWorldList world_list;
extern ClientList client_list;
extern LoginDatabase database;
extern map<int16,OpcodeManager*>EQOpcodeManager;
extern ConfigReader configReader;
using namespace std;
Client::Client(EQStream* ieqnc) {
eqnc = ieqnc;
ip = eqnc->GetrIP();
port = ntohs(eqnc->GetrPort());
account_id = 0;
lsadmin = 0;
worldadmin = 0;
lsstatus = 0;
version = 0;
kicked = false;
verified = false;
memset(bannedreason, 0, sizeof(bannedreason));
//worldresponse_timer = new Timer(10000);
//worldresponse_timer->Disable();
memset(key,0,10);
LoginMode = None;
num_updates = 0;
updatetimer = new Timer(500);
updatelisttimer = new Timer(10000);
//keepalive = new Timer(5000);
//logintimer = new Timer(500); // Give time for the servers to send updates
//keepalive->Start();
//updatetimer->Start();
//logintimer->Disable();
disconnectTimer = 0;
memset(ClientSession,0,25);
request_num = 0;
login_account = 0;
createRequest = 0;
playWaitTimer = NULL;
start = false;
update_position = 0;
update_packets = 0;
needs_world_list = true;
sent_character_list = false;
}
Client::~Client() {
//safe_delete(worldresponse_timer);
//safe_delete(logintimer);
safe_delete(login_account);
eqnc->Close();
safe_delete(playWaitTimer);
safe_delete(createRequest);
safe_delete(disconnectTimer);
safe_delete(updatetimer);
}
bool Client::Process() {
if(!start && !eqnc->CheckActive()){
if(!playWaitTimer)
playWaitTimer = new Timer(5000);
else if(playWaitTimer->Check()){
safe_delete(playWaitTimer);
return false;
}
return true;
}
else if(!start){
safe_delete(playWaitTimer);
start = true;
}
if (disconnectTimer && disconnectTimer->Check())
{
safe_delete(disconnectTimer);
getConnection()->SendDisconnect();
}
if (!kicked) {
/************ Get all packets from packet manager out queue and process them ************/
EQApplicationPacket *app = 0;
/*if(logintimer && logintimer->Check())
{
database.LoadCharacters(GetLoginAccount());
SendLoginAccepted();
logintimer->Disable();
}*/
/*if(worldresponse_timer && worldresponse_timer->Check())
{
FatalError(WorldDownErrorMessage);
worldresponse_timer->Disable();
}*/
if(playWaitTimer != NULL && playWaitTimer->Check ( ) )
{
SendPlayFailed(PLAY_ERROR_SERVER_TIMEOUT);
safe_delete(playWaitTimer);
}
if(!needs_world_list && updatetimer && updatetimer->Check()){
if(updatelisttimer && updatelisttimer->Check()){
if(num_updates >= 180){ //30 minutes
getConnection()->SendDisconnect();
}
else{
vector<PacketStruct*>::iterator itr;
if(update_packets){
for(itr = update_packets->begin(); itr != update_packets->end(); itr++){
safe_delete(*itr);
}
}
safe_delete(update_packets);
update_packets = world_list.GetServerListUpdate(version);
}
num_updates++;
}
else{
if(!update_packets){
update_packets = world_list.GetServerListUpdate(version);
}
else{
if(update_position < update_packets->size()){
QueuePacket(update_packets->at(update_position)->serialize());
update_position++;
}
else
update_position = 0;
}
}
}
while(app = eqnc->PopPacket())
{
switch(app->GetOpcode())
{
case OP_LoginRequestMsg:{
DumpPacket(app);
PacketStruct* packet = configReader.getStruct("LS_LoginRequest", 1);
if(packet && packet->LoadPacketData(app->pBuffer,app->size)){
version = packet->getType_int16_ByName("version");
LogWrite(LOGIN__DEBUG, 0, "Login", "Classic Client Version Provided: %i", version);
if (version == 0 || EQOpcodeManager.count(GetOpcodeVersion(version)) == 0)
{
safe_delete(packet);
packet = configReader.getStruct("LS_LoginRequest", 1208);
if (packet && packet->LoadPacketData(app->pBuffer, app->size)) {
version = packet->getType_int16_ByName("version");
}
else
break;
}
//[7:19 PM] Kirmmin: Well, I very quickly learned that unknown3 in LS_LoginRequest packet is the same value as cl_eqversion in the eq2_defaults.ini file.
LogWrite(LOGIN__DEBUG, 0, "Login", "New Client Version Provided: %i", version);
if (EQOpcodeManager.count(GetOpcodeVersion(version)) == 0) {
LogWrite(LOGIN__ERROR, 0, "Login", "Incompatible client version provided: %i", version);
SendLoginDenied();
return false;
}
if(EQOpcodeManager.count(GetOpcodeVersion(version)) > 0 && getConnection()){
getConnection()->SetClientVersion(GetVersion());
EQ2_16BitString username = packet->getType_EQ2_16BitString_ByName("username");
EQ2_16BitString password = packet->getType_EQ2_16BitString_ByName("password");
LoginAccount* acct = database.LoadAccount(username.data.c_str(),password.data.c_str(), net.IsAllowingAccountCreation());
if(acct){
Client* otherclient = client_list.FindByLSID(acct->getLoginAccountID());
if(otherclient)
otherclient->getConnection()->SendDisconnect(); // This person is already logged in, we don't want them logged in twice, kick the previous client as it might be a ghost
}
if(acct){
SetAccountName(username.data.c_str());
database.UpdateAccountIPAddress(acct->getLoginAccountID(), getConnection()->GetrIP());
database.UpdateAccountClientDataVersion(acct->getLoginAccountID(), version);
LogWrite(LOGIN__INFO, 0, "Login", "%s successfully logged in.", (char*)username.data.c_str());
}
else
{
if (username.size > 0)
LogWrite(LOGIN__ERROR, 0, "Login", "%s login failed!", (char*)username.data.c_str());
else
LogWrite(LOGIN__ERROR, 0, "Login", "[UNKNOWN USER] login failed!");
}
if(!acct)
SendLoginDenied();
else{
needs_world_list = true;
SetLoginAccount(acct);
SendLoginAccepted();
}
}
else{
cout << "Error bad version: " << version << endl;
SendLoginDeniedBadVersion();
}
}
else{
cout << "Error loading LS_LoginRequest packet: \n";
//DumpPacket(app);
}
safe_delete(packet);
break;
}
case OP_KeymapLoadMsg:{
// cout << "Received OP_KeymapNoneMsg\n";
//dunno what this is for
break;
}
case OP_AllWSDescRequestMsg:{
SendWorldList();
needs_world_list = false;
if(!sent_character_list) {
database.LoadCharacters(GetLoginAccount(), GetVersion());
sent_character_list = true;
}
SendCharList();
break;
}
case OP_LsClientCrashlogReplyMsg:{
// DumpPacket(app);
SaveErrorsToDB(app, "Crash Log", GetVersion());
break;
}
case OP_LsClientVerifylogReplyMsg:{
// DumpPacket(app);
SaveErrorsToDB(app, "Verify Log", GetVersion());
break;
}
case OP_LsClientAlertlogReplyMsg:{
// DumpPacket(app);
SaveErrorsToDB(app, "Alert Log", GetVersion());
break;
}
case OP_LsClientBaselogReplyMsg:{
// DumpPacket(app);
SaveErrorsToDB(app, "Base Log", GetVersion());
break;
}
case OP_AllCharactersDescRequestMsg:{
break;
}
case OP_CreateCharacterRequestMsg:{
PacketStruct* packet = configReader.getStruct("CreateCharacter", GetVersion());
DumpPacket(app);
playWaitTimer = new Timer ( 15000 );
playWaitTimer->Start ( );
LogWrite(WORLD__INFO, 1, "World", "Character creation request from account %s", GetAccountName());
if(packet->LoadPacketData(app->pBuffer,app->size, GetVersion() <= 561 ? false : true)){
DumpPacket(app->pBuffer, app->size);
packet->setDataByName("account_id",GetAccountID());
LWorld* world_server = world_list.FindByID(packet->getType_int32_ByName("server_id"));
if(!world_server)
{
DumpPacket(app->pBuffer, app->size);
cout << GetAccountName() << " attempted creation of character with an invalid server id of: " << packet->getType_int32_ByName("server_id") << "\n";
break;
}
else
{
createRequest = packet;
ServerPacket* outpack = new ServerPacket(ServerOP_CharacterCreate, app->size+sizeof(int16));
int16 out_version = GetVersion();
memcpy(outpack->pBuffer, &out_version, sizeof(int16));
memcpy(outpack->pBuffer + sizeof(int16), app->pBuffer, app->size);
uchar* tmp = outpack->pBuffer;
if(out_version<=283)
tmp+=2;
else if(out_version == 373) {
tmp += 6;
}
else
tmp += 7;
int32 account_id = GetAccountID();
memcpy(tmp, &account_id, sizeof(int32));
world_server->SendPacket(outpack);
safe_delete(outpack);
}
}
else{
LogWrite(WORLD__ERROR, 1, "World", "Error in character creation request from account %s!", GetAccountName());
safe_delete(packet);
}
// world_list.SendWorldChanged(create.profile.server_id, false, this);
break;
}
case OP_PlayCharacterRequestMsg:{
int32 char_id = 0;
int32 server_id = 0;
PacketStruct* request = configReader.getStruct("LS_PlayRequest",GetVersion());
if(request && request->LoadPacketData(app->pBuffer,app->size)){
char_id = request->getType_int32_ByName("char_id");
if (GetVersion() <= 283) {
server_id = database.GetServer(GetAccountID(), char_id, request->getType_EQ2_16BitString_ByName("name").data);
}
else {
server_id = request->getType_int32_ByName("server_id");
}
LWorld* world = world_list.FindByID(server_id);
string name = database.GetCharacterName(char_id,server_id,GetAccountID());
if(world && name.length() > 0){
pending_play_char_id = char_id;
ServerPacket* outpack = new ServerPacket(ServerOP_UsertoWorldReq, sizeof(UsertoWorldRequest_Struct));
UsertoWorldRequest_Struct* req = (UsertoWorldRequest_Struct*)outpack->pBuffer;
req->char_id = char_id;
req->lsaccountid = GetAccountID();
req->worldid = server_id;
struct in_addr in;
in.s_addr = GetIP();
strcpy(req->ip_address, inet_ntoa(in));
world->SendPacket(outpack);
delete outpack;
safe_delete(playWaitTimer);
playWaitTimer = new Timer ( 5000 );
playWaitTimer->Start ( );
}
else{
cout << GetAccountName() << " sent invalid Play Request: \n";
SendPlayFailed(PLAY_ERROR_PROBLEM);
DumpPacket(app);
}
}
safe_delete(request);
break;
}
case OP_DeleteCharacterRequestMsg:{
PacketStruct* request = configReader.getStruct("LS_DeleteCharacterRequest", GetVersion());
PacketStruct* response = configReader.getStruct("LS_DeleteCharacterResponse", GetVersion());
if(request && response && request->LoadPacketData(app->pBuffer,app->size)){
EQ2_16BitString name = request->getType_EQ2_16BitString_ByName("name");
int32 acct_id = GetAccountID();
int32 char_id = request->getType_int32_ByName("char_id");
int32 server_id = request->getType_int32_ByName("server_id");
if(database.VerifyDelete(acct_id, char_id, name.data.c_str())){
response->setDataByName("response", 1);
GetLoginAccount()->removeCharacter((char*)name.data.c_str(), GetVersion());
LWorld* world_server = world_list.FindByID(server_id);
if(world_server != NULL)
world_server->SendDeleteCharacter ( char_id , acct_id );
}
else
response->setDataByName("response", 0);
response->setDataByName("server_id", server_id);
response->setDataByName("char_id", char_id);
response->setDataByName("account_id", account_id);
response->setMediumStringByName("name", (char*)name.data.c_str());
response->setDataByName("max_characters", 10);
EQ2Packet* outapp = response->serialize();
QueuePacket(outapp);
this->SendCharList();
}
safe_delete(request);
safe_delete(response);
break;
}
default: {
const char* name = app->GetOpcodeName();
if (name)
LogWrite(OPCODE__DEBUG, 1, "Opcode", "%s Received %04X (%i)", name, app->GetRawOpcode(), app->GetRawOpcode());
else
LogWrite(OPCODE__DEBUG, 1, "Opcode", "Received %04X (%i)", app->GetRawOpcode(), app->GetRawOpcode());
}
}
delete app;
}
}
if (!eqnc->CheckActive()) {
return false;
}
return true;
}
void Client::SaveErrorsToDB(EQApplicationPacket* app, char* type, int32 version){
int32 size = 0;
z_stream zstream;
if (version >= 546) {
memcpy(&size, app->pBuffer + sizeof(int32), sizeof(int32));
zstream.next_in = app->pBuffer + 8;
zstream.avail_in = app->size - 8;
}
else { //box set
size = 0xFFFF;
zstream.next_in = app->pBuffer + 2;
zstream.avail_in = app->size - 2;
}
size++;
char* message = new char[size];
memset(message, 0, size);
int zerror = 0;
zstream.next_out = (BYTE*)message;
zstream.avail_out = size;
zstream.zalloc = Z_NULL;
zstream.zfree = Z_NULL;
zstream.opaque = Z_NULL;
zerror = inflateInit( &zstream);
if(zerror != Z_OK) {
safe_delete_array(message);
return;
}
zerror = inflate( &zstream, 0 );
if(message && strlen(message) > 0)
database.SaveClientLog(type, message, GetLoginAccount()->getLoginName(), GetVersion());
safe_delete_array(message);
}
void Client::CharacterApproved(int32 server_id,int32 char_id)
{
if(createRequest && server_id == createRequest->getType_int32_ByName("server_id")){
LWorld* world_server = world_list.FindByID(server_id);
if(!world_server)
return;
PacketStruct* packet = configReader.getStruct("LS_CreateCharacterReply", GetVersion());
if(packet){
packet->setDataByName("account_id", GetAccountID());
packet->setDataByName("unknown", 0xFFFFFFFF);
packet->setDataByName("response", CREATESUCCESS_REPLY);
packet->setMediumStringByName("name", (char*)createRequest->getType_EQ2_16BitString_ByName("name").data.c_str());
EQ2Packet* outapp = packet->serialize();
QueuePacket(outapp);
safe_delete(packet);
database.SaveCharacter(createRequest, GetLoginAccount(),char_id, GetVersion());
// refresh characters for this account
database.LoadCharacters(GetLoginAccount(), GetVersion());
SendCharList();
if (GetVersion() <= 561)
{
pending_play_char_id = char_id;
ServerPacket* outpack = new ServerPacket(ServerOP_UsertoWorldReq, sizeof(UsertoWorldRequest_Struct));
UsertoWorldRequest_Struct* req = (UsertoWorldRequest_Struct*)outpack->pBuffer;
req->char_id = char_id;
req->lsaccountid = GetAccountID();
req->worldid = server_id;
struct in_addr in;
in.s_addr = GetIP();
strcpy(req->ip_address, inet_ntoa(in));
world_server->SendPacket(outpack);
delete outpack;
}
}
}
else{
cout << GetAccountName() << " received invalid CharacterApproval from server: " << server_id << endl;
}
safe_delete(createRequest);
}
void Client::CharacterRejected(int8 reason_number)
{
PacketStruct* packet = configReader.getStruct("LS_CreateCharacterReply", GetVersion());
if(createRequest && packet){
packet->setDataByName("account_id", GetAccountID());
int8 clientReasonNum = reason_number;
// reason numbers change and instead of updating the world server
// the login server will hold the up to date #'s
/*
switch(reason_number)
{
// these error codes seem to be removed now, they shutdown the client rather immediately
// for now we are just going to play a joke on them and say they can't create a new character.
case INVALIDRACE_REPLY:
case INVALIDGENDER_REPLY:
clientReasonNum = 8;
break;
case BADNAMELENGTH_REPLY:
clientReasonNum = 9;
break;
case NAMEINVALID_REPLY:
clientReasonNum = 10;
break;
case NAMEFILTER_REPLY:
clientReasonNum = 11;
break;
case NAMETAKEN_REPLY:
clientReasonNum = 12;
break;
case OVERLOADEDSERVER_REPLY:
clientReasonNum = 13;
break;
}
*/
packet->setDataByName("response", clientReasonNum);
packet->setMediumStringByName("name", "");
EQ2Packet* outapp = packet->serialize();
QueuePacket(outapp);
safe_delete(packet);
}
/*LS_CreateCharacterReply reply(GetAccountID(), reason_number, create.profile.name.data);
EQ2Packet* outapp = reply.serialize();
QueuePacket(outapp);
create.Clear();*/
}
void Client::SendCharList(){
/*PacketStruct* packet = configReader.getStruct("LS_CreateCharacterReply");
packet->setDataByName("account_id", GetAccountID());
packet->setDataByName("response", reason_number);
packet->setDataByName("name", &create.profile.name);
EQ2Packet* outapp = packet->serialize();
QueuePacket(outapp);
safe_delete(packet);*/
LogWrite(LOGIN__INFO, 0, "Login", "[%s] sending character list.", GetAccountName());
LS_CharSelectList list;
list.loadData(GetAccountID(), GetLoginAccount()->charlist, GetVersion());
EQ2Packet* outapp = list.serialize(GetVersion());
DumpPacket(outapp->pBuffer, outapp->size);
QueuePacket(outapp);
}
void Client::SendLoginDeniedBadVersion(){
EQ2Packet* app = new EQ2Packet(OP_LoginReplyMsg, 0, sizeof(LS_LoginResponse));
LS_LoginResponse* ls_response = (LS_LoginResponse*)app->pBuffer;
ls_response->reply_code = 6;
ls_response->unknown03 = 0xFFFFFFFF;
ls_response->unknown04 = 0xFFFFFFFF;
QueuePacket(app);
StartDisconnectTimer();
}
void Client::SendLoginDenied(){
EQ2Packet* app = new EQ2Packet(OP_LoginReplyMsg, 0, sizeof(LS_LoginResponse));
LS_LoginResponse* ls_response = (LS_LoginResponse*)app->pBuffer;
ls_response->reply_code = 1;
// reply_codes for AoM:
/* 1 = Login rejected: Invalid username or password. Please try again.
2 = Login rejected: Server thinks your account is currently playing; you may have to wait "
"a few minutes for it to clear, then try again
6 = Login rejected: The client's version does not match the server's. Please re-run the patcher.
7 = Login rejected: You have no scheduled playtimes.
8 = Your account does not have the features required to play on this server.
11 = The client's build does not match the server's. Please re-run the patcher.
12 = You must update your password in order to log in. Pressing OK will op"
"en your web browser to the SOE password management page
Other Value > 1 = Login rejected for an unknown reason.
*/
ls_response->unknown03 = 0xFFFFFFFF;
ls_response->unknown04 = 0xFFFFFFFF;
QueuePacket(app);
StartDisconnectTimer();
}
void Client::SendLoginAccepted(int32 account_id, int8 login_response) {
PacketStruct* packet = configReader.getStruct("LS_LoginReplyMsg", GetVersion());
int i = 0;
if (packet)
{
packet->setDataByName("account_id", account_id);
packet->setDataByName("login_response", login_response);
packet->setDataByName("do_not_force_soga", 1);
// sub_level 0xFFFFFFFF = blacks out all portraits for class alignments, considered non membership
// sub_level > 0 = class alignments still required, but portraits are viewable and race selectable
// sub_level = 2 membership, you can 'create characters on time locked servers' vs standard
// sub_level = 0 forces popup on close to web browser
packet->setDataByName("sub_level", net.GetDefaultSubscriptionLevel());
packet->setDataByName("race_flag", 0x1FFFFF);
packet->setDataByName("class_flag", 0x7FFFFFE);
packet->setMediumStringByName("username", GetAccountName());
packet->setMediumStringByName("password", GetAccountName());
// unknown5
// full support = 0x7CFF
// 1 << 12 (-4096) = missing echoes of faydwer, disables Fae and Arasai (black portraits) and kelethin as starting city
// 1 << 13 (-8192) = disables sarnak (black portraits) and gorowyn as starting city
packet->setDataByName("unknown5", net.GetExpansionFlag());
packet->setDataByName("unknown6", 0xFF);
packet->setDataByName("unknown6", 0xFF, 1);
packet->setDataByName("unknown6", 0xFF, 2);
// controls class access / playable characters
packet->setDataByName("unknown10", 0xFF);
// packet->setDataByName("unknown7a", 0x0101);
// packet->setDataByName("race_unknown", 0x01);
packet->setDataByName("unknown7", net.GetEnabledRaces()); // 0x01-0xFF disable extra races FAE(16) ARASAI (17) SARNAK (18) -- with 4096/8192 flags, no visibility of portraits
packet->setDataByName("unknown7a", 0xEE);
packet->setDataByName("unknown8", net.GetCitiesFlag(), 1); // dword_1ECBA18 operand for race flag packs (sublevel 0,1,2?) -- (sublevel -1) controls starting zones omission 0xEE vs 0xCF (CF misses halas)
/*
1 = city of qeynos
2 = city of freeport
4 = city of kelethin
8 = city of neriak
16 = gorowyn
32 = new halas
64 = queens colony
128 = outpost overlord
*/
EQ2Packet* outapp = packet->serialize();
QueuePacket(outapp);
safe_delete(packet);
}
}
void Client::SendWorldList(){
EQ2Packet* pack = world_list.MakeServerListPacket(lsadmin, version);
EQ2Packet* dupe = pack->Copy();
DumpPacket(dupe->pBuffer,dupe->size);
QueuePacket(dupe);
SendLoginAccepted(0, 10); // triggers a different code path in the client to set certain flags
return;
}
void Client::QueuePacket(EQ2Packet* app){
eqnc->EQ2QueuePacket(app);
}
void Client::WorldResponse(int32 worldid, int8 response, char* ip_address, int32 port, int32 access_key)
{
LWorld* world = world_list.FindByID(worldid);
if(world == 0) {
FatalError(0);
return;
}
if(response != 1){
if(response == PLAY_ERROR_CHAR_NOT_LOADED){
string pending_play_char_name = database.GetCharacterName(pending_play_char_id, worldid, GetAccountID());
if(database.VerifyDelete(GetAccountID(), pending_play_char_id, pending_play_char_name.c_str())){
GetLoginAccount()->removeCharacter((char*)pending_play_char_name.c_str(), GetVersion());
}
}
FatalError(response);
return;
}
PacketStruct* response_packet = configReader.getStruct("LS_PlayResponse", GetVersion());
if(response_packet){
safe_delete(playWaitTimer);
response_packet->setDataByName("response", 1);
response_packet->setSmallStringByName("server", ip_address);
response_packet->setDataByName("port", port);
response_packet->setDataByName("account_id", GetAccountID());
response_packet->setDataByName("access_code", access_key);
EQ2Packet* outapp = response_packet->serialize();
QueuePacket(outapp);
safe_delete(response_packet);
}
return;
}
void Client::FatalError(int8 response) {
safe_delete(playWaitTimer);
SendPlayFailed(response);
}
void Client::SendPlayFailed(int8 response){
PacketStruct* response_packet = configReader.getStruct("LS_PlayResponse", GetVersion());
if(response_packet){
response_packet->setDataByName("response", response);
response_packet->setSmallStringByName("server", "");
response_packet->setDataByName("port", 0);
response_packet->setDataByName("account_id", GetAccountID());
response_packet->setDataByName("access_code", 0);
EQ2Packet* outapp = response_packet->serialize();
QueuePacket(outapp);
safe_delete(response_packet);
}
}
void ClientList::Add(Client* client) {
MClientList.writelock();
client_list[client] = true;
MClientList.releasewritelock();
}
Client* ClientList::Get(int32 ip, int16 port) {
Client* ret = 0;
map<Client*, bool>::iterator itr;
MClientList.readlock();
for(itr = client_list.begin(); itr != client_list.end(); itr++){
if(itr->first->GetIP() == ip && itr->first->GetPort() == port){
ret = itr->first;
break;
}
}
MClientList.releasereadlock();
return ret;
}
void ClientList::FindByCreateRequest(){
Client* client = 0;
map<Client*, bool>::iterator itr;
MClientList.readlock();
for(itr = client_list.begin(); itr != client_list.end(); itr++){
if(itr->first->AwaitingCharCreationRequest()){
if(!client)
client = itr->first;
else{
client = 0;//more than 1 character waiting, dont want to send rejection to wrong one
break;
}
}
}
MClientList.releasereadlock();
if(client)
client->CharacterRejected(UNKNOWNERROR_REPLY);
}
Client* ClientList::FindByLSID(int32 lsaccountid) {
Client* client = 0;
map<Client*, bool>::iterator itr;
MClientList.readlock();
for(itr = client_list.begin(); itr != client_list.end(); itr++){
if(itr->first->GetAccountID() == lsaccountid){
client = itr->first;
break;
}
}
MClientList.releasereadlock();
return client;
}
void ClientList::SendPacketToAllClients(EQ2Packet* app){
Client* client = 0;
map<Client*, bool>::iterator itr;
MClientList.readlock();
if(client_list.size() > 0){
for(itr = client_list.begin(); itr != client_list.end(); itr++){
itr->first->QueuePacket(app->Copy());
}
}
safe_delete(app);
MClientList.releasereadlock();
}
void ClientList::Process() {
Client* client = 0;
vector<Client*> erase_list;
map<Client*, bool>::iterator itr;
MClientList.readlock();
for(itr = client_list.begin(); itr != client_list.end(); itr++){
client = itr->first;
if(!client->Process())
erase_list.push_back(client);
}
MClientList.releasereadlock();
if(erase_list.size() > 0){
vector<Client*>::iterator erase_itr;
MClientList.writelock();
for(erase_itr = erase_list.begin(); erase_itr != erase_list.end(); erase_itr++){
client = *erase_itr;
struct in_addr in;
in.s_addr = client->getConnection()->GetRemoteIP();
net.numclients--;
LogWrite(LOGIN__INFO, 0, "Login", "Removing client from ip: %s on port %i, Account Name: %s", inet_ntoa(in), ntohs(client->getConnection()->GetRemotePort()), client->GetAccountName());
client->getConnection()->Close();
net.UpdateWindowTitle();
client_list.erase(client);
}
MClientList.releasewritelock();
}
}
void Client::StartDisconnectTimer() {
if (!disconnectTimer)
{
disconnectTimer = new Timer(1000);
disconnectTimer->Start();
}
}

131
source/LoginServer/client.h Normal file
View File

@ -0,0 +1,131 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
*/
#ifndef CLIENT_H
#define CLIENT_H
#include "../common/linked_list.h"
#include "../common/timer.h"
#include "../common/TCPConnection.h"
#include "login_structs.h"
#include "LoginAccount.h"
#include "../common/PacketStruct.h"
#include <string>
#include <vector>
enum eLoginMode { None, Normal, Registration };
class DelayQue;
class Client
{
public:
Client(EQStream* ieqnc);
~Client();
void SendLoginDenied();
void SendLoginDeniedBadVersion();
void SendLoginAccepted(int32 account_id = 1, int8 login_response = 0);
void SendWorldList();
void SendCharList();
int16 AddWorldToList2(uchar* buffer, char* name, int32 id, int16* flags);
void GenerateChecksum(EQApplicationPacket* outapp);
int8 LoginKey[10];
int8 ClientSession[25];
bool Process();
void SaveErrorsToDB(EQApplicationPacket* app, char* type, int32 version);
void CharacterApproved(int32 server_id,int32 char_id);
void CharacterRejected(int8 reason_number);
EQStream* getConnection() { return eqnc; }
LoginAccount* GetLoginAccount() { return login_account; }
void SetLoginAccount(LoginAccount* in_account) {
login_account = in_account;
if(in_account)
account_id = in_account->getLoginAccountID();
}
int16 GetVersion(){ return version; }
char* GetKey() { return key; }
void SetKey(char* in_key) { strcpy(key,in_key); }
int32 GetIP() { return ip; }
int16 GetPort() { return port; }
int32 GetAccountID() { return account_id; }
const char* GetAccountName(){ return (char*)account_name.c_str(); }
void SetAccountName(const char* name){ account_name = string(name); }
void ProcessLogin(char* name, char* pass,int seq=0);
void QueuePacket(EQ2Packet* app);
void FatalError(int8 response);
void WorldResponse(int32 worldid, int8 response, char* ip_address, int32 port, int32 access_key);
bool AwaitingCharCreationRequest(){
if(createRequest)
return true;
else
return false;
}
Timer* updatetimer;
Timer* updatelisttimer;
Timer* disconnectTimer;
//Timer* keepalive;
//Timer* logintimer;
int16 packettotal;
int32 requested_server_id;
int32 request_num;
LinkedList<DelayQue*> delay_que;
void SendPlayFailed(int8 response);
void StartDisconnectTimer();
private:
string pending_play_char_name;
int32 pending_play_char_id;
int8 update_position;
int16 num_updates;
vector<PacketStruct*>* update_packets;
LoginAccount* login_account;
EQStream* eqnc;
int32 ip;
int16 port;
int32 account_id;
string account_name;
char key[10];
int8 lsadmin;
sint16 worldadmin;
int lsstatus;
bool kicked;
bool verified;
bool start;
bool needs_world_list;
int16 version;
char bannedreason[30];
bool sent_character_list;
eLoginMode LoginMode;
PacketStruct* createRequest;
Timer* playWaitTimer;
};
class ClientList
{
public:
ClientList() {}
~ClientList() {}
void Add(Client* client);
Client* Get(int32 ip, int16 port);
Client* FindByLSID(int32 lsaccountid);
void FindByCreateRequest();
void SendPacketToAllClients(EQ2Packet* app);
void Process();
private:
Mutex MClientList;
map<Client*, bool> client_list;
};
class DelayQue {
public:
DelayQue(Timer* in_timer, EQApplicationPacket* in_packet){
timer = in_timer;
packet = in_packet;
};
Timer* timer;
EQApplicationPacket* packet;
};
#endif

View File

@ -0,0 +1,52 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
*/
#ifndef LOGIN_OPCODES_H
#define LOGIN_OPCODES_H
#define OP_Login2 0x0200
#define OP_GetLoginInfo 0x0300
#define OP_SendServersFragment 0x0D00
#define OP_LoginInfo 0x0100
#define OP_SessionId 0x0900
#define OP_Disconnect 0x0500
//#define OP_Reg_SendPricing 0x0400
#define OP_AllFinish 0x0500
#define OP_Ack5 0x1500
#define OP_Chat_ChannelList 0x0600
#define OP_Chat_JoinChannel 0x0700
#define OP_Chat_PartChannel 0x0800
#define OP_Chat_ChannelMessage 0x0930
#define OP_Chat_Tell 0x0a00
#define OP_Chat_SysMsg 0x0b00
#define OP_Chat_CreateChannel 0x0c00
#define OP_Chat_ChangeChannel 0x0d00
#define OP_Chat_DeleteChannel 0x0e00
#define OP_Chat_UserList 0x1000
#define OP_Reg_GetPricing 0x1a00 // for new account signup
#define OP_Reg_SendPricing 0x1b00
#define OP_RegisterAccount 0x2300
#define OP_Chat_ChannelWelcome 0x2400
#define OP_Chat_PopupMakeWindow 0x3000
#define OP_BillingInfoAccepted 0x3300 // i THINK =p
#define OP_CheckGameCardValid 0x3400
#define OP_GameCardTimeLeft 0x3600
#define OP_AccountExpired 0x4200
#define OP_Reg_GetPricing2 0x4400 // for re-registering
#define OP_ChangePassword 0x4500
#define OP_ServerList 0x4600
#define OP_SessionKey 0x4700
#define OP_RequestServerStatus 0x4800
#define OP_SendServerStatus 0x4A00
#define OP_Reg_ChangeAcctLogin 0x5100
#define OP_LoginBanner 0x5200
#define OP_Chat_GuildsList 0x5500
#define OP_Chat_GuildEdit 0x5700
#define OP_Version 0x5900
#define OP_RenewAccountBillingInfo 0x7a00
#endif /* LOGIN_OPCODES_H */

View File

@ -0,0 +1,61 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
*/
#ifndef LOGIN_STRUCTS_H
#define LOGIN_STRUCTS_H
#include "../common/types.h"
#include "PacketHeaders.h"
#pragma pack(1)
struct LS_LoginRequest{
EQ2_16BitString AccessCode;
EQ2_16BitString unknown1;
EQ2_16BitString username;
EQ2_16BitString password;
EQ2_16BitString unknown2[4];
int16 unknown3;
int32 unknown4[2];
};
struct LS_WorldStatusChanged{
int32 server_id;
int8 up;
int8 locked;
int8 hidden;
};
struct LS_PlayCharacterRequest{
int32 character_id;
int32 server_id;
int16 unknown1;
};
struct LS_OLDPlayCharacterRequest{
int32 character_id;
EQ2_16BitString name;
};
struct LS_CharListAccountInfoEarlyClient {
int32 account_id;
int32 unknown1;
int16 unknown2;
int32 maxchars;
int8 unknown4; // 15 bytes total
// int8 unknown7; // adds 'free' option..
};
struct LS_CharListAccountInfo{
int32 account_id;
int32 unknown1;
int16 unknown2;
int32 maxchars;
// DoF does not have the following data
int8 unknown4;
int32 unknown5[4];
int8 vet_adv_bonus; // sets Veteran Bonus under 'Select Character' yellow (vs greyed out), adventure/tradeskill bonus 200%
int8 vet_trade_bonus; // when 1 (count?) provides free upgrade option for character to lvl 90 (heroic character) -- its a green 'Free' up arrow next to the character that is selected in char select
}; // 33 bytes
#pragma pack()
#endif

View File

@ -0,0 +1,32 @@
APP=login
SF= ../common/Log.o ../common/timer.o ../common/packet_dump.o ../common/unix.o \
../common/Mutex.o ../common/MiscFunctions.o LoginDatabase.o LoginAccount.o \
../common/TCPConnection.o ../common/emu_opcodes.o \
client.o net.o PacketHeaders.o LWorld.o ../common/md5.o ../common/dbcore.o \
Web/LoginWeb.o \
../common/EQEMuError.o ../common/misc.o ../common/Crypto.o ../common/RC4.o \
.obj/debug.o .obj/database.o .obj/EQStream.o ../common/xmlParser.o \
.obj/EQStreamFactory.o .obj/EQPacket.o ../common/CRC16.o ../common/packet_functions.o \
../common/Condition.o ../common/opcodemgr.o ../common/PacketStruct.o ../common/ConfigReader.o \
../common/DatabaseNew.o ../common/DatabaseResult.o ../common/Web/WebServer.o ../common/JsonParser.o
CC=g++
LINKER=gcc
DFLAGS=-DEQ2 -DLOGIN
WFLAGS=-Wall -Wuninitialized -Wwrite-strings -Wcast-qual -Wcomment -Wcast-align -Wno-deprecated
COPTS=$(WFLAGS) -ggdb -march=native -pthread -pipe -DFX -D_GNU_SOURCE -DINVERSEXY $(DFLAGS) -I/usr/include/mariadb -I/usr/local/include/boost -std=c++17
LINKOPTS=-rdynamic -L. -lstdc++ -lm -lz -L/usr/lib/x86_64-linux-gnu -lmariadb -lboost_system -lboost_thread -lboost_filesystem -lssl -lcrypto -lpthread -ldl
all: $(APP)
$(APP): $(SF)
$(LINKER) $(COPTS) $(OBJS) $^ $(LINKOPTS) -o $@
clean:
rm -f $(SF) $(APP)
%.o: %.cpp
$(CC) -c $(COPTS) $< -o $@
.obj/%.o: ../common/%.cpp ../common/%.h
mkdir -p .obj
$(CC) $(COPTS) -c $< -o $@

363
source/LoginServer/net.cpp Normal file
View File

@ -0,0 +1,363 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
*/
#include "../common/debug.h"
#include <iostream>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sstream>
#include <string>
#include <iostream>
#include "../common/queue.h"
#include "../common/timer.h"
#include "../common/seperator.h"
#include "net.h"
#include "client.h"
#include "LoginDatabase.h"
#include "LWorld.h"
#include "../common/packet_functions.h"
#include "../common/EQStreamFactory.h"
#include "../common/MiscFunctions.h"
#include "../common/version.h"
#include "../common/PacketStruct.h"
#include "../common/DataBuffer.h"
#include "../common/ConfigReader.h"
#include "../common/Log.h"
#include "../common/JsonParser.h"
#include "../common/Common_Defines.h"
#ifdef WIN32
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#include <conio.h>
#else
#include <stdlib.h>
#include "../common/unix.h"
#endif
EQStreamFactory eqsf(LoginStream);
map<int16,OpcodeManager*>EQOpcodeManager;
//TCPServer eqns(5999);
NetConnection net;
ClientList client_list;
LWorldList world_list;
LoginDatabase database;
ConfigReader configReader;
map<int16, int16> EQOpcodeVersions;
Timer statTimer(60000);
volatile bool RunLoops = true;
bool ReadLoginConfig();
#ifdef PUBLICLOGIN
char version[200], consoletitle[200];
#endif
#include "../common/timer.h"
#include "../common/CRC16.h"
#include <fstream>
int main(int argc, char** argv){
#ifdef _DEBUG
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
if (signal(SIGINT, CatchSignal) == SIG_ERR) {
cerr << "Could not set signal handler" << endl;
}
LogStart();
LogParseConfigs();
net.WelcomeHeader();
srand(time(NULL));
if(!net.ReadLoginConfig())
return 1;
net.InitWebServer(net.GetWebLoginAddress(), net.GetWebLoginPort(), net.GetWebCertFile(), net.GetWebKeyFile(), net.GetWebKeyPassword(), net.GetWebHardcodeUser(), net.GetWebHardcodePassword());
const char* structList[] = { "CommonStructs.xml", "LoginStructs.xml" };
for (int s = 0; s < sizeof(structList) / sizeof(const char*); s++)
{
LogWrite(INIT__INFO, 0, "Init", "Loading Structs File %s..", structList[s]);
if (configReader.processXML_Elements(structList[s]))
LogWrite(INIT__INFO, 0, "Init", "Loading Structs File %s completed..", structList[s]);
else
{
LogWrite(INIT__ERROR, 0, "Init", "Loading Structs File %s FAILED!", structList[s]);
return 1;
}
}
LogWrite(INIT__INFO, 0, "Init", "Initialize World List..");
world_list.Init();
if(eqsf.listen_ip_address)
LogWrite(INIT__INFO, 0, "Init", "Login server listening on %s port %i", eqsf.listen_ip_address, net.GetPort());
else
LogWrite(INIT__INFO, 0, "Init", "Login server listening on port %i", net.GetPort());
/*}
else {
cout << "EQNetworkServer.Open() error" << endl;
return 1;
}*/
if (!eqsf.Open(net.GetPort())) {
LogWrite(INIT__ERROR, 0, "Init", "Failed to open port %i.", net.GetPort());
return 1;
}
net.login_running = true;
net.login_uptime = getCurrentTimestamp();
net.UpdateWindowTitle();
EQStream* eqs;
Timer* TimeoutTimer = new Timer(5000);
TimeoutTimer->Start();
while(RunLoops) {
Timer::SetCurrentTime();
while ((eqs = eqsf.Pop())) {
struct in_addr in;
in.s_addr = eqs->GetRemoteIP();
LogWrite(LOGIN__INFO, 0, "Login", "New client from IP: %s on port %i", inet_ntoa(in), ntohs(eqs->GetRemotePort()));
Client* client = new Client(eqs);
eqs->SetClientVersion(0);
client_list.Add(client);
net.numclients++;
net.UpdateWindowTitle();
}
if(TimeoutTimer->Check()){
eqsf.CheckTimeout();
}
if(statTimer.Check()){
world_list.UpdateWorldStats();
database.RemoveOldWorldServerStats();
database.FixBugReport();
}
client_list.Process();
world_list.Process();
#ifdef WIN32
if(kbhit())
{
int hitkey = getch();
net.HitKey(hitkey);
}
#endif
Sleep(1);
}
//close
//eqns.Close();
eqsf.Close();
world_list.Shutdown();
return 0;
}
#ifdef WIN32
void NetConnection::HitKey(int keyhit)
{
switch(keyhit)
{
case 'l':
case 'L': {
world_list.ListWorldsToConsole();
break;
}
case 'v':
case 'V':
{
printf("========Version Info=========\n");
printf("%s %s\n", EQ2EMU_MODULE, CURRENT_VERSION);
printf("Last Compiled on %s %s\n", COMPILE_DATE, COMPILE_TIME);
printf("=============================\n\n");
break;
}
case 'H':
case 'h': {
printf("===========Help=============\n");
printf("Available Commands:\n");
printf("l = Listing of World Servers\n");
printf("v = Login Version\n");
// printf("0 = Kick all connected world servers\n");
printf("============================\n\n");
break;
}
default:
printf("Invalid Command.\n");
break;
}
}
#endif
void CatchSignal(int sig_num) {
cout << "Got signal " << sig_num << endl;
RunLoops = false;
}
bool NetConnection::ReadLoginConfig() {
JsonParser parser(MAIN_CONFIG_FILE);
if(!parser.IsLoaded()) {
LogWrite(INIT__ERROR, 0, "Init", "Failed to find %s in server directory..", MAIN_CONFIG_FILE);
return false;
}
std::string serverport = parser.getValue("loginconfig.serverport");
std::string serverip = parser.getValue("loginconfig.serverip");
if (!parser.convertStringToUnsignedShort(serverport, port)) {
LogWrite(INIT__ERROR, 0, "Init", "Failed to translate loginconfig.serverport..");
return false;
}
if(serverip.size() > 0) {
eqsf.listen_ip_address = new char[serverip.size() + 1];
strcpy(eqsf.listen_ip_address, serverip.c_str());
}
else {
safe_delete(eqsf.listen_ip_address);
eqsf.listen_ip_address = nullptr;
}
std::string acctcreate_str = parser.getValue("loginconfig.accountcreation");
int16 allow_acct = 0;
parser.convertStringToUnsignedShort(acctcreate_str, allow_acct);
allowAccountCreation = allow_acct > 0 ? true : false;
std::string expflag_str = parser.getValue("loginconfig.expansionflag");
parser.convertStringToUnsignedInt(expflag_str, expansionFlag);
std::string citiesflag_str = parser.getValue("loginconfig.citiesflag");
parser.convertStringToUnsignedChar(citiesflag_str, citiesFlag);
std::string defaultsublevel_str = parser.getValue("loginconfig.defaultsubscriptionlevel");
parser.convertStringToUnsignedInt(defaultsublevel_str, defaultSubscriptionLevel);
std::string enableraces_str = parser.getValue("loginconfig.enabledraces");
parser.convertStringToUnsignedInt(enableraces_str, enabledRaces);
web_loginaddress = parser.getValue("loginconfig.webloginaddress");
web_certfile = parser.getValue("loginconfig.webcertfile");
web_keyfile = parser.getValue("loginconfig.webkeyfile");
web_keypassword = parser.getValue("loginconfig.webkeypassword");
web_hardcodeuser = parser.getValue("loginconfig.webhardcodeuser");
web_hardcodepassword = parser.getValue("loginconfig.webhardcodepassword");
std::string webloginport_str = parser.getValue("loginconfig.webloginport");
parser.convertStringToUnsignedShort(webloginport_str, web_loginport);
LogWrite(INIT__INFO, 0, "Init", "%s loaded..", MAIN_CONFIG_FILE);
LogWrite(INIT__INFO, 0, "Init", "Database init begin..");
//remove this when all database calls are using the new database class
if (!database.Init()) {
LogWrite(INIT__ERROR, 0, "Init", "Database init FAILED!");
LogStop();
return false;
}
LogWrite(INIT__INFO, 0, "Init", "Loading opcodes 2.0..");
EQOpcodeVersions = database.GetVersions();
map<int16,int16>::iterator version_itr2;
int16 version1 = 0;
for (version_itr2 = EQOpcodeVersions.begin(); version_itr2 != EQOpcodeVersions.end(); version_itr2++) {
version1 = version_itr2->first;
EQOpcodeManager[version1] = new RegularOpcodeManager();
map<string, uint16> eq = database.GetOpcodes(version1);
if(!EQOpcodeManager[version1]->LoadOpcodes(&eq)) {
LogWrite(INIT__ERROR, 0, "Init", "Loading opcodes failed. Make sure you have sourced the opcodes.sql file!");
return false;
}
}
return true;
}
void NetConnection::UpdateWindowTitle(char* iNewTitle) {
#ifdef WIN32
char tmp[500];
if (iNewTitle) {
snprintf(tmp, sizeof(tmp), "Login: %s", iNewTitle);
}
else {
snprintf(tmp, sizeof(tmp), "%s, Version: %s: %i Server(s), %i Client(s) Connected", EQ2EMU_MODULE, CURRENT_VERSION, net.numservers, net.numclients);
}
SetConsoleTitle(tmp);
#endif
}
void NetConnection::WelcomeHeader()
{
#ifdef _WIN32
HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(console, FOREGROUND_WHITE_BOLD);
#endif
printf("Module: %s, Version: %s", EQ2EMU_MODULE, CURRENT_VERSION);
#ifdef _WIN32
SetConsoleTextAttribute(console, FOREGROUND_YELLOW_BOLD);
#endif
printf("\n\nCopyright (C) 2007-2021 EQ2Emulator. https://www.eq2emu.com \n\n");
printf("EQ2Emulator is free software: you can redistribute it and/or modify\n");
printf("it under the terms of the GNU General Public License as published by\n");
printf("the Free Software Foundation, either version 3 of the License, or\n");
printf("(at your option) any later version.\n\n");
printf("EQ2Emulator is distributed in the hope that it will be useful,\n");
printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
printf("GNU General Public License for more details.\n\n");
#ifdef _WIN32
SetConsoleTextAttribute(console, FOREGROUND_GREEN_BOLD);
#endif
printf(" /$$$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$$$ \n");
printf("| $$_____/ /$$__ $$ /$$__ $$| $$_____/ \n");
printf("| $$ | $$ \\ $$|__/ \\ $$| $$ /$$$$$$/$$$$ /$$ /$$\n");
printf("| $$$$$ | $$ | $$ /$$$$$$/| $$$$$ | $$_ $$_ $$| $$ | $$\n");
printf("| $$__/ | $$ | $$ /$$____/ | $$__/ | $$ \\ $$ \\ $$| $$ | $$\n");
printf("| $$ | $$/$$ $$| $$ | $$ | $$ | $$ | $$| $$ | $$\n");
printf("| $$$$$$$$| $$$$$$/| $$$$$$$$| $$$$$$$$| $$ | $$ | $$| $$$$$$/\n");
printf("|________/ \\____ $$$|________/|________/|__/ |__/ |__/ \\______/ \n");
printf(" \\__/ \n\n");
#ifdef _WIN32
SetConsoleTextAttribute(console, FOREGROUND_MAGENTA_BOLD);
#endif
printf(" Website : https://eq2emu.com \n");
printf(" Wiki : https://wiki.eq2emu.com \n");
printf(" Git : https://git.eq2emu.com \n");
printf(" Discord : https://discord.gg/5Cavm9NYQf \n\n");
#ifdef _WIN32
SetConsoleTextAttribute(console, FOREGROUND_WHITE_BOLD);
#endif
printf("For more detailed logging, modify 'Level' param the log_config.xml file.\n\n");
#ifdef _WIN32
SetConsoleTextAttribute(console, FOREGROUND_WHITE);
#endif
fflush(stdout);
}
void NetConnection::InitWebServer(std::string web_ipaddr, int16 web_port, std::string cert_file, std::string key_file, std::string key_password, std::string hardcode_user, std::string hardcode_password) {
if(web_ipaddr.size() > 0 && web_port > 0) {
try {
login_webserver = new WebServer(web_ipaddr, web_port, cert_file, key_file, key_password, hardcode_user, hardcode_password);
login_webserver->register_route("/status", NetConnection::Web_loginhandle_status);
login_webserver->register_route("/worlds", NetConnection::Web_loginhandle_worlds);
login_webserver->run();
LogWrite(INIT__INFO, 0, "Init", "Login Web Server is listening on %s:%u..", web_ipaddr.c_str(), web_port);
}
catch (const std::exception& e) {
LogWrite(INIT__ERROR, 0, "Init", "Login Web Server failed to listen on %s:%u due to reason %s", web_ipaddr.c_str(), web_port, e.what());
}
}
}

147
source/LoginServer/net.h Normal file
View File

@ -0,0 +1,147 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
*/
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#endif
//#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <atomic>
#include "../common/types.h"
#include "../common/Web/WebServer.h"
#include "../common/MiscFunctions.h"
void CatchSignal(int sig_num);
enum eServerMode { Standalone, Master, Slave, Mesh };
class NetConnection
{
public:
NetConnection() {
port = 5999;
listening_socket = 0;
memset(masteraddress, 0, sizeof(masteraddress));
uplinkport = 0;
memset(uplinkaccount, 0, sizeof(uplinkaccount));
memset(uplinkpassword, 0, sizeof(uplinkpassword));
LoginMode = Standalone;
Uplink_WrongVersion = false;
numclients = 0;
numservers = 0;
allowAccountCreation = true;
// full support = 0x7CFF
// 1 << 12 (-4096) = missing echoes of faydwer, disables Fae and Arasai (black portraits) and kelethin as starting city
// 1 << 13 (-8192) = disables sarnak (black portraits) and gorowyn as starting city
expansionFlag = 0x7CFF; // 0x4CF5
/* dword_1ECBA18 operand for race flag packs (sublevel 0,1,2?) -- (sublevel -1) controls starting zones omission 0xEE vs 0xCF (CF misses halas)
1 = city of qeynos
2 = city of freeport
4 = city of kelethin
8 = city of neriak
16 = gorowyn
32 = new halas
64 = queens colony
128 = outpost overlord
*/
citiesFlag = 0xFF;
// sub_level 0xFFFFFFFF = blacks out all portraits for class alignments, considered non membership
// sub_level > 0 = class alignments still required, but portraits are viewable and race selectable
// sub_level = 2 membership, you can 'create characters on time locked servers' vs standard
// sub_level = 0 forces popup on close to web browser
defaultSubscriptionLevel = 0xFFFFFFFF;
// disable extra races FAE(16) ARASAI (17) SARNAK (18) -- with 4096/8192 flags, no visibility of portraits
enabledRaces = 0xFFFF; // 0xCFFF
web_loginport = 0;
login_webserver = nullptr;
login_running = false;
login_uptime = getCurrentTimestamp();
}
~NetConnection() {
safe_delete(login_webserver);
}
void UpdateWindowTitle(char* iNewTitle = 0);
bool Init();
void ListenNewClients();
void HitKey(int keyhit);
char address[1024];
int32 numclients;
int32 numservers;
int16 GetPort() { return port; }
void SetPort(int16 in_port) { port = in_port; }
eServerMode GetLoginMode() { return LoginMode; }
bool ReadLoginConfig();
char* GetMasterAddress() { return masteraddress; }
int16 GetUplinkPort() { if (uplinkport != 0) return uplinkport; else return port; }
char* GetUplinkAccount() { return uplinkaccount; }
char* GetUplinkPassword() { return uplinkpassword; }
bool IsAllowingAccountCreation() { return allowAccountCreation; }
int32 GetExpansionFlag() { return expansionFlag; }
int8 GetCitiesFlag() { return citiesFlag; }
int32 GetDefaultSubscriptionLevel() { return defaultSubscriptionLevel; }
int32 GetEnabledRaces() { return enabledRaces; }
std::string GetWebLoginAddress() { return web_loginaddress; }
inline int16 GetWebLoginPort() { return web_loginport; }
std::string GetWebCertFile() { return web_certfile; }
std::string GetWebKeyFile() { return web_keyfile; }
std::string GetWebKeyPassword() { return web_keypassword; }
std::string GetWebHardcodeUser() { return web_hardcodeuser; }
std::string GetWebHardcodePassword() { return web_hardcodepassword; }
void WelcomeHeader();
void InitWebServer(std::string web_ipaddr, int16 web_port, std::string cert_file, std::string key_file, std::string key_password, std::string hardcode_user, std::string hardcode_password);
static void Web_loginhandle_status(const http::request<http::string_body>& req, http::response<http::string_body>& res);
static void Web_loginhandle_worlds(const http::request<http::string_body>& req, http::response<http::string_body>& res);
bool login_running;
std::atomic<int64> login_uptime;
protected:
friend class LWorld;
bool Uplink_WrongVersion;
private:
int16 port;
int listening_socket;
char masteraddress[300];
int16 uplinkport;
char uplinkaccount[300];
char uplinkpassword[300];
eServerMode LoginMode;
bool allowAccountCreation;
int32 expansionFlag;
int8 citiesFlag;
int32 defaultSubscriptionLevel;
int32 enabledRaces;
std::string web_loginaddress;
std::string web_certfile;
std::string web_keyfile;
std::string web_keypassword;
std::string web_hardcodeuser;
std::string web_hardcodepassword;
int16 web_loginport;
WebServer* login_webserver;
};

View File

@ -0,0 +1,332 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Achievements.h"
#include "../../common/Log.h"
#include "../../common/ConfigReader.h"
#include <assert.h>
extern ConfigReader configReader;
extern MasterAchievementList master_achievement_list;
Achievement::Achievement() {
id = 0;
memset(title, 0, sizeof(title));
memset(uncompleted_text, 0, sizeof(uncompleted_text));
memset(completed_text, 0, sizeof(completed_text));
memset(category, 0, sizeof(category));
memset(expansion, 0, sizeof(expansion));
icon = 0;
point_value = 0;
qty_req = 0;
hide = false;
unknown3a = 0;
unknown3b = 0;
}
Achievement::Achievement(Achievement *in) {
vector<struct AchievementRequirements *> *requirements_in;
vector<struct AchievementRewards *> *rewards_in;
vector<struct AchievementRequirements *>::iterator itr;
vector<struct AchievementRewards *>::iterator itr2;
struct AchievementRequirements *achievement_requirement;
struct AchievementRewards *achievement_reward;
assert(in);
id = in->GetID();
strncpy(title, in->GetTitle(), sizeof(title));
strncpy(uncompleted_text, in->GetUncompletedText(), sizeof(uncompleted_text));
strncpy(completed_text, in->GetCompletedText(), sizeof(completed_text));
strncpy(category, in->GetCategory(), sizeof(category));
strncpy(expansion, in->GetExpansion(), sizeof(expansion));
icon = in->GetIcon();
point_value = in->GetPointValue();
qty_req = in->GetQtyReq();
hide = in->GetHide();
unknown3a = in->GetUnknown3a();
unknown3b = in->GetUnknown3b();
requirements_in = in->GetRequirements();
for (itr = requirements_in->begin(); itr != requirements_in->end(); itr++) {
achievement_requirement = new struct AchievementRequirements;
achievement_requirement->achievement_id = (*itr)->achievement_id;
achievement_requirement->name = (*itr)->name;
achievement_requirement->qty_req = (*itr)->qty_req;
requirements.push_back(achievement_requirement);
}
rewards_in = in->GetRewards();
for (itr2 = rewards_in->begin(); itr2 != rewards_in->end(); itr2++) {
achievement_reward = new struct AchievementRewards;
achievement_reward->achievement_id = (*itr2)->achievement_id;
achievement_reward->reward = (*itr2)->reward;
rewards.push_back(achievement_reward);
}
}
Achievement::~Achievement() {
vector<struct AchievementRequirements *>::iterator itr;
vector<struct AchievementRewards *>::iterator itr2;
for (itr = requirements.begin(); itr != requirements.end(); itr++)
safe_delete(*itr);
for (itr2 = rewards.begin(); itr2 != rewards.end(); itr2++)
safe_delete(*itr2);
}
void Achievement::AddAchievementRequirement(struct AchievementRequirements *requirement) {
assert(requirement);
requirements.push_back(requirement);
}
void Achievement::AddAchievementReward(struct AchievementRewards *reward) {
assert(reward);
rewards.push_back(reward);
}
void AchievementUpdate::AddAchievementUpdateItems(struct AchievementUpdateItems *update_item) {
assert(update_item);
update_items.push_back(update_item);
}
MasterAchievementList::MasterAchievementList() {
m_packetsCreated = false;
masterPacket = 0;
mutex_achievements.SetName("MasterAchievementList::achievements");
}
MasterAchievementList::~MasterAchievementList() {
ClearAchievements();
}
bool MasterAchievementList::AddAchievement(Achievement *achievement) {
bool ret = false;
assert(achievement);
mutex_achievements.writelock(__FUNCTION__, __LINE__);
if (achievements.count(achievement->GetID()) == 0) {
achievements[achievement->GetID()] = achievement;
ret = true;
}
mutex_achievements.releasewritelock(__FUNCTION__, __LINE__);
return ret;
}
Achievement * MasterAchievementList::GetAchievement(int32 achievement_id) {
Achievement *achievement = 0;
mutex_achievements.readlock(__FUNCTION__, __LINE__);
if (achievements.count(achievement_id) > 0)
achievement = achievements[achievement_id];
mutex_achievements.releasereadlock(__FUNCTION__, __LINE__);
return achievement;
}
void MasterAchievementList::ClearAchievements() {
map<int32, Achievement *>::iterator itr;
mutex_achievements.writelock(__FUNCTION__, __LINE__);
for (itr = achievements.begin(); itr != achievements.end(); itr++)
safe_delete(itr->second);
achievements.clear();
mutex_achievements.releasewritelock(__FUNCTION__, __LINE__);
}
int32 MasterAchievementList::Size() {
int32 size;
mutex_achievements.readlock(__FUNCTION__, __LINE__);
size = achievements.size();
mutex_achievements.releasereadlock(__FUNCTION__, __LINE__);
return size;
}
PlayerAchievementList::PlayerAchievementList() {
}
PlayerAchievementList::~PlayerAchievementList() {
ClearAchievements();
}
bool PlayerAchievementList::AddAchievement(Achievement *achievement) {
assert(achievement);
if (achievements.count(achievement->GetID()) == 0) {
achievements[achievement->GetID()] = achievement;
return true;
}
return false;
}
Achievement * PlayerAchievementList::GetAchievement(int32 achievement_id) {
if (achievements.count(achievement_id) > 0)
return achievements[achievement_id];
return 0;
}
void PlayerAchievementList::ClearAchievements() {
map<int32, Achievement *>::iterator itr;
for (itr = achievements.begin(); itr != achievements.end(); itr++)
safe_delete(itr->second);
achievements.clear();
}
int32 PlayerAchievementList::Size() {
return achievements.size();
}
AchievementUpdate::AchievementUpdate() {
id = 0;
completed_date = 0;
}
AchievementUpdate::AchievementUpdate(AchievementUpdate *in) {
vector<struct AchievementUpdateItems *> *items_in;
vector<struct AchievementUpdateItems *>::iterator itr;
struct AchievementUpdateItems *items;
assert(in);
id = in->GetID();
completed_date = in->GetCompletedDate();
items_in = in->GetUpdateItems();
for (itr = items_in->begin(); itr != items_in->end(); itr++) {
items = new struct AchievementUpdateItems;
items->achievement_id = (*itr)->achievement_id;
items->item_update = (*itr)->item_update;
update_items.push_back(items);
}
}
AchievementUpdate::~AchievementUpdate() {
vector<struct AchievementUpdateItems *>::iterator itr;
for (itr = update_items.begin(); itr != update_items.end(); itr++)
safe_delete(*itr);
}
PlayerAchievementUpdateList::PlayerAchievementUpdateList() {
}
PlayerAchievementUpdateList::~PlayerAchievementUpdateList() {
ClearAchievementUpdates();
}
bool PlayerAchievementUpdateList::AddAchievementUpdate(AchievementUpdate *update) {
assert(update);
if (achievement_updates.count(update->GetID()) == 0) {
achievement_updates[update->GetID()] = update;
return true;
}
return false;
}
void PlayerAchievementUpdateList::ClearAchievementUpdates() {
map<int32, AchievementUpdate *>::iterator itr;
for (itr = achievement_updates.begin(); itr != achievement_updates.end(); itr++)
safe_delete(itr->second);
achievement_updates.clear();
}
int32 PlayerAchievementUpdateList::Size() {
return achievement_updates.size();
}
void MasterAchievementList::CreateMasterAchievementListPacket() {
map<int32, Achievement *>::iterator itr;
Achievement *achievement;
vector<AchievementRequirements *> *requirements = 0;
vector<AchievementRequirements *>::iterator itr2;
AchievementRequirements *requirement;
vector<AchievementRewards *> *rewards = 0;
vector<AchievementRewards *>::iterator itr3;
AchievementRewards *reward;
PacketStruct *packet;
int16 i = 0;
int16 j = 0;
int16 k = 0;
int16 version = 1096;
if (!(packet = configReader.getStruct("WS_CharacterAchievements", version))) {
return;
}
packet->setArrayLengthByName("num_achievements" , achievements.size());
for (itr = achievements.begin(); itr != achievements.end(); itr++) {
achievement = itr->second;
packet->setArrayDataByName("achievement_id", achievement->GetID(), i);
packet->setArrayDataByName("title", achievement->GetTitle(), i);
packet->setArrayDataByName("uncompleted_text", achievement->GetUncompletedText(), i);
packet->setArrayDataByName("completed_text", achievement->GetCompletedText(), i);
packet->setArrayDataByName("category", achievement->GetCategory(), i);
packet->setArrayDataByName("expansion", achievement->GetExpansion(), i);
packet->setArrayDataByName("icon", achievement->GetIcon(), i);
packet->setArrayDataByName("point_value", achievement->GetPointValue(), i);
packet->setArrayDataByName("qty_req", achievement->GetQtyReq(), i);
packet->setArrayDataByName("hide_achievement", achievement->GetHide(), i);
packet->setArrayDataByName("unknown3", achievement->GetUnknown3a(), i);
packet->setArrayDataByName("unknown3", achievement->GetUnknown3b(), i);
requirements = achievement->GetRequirements();
rewards = achievement->GetRewards();
j = 0;
k = 0;
packet->setSubArrayLengthByName("num_items", requirements->size(), i, j);
for (itr2 = requirements->begin(); itr2 != requirements->end(); itr2++) {
requirement = *itr2;
packet->setSubArrayDataByName("item_name", requirement->name.c_str(), i, j);
packet->setSubArrayDataByName("item_qty_req", requirement->qty_req, i, j);
j++;
}
packet->setSubArrayLengthByName("num_rewards", achievement->GetRewards()->size(), i, k);
for (itr3 = rewards->begin(); itr3 != rewards->end(); itr3++) {
reward = *itr3;
packet->setSubArrayDataByName("reward_item", reward->reward.c_str(), i, k);
k++;
}
i++;
}
//packet->PrintPacket();
EQ2Packet* data = packet->serialize();
masterPacket = new EQ2Packet(OP_ClientCmdMsg, data->pBuffer, data->size);
safe_delete(packet);
safe_delete(data);
//DumpPacket(app);
m_packetsCreated = true;
}

View File

@ -0,0 +1,176 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ACHIEVEMENTS_H_
#define ACHIEVEMENTS_H_
#include "../../common/types.h"
#include "../../common/Mutex.h"
#include "../Items/Items.h"
#include <map>
#include <vector>
using namespace std;
struct AchievementRewards
{
int32 achievement_id;
string reward;
};
struct AchievementRequirements
{
int32 achievement_id;
string name;
int32 qty_req;
};
struct AchievementUpdateItems
{
int32 achievement_id;
int32 item_update;
};
class Achievement {
public:
Achievement();
Achievement(Achievement *in);
virtual ~Achievement();
void SetID(int32 id) {this->id = id;}
void SetTitle(const char *title) {strncpy(this->title, title, sizeof(this->title));}
void SetUncompletedText(const char *uncompleted_text) {strncpy(this->uncompleted_text, uncompleted_text, sizeof(this->uncompleted_text));}
void SetCompletedText(const char *completed_text) {strncpy(this->completed_text, completed_text, sizeof(this->completed_text));}
void SetCategory(const char *category) {strncpy(this->category, category, sizeof(this->category));}
void SetExpansion(const char *expansion) {strncpy(this->expansion, expansion, sizeof(this->expansion));}
void SetIcon(int16 icon) {this->icon = icon;}
void SetPointValue(int32 point_value) {this->point_value = point_value;}
void SetQtyReq(int32 qty_req) {this->qty_req = qty_req;}
void SetHide(bool hide) {this->hide = hide;}
void SetUnknown3a(int32 unknown3a) {this->unknown3a = unknown3a;}
void SetUnknown3b(int32 unknown3b) {this->unknown3b = unknown3b;}
void AddAchievementRequirement(struct AchievementRequirements *requirements);
void AddAchievementReward(struct AchievementRewards *reward);
int32 GetID() {return id;}
const char * GetTitle() {return title;}
const char * GetUncompletedText() {return uncompleted_text;}
const char * GetCompletedText() {return completed_text;}
const char * GetCategory() {return category;}
const char * GetExpansion() {return expansion;}
int16 GetIcon() {return icon;}
int32 GetPointValue() {return point_value;}
int32 GetQtyReq() {return qty_req;}
bool GetHide() {return hide;}
int32 GetUnknown3a() {return unknown3a;}
int32 GetUnknown3b() {return unknown3b;}
vector<struct AchievementRequirements *> * GetRequirements() {return &requirements;}
vector<struct AchievementRewards *> * GetRewards() {return &rewards;}
private:
int32 id;
char title[512];
char uncompleted_text[512];
char completed_text[512];
char category[32];
char expansion[32];
int16 icon;
int32 point_value;
int32 qty_req;
bool hide;
int32 unknown3a;
int32 unknown3b;
vector<struct AchievementRequirements *> requirements;
vector<struct AchievementRewards *> rewards;
};
class AchievementUpdate {
public:
AchievementUpdate();
AchievementUpdate(AchievementUpdate *in);
virtual ~AchievementUpdate();
void SetID(int32 id) {this->id = id;}
void SetCompletedDate(int32 completed_date) {this->completed_date = completed_date;}
void AddAchievementUpdateItems(struct AchievementUpdateItems *update_items);
int32 GetID() {return id;}
int32 GetCompletedDate() {return completed_date;}
vector<struct AchievementUpdateItems *> * GetUpdateItems() {return &update_items;}
private:
int32 id;
int32 completed_date;
vector<struct AchievementUpdateItems *> update_items;
};
class MasterAchievementList {
public:
MasterAchievementList();
virtual ~MasterAchievementList();
bool AddAchievement(Achievement *achievement);
Achievement * GetAchievement(int32 achievement_id);
void ClearAchievements();
int32 Size();
void CreateMasterAchievementListPacket();
EQ2Packet * GetAchievementPacket() { return m_packetsCreated ? masterPacket : 0;}
EQ2Packet *masterPacket;
private:
Mutex mutex_achievements;
map<int32, Achievement *> achievements;
bool m_packetsCreated;
};
class PlayerAchievementList {
public:
PlayerAchievementList();
virtual ~PlayerAchievementList();
bool AddAchievement(Achievement *achievement);
Achievement * GetAchievement(int32 achievement_id);
void ClearAchievements();
int32 Size();
map<int32, Achievement *> * GetAchievements() {return &achievements;}
private:
map<int32, Achievement *> achievements;
};
class PlayerAchievementUpdateList {
public:
PlayerAchievementUpdateList();
virtual ~PlayerAchievementUpdateList();
bool AddAchievementUpdate(AchievementUpdate *achievement_update);
void ClearAchievementUpdates();
int32 Size();
map<int32, AchievementUpdate *> * GetAchievementUpdates() {return &achievement_updates;}
private:
map<int32, AchievementUpdate *> achievement_updates;
};
#endif

View File

@ -0,0 +1,241 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef WIN32
#include <WinSock2.h>
#include <windows.h>
#endif
#include <mysql.h>
#include <assert.h>
#include "../../common/Log.h"
#include "../WorldDatabase.h"
#include "Achievements.h"
extern MasterAchievementList master_achievement_list;
void WorldDatabase::LoadAchievements()
{
Achievement *achievement;
Query query;
MYSQL_ROW row;
MYSQL_RES *res;
int32 aReqs_total = 0;
int32 aRewards_total = 0;
res = query.RunQuery2(Q_SELECT, "SELECT `achievement_id`,`title`,`uncompleted_text`,`completed_text`,`category`,`expansion`,`icon`,`point_value`,`qty_req`,`hide_achievement`,`unknown3a`,`unknown3b`\n"
"FROM `achievements`");
if (res)
{
while ((row = mysql_fetch_row(res)))
{
achievement = new Achievement();
achievement->SetID(atoul(row[0]));
achievement->SetTitle(row[1]);
achievement->SetUncompletedText(row[2]);
achievement->SetCompletedText(row[3]);
achievement->SetCategory(row[4]);
achievement->SetExpansion(row[5]);
achievement->SetIcon(atoi(row[6]));
achievement->SetPointValue(atoul(row[7]));
achievement->SetQtyReq(atoul(row[8]));
achievement->SetHide( atoi(row[9]) == 0 ? false : true );
achievement->SetUnknown3a(atoul(row[10]));
achievement->SetUnknown3b(atoul(row[11]));
LogWrite(ACHIEVEMENT__DEBUG, 5, "Achievements", "\tLoading Achievement: '%s' (%u)", achievement->GetTitle(), achievement->GetID());
if (!master_achievement_list.AddAchievement(achievement))
{
LogWrite(ACHIEVEMENT__ERROR, 0, "Achievements", "Error adding achievement '%s' - duplicate ID: %u", achievement->GetTitle(), achievement->GetID());
safe_delete(achievement);
continue;
}
aReqs_total += LoadAchievementRequirements(achievement);
aRewards_total += LoadAchievementRewards(achievement);
}
}
LogWrite(ACHIEVEMENT__DEBUG, 0, "Achievements", "\tLoaded %u achievements", master_achievement_list.Size());
LogWrite(ACHIEVEMENT__DEBUG, 0, "Achievements", "\tLoaded %u achievement requirements", aReqs_total);
LogWrite(ACHIEVEMENT__DEBUG, 0, "Achievements", "\tLoaded %u achievement rewards", aRewards_total);
}
int32 WorldDatabase::LoadAchievementRequirements(Achievement *achievement)
{
AchievementRequirements *requirements;
Query query;
MYSQL_ROW row;
MYSQL_RES *res;
int16 total = 0;
assert(achievement);
res = query.RunQuery2(Q_SELECT, "SELECT `achievement_id`, `name`, `qty_req` FROM `achievements_requirements` WHERE `achievement_id` = %u", achievement->GetID());
if (res) {
while ((row = mysql_fetch_row(res))) {
requirements = new AchievementRequirements();
requirements->achievement_id = atoul(row[0]);
requirements->name = row[1];
requirements->qty_req = atoul(row[2]);
achievement->AddAchievementRequirement(requirements);
LogWrite(ACHIEVEMENT__DEBUG, 5, "Achievements", "Loading Achievements Requirement '%s'", requirements->name.c_str());
total++;
}
}
LogWrite(ACHIEVEMENT__DEBUG, 5, "Achievements", "Loaded %u requirements for achievement '%s' ID: %u", total, achievement->GetTitle(), achievement->GetID());
return total;
}
int32 WorldDatabase::LoadAchievementRewards(Achievement *achievement)
{
AchievementRewards *rewards;
Query query;
MYSQL_ROW row;
MYSQL_RES *res;
int16 total = 0;
assert(achievement);
res = query.RunQuery2(Q_SELECT, "SELECT `achievement_id`, `reward` FROM `achievements_rewards` WHERE `achievement_id` = %u", achievement->GetID());
if (res) {
while ((row = mysql_fetch_row(res))) {
rewards = new AchievementRewards();
rewards->achievement_id = atoul(row[0]);
rewards->reward = row[1];
achievement->AddAchievementReward(rewards);
LogWrite(ACHIEVEMENT__DEBUG, 5, "Achievements", "Loading Achievements Reward '%s'", rewards->reward.c_str());
total++;
}
}
LogWrite(ACHIEVEMENT__DEBUG, 5, "Achievements", "Loaded %u rewards for achievement '%s' ID: %u", total, achievement->GetTitle(), achievement->GetID());
return total;
}
void WorldDatabase::LoadPlayerAchievements(Player *player) {
Achievement *achievement;
Query query;
MYSQL_ROW row;
MYSQL_RES *res;
int32 aReqs_total = 0;
int32 aRewards_total = 0;
int32 total = 0;
assert(player);
res = query.RunQuery2(Q_SELECT, "SELECT `achievement_id`,`title`,`uncompleted_text`,`completed_text`,`category`,`expansion`,`icon`,`point_value`,`qty_req`,`hide_achievement`,`unknown3a`,`unknown3b`\n"
"FROM `achievements`");
if (res)
{
while ((row = mysql_fetch_row(res)))
{
achievement = new Achievement();
achievement->SetID(atoul(row[0]));
achievement->SetTitle(row[1]);
achievement->SetUncompletedText(row[2]);
achievement->SetCompletedText(row[3]);
achievement->SetCategory(row[4]);
achievement->SetExpansion(row[5]);
achievement->SetIcon(atoi(row[6]));
achievement->SetPointValue(atoul(row[7]));
achievement->SetQtyReq(atoul(row[8]));
achievement->SetHide( atoi(row[9]) == 0 ? false : true );
achievement->SetUnknown3a(atoul(row[10]));
achievement->SetUnknown3b(atoul(row[11]));
LogWrite(ACHIEVEMENT__DEBUG, 5, "Achievements", "\tLoading Achievement: '%s' (%u)", achievement->GetTitle(), achievement->GetID());
if (!player->GetAchievementList()->AddAchievement(achievement))
{
LogWrite(ACHIEVEMENT__ERROR, 0, "Achievements", "Error adding achievement '%s' - duplicate ID: %u", achievement->GetTitle(), achievement->GetID());
safe_delete(achievement);
continue;
}
total++;
aReqs_total += LoadAchievementRequirements(achievement);
aRewards_total += LoadAchievementRewards(achievement);
}
}
LogWrite(ACHIEVEMENT__DEBUG, 0, "Achievements", "\tLoaded %u achievements for '%s'", total, player->GetName());
LogWrite(ACHIEVEMENT__DEBUG, 0, "Achievements", "\tLoaded %u achievement requirements for '%s'", aReqs_total, player->GetName());
LogWrite(ACHIEVEMENT__DEBUG, 0, "Achievements", "\tLoaded %u achievement rewards for '%s'", aRewards_total, player->GetName());
}
int32 WorldDatabase::LoadPlayerAchievementsUpdates(Player *player) {
AchievementUpdate *update;
Query query;
MYSQL_ROW row;
MYSQL_RES *res;
int32 total = 0;
int32 items_total = 0;
assert(player);
res = query.RunQuery2(Q_SELECT, "SELECT `char_id`, `achievement_id`, `completed_date` FROM character_achievements WHERE char_id = %u ", player->GetCharacterID());
if (res) {
while ((row = mysql_fetch_row(res))) {
update = new AchievementUpdate();
update->SetID(atoul(row[1]));
update->SetCompletedDate(atoul(row[2]));
LogWrite(ACHIEVEMENT__DEBUG, 5, "Achievements", "Loading Player Achievement Update for Achievement ID: %u ", update->GetID());
if (!player->GetAchievementUpdateList()->AddAchievementUpdate(update))
{
LogWrite(ACHIEVEMENT__ERROR, 0, "Achievements", "Error adding achievement update %u - diplicate ID", update->GetID());
safe_delete(update);
continue;
}
total++;
items_total += LoadPlayerAchievementsUpdateItems(update, player->GetCharacterID());
}
}
LogWrite(ACHIEVEMENT__DEBUG, 0, "Achievements", "Loaded %u player achievement updates", total);
return total;
}
int32 WorldDatabase::LoadPlayerAchievementsUpdateItems(AchievementUpdate *update, int32 player_id) {
AchievementUpdateItems *update_items;
Query query;
MYSQL_ROW row;
MYSQL_RES *res;
int32 total = 0;
assert(update);
res = query.RunQuery2(Q_SELECT, "SELECT `achievement_id`, `items` FROM character_achievements_items WHERE char_id = %u AND achievement_id = %u;", player_id, update->GetID());
if (res) {
while ((row = mysql_fetch_row(res))) {
update_items = new AchievementUpdateItems();
update_items->achievement_id = atoul(row[0]);
update_items->item_update = atoul(row[1]);
update->AddAchievementUpdateItems(update_items);
LogWrite(ACHIEVEMENT__DEBUG, 5, "Achievements", "Loading Player Achievement Update Items for Achievement ID: %u ", update_items->achievement_id);
total++;
}
}
LogWrite(ACHIEVEMENT__DEBUG, 0, "Achievements", "Loaded %u player achievement update items", total);
return total;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,118 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __AltAdvancement__
#define __AltAdvancement__
#include <vector>
#include "../../common/types.h"
#include "../../common/EQPacket.h"
#include "../client.h"
// defines for AA tabs based on group # from DB
#define AA_CLASS 0
#define AA_SUBCLASS 1
#define AA_SHADOW 2
#define AA_HEROIC 3
#define AA_TRADESKILL 4
#define AA_PRESTIGE 5
#define AA_TRADESKILL_PRESTIGE 6
#define AA_DRAGON 7
#define AA_DRAGONCLASS 8
#define AA_FARSEAS 9
struct AltAdvanceData
{
int32 spellID;
int8 min_level;
int32 spell_crc;
string name;
string description;
int8 group;
int16 icon;
int16 icon2;
int8 col;
int8 row;
int8 rankCost;
int8 maxRank;
int32 rankPrereqID;
int8 rankPrereq;
int8 class_req;
int8 tier;
int8 req_points;
int16 req_tree_points;
string class_name;
string subclass_name;
string line_title;
int8 title_level;
int32 node_id;
};
class MasterAAList
{
public:
MasterAAList();
~MasterAAList();
/// <summary>Sorts the Alternate Advancements for the given client, creates and sends the OP_AdventureList packet.</summary>
/// <param name='client'>The Client calling this function</param>
/// <returns>EQ2Packet*</returns>
EQ2Packet* GetAAListPacket(Client* client);
/// <summary>Add Alternate Advancement data to the global list.</summary>
/// <param name='data'>The Alternate Advancement data to add.</param>
void AddAltAdvancement(AltAdvanceData* data);
/// <summary>Get the total number of Alternate Advancements in the global list.</summary>
int Size();
/// <summary>Get the Alternate Advancement data for the given spell.</summary>
/// <param name='spellID'>Spell ID to get Alternate Advancement data for.</param>
AltAdvanceData* GetAltAdvancement(int32 spellID);
/// <summary>empties the master Alternate Advancement list</summary>
void DestroyAltAdvancements();
void DisplayAA(Client* client,int8 newtemplate,int8 changemode);
private:
vector <AltAdvanceData*> AAList;
Mutex MMasterAAList;
};
struct TreeNodeData
{
int32 classID;
int32 treeID;
int32 AAtreeID;
};
class MasterAANodeList
{
public:
MasterAANodeList();
~MasterAANodeList();
void AddTreeNode(TreeNodeData* data);
int Size();
void DestroyTreeNodes();
vector<TreeNodeData*> GetTreeNodes();
private:
vector<TreeNodeData*> TreeNodeList;
};
#endif

View File

@ -0,0 +1,102 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef WIN32
#include <WinSock2.h>
#include <windows.h>
#endif
#include <mysql.h>
#include <assert.h>
#include "../../common/Log.h"
#include "../../common/DatabaseNew.h"
#include "../WorldDatabase.h"
#include "AltAdvancement.h"
extern MasterAAList master_aa_list;
extern MasterAANodeList master_tree_nodes;
void WorldDatabase::LoadAltAdvancements()
{
Query query;
MYSQL_ROW row;
AltAdvanceData* data;
//MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `spell_id`, `group`, `icon`, `icon2`, `col`, `row`, `rank_cost`, `max_cost`, `rank_prereq_id`, `rank_prereq`, `class_req`, `tier`, `class_name`, `subclass_name`, `line_title` FROM spell_aa");
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `nodeid`,`minlevel`, `spellcrc`, `name`, `description`, `aa_list_fk`, `icon_id`, `icon_backdrop`, `xcoord`, `ycoord`, `pointspertier`, `maxtier`, `firstparentid`, `firstparentrequiredtier`, `displayedclassification`,`requiredclassification`, `classificationpointsrequired`, `pointsspentintreetounlock`, `title`,`titlelevel` FROM spell_aa_nodelist");
while (result && (row = mysql_fetch_row(result))) {
data = new AltAdvanceData;
int8 i = 0;
data->spellID = strtoul(row[0], NULL, 0);
data->min_level = atoi(row[++i]);
data->spell_crc = strtoul(row[++i], NULL, 0);
data->name = string(row[++i]);
data->description = string(row[++i]);
data->group = atoi(row[++i]);
data->icon = atoi(row[++i]);
data->icon2 = atoi(row[++i]);
data->col = atoi(row[++i]);
data->row = atoi(row[++i]);
data->rankCost = atoi(row[++i]);
data->maxRank = atoi(row[++i]);
data->rankPrereqID = strtoul(row[++i], NULL, 0);
data->rankPrereq = atoi(row[++i]);
data->tier = 1;
data->class_name = string(row[++i]);
data->subclass_name = string(row[i]);
data->req_points = atoi(row[++i]);
data->req_tree_points = atoi(row[++i]);
data->line_title = string(row[++i]);
data->title_level = atoi(row[++i]);
master_aa_list.AddAltAdvancement(data);
}
LogWrite(SPELL__INFO, 0, "AA", "Loaded %u Alternate Advancement(s)", master_aa_list.Size());
}
void WorldDatabase::LoadTreeNodes()
{
Query query;
MYSQL_ROW row;
TreeNodeData* data;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT class_id, tree_node, aa_tree_id FROM spell_aa_class_list");
while (result && (row = mysql_fetch_row(result))) {
data = new TreeNodeData;
data->classID = strtoul(row[0], NULL, 0);
data->treeID = strtoul(row[1], NULL, 0);
data->AAtreeID = strtoul(row[2], NULL, 0);
master_tree_nodes.AddTreeNode(data);
}
LogWrite(SPELL__INFO, 0, "AA", "Loaded %u AA Tree Nodes", master_tree_nodes.Size());
}
void WorldDatabase::LoadPlayerAA(Player *player)
{
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `template_id`,`tab_id`,`aa_id`,`order`,treeid FROM character_aa where char_id = %i order by `order`",player->id);
while (result && (row = mysql_fetch_row(result))) {
}
LogWrite(SPELL__INFO, 0, "AA", "Loaded %u AA Tree Nodes", master_tree_nodes.Size());
}

View File

@ -0,0 +1,87 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include <map>
using namespace std;
// Appearances must use a hash table because of the large amount that exists and the large spacing
// between their ID's. String and character arrays could not be used for the first iterator because
// it would require the same pointer to access it from the hash table, which is obviously not possible
// since the text is from the client.
// maximum amount of iterations it will attempt to find a entree
#define HASH_SEARCH_MAX 20
class Appearance
{
public:
// JA: someday add the min_client_version to the map to determine which appearance_id to set per client version
Appearance(int32 inID, const char *inName, int16 inVer)
{
if( !inName )
return;
name = string(inName);
id = inID;
min_client = inVer;
}
int32 GetID() { return id; }
const char* GetName() { return name.c_str(); }
int16 GetMinClientVersion() { return min_client; }
string GetNameString() { return name; }
private:
int32 id;
string name;
int16 min_client;
};
class Appearances
{
public:
~Appearances(){
Reset();
}
void Reset(){
ClearAppearances();
}
void ClearAppearances(){
map<int32, Appearance*>::iterator map_list;
for(map_list = appearanceMap.begin(); map_list != appearanceMap.end(); map_list++ )
safe_delete(map_list->second);
appearanceMap.clear();
}
void InsertAppearance(Appearance* a){
appearanceMap[a->GetID()] = a;
}
Appearance* FindAppearanceByID(int32 id){
if(appearanceMap.count(id) > 0)
return appearanceMap[id];
return 0;
}
private:
map<int32, Appearance*> appearanceMap;
};

View File

@ -0,0 +1,732 @@
#include "Bot.h"
#include "BotBrain.h"
#include "../Trade.h"
#include "../../common/Log.h"
#include "../WorldDatabase.h"
#include "../classes.h"
#include "../SpellProcess.h"
extern WorldDatabase database;
extern MasterSpellList master_spell_list;
extern World world;
extern Classes classes;
Bot::Bot() : NPC() {
SetBrain(new BotBrain(this));
BotID = 0;
ShowHelm = true;
ShowCloak = true;
CanTaunt = false;
combat_target = 0;
main_tank = 0;
//AddPrimaryEntityCommand("hail", 10000, "hail", "", 0, 0);
AddSecondaryEntityCommand("invite bot", 10000, "invite", "", 0, 0);
AddSecondaryEntityCommand("bot inventory", 10000, "bot inv list", "", 0, 0);
InfoStruct* info = GetInfoStruct();
info->set_str_base(50);
info->set_sta_base(20);
info->set_wis_base(20);
info->set_intel_base(20);
info->set_agi_base(20);
camping = false;
immediate_camp = false;
}
Bot::~Bot() {
}
void Bot::GiveItem(int32 item_id) {
Item* master_item = master_item_list.GetItem(item_id);
Item* item = 0;
if (master_item)
item = new Item(master_item);
if (item) {
int8 slot = GetEquipmentList()->GetFreeSlot(item);
if (slot != 255) {
GetEquipmentList()->AddItem(slot, item);
SetEquipment(item, slot);
database.SaveBotItem(BotID, item_id, slot);
if (slot == 0) {
ChangePrimaryWeapon();
if (IsBot())
LogWrite(PLAYER__ERROR, 0, "Bot", "Changing bot primary weapon.");
}
CalculateBonuses();
}
}
}
void Bot::GiveItem(Item* item) {
if (item) {
int8 slot = GetEquipmentList()->GetFreeSlot(item);
if (slot != 255) {
GetEquipmentList()->AddItem(slot, item);
SetEquipment(item, slot);
database.SaveBotItem(BotID, item->details.item_id, slot);
if (slot == 0) {
ChangePrimaryWeapon();
if (IsBot())
LogWrite(PLAYER__ERROR, 0, "Bot", "Changing bot primary weapon.");
}
CalculateBonuses();
}
}
}
void Bot::RemoveItem(Item* item) {
int8 slot = GetEquipmentList()->GetSlotByItem(item);
if (slot != 255) {
GetEquipmentList()->RemoveItem(slot, true);
SetEquipment(0, slot);
}
}
void Bot::TradeItemAdded(Item* item) {
int8 slot = GetEquipmentList()->GetFreeSlot(item);
if (slot == 255 && item->slot_data.size() > 0) {
slot = item->slot_data[0];
AddItemToTrade(slot);
}
}
void Bot::AddItemToTrade(int8 slot) {
Item* item = GetEquipmentList()->GetItem(slot);
if (trading_slots.count(slot) == 0 && item && trade) {
trade->AddItemToTrade(this, item, 1, 255);
trading_slots.insert(slot);
}
}
bool Bot::CheckTradeItems(map<int8, TradeItemInfo>* list) {
if (!list) {
LogWrite(PLAYER__ERROR, 0, "Bot", "CheckTradeItems did not recieve a valid list of items");
return false;
}
bool ret = true;
map<int8, TradeItemInfo>::iterator itr;
for (itr = list->begin(); itr != list->end(); itr++) {
Item* item = itr->second.item;
if (item) {
if (!CanEquipItem(item)) {
// No slots means not equipable so reject the trade
ret = false;
break;
}
}
}
return ret;
}
void Bot::FinishTrade() {
trading_slots.clear();
}
bool Bot::CanEquipItem(Item* item) {
if (item) {
if (item->IsArmor() || item->IsWeapon() || item->IsFood() || item->IsRanged() || item->IsShield() || item->IsBauble() || item->IsAmmo() || item->IsThrown()) {
int16 override_level = item->GetOverrideLevel(GetAdventureClass(), GetTradeskillClass());
if (override_level > 0 && override_level <= GetLevel()) {
LogWrite(PLAYER__ERROR, 0, "Bot", "Passed in override_level check");
return true;
}
if (item->CheckClass(GetAdventureClass(), GetTradeskillClass()))
if (item->CheckLevel(GetAdventureClass(), GetTradeskillClass(), GetLevel())) {
LogWrite(PLAYER__ERROR, 0, "Bot", "Passed in normal check");
return true;
}
}
}
return false;
}
void Bot::MessageGroup(string msg) {
GroupMemberInfo* gmi = GetGroupMemberInfo();
if (gmi)
world.GetGroupManager()->GroupChatMessage(gmi->group_id, this, 0, msg.c_str());
}
void Bot::GetNewSpells() {
vector<Spell*> spells;
vector<Spell*>* spells1 = master_spell_list.GetSpellListByAdventureClass(GetAdventureClass(), GetLevel(), 1);
vector<Spell*>* spells2 = master_spell_list.GetSpellListByAdventureClass(classes.GetBaseClass(GetAdventureClass()), GetLevel(), 1);
vector<Spell*>* spells3 = master_spell_list.GetSpellListByAdventureClass(classes.GetSecondaryBaseClass(GetAdventureClass()), GetLevel(), 1);
spells.insert(spells.end(), spells1->begin(), spells1->end());
spells.insert(spells.end(), spells2->begin(), spells2->end());
spells.insert(spells.end(), spells3->begin(), spells3->end());
vector<Spell*>::iterator itr;
map<int32, int8>* spell_list = 0;
for (itr = spells.begin(); itr != spells.end(); itr++) {
switch ((*itr)->GetSpellData()->spell_type) {
case SPELL_TYPE_DD:
spell_list = &dd_spells;
break;
case SPELL_TYPE_DOT:
spell_list = &dot_spells;
break;
case SPELL_TYPE_HEAL:
spell_list = &heal_spells;
break;
case SPELL_TYPE_HOT_WARD:
spell_list = &hot_ward_spells;
break;
case SPELL_TYPE_DEBUFF:
spell_list = &debuff_spells;
break;
case SPELL_TYPE_BUFF:
spell_list = &buff_spells;
break;
case SPELL_TYPE_COMBATBUFF:
spell_list = &combat_buff_spells;
break;
case SPELL_TYPE_TAUNT:
spell_list = &taunt_spells;
break;
case SPELL_TYPE_DETAUNT:
spell_list = &detaunt_spells;
break;
case SPELL_TYPE_REZ:
LogWrite(PLAYER__ERROR, 0, "Bot", "Adding rez spell.");
spell_list = &rez_spells;
break;
case SPELL_TYPE_CURE:
spell_list = &cure_spells;
break;
default:
spell_list = 0;
break;
}
if (spell_list && spell_list->count((*itr)->GetSpellID()) == 0)
(*spell_list)[(*itr)->GetSpellID()] = 1;
}
safe_delete(spells1);
safe_delete(spells2);
safe_delete(spells3);
}
Entity* Bot::GetCombatTarget() {
Spawn* target = GetZone()->GetSpawnByID(combat_target);
if (target && target->IsEntity())
return (Entity*)target;
combat_target = 0;
return 0;
}
Spell* Bot::SelectSpellToCast(float distance) {
Spell* spell = 0;
map<int32, int8>::iterator itr;
// Heal
spell = GetHealSpell();
if (spell)
return spell;
// Taunt
spell = GetTauntSpell();
if (spell)
return spell;
// Detaunt
spell = GetDetauntSpell();
if (spell)
return spell;
// Hot/Ward
spell = GetHoTWardSpell();
if (spell)
return spell;
// Debuff
spell = GetDebuffSpell();
if (spell)
return spell;
// Combat Buff
spell = GetCombatBuffSpell();
if (spell)
return spell;
// DoT
spell = GetDoTSpell();
if (spell)
return spell;
// DD
spell = GetDDSpell();
if (spell)
return spell;
return 0;
}
void Bot::SetRecast(Spell* spell, int32 time) {
recast_times[spell->GetSpellID()] = time;
}
bool Bot::IsSpellReady(Spell* spell) {
if (recast_times.count(spell->GetSpellID()) > 0) {
if (recast_times[spell->GetSpellID()] > Timer::GetCurrentTime2())
return false;
}
return true;
}
Spell* Bot::GetDDSpell() {
if (dd_spells.size() == 0)
return 0;
Spell* spell = 0;
map<int32, int8>::iterator itr;
for (itr = dd_spells.begin(); itr != dd_spells.end(); itr++) {
spell = master_spell_list.GetSpell(itr->first, itr->second);
if (spell && IsSpellReady(spell)) {
return spell;
}
}
return 0;
}
Spell* Bot::GetHealSpell() {
if (heal_spells.size() == 0)
return 0;
// Get an available heal spell
Spell* spell = 0;
map<int32, int8>::iterator itr;
for (itr = heal_spells.begin(); itr != heal_spells.end(); itr++) {
spell = master_spell_list.GetSpell(itr->first, itr->second);
if (spell && IsSpellReady(spell)) {
break;
}
}
// No heal available, return out
if (!spell)
return 0;
// There was a heal spell so find a group member that needs healing
int8 threshold = GetHealThreshold();
GroupMemberInfo* gmi = GetGroupMemberInfo();
PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
if (group)
{
group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
deque<GroupMemberInfo*>* members = group->GetMembers();
for (int8 i = 0; i < members->size(); i++) {
Entity* member = members->at(i)->member;
if(!member)
continue;
if (!member->Alive())
continue;
int8 percent = (int8)(((float)member->GetHP() / member->GetTotalHP()) * 100);
if (percent <= threshold) {
if (spell) {
SetTarget(member);
group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
return spell;
}
}
}
group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
}
return 0;
}
Spell* Bot::GetTauntSpell() {
if (taunt_spells.size() == 0)
return 0;
// If not the main tank and taunts are turned off return out
if (main_tank != this && !CanTaunt)
return 0;
Spell* spell = 0;
map<int32, int8>::iterator itr;
for (itr = taunt_spells.begin(); itr != taunt_spells.end(); itr++) {
spell = master_spell_list.GetSpell(itr->first, itr->second);
if (spell && IsSpellReady(spell)) {
return spell;
}
}
return 0;
}
Spell* Bot::GetDetauntSpell() {
if (detaunt_spells.size() == 0)
return 0;
if (!GetTarget() || !GetTarget()->IsNPC())
return 0;
NPC* target = (NPC*)GetTarget();
Entity* hated = target->Brain()->GetMostHated();
if (hated == this) {
Spell* spell = 0;
map<int32, int8>::iterator itr;
for (itr = detaunt_spells.begin(); itr != detaunt_spells.end(); itr++) {
spell = master_spell_list.GetSpell(itr->first, itr->second);
if (spell && IsSpellReady(spell)) {
return spell;
}
}
}
return 0;
}
Spell* Bot::GetHoTWardSpell() {
if (hot_ward_spells.size() == 0)
return 0;
// Get an available spell
Spell* spell = 0;
map<int32, int8>::iterator itr;
for (itr = hot_ward_spells.begin(); itr != hot_ward_spells.end(); itr++) {
spell = master_spell_list.GetSpell(itr->first, itr->second);
if (spell && IsSpellReady(spell)) {
break;
}
}
// No spell available, return out
if (!spell)
return 0;
// There was a spell so find a group member that needs healing
int8 threshold = GetHealThreshold();
GroupMemberInfo* gmi = GetGroupMemberInfo();
PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
if (group)
{
group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
deque<GroupMemberInfo*>* members = group->GetMembers();
for (int8 i = 0; i < members->size(); i++) {
Entity* member = members->at(i)->member;
if(!member)
continue;
int8 percent = 0;
if (member->GetHP() > 0)
percent = (int8)(((float)member->GetHP() / member->GetTotalHP()) * 100);
if (percent <= 99 && percent > threshold) {
if (spell) {
SetTarget(member);
group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
return spell;
}
}
}
group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
}
return 0;
}
Spell* Bot::GetDebuffSpell() {
if (debuff_spells.size() == 0)
return 0;
Spell* spell = 0;
map<int32, int8>::iterator itr;
for (itr = debuff_spells.begin(); itr != debuff_spells.end(); itr++) {
spell = master_spell_list.GetSpell(itr->first, itr->second);
if (spell && IsSpellReady(spell)) {
// If target already has this effect on them then continue to the next spell
if (((Entity*)GetTarget())->GetSpellEffect(itr->first))
continue;
return spell;
}
}
return 0;
}
Spell* Bot::GetCombatBuffSpell() {
return 0;
}
Spell* Bot::GetDoTSpell() {
if (dot_spells.size() == 0)
return 0;
Spell* spell = 0;
map<int32, int8>::iterator itr;
for (itr = dot_spells.begin(); itr != dot_spells.end(); itr++) {
spell = master_spell_list.GetSpell(itr->first, itr->second);
if (spell && IsSpellReady(spell)) {
// If target already has this effect on them then continue to the next spell
if (((Entity*)GetTarget())->GetSpellEffect(itr->first))
continue;
return spell;
}
}
return 0;
}
Spell* Bot::GetBuffSpell() {
if (buff_spells.size() == 0)
return 0;
Spell* spell = 0;
Entity* target = 0;
map<int32, int8>::iterator itr;
for (itr = buff_spells.begin(); itr != buff_spells.end(); itr++) {
spell = master_spell_list.GetSpell(itr->first, itr->second);
if (spell && IsSpellReady(spell)) {
target = 0;
if (spell->GetSpellData()->target_type == SPELL_TARGET_SELF)
target = this;
if (spell->GetSpellData()->target_type == SPELL_TARGET_GROUP_AE)
target = this;
if (spell->GetSpellData()->target_type == SPELL_TARGET_ENEMY && spell->GetSpellData()->friendly_spell == 1)
target = (main_tank != NULL) ? main_tank : GetOwner();
if (!target)
continue;
if (!target->Alive())
continue;
// If target already has this effect on them then continue to the next spell
if (target->GetSpellEffect(itr->first))
continue;
SetTarget(target);
return spell;
}
}
return 0;
}
Spell* Bot::GetRezSpell() {
if (rez_spells.size() == 0)
return 0;
GroupMemberInfo* gmi = GetGroupMemberInfo();
if (!gmi)
return 0;
Entity* target = 0;
PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
if (group)
{
group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
deque<GroupMemberInfo*>* members = group->GetMembers();
for (int8 i = 0; i < members->size(); i++) {
Entity* member = members->at(i)->member;
if (member && !member->Alive() && member->IsPlayer()) {
PendingResurrection* rez = members->at(i)->client->GetCurrentRez();
if (rez->active)
continue;
target = member;
break;
}
}
group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
}
if (!target)
return 0;
Spell* spell = 0;
map<int32, int8>::iterator itr;
for (itr = rez_spells.begin(); itr != rez_spells.end(); itr++) {
spell = master_spell_list.GetSpell(itr->first, itr->second);
if (spell && IsSpellReady(spell)) {
SetTarget(target);
return spell;
}
}
return 0;
}
Spell* Bot::GetCureSpell() {
return 0;
}
int8 Bot::GetHealThreshold() {
int8 ret = 0;
switch (GetAdventureClass()) {
case PRIEST:
case CLERIC:
case TEMPLAR:
case INQUISITOR:
case DRUID:
case WARDEN:
case FURY:
case SHAMAN:
case MYSTIC:
case DEFILER:
ret = 70;
break;
default:
ret = 30;
break;
}
return ret;
}
bool Bot::ShouldMelee() {
bool ret = true;
switch (GetAdventureClass()) {
case PRIEST:
case CLERIC:
case TEMPLAR:
case INQUISITOR:
case DRUID:
case WARDEN:
case FURY:
case SHAMAN:
case MYSTIC:
case DEFILER:
case MAGE:
case SORCERER:
case WIZARD:
case WARLOCK:
case ENCHANTER:
case ILLUSIONIST:
case COERCER:
case SUMMONER:
case CONJUROR:
case NECROMANCER:
ret = false;
break;
default:
ret = true;
break;
}
if (GetTarget() == GetOwner())
ret = false;
return ret;
}
void Bot::Camp(bool immediate) {
// Copy from COMMAND_GROUP_LEAVE
camping = true;
immediate_camp = immediate;
}
void Bot::ChangeLevel(int16 old_level, int16 new_level) {
if (new_level < 1)
return;
if (GetLevel() != new_level) {
SetLevel(new_level);
if (GetGroupMemberInfo()) {
UpdateGroupMemberInfo();
world.GetGroupManager()->SendGroupUpdate(GetGroupMemberInfo()->group_id);
}
}
if (GetPet()) {
NPC* pet = (NPC*)GetPet();
if (pet->GetMaxPetLevel() == 0 || new_level <= pet->GetMaxPetLevel()) {
pet->SetLevel(new_level);
GetZone()->PlayAnimation(pet, 1753);
}
}
// level up animation
GetZone()->PlayAnimation(this, 1753);
//player->GetSkills()->IncreaseAllSkillCaps(5 * (new_level - old_level));
GetNewSpells();
//SendNewSpells(player->GetAdventureClass());
//SendNewSpells(classes.GetBaseClass(player->GetAdventureClass()));
//SendNewSpells(classes.GetSecondaryBaseClass(player->GetAdventureClass()));
GetInfoStruct()->set_level(new_level);
UpdateWeapons();
// GetPlayer()->SetLevel(new_level);
LogWrite(MISC__TODO, 1, "TODO", "Get new HP/POWER/stat based on default values from DB\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
SetTotalHPBase(new_level*new_level * 2 + 40);
SetTotalPowerBase((sint32)(new_level*new_level*2.1 + 45));
CalculateBonuses();
SetHP(GetTotalHP());
SetPower(GetTotalPower());
GetInfoStruct()->set_agi_base(new_level * 2 + 15);
GetInfoStruct()->set_intel_base(new_level * 2 + 15);
GetInfoStruct()->set_wis_base(new_level * 2 + 15);
GetInfoStruct()->set_str_base(new_level * 2 + 15);
GetInfoStruct()->set_sta_base(new_level * 2 + 15);
GetInfoStruct()->set_cold_base((int16)(new_level*1.5 + 10));
GetInfoStruct()->set_heat_base((int16)(new_level*1.5 + 10));
GetInfoStruct()->set_disease_base((int16)(new_level*1.5 + 10));
GetInfoStruct()->set_mental_base((int16)(new_level*1.5 + 10));
GetInfoStruct()->set_magic_base((int16)(new_level*1.5 + 10));
GetInfoStruct()->set_divine_base((int16)(new_level*1.5 + 10));
GetInfoStruct()->set_poison_base((int16)(new_level*1.5 + 10));
/*UpdateTimeStampFlag(LEVEL_UPDATE_FLAG);
GetPlayer()->SetCharSheetChanged(true);
Message(CHANNEL_COLOR_EXP, "You are now level %i!", new_level);
LogWrite(WORLD__DEBUG, 0, "World", "Player: %s leveled from %u to %u", GetPlayer()->GetName(), old_level, new_level);
GetPlayer()->GetSkills()->SetSkillCapsByType(1, 5 * new_level);
GetPlayer()->GetSkills()->SetSkillCapsByType(3, 5 * new_level);
GetPlayer()->GetSkills()->SetSkillCapsByType(6, 5 * new_level);
GetPlayer()->GetSkills()->SetSkillCapsByType(13, 5 * new_level);
*/
}
void Bot::Begin_Camp() {
GroupMemberInfo* gmi = GetGroupMemberInfo();
if (gmi) {
int32 group_id = gmi->group_id;
world.GetGroupManager()->RemoveGroupMember(group_id, this);
if (!world.GetGroupManager()->IsGroupIDValid(group_id)) {
// leader->Message(CHANNEL_COLOR_GROUP, "%s has left the group.", client->GetPlayer()->GetName());
}
else {
world.GetGroupManager()->GroupMessage(group_id, "%s has left the group.", GetName());
}
}
if(!immediate_camp)
{
GetZone()->PlayAnimation(this, 538);
SetVisualState(540);
GetZone()->Despawn(this, 5000);
}
if (!GetOwner())
return;
if (GetOwner()->IsPlayer())
((Player*)GetOwner())->SpawnedBots.erase(BotIndex);
camping = false;
immediate_camp = true;
}

View File

@ -0,0 +1,95 @@
#pragma once
#include "../NPC.h"
#include <set>
struct TradeItemInfo;
class Bot : public NPC {
public:
Bot();
~Bot();
int32 BotID; // DB id
int32 BotIndex; // Bot id with its owner (player)
bool IsBot() { return true; }
void GiveItem(int32 item_id);
void GiveItem(Item* item);
void RemoveItem(Item* item);
void TradeItemAdded(Item* item);
void AddItemToTrade(int8 slot);
bool CheckTradeItems(map<int8, TradeItemInfo>* list);
void FinishTrade();
void GetNewSpells();
map<int32, int8>* GetBotSpells() { return &dd_spells; }
bool ShowHelm;
bool ShowCloak;
bool CanTaunt;
Entity* GetCombatTarget();
void SetCombatTarget(int32 target) { combat_target = target; }
Spell* SelectSpellToCast(float distance);
void MessageGroup(string msg);
void SetRecast(Spell* spell, int32 time);
bool ShouldMelee();
Spell* GetNextBuffSpell(Spawn* target = 0) { return GetBuffSpell(); }
Spell* GetHealSpell();
Spell* GetRezSpell();
void SetMainTank(Entity* tank) { main_tank = tank; }
void Camp(bool immediate=false);
void ChangeLevel(int16 old_level, int16 new_level);
bool IsCamping() { return camping; }
bool IsImmediateCamp() { return immediate_camp; }
void Begin_Camp();
private:
bool CanEquipItem(Item* item);
bool IsSpellReady(Spell* spell);
Spell* GetTauntSpell();
Spell* GetDetauntSpell();
Spell* GetHoTWardSpell();
Spell* GetDebuffSpell();
Spell* GetCombatBuffSpell();
Spell* GetDoTSpell();
Spell* GetDDSpell();
Spell* GetBuffSpell();
Spell* GetCureSpell();
int8 GetHealThreshold();
set<int8> trading_slots;
int32 combat_target;
Entity* main_tank;
map<int32, int8> bot_spells;
map<int32, int8> dd_spells;
map<int32, int8> dot_spells;
map<int32, int8> heal_spells;
map<int32, int8> hot_ward_spells;
map<int32, int8> debuff_spells;
map<int32, int8> buff_spells;
map<int32, int8> combat_buff_spells;
map<int32, int8> taunt_spells;
map<int32, int8> detaunt_spells;
map<int32, int8> rez_spells;
map<int32, int8> cure_spells;
// First int32 = spell id (change to timer id later), second int32 is time the spell is available to cast again
map<int32, int32> recast_times;
std::atomic<bool> camping;
std::atomic<bool> immediate_camp;
};

View File

@ -0,0 +1,205 @@
#include "BotBrain.h"
#include "../Combat.h"
#include "../Spells.h"
#include "../../common/Log.h"
#include "../Rules/Rules.h"
extern RuleManager rule_manager;
BotBrain::BotBrain(Bot* body) : Brain(body) {
Body = body;
}
BotBrain::~BotBrain() {
}
void BotBrain::Think() {
// No ownder do nothing, probably despawn as owner should never be empty for bots
if (!m_body->GetOwner())
return;
// Not in a group yet then do nothing
if (!m_body->GetGroupMemberInfo())
return;
if (!Body->Alive())
return;
if (Body->IsMezzedOrStunned())
return;
// If combat was processed we can return out
if (ProcessCombat())
return;
// Combat failed to process so do out of combat tasks like follow the player
if (ProcessOutOfCombatSpells())
return;
// put htis here so bots don't try to follow the owner while in combat
if (Body->EngagedInCombat())
return;
// Set target to owner
Spawn* target = GetBody()->GetFollowTarget();
if(target)
{
// Get distance from the owner
float distance = GetBody()->GetDistance(target);
// If out of melee range then move closer
if (distance > rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat())
MoveCloser(target);
}
}
bool BotBrain::ProcessCombat() {
SetTarget();
if (Body->GetTarget() && Body->EngagedInCombat()) {
if (Body->GetTarget() && Body->GetTarget()->IsEntity() && Body->AttackAllowed((Entity*)Body->GetTarget())) {
Entity* target = (Entity*)Body->GetTarget();
float distance = Body->GetDistance(target);
if (!ProcessSpell(target, distance)) {
if (Body->ShouldMelee())
ProcessMelee(target, distance);
}
NPC* pet = (NPC*)Body->GetPet();
if (pet) {
if (pet->Brain()->GetHate(target) == 0)
pet->AddHate(target, 1);
}
}
return true;
}
return false;
}
void BotBrain::SetTarget() {
// The target issued from /bot attack
if (Body->GetCombatTarget() && Body->GetCombatTarget()->Alive()) {
Body->SetTarget(Body->GetCombatTarget());
Body->InCombat(true);
return;
}
// Assist
Entity* owner = Body->GetOwner();
if (owner && owner->EngagedInCombat()) {
if (owner->GetTarget() && owner->GetTarget()->IsEntity() && owner->GetTarget()->Alive() && owner->AttackAllowed((Entity*)owner->GetTarget())) {
Body->SetTarget(owner->GetTarget());
Body->InCombat(true);
// Add some hate to keep the bot attacking if
// the player toggles combat off
if (GetHate((Entity*)Body->GetTarget()) == 0)
AddHate((Entity*)Body->GetTarget(), 1);
return;
}
}
// Most hated
Entity* hated = GetMostHated();
if (hated && hated->Alive()) {
if (hated == Body->GetOwner()) {
ClearHate(hated);
}
else {
Body->SetTarget(hated);
Body->InCombat(true);
return;
}
}
// None of the above true so clear target and turn combat off
Body->SetTarget(0);
Body->InCombat(false);
}
bool BotBrain::ProcessSpell(Entity* target, float distance) {
if (Body->IsStifled() || Body->IsFeared())
return false;
if (Body->IsCasting())
return false;
if (!HasRecovered())
return false;
Spell* spell = Body->SelectSpellToCast(distance);
if (spell) {
// Target can change (heals for example) so recalculate distance and if out of range move closer
float distance = Body->GetDistance(Body->GetTarget());
if (distance > spell->GetSpellData()->range) {
if (Body->GetTarget()->IsEntity())
MoveCloser((Spawn*)Body->GetTarget());
}
else {
// stop movement if spell can't be cast while moving
if (!spell->GetSpellData()->cast_while_moving)
Body->CalculateRunningLocation(true);
Body->GetZone()->ProcessSpell(spell, Body, Body->GetTarget());
m_spellRecovery = (int32)(Timer::GetCurrentTime2() + (spell->GetSpellData()->cast_time * 10) + (spell->GetSpellData()->recovery * 10) + 2000);
// recast time
int32 time = Timer::GetCurrentTime2() + (spell->CalculateRecastTimer(Body));
Body->SetRecast(spell, time);
string str = "I am casting ";
str += spell->GetName();
Body->MessageGroup(str);
}
return true;
}
return false;
}
bool BotBrain::ProcessOutOfCombatSpells() {
if (Body->IsStifled() || Body->IsFeared())
return false;
if (Body->IsCasting())
return false;
if (!HasRecovered())
return false;
Spell* spell = Body->GetHealSpell();
if (!spell)
spell = Body->GetRezSpell();
if (!spell)
spell = Body->GetNextBuffSpell();
if (spell) {
// stop movement if spell can't be cast while moving
if (!spell->GetSpellData()->cast_while_moving)
Body->CalculateRunningLocation(true);
// See if we are in range of target, if not move closer
float distance = Body->GetDistance(Body->GetTarget());
if (distance > spell->GetSpellData()->range) {
if (Body->GetTarget()->IsEntity())
MoveCloser((Spawn*)Body->GetTarget());
}
else {
Body->GetZone()->ProcessSpell(spell, Body, Body->GetTarget());
m_spellRecovery = (int32)(Timer::GetCurrentTime2() + (spell->GetSpellData()->cast_time * 10) + (spell->GetSpellData()->recovery * 10) + 2000);
// recast time
int32 time = Timer::GetCurrentTime2() + (spell->CalculateRecastTimer(Body));
Body->SetRecast(spell, time);
string str = "I am casting ";
str += spell->GetName();
Body->MessageGroup(str);
}
return true;
}
return false;
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "../NPC_AI.h"
#include "Bot.h"
class BotBrain : public Brain {
public:
BotBrain(Bot* body);
virtual ~BotBrain();
void Think();
bool ProcessSpell(Entity* target, float distance);
bool ProcessOutOfCombatSpells();
private:
Bot* Body;
bool ProcessCombat();
void SetTarget();
};

View File

@ -0,0 +1,830 @@
#include "../Commands/Commands.h"
#include "../WorldDatabase.h"
#include "../classes.h"
#include "../races.h"
#include "../Bots/Bot.h"
#include "../../common/Log.h"
#include "../Trade.h"
#include "../PlayerGroups.h"
#include "../World.h"
#include "../../common/GlobalHeaders.h"
extern WorldDatabase database;
extern ConfigReader configReader;
extern World world;
extern MasterSpellList master_spell_list;
void Commands::Command_Bot(Client* client, Seperator* sep) {
if (sep && sep->IsSet(0)) {
if (strncasecmp("camp", sep->arg[0], 4) == 0) {
if (!client->GetPlayer()->GetTarget() || !client->GetPlayer()->GetTarget()->IsBot()) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You must target a bot");
return;
}
Bot* bot = (Bot*)client->GetPlayer()->GetTarget();
if (bot->GetOwner() != client->GetPlayer()) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You can only camp your own bots.");
return;
}
bot->Camp();
return;
}
else if (strncasecmp("attack", sep->arg[0], 6) == 0) {
if (client->GetPlayer()->GetTarget() && client->GetPlayer()->GetTarget()->IsEntity() && client->GetPlayer()->GetTarget()->Alive()) {
Entity* target = (Entity*)client->GetPlayer()->GetTarget();
if (client->GetPlayer()->GetDistance(target) <= 50) {
if (client->GetPlayer()->AttackAllowed(target)) {
GroupMemberInfo* gmi = client->GetPlayer()->GetGroupMemberInfo();
if (gmi) {
PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
if (group)
{
group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
deque<GroupMemberInfo*>* members = group->GetMembers();
deque<GroupMemberInfo*>::iterator itr;
for (itr = members->begin(); itr != members->end(); itr++) {
//devn00b compile says this is no good, commenting out for now.
//if(!member)
// continue;
if ((*itr)->member && (*itr)->member->IsBot() && ((Bot*)(*itr)->member)->GetOwner() == client->GetPlayer()) {
((Bot*)(*itr)->member)->SetCombatTarget(target->GetID());
}
}
group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
}
}
}
else
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You can not attack that target.");
}
else
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Target is to far away.");
}
else
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Not a valid target.");
return;
}
else if (strncasecmp("spells", sep->arg[0], 6) == 0) {
if (client->GetPlayer()->GetTarget() && client->GetPlayer()->GetTarget()->IsBot()) {
Bot* bot = (Bot*)client->GetPlayer()->GetTarget();
map<int32, int8>* spells = bot->GetBotSpells();
map<int32, int8>::iterator itr;
string output;
for (itr = spells->begin(); itr != spells->end(); itr++) {
Spell* spell = master_spell_list.GetSpell(itr->first, itr->second);
if (spell) {
output += spell->GetName();
output += "\n";
}
}
client->SimpleMessage(CHANNEL_COLOR_YELLOW, output.c_str());
return;
}
}
else if (strncasecmp("maintank", sep->arg[0], 8) == 0) {
if (!client->GetPlayer()->GetTarget() || !client->GetPlayer()->GetTarget()->IsEntity()) {
client->SimpleMessage(CHANNEL_COMMAND_TEXT, "Not a valid target.");
return;
}
GroupMemberInfo* gmi = client->GetPlayer()->GetGroupMemberInfo();
if (!gmi) {
client->SimpleMessage(CHANNEL_COMMAND_TEXT, "You are not in a group.");
return;
}
Entity* target = (Entity*)client->GetPlayer()->GetTarget();
if (!world.GetGroupManager()->IsInGroup(gmi->group_id, target)) {
client->SimpleMessage(CHANNEL_COMMAND_TEXT, "Target is not in your group.");
return;
}
PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
if (group)
{
group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
deque<GroupMemberInfo*>* members = group->GetMembers();
for (int8 i = 0; i < members->size(); i++) {
GroupMemberInfo* gmi2 = members->at(i);
if(!gmi2 || !gmi2->member)
continue;
if (gmi2->member->IsBot() && ((Bot*)gmi2->member)->GetOwner() == client->GetPlayer()) {
((Bot*)gmi2->member)->SetMainTank(target);
client->Message(CHANNEL_COMMAND_TEXT, "Setting main tank for %s to %s", gmi2->member->GetName(), target->GetName());
}
}
group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
}
return;
}
else if (strncasecmp("delete", sep->arg[0], 6) == 0) {
if (sep->IsSet(1) && sep->IsNumber(1)) {
int32 index = atoi(sep->arg[1]);
// Check if bot is currently spawned and if so camp it out
if (client->GetPlayer()->SpawnedBots.count(index) > 0) {
Spawn* bot = client->GetCurrentZone()->GetSpawnByID(client->GetPlayer()->SpawnedBots[index]);
if (bot && bot->IsBot())
((Bot*)bot)->Camp();
}
database.DeleteBot(client->GetCharacterID(), index);
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Bot has been deleted.");
return;
}
else {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You must give the id (from /bot list) to delete a bot");
return;
}
}
else if (strncasecmp("follow", sep->arg[0], 6) == 0) {
if (sep->IsSet(1) && sep->IsNumber(1)) {
int32 index = atoi(sep->arg[1]);
// Check if bot is currently spawned and if so camp it out
if (client->GetPlayer()->SpawnedBots.count(index) > 0) {
Spawn* bot = client->GetCurrentZone()->GetSpawnByID(client->GetPlayer()->SpawnedBots[index]);
if (bot && bot->IsBot())
((Bot*)bot)->SetFollowTarget(client->GetPlayer(), 5);
}
return;
}
else {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You must give the id (from /bot list) to have a bot follow you");
return;
}
}
else if (strncasecmp("stopfollow", sep->arg[0], 10) == 0) {
if (sep->IsSet(1) && sep->IsNumber(1)) {
int32 index = atoi(sep->arg[1]);
// Check if bot is currently spawned and if so camp it out
if (client->GetPlayer()->SpawnedBots.count(index) > 0) {
Spawn* bot = client->GetCurrentZone()->GetSpawnByID(client->GetPlayer()->SpawnedBots[index]);
if (bot && bot->IsBot())
((Bot*)bot)->SetFollowTarget(nullptr);
}
return;
}
else {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You must give the id (from /bot list) to stop a following bot");
return;
}
}
else if (strncasecmp("summon", sep->arg[0], 6) == 0) {
if (sep->IsSet(1) && strncasecmp("group", sep->arg[1], 5) == 0) {
GroupMemberInfo* gmi = client->GetPlayer()->GetGroupMemberInfo();
if (gmi) {
Player* player = client->GetPlayer();
PlayerGroup* group = world.GetGroupManager()->GetGroup(gmi->group_id);
if (group)
{
group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
deque<GroupMemberInfo*>* members = group->GetMembers();
for (int8 i = 0; i < members->size(); i++) {
Entity* member = members->at(i)->member;
if(!member)
continue;
if (member->IsBot() && ((Bot*)member)->GetOwner() == player) {
if(member->GetZone() && member->GetLocation() != player->GetLocation()) {
member->SetLocation(player->GetLocation());
}
member->SetX(player->GetX());
member->SetY(player->GetY());
member->SetZ(player->GetZ());
client->Message(CHANNEL_COLOR_YELLOW, "Summoning %s.", member->GetName());
}
}
group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
}
return;
}
else {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not in a group.");
return;
}
}
else {
if (client->GetPlayer()->GetTarget() && client->GetPlayer()->GetTarget()->IsBot()) {
Bot* bot = (Bot*)client->GetPlayer()->GetTarget();
Player* player = client->GetPlayer();
if (bot && bot->GetOwner() == player) {
bot->SetLocation(player->GetLocation());
bot->SetX(player->GetX());
bot->SetY(player->GetY());
bot->SetZ(player->GetZ());
client->Message(CHANNEL_COLOR_YELLOW, "Summoning %s.", bot->GetName());
return;
}
else {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You can only summon your own bots.");
return;
}
}
else {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You must target a bot.");
return;
}
}
}
else if (strncasecmp("test", sep->arg[0], 4) == 0) {
if (client->GetPlayer()->GetTarget() && client->GetPlayer()->GetTarget()->IsBot()) {
((Bot*)client->GetPlayer()->GetTarget())->MessageGroup("Test message");
return;
}
}
}
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "BotCommands:");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot create [race] [gender] [class] [name]");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot customize - customize the appearance of the bot");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot list - list all the bots you have created with this character");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot spawn [id] - spawns a bot into the world, id obtained from /bot list");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot inv [give/list/remove] - manage bot equipment, for remove a slot must be provided");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot settings [helm/hood/cloak/taunt] [0/1] - Turn setting on (1) or off(0)");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot camp - removes the bot from your group and despawns them");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot attack - commands your bots to attack your target");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot spells - lists bot spells, not fully implemented yet");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot maintank - sets targeted group member as the main tank for your bots");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot delete [id] - deletes the bot with the given id (obtained from /bot list)");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot help");
}
void Commands::Command_Bot_Create(Client* client, Seperator* sep) {
int8 race = BARBARIAN;
int8 gender = 0;
int8 advClass = GUARDIAN;
string name;
if (sep) {
if (sep->IsSet(0) && sep->IsNumber(0))
race = atoi(sep->arg[0]);
else {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "First param of \"/bot create\" needs to be a number");
return;
}
if (sep->IsSet(1) && sep->IsNumber(1))
gender = atoi(sep->arg[1]);
else {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Second param of \"/bot create\" needs to be a number");
return;
}
if (sep->IsSet(2) && sep->IsNumber(2))
advClass = atoi(sep->arg[2]);
else {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Third param of \"/bot create\" needs to be a number");
return;
}
if (sep->IsSet(3)) {
name = string(sep->arg[3]);
transform(name.begin(), name.begin() + 1, name.begin(), ::toupper);
transform(name.begin() + 1, name.end(), name.begin() + 1, ::tolower);
}
else {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Fourth param (name) of \"/bot create\" is required");
return;
}
}
else {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Syntax: /bot create [race ID] [Gender ID] [class ID] [name]");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "All parameters are required. /bot help race or /bot help class for ID's.");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Gender ID's: 0 = Female, 1 = Male");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Ex: /bot create 0 0 3 Botty");
return;
}
int8 result = database.CheckNameFilter(name.c_str());
if (result == BADNAMELENGTH_REPLY) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Name length is invalid, must be greater then 3 characters and less then 16.");
return;
}
else if (result == NAMEINVALID_REPLY) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Name is invalid, can only contain letters.");
return;
}
else if (result == NAMETAKEN_REPLY) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Name is already taken, please choose another.");
return;
}
else if (result == NAMEFILTER_REPLY) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Name failed the filter check.");
return;
}
else if (result == UNKNOWNERROR_REPLY) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Unknown error while checking the name.");
return;
}
string race_string;
switch (race) {
case BARBARIAN:
race_string = "/barbarian/barbarian";
break;
case DARK_ELF:
race_string = "/darkelf/darkelf";
break;
case DWARF:
race_string = "/dwarf/dwarf";
break;
case ERUDITE:
race_string = "/erudite/erudite";
break;
case FROGLOK:
race_string = "/froglok/froglok";
break;
case GNOME:
race_string = "/gnome/gnome";
break;
case HALF_ELF:
race_string = "/halfelf/halfelf";
break;
case HALFLING:
race_string = "/halfling/halfling";
break;
case HIGH_ELF:
race_string = "/highelf/highelf";
break;
case HUMAN:
race_string = "/human/human";
break;
case IKSAR:
race_string = "/iksar/iksar";
break;
case KERRA:
race_string = "/kerra/kerra";
break;
case OGRE:
race_string = "/ogre/ogre";
break;
case RATONGA:
race_string = "/ratonga/ratonga";
break;
case TROLL:
race_string = "/troll/troll";
break;
case WOOD_ELF:
race_string = "/woodelf/woodelf";
break;
case FAE:
race_string = "/fae/fae_light";
break;
case ARASAI:
race_string = "/fae/fae_dark";
break;
case SARNAK:
gender == 1 ? race_string = "01/sarnak_male/sarnak" : race_string = "01/sarnak_female/sarnak";
break;
case VAMPIRE:
race_string = "/vampire/vampire";
break;
case AERAKYN:
race_string = "/aerakyn/aerakyn";
break;
}
if (race_string.length() > 0) {
string gender_string;
Bot* bot = 0;
gender == 1 ? gender_string = "male" : gender_string = "female";
vector<int16>* id_list = database.GetAppearanceIDsLikeName("ec/pc" + race_string + "_" + gender_string);
if (id_list) {
bot = new Bot();
memset(&bot->appearance, 0, sizeof(bot->appearance));
bot->appearance.pos.collision_radius = 32;
bot->secondary_command_list_id = 0;
bot->primary_command_list_id = 0;
bot->appearance.display_name = 1;
bot->appearance.show_level = 1;
bot->appearance.attackable = 1;
bot->appearance.show_command_icon = 1;
bot->appearance.targetable = 1;
bot->appearance.race = race;
bot->appearance.gender = gender;
bot->SetID(Spawn::NextID());
bot->SetX(client->GetPlayer()->GetX());
bot->SetY(client->GetPlayer()->GetY());
bot->SetZ(client->GetPlayer()->GetZ());
bot->SetHeading(client->GetPlayer()->GetHeading());
bot->SetSpawnOrigX(bot->GetX());
bot->SetSpawnOrigY(bot->GetY());
bot->SetSpawnOrigZ(bot->GetZ());
bot->SetSpawnOrigHeading(bot->GetHeading());
bot->SetLocation(client->GetPlayer()->GetLocation());
bot->SetInitialState(16512);
bot->SetModelType(id_list->at(0));
bot->SetAdventureClass(advClass);
bot->SetLevel(client->GetPlayer()->GetLevel());
bot->SetName(name.c_str());
bot->SetDifficulty(6);
bot->size = 32;
if (bot->GetTotalHP() == 0) {
bot->SetTotalHP(25 * bot->GetLevel() + 1);
bot->SetTotalHPBaseInstance(bot->GetTotalHP());
bot->SetHP(25 * bot->GetLevel() + 1);
}
if (bot->GetTotalPower() == 0) {
bot->SetTotalPower(25 * bot->GetLevel() + 1);
bot->SetTotalPowerBaseInstance(bot->GetTotalPower());
bot->SetPower(25 * bot->GetLevel() + 1);
}
bot->SetOwner(client->GetPlayer());
bot->GetNewSpells();
client->GetCurrentZone()->AddSpawn(bot);
int32 index;
int32 bot_id = database.CreateNewBot(client->GetCharacterID(), name, race, advClass, gender, id_list->at(0), index);
if (bot_id == 0) {
LogWrite(PLAYER__ERROR, 0, "Player", "Error saving bot to DB. Bot was not saved!");
client->SimpleMessage(CHANNEL_ERROR, "Error saving bot to DB. Bot was not saved!");
}
else {
bot->BotID = bot_id;
bot->BotIndex = index;
client->GetPlayer()->SpawnedBots[bot->BotIndex] = bot->GetID();
// Add Items
database.SetBotStartingItems(bot, advClass, race);
}
}
else {
client->SimpleMessage(CHANNEL_COLOR_RED, "Error finding the id list for your race, please verify the race id.");
}
safe_delete(id_list);
}
else
client->SimpleMessage(CHANNEL_COLOR_RED, "Error finding the race string, please verify the race id.");
}
void Commands::Command_Bot_Customize(Client* client, Seperator* sep) {
Bot* bot = 0;
if (client->GetPlayer()->GetTarget() && client->GetPlayer()->GetTarget()->IsBot())
bot = (Bot*)client->GetPlayer()->GetTarget();
client->Message(CHANNEL_COLOR_RED, "This command is disabled and requires new implementation.");
/*if (bot && bot->GetOwner() == client->GetPlayer()) {
PacketStruct* packet = configReader.getStruct("WS_OpenCharCust", client->GetVersion());
if (packet) {
AppearanceData* botApp = &bot->appearance;
CharFeatures* botFeatures = &bot->features;
AppearanceData* playerApp = &client->GetPlayer()->appearance;
CharFeatures* playerFeatures = &client->GetPlayer()->features;
memcpy(&client->GetPlayer()->SavedApp, playerApp, sizeof(AppearanceData));
memcpy(&client->GetPlayer()->SavedFeatures, playerFeatures, sizeof(CharFeatures));
client->GetPlayer()->custNPC = true;
client->GetPlayer()->custNPCTarget = bot;
memcpy(playerApp, botApp, sizeof(AppearanceData));
memcpy(playerFeatures, botFeatures, sizeof(CharFeatures));
client->GetPlayer()->changed = true;
client->GetPlayer()->info_changed = true;
client->GetCurrentZone()->SendSpawnChanges(client->GetPlayer(), client);
packet->setDataByName("race_id", 255);
client->QueuePacket(packet->serialize());
}
}*/
}
void Commands::Command_Bot_Spawn(Client* client, Seperator* sep) {
if (sep && sep->IsSet(0) && sep->IsNumber(0)) {
int32 bot_id = atoi(sep->arg[0]);
if (client->GetPlayer()->SpawnedBots.count(bot_id) > 0) {
client->Message(CHANNEL_COLOR_YELLOW, "The bot with id %u is already spawned.", bot_id);
return;
}
Bot* bot = new Bot();
memset(&bot->appearance, 0, sizeof(bot->appearance));
if (database.LoadBot(client->GetCharacterID(), bot_id, bot)) {
bot->SetFollowTarget(client->GetPlayer(), 5);
bot->appearance.pos.collision_radius = 32;
bot->secondary_command_list_id = 0;
bot->primary_command_list_id = 0;
bot->appearance.display_name = 1;
bot->appearance.show_level = 1;
bot->appearance.attackable = 1;
bot->appearance.show_command_icon = 1;
bot->appearance.targetable = 1;
bot->SetID(Spawn::NextID());
bot->SetX(client->GetPlayer()->GetX());
bot->SetY(client->GetPlayer()->GetY());
bot->SetZ(client->GetPlayer()->GetZ());
bot->SetHeading(client->GetPlayer()->GetHeading());
bot->SetSpawnOrigX(bot->GetX());
bot->SetSpawnOrigY(bot->GetY());
bot->SetSpawnOrigZ(bot->GetZ());
bot->SetSpawnOrigHeading(bot->GetHeading());
bot->SetLocation(client->GetPlayer()->GetLocation());
bot->SetInitialState(16512);
bot->SetLevel(client->GetPlayer()->GetLevel());
bot->SetDifficulty(6);
bot->size = 32;
if (bot->GetTotalHP() == 0) {
bot->SetTotalHP(25 * bot->GetLevel() + 1);
bot->SetHP(25 * bot->GetLevel() + 1);
}
if (bot->GetTotalPower() == 0) {
bot->SetTotalPower(25 * bot->GetLevel() + 1);
bot->SetPower(25 * bot->GetLevel() + 1);
}
bot->SetOwner(client->GetPlayer());
bot->UpdateWeapons();
bot->CalculateBonuses();
bot->GetNewSpells();
client->GetCurrentZone()->AddSpawn(bot);
if (sep->IsSet(1) && sep->IsNumber(1) && atoi(sep->arg[1]) == 1) {
client->GetCurrentZone()->SendSpawn(bot, client);
int8 result = world.GetGroupManager()->Invite(client->GetPlayer(), bot);
if (result == 0)
client->Message(CHANNEL_COMMANDS, "You invite %s to group with you.", bot->GetName());
else if (result == 1)
client->SimpleMessage(CHANNEL_COMMANDS, "That player is already in a group.");
else if (result == 2)
client->SimpleMessage(CHANNEL_COMMANDS, "That player has been invited to another group.");
else if (result == 3)
client->SimpleMessage(CHANNEL_COMMANDS, "Your group is already full.");
else if (result == 4)
client->SimpleMessage(CHANNEL_COMMANDS, "You have a pending invitation, cancel it first.");
else if (result == 5)
client->SimpleMessage(CHANNEL_COMMANDS, "You cannot invite yourself!");
else if (result == 6)
client->SimpleMessage(CHANNEL_COMMANDS, "Could not locate the player.");
else
client->SimpleMessage(CHANNEL_COMMANDS, "Group invite failed, unknown error!");
}
client->GetPlayer()->SpawnedBots[bot_id] = bot->GetID();
}
else {
client->Message(CHANNEL_ERROR, "Error spawning bot (%u)", bot_id);
}
}
else {
Command_Bot(client, sep);
}
}
void Commands::Command_Bot_List(Client* client, Seperator* sep) {
string bot_list;
bot_list = database.GetBotList(client->GetCharacterID());
if (!bot_list.empty())
client->SimpleMessage(CHANNEL_COLOR_YELLOW, bot_list.c_str());
}
void Commands::Command_Bot_Inv(Client* client, Seperator* sep) {
if (sep && sep->IsSet(0)) {
if (strncasecmp("give", sep->arg[0], 4) == 0) {
if (client->GetPlayer()->trade) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are already trading.");
return;
}
if (!client->GetPlayer()->GetTarget() || !client->GetPlayer()->GetTarget()->IsBot()) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You must target a bot");
return;
}
Bot* bot = (Bot*)client->GetPlayer()->GetTarget();
if (bot->trade) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Bot is already in a trade...");
return;
}
if (bot->GetOwner() != client->GetPlayer()) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You can only trade with your own bot.");
return;
}
Trade* trade = new Trade(client->GetPlayer(), bot);
client->GetPlayer()->trade = trade;
bot->trade = trade;
}
else if (strncasecmp("list", sep->arg[0], 4) == 0) {
if (!client->GetPlayer()->GetTarget() || !client->GetPlayer()->GetTarget()->IsBot()) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You must target a bot");
return;
}
Bot* bot = (Bot*)client->GetPlayer()->GetTarget();
if (bot->GetOwner() != client->GetPlayer()) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You can only see the inventory of your own bot.");
return;
}
string item_list = "Bot Items:\nSlot\tName\n";
for (int8 i = 0; i < NUM_SLOTS; i++) {
Item* item = bot->GetEquipmentList()->GetItem(i);
if (item) {
//\\aITEM %u %u:%s\\/a
item_list += to_string(i) + ":\t" + item->CreateItemLink(client->GetVersion(), true) + "\n";
}
}
client->SimpleMessage(CHANNEL_COLOR_YELLOW, item_list.c_str());
}
else if (strncasecmp("remove", sep->arg[0], 6) == 0) {
if (sep->IsSet(1) && sep->IsNumber(1)) {
int8 slot = atoi(sep->arg[1]);
if (slot >= NUM_SLOTS) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Invalid slot");
return;
}
if (!client->GetPlayer()->GetTarget() || !client->GetPlayer()->GetTarget()->IsBot()) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You must target a bot.");
return;
}
Bot* bot = (Bot*)client->GetPlayer()->GetTarget();
if (bot->GetOwner() != client->GetPlayer()) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You can only remove items from your own bot.");
return;
}
if (client->GetPlayer()->trade) {
Trade* trade = client->GetPlayer()->trade;
if (trade->GetTradee(client->GetPlayer()) != bot) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are already in a trade.");
return;
}
bot->AddItemToTrade(slot);
}
else {
if (bot->trade) {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Your bot is already trading...");
return;
}
Trade* trade = new Trade(client->GetPlayer(), bot);
client->GetPlayer()->trade = trade;
bot->trade = trade;
bot->AddItemToTrade(slot);
}
}
}
else
Command_Bot(client, sep);
}
else
Command_Bot(client, sep);
}
void Commands::Command_Bot_Settings(Client* client, Seperator* sep) {
if (sep && sep->IsSet(0) && sep->IsSet(1) && sep->IsNumber(1)) {
if (client->GetPlayer()->GetTarget() && client->GetPlayer()->GetTarget()->IsBot()) {
Bot* bot = (Bot*)client->GetPlayer()->GetTarget();
if (bot->GetOwner() == client->GetPlayer()) {
if (strncasecmp("helm", sep->arg[0], 4) == 0) {
bot->ShowHelm = (atoi(sep->arg[1]) == 1) ? true : false;
bot->info_changed = true;
bot->changed = true;
bot->GetZone()->SendSpawnChanges(bot);
}
else if (strncasecmp("cloak", sep->arg[0], 5) == 0) {
bot->ShowCloak = (atoi(sep->arg[1]) == 1) ? true : false;
bot->info_changed = true;
bot->changed = true;
bot->GetZone()->SendSpawnChanges(bot);
}
else if (strncasecmp("taunt", sep->arg[0], 5) == 0) {
bot->CanTaunt = (atoi(sep->arg[1]) == 1) ? true : false;
}
else if (strncasecmp("hood", sep->arg[0], 4) == 0) {
bot->SetHideHood((atoi(sep->arg[0]) == 1) ? 0 : 1);
}
else
Command_Bot(client, sep);
}
else
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You can only change settings on your own bot.");
}
else
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You must target a bot.");
}
else
Command_Bot(client, sep);
}
void Commands::Command_Bot_Help(Client* client, Seperator* sep) {
if (sep && sep->IsSet(0)) {
if (strncasecmp("race", sep->arg[0], 4) == 0) {
string title = "Race ID's";
string details;
details += "0\tBarbarian\n";
details += "1\tDark Elf\n";
details += "2\tDwarf\n";
details += "3\tErudite\n";
details += "4\tFroglok\n";
details += "5\tGnome\n";
details += "6\tHalf Elf\n";
details += "7\tHalfling\n";
details += "8\tHigh Elf\n";
details += "9\tHuman\n";
details += "10\tIksar\n";
details += "11\tKerra\n";
details += "12\tOgre\n";
details += "13\tRatonga\n";
details += "14\tTroll\n";
details += "15\tWood Elf\n";
details += "16\tFae\n";
details += "17\tArasai\n";
details += "18\tSarnak\n";
details += "19\tVampire\n";
details += "20\tAerakyn\n";
client->SendShowBook(client->GetPlayer(), title, 0, 1, details);
return;
}
else if (strncasecmp("class", sep->arg[0], 5) == 0) {
string title = "Class ID's";
string details;
details += "0\tCOMMONER\n";
details += "1\tFIGHTER\n";
details += "2\tWARRIOR\n";
details += "3\tGUARDIAN\n";
details += "4\tBERSERKER\n";
details += "5\tBRAWLER\n";
details += "6\tMONK\n";
details += "7\tBRUISER\n";
details += "8\tCRUSADER\n";
details += "9\tSHADOWKNIGHT\n";
details += "10\tPALADIN\n";
details += "11\tPRIEST\n";
details += "12\tCLERIC\n";
details += "13\tTEMPLAR\n";
details += "14\tINQUISITOR\n";
details += "15\tDRUID\n";
details += "16\tWARDEN\n";
details += "17\tFURY\n";
details += "18\tSHAMAN\n";
details += "19\tMYSTIC\n";
details += "20\tDEFILER\n";
string details2 = "21\tMAGE\n";
details2 += "22\tSORCERER\n";
details2 += "23\tWIZARD\n";
details2 += "24\tWARLOCK\n";
details2 += "25\tENCHANTER\n";
details2 += "26\tILLUSIONIST\n";
details2 += "27\tCOERCER\n";
details2 += "28\tSUMMONER\n";
details2 += "29\tCONJUROR\n";
details2 += "30\tNECROMANCER\n";
details2 += "31\tSCOUT\n";
details2 += "32\tROGUE\n";
details2 += "33\tSWASHBUCKLER\n";
details2 += "34\tBRIGAND\n";
details2 += "35\tBARD\n";
details2 += "36\tTROUBADOR\n";
details2 += "37\tDIRGE\n";
details2 += "38\tPREDATOR\n";
details2 += "39\tRANGER\n";
details2 += "40\tASSASSIN\n";
string details3 = "\\#FF0000Following aren't implemented yet.\\#000000\n";
details3 += "41\tANIMALIST\n";
details3 += "42\tBEASTLORD\n";
details3 += "43\tSHAPER\n";
details3 += "44\tCHANNELER\n";
client->SendShowBook(client->GetPlayer(), title, 0, 3, details, details2, details3);
return;
}
}
else {
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Bot help is WIP.");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot help race - race id list");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/bot help class - class id list");
}
}

View File

@ -0,0 +1,467 @@
#include "../WorldDatabase.h"
#include "../../common/Log.h"
#include "Bot.h"
#include "../classes.h"
#include "../races.h"
extern Classes classes;
extern Races races;
int32 WorldDatabase::CreateNewBot(int32 char_id, string name, int8 race, int8 advClass, int8 gender, int16 model_id, int32& index) {
DatabaseResult result;
index = 0;
if (!database_new.Select(&result, "SELECT MAX(`bot_id`) FROM `bots` WHERE `char_id` = %u", char_id)) {
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
return 0;
}
if (result.Next()) {
if (result.IsNull(0))
index = 1;
else
index = result.GetInt32(0) + 1;
}
if (!database_new.Query("INSERT INTO `bots` (`char_id`, `bot_id`, `name`, `race`, `class`, `gender`, `model_type`) VALUES (%u, %u, \"%s\", %u, %u, %u, %u)", char_id, index, name.c_str(), race, advClass, gender, model_id)) {
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
return 0;
}
int32 ret = database_new.LastInsertID();
LogWrite(PLAYER__DEBUG, 0, "Player", "New bot (%s) created for player (%u)", name.c_str(), char_id);
return ret;
}
void WorldDatabase::SaveBotAppearance(Bot* bot) {
SaveBotColors(bot->BotID, "skin_color", bot->features.skin_color);
SaveBotColors(bot->BotID, "model_color", bot->features.model_color);
SaveBotColors(bot->BotID, "eye_color", bot->features.eye_color);
SaveBotColors(bot->BotID, "hair_color1", bot->features.hair_color1);
SaveBotColors(bot->BotID, "hair_color2", bot->features.hair_color2);
SaveBotColors(bot->BotID, "hair_highlight", bot->features.hair_highlight_color);
SaveBotColors(bot->BotID, "hair_type_color", bot->features.hair_type_color);
SaveBotColors(bot->BotID, "hair_type_highlight_color", bot->features.hair_type_highlight_color);
SaveBotColors(bot->BotID, "hair_face_color", bot->features.hair_face_color);
SaveBotColors(bot->BotID, "hair_face_highlight_color", bot->features.hair_face_highlight_color);
SaveBotColors(bot->BotID, "wing_color1", bot->features.wing_color1);
SaveBotColors(bot->BotID, "wing_color2", bot->features.wing_color2);
SaveBotColors(bot->BotID, "shirt_color", bot->features.shirt_color);
//SaveBotColors(bot->BotID, "unknown_chest_color", );
SaveBotColors(bot->BotID, "pants_color", bot->features.pants_color);
//SaveBotColors(bot->BotID, "unknown_legs_color", );
//SaveBotColors(bot->BotID, "unknown9", );
SaveBotFloats(bot->BotID, "eye_type", bot->features.eye_type[0], bot->features.eye_type[1], bot->features.eye_type[2]);
SaveBotFloats(bot->BotID, "ear_type", bot->features.ear_type[0], bot->features.ear_type[1], bot->features.ear_type[2]);
SaveBotFloats(bot->BotID, "eye_brow_type", bot->features.eye_brow_type[0], bot->features.eye_brow_type[1], bot->features.eye_brow_type[2]);
SaveBotFloats(bot->BotID, "cheek_type", bot->features.cheek_type[0], bot->features.cheek_type[1], bot->features.cheek_type[2]);
SaveBotFloats(bot->BotID, "lip_type", bot->features.lip_type[0], bot->features.lip_type[1], bot->features.lip_type[2]);
SaveBotFloats(bot->BotID, "chin_type", bot->features.chin_type[0], bot->features.chin_type[1], bot->features.chin_type[2]);
SaveBotFloats(bot->BotID, "nose_type", bot->features.nose_type[0], bot->features.nose_type[1], bot->features.nose_type[2]);
SaveBotFloats(bot->BotID, "body_size", bot->features.body_size, 0, 0);
SaveBotFloats(bot->BotID, "body_age", bot->features.body_age, 0, 0);
SaveBotColors(bot->BotID, "soga_skin_color", bot->features.soga_skin_color);
SaveBotColors(bot->BotID, "soga_model_color", bot->features.soga_model_color);
SaveBotColors(bot->BotID, "soga_eye_color", bot->features.soga_eye_color);
SaveBotColors(bot->BotID, "soga_hair_color1", bot->features.soga_hair_color1);
SaveBotColors(bot->BotID, "soga_hair_color2", bot->features.soga_hair_color2);
SaveBotColors(bot->BotID, "soga_hair_highlight", bot->features.soga_hair_highlight_color);
SaveBotColors(bot->BotID, "soga_hair_type_color", bot->features.soga_hair_type_color);
SaveBotColors(bot->BotID, "soga_hair_type_highlight_color", bot->features.soga_hair_type_highlight_color);
SaveBotColors(bot->BotID, "soga_hair_face_color", bot->features.soga_hair_face_color);
SaveBotColors(bot->BotID, "soga_hair_face_highlight_color", bot->features.soga_hair_face_highlight_color);
SaveBotColors(bot->BotID, "soga_wing_color1", bot->features.wing_color1);
SaveBotColors(bot->BotID, "soga_wing_color2", bot->features.wing_color2);
SaveBotColors(bot->BotID, "soga_shirt_color", bot->features.shirt_color);
//SaveBotColors(bot->BotID, "soga_unknown_chest_color", );
SaveBotColors(bot->BotID, "soga_pants_color", bot->features.pants_color);
//SaveBotColors(bot->BotID, "soga_unknown_legs_color", );
//SaveBotColors(bot->BotID, "soga_unknown13", );
SaveBotFloats(bot->BotID, "soga_eye_type", bot->features.soga_eye_type[0], bot->features.soga_eye_type[1], bot->features.soga_eye_type[2]);
SaveBotFloats(bot->BotID, "soga_ear_type", bot->features.soga_ear_type[0], bot->features.soga_ear_type[1], bot->features.soga_ear_type[2]);
SaveBotFloats(bot->BotID, "soga_eye_brow_type", bot->features.soga_eye_brow_type[0], bot->features.soga_eye_brow_type[1], bot->features.soga_eye_brow_type[2]);
SaveBotFloats(bot->BotID, "soga_cheek_type", bot->features.soga_cheek_type[0], bot->features.soga_cheek_type[1], bot->features.soga_cheek_type[2]);
SaveBotFloats(bot->BotID, "soga_lip_type", bot->features.soga_lip_type[0], bot->features.soga_lip_type[1], bot->features.soga_lip_type[2]);
SaveBotFloats(bot->BotID, "soga_chin_type", bot->features.soga_chin_type[0], bot->features.soga_chin_type[1], bot->features.soga_chin_type[2]);
SaveBotFloats(bot->BotID, "soga_nose_type", bot->features.soga_nose_type[0], bot->features.soga_nose_type[1], bot->features.soga_nose_type[2]);
if (!database_new.Query("UPDATE `bots` SET `model_type` = %u, `hair_type` = %u, `face_type` = %u, `wing_type` = %u, `chest_type` = %u, `legs_type` = %u, `soga_model_type` = %u, `soga_hair_type` = %u, `soga_face_type` = %u WHERE `id` = %u",
bot->GetModelType(), bot->GetHairType(), bot->GetFacialHairType(), bot->GetWingType(), bot->GetChestType(), bot->GetLegsType(), bot->GetSogaModelType(), bot->GetSogaHairType(), bot->GetSogaFacialHairType(), bot->BotID)) {
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
return;
}
}
void WorldDatabase::SaveBotColors(int32 bot_id, const char* type, EQ2_Color color) {
if (!database_new.Query("INSERT INTO `bot_appearance` (`bot_id`, `type`, `red`, `green`, `blue`) VALUES (%i, '%s', %i, %i, %i) ON DUPLICATE KEY UPDATE `red` = %i, `blue` = %i, `green` = %i", bot_id, type, color.red, color.green, color.blue, color.red, color.blue, color.green)) {
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
return;
}
}
void WorldDatabase::SaveBotFloats(int32 bot_id, const char* type, float float1, float float2, float float3) {
if (!database_new.Query("INSERT INTO `bot_appearance` (`bot_id`, `type`, `red`, `green`, `blue`, `signed_value`) VALUES (%i, '%s', %i, %i, %i, 1) ON DUPLICATE KEY UPDATE `red` = %i, `blue` = %i, `green` = %i", bot_id, type, float1, float2, float3, float1, float2, float3)) {
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
return;
}
}
bool WorldDatabase::LoadBot(int32 char_id, int32 bot_index, Bot* bot) {
DatabaseResult result;
if (!database_new.Select(&result, "SELECT * FROM bots WHERE `char_id` = %u AND `bot_id` = %u", char_id, bot_index)) {
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
return false;
}
if (result.Next()) {
bot->BotID = result.GetInt32(0);
bot->BotIndex = result.GetInt32(2);
bot->SetName(result.GetString(3));
bot->SetRace(result.GetInt8(4));
bot->SetAdventureClass(result.GetInt8(5));
bot->SetGender(result.GetInt8(6));
bot->SetModelType(result.GetInt16(7));
bot->SetHairType(result.GetInt16(8));
bot->SetFacialHairType(result.GetInt16(9));
bot->SetWingType(result.GetInt16(10));
bot->SetChestType(result.GetInt16(11));
bot->SetLegsType(result.GetInt16(12));
bot->SetSogaModelType(result.GetInt16(13));
bot->SetSogaHairType(result.GetInt16(14));
bot->SetSogaFacialHairType(result.GetInt16(15));
}
else
return false;
LoadBotAppearance(bot);
LoadBotEquipment(bot);
return true;
}
void WorldDatabase::LoadBotAppearance(Bot* bot) {
DatabaseResult result;
string type;
map<string, int8> appearance_types;
EQ2_Color color;
color.red = 0;
color.green = 0;
color.blue = 0;
if (!database_new.Select(&result, "SELECT distinct `type` FROM bot_appearance WHERE length(`type`) > 0 AND `bot_id` = %u", bot->BotID)) {
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
return;
}
while (result.Next()) {
type = result.GetString(0);
appearance_types[type] = GetAppearanceType(type);
if (appearance_types[type] == 255)
LogWrite(WORLD__ERROR, 0, "Appearance", "Unknown appearance type '%s' in LoadBotAppearances.", type.c_str());
}
if (!database_new.Select(&result, "SELECT `type`, `signed_value`, `red`, `green`, `blue` FROM bot_appearance WHERE length(`type`) > 0 AND bot_id = %u", bot->BotID)) {
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
return;
}
while (result.Next()) {
type = result.GetString(0);
if (appearance_types[type] < APPEARANCE_SOGA_EBT) {
color.red = result.GetInt8(2);
color.green = result.GetInt8(3);
color.blue = result.GetInt8(4);
}
switch (appearance_types[type]) {
case APPEARANCE_SOGA_HFHC: {
bot->features.soga_hair_face_highlight_color = color;
break;
}
case APPEARANCE_SOGA_HTHC: {
bot->features.soga_hair_type_highlight_color = color;
break;
}
case APPEARANCE_SOGA_HFC: {
bot->features.soga_hair_face_color = color;
break;
}
case APPEARANCE_SOGA_HTC: {
bot->features.soga_hair_type_color = color;
break;
}
case APPEARANCE_SOGA_HH: {
bot->features.soga_hair_highlight_color = color;
break;
}
case APPEARANCE_SOGA_HC1: {
bot->features.soga_hair_color1 = color;
break;
}
case APPEARANCE_SOGA_HC2: {
bot->features.soga_hair_color2 = color;
break;
}
case APPEARANCE_SOGA_SC: {
bot->features.soga_skin_color = color;
break;
}
case APPEARANCE_SOGA_EC: {
bot->features.soga_eye_color = color;
break;
}
case APPEARANCE_HTHC: {
bot->features.hair_type_highlight_color = color;
break;
}
case APPEARANCE_HFHC: {
bot->features.hair_face_highlight_color = color;
break;
}
case APPEARANCE_HTC: {
bot->features.hair_type_color = color;
break;
}
case APPEARANCE_HFC: {
bot->features.hair_face_color = color;
break;
}
case APPEARANCE_HH: {
bot->features.hair_highlight_color = color;
break;
}
case APPEARANCE_HC1: {
bot->features.hair_color1 = color;
break;
}
case APPEARANCE_HC2: {
bot->features.hair_color2 = color;
break;
}
case APPEARANCE_WC1: {
bot->features.wing_color1 = color;
break;
}
case APPEARANCE_WC2: {
bot->features.wing_color2 = color;
break;
}
case APPEARANCE_SC: {
bot->features.skin_color = color;
break;
}
case APPEARANCE_EC: {
bot->features.eye_color = color;
break;
}
case APPEARANCE_SOGA_EBT: {
for (int i = 0; i < 3; i++)
bot->features.soga_eye_brow_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_SOGA_CHEEKT: {
for (int i = 0; i < 3; i++)
bot->features.soga_cheek_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_SOGA_NT: {
for (int i = 0; i < 3; i++)
bot->features.soga_nose_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_SOGA_CHINT: {
for (int i = 0; i < 3; i++)
bot->features.soga_chin_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_SOGA_LT: {
for (int i = 0; i < 3; i++)
bot->features.soga_lip_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_SOGA_EART: {
for (int i = 0; i < 3; i++)
bot->features.soga_ear_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_SOGA_EYET: {
for (int i = 0; i < 3; i++)
bot->features.soga_eye_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_EBT: {
for (int i = 0; i < 3; i++)
bot->features.eye_brow_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_CHEEKT: {
for (int i = 0; i < 3; i++)
bot->features.cheek_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_NT: {
for (int i = 0; i < 3; i++)
bot->features.nose_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_CHINT: {
for (int i = 0; i < 3; i++)
bot->features.chin_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_EART: {
for (int i = 0; i < 3; i++)
bot->features.ear_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_EYET: {
for (int i = 0; i < 3; i++)
bot->features.eye_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_LT: {
for (int i = 0; i < 3; i++)
bot->features.lip_type[i] = result.GetSInt8(2 + i);
break;
}
case APPEARANCE_SHIRT: {
bot->features.shirt_color = color;
break;
}
case APPEARANCE_UCC: {
break;
}
case APPEARANCE_PANTS: {
bot->features.pants_color = color;
break;
}
case APPEARANCE_ULC: {
break;
}
case APPEARANCE_U9: {
break;
}
case APPEARANCE_BODY_SIZE: {
bot->features.body_size = color.red;
break;
}
case APPEARANCE_SOGA_WC1: {
break;
}
case APPEARANCE_SOGA_WC2: {
break;
}
case APPEARANCE_SOGA_SHIRT: {
break;
}
case APPEARANCE_SOGA_UCC: {
break;
}
case APPEARANCE_SOGA_PANTS: {
break;
}
case APPEARANCE_SOGA_ULC: {
break;
}
case APPEARANCE_SOGA_U13: {
break;
}
case APPEARANCE_BODY_AGE: {
bot->features.body_age = color.red;
break;
}
case APPEARANCE_MC:{
bot->features.model_color = color;
break;
}
case APPEARANCE_SMC:{
bot->features.soga_model_color = color;
break;
}
case APPEARANCE_SBS: {
bot->features.soga_body_size = color.red;
break;
}
case APPEARANCE_SBA: {
bot->features.soga_body_age = color.red;
break;
}
}
}
}
void WorldDatabase::SaveBotItem(int32 bot_id, int32 item_id, int8 slot) {
if (!database_new.Query("INSERT INTO `bot_equipment` (`bot_id`, `slot`, `item_id`) VALUES (%u, %u, %u) ON DUPLICATE KEY UPDATE `item_id` = %u", bot_id, slot, item_id, item_id)) {
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
return;
}
}
void WorldDatabase::LoadBotEquipment(Bot* bot) {
DatabaseResult result;
if (!database_new.Select(&result, "SELECT `slot`, `item_id` FROM `bot_equipment` WHERE `bot_id` = %u", bot->BotID)) {
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
return;
}
Item* master_item = 0;
Item* item = 0;
while (result.Next()) {
int8 slot = result.GetInt8(0);
int32 item_id = result.GetInt32(1);
master_item = master_item_list.GetItem(item_id);
if (master_item) {
item = new Item(master_item);
if (item) {
bot->GetEquipmentList()->AddItem(slot, item);
bot->SetEquipment(item, slot);
}
}
}
}
string WorldDatabase::GetBotList(int32 char_id) {
DatabaseResult result;
string ret;
if (!database_new.Select(&result, "SELECT `bot_id`, `name`, `race`, `class` FROM `bots` WHERE `char_id` = %u", char_id)) {
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
return ret;
}
while (result.Next()) {
ret += to_string(result.GetInt32(0)) + ": ";
ret += result.GetString(1);
ret += " the ";
ret += races.GetRaceNameCase(result.GetInt8(2));
ret += " ";
ret += classes.GetClassNameCase(result.GetInt8(3)) + "\n";
}
return ret;
}
void WorldDatabase::DeleteBot(int32 char_id, int32 bot_index) {
if (!database_new.Query("DELETE FROM `bots` WHERE `char_id` = %u AND `bot_id` = %u", char_id, bot_index)) {
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
}
}
void WorldDatabase::SetBotStartingItems(Bot* bot, int8 class_id, int8 race_id) {
int32 bot_id = bot->BotID;
LogWrite(PLAYER__DEBUG, 0, "Bot", "Adding default items for race: %u, class: %u for bot_id: %u", race_id, class_id, bot_id);
DatabaseResult result;
if (!database_new.Select(&result, "SELECT item_id FROM starting_items WHERE class_id IN (%i, %i, %i, 255) AND race_id IN (%i, 255) ORDER BY id", classes.GetBaseClass(class_id), classes.GetSecondaryBaseClass(class_id), class_id, race_id)) {
LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
return;
}
while (result.Next()) {
bot->GiveItem(result.GetInt32(0));
}
}

View File

@ -0,0 +1,372 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Chat.h"
#include "../../common/Log.h"
#include "../../common/ConfigReader.h"
#include "../../common/PacketStruct.h"
#include "../Rules/Rules.h"
extern RuleManager rule_manager;
//devn00b
#ifdef DISCORD
#ifndef WIN32
#include <dpp/dpp.h>
#include "ChatChannel.h"
extern ChatChannel channel;
#endif
#endif
extern ConfigReader configReader;
Chat::Chat() {
m_channels.SetName("Chat::Channels");
}
Chat::~Chat() {
vector<ChatChannel *>::iterator itr;
m_channels.writelock(__FUNCTION__, __LINE__);
for (itr = channels.begin(); itr != channels.end(); itr++)
safe_delete(*itr);
m_channels.releasewritelock(__FUNCTION__, __LINE__);
}
void Chat::AddChannel(ChatChannel *channel) {
m_channels.writelock(__FUNCTION__, __LINE__);
channels.push_back(channel);
m_channels.releasewritelock(__FUNCTION__, __LINE__);
}
unsigned int Chat::GetNumChannels() {
unsigned int ret;
m_channels.readlock(__FUNCTION__, __LINE__);
ret = (unsigned int)channels.size();
m_channels.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
EQ2Packet * Chat::GetWorldChannelList(Client *client) {
PacketStruct *packet_struct = configReader.getStruct("WS_AvailWorldChannels", client->GetVersion());
Player *player = client->GetPlayer();
vector<ChatChannel *> channels_to_send;
vector<ChatChannel *>::iterator itr;
ChatChannel *channel;
EQ2Packet *packet;
int32 i = 0;
bool add;
if (packet_struct == NULL) {
LogWrite(CHAT__ERROR, 0, "Chat", "Could not find packet 'WS_AvailWorldChannels' for client %s on version %i\n", player->GetName(), client->GetVersion());
return NULL;
}
m_channels.readlock(__FUNCTION__, __LINE__);
for (itr = channels.begin(); itr != channels.end(); itr++) {
channel = *itr;
if (channel->GetType() == CHAT_CHANNEL_TYPE_WORLD) {
add = true;
if (add && !channel->CanJoinChannelByLevel(player->GetLevel()))
add = false;
if (add && !channel->CanJoinChannelByRace(player->GetRace()))
add = false;
if (add && !channel->CanJoinChannelByClass(player->GetAdventureClass()))
add = false;
if (add)
channels_to_send.push_back(channel);
}
}
m_channels.releasereadlock(__FUNCTION__, __LINE__);
packet_struct->setArrayLengthByName("num_channels", channels_to_send.size());
for (itr = channels_to_send.begin(); itr != channels_to_send.end(); itr++, i++) {
packet_struct->setArrayDataByName("channel_name", (*itr)->GetName(), i);
packet_struct->setArrayDataByName("unknown", 0, i);
}
packet = packet_struct->serialize();
safe_delete(packet_struct);
return packet;
}
bool Chat::ChannelExists(const char *channel_name) {
vector<ChatChannel *>::iterator itr;
bool ret = false;
m_channels.readlock(__FUNCTION__, __LINE__);
for (itr = channels.begin(); itr != channels.end(); itr++) {
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
ret = true;
break;
}
}
m_channels.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
bool Chat::HasPassword(const char *channel_name) {
vector<ChatChannel *>::iterator itr;
bool ret = false;
m_channels.readlock(__FUNCTION__, __LINE__);
for (itr = channels.begin(); itr != channels.end(); itr++) {
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
ret = (*itr)->HasPassword();
break;
}
}
m_channels.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
bool Chat::PasswordMatches(const char *channel_name, const char *password) {
vector<ChatChannel *>::iterator itr;
bool ret = false;
m_channels.readlock(__FUNCTION__, __LINE__);
for (itr = channels.begin(); itr != channels.end(); itr++) {
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
ret = (*itr)->PasswordMatches(password);
break;
}
}
m_channels.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
bool Chat::CreateChannel(const char *channel_name) {
return CreateChannel(channel_name, NULL);
}
bool Chat::CreateChannel(const char *channel_name, const char *password) {
LogWrite(CHAT__DEBUG, 0, "Chat", "Channel %s being created", channel_name);
ChatChannel *channel = new ChatChannel();
channel->SetName(channel_name);
channel->SetType(CHAT_CHANNEL_TYPE_CUSTOM);
if (password != NULL)
channel->SetPassword(password);
m_channels.writelock(__FUNCTION__, __LINE__);
channels.push_back(channel);
m_channels.releasewritelock(__FUNCTION__, __LINE__);
return true;
}
bool Chat::IsInChannel(Client *client, const char *channel_name) {
vector<ChatChannel *>::iterator itr;
bool ret = false;
m_channels.readlock(__FUNCTION__, __LINE__);
for (itr = channels.begin(); itr != channels.end(); itr++) {
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
ret = (*itr)->IsInChannel(client->GetCharacterID());
break;
}
}
m_channels.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
bool Chat::JoinChannel(Client *client, const char *channel_name) {
vector<ChatChannel *>::iterator itr;
bool ret = false;
LogWrite(CHAT__DEBUG, 1, "Chat", "Client %s is joining channel %s", client->GetPlayer()->GetName(), channel_name);
m_channels.writelock(__FUNCTION__, __LINE__);
for (itr = channels.begin(); itr != channels.end(); itr++) {
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
ret = (*itr)->JoinChannel(client);
break;
}
}
m_channels.releasewritelock(__FUNCTION__, __LINE__);
return ret;
}
bool Chat::LeaveChannel(Client *client, const char *channel_name) {
vector<ChatChannel *>::iterator itr;
bool ret = false;
LogWrite(CHAT__DEBUG, 1, "Chat", "Client %s is leaving channel %s", client->GetPlayer()->GetName(), channel_name);
m_channels.writelock(__FUNCTION__, __LINE__);
for (itr = channels.begin(); itr != channels.end(); itr++) {
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
ret = (*itr)->LeaveChannel(client);
if ((*itr)->GetType() == CHAT_CHANNEL_TYPE_CUSTOM && (*itr)->GetNumClients() == 0) {
LogWrite(CHAT__DEBUG, 0, "Chat", "Custom channel %s has 0 clients left, deleting channel", channel_name);
safe_delete(*itr);
channels.erase(itr);
}
break;
}
}
m_channels.releasewritelock(__FUNCTION__, __LINE__);
return ret;
}
bool Chat::LeaveAllChannels(Client *client) {
vector<ChatChannel *>::iterator itr;
ChatChannel *channel;
bool erased;
m_channels.writelock(__FUNCTION__, __LINE__);
itr = channels.begin();
while (itr != channels.end()) {
channel = *itr;
erased = false;
if (channel->IsInChannel(client->GetCharacterID())) {
LogWrite(CHAT__DEBUG, 1, "Chat", "Client %s is leaving channel %s", client->GetPlayer()->GetName(), channel->GetName());
channel->LeaveChannel(client);
if (channel->GetType() == CHAT_CHANNEL_TYPE_CUSTOM && channel->GetNumClients() == 0) {
LogWrite(CHAT__DEBUG, 0, "Chat", "Custom channel %s has 0 clients left, deleting channel", channel->GetName());
safe_delete(*itr);
itr = channels.erase(itr);
erased = true;
}
}
if (!erased)
itr++;
}
m_channels.releasewritelock(__FUNCTION__, __LINE__);
return true;
}
bool Chat::TellChannel(Client *client, const char *channel_name, const char *message, const char* name) {
vector<ChatChannel *>::iterator itr;
bool ret = false;
bool enablediscord = rule_manager.GetGlobalRule(R_Discord, DiscordEnabled)->GetBool();
const char* discordchan = rule_manager.GetGlobalRule(R_Discord, DiscordChannel)->GetString();
m_channels.readlock(__FUNCTION__, __LINE__);
for (itr = channels.begin(); itr != channels.end(); itr++) {
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
if (client && name)
ret = (*itr)->TellChannelClient(client, message, name);
else
ret = (*itr)->TellChannel(client, message, name);
if(enablediscord == true && client){
if (strcmp(channel_name, discordchan) != 0){
m_channels.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
#ifdef DISCORD
if (client) {
std::string whofrom = client->GetPlayer()->GetName();
std::string msg = string(message);
ret = PushDiscordMsg(msg.c_str(), whofrom.c_str());
}
#endif
}
break;
}
}
m_channels.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
bool Chat::SendChannelUserList(Client *client, const char *channel_name) {
vector<ChatChannel *>::iterator itr;
bool ret = false;
m_channels.readlock(__FUNCTION__, __LINE__);
for (itr = channels.begin(); itr != channels.end(); itr++) {
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
ret = (*itr)->SendChannelUserList(client);
break;
}
}
m_channels.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
ChatChannel* Chat::GetChannel(const char *channel_name) {
vector<ChatChannel *>::iterator itr;
ChatChannel* ret = 0;
m_channels.readlock(__FUNCTION__, __LINE__);
for (itr = channels.begin(); itr != channels.end(); itr++) {
if (strncasecmp(channel_name, (*itr)->GetName(), CHAT_CHANNEL_MAX_NAME) == 0) {
ret = (*itr);
break;
}
}
m_channels.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
#ifdef DISCORD
//this sends chat from EQ2EMu to Discord. Currently using webhooks. Makes things simpler code wise.
int Chat::PushDiscordMsg(const char* msg, const char* from) {
bool enablediscord = rule_manager.GetGlobalRule(R_Discord, DiscordEnabled)->GetBool();
if(enablediscord == false) {
LogWrite(INIT__INFO, 0,"Discord","Bot Disabled By Rule...");
return 0;
}
m_channels.readlock(__FUNCTION__, __LINE__);
const char* hook = rule_manager.GetGlobalRule(R_Discord, DiscordWebhookURL)->GetString();
std::string servername = net.GetWorldName();
char ourmsg[4096];
//form our message
sprintf(ourmsg,"[%s] [%s] Says: %s",from, servername.c_str(), msg);
/* send a message with this webhook */
dpp::cluster bot("");
dpp::webhook wh(hook);
bot.execute_webhook(wh, dpp::message(ourmsg));
m_channels.releasereadlock(__FUNCTION__, __LINE__);
return 1;
}
#endif

View File

@ -0,0 +1,119 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHAT_CHAT_H_
#define CHAT_CHAT_H_
#include <vector>
#include "../../common/types.h"
#include "../../common/EQPacket.h"
#include "../../common/Mutex.h"
#include "../client.h"
#include "ChatChannel.h"
#ifdef DISCORD
#ifndef WIN32
#pragma once
#include <dpp/dpp.h>
#endif
#endif
using namespace std;
/*
CREATING A CHANNEL
-- OP_RemoteCmdMsg --
3/14/2012 20:17:06
192.168.1.198 -> 69.174.200.73
0000: 00 09 05 9A 2A 0E 00 0F 00 63 75 73 74 6F 6D 20 ....*....custom
0010 70 61 73 73 77 6F 72 64 password
TALKING IN A CHANNEL
[11:52.23] <@Xinux> -- OP_RemoteCmdMsg --
[11:52.23] <@Xinux> 3/14/2012 20:17:25
[11:52.23] <@Xinux> 192.168.1.198 -> 69.174.200.73
[11:52.23] <@Xinux> 0000: 00 09 06 2D 2A 11 00 21 00 63 75 73 74 6F 6D 20 ...-*..!.custom
[11:52.23] <@Xinux> 0010: 20 74 68 69 73 20 69 73 20 6D 79 20 63 75 73 74 this is my cust
[11:52.23] <@Xinux> 0020 6F 6D 20 63 68 61 6E 6E 65 6C om channel
[08:37.46] <@Xinux_Work> 00 09 05 8B 00 3A 53 00 00 00 FF 3C 02 00 00 FF .....:S....<....
[08:37.46] <@Xinux_Work> FF FF FF FF FF FF FF 06 00 4C 65 69 68 69 61 07 .........Leihia.
[08:37.46] <@Xinux_Work> 00 4B 6F 65 63 68 6F 68 00 02 00 00 00 00 01 00 .Koechoh........
[08:37.46] <@Xinux_Work> 00 00 22 00 18 00 62 65 74 74 65 72 20 74 68 61 .."...better tha
[08:37.46] <@Xinux_Work> 6E 20 61 20 72 65 64 20 6F 6E 65 20 3A 50 09 00 n a red one :P..
[08:37.46] <@Xinux_Work> 4C 65 76 65 6C 5F 31 2D 39 01 01 00 00 Level_1-9....
OTHERS LEAVING AND JOINING A CHANNEL
-- OP_ClientCmdMsg::OP_EqChatChannelUpdateCmd --
3/14/2012 20:17:06
69.174.200.73 -> 192.168.1.198
0000: 00 3A 18 00 00 00 FF 88 02 03 09 00 4C 65 76 65 .:..........Leve
0010 6C 5F 31 2D 39 07 00 53 68 61 77 6E 61 68 l_1-9..Shawnah
-- OP_ClientCmdMsg::OP_EqChatChannelUpdateCmd --
3/14/2012 20:17:06
69.174.200.73 -> 192.168.1.198
0000: 00 3A 16 00 00 00 FF 88 02 03 07 00 41 75 63 74 .:..........Auct
0010 69 6F 6E 07 00 53 68 61 77 6E 61 68 ion..Shawnah
OP_EqChatChannelUpdateCmd
unknown=0 unknown1=blank join
unknown=1 unknown1=blank leave
unknown=2 unknown2=player join/leave?
unknown=3 unknown2=player join/leave?
*/
class Chat{
public:
Chat();
virtual ~Chat();
void AddChannel(ChatChannel *channel);
unsigned int GetNumChannels();
EQ2Packet * GetWorldChannelList(Client *client);
bool ChannelExists(const char *channel_name);
bool HasPassword(const char *channel_name);
bool PasswordMatches(const char *channel_name, const char *password);
bool CreateChannel(const char *channel_name);
bool CreateChannel(const char *channel_name, const char *password);
bool IsInChannel(Client *client, const char *channel_name);
bool JoinChannel(Client *client, const char *channel_name);
bool LeaveChannel(Client *client, const char *channel_name);
bool LeaveAllChannels(Client *client);
bool TellChannel(Client *client, const char *channel_name, const char *message, const char* name = 0);
bool SendChannelUserList(Client *client, const char *channel_name);
//devn00b
int PushDiscordMsg(const char*, const char*);
ChatChannel* GetChannel(const char* channel_name);
private:
Mutex m_channels;
vector<ChatChannel *> channels;
};
#endif

View File

@ -0,0 +1,227 @@
#include <string.h>
#include "../../common/Log.h"
#include "../../common/ConfigReader.h"
#include "../../common/PacketStruct.h"
#include "../World.h"
#include "ChatChannel.h"
extern ConfigReader configReader;
extern ZoneList zone_list;
#define CHAT_CHANNEL_JOIN 0
#define CHAT_CHANNEL_LEAVE 1
#define CHAT_CHANNEL_OTHER_JOIN 2
#define CHAT_CHANNEL_OTHER_LEAVE 3
ChatChannel::ChatChannel() {
memset(name, 0, sizeof(name));
memset(password, 0, sizeof(password));
type = CHAT_CHANNEL_TYPE_NONE;
level_restriction = 0;
races = 0;
classes = 0;
}
ChatChannel::~ChatChannel() {
}
bool ChatChannel::IsInChannel(int32 character_id) {
vector<int32>::iterator itr;
for (itr = clients.begin(); itr != clients.end(); itr++) {
if (character_id == *itr)
return true;
}
return false;
}
bool ChatChannel::JoinChannel(Client *client) {
PacketStruct *packet_struct;
vector<int32>::iterator itr;
Client *to_client;
//send the player join packet to the joining client
if ((packet_struct = configReader.getStruct("WS_ChatChannelUpdate", client->GetVersion())) == NULL) {
LogWrite(CHAT__ERROR, 0, "Chat", "Could not find packet 'WS_ChatChannelUpdate' when client %s was trying to join channel %s", client->GetPlayer()->GetName(), name);
return false;
}
packet_struct->setDataByName("action", CHAT_CHANNEL_JOIN);
packet_struct->setDataByName("channel_name", name);
client->QueuePacket(packet_struct->serialize());
safe_delete(packet_struct);
clients.push_back(client->GetCharacterID());
//loop through everyone else in the channel and send the "other" player join packet
for (itr = clients.begin(); itr != clients.end(); itr++) {
if (client->GetCharacterID() == *itr)
continue;
if ((to_client = zone_list.GetClientByCharID(*itr)) == NULL)
continue;
if ((packet_struct = configReader.getStruct("WS_ChatChannelUpdate", to_client->GetVersion())) == NULL)
continue;
packet_struct->setDataByName("action", CHAT_CHANNEL_OTHER_JOIN);
packet_struct->setDataByName("channel_name", name);
packet_struct->setDataByName("player_name", client->GetPlayer()->GetName());
to_client->QueuePacket(packet_struct->serialize());
safe_delete(packet_struct);
}
return true;
}
bool ChatChannel::LeaveChannel(Client *client) {
vector<int32>::iterator itr;
PacketStruct *packet_struct;
Client *to_client;
bool ret = false;
for (itr = clients.begin(); itr != clients.end(); itr++) {
if (client->GetCharacterID() == *itr) {
clients.erase(itr);
ret = true;
break;
}
}
if (ret) {
//send the packet to the leaving client
if ((packet_struct = configReader.getStruct("WS_ChatChannelUpdate", client->GetVersion())) == NULL)
return false;
packet_struct->setDataByName("action", CHAT_CHANNEL_LEAVE);
packet_struct->setDataByName("channel_name", name);
client->QueuePacket(packet_struct->serialize());
safe_delete(packet_struct);
//send the leave packet to all other clients in the channel
for (itr = clients.begin(); itr != clients.end(); itr++) {
if ((to_client = zone_list.GetClientByCharID(*itr)) == NULL)
continue;
if (to_client == client) // don't need to send to self.
continue;
if ((packet_struct = configReader.getStruct("WS_ChatChannelUpdate", to_client->GetVersion())) == NULL)
continue;
packet_struct->setDataByName("action", CHAT_CHANNEL_OTHER_LEAVE);
packet_struct->setDataByName("channel_name", name);
packet_struct->setDataByName("player_name", client->GetPlayer()->GetName());
to_client->QueuePacket(packet_struct->serialize());
safe_delete(packet_struct);
}
}
return ret;
}
bool ChatChannel::TellChannel(Client *client, const char *message, const char* name2) {
vector<int32>::iterator itr;
PacketStruct *packet_struct;
Client *to_client;
for (itr = clients.begin(); itr != clients.end(); itr++) {
if ((to_client = zone_list.GetClientByCharID(*itr)) == NULL)
continue;
if ((packet_struct = configReader.getStruct("WS_HearChat", to_client->GetVersion())) == NULL)
continue;
packet_struct->setDataByName("unknown", 0);
packet_struct->setDataByName("from_spawn_id", 0xFFFFFFFF);
packet_struct->setDataByName("to_spawn_id", 0xFFFFFFFF);
if (client != NULL){
packet_struct->setDataByName("from", client->GetPlayer()->GetName());
} else {
char name3[128];
sprintf(name3,"[%s] from discord",name2);
packet_struct->setDataByName("from", name3);
}
packet_struct->setDataByName("to", to_client->GetPlayer()->GetName());
packet_struct->setDataByName("channel", to_client->GetMessageChannelColor(CHANNEL_CUSTOM_CHANNEL));
if(client != NULL){
packet_struct->setDataByName("language", client->GetPlayer()->GetCurrentLanguage());
}else{
packet_struct->setDataByName("language", 0);
}
packet_struct->setDataByName("message", message);
packet_struct->setDataByName("channel_name", name);
packet_struct->setDataByName("show_bubble", 1);
if(client != NULL){
if (client->GetPlayer()->GetCurrentLanguage() == 0 || to_client->GetPlayer()->HasLanguage(client->GetPlayer()->GetCurrentLanguage())) {
packet_struct->setDataByName("understood", 1);
}
} else {
packet_struct->setDataByName("understood", 1);
}
packet_struct->setDataByName("unknown4", 0);
to_client->QueuePacket(packet_struct->serialize());
safe_delete(packet_struct);
}
return true;
}
bool ChatChannel::TellChannelClient(Client* to_client, const char* message, const char* name2) {
PacketStruct *packet_struct;
if (string(name2).find('[') != string::npos)
return true;
packet_struct = configReader.getStruct("WS_HearChat", to_client->GetVersion());
if (packet_struct) {
packet_struct->setDataByName("unknown", 0);
packet_struct->setDataByName("from_spawn_id", 0xFFFFFFFF);
packet_struct->setDataByName("to_spawn_id", 0xFFFFFFFF);
packet_struct->setDataByName("from", name2);
packet_struct->setDataByName("to", to_client->GetPlayer()->GetName());
packet_struct->setDataByName("channel", to_client->GetMessageChannelColor(CHANNEL_CUSTOM_CHANNEL));
packet_struct->setDataByName("language", 0);
packet_struct->setDataByName("message", message);
packet_struct->setDataByName("channel_name", name);
packet_struct->setDataByName("show_bubble", 1);
packet_struct->setDataByName("understood", 1);
packet_struct->setDataByName("unknown4", 0);
to_client->QueuePacket(packet_struct->serialize());
}
safe_delete(packet_struct);
return true;
}
bool ChatChannel::SendChannelUserList(Client *client) {
vector<int32>::iterator itr;
PacketStruct *packet_struct;
Client *to_client;
int8 i = 0;
if ((packet_struct = configReader.getStruct("WS_WhoChannelQueryReply", client->GetVersion())) == NULL)
return false;
packet_struct->setDataByName("channel_name", name);
packet_struct->setDataByName("unknown", 0);
packet_struct->setArrayLengthByName("num_players", clients.size());
for (itr = clients.begin(); itr != clients.end(); itr++) {
if ((to_client = zone_list.GetClientByCharID(*itr)) != NULL)
packet_struct->setArrayDataByName("player_name", client->GetPlayer()->GetName(), i++);
else
packet_struct->setArrayDataByName("player_name", "<Unknown>", i++);
}
client->QueuePacket(packet_struct->serialize());
safe_delete(packet_struct);
return true;
}

View File

@ -0,0 +1,79 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHAT_CHATCHANNEL_H_
#define CHAT_CHATCHANNEL_H_
#include "../../common/types.h"
#include "../client.h"
#include <vector>
using namespace std;
#define CHAT_CHANNEL_MAX_NAME 100
#define CHAT_CHANNEL_MAX_PASSWORD 100
enum ChatChannelType {
CHAT_CHANNEL_TYPE_NONE = 0,
CHAT_CHANNEL_TYPE_WORLD,
CHAT_CHANNEL_TYPE_CUSTOM
};
class ChatChannel {
public:
ChatChannel();
virtual ~ChatChannel();
void SetName(const char *name) {strncpy(this->name, name, CHAT_CHANNEL_MAX_NAME);}
void SetPassword(const char *password) {strncpy(this->password, password, CHAT_CHANNEL_MAX_PASSWORD);}
void SetType(ChatChannelType type) {this->type = type;}
void SetLevelRestriction(int16 level_restriction) {this->level_restriction = level_restriction;}
void SetRacesAllowed(int64 races) {this->races = races;}
void SetClassesAllowed(int64 classes) {this->classes = classes;}
const char * GetName() {return name;}
ChatChannelType GetType() {return type;}
unsigned int GetNumClients() {return clients.size();}
bool HasPassword() {return password[0] != '\0';}
bool PasswordMatches(const char *password) {return strncmp(this->password, password, CHAT_CHANNEL_MAX_PASSWORD) == 0;}
bool CanJoinChannelByLevel(int16 level) {return level >= level_restriction;}
bool CanJoinChannelByRace(int8 race_id) {return races == 0 || (1 << race_id) & races;}
bool CanJoinChannelByClass(int8 class_id) {return classes == 0 || (1 << class_id) & classes;}
bool IsInChannel(int32 character_id);
bool JoinChannel(Client *client);
bool LeaveChannel(Client *client);
bool TellChannel(Client *client, const char *message, const char* name2 = 0);
bool TellChannelClient(Client* to_client, const char* message, const char* name2 = 0);
bool SendChannelUserList(Client *client);
private:
char name[CHAT_CHANNEL_MAX_NAME + 1];
char password[CHAT_CHANNEL_MAX_PASSWORD + 1];
ChatChannelType type;
vector<int32> clients;
int16 level_restriction;
int64 races;
int64 classes;
};
#endif

View File

@ -0,0 +1,46 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../../common/Log.h"
#include "Chat.h"
#include "../WorldDatabase.h"
extern Chat chat;
void WorldDatabase::LoadChannels() {
DatabaseResult result;
ChatChannel *channel;
if (database_new.Select(&result, "SELECT `name`,`password`,`level_restriction`,`classes`,`races` FROM `channels`")) {
while (result.Next()) {
channel = new ChatChannel();
channel->SetName(result.GetString(0));
if (!result.IsNull(1))
channel->SetPassword(result.GetString(1));
channel->SetLevelRestriction(result.GetInt16(2));
channel->SetClassesAllowed(result.GetInt64(3));
channel->SetRacesAllowed(result.GetInt64(4));
channel->SetType(CHAT_CHANNEL_TYPE_WORLD);
chat.AddChannel(channel);
}
}
}

View File

@ -0,0 +1,475 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ClientPacketFunctions.h"
#include "WorldDatabase.h"
#include "../common/ConfigReader.h"
#include "Variables.h"
#include "World.h"
#include "classes.h"
#include "../common/Log.h"
#include "Traits/Traits.h"
extern Classes classes;
extern Commands commands;
extern WorldDatabase database;
extern ConfigReader configReader;
extern MasterSpellList master_spell_list;
extern MasterTraitList master_trait_list;
extern Variables variables;
extern World world;
void ClientPacketFunctions::SendFinishedEntitiesList ( Client* client ){
EQ2Packet* finishedEntitiesApp = new EQ2Packet(OP_DoneSendingInitialEntitiesMsg, 0, 0);
client->QueuePacket(finishedEntitiesApp);
}
void ClientPacketFunctions::SendSkillSlotMappings(Client* client){
EQ2Packet* app = client->GetPlayer()->GetSpellSlotMappingPacket(client->GetVersion());
if(app)
client->QueuePacket(app);
}
void ClientPacketFunctions::SendLoginDenied ( Client* client ){
PacketStruct* packet = configReader.getStruct("LS_LoginResponse", 1);
if(packet){
packet->setDataByName("reply_code", 1);
packet->setDataByName("unknown03", 0xFFFFFFFF);
packet->setDataByName("unknown04", 0xFFFFFFFF);
EQ2Packet* app = packet->serialize();
client->QueuePacket(app);
safe_delete(packet);
}
}
void ClientPacketFunctions::SendLoginAccepted ( Client* client ){
LogWrite(PACKET__DEBUG, 0, "Packet", "Sending Login Accepted packet (LS_LoginResponse, %i)", client->GetVersion());
PacketStruct* response_packet = configReader.getStruct("LS_LoginResponse", client->GetVersion());
if(response_packet){
response_packet->setDataByName("unknown02", 1);
response_packet->setDataByName("unknown05", -959971393);
response_packet->setDataByName("unknown08", 2);
response_packet->setDataByName("unknown09", 585);
response_packet->setDataByName("unknown10", 1597830);
response_packet->setDataByName("accountid", 3); //client->GetAccountID());
EQ2Packet* outapp = response_packet->serialize();
client->QueuePacket(outapp);
safe_delete(response_packet);
}
}
void ClientPacketFunctions::SendCommandList ( Client* client ){
EQ2Packet* app = commands.GetRemoteCommands()->serialize(client->GetVersion());
client->QueuePacket(app);
}
void ClientPacketFunctions::SendGameWorldTime ( Client* client ){
PacketStruct* packet = world.GetWorldTime(client->GetVersion());
if(packet){
client->QueuePacket(packet->serialize());
safe_delete(packet);
}
//opcode 501 was the selection display opcode
}
void ClientPacketFunctions::SendCharacterData ( Client* client ){
client->GetPlayer()->SetCharacterID(client->GetCharacterID());
if(!client->IsReloadingZone()) {
EQ2Packet* outapp = client->GetPlayer()->serialize(client->GetPlayer(), client->GetVersion());
//DumpPacket(outapp);
client->QueuePacket(outapp);
}
}
void ClientPacketFunctions::SendCharacterSheet ( Client* client ){
EQ2Packet* app = client->GetPlayer()->GetPlayerInfo()->serialize(client->GetVersion());
client->QueuePacket(app);
if (client->GetVersion() >= 1188) {
EQ2Packet* app2 = client->GetPlayer()->GetPlayerInfo()->serializePet(client->GetVersion());
if (app2)
client->QueuePacket(app2);
}
}
void ClientPacketFunctions::SendSkillBook ( Client* client ){
EQ2Packet* app = client->GetPlayer()->skill_list.GetSkillPacket(client->GetVersion());
if(app)
client->QueuePacket(app);
}
// Jabantiz: Attempt to get the char trait list working
void ClientPacketFunctions::SendTraitList(Client* client) {
if (client->GetVersion() >= 562) {
EQ2Packet* traitApp = master_trait_list.GetTraitListPacket(client);
//DumpPacket(traitApp);
if (traitApp) {
client->QueuePacket(traitApp);
}
}
}
void ClientPacketFunctions::SendAbilities ( Client* client ){
LogWrite(MISC__TODO, 1, "TODO", " Add SendAbilities functionality\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
// this is the featherfall ability data
// later this would loop through and send all abilities
/*uchar abilityData[] ={0x11,0x00,0x00,0x00,0xff,0x15,0x02,0x00,0x0b,0x00,0x46,0x65,0x61,0x74
,0x68,0x65,0x72,0x66,0x61,0x6c,0x6c};
EQ2Packet* abilityApp = new EQ2Packet(OP_ClientCmdMsg, abilityData, sizeof(abilityData));
client->QueuePacket(abilityApp);*/
}
void ClientPacketFunctions::SendCommandNamePacket ( Client* client ){
LogWrite(MISC__TODO, 1, "TODO", " fix, this is actually quest/collection information\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
/*
PacketStruct* command_packet = configReader.getStruct("WS_CommandName", client->GetVersion());
if(command_packet){
command_packet->setDataByName("unknown03", 0x221bfb47);
char* charName = { "BogusName" };
command_packet->setMediumStringByName("character_name",charName);
EQ2Packet* outapp = command_packet->serialize();
client->QueuePacket(outapp);
safe_delete(command_packet);
}
*/
}
void ClientPacketFunctions::SendQuickBarInit ( Client* client ){
int32 count = database.LoadPlayerSkillbar(client);
if(count == 0) {
LogWrite(PACKET__DEBUG, 0, "Packet", "No character quickbar found!");
database.UpdateStartingSkillbar(client->GetCharacterID(), client->GetPlayer()->GetAdventureClass(), client->GetPlayer()->GetRace());
database.LoadPlayerSkillbar(client);
}
EQ2Packet* quickbarApp = client->GetPlayer()->GetQuickbarPacket(client->GetVersion());
if(quickbarApp)
client->QueuePacket(quickbarApp);
}
void ClientPacketFunctions::SendCharacterMacros(Client* client) {
LogWrite(PACKET__DEBUG, 0, "Packet", "Sending Character Macro packet (WS_MacroInit, %i)", client->GetVersion());
map<int8, vector<MacroData*> >* macros = database.LoadCharacterMacros(client->GetCharacterID());
if (macros) {
PacketStruct* macro_packet = configReader.getStruct("WS_MacroInit", client->GetVersion());
if (macro_packet) {
map<int8, vector<MacroData*> >::iterator itr;
macro_packet->setArrayLengthByName("macro_count", macros->size());
int8 x = 0;
for (itr = macros->begin(); itr != macros->end(); itr++, x++) {
macro_packet->setArrayDataByName("number", itr->first, x);
if (itr->second.size() > 0) {
LogWrite(PACKET__DEBUG, 5, "Packet", "Loading Macro %i, name: %s", itr->first, itr->second[0]->name.c_str());
macro_packet->setArrayDataByName("name", itr->second[0]->name.c_str(), x);
}
if (client->GetVersion() > 373) {
char tmp_details_count[25] = { 0 };
sprintf(tmp_details_count, "macro_details_count_%i", x);
macro_packet->setArrayLengthByName(tmp_details_count, itr->second.size());
for (int8 i = 0; i < itr->second.size(); i++) {
char tmp_command[15] = { 0 };
sprintf(tmp_command, "command%i", x);
LogWrite(PACKET__DEBUG, 5, "Packet", "\tLoading Command %i: %s", itr->first, x, itr->second[i]->text.c_str());
macro_packet->setArrayDataByName(tmp_command, itr->second[i]->text.c_str(), i);
if ( i > 0 ) // itr->second[0] used below, we will delete it later
safe_delete(itr->second[i]); // delete MacroData*
}
macro_packet->setArrayDataByName("unknown2", 2, x);
macro_packet->setArrayDataByName("unknown3", 0xFFFFFFFF, x);
}
else {
if (itr->second.size() > 0)
macro_packet->setArrayDataByName("command", itr->second[0]->text.c_str(), x);
}
macro_packet->setArrayDataByName("icon", itr->second[0]->icon, x);
client->GetPlayer()->macro_icons[itr->first] = itr->second[0]->icon;
// remove itr->second[0] now that we are done with it
safe_delete(itr->second[0]); // delete MacroData*
}
EQ2Packet* packet = macro_packet->serialize();
client->QueuePacket(packet);
safe_delete(macro_packet);
}
safe_delete(macros);
}
}
void ClientPacketFunctions::SendMOTD ( Client* client ){
const char* motd = 0;
// fetch MOTD from `variables` table
Variable* var = variables.FindVariable("motd");
if( var == NULL || strlen (var->GetValue()) == 0) {
LogWrite(WORLD__WARNING, 0, "World", "No MOTD set. Sending generic message...");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Message of the Day: Welcome to EQ2Emulator! Customize this message in the `variables`.`motd` data!");
}
else {
motd = var->GetValue();
LogWrite(WORLD__DEBUG, 0, "World", "Send MOTD...");
client->SimpleMessage(CHANNEL_COLOR_YELLOW, motd);
}
}
void ClientPacketFunctions::SendUpdateSpellBook ( Client* client ){
if(client->IsReadyForSpawns()){
EQ2Packet* app = client->GetPlayer()->GetSpellBookUpdatePacket(client->GetVersion());
if(app)
client->QueuePacket(app);
}
client->GetPlayer()->UnlockAllSpells(true);
}
void ClientPacketFunctions::SendServerControlFlagsClassic(Client* client, int32 param, int32 value) {
PacketStruct* packet = configReader.getStruct("WS_ServerControlFlags", client->GetVersion());
if(packet) {
packet->setDataByName("parameter", param);
packet->setDataByName("value", value);
client->QueuePacket(packet->serialize());
}
safe_delete(packet);
}
void ClientPacketFunctions::SendServerControlFlags(Client* client, int8 param, int8 param_val, int8 value) {
PacketStruct* packet = configReader.getStruct("WS_ServerControlFlags", client->GetVersion());
if(packet) {
if (param == 1)
packet->setDataByName("parameter1", param_val);
else if (param == 2)
packet->setDataByName("parameter2", param_val);
else if (param == 3)
packet->setDataByName("parameter3", param_val);
else if (param == 4)
packet->setDataByName("parameter4", param_val);
else if (param == 5)
packet->setDataByName("parameter5", param_val);
else {
safe_delete(packet);
return;
}
packet->setDataByName("value", value);
client->QueuePacket(packet->serialize());
/*
Some other values for this packet
first param:
01 flymode
02 collisons off
04 unknown
08 heading movement only
16 forward/reverse movement only
32 low gravity
64 sit
second
2 crouch
third:
04 float when trying to jump, no movement
08 jump high, no movement
128 walk underwater
fourth:
01 moon jump underwater
04 fear
16 moon jumps
32 safe fall (float to ground)
64 cant move
fifth:
01 die
08 hover (fae)
32 flymode2?
*/
}
safe_delete(packet);
}
void ClientPacketFunctions::SendInstanceList(Client* client) {
if (client->GetPlayer()->GetCharacterInstances()->GetInstanceCount() > 0) {
PacketStruct* packet = configReader.getStruct("WS_InstanceCreated", client->GetVersion());
if (packet) {
vector<InstanceData> persist = client->GetPlayer()->GetCharacterInstances()->GetPersistentInstances();
vector<InstanceData> lockout = client->GetPlayer()->GetCharacterInstances()->GetLockoutInstances();
packet->setArrayLengthByName("num_instances", lockout.size());
for (int32 i = 0; i < lockout.size(); i++) {
InstanceData data = lockout.at(i);
packet->setArrayDataByName("unknown1", data.db_id, i); // unique id per player
packet->setArrayDataByName("instance_zone_name", data.zone_name.c_str(), i);
packet->setArrayDataByName("unknown2", 0x0B, i); // Always set to 0x0B on live packets
packet->setArrayDataByName("success_last", data.last_success_timestamp, i);
packet->setArrayDataByName("last_failure", data.last_failure_timestamp, i);
packet->setArrayDataByName("failure", data.failure_lockout_time, i);
packet->setArrayDataByName("success", data.success_lockout_time, i);
}
packet->setArrayLengthByName("num_persistent", persist.size());
for (int32 i = 0; i < persist.size(); i++) {
InstanceData data = persist.at(i);
packet->setArrayDataByName("unknown1a", data.db_id, i); // unique id per player
packet->setArrayDataByName("persistent_zone_name", data.zone_name.c_str(), i);
packet->setArrayDataByName("unknown2a", 0x0B, i); // set to 0x0B in all live packets
packet->setArrayDataByName("persist_success_timestamp", data.last_success_timestamp, i);
packet->setArrayDataByName("persist_failure_timestamp", data.last_failure_timestamp, i);
// Check min duration (last success + failure)
//if (Timer::GetUnixTimeStamp() < data.last_success_timestamp + data.failure_lockout_time*/)
//packet->setArrayDataByName("unknown3b", 1, i);
packet->setArrayDataByName("unknown3b", 1, i);
packet->setArrayDataByName("minimum_duration", data.failure_lockout_time, i);
packet->setArrayDataByName("maximum_duration", data.success_lockout_time, i);
packet->setArrayDataByName("unknown4a", 1800, i); // All live logs have 0x0708
}
client->QueuePacket(packet->serialize());
}
safe_delete(packet);
}
}
void ClientPacketFunctions::SendMaintainedExamineUpdate(Client* client, int8 slot_pos, int32 update_value, int8 update_type){
if (!client)
return;
PacketStruct* packet = configReader.getStruct("WS_UpdateMaintainedExamine", client->GetVersion());
if (packet){
packet->setSubstructDataByName("info_header", "show_name", 1);
packet->setSubstructDataByName("info_header", "packettype", 19710);
packet->setSubstructDataByName("info_header", "packetsubtype", 5);
packet->setDataByName("time_stamp", Timer::GetCurrentTime2());
packet->setDataByName("slot_pos", slot_pos);
packet->setDataByName("update_value", update_value > 0 ? update_value : 0xFFFFFFFF);
packet->setDataByName("update_type", update_type);
client->QueuePacket(packet->serialize());
safe_delete(packet);
}
}
void ClientPacketFunctions::SendZoneChange(Client* client, char* zone_ip, int16 zone_port, int32 key) {
if (!client)
return;
PacketStruct* packet = configReader.getStruct("WS_ZoneChangeMsg", client->GetVersion());
if (packet) {
packet->setDataByName("account_id", client->GetAccountID());
packet->setDataByName("key", key);
packet->setDataByName("ip_address", zone_ip);
packet->setDataByName("port", zone_port);
client->QueuePacket(packet->serialize());
}
safe_delete(packet);
}
void ClientPacketFunctions::SendStateCommand(Client* client, int32 spawn_id, int32 state) {
if (!client || !spawn_id) {
return;
}
PacketStruct* packet = configReader.getStruct("WS_StateCmd", client->GetVersion());
if (packet) {
packet->setDataByName("spawn_id", spawn_id);
packet->setDataByName("state", state);
client->QueuePacket(packet->serialize());
}
safe_delete(packet);
}
void ClientPacketFunctions::SendFlyMode(Client* client, int8 flymode, bool updateCharProperty)
{
if (updateCharProperty)
database.insertCharacterProperty(client, CHAR_PROPERTY_FLYMODE, (char*)std::to_string(flymode).c_str());
if(client->GetVersion() <= 561) {
if(flymode) {
// old flymode
SendServerControlFlagsClassic(client, flymode, 1);
if(flymode == 1) {
// disable noclip
SendServerControlFlagsClassic(client, 2, 0);
}
}
else {
// disable flymode and noclip
SendServerControlFlagsClassic(client, 2, 0);
SendServerControlFlagsClassic(client, 1, 0);
}
}
else {
if(flymode == 2) {
// new flymode + noclip
SendServerControlFlags(client, 5, 32, 1);
SendServerControlFlags(client, 1, 2, 1);
}
else if(flymode == 1) {
// new flymode
SendServerControlFlags(client, 5, 32, 1);
SendServerControlFlags(client, 1, 2, 0);
}
else {
// disable flymode and noclip
SendServerControlFlags(client, 5, 32, 0);
SendServerControlFlags(client, 1, 2, 0);
}
}
client->Message(CHANNEL_STATUS, "Flymode %s, No Clip %s", flymode > 0 ? "on" : "off", flymode > 1 ? "on" : "off");
/*
CLASSIC/DOF ONLY HAS THE FIRST SET OF FLAGS
Some other values for this packet
first param:
01 flymode
02 collisons off
04 unknown
08 forward movement
16 heading movement
32 low gravity
64 sit
EVERYTHING BELOW NOT SUPPORTED BY CLASSIC/DOF
second
2 crouch
third:
04 float when trying to jump, no movement
08 jump high, no movement
fourth:
04 autorun (fear?)
16 moon jumps
32 safe fall (float to ground)
64 cant move
fifth:
01 die
08 hover (fae)
32 flymode2?
*/
}

View File

@ -0,0 +1,92 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "client.h"
struct HouseZone;
struct PlayerHouse;
struct HeroicOP;
class ClientPacketFunctions
{
public:
static void SendFinishedEntitiesList ( Client* client );
static void SendLoginDenied ( Client* client );
static void SendLoginAccepted ( Client* client );
static void SendCommandList ( Client* client );
static void SendGameWorldTime ( Client* client );
static void SendCharacterData ( Client* client );
static void SendCharacterSheet ( Client* client );
static void SendSkillBook ( Client* client );
static void SendTraitList ( Client* client );
static void SendAbilities ( Client* client );
static void SendCommandNamePacket ( Client* client );
static void SendQuickBarInit ( Client* client );
static void SendMOTD ( Client* client );
static void SendCharacterMacros(Client* client);
static void SendUpdateSpellBook ( Client* client );
static void SendSkillSlotMappings(Client* client);
static void SendRestartZoneMsg(Client* client);
static void SendServerControlFlags(Client* client, int8 param, int8 param_val, int8 value);
static void SendServerControlFlagsClassic(Client* client, int32 param, int32 value);
static void SendInstanceList(Client* client);
static void SendZoneChange(Client* client, char* zone_ip, int16 zone_port, int32 key);
static void SendStateCommand(Client* client, int32 spawn_id, int32 state);
static void SendFlyMode(Client* client, int8 flymode, bool updateCharProperty=true);
/* Tradeskills (/Tradeskills/TradeskillsPackets.cpp) */
static void SendCreateFromRecipe(Client* client, int32 recipeID);
static void SendItemCreationUI(Client* client, Recipe* recipe);
static void StopCrafting(Client* client);
static void CounterReaction(Client* client, bool countered);
static void SendAchievementList(Client* client);
/* Housing (/Housing/HousingPackets.cpp) */
static void SendHousePurchase(Client* client, HouseZone* hz, int32 spawnID);
static void SendHousingList(Client* client);
static void SendBaseHouseWindow(Client* client, HouseZone* hz, PlayerHouse* ph, int32 spawnID);
static void SendHouseVisitWindow(Client* client, vector<PlayerHouse*> houses);
static void SendLocalizedTextMessage(Client* client);
/* Heroic OP's (/HeroicOp/HeroicOpPackets.cpp) */
static void SendHeroicOPUpdate(Client* client, HeroicOP* ho);
//UI updates for trigger count and damage remaining on maintained spells
static void SendMaintainedExamineUpdate(Client* client, int8 slot_pos, int32 update_value, int8 update_type);
};

View File

@ -0,0 +1,317 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Collections.h"
#include "../../common/Log.h"
#include <assert.h>
extern MasterCollectionList master_collection_list;
Collection::Collection() {
id = 0;
memset(name, 0, sizeof(name));
memset(category, 0, sizeof(category));
level = 0;
reward_coin = 0;
reward_xp = 0;
completed = false;
save_needed = false;
}
Collection::Collection(Collection *in) {
vector<struct CollectionItem *> *collection_items_in;
vector<struct CollectionRewardItem *> *reward_items_in;
vector<struct CollectionItem *>::iterator itr;
vector<struct CollectionRewardItem *>::iterator itr2;
struct CollectionItem *collection_item;
struct CollectionRewardItem *reward_item;
assert(in);
id = in->GetID();
strncpy(name, in->GetName(), sizeof(name));
strncpy(category, in->GetCategory(), sizeof(category));
level = in->GetLevel();
reward_coin = in->GetRewardCoin();
reward_xp = in->GetRewardXP();
completed = in->GetCompleted();
save_needed = in->GetSaveNeeded();
collection_items_in = in->GetCollectionItems();
for (itr = collection_items_in->begin(); itr != collection_items_in->end(); itr++) {
collection_item = new struct CollectionItem;
collection_item->item = (*itr)->item;
collection_item->index = (*itr)->index;
collection_item->found = (*itr)->found;
collection_items.push_back(collection_item);
}
reward_items_in = in->GetRewardItems();
for (itr2 = reward_items_in->begin(); itr2 != reward_items_in->end(); itr2++) {
reward_item = new struct CollectionRewardItem;
reward_item->item = (*itr2)->item;
reward_item->quantity = (*itr2)->quantity;
reward_items.push_back(reward_item);
}
reward_items_in = in->GetSelectableRewardItems();
for (itr2 = reward_items_in->begin(); itr2 != reward_items_in->end(); itr2++) {
reward_item = new struct CollectionRewardItem;
reward_item->item = (*itr2)->item;
reward_item->quantity = (*itr2)->quantity;
selectable_reward_items.push_back(reward_item);
}
}
Collection::~Collection() {
vector<struct CollectionItem *>::iterator itr;
vector<struct CollectionRewardItem *>::iterator itr2;
for (itr = collection_items.begin(); itr != collection_items.end(); itr++)
safe_delete(*itr);
for (itr2 = reward_items.begin(); itr2 != reward_items.end(); itr2++)
safe_delete(*itr2);
for (itr2 = selectable_reward_items.begin(); itr2 != selectable_reward_items.end(); itr2++)
safe_delete(*itr2);
}
void Collection::AddCollectionItem(struct CollectionItem *collection_item) {
assert(collection_item);
collection_items.push_back(collection_item);
}
void Collection::AddRewardItem(struct CollectionRewardItem *reward_item) {
assert(reward_item);
reward_items.push_back(reward_item);
}
void Collection::AddSelectableRewardItem(struct CollectionRewardItem *reward_item) {
assert(reward_item);
selectable_reward_items.push_back(reward_item);
}
bool Collection::NeedsItem(Item *item) {
vector<struct CollectionItem *>::iterator itr;
struct CollectionItem *collection_item;
assert(item);
if (completed)
return false;
for (itr = collection_items.begin(); itr != collection_items.end(); itr++) {
collection_item = *itr;
if (collection_item->item == item->details.item_id) {
if (collection_item->found)
return false;
else
return true;
}
}
/* item is not required by this collection at all */
return false;
}
struct CollectionItem * Collection::GetCollectionItemByItemID(int32 item_id) {
vector<struct CollectionItem *>::iterator itr;
struct CollectionItem *collection_item;
for (itr = collection_items.begin(); itr != collection_items.end(); itr++) {
collection_item = *itr;
if (collection_item->item == item_id)
return collection_item;
}
return 0;
}
bool Collection::GetIsReadyToTurnIn() {
vector<struct CollectionItem *>::iterator itr;
if (completed)
return false;
for (itr = collection_items.begin(); itr != collection_items.end(); itr++) {
if (!(*itr)->found)
return false;
}
return true;
}
MasterCollectionList::MasterCollectionList() {
mutex_collections.SetName("MasterCollectionList::collections");
}
MasterCollectionList::~MasterCollectionList() {
ClearCollections();
}
bool MasterCollectionList::AddCollection(Collection *collection) {
bool ret = false;
assert(collection);
mutex_collections.writelock(__FUNCTION__, __LINE__);
if (collections.count(collection->GetID()) == 0) {
collections[collection->GetID()] = collection;
ret = true;
}
mutex_collections.releasewritelock(__FUNCTION__, __LINE__);
return ret;
}
Collection * MasterCollectionList::GetCollection(int32 collection_id) {
Collection *collection = 0;
mutex_collections.readlock(__FUNCTION__, __LINE__);
if (collections.count(collection_id) > 0)
collection = collections[collection_id];
mutex_collections.releasereadlock(__FUNCTION__, __LINE__);
return collection;
}
void MasterCollectionList::ClearCollections() {
map<int32, Collection *>::iterator itr;
mutex_collections.writelock(__FUNCTION__, __LINE__);
for (itr = collections.begin(); itr != collections.end(); itr++)
safe_delete(itr->second);
collections.clear();
mutex_collections.releasewritelock(__FUNCTION__, __LINE__);
}
int32 MasterCollectionList::Size() {
int32 size;
mutex_collections.readlock(__FUNCTION__, __LINE__);
size = collections.size();
mutex_collections.releasereadlock(__FUNCTION__, __LINE__);
return size;
}
bool MasterCollectionList::NeedsItem(Item *item) {
map<int32, Collection *>::iterator itr;
bool ret = false;
assert(item);
mutex_collections.readlock(__FUNCTION__, __LINE__);
for (itr = collections.begin(); itr != collections.end(); itr++) {
if (itr->second->NeedsItem(item)) {
ret = true;
break;
}
}
mutex_collections.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
PlayerCollectionList::PlayerCollectionList() {
}
PlayerCollectionList::~PlayerCollectionList() {
ClearCollections();
}
bool PlayerCollectionList::AddCollection(Collection *collection) {
assert(collection);
if (collections.count(collection->GetID()) == 0) {
collections[collection->GetID()] = collection;
return true;
}
return false;
}
Collection * PlayerCollectionList::GetCollection(int32 collection_id) {
if (collections.count(collection_id) > 0)
return collections[collection_id];
return 0;
}
void PlayerCollectionList::ClearCollections() {
map<int32, Collection *>::iterator itr;
for (itr = collections.begin(); itr != collections.end(); itr++)
safe_delete(itr->second);
collections.clear();
}
int32 PlayerCollectionList::Size() {
return collections.size();
}
bool PlayerCollectionList::NeedsItem(Item *item) {
map<int32, Collection *> *master_collections;
map<int32, Collection *>::iterator itr;
Collection *collection;
Mutex *master_mutex;
bool ret = false;
assert(item);
for (itr = collections.begin(); itr != collections.end(); itr++) {
if (itr->second->NeedsItem(item)) {
ret = true;
break;
}
}
/* if the player doesnt have a collection that needs the item, check the master collection list to see if there's a collection
* in there that needs the item that the player does not have yet */
if (!ret) {
master_mutex = master_collection_list.GetMutex();
master_collections = master_collection_list.GetCollections();
master_mutex->readlock(__FUNCTION__, __LINE__);
for (itr = master_collections->begin(); itr != master_collections->end(); itr++) {
collection = itr->second;
if (collection->NeedsItem(item) && !GetCollection(collection->GetID())) {
ret = true;
break;
}
}
master_mutex->releasereadlock(__FUNCTION__, __LINE__);
}
return ret;
}
bool PlayerCollectionList::HasCollectionsToHandIn() {
map<int32, Collection *>::iterator itr;
for (itr = collections.begin(); itr != collections.end(); itr++) {
if (itr->second->GetIsReadyToTurnIn())
return true;
}
return false;
}

View File

@ -0,0 +1,107 @@
#ifndef COLLECTIONS_H_
#define COLLECTIONS_H_
#include "../../common/types.h"
#include "../../common/Mutex.h"
#include "../Items/Items.h"
#include <map>
#include <vector>
using namespace std;
struct CollectionItem {
int32 item;
int8 index;
int8 found;
};
struct CollectionRewardItem {
Item *item;
int8 quantity;
};
class Collection {
public:
Collection();
Collection(Collection *in);
virtual ~Collection();
void SetID(int32 id) {this->id = id;}
void SetName(const char *name) {strncpy(this->name, name, sizeof(this->name));}
void SetCategory(const char *category) {strncpy(this->category, category, sizeof(this->category));}
void SetLevel(int8 level) {this->level = level;}
void SetCompleted(bool completed) {this->completed = completed;}
void SetSaveNeeded(bool save_needed) {this->save_needed = save_needed;}
void AddCollectionItem(struct CollectionItem *collection_item);
void AddRewardItem(struct CollectionRewardItem *reward_item);
void AddSelectableRewardItem(struct CollectionRewardItem *reward_item);
void SetRewardCoin(int64 reward_coin) {this->reward_coin = reward_coin;}
void SetRewardXP(int64 reward_xp) {this->reward_xp = reward_xp;}
bool NeedsItem(Item *item);
struct CollectionItem * GetCollectionItemByItemID(int32 item_id);
int32 GetID() {return id;}
const char * GetName() {return name;}
const char * GetCategory() {return category;}
int8 GetLevel() {return level;}
bool GetIsReadyToTurnIn();
bool GetCompleted() {return completed;}
bool GetSaveNeeded() {return save_needed;}
vector<struct CollectionItem *> * GetCollectionItems() {return &collection_items;}
vector<struct CollectionRewardItem *> * GetRewardItems() {return &reward_items;}
vector<struct CollectionRewardItem *> * GetSelectableRewardItems() {return &selectable_reward_items;}
int64 GetRewardCoin() {return reward_coin;}
int64 GetRewardXP() {return reward_xp;}
private:
int32 id;
char name[512];
char category[512];
int8 level;
int64 reward_coin;
int64 reward_xp;
bool completed;
bool save_needed;
vector<struct CollectionItem *> collection_items;
vector<struct CollectionRewardItem *> reward_items;
vector<struct CollectionRewardItem *> selectable_reward_items;
};
class MasterCollectionList {
public:
MasterCollectionList();
virtual ~MasterCollectionList();
bool AddCollection(Collection *collection);
Collection * GetCollection(int32 collection_id);
void ClearCollections();
int32 Size();
bool NeedsItem(Item *item);
Mutex * GetMutex() {return &mutex_collections;}
map<int32, Collection *> * GetCollections() {return &collections;}
private:
Mutex mutex_collections;
map<int32, Collection *> collections;
};
class PlayerCollectionList {
public:
PlayerCollectionList();
virtual ~PlayerCollectionList();
bool AddCollection(Collection *collection);
Collection * GetCollection(int32 collection_id);
void ClearCollections();
int32 Size();
bool NeedsItem(Item *item);
bool HasCollectionsToHandIn();
map<int32, Collection *> * GetCollections() {return &collections;}
private:
map<int32, Collection *> collections;
};
#endif

View File

@ -0,0 +1,295 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef WIN32
#include <WinSock2.h>
#include <windows.h>
#endif
#include <mysql.h>
#include <assert.h>
#include "../../common/Log.h"
#include "../WorldDatabase.h"
#include "Collections.h"
extern MasterCollectionList master_collection_list;
void WorldDatabase::LoadCollections()
{
Collection *collection;
Query query;
MYSQL_ROW row;
MYSQL_RES *res;
int32 cItems_total = 0;
int32 cItems_rewards = 0;
res = query.RunQuery2(Q_SELECT, "SELECT `id`,`collection_name`,`collection_category`,`level`\n"
"FROM `collections`");
if (res)
{
while ((row = mysql_fetch_row(res)))
{
collection = new Collection();
collection->SetID(atoul(row[0]));
collection->SetName(row[1]);
collection->SetCategory(row[2]);
collection->SetLevel(atoi(row[3]));
LogWrite(COLLECTION__DEBUG, 5, "Collect", "\tLoading Collection: '%s' (%u)", collection->GetName(),collection->GetID());
if (!master_collection_list.AddCollection(collection))
{
LogWrite(COLLECTION__ERROR, 0, "Collect", "Error adding collection '%s' - duplicate ID: %u", collection->GetName(),collection->GetID());
safe_delete(collection);
continue;
}
cItems_total += LoadCollectionItems(collection);
cItems_rewards += LoadCollectionRewards(collection);
}
}
LogWrite(COLLECTION__DEBUG, 0, "Collect", "\tLoaded %u collections", master_collection_list.Size());
LogWrite(COLLECTION__DEBUG, 0, "Collect", "\tLoaded %u collection items", cItems_total);
LogWrite(COLLECTION__DEBUG, 0, "Collect", "\tLoaded %u collection rewards", cItems_rewards);
}
int32 WorldDatabase::LoadCollectionItems(Collection *collection)
{
struct CollectionItem *collection_item;
Item *item;
Query query;
MYSQL_ROW row;
MYSQL_RES *res;
int32 total = 0;
assert(collection);
res = query.RunQuery2(Q_SELECT, "SELECT `item_id`,`item_index`\n"
"FROM `collection_details`\n"
"WHERE `collection_id`=%u\n"
"ORDER BY `item_index` ASC",
collection->GetID());
if (res)
{
while ((row = mysql_fetch_row(res)))
{
if ((item = master_item_list.GetItem(atoul(row[0]))))
{
collection_item = new struct CollectionItem;
collection_item->item = atoul(row[0]);
collection_item->index = atoi(row[1]);
collection_item->found = 0;
LogWrite(COLLECTION__DEBUG, 5, "Collect", "\tLoading Collection Item: (%u)", atoul(row[0])); //LogWrite(COLLECTION__DEBUG, 5, "Collect", "\tLoading Collection Item: '%s' (%u)", master_item_list.GetItem(collection_item->item)->name.c_str(), atoul(row[0]));
collection->AddCollectionItem(collection_item);
total++;
}
}
}
if(query.GetErrorNumber())
LogWrite(COLLECTION__ERROR, 0, "Collect", "Error Loading Collection Items, Query: %s, Error: %s", query.GetQuery(), query.GetError());
return total;
}
int32 WorldDatabase::LoadCollectionRewards(Collection *collection)
{
struct CollectionRewardItem *reward_item;
Query query;
MYSQL_ROW row;
MYSQL_RES *res;
int32 total = 0;
assert(collection);
res = query.RunQuery2(Q_SELECT, "SELECT `reward_type`,`reward_value`,`reward_quantity`\n"
"FROM `collection_rewards`\n"
"WHERE `collection_id`=%u",
collection->GetID());
if (res)
{
while ((row = mysql_fetch_row(res)))
{
LogWrite(COLLECTION__DEBUG, 5, "Collect", "\tLoading Collection Reward: Type: %s, Val: %s, Qty: %u", row[0], row[1], atoi(row[2]));
if (!strcasecmp(row[0], "Item"))
{
reward_item = new struct CollectionRewardItem;
reward_item->item = master_item_list.GetItem(atoul(row[1]));
reward_item->quantity = atoi(row[2]);
collection->AddRewardItem(reward_item);
total++;
}
else if (!strcasecmp(row[0], "Selectable"))
{
reward_item = new struct CollectionRewardItem;
reward_item->item = master_item_list.GetItem(atoul(row[1]));
reward_item->quantity = atoi(row[2]);
collection->AddSelectableRewardItem(reward_item);
total++;
}
else if (!strcasecmp(row[0], "Coin"))
{
collection->SetRewardCoin(atoi64(row[1]));
total++;
}
else if (!strcasecmp(row[0], "XP"))
{
collection->SetRewardXP(atoi64(row[1]));
total++;
}
else
LogWrite(COLLECTION__ERROR, 0, "Collect", "Error adding collection reward to collection '%s'. Unknown reward type '%s'", collection->GetName(), row[0]);
}
}
if(query.GetErrorNumber())
LogWrite(COLLECTION__ERROR, 0, "Collect", "Error Loading Collection Rewards, Query: %s, Error: %s", query.GetQuery(), query.GetError());
return total;
}
void WorldDatabase::LoadPlayerCollections(Player *player)
{
Collection *collection;
Query query;
MYSQL_ROW row;
MYSQL_RES *res;
assert(player);
res = query.RunQuery2(Q_SELECT, "SELECT `collection_id`,`completed` FROM `character_collections` WHERE `char_id`=%u", player->GetCharacterID());
if (res)
{
while ((row = mysql_fetch_row(res)))
{
collection = new Collection(master_collection_list.GetCollection(atoul(row[0])));
collection->SetCompleted(atoi(row[1]));
if (!player->GetCollectionList()->AddCollection(collection))
{
LogWrite(COLLECTION__ERROR, 0, "Collect", "Error adding collection %u to player '%s' - duplicate ID\n", collection->GetID(), player->GetName());
safe_delete(collection);
continue;
}
LoadPlayerCollectionItems(player, collection);
}
}
if(query.GetErrorNumber())
LogWrite(COLLECTION__ERROR, 0, "Collect", "Error Loading Character Collections, Query: %s, Error: %s", query.GetQuery(), query.GetError());
}
void WorldDatabase::LoadPlayerCollectionItems(Player *player, Collection *collection)
{
struct CollectionItem *collection_item;
Query query;
MYSQL_ROW row;
MYSQL_RES *res;
assert(player);
assert(collection);
res = query.RunQuery2(Q_SELECT, "SELECT `collection_item_id`\n"
"FROM `character_collection_items`\n"
"WHERE `char_id`=%u\n"
"AND `collection_id`=%u",
player->GetCharacterID(), collection->GetID());
if (res)
{
while ((row = mysql_fetch_row(res)))
{
if ((collection_item = collection->GetCollectionItemByItemID(atoul(row[0]))))
collection_item->found = true;
else
LogWrite(COLLECTION__ERROR, 0, "Collect", "Error Loading character collection items. Item ID %u does not exist in collection %s", atoul(row[0]), collection->GetName());
}
}
if(query.GetErrorNumber())
LogWrite(COLLECTION__ERROR, 0, "Collect", "Error Loading Character Collection Items, Query: %s, Error: %s", query.GetQuery(), query.GetError());
}
void WorldDatabase::SavePlayerCollections(Client *client)
{
map<int32, Collection *> *collections;
map<int32, Collection *>::iterator itr;
Collection *collection;
assert(client);
collections = client->GetPlayer()->GetCollectionList()->GetCollections();
for (itr = collections->begin(); itr != collections->end(); itr++)
{
collection = itr->second;
if (collection->GetSaveNeeded())
{
SavePlayerCollection(client, collection);
SavePlayerCollectionItems(client, collection);
collection->SetSaveNeeded(false);
}
}
}
void WorldDatabase::SavePlayerCollection(Client *client, Collection *collection)
{
Query query;
assert(client);
assert(collection);
query.AddQueryAsync(client->GetCharacterID(), this, Q_UPDATE, "INSERT INTO `character_collections` (`char_id`,`collection_id`,`completed`)\n"
"VALUES (%u,%u,0)\n"
"ON DUPLICATE KEY UPDATE `completed`=%i",
client->GetPlayer()->GetCharacterID(), collection->GetID(),
collection->GetCompleted() ? 1 : 0);
}
void WorldDatabase::SavePlayerCollectionItems(Client *client, Collection *collection)
{
vector<struct CollectionItem *> *collection_items;
vector<struct CollectionItem *>::iterator itr;
struct CollectionItem *collection_item;
assert(client);
assert(collection);
collection_items = collection->GetCollectionItems();
for (itr = collection_items->begin(); itr != collection_items->end(); itr++)
{
collection_item = *itr;
if (collection_item->found > 0)
SavePlayerCollectionItem(client, collection, collection_item->item);
}
}
void WorldDatabase::SavePlayerCollectionItem(Client *client, Collection *collection, int32 item_id)
{
Query query;
assert(client);
assert(collection);
//assert(item);
query.AddQueryAsync(client->GetCharacterID(), this, Q_INSERT, "INSERT IGNORE INTO `character_collection_items` (`char_id`,`collection_id`,`collection_item_id`)\n"
"VALUES (%u,%u,%u)",
client->GetPlayer()->GetCharacterID(), collection->GetID(), item_id);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __EQ2_COMBAT_H__
#define __EQ2_COMBAT_H__
#include "Player.h"
#include "../common/timer.h"
#include "NPC_AI.h"
#include "MutexList.h"
#define COMBAT_NORMAL_FIGHTER 0
#define COMBAT_ADD_FIGHTER 1
#define COMBAT_REMOVE_FIGHTER 2
// replace with rule rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat()
//#define MAX_COMBAT_RANGE 3
class ZoneServer;
class SpellProcess;
class LuaSpell;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,976 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __EQ2_COMMANDS__
#define __EQ2_COMMANDS__
#include "../../common/DataBuffer.h"
#include "../../common/MiscFunctions.h"
#include "../../common/types.h"
#include "../../common/opcodemgr.h"
#include <vector>
#include <string>
#include <map>
#include "../../common/debug.h"
using namespace std;
class Client;
class Spawn;
class ZoneServer;
extern map<int16,OpcodeManager*>EQOpcodeManager;
#define CHANNEL_COLOR_RED 3
#define CHANNEL_COLOR_CHAT_RELATIONSHIP 4
#define CHANNEL_COLOR_YELLOW 5
#define CHANNEL_COLOR_NEW_LOOT 84
#define CHANNEL_COLOR_NEWEST_LOOT 89
#define UPDATE_COLOR_WHITE 254 // For UpdateText
#define CHANNEL_ALL_TEXT 0
#define CHANNEL_GAME_TEXT 1
#define CHANNEL_DEFAULT 2
#define CHANNEL_ERROR 3
#define CHANNEL_STATUS 4
#define CHANNEL_MOTD 5
#define CHANNEL_CHAT_TEXT 6
#define CHANNEL_NEARBY_CHAT 7
#define CHANNEL_SAY 8
#define CHANNEL_SHOUT 9
#define CHANNEL_EMOTE 10
#define CHANNEL_YELL 11
#define CHANNEL_NARRATIVE 12 //white
#define CHANNEL_NONPLAYER_SAY 13
#define CHANNEL_GROUP_CHAT 14
#define CHANNEL_GROUP_SAY 15 // Use this for group chat
#define CHANNEL_RAID_SAY 16
#define CHANNEL_GUILD_CHAT 17
#define CHANNEL_GUILD_SAY 18 // Use this for guild chat
#define CHANNEL_OFFICER_SAY 19
#define CHANNEL_GUILD_MOTD 20
#define CHANNEL_GUILD_MEMBER_ONLINE 21
#define CHANNEL_GUILD_EVENT 22
#define CHANNEL_GUILD_RECRUITING_PAGE 23
#define CHANNEL_GUILD_RECRUITING_PAGE_OTHER 24
#define CHANNEL_PRIVATE_CHAT 25
#define CHANNEL_NONPLAYER_TELL 26
#define CHANNEL_OBJECT_TEXT 27
#define CHANNEL_PRIVATE_TELL 28
#define CHANNEL_TELL_FROM_CS 29
#define CHANNEL_ARENA 30
#define CHANNEL_CHAT_CHANNEL_TEXT 31
#define CHANNEL_OUT_OF_CHARACTER 32
#define CHANNEL_AUCTION 33
#define CHANNEL_CUSTOM_CHANNEL 34 // 34 is nothing, message with 34 as type will not show on client
#define CHANNEL_CHARACTER_TEXT 35
#define CHANNEL_REWARD 36
#define CHANNEL_DEATH 37
#define CHANNEL_PET_CHAT 38
#define CHANNEL_SKILL 39
#define CHANNEL_FACTION 40
// Combat related chat channels start here
#define CHANNEL_SPELLS 41
#define CHANNEL_YOU_CAST 42
#define CHANNEL_YOU_FAIL 43
#define CHANNEL_CRITICAL_CAST 44
#define CHANNEL_FRIENDLY_CAST 45
#define CHANNEL_FRIENDLY_FAIL 46
#define CHANNEL_OTHER_CAST 47
#define CHANNEL_OTHER_FAIL 48
#define CHANNEL_HOSTILE_CAST 49
#define CHANNEL_HOSTILE_FAIL 50
#define CHANNEL_WORN_OFF 51
#define CHANNEL_SPELLS_OTHER 52
#define CHANNEL_HEAL_SPELLS 53
#define CHANNEL_HEALS 54
#define CHANNEL_FRIENDLY_HEALS 55
#define CHANNEL_OTHER_HEALS 56
#define CHANNEL_HOSTILE_HEALS 57
#define CHANNEL_CRITICAL_HEALS 58
#define CHANNEL_COMBAT 59
#define CHANNEL_GENERAL_COMBAT 60
#define CHANNEL_HEROIC_OPPORTUNITY 61
#define CHANNEL_NON_MELEE_DAMAGE 62
#define CHANNEL_DAMAGE_SHIELD 63
#define CHANNEL_WARD 64
#define CHANNEL_DAMAGE_INTERCEPT 65
#define CHANNEL_MELEE_COMBAT 66
#define CHANNEL_WARNINGS 67
#define CHANNEL_YOU_HIT 68
#define CHANNEL_YOU_MISS 69
#define CHANNEL_ATTACKER_HITS 70
#define CHANNEL_ATTACKER_MISSES 71
#define CHANNEL_YOUR_PET_HITS 72
#define CHANNEL_YOUR_PET_MISSES 73
#define CHANNEL_ATTACKER_HITS_PET 74
#define CHANNEL_ATTACKER_MISSES_PET 75
#define CHANNEL_OTHER_HIT 76
#define CHANNEL_OTHER_MISSES 77
#define CHANNEL_CRITICAL_HIT 78
#define CHANNEL_HATE_ADJUSTMENTS 79
#define CHANNEL_YOUR_HATE 80
#define CHANNEL_OTHERS_HATE 81
#define CHANNEL_DISPELS_AND_CURES 82
#define CHANNEL_DISPEL_YOU 83
#define CHANNEL_DISPEL_OTHER 84
#define CHANNEL_CURE_YOU 85
#define CHANNEL_CURE_OTHER 86
// End of combat chat channels
#define CHANNEL_OTHER 87
#define CHANNEL_MONEY_SPLIT 88
#define CHANNEL_LOOT 89
#define CHANNEL_LOOT_ROLLS 90
#define CHANNEL_COMMAND_TEXT 91
#define CHANNEL_BROADCAST 92 // Goes to all chat windows no matter what
#define CHANNEL_WHO 93
#define CHANNEL_COMMANDS 94
#define CHANNEL_MERCHANT 95
#define CHANNEL_MERCHANT_BUY_SELL 96
#define CHANNEL_CONSIDER_MESSAGE 97
#define CHANNEL_CON_MINUS_2 98
#define CHANNEL_CON_MINUS_1 99
#define CHANNEL_CON_0 100
#define CHANNEL_CON_1 101
#define CHANNEL_CON_2 102
#define CHANNEL_TRADESKILLS 103
#define CHANNEL_HARVESTING 104
#define CHANNEL_HARVESTING_WARNINGS 105
// 106 is nothing, message sent with this channel won't display in the client
#define CHANNEL_VOICE_CHAT 107
// 108+ will crash the client DO NOT USE
/* Using this in the /zone details command so that we do not have to store a whole zone in memory while changing zone attributes. Also,
ran into a problem when deleting a zone pointer (for zones that were not running), it would try to shut down a zone which was not
running, causing world to crash. */
struct ZoneInfo {
int32 id;
int8 expansion_id;
char name[64];
char file[64];
char description[256];
float safe_x;
float safe_y;
float safe_z;
float underworld;
int8 min_recommended;
int8 max_recommended;
char zone_type[64];
bool always_loaded;
bool city_zone;
sint16 min_status;
int16 min_level;
int16 max_level;
int8 start_zone;
int8 instance_type;
int32 default_reenter_time;
int32 default_reset_time;
int32 default_lockout_time;
int8 force_group_to_zone;
char lua_script[256];
int32 shutdown_timer;
char zone_motd[256];
float xp_modifier;
int16 min_version;
bool weather_allowed;
int32 ruleset_id;
char sky_file[64];
};
class EQ2_CommandString : public DataBuffer{
public:
EQ2_CommandString(){ handler = 0; }
EQ2_CommandString(uchar* buffer, int32 size){
InitializeLoadData(buffer, size);
LoadData(handler);
LoadDataString(command);
}
EQ2_16BitString command;
int16 handler;
};
class EQ2_RemoteCommandString : public DataBuffer{
public:
EQ2_RemoteCommandString(){ handler = 0; }
EQ2_RemoteCommandString(char* name, int32 in_handler, sint16 in_status){
command.data = string(name);
command.size = command.data.length();
handler = in_handler;
required_status = in_status;
}
EQ2_RemoteCommandString(uchar* buffer, int32 size){
required_status = 0;
InitializeLoadData(buffer, size);
LoadData(handler);
LoadDataString(command);
}
EQ2_8BitString command;
int16 handler;
sint16 required_status;
};
class RemoteCommands {
public:
RemoteCommands(){ num_commands = 0; buffer.clear(); }
int16 num_commands;
vector<EQ2_RemoteCommandString> commands;
void addCommand(EQ2_RemoteCommandString add){ commands.push_back(add); num_commands++;}
void AddSubCommand(string command, EQ2_RemoteCommandString subcommand){
subcommands[command][subcommand.command.data] = subcommand;
}
bool validSubCommand(string command, string subcommand){
if(subcommands.count(command) > 0 && subcommands[command].count(subcommand) > 0)
return true;
return false;
}
void addZero(){
num_commands++;
EQ2_RemoteCommandString add;
add.handler = 0;
add.required_status = 300;
add.command.size = 0;
commands.push_back(add);
}
void CheckAddSubCommand(string command, EQ2_RemoteCommandString subcommand){
vector<EQ2_RemoteCommandString>::iterator itr;
for(itr = commands.begin(); itr != commands.end();itr++){
if((*itr).command.data == command){
AddSubCommand(command, subcommand);
return;
}
}
// TODO: cannot seem to use LogWrite in this .h file!
printf("Unable to find parent command '%s' for subcommand: '%s'\n\tEvery subcommand must have a parent command!", command.c_str(), subcommand.command.data.c_str());
}
void AddDataCommand(EQ2_RemoteCommandString* command){
buffer.append((char*)&command->command.size, sizeof(command->command.size));
if(command->command.size>0)
buffer.append(command->command.data);
}
int32 GetCommandHandler(const char* name){
if(!name)
return 0xFFFFFFFF;
int8 name_size = strlen(name);
for(int32 i = 0; i < commands.size(); i++){
if(commands[i].command.size > 0){
if(strncasecmp(commands[i].command.data.c_str(), name, name_size) == 0)
return commands[i].handler;
}
}
return 0xFFFFFFFF;
}
string buffer;
EQ2Packet* serialize(int16 version = 0);
map<string, map <string, EQ2_RemoteCommandString> > subcommands;
};
class Commands{
public:
Commands();
~Commands();
bool SetSpawnCommand(Client* client, Spawn* target, int8 type, const char* value, bool send_update = true, bool temporary = false, string* temp_value = 0, int8 index = 0);
void UpdateDatabaseAppearance(Client* client, Spawn* target, string fieldName, sint8 r, sint8 g, sint8 b);
bool SetZoneCommand(Client* client, int32 zone_id, ZoneServer* zone, int8 type, const char* value);
RemoteCommands* GetRemoteCommands() { return remote_commands; }
void Process(int32 index, EQ2_16BitString* command_parms, Client* client, Spawn* targetOverride=NULL);
int32 GetCommandHandler(const char* name){
return remote_commands->GetCommandHandler(name);
}
int32 GetSpawnSetType(string val);
// JA: New Command handlers
void Command_AcceptAdvancement(Client* client, Seperator* sep);
void Command_AFK(Client* client, Seperator* sep);
void Command_Appearance(Client* client, Seperator* sep, int handler);
void Command_CancelMaintained(Client* client, Seperator* sep);
void Command_Claim(Client* client, Seperator* sep);
void Command_ClearAllQueued(Client* client);
void Command_Create(Client* client, Seperator* sep);
void Command_CreateFromRecipe(Client* client, Seperator* sep);
void Command_Distance(Client* client);
void Command_Duel(Client* client, Seperator* sep);
void Command_DuelBet(Client* client, Seperator* sep);
void Command_DuelAccept(Client* client, Seperator* sep);
void Command_DuelDecline(Client* client, Seperator* sep);
void Command_DuelSurrender(Client* client, Seperator* sep);
void Command_DuelToggle(Client* client, Seperator* sep);
void Command_EntityCommand(Client* client, Seperator* sep, int handler);
void Command_Follow(Client* client, Seperator* sep);
void Command_StopFollow(Client* client, Seperator* sep);
void Command_Grid(Client* client, Seperator* sep);
void Command_Guild(Client* client, Seperator* sep);
void Command_CreateGuild(Client* client);
void Command_SetGuildOfficerNote(Client* client, Seperator* sep);
void Command_SetGuildMemberNote(Client* client, Seperator* sep);
void Command_OfficerSay(Client* client, Seperator* sep);
void Command_GuildSay(Client* client, Seperator* sep);
void Command_Guilds(Client* client);
void Command_GuildsAdd(Client* client, Seperator* sep);
void Command_GuildsCreate(Client* client, Seperator* sep);
void Command_GuildsDelete(Client* client, Seperator* sep);
void Command_GuildsList(Client* client);
void Command_GuildsRemove(Client* client, Seperator* sep);
void Command_InspectPlayer(Client* client, Seperator* sep);
void Command_Inventory(Client* client, Seperator* sep, EQ2_RemoteCommandString* command);
void Command_Languages(Client* client, Seperator* sep);
void Command_SetLanguage(Client* client, Seperator* sep);
void Command_LastName(Client* client, Seperator* sep);
void Command_ConfirmLastName(Client* client, Seperator* sep);
void Command_Location(Client* client);
void Command_LocationAdd(Client* client, Seperator* sep);
void Command_LocationCreate(Client* client, Seperator* sep);
void Command_LocationDelete(Client* client, Seperator* sep);
void Command_LocationList(Client* client, Seperator* sep);
void Command_LocationRemove(Client* client, Seperator* sep);
void Command_Merchant(Client* client, Seperator* sep, int handler);
//devn00b
void Command_Mood(Client* client, Seperator* sep);
void Command_Modify(Client* client); // usage function
void Command_ModifyCharacter(Client* client, Seperator* sep);
void Command_ModifyFaction(Client* client, Seperator* sep);
void Command_ModifyGuild(Client* client, Seperator* sep);
void Command_ModifyItem(Client* client, Seperator* sep);
void Command_ModifyQuest(Client* client, Seperator* sep);
void Command_ModifySkill(Client* client, Seperator* sep);
void Command_ModifySpawn(Client* client, Seperator* sep);
void Command_ModifySpell(Client* client, Seperator* sep);
void Command_ModifyZone(Client* client, Seperator* sep);
void Command_MOTD(Client* client);
void Command_Pet(Client* client, Seperator* sep);
void Command_PetName(Client* client, Seperator* sep);
void Command_NamePet(Client* client, Seperator* sep);
void Command_Rename(Client* client, Seperator* sep);
void Command_ConfirmRename(Client* client, Seperator* sep);
void Command_PetOptions(Client* client, Seperator* sep);
void Command_Random(Client* client, Seperator* sep);
void Command_Randomize(Client* client, Seperator* sep);
void Command_ReportBug(Client* client, Seperator* sep);
void Command_ShowCloak(Client* client, Seperator* sep);
void Command_ShowHelm(Client* client, Seperator* sep);
void Command_ShowHood(Client* client, Seperator* sep);
void Command_ShowHoodHelm(Client* client, Seperator* sep);
void Command_ShowRanged(Client* client, Seperator* sep);
void Command_Skills(Client* client, Seperator* sep, int handler);
void Command_SpawnTemplate(Client* client, Seperator* sep);
void Command_Speed(Client* client, Seperator* sep);
void Command_StationMarketPlace(Client* client, Seperator* sep);
void Command_StopEating(Client* client);
void Command_StopDrinking(Client* client);
void Command_Test(Client* client, EQ2_16BitString* command_parms);
void Command_Title(Client* client);
void Command_TitleList(Client* client);
void Command_TitleSetPrefix(Client* client, Seperator* sep);
void Command_TitleSetSuffix(Client* client, Seperator* sep);
void Command_TitleFix(Client* client, Seperator* sep);
void Command_Toggle_Anonymous(Client* client);
void Command_Toggle_AutoConsume(Client* client, Seperator* sep);
void Command_Toggle_BonusXP(Client* client);
void Command_Toggle_CombatXP(Client* client);
void Command_Toggle_GMHide(Client* client);
void Command_Toggle_GMVanish(Client* client);
void Command_Toggle_Illusions(Client* client, Seperator* sep);
void Command_Toggle_LFG(Client* client);
void Command_Toggle_LFW(Client* client);
void Command_Toggle_QuestXP(Client* client);
void Command_Toggle_Roleplaying(Client* client);
void Command_Toggle_Duels(Client* client);
void Command_Toggle_Trades(Client* client);
void Command_Toggle_Guilds(Client* client);
void Command_Toggle_Groups(Client* client);
void Command_Toggle_Raids(Client* client);
void Command_Toggle_LON(Client* client);
void Command_Toggle_VoiceChat(Client* client);
void Command_Track(Client* client);
void Command_TradeStart(Client* client, Seperator* sep);
void Command_TradeAccept(Client* client, Seperator* sep);
void Command_TradeReject(Client* client, Seperator* sep);
void Command_TradeCancel(Client* client, Seperator* sep);
void Command_TradeSetCoin(Client* client, Seperator* sep);
void Command_TradeAddCoin(Client* client, Seperator* sep, int handler);
void Command_TradeRemoveCoin(Client* client, Seperator* sep, int handler);
void Command_TradeAddItem(Client* client, Seperator* sep);
void Command_TradeRemoveItem(Client* client, Seperator* sep);
void Command_TryOn(Client* client, Seperator* sep);
void Command_JoinChannel(Client *client, Seperator *sep);
void Command_JoinChannelFromLoad(Client *client, Seperator *sep);
void Command_TellChannel(Client *client, Seperator *sep);
void Command_LeaveChannel(Client *client, Seperator *sep);
void Command_WeaponStats(Client *client);
void Command_WhoChannel(Client *client, Seperator *sep);
void Command_ZoneSafeCoords(Client *client, Seperator *sep);
void Command_ZoneDetails(Client *client, Seperator *sep);
void Command_ZoneSet(Client *client, Seperator *sep);
void Command_Rain(Client* client, Seperator* sep);
void Command_Wind(Client* client, Seperator* sep);
void Command_SendMerchantWindow(Client* client, Seperator* sep, bool sell = false);
void Command_Weather(Client* client, Seperator* sep);
void Command_Select(Client* client, Seperator* sep);
void Command_ConsumeFood(Client* client, Seperator* sep);
void Command_Aquaman(Client* client, Seperator* sep);
void Command_Attune_Inv(Client* client, Seperator* sep);
void Command_Player(Client* client, Seperator* sep);
void Command_Player_Coins(Client* client, Seperator* sep);
void Command_Reset_Zone_Timer(Client* client, Seperator* sep);
void Command_AchievementAdd(Client* client, Seperator* sep);
void Command_Editor(Client* client, Seperator* sep);
void Command_AcceptResurrection(Client* client, Seperator* sep);
void Command_DeclineResurrection(Client* client, Seperator* set);
void Command_TargetItem(Client* client, Seperator* set);
void Command_FindSpawn(Client* client, Seperator* set);
void Command_MoveCharacter(Client* client, Seperator* set);
// Bot Commands
void Command_Bot(Client* client, Seperator* sep);
void Command_Bot_Create(Client* client, Seperator* sep);
void Command_Bot_Customize(Client* client, Seperator* sep);
void Command_Bot_Spawn(Client* client, Seperator* sep);
void Command_Bot_List(Client* client, Seperator* sep);
void Command_Bot_Inv(Client* client, Seperator* sep);
void Command_Bot_Settings(Client* client, Seperator* sep);
void Command_Bot_Help(Client* client, Seperator* sep);
void Command_CancelEffect(Client* client, Seperator* sep);
void Command_CurePlayer(Client* client, Seperator* sep);
void Command_ShareQuest(Client* client, Seperator* sep);
void Command_Yell(Client* client, Seperator* sep);
void Command_SetAutoLootMode(Client* client, Seperator* sep);
void Command_AutoAttack(Client* client, Seperator* sep);
void Command_Assist(Client* client, Seperator* sep);
void Command_Target(Client* client, Seperator* sep);
void Command_Target_Pet(Client* client, Seperator* sep);
// AA Commands
void Get_AA_Xml(Client* client, Seperator* sep);
void Add_AA(Client* client, Seperator* sep);
void Commit_AA_Profile(Client* client, Seperator* sep);
void Begin_AA_Profile(Client* client, Seperator* sep);
void Back_AA(Client* client, Seperator* sep);
void Remove_AA(Client* client, Seperator* sep);
void Switch_AA_Profile(Client* client, Seperator* sep);
void Cancel_AA_Profile(Client* client, Seperator* sep);
void Save_AA_Profile(Client* client, Seperator* sep);
private:
RemoteCommands* remote_commands;
map<string, int8> spawn_set_values;
map<string, int8> zone_set_values;
};
#define SPAWN_SET_VALUE_LIST 0
#define SPAWN_SET_VALUE_NAME 1
#define SPAWN_SET_VALUE_LEVEL 2
#define SPAWN_SET_VALUE_DIFFICULTY 3
#define SPAWN_SET_VALUE_MODEL_TYPE 4
#define SPAWN_SET_VALUE_CLASS 5
#define SPAWN_SET_VALUE_GENDER 6
#define SPAWN_SET_VALUE_SHOW_NAME 7
#define SPAWN_SET_VALUE_ATTACKABLE 8
#define SPAWN_SET_VALUE_SHOW_LEVEL 9
#define SPAWN_SET_VALUE_TARGETABLE 10
#define SPAWN_SET_VALUE_SHOW_COMMAND_ICON 11
#define SPAWN_SET_VALUE_HAND_ICON 12
#define SPAWN_SET_VALUE_HAIR_TYPE 13
#define SPAWN_SET_VALUE_FACIAL_HAIR_TYPE 14
#define SPAWN_SET_VALUE_WING_TYPE 15
#define SPAWN_SET_VALUE_CHEST_TYPE 16
#define SPAWN_SET_VALUE_LEGS_TYPE 17
#define SPAWN_SET_VALUE_SOGA_HAIR_TYPE 18
#define SPAWN_SET_VALUE_SOGA_FACIAL_HAIR_TYPE 19
#define SPAWN_SET_VALUE_SOGA_MODEL_TYPE 20
#define SPAWN_SET_VALUE_SIZE 21
#define SPAWN_SET_VALUE_HP 22
#define SPAWN_SET_VALUE_POWER 23
#define SPAWN_SET_VALUE_HEROIC 24
#define SPAWN_SET_VALUE_RESPAWN 25
#define SPAWN_SET_VALUE_X 26
#define SPAWN_SET_VALUE_Y 27
#define SPAWN_SET_VALUE_Z 28
#define SPAWN_SET_VALUE_HEADING 29
#define SPAWN_SET_VALUE_LOCATION 30
#define SPAWN_SET_VALUE_COMMAND_PRIMARY 31
#define SPAWN_SET_VALUE_COMMAND_SECONDARY 32
#define SPAWN_SET_VALUE_VISUAL_STATE 33
#define SPAWN_SET_VALUE_ACTION_STATE 34
#define SPAWN_SET_VALUE_MOOD_STATE 35
#define SPAWN_SET_VALUE_INITIAL_STATE 36
#define SPAWN_SET_VALUE_ACTIVITY_STATE 37
#define SPAWN_SET_VALUE_COLLISION_RADIUS 38
#define SPAWN_SET_VALUE_FACTION 39
#define SPAWN_SET_VALUE_SPAWN_SCRIPT 40
#define SPAWN_SET_VALUE_SPAWNENTRY_SCRIPT 41
#define SPAWN_SET_VALUE_SPAWNLOCATION_SCRIPT 42
#define SPAWN_SET_VALUE_SUB_TITLE 43
#define SPAWN_SET_VALUE_EXPIRE 45
#define SPAWN_SET_VALUE_EXPIRE_OFFSET 46
#define SPAWN_SET_VALUE_X_OFFSET 47
#define SPAWN_SET_VALUE_Y_OFFSET 48
#define SPAWN_SET_VALUE_Z_OFFSET 49
#define SPAWN_SET_VALUE_DEVICE_ID 50
#define SPAWN_SET_VALUE_PITCH 51
#define SPAWN_SET_VALUE_ROLL 52
#define SPAWN_SET_VALUE_HIDE_HOOD 53
#define SPAWN_SET_VALUE_EMOTE_STATE 54
#define SPAWN_SET_VALUE_ICON 55
#define SPAWN_SET_VALUE_PREFIX 56
#define SPAWN_SET_VALUE_SUFFIX 57
#define SPAWN_SET_VALUE_LASTNAME 58
#define SPAWN_SET_VALUE_EXPANSION_FLAG 59
#define SPAWN_SET_VALUE_MERCHANT_MIN_LEVEL 60
#define SPAWN_SET_VALUE_MERCHANT_MAX_LEVEL 61
#define SPAWN_SET_VALUE_HOLIDAY_FLAG 62
#define SPAWN_SET_SKIN_COLOR 63
#define SPAWN_SET_AAXP_REWARDS 64
#define SPAWN_SET_HAIR_COLOR1 65
#define SPAWN_SET_HAIR_COLOR2 66
#define SPAWN_SET_HAIR_TYPE_COLOR 67
#define SPAWN_SET_HAIR_FACE_COLOR 68
#define SPAWN_SET_HAIR_TYPE_HIGHLIGHT_COLOR 69
#define SPAWN_SET_HAIR_FACE_HIGHLIGHT_COLOR 70
#define SPAWN_SET_HAIR_HIGHLIGHT 71
#define SPAWN_SET_MODEL_COLOR 72
#define SPAWN_SET_EYE_COLOR 73
#define SPAWN_SET_SOGA_SKIN_COLOR 74
#define SPAWN_SET_SOGA_HAIR_COLOR1 75
#define SPAWN_SET_SOGA_HAIR_COLOR2 76
#define SPAWN_SET_SOGA_HAIR_TYPE_COLOR 77
#define SPAWN_SET_SOGA_HAIR_FACE_COLOR 78
#define SPAWN_SET_SOGA_HAIR_TYPE_HIGHLIGHT_COLOR 79
#define SPAWN_SET_SOGA_HAIR_FACE_HIGHLIGHT_COLOR 80
#define SPAWN_SET_SOGA_HAIR_HIGHLIGHT 81
#define SPAWN_SET_SOGA_MODEL_COLOR 82
#define SPAWN_SET_SOGA_EYE_COLOR 83
#define SPAWN_SET_CHEEK_TYPE 84
#define SPAWN_SET_CHIN_TYPE 85
#define SPAWN_SET_EAR_TYPE 86
#define SPAWN_SET_EYE_BROW_TYPE 87
#define SPAWN_SET_EYE_TYPE 88
#define SPAWN_SET_LIP_TYPE 89
#define SPAWN_SET_NOSE_TYPE 90
#define SPAWN_SET_BODY_SIZE 91
#define SPAWN_SET_BODY_AGE 92
#define SPAWN_SET_SOGA_CHEEK_TYPE 93
#define SPAWN_SET_SOGA_CHIN_TYPE 94
#define SPAWN_SET_SOGA_EAR_TYPE 95
#define SPAWN_SET_SOGA_EYE_BROW_TYPE 96
#define SPAWN_SET_SOGA_EYE_TYPE 97
#define SPAWN_SET_SOGA_LIP_TYPE 98
#define SPAWN_SET_SOGA_NOSE_TYPE 99
#define SPAWN_SET_SOGA_BODY_SIZE 100
#define SPAWN_SET_SOGA_BODY_AGE 101
#define SPAWN_SET_ATTACK_TYPE 102
#define SPAWN_SET_RACE_TYPE 103
#define SPAWN_SET_LOOT_TIER 104
#define SPAWN_SET_LOOT_DROP_TYPE 105
#define SPAWN_SET_SCARED_STRONG_PLAYERS 106
#define ZONE_SET_VALUE_EXPANSION_ID 0
#define ZONE_SET_VALUE_NAME 1
#define ZONE_SET_VALUE_FILE 2
#define ZONE_SET_VALUE_DESCRIPTION 3
#define ZONE_SET_VALUE_SAFE_X 4
#define ZONE_SET_VALUE_SAFE_Y 5
#define ZONE_SET_VALUE_SAFE_Z 6
#define ZONE_SET_VALUE_UNDERWORLD 7
#define ZONE_SET_VALUE_MIN_RECOMMENDED 8
#define ZONE_SET_VALUE_MAX_RECOMMENDED 9
#define ZONE_SET_VALUE_ZONE_TYPE 10
#define ZONE_SET_VALUE_ALWAYS_LOADED 11
#define ZONE_SET_VALUE_CITY_ZONE 12
#define ZONE_SET_VALUE_MIN_STATUS 13
#define ZONE_SET_VALUE_MIN_LEVEL 14
#define ZONE_SET_VALUE_START_ZONE 15
#define ZONE_SET_VALUE_INSTANCE_TYPE 16
#define ZONE_SET_VALUE_DEFAULT_REENTER_TIME 17
#define ZONE_SET_VALUE_DEFAULT_RESET_TIME 18
#define ZONE_SET_VALUE_DEFAULT_LOCKOUT_TIME 19
#define ZONE_SET_VALUE_FORCE_GROUP_TO_ZONE 20
#define ZONE_SET_VALUE_LUA_SCRIPT 21
#define ZONE_SET_VALUE_SHUTDOWN_TIMER 22
#define ZONE_SET_VALUE_ZONE_MOTD 23
#define ZONE_SET_VALUE_MAX_LEVEL 24
#define ZONE_SET_VALUE_WEATHER_ALLOWED 25
#define COMMAND_SPAWN 1
#define COMMAND_RACE 2
#define COMMAND_LEVEL 3
#define COMMAND_CLASS 4
#define COMMAND_NAME 6
#define COMMAND_SAY 7
#define COMMAND_TELL 8
#define COMMAND_YELL 9
#define COMMAND_SHOUT 10
#define COMMAND_AUCTION 11
#define COMMAND_OOC 12
#define COMMAND_EMOTE 13
#define COMMAND_GROUPSAY 14
#define COMMAND_GROUPINVITE 15
#define COMMAND_GROUPDISBAND 16
#define COMMAND_GROUP 17
#define COMMAND_CLAIM 18
#define COMMAND_HAIL 19
#define COMMAND_ZONE 20
#define COMMAND_ADMINFLAG 21
#define COMMAND_KICK 22
#define COMMAND_BAN 23
#define COMMAND_INVENTORY 24
#define COMMAND_SUMMONITEM 25
#define COMMAND_FOLLOW 26
#define COMMAND_STOP_FOLLOW 27
#define COMMAND_LASTNAME 28
#define COMMAND_CONFIRMLASTNAME 29
#define COMMAND_COLLECTION_ADDITEM 30
#define COMMAND_COLLECTION_FILTER_MATCHITEM 31
#define COMMAND_MOVE 32
#define COMMAND_INFO 33
#define COMMAND_USEABILITY 34
#define COMMAND_ENABLE_ABILITY_QUE 35
#define COMMAND_RELOAD_ITEMS 36
#define COMMAND_AUTO_ATTACK 37
#define COMMAND_WEATHER 38
#define COMMAND_SPEED 39
#define COMMAND_SPAWN_MOVE 40
#define COMMAND_WHO 41
#define COMMAND_VERSION 42
#define COMMAND_SPAWN_ADD 43
#define COMMAND_SPAWN_CREATE 44
#define COMMAND_SPAWN_SET 45
#define COMMAND_SPAWN_REMOVE 46
#define COMMAND_SPAWN_LIST 47
#define COMMAND_SIT 48
#define COMMAND_STAND 49
#define COMMAND_SPAWN_TARGET 50
#define COMMAND_SPAWN_EQUIPMENT 51
#define COMMAND_SPAWN_DETAILS 52
#define COMMAND_SELECT_JUNCTION 53
#define COMMAND_KILL 54
#define COMMAND_SUMMON 55
#define COMMAND_GOTO 56
#define COMMAND_FLYMODE 57
#define COMMAND_SETTIME 58
#define COMMAND_RELOAD_SPELLS 59
#define COMMAND_LOOT 60
#define COMMAND_USE 61
#define COMMAND_RELOADSPAWNSCRIPTS 62
#define COMMAND_RELOADLUASYSTEM 63
#define COMMAND_RELOADSTRUCTS 64
#define COMMAND_RELOAD 65
#define COMMAND_LOOT_LIST 66
#define COMMAND_LOOT_SETCOIN 67
#define COMMAND_LOOT_ADDITEM 68
#define COMMAND_LOOT_REMOVEITEM 69
#define COMMAND_BANK 70
#define COMMAND_BANK_DEPOSIT 71
#define COMMAND_BANK_WITHDRAWAL 72
#define COMMAND_BANK_CANCEL 73
#define COMMAND_ATTACK 74
#define COMMAND_REPORT_BUG 75
#define COMMAND_ACCEPT_QUEST 76
#define COMMAND_DECLINE_QUEST 77
#define COMMAND_DELETE_QUEST 78
#define COMMAND_RELOAD_QUESTS 79
#define COMMAND_SPAWN_COMBINE 80
#define COMMAND_DEPOP 81
#define COMMAND_REPOP 82
#define COMMAND_LUADEBUG 83
#define COMMAND_TEST 84
#define COMMAND_ACCEPT_REWARD 85
#define COMMAND_FROM_MERCHANT 86
#define COMMAND_MERCHANT_BUY 87
#define COMMAND_MERCHANT_SELL 88
#define COMMAND_CANCEL_MERCHANT 89
#define COMMAND_START_MERCHANT 90
#define COMMAND_BUYBACK 91
#define COMMAND_SEARCH_STORES 92
#define COMMAND_INVULNERABLE 93
#define COMMAND_SEARCH_STORES_PAGE 94
#define COMMAND_BUY_FROM_BROKER 95
#define COMMAND_GROUP_ACCEPT_INVITE 96
#define COMMAND_GROUP_DECLINE_INVITE 97
#define COMMAND_RELOAD_GROUNDSPAWNS 98
#define COMMAND_RELOAD_SPAWNS 99
#define COMMAND_LOCK 100
#define COMMAND_GIVEITEM 101
#define COMMAND_SET_COMBAT_VOICE 102
#define COMMAND_SET_EMOTE_VOICE 103
#define COMMAND_RELOAD_ZONESCRIPTS 104
#define COMMAND_GROUP_LEAVE 105
#define COMMAND_GROUP_MAKE_LEADER 106
#define COMMAND_GROUP_KICK 107
#define COMMAND_FRIEND_ADD 108
#define COMMAND_FRIEND_REMOVE 109
#define COMMAND_FRIENDS 110
#define COMMAND_IGNORE_ADD 111
#define COMMAND_IGNORE_REMOVE 112
#define COMMAND_IGNORES 113
#define COMMAND_MENDER_REPAIR 114
#define COMMAND_MENDER_REPAIR_ALL 115
#define COMMAND_REPAIR 116
#define COMMAND_USE_ITEM 117
#define COMMAND_WEAPONSTATS 118
#define COMMAND_START_MAIL 119
#define COMMAND_GET_MAIL_MESSAGE 120
#define COMMAND_TAKE_MAIL_ATTACHMENTS 121
#define COMMAND_REPORT_SPAM 122
#define COMMAND_CANCEL_MAIL 123
#define COMMAND_ADD_MAIL_PLAT 124
#define COMMAND_ADD_MAIL_GOLD 125
#define COMMAND_ADD_MAIL_SILVER 126
#define COMMAND_ADD_MAIL_COPPER 127
#define COMMAND_SET_MAIL_ITEM 128
#define COMMAND_CANCEL_SEND_MAIL 129
#define COMMAND_REMOVE_MAIL_PLAT 130
#define COMMAND_REMOVE_MAIL_GOLD 131
#define COMMAND_REMOVE_MAIL_SILVER 132
#define COMMAND_REMOVE_MAIL_COPPER 133
#define COMMAND_DELETE_MAIL_MESSAGE 134
#define COMMAND_TRACK 135
#define COMMAND_INSPECT_PLAYER 136
#define COMMAND_PET 137
#define COMMAND_PETNAME 138
#define COMMAND_NAME_PET 139
#define COMMAND_RENAME 140
#define COMMAND_CONFIRMRENAME 141
#define COMMAND_PETOPTIONS 142
#define COMMAND_SPAWN_TEMPLATE 143 // JA: new /spawn template command
#define COMMAND_CANNEDEMOTE 144
#define COMMAND_BROADCAST 145
#define COMMAND_ANNOUNCE 146
#define COMMAND_AFK 147
#define COMMAND_TOGGLE_ANONYMOUS 148
#define COMMAND_TOGGLE_LFW 149
#define COMMAND_TOGGLE_LFG 150
#define COMMAND_SHOW_RANGED 151
#define COMMAND_TOGGLE_AUTOCONSUME 152
#define COMMAND_SHOW_HELM 153
#define COMMAND_SHOW_HOOD_OR_HELM 154
#define COMMAND_SHOW_CLOAK 155
#define COMMAND_STOP_EATING 156
#define COMMAND_STOP_DRINKING 157
#define COMMAND_TOGGLE_ILLUSIONS 158
#define COMMAND_SHOW_HOOD 159
#define COMMAND_TOGGLE_DUELS 160
#define COMMAND_TOGGLE_TRADES 161
#define COMMAND_TOGGLE_GUILDS 162
#define COMMAND_TOGGLE_GROUPS 163
#define COMMAND_TOGGLE_RAIDS 164
#define COMMAND_TOGGLE_LON 165
#define COMMAND_TOGGLE_GM_HIDE 167
#define COMMAND_TOGGLE_GM_VANISH 168
#define COMMAND_SPAWN_GROUP 169
#define COMMAND_TOGGLE_ROLEPLAYING 170
#define COMMAND_TOGGLE_VCINVITE 171
#define COMMAND_START_TRADE 172
#define COMMAND_ACCEPT_TRADE 173
#define COMMAND_REJECT_TRADE 174
#define COMMAND_CANCEL_TRADE 175
#define COMMAND_SET_TRADE_COIN 176
#define COMMAND_ADD_TRADE_COPPER 177
#define COMMAND_ADD_TRADE_SILVER 178
#define COMMAND_ADD_TRADE_GOLD 179
#define COMMAND_ADD_TRADE_PLAT 180
#define COMMAND_REMOVE_TRADE_COPPER 181
#define COMMAND_REMOVE_TRADE_SILVER 182
#define COMMAND_REMOVE_TRADE_GOLD 183
#define COMMAND_REMOVE_TRADE_PLAT 184
#define COMMAND_ADD_TRADE_ITEM 185
#define COMMAND_REMOVE_TRADE_ITEM 186
#define COMMAND_TOGGLE_COMBAT_EXP 187
#define COMMAND_TOGGLE_QUEST_EXP 188
#define COMMAND_TOGGLE_BONUS_EXP 189
#define COMMAND_ZONE_SHUTDOWN 190
#define COMMAND_ZONE_SAFE 191
#define COMMAND_ZONE_REVIVE 192
#define COMMAND_RELOAD_ZONES 193
#define COMMAND_DUEL 200
#define COMMAND_DUELBET 201
#define COMMAND_DUEL_ACCEPT 202
#define COMMAND_DUEL_DECLINE 203
#define COMMAND_DUEL_SURRENDER 204
#define COMMAND_DUEL_TOGGLE 205
#define COMMAND_ANIMTEST 211
#define COMMAND_ITEMSEARCH 212
#define COMMAND_ACTION 232 // JA: What is this? Exists nowhere else...
#define COMMAND_SKILL_ADD 233
#define COMMAND_SKILL_REMOVE 234
#define COMMAND_SKILL_LIST 235
#define COMMAND_SKILL 236
#define COMMAND_ZONE_SET 237
#define COMMAND_ZONE_DETAILS 238
#define COMMAND_RANDOMIZE 239
#define COMMAND_RELOAD_ENTITYCOMMANDS 240
#define COMMAND_ENTITYCOMMAND 241
#define COMMAND_ENTITYCOMMAND_LIST 242
#define COMMAND_RELOAD_FACTIONS 243
#define COMMAND_MERCHANT 244
#define COMMAND_MERCHANT_LIST 245
#define COMMAND_APPEARANCE 246
#define COMMAND_APPEARANCE_LIST 247
#define COMMAND_RELOAD_MAIL 248
#define COMMAND_DISTANCE 249
#define COMMAND_GUILDSAY 250
#define COMMAND_OFFICERSAY 251
#define COMMAND_GUILD 252
#define COMMAND_SET_GUILD_MEMBER_NOTE 253
#define COMMAND_SET_GUILD_OFFICER_NOTE 254
#define COMMAND_RELOAD_GUILDS 255
#define COMMAND_CREATE 256
#define COMMAND_CREATE_GUILD 257
#define COMMAND_GUILDS 258
#define COMMAND_GUILDS_CREATE 259
#define COMMAND_GUILDS_DELETE 260
#define COMMAND_GUILDS_ADD 261
#define COMMAND_GUILDS_REMOVE 262
#define COMMAND_GUILDS_LIST 263
#define COMMAND_LOTTO 264
#define COMMAND_CLEAR_ALL_QUEUED 265
#define COMMAND_SCRIBE_SCROLL_ITEM 266
#define COMMAND_RELOAD_LOCATIONS 267
#define COMMAND_LOCATION 268
#define COMMAND_LOCATION_CREATE 269
#define COMMAND_LOCATION_ADD 270
#define COMMAND_GRID 271
#define COMMAND_LOCATION_REMOVE 272
#define COMMAND_LOCATION_DELETE 273
#define COMMAND_LOCATION_LIST 274
#define COMMAND_USE_EQUIPPED_ITEM 275
#define COMMAND_CANCEL_MAINTAINED 276
#define COMMAND_LOOT_CORPSE 277
#define COMMAND_MOTD 278
#define COMMAND_RANDOM 279
#define COMMAND_TRY_ON 280
#define COMMAND_TITLE 281
#define COMMAND_GUILD_BANK 282
#define COMMAND_GUILD_BANK_DEPOSIT 283
#define COMMAND_GUILD_BANK_WITHDRAWAL 284
#define COMMAND_GUILD_BANK_CANCEL 285
#define COMMAND_TITLE_LIST 286
#define COMMAND_TITLE_SETPREFIX 287
#define COMMAND_TITLE_SETSUFFIX 288
#define COMMAND_TITLE_FIX 289
#define COMMAND_LANGUAGES 290
#define COMMAND_SET_LANGUAGE 291
#define COMMAND_ACCEPT_ADVANCEMENT 293
#define COMMAND_JOIN_CHANNEL 294
#define COMMAND_JOIN_CHANNEL_FROM_LOAD 295
#define COMMAND_TELL_CHANNEL 296
#define COMMAND_LEAVE_CHANNEL 297
#define COMMAND_WHO_CHANNEL 298
#define COMMAND_CREATEFROMRECIPE 299
#define COMMAND_RAIN 300
#define COMMAND_TO_MERCHANT 301
#define COMMAND_SELECT 302
#define COMMAND_SMP 303
#define COMMAND_CONSUME_FOOD 304
#define COMMAND_AQUAMAN 305
#define COMMAND_ATTUNE_INV 306
#define COMMAND_PLAYER 307
#define COMMAND_PLAYER_COINS 308
#define COMMAND_RESET_ZONE_TIMER 309
#define COMMAND_ACHIEVEMENT_ADD 310
#define COMMAND_EDITOR 311
#define COMMAND_ACCEPT_RESURRECTION 312
#define COMMAND_DECLINE_RESURRECTION 313
#define COMMAND_WIND 314
#define COMMAND_TARGETITEM 315
#define COMMAND_READ 463
#define COMMAND_BOT 500
#define COMMAND_BOT_CREATE 501
#define COMMAND_BOT_CUSTOMIZE 502
#define COMMAND_BOT_SPAWN 503
#define COMMAND_BOT_LIST 504
#define COMMAND_BOT_INV 505
#define COMMAND_BOT_SETTINGS 506
#define COMMAND_BOT_HELP 507
#define COMMAND_OPEN 508
#define COMMAND_CASTSPELL 509
#define COMMAND_DISARM 510
#define COMMAND_KNOWLEDGEWINDOWSORT 511
#define COMMAND_PLACE_HOUSE_ITEM 512
#define COMMAND_GM 513
#define COMMAND_HOUSE_UI 514
#define COMMAND_HOUSE 515
#define COMMAND_MOVE_ITEM 516
#define COMMAND_PICKUP 517
#define COMMAND_HOUSE_DEPOSIT 518
#define COMMAND_RELOAD_RULES 519
#define COMMAND_RELOAD_TRANSPORTERS 520
#define COMMAND_FINDSPAWN 521
#define COMMAND_RELOAD_STARTABILITIES 522
#define COMMAND_WAYPOINT 523
#define COMMAND_RELOADREGIONSCRIPTS 524
#define COMMAND_MOVECHARACTER 525
#define COMMAND_CRAFTITEM 526
#define COMMAND_FROMBROKER 527
#define COMMAND_MENTOR 528
#define COMMAND_UNMENTOR 529
#define COMMAND_CANCEL_EFFECT 530
#define COMMAND_CUREPLAYER 531
#define COMMAND_RELOAD_VOICEOVERS 532
#define COMMAND_SHARE_QUEST 533
#define COMMAND_SETAUTOLOOTMODE 534
#define COMMAND_ASSIST 535
#define COMMAND_TARGET 536
#define COMMAND_TARGET_PET 537
#define COMMAND_SET_CONSUME_FOOD 538
#define GET_AA_XML 750
#define ADD_AA 751
#define COMMIT_AA_PROFILE 752
#define BEGIN_AA_PROFILE 753
#define BACK_AA 754
#define REMOVE_AA 755
#define SWITCH_AA_PROFILE 756
#define CANCEL_AA_PROFILE 757
#define SAVE_AA_PROFILE 758
#define COMMAND_MOOD 800
#define COMMAND_MODIFY 1000 // INSERT INTO `commands`(`id`,`type`,`command`,`subcommand`,`handler`,`required_status`) VALUES ( NULL,'1','modify','','1000','200');
#define COMMAND_MODIFY_CHARACTER 1001
#define COMMAND_MODIFY_FACTION 1002
#define COMMAND_MODIFY_GUILD 1003
#define COMMAND_MODIFY_ITEM 1004
#define COMMAND_MODIFY_QUEST 1005
#define COMMAND_MODIFY_SKILL 1006
#define COMMAND_MODIFY_SPAWN 1007
#define COMMAND_MODIFY_SPELL 1008
#define COMMAND_MODIFY_ZONE 1009
#endif

View File

@ -0,0 +1,316 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef WIN32
#include <WinSock2.h>
#include <windows.h>
#endif
#include <mysql.h>
#include <assert.h>
#include "../../common/Log.h"
#include "../WorldDatabase.h"
#include "Commands.h"
#include "ConsoleCommands.h"
map<int32, string>* WorldDatabase::GetSpawnTemplateListByName(const char* name)
{
LogWrite(COMMAND__DEBUG, 0, "Command", "Player listing spawn templates by template name ('%s')...", name);
map<int32, string>* ret = 0;
string template_name = "";
Query query;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, name FROM spawn_templates WHERE name RLIKE '%s' LIMIT 0,10", getSafeEscapeString(name).c_str());
if(result && mysql_num_rows(result) > 0)
{
ret = new map<int32, string>;
MYSQL_ROW row;
while(result && (row = mysql_fetch_row(result)))
{
template_name = string(row[1]);
(*ret)[atoul(row[0])] = template_name;
LogWrite(COMMAND__DEBUG, 5, "Command", "\t%u. '%s'", atoul(row[0]), template_name.c_str());
}
}
return ret;
}
map<int32, string>* WorldDatabase::GetSpawnTemplateListByID(int32 location_id)
{
LogWrite(COMMAND__DEBUG, 0, "Command", "Player listing spawn templates by LocaionID: %u...", location_id);
map<int32, string>* ret = 0;
string template_name = "";
Query query;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, name FROM spawn_templates WHERE spawn_location_id = %u", location_id);
if(result && mysql_num_rows(result) > 0)
{
ret = new map<int32, string>;
MYSQL_ROW row;
while(result && (row = mysql_fetch_row(result)))
{
template_name = string(row[1]);
(*ret)[atoul(row[0])] = template_name;
LogWrite(COMMAND__DEBUG, 5, "Command", "\t%u. '%s'", atoul(row[0]), template_name.c_str());
}
}
return ret;
}
int32 WorldDatabase::SaveSpawnTemplate(int32 placement_id, const char* template_name)
{
Query query;
string str_name = getSafeEscapeString(template_name).c_str();
LogWrite(COMMAND__DEBUG, 0, "Command", "Player saving spawn template '%s' for placement_id %u...", str_name.c_str(), placement_id);
query.RunQuery2(Q_INSERT, "INSERT INTO spawn_templates (name, spawn_location_id) VALUES ('%s', %u)", str_name.c_str(), placement_id);
if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
LogWrite(COMMAND__ERROR, 0, "Command", "Error in SaveSpawnTemplate query '%s': %s", query.GetQuery(), query.GetError());
return 0;
}
int32 ret = query.GetLastInsertedID();
LogWrite(COMMAND__DEBUG, 0, "Command", "Success! Returning TemplateID: %u...", ret);
return ret;
}
bool WorldDatabase::RemoveSpawnTemplate(int32 template_id)
{
Query query;
LogWrite(COMMAND__DEBUG, 0, "Command", "Player removing spawn template ID %u...", template_id);
query.RunQuery2(Q_DELETE, "DELETE FROM spawn_templates WHERE id = %u", template_id);
if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
LogWrite(COMMAND__ERROR, 0, "Command", "Error in RemoveSpawnTemplate query '%s': %s", query.GetQuery(), query.GetError());
return false;
}
if (query.GetAffectedRows() > 0 )
{
LogWrite(COMMAND__DEBUG, 0, "Command", "Success! Removed spawn template ID %u...", template_id);
return true;
}
return false;
}
int32 WorldDatabase::CreateSpawnFromTemplateByID(Client* client, int32 template_id)
{
Query query, query2, query3, query4, query5, query6;
MYSQL_ROW row;
int32 spawn_location_id = 0;
float new_x = client->GetPlayer()->GetX();
float new_y = client->GetPlayer()->GetY();
float new_z = client->GetPlayer()->GetZ();
float new_heading = client->GetPlayer()->GetHeading();
LogWrite(COMMAND__DEBUG, 0, "Command", "Creating spawn point from templateID %u...", template_id);
LogWrite(COMMAND__DEBUG, 5, "Command", "\tCoords: %.2f %.2f %.2f...", new_x, new_y, new_z);
// find the spawn_location_id in the template we plan to duplicate
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT spawn_location_id FROM spawn_templates WHERE id = %u", template_id);
if (result && (row = mysql_fetch_row(result))) {
if (row[0])
spawn_location_id = atoi(row[0]);
}
if( spawn_location_id > 0 )
{
LogWrite(COMMAND__DEBUG, 5, "Command", "\tUsing LocationID: %u...", spawn_location_id);
// insert a new spawn_location_name record
string name = "TemplateGenerated";
query2.RunQuery2(Q_INSERT, "INSERT INTO spawn_location_name (name) VALUES ('%s')", name.c_str());
if(query2.GetErrorNumber() && query2.GetError() && query2.GetErrorNumber() < 0xFFFFFFFF){
LogWrite(COMMAND__ERROR, 0, "Command", "Error in CreateSpawnFromTemplateByID query '%s': %s", query2.GetQuery(), query2.GetError());
return 0;
}
int32 new_location_id = query2.GetLastInsertedID();
LogWrite(COMMAND__DEBUG, 5, "Command", "Created new Spawn Location: '%s' (%u)", name.c_str(), new_location_id);
// get all spawn_location_entries that match the templates spawn_location_id value and insert as new
LogWrite(COMMAND__DEBUG, 5, "Command", "Finding existing spawn_location_entry(s) for location_id %u", spawn_location_id);
MYSQL_RES* result2 = query3.RunQuery2(Q_SELECT, "SELECT spawn_id, spawnpercentage FROM spawn_location_entry WHERE spawn_location_id = %u", spawn_location_id);
if(result2 && mysql_num_rows(result2) > 0){
MYSQL_ROW row2;
while(result2 && (row2 = mysql_fetch_row(result2)) && row2[0])
{
query4.RunQuery2(Q_INSERT, "INSERT INTO spawn_location_entry (spawn_id, spawn_location_id, spawnpercentage) VALUES (%u, %u, %i)",
atoul(row2[0]), new_location_id, atoi(row2[1]));
if(query4.GetErrorNumber() && query4.GetError() && query4.GetErrorNumber() < 0xFFFFFFFF){
LogWrite(COMMAND__ERROR, 0, "Command", "Error in CreateSpawnFromTemplateByID query '%s': %s", query4.GetQuery(), query4.GetError());
return 0;
}
LogWrite(COMMAND__DEBUG, 5, "Command", "Insert Entry for spawn_id %u, location_id %u, percentage %i", atoul(row2[0]), new_location_id, atoi(row2[1]));
}
}
// get all spawn_location_placements that match the templates spawn_location_id value and insert as new
// Note: /spawn templates within current zone_id only, because of spawn_id issues (cannot template an Antonic spawn in Commonlands)
LogWrite(COMMAND__DEBUG, 5, "Command", "Finding existing spawn_location_placement(s) for location_id %u", spawn_location_id);
MYSQL_RES* result3 = query5.RunQuery2(Q_SELECT, "SELECT zone_id, x_offset, y_offset, z_offset, respawn, expire_timer, expire_offset, grid_id FROM spawn_location_placement WHERE spawn_location_id = %u", spawn_location_id);
if(result3 && mysql_num_rows(result3) > 0){
MYSQL_ROW row3;
while(result3 && (row3 = mysql_fetch_row(result3)) && row3[0])
{
query6.RunQuery2(Q_INSERT, "INSERT INTO spawn_location_placement (zone_id, spawn_location_id, x, y, z, heading, x_offset, y_offset, z_offset, respawn, expire_timer, expire_offset, grid_id) VALUES (%i, %u, %2f, %2f, %2f, %2f, %2f, %2f, %2f, %i, %i, %i, %u)",
atoi(row3[0]), new_location_id, new_x, new_y, new_z, new_heading, atof(row3[1]), atof(row3[2]), atof(row3[3]), atoi(row3[4]), atoi(row3[5]), atoi(row3[6]), atoul(row3[7]));
if(query6.GetErrorNumber() && query6.GetError() && query6.GetErrorNumber() < 0xFFFFFFFF){
LogWrite(COMMAND__ERROR, 0, "Command", "Error in CreateSpawnFromTemplateByID query '%s': %s", query6.GetQuery(), query6.GetError());
return 0;
}
LogWrite(COMMAND__DEBUG, 5, "Command", "Insert Placement at new coords for location_id %u", new_location_id);
}
}
LogWrite(COMMAND__DEBUG, 0, "Command", "Success! New spawn(s) from TemplateID %u created from location %u", template_id, spawn_location_id);
return new_location_id;
}
return 0;
}
int32 WorldDatabase::CreateSpawnFromTemplateByName(Client* client, const char* template_name)
{
Query query, query1, query2, query3, query4, query5, query6;
MYSQL_ROW row;
int32 template_id = 0;
int32 spawn_location_id = 0;
float new_x = client->GetPlayer()->GetX();
float new_y = client->GetPlayer()->GetY();
float new_z = client->GetPlayer()->GetZ();
float new_heading = client->GetPlayer()->GetHeading();
LogWrite(COMMAND__DEBUG, 0, "Command", "Creating spawn point from template '%s'...", template_name);
LogWrite(COMMAND__DEBUG, 5, "Command", "\tCoords: %.2f %.2f %.2f...", new_x, new_y, new_z);
// find the spawn_location_id in the template we plan to duplicate
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, spawn_location_id FROM spawn_templates WHERE name = '%s'", template_name);
if (result && (row = mysql_fetch_row(result))) {
if (row[0])
{
template_id = atoul(row[0]);
spawn_location_id = atoi(row[1]);
}
}
if( spawn_location_id > 0 )
{
LogWrite(COMMAND__DEBUG, 5, "Command", "\tUsing LocationID: %u...", spawn_location_id);
// insert a new spawn_location_name record
string name = "TemplateGenerated";
query2.RunQuery2(Q_INSERT, "INSERT INTO spawn_location_name (name) VALUES ('%s')", name.c_str());
if(query2.GetErrorNumber() && query2.GetError() && query2.GetErrorNumber() < 0xFFFFFFFF){
LogWrite(COMMAND__ERROR, 0, "Command", "Error in CreateSpawnFromTemplateByID query '%s': %s", query2.GetQuery(), query2.GetError());
return 0;
}
int32 new_location_id = query2.GetLastInsertedID();
LogWrite(COMMAND__DEBUG, 5, "Command", "Created new Spawn Location: '%s' (%u)", name.c_str(), new_location_id);
// get all spawn_location_entries that match the templates spawn_location_id value and insert as new
LogWrite(COMMAND__DEBUG, 5, "Command", "Finding existing spawn_location_entry(s) for location_id %u", spawn_location_id);
MYSQL_RES* result2 = query3.RunQuery2(Q_SELECT, "SELECT spawn_id, spawnpercentage FROM spawn_location_entry WHERE spawn_location_id = %u", spawn_location_id);
if(result2 && mysql_num_rows(result2) > 0){
MYSQL_ROW row2;
while(result2 && (row2 = mysql_fetch_row(result2)) && row2[0])
{
query4.RunQuery2(Q_INSERT, "INSERT INTO spawn_location_entry (spawn_id, spawn_location_id, spawnpercentage) VALUES (%u, %u, %i)",
atoul(row2[0]), new_location_id, atoi(row2[1]));
if(query4.GetErrorNumber() && query4.GetError() && query4.GetErrorNumber() < 0xFFFFFFFF){
LogWrite(COMMAND__ERROR, 0, "Command", "Error in CreateSpawnFromTemplateByID query '%s': %s", query4.GetQuery(), query4.GetError());
return 0;
}
LogWrite(COMMAND__DEBUG, 5, "Command", "Insert Entry for spawn_id %u, location_id %u, percentage %i", atoul(row2[0]), new_location_id, atoi(row2[1]));
}
}
// get all spawn_location_placements that match the templates spawn_location_id value and insert as new
// Note: /spawn templates within current zone_id only, because of spawn_id issues (cannot template an Antonic spawn in Commonlands)
LogWrite(COMMAND__DEBUG, 5, "Command", "Finding existing spawn_location_placement(s) for location_id %u", spawn_location_id);
MYSQL_RES* result3 = query5.RunQuery2(Q_SELECT, "SELECT zone_id, x_offset, y_offset, z_offset, respawn, expire_timer, expire_offset, grid_id FROM spawn_location_placement WHERE spawn_location_id = %u", spawn_location_id);
if(result3 && mysql_num_rows(result3) > 0){
MYSQL_ROW row3;
while(result3 && (row3 = mysql_fetch_row(result3)) && row3[0])
{
query6.RunQuery2(Q_INSERT, "INSERT INTO spawn_location_placement (zone_id, spawn_location_id, x, y, z, heading, x_offset, y_offset, z_offset, respawn, expire_timer, expire_offset, grid_id) VALUES (%i, %u, %2f, %2f, %2f, %2f, %2f, %2f, %2f, %i, %i, %i, %u)",
atoi(row3[0]), new_location_id, new_x, new_y, new_z, new_heading, atof(row3[1]), atof(row3[2]), atof(row3[3]), atoi(row3[4]), atoi(row3[5]), atoi(row3[6]), atoul(row3[7]));
if(query6.GetErrorNumber() && query6.GetError() && query6.GetErrorNumber() < 0xFFFFFFFF){
LogWrite(COMMAND__ERROR, 0, "Command", "Error in CreateSpawnFromTemplateByID query '%s': %s", query6.GetQuery(), query6.GetError());
return 0;
}
LogWrite(COMMAND__DEBUG, 5, "Command", "Insert Placement at new coords for location_id %u", new_location_id);
}
}
LogWrite(COMMAND__DEBUG, 0, "Command", "Success! New spawn(s) from TemplateID %u created from location %u", template_id, spawn_location_id);
return new_location_id;
}
return 0;
}
bool WorldDatabase::SaveZoneSafeCoords(int32 zone_id, float x, float y, float z, float heading)
{
Query query;
LogWrite(COMMAND__DEBUG, 0, "Command", "Setting safe coords for zone %u (X: %.2f, Y: %.2f, Z: %.2f, H: %.2f)", zone_id, x, y, z, heading);
query.RunQuery2(Q_UPDATE, "UPDATE zones SET safe_x = %f, safe_y = %f, safe_z = %f, safe_heading = %f WHERE id = %u", x, y, z, heading, zone_id);
if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
LogWrite(DATABASE__ERROR, 0, "DBCore", "Error in SaveZoneSafeCoords query '%s': %s", query.GetQuery(), query.GetError());
return false;
}
if (query.GetAffectedRows() > 0 )
{
LogWrite(COMMAND__DEBUG, 0, "Command", "Success! Set new safe coordinates in zone ID %u...", zone_id);
return true;
}
LogWrite(COMMAND__ERROR, 0, "Command", "FAILED! Set new safe coordinates in zone ID %u...", zone_id);
return false;
}
bool WorldDatabase::SaveSignZoneToCoords(int32 spawn_id, float x, float y, float z, float heading)
{
Query query;
LogWrite(COMMAND__DEBUG, 0, "Command", "Setting Zone-To coords for Spawn ID %u (X: %.2f, Y: %.2f, Z: %.2f, H: %.2f)", spawn_id, x, y, z, heading);
query.RunQuery2(Q_UPDATE, "UPDATE spawn_signs SET zone_x = %f, zone_y = %f, zone_z = %f, zone_heading = %f WHERE spawn_id = %u", x, y, z, heading, spawn_id);
if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
LogWrite(DATABASE__ERROR, 0, "DBCore", "Error in SaveSignZoneToCoords query '%s': %s", query.GetQuery(), query.GetError());
return false;
}
if (query.GetAffectedRows() > 0 )
{
LogWrite(COMMAND__DEBUG, 0, "Command", "Success! Set new Zone-To coordinates in zone ID %u...", spawn_id);
return true;
}
LogWrite(COMMAND__ERROR, 0, "Command", "FAILED! Set new Zone-To coordinates in zone ID %u...", spawn_id);
return false;
}

View File

@ -0,0 +1,549 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "../../common/debug.h"
#include "../../common/Log.h"
#include "../../common/seperator.h"
#include "ConsoleCommands.h"
#include "../World.h"
#include "../Rules/Rules.h"
#include "../WorldDatabase.h"
extern volatile bool RunLoops;
bool ContinueLoops = false;
extern Variables variables;
extern ZoneList zone_list;
extern RuleManager rule_manager;
extern WorldDatabase database;
void ProcessConsoleInput(const char * cmdInput)
{
static ConsoleCommand Commands[] = {
// account controls
{ &ConsoleBanCommand, "ban", "[player] {duration} {reason}", "Ban player with {optional} duration and reason." },
{ &ConsoleUnbanCommand, "unban", "[player]", "Unban a player." },
{ &ConsoleKickCommand, "kick", "[player] {reason}", "Kick player with {optional} reason." },
// chat controls
{ &ConsoleAnnounceCommand, "announce", "[message]", "Sends Announcement message to all channels/clients." },
{ &ConsoleBroadcastCommand, "broadcast","[message]", "Sends Broadcast message to all channels/clients." },
{ &ConsoleChannelCommand, "channel", "[channel] [message]", "Sends Channel message to channel." },
{ &ConsoleTellCommand, "tell", "[player] [message]", "Sends Private message to player." },
// world system controls
{ &ConsoleGuildCommand, "guild", "[params]", "" },
{ &ConsolePlayerCommand, "player", "[params]", "" },
{ &ConsoleSetAdminPlayer, "makeadmin", "[charname] [status=0]", "" },
{ &ConsoleZoneCommand, "zone", "[command][value]", "command = help to get help" },
{ &ConsoleWorldCommand, "world", "[params]", "" },
{ &ConsoleGetMOTDCommand, "getmotd", "", "Display current MOTD" },
{ &ConsoleSetMOTDCommand, "setmotd", "[new motd]", "Sets a new MOTD" },
/// misc controls
{ &ConsoleWhoCommand, "who", "{zone id | player}", "Shows who is online globally, or in a given zone." },
{ &ConsoleReloadCommand, "reload", "[all | [type]]", "Reload main systems." },
{ &ConsoleRulesCommand, "rules", "{zone} {id}", "Show Global Ruleset (or Zone ruleset {optional})" },
{ &ConsoleShutdownCommand, "shutdown", "[delay]", "Gracefully shutdown world in [delay] sesconds." },
{ &ConsoleCancelShutdownCommand,"cancel", "", "Cancel shutdown command." },
{ &ConsoleExitCommand, "exit", "", "Brutally kills the world without mercy." },
{ &ConsoleExitCommand, "quit", "", "Brutally kills the world without mercy." },
{ &ConsoleTestCommand, "test", "", "Dev testing command." },
{ NULL, NULL, NULL, NULL },
};
Seperator *sep = new Seperator(cmdInput, ' ', 20, 100, true);
bool found = false;
uint32 i;
if (!sep)
return;
if (!strcasecmp(sep->arg[0], "help") || sep->arg[0][0] == 'h' || sep->arg[0][0] == 'H' || sep->arg[0][0] == '?') {
found = true;
printf("======================================================================================================\n");
printf("| %10s | %30s | %52s |\n", "Name", "Params", "Description");
printf("======================================================================================================\n");
for (i = 0; Commands[i].Name != NULL; i++) {
printf("| %10s | %30s | %52s |\n", Commands[i].Name, Commands[i].ParameterFormat, Commands[i].Description);
}
printf("======================================================================================================\n");
printf("-[ Help formatted for 120 chars wide screen ]-\n");
}
else {
for (i = 0; Commands[i].Name != NULL; ++i) {
if (!strcasecmp(Commands[i].Name, sep->arg[0])) {
found = true;
if (!Commands[i].CommandPointer(sep))
printf("\nError, incorrect syntax for '%s'.\n Correct syntax is: '%s'.\n\n", Commands[i].Name, Commands[i].ParameterFormat );
}
}
}
if (!found)
printf("Invalid Command '%s'! Type '?' or 'help' to get a command list.\n\n", sep->arg[0]);
fflush(stdout);
delete sep;
}
/************************************************* COMMANDS *************************************************/
bool ConsoleBanCommand(Seperator *sep)
{
if( strlen(sep->arg[1]) == 0 )
return false;
return true;
}
bool ConsoleUnbanCommand(Seperator *sep)
{
if( strlen(sep->arg[1]) == 0 )
return false;
return true;
}
bool ConsoleKickCommand(Seperator *sep)
{
if( strlen(sep->arg[1]) == 0 )
return false;
return true;
}
bool ConsoleAnnounceCommand(Seperator *sep)
{
if( strlen(sep->arg[1]) == 0 )
return false;
return true;
}
bool ConsoleBroadcastCommand(Seperator *sep)
{
if( strlen(sep->arg[1]) == 0 )
return false;
char message[4096];
snprintf(message, sizeof(message), "%s %s", "BROADCAST:", sep->argplus[1]);
zone_list.HandleGlobalBroadcast(message);
return true;
}
bool ConsoleChannelCommand(Seperator *sep)
{
if( strlen(sep->arg[1]) == 0 )
return false;
return true;
}
bool ConsoleTellCommand(Seperator *sep)
{
if( strlen(sep->arg[1]) == 0 )
return false;
return true;
}
bool ConsoleWhoCommand(Seperator *sep)
{
// zone_list.ProcessWhoQuery(who, client);
if (!strcasecmp(sep->arg[1], "zone")) {
printf("Who's Online in Zone");
if (sep->IsNumber(2)) {
printf("ID %s:\n", sep->arg[2]);
printf("===============================================================================\n");
printf("| %10s | %62s |\n", "CharID", "Name");
printf("===============================================================================\n");
}
else {
printf(" '%s':\n", sep->arg[2]);
printf("===============================================================================\n");
printf("| %10s | %62s |\n", "CharID", "Name");
printf("===============================================================================\n");
}
}
else {
printf("Who's Online (Global):\n");
printf("===============================================================================\n");
printf("| %10s | %20s | %39s |\n", "CharID", "Name", "Zone");
printf("===============================================================================\n");
}
printf("Not Implemented... yet :)\n");
printf("===============================================================================\n");
return true;
}
bool ConsoleGuildCommand(Seperator *sep)
{
if( strlen(sep->arg[1]) == 0 )
return false;
return true;
}
bool ConsolePlayerCommand(Seperator *sep)
{
if( strlen(sep->arg[1]) == 0 )
return false;
return true;
}
bool ConsoleSetAdminPlayer(Seperator *sep)
{
if(!sep->arg[1] || strlen(sep->arg[1]) == 0)
return false;
sint16 status = 0;
if(sep->IsNumber(2))
status = atoi(sep->arg[2]);
Client* client = zone_list.GetClientByCharName(sep->arg[1]);
if(!client) {
printf("Client not found by char name, must be logged in\n");
return true;
}
if(!client->GetPlayer()) {
printf("Player is not available for client class, try again\n");
return true;
}
client->SetAdminStatus(status);
if(status)
client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Admin status updated.");
database.UpdateAdminStatus(client->GetPlayer()->GetName(), status);
printf("Admin status for %s is updated to %i\n", client->GetPlayer()->GetName(), status);
return true;
}
bool ConsoleWorldCommand(Seperator *sep)
{
if( strlen(sep->arg[1]) == 0 )
return false;
return true;
}
bool ConsoleZoneCommand(Seperator *sep)
{
if( strlen(sep->arg[1]) == 0 ) // has to be at least 1 arg (command)
return false;
ZoneServer* zone = 0;
if( strlen(sep->arg[2]) == 0 )
{
// process commands without values
if (!strcasecmp(sep->arg[1], "active") )
{
// not correct, but somehow need to access the Private zlist from World.h ???
list<ZoneServer*> zlist;
list<ZoneServer*>::iterator zone_iter;
ZoneServer* tmp = 0;
int zonesListed = 0;
printf("> List Active Zones...\n");
printf("======================================================================================================\n");
printf("| %7s | %30s | %10s | %42s |\n", "ID", "Name", "Instance", "Description");
printf("======================================================================================================\n");
for(zone_iter=zlist.begin(); zone_iter!=zlist.end(); zone_iter++){
tmp = *zone_iter;
zonesListed++;
printf("| %7d | %30s | %10d | %42s |\n", tmp->GetZoneID(), tmp->GetZoneName(), tmp->GetInstanceID(),tmp->GetZoneDescription());
}
return true;
}
else if (!strcasecmp(sep->arg[1], "help") || sep->arg[1][0] == '?')
{
printf("======================================================================================================\n");
printf("| %10s | %30s | %52s |\n", "Command", "Value", "Description");
printf("======================================================================================================\n");
printf("| %10s | %30s | %52s |\n", "active", "n/a", "List currently active zones");
printf("| %10s | %30s | %52s |\n", "list", "[name]", "Lookup zone by name");
printf("| %10s | %30s | %52s |\n", "status", "[zone_id | name | ALL]", "List zone stats");
printf("| %10s | %30s | %52s |\n", "lock", "[zone_id | name]", "Locks a zone");
printf("| %10s | %30s | %52s |\n", "unlock", "[zone_id | name]", "Unlocks a zone");
printf("| %10s | %30s | %52s |\n", "shutdown", "[zone_id | name | ALL]", "Gracefully shuts down a zone");
printf("| %10s | %30s | %52s |\n", "kill", "[zone_id | name | ALL]", "Terminates a zone");
printf("======================================================================================================\n");
return true;
}
else
return false;
}
else
{
if( !strcasecmp(sep->arg[1], "list") )
{
const char* name = 0;
name = sep->argplus[2];
map<int32, string>* zone_names = database.GetZoneList(name);
if(!zone_names)
{
printf("> No zones found.\n");
}
else
{
printf("> List zones matching '%s'...\n", sep->arg[2]);
printf("====================================================\n");
printf("| %3s | %42s |\n", "ID", "Name");
printf("====================================================\n");
map<int32, string>::iterator itr;
for(itr = zone_names->begin(); itr != zone_names->end(); itr++)
printf("| %3u | %42s |\n", itr->first, itr->second.c_str());
safe_delete(zone_names);
printf("====================================================\n");
}
return true;
}
if( !strcasecmp(sep->arg[1], "lock") )
{
if( sep->IsNumber(2) )
printf("> Locking zone ID %i...\n", atoul(sep->arg[2]));
else
printf("> Locking zone '%s'...\n", sep->arg[2]);
return true;
}
if( !strcasecmp(sep->arg[1], "unlock") )
{
if( strlen(sep->arg[2]) > 0 && sep->IsNumber(2) )
printf("> Unlocking zone ID %i...\n", atoi(sep->arg[2]));
else
printf("> Unlocking zone '%s'...\n", sep->arg[2]);
return true;
}
if( !strcasecmp(sep->arg[1], "status") )
{
if( sep->IsNumber(2) )
{
zone = zone_list.Get(atoi(sep->arg[2]), false, false, false);
if( zone )
{
printf("> Zone status for zone ID %i...\n", atoi(sep->arg[2]));
printf("============================================================================================\n");
printf("| %30s | %10s | %42s |\n", "Zone", "Param", "Value");
printf("============================================================================================\n");
printf("| %30s | %10s | %42s |\n", zone->GetZoneName(), "locked", zone->GetZoneLockState() ? "true" : "false");
}
else
{
printf("> Zone ID %i not running, so not locked.\n", atoi(sep->arg[2]));
}
}
else if( !strcasecmp(sep->arg[2], "ALL") )
{
printf("> Zone status for ALL active zones...\n");
}
else
{
printf("> Zone status for zone '%s'...\n", sep->arg[2]);
}
return true;
}
if( !strcasecmp(sep->arg[1], "shutdown") )
{
if( sep->IsNumber(2) )
printf("> Shutdown zone ID %i...\n", atoi(sep->arg[2]));
else if( !strcasecmp(sep->arg[2], "ALL") )
printf("> Shutdown ALL active zones...\n");
else
printf("> Shutdown zone '%s'...\n", sep->arg[2]);
return true;
}
if( !strcasecmp(sep->arg[1], "kill") )
{
if( sep->IsNumber(2) )
printf("> Kill zone ID %i...\n", atoi(sep->arg[2]));
else if( !strcasecmp(sep->arg[2], "ALL") )
printf("> Kill ALL active zones...\n");
else
printf("> Kill zone '%s'...\n", sep->arg[2]);
return true;
}
}
return false;
}
bool ConsoleGetMOTDCommand(Seperator *sep)
{
const char* motd = 0;
Variable* var = variables.FindVariable("motd");
if( var == NULL || strlen (var->GetValue()) == 0){
printf("No MOTD.");
}
else{
motd = var->GetValue();
printf("%s\n", motd);
}
return true;
}
bool ConsoleSetMOTDCommand(Seperator *sep)
{
if( strlen(sep->arg[1]) == 0 )
return false;
return true;
}
bool ConsoleReloadCommand(Seperator *sep)
{
#ifdef _WIN32
HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(console, FOREGROUND_YELLOW_BOLD);
#else
printf("\033[1;33m");
#endif
printf("Usage: ");
#ifdef _WIN32
SetConsoleTextAttribute(console, FOREGROUND_WHITE_BOLD);
#else
printf("\033[1;37m");
#endif
printf("reload [type]\n");
#ifdef _WIN32
SetConsoleTextAttribute(console, 8);
#else
printf("\033[0m");
#endif
printf("Valid [type] paramters are:\n");
printf("===============================================================================\n");
printf("| %21s | %51s |\n", "all", "Reloads all systems (why not just restart?)");
printf("| %21s | %51s |\n", "structs", "Reloads structs (XMLs)");
printf("| %21s | %51s |\n", "items", "Reload Items data");
printf("| %21s | %51s |\n", "luasystem", "Reload LUA System Scripts");
printf("| %21s | %51s |\n", "spawnscripts", "Reload SpawnScripts");
printf("| %21s | %51s |\n", "quests", "Reload Quest Data and Scripts");
printf("| %21s | %51s |\n", "spawns", "Reload ALL Spawns from DB");
printf("| %21s | %51s |\n", "groundspawn_items", "Reload Groundspawn Items lists");
printf("| %21s | %51s |\n", "zonescripts", "Reload Zone Scripts");
printf("| %21s | %51s |\n", "entity_commands", "Reload Entity Commands");
printf("| %21s | %51s |\n", "factions", "Reload Factions");
printf("| %21s | %51s |\n", "mail", "Reload in-game Mail data");
printf("| %21s | %51s |\n", "guilds", "Reload Guilds");
printf("| %21s | %51s |\n", "locations", "Reload Locations data");
printf("===============================================================================\n");
if( strlen(sep->arg[1]) > 0 ) {
// handle reloads here
if (!strcasecmp(sep->arg[1], "spawns"))
zone_list.ReloadSpawns();
}
return true;
}
bool ConsoleShutdownCommand(Seperator *sep)
{
if ( IsNumber(sep->arg[1]) ) {
int8 shutdown_delay = atoi(sep->arg[1]);
printf("Shutdown World in %i second(s)...\n", shutdown_delay);
// shutting down gracefully, warn players.
char message[4096];
snprintf(message, sizeof(message), "BROADCAST: Server is shutting down in %s second(s)", sep->arg[1]);
zone_list.HandleGlobalBroadcast(message);
Sleep(shutdown_delay * 1000);
}
else {
printf("Shutdown World immediately... you probably won't even see this message, huh!\n");
}
if( !ContinueLoops )
RunLoops = false;
return true;
}
bool ConsoleCancelShutdownCommand(Seperator *sep)
{
printf("Cancel World Shutdown...\n");
ContinueLoops = true;
return true;
}
bool ConsoleExitCommand(Seperator *sep)
{
// I wanted this to be a little more Terminate-y... killkillkill
printf("Terminate World immediately...\n");
RunLoops = false;
return true;
}
bool ConsoleRulesCommand(Seperator *sep)
{
/*if( strlen(sep->arg[1]) == 0 )
return false;*/
printf("Current Active Ruleset");
if (!strcasecmp(sep->arg[1], "zone"))
{
if (sep->IsNumber(2)) {
printf(" in Zone ID: %s\n", sep->arg[2]);
}
else
return false;
}
else
{
printf(" (global):\n");
}
printf("===============================================================================\n");
printf("| %20s | %20s | %29s |\n", "Category", "Type", "Value");
printf("===============================================================================\n");
return true;
}
bool ConsoleTestCommand(Seperator *sep)
{
// devs put whatever test code in here
printf("Testing Server Guild Rules values:\n");
printf("AutoJoin: %i\n", rule_manager.GetGlobalRule(R_World, GuildAutoJoin)->GetInt8());
printf("Guild ID: %i\n", rule_manager.GetGlobalRule(R_World, GuildAutoJoinID)->GetInt32());
printf("Rank: %i\n", rule_manager.GetGlobalRule(R_World, GuildAutoJoinDefaultRankID)->GetInt8());
return true;
}

View File

@ -0,0 +1,62 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CONSOLECOMMANDS_H
#define _CONSOLECOMMANDS_H
#include "../../common/seperator.h"
struct ConsoleCommand
{
bool(*CommandPointer)(Seperator *);
const char * Name; // 10 chars
const char * ParameterFormat; // 30 chars
const char * Description; // 40 chars
// = 70 chars
};
void ProcessConsoleInput(const char * command);
bool ConsoleBanCommand(Seperator *sep);
bool ConsoleUnbanCommand(Seperator *sep);
bool ConsoleKickCommand(Seperator *sep);
bool ConsoleAnnounceCommand(Seperator *sep);
bool ConsoleBroadcastCommand(Seperator *sep);
bool ConsoleChannelCommand(Seperator *sep);
bool ConsoleTellCommand(Seperator *sep);
bool ConsoleGuildCommand(Seperator *sep);
bool ConsolePlayerCommand(Seperator *sep);
bool ConsoleSetAdminPlayer(Seperator *sep);
bool ConsoleWorldCommand(Seperator *sep);
bool ConsoleZoneCommand(Seperator *sep);
bool ConsoleGetMOTDCommand(Seperator *sep);
bool ConsoleSetMOTDCommand(Seperator *sep);
bool ConsoleWhoCommand(Seperator *sep);
bool ConsoleReloadCommand(Seperator *sep);
bool ConsoleShutdownCommand(Seperator *sep);
bool ConsoleCancelShutdownCommand(Seperator *sep);
bool ConsoleExitCommand(Seperator *sep);
bool ConsoleRulesCommand(Seperator *sep);
bool ConsoleTestCommand(Seperator *sep);
#endif

File diff suppressed because it is too large Load Diff

2145
source/WorldServer/Entity.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,183 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Factions.h"
#include "client.h"
extern MasterFactionList master_faction_list;
extern ConfigReader configReader;
PlayerFaction::PlayerFaction(){
MFactionUpdateNeeded.SetName("PlayerFaction::MFactionUpdateNeeded");
}
sint32 PlayerFaction::GetMaxValue(sint8 con){
if(con < 0)
return con * 10000;
else
return (con * 10000) + 9999;
}
sint32 PlayerFaction::GetMinValue(sint8 con){
if(con <= 0)
return (con * 10000) - 9999;
else
return (con * 10000);
}
bool PlayerFaction::ShouldAttack(int32 faction_id){
return (GetCon(faction_id) <= -4);
}
sint8 PlayerFaction::GetCon(int32 faction_id){
if(faction_id <= 10){
if(faction_id == 0)
return 0;
return (faction_id-5);
}
sint32 value = GetFactionValue(faction_id);
if(value >= -9999 && value <= 9999)
return 0;
else{
if(value>= 40000)
return 4;
else if(value <= -40000)
return -4;
return (sint8)(value/10000);
}
}
int8 PlayerFaction::GetPercent(int32 faction_id){
if(faction_id <= 10)
return 0;
sint8 con = GetCon(faction_id);
sint32 value = GetFactionValue(faction_id);
if(con != 0){
if(value <= 0)
value *= -1;
if(con < 0)
con *= -1;
value -= con * 10000;
value *= 100;
return value / 10000;
}
else{
value += 10000;
value *= 100;
return value / 20000;
}
}
EQ2Packet* PlayerFaction::FactionUpdate(int16 version){
EQ2Packet* ret = 0;
Faction* faction = 0;
PacketStruct* packet = configReader.getStruct("WS_FactionUpdate", version);
MFactionUpdateNeeded.lock();
if(packet){
packet->setArrayLengthByName("num_factions", faction_update_needed.size());
for(int32 i=0;i<faction_update_needed.size();i++){
faction = master_faction_list.GetFaction(faction_update_needed[i]);
if(faction){
packet->setArrayDataByName("faction_id", faction->id, i);
packet->setArrayDataByName("name", faction->name.c_str(), i);
packet->setArrayDataByName("description", faction->description.c_str(), i);
packet->setArrayDataByName("category", faction->type.c_str(), i);
packet->setArrayDataByName("con", GetCon(faction->id), i);
packet->setArrayDataByName("percentage", GetPercent(faction->id), i);
packet->setArrayDataByName("value", GetFactionValue(faction->id), i);
}
}
ret = packet->serialize();
safe_delete(packet);
}
faction_update_needed.clear();
MFactionUpdateNeeded.unlock();
return ret;
}
sint32 PlayerFaction::GetFactionValue(int32 faction_id){
if(faction_id <= 10)
return 0;
//devn00b: This always seems to return 1, even if the player infact has no faction. since we handle this via a check in zoneserver.cpp (processfaction)
//if(faction_values.count(faction_id) == 0)
//return master_faction_list.GetDefaultFactionValue(faction_id); //faction_values[faction_id] = master_faction_list.GetDefaultFactionValue(faction_id);
return faction_values[faction_id];
}
bool PlayerFaction::ShouldIncrease(int32 faction_id){
if(faction_id <= 10 || master_faction_list.GetIncreaseAmount(faction_id) == 0)
return false;
return true;
}
bool PlayerFaction::ShouldDecrease(int32 faction_id){
if(faction_id <= 10 || master_faction_list.GetDecreaseAmount(faction_id) == 0)
return false;
return true;
}
bool PlayerFaction::IncreaseFaction(int32 faction_id, int32 amount){
if(faction_id <= 10)
return true;
bool ret = true;
if(amount == 0)
amount = master_faction_list.GetIncreaseAmount(faction_id);
faction_values[faction_id] += amount;
if(faction_values[faction_id] >= 50000){
faction_values[faction_id] = 50000;
ret = false;
}
MFactionUpdateNeeded.lock();
faction_update_needed.push_back(faction_id);
MFactionUpdateNeeded.unlock();
return ret;
}
bool PlayerFaction::DecreaseFaction(int32 faction_id, int32 amount){
if(faction_id <= 10)
return true;
bool ret = true;
if(amount == 0)
amount = master_faction_list.GetDecreaseAmount(faction_id);
if(amount != 0){
faction_values[faction_id] -= amount;
if(faction_values[faction_id] <= -50000){
faction_values[faction_id] = -50000;
ret = false;
}
}
else
ret = false;
MFactionUpdateNeeded.lock();
faction_update_needed.push_back(faction_id);
MFactionUpdateNeeded.unlock();
return ret;
}
bool PlayerFaction::SetFactionValue(int32 faction_id, sint32 value){
faction_values[faction_id] = value;
MFactionUpdateNeeded.lock();
faction_update_needed.push_back(faction_id);
MFactionUpdateNeeded.unlock();
return true;
}

View File

@ -0,0 +1,139 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EQ2_FACTIONS
#define EQ2_FACTIONS
#include "../common/ConfigReader.h"
#include "../common/Mutex.h"
struct Faction {
int32 id;
string name;
string type;
string description;
int16 negative_change;
int16 positive_change;
sint32 default_value;
};
class MasterFactionList{
public:
MasterFactionList(){
}
~MasterFactionList(){
Clear();
}
void Clear() {
map<int32,Faction*>::iterator iter;
for(iter = global_faction_list.begin();iter != global_faction_list.end(); iter++){
safe_delete(iter->second);
}
hostile_factions.clear();
friendly_factions.clear();
}
sint32 GetDefaultFactionValue(int32 faction_id){
if(global_faction_list.count(faction_id) > 0 && global_faction_list[faction_id])
return global_faction_list[faction_id]->default_value;
return 0;
}
Faction* GetFaction(char* name){
return faction_name_list[name];
}
Faction* GetFaction(int32 id){
if(global_faction_list.count(id) > 0)
return global_faction_list[id];
return 0;
}
void AddFaction(Faction* faction){
global_faction_list[faction->id] = faction;
faction_name_list[faction->name] = faction;
}
sint32 GetIncreaseAmount(int32 faction_id){
if(global_faction_list.count(faction_id) > 0 && global_faction_list[faction_id])
return global_faction_list[faction_id]->positive_change;
return 0;
}
sint32 GetDecreaseAmount(int32 faction_id){
if(global_faction_list.count(faction_id) > 0 && global_faction_list[faction_id])
return global_faction_list[faction_id]->negative_change;
return 0;
}
int32 GetFactionCount(){
return global_faction_list.size();
}
void AddHostileFaction(int32 faction_id, int32 hostile_faction_id){
hostile_factions[faction_id].push_back(hostile_faction_id);
}
void AddFriendlyFaction(int32 faction_id, int32 friendly_faction_id){
friendly_factions[faction_id].push_back(friendly_faction_id);
}
vector<int32>* GetFriendlyFactions(int32 faction_id){
if(friendly_factions.count(faction_id) > 0)
return &friendly_factions[faction_id];
else
return 0;
}
vector<int32>* GetHostileFactions(int32 faction_id){
if(hostile_factions.count(faction_id) > 0)
return &hostile_factions[faction_id];
else
return 0;
}
const char* GetFactionNameByID(int32 faction_id) {
if (faction_id > 0 && global_faction_list.count(faction_id) > 0)
return global_faction_list[faction_id]->name.c_str();
return 0;
}
private:
map<int32, vector<int32> > friendly_factions;
map<int32, vector<int32> > hostile_factions;
map<int32,Faction*> global_faction_list;
map<string,Faction*> faction_name_list;
};
class PlayerFaction{
public:
PlayerFaction();
sint32 GetMaxValue(sint8 con);
sint32 GetMinValue(sint8 con);
EQ2Packet* FactionUpdate(int16 version);
sint32 GetFactionValue(int32 faction_id);
bool ShouldIncrease(int32 faction_id);
bool ShouldDecrease(int32 faction_id);
bool IncreaseFaction(int32 faction_id, int32 amount = 0);
bool DecreaseFaction(int32 faction_id, int32 amount = 0);
bool SetFactionValue(int32 faction_id, sint32 value);
sint8 GetCon(int32 faction_id);
int8 GetPercent(int32 faction_id);
map<int32, sint32>* GetFactionValues(){
return &faction_values;
}
bool ShouldAttack(int32 faction_id);
private:
Mutex MFactionUpdateNeeded;
vector<int32> faction_update_needed;
map<int32, sint32> faction_values;
map<int32, int8> faction_percent;
};
#endif

View File

@ -0,0 +1,575 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GroundSpawn.h"
#include "World.h"
#include "Spells.h"
#include "Rules/Rules.h"
#include "../common/MiscFunctions.h"
#include "../common/Log.h"
extern ConfigReader configReader;
extern MasterSpellList master_spell_list;
extern World world;
extern RuleManager rule_manager;
GroundSpawn::GroundSpawn(){
packet_num = 0;
appearance.difficulty = 0;
spawn_type = 2;
appearance.pos.state = 129;
number_harvests = 0;
num_attempts_per_harvest = 0;
groundspawn_id = 0;
MHarvest.SetName("GroundSpawn::MHarvest");
MHarvestUse.SetName("GroundSpawn::MHarvestUse");
randomize_heading = true; // we by default randomize heading of groundspawns DB overrides
}
GroundSpawn::~GroundSpawn(){
}
EQ2Packet* GroundSpawn::serialize(Player* player, int16 version){
return spawn_serialize(player, version);
}
int8 GroundSpawn::GetNumberHarvests(){
return number_harvests;
}
void GroundSpawn::SetNumberHarvests(int8 val){
number_harvests = val;
}
int8 GroundSpawn::GetAttemptsPerHarvest(){
return num_attempts_per_harvest;
}
void GroundSpawn::SetAttemptsPerHarvest(int8 val){
num_attempts_per_harvest = val;
}
int32 GroundSpawn::GetGroundSpawnEntryID(){
return groundspawn_id;
}
void GroundSpawn::SetGroundSpawnEntryID(int32 val){
groundspawn_id = val;
}
void GroundSpawn::SetCollectionSkill(const char* val){
if(val)
collection_skill = string(val);
}
const char* GroundSpawn::GetCollectionSkill(){
return collection_skill.c_str();
}
void GroundSpawn::ProcessHarvest(Client* client) {
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Process harvesting for player '%s' (%u)", client->GetPlayer()->GetName(), client->GetPlayer()->GetID());
MHarvest.lock();
vector<GroundSpawnEntry*>* groundspawn_entries = GetZone()->GetGroundSpawnEntries(groundspawn_id);
vector<GroundSpawnEntryItem*>* groundspawn_items = GetZone()->GetGroundSpawnEntryItems(groundspawn_id);
Item* master_item = 0;
Item* master_rare = 0;
Item* item = 0;
Item* item_rare = 0;
int16 lowest_skill_level = 0;
int16 table_choice = 0;
int32 item_choice = 0;
int32 rare_choice = 0;
int8 harvest_type = 0;
int32 item_harvested = 0;
int8 reward_total = 1;
int32 rare_harvested = 0;
int8 rare_item = 0;
bool is_collection = false;
if (!groundspawn_entries || !groundspawn_items) {
LogWrite(GROUNDSPAWN__ERROR, 3, "GSpawn", "No groundspawn entries or items assigned to groundspawn id: %u", groundspawn_id);
client->Message(CHANNEL_COLOR_RED, "Error: There are no groundspawn entries or items assigned to groundspawn id: %u", groundspawn_id);
MHarvest.unlock();
return;
}
if (number_harvests == 0) {
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Total harvests depleated for groundspawn id: %u", groundspawn_id);
client->SimpleMessage(CHANNEL_COLOR_RED, "Error: This spawn has nothing more to harvest!");
MHarvest.unlock();
return;
}
Skill* skill = 0;
if (collection_skill == "Collecting") {
skill = client->GetPlayer()->GetSkillByName("Gathering");
is_collection = true;
}
else
skill = client->GetPlayer()->GetSkillByName(collection_skill.c_str()); // Fix: #576 - don't skill up yet with GetSkillByName(skill, true), we might be trying to harvest low level
if (!skill) {
LogWrite(GROUNDSPAWN__WARNING, 3, "GSpawn", "Player '%s' lacks the skill: '%s'", client->GetPlayer()->GetName(), collection_skill.c_str());
client->Message(CHANNEL_COLOR_RED, "Error: You do not have the '%s' skill!", collection_skill.c_str());
MHarvest.unlock();
return;
}
int16 totalSkill = skill->current_val;
int32 skillID = master_item_list.GetItemStatIDByName(collection_skill);
int16 max_skill_req_groundspawn = 0;
if(skillID != 0xFFFFFFFF)
{
((Entity*)client->GetPlayer())->MStats.lock();
totalSkill += ((Entity*)client->GetPlayer())->stats[skillID];
((Entity*)client->GetPlayer())->MStats.unlock();
}
for (int8 i = 0; i < num_attempts_per_harvest; i++) {
vector<GroundSpawnEntry*> mod_groundspawn_entries;
if (groundspawn_entries) {
vector<GroundSpawnEntry*> highest_match;
vector<GroundSpawnEntry*>::iterator itr;
GroundSpawnEntry* entry = 0; // current data
GroundSpawnEntry* selected_table = 0; // selected table data
// first, iterate through groundspawn_entries, discard tables player cannot use
for (itr = groundspawn_entries->begin(); itr != groundspawn_entries->end(); itr++) {
entry = *itr;
if(entry->min_skill_level > max_skill_req_groundspawn)
max_skill_req_groundspawn = entry->min_skill_level;
// if player lacks skill, skip table
if (entry->min_skill_level > totalSkill)
continue;
// if bonus, but player lacks level, skip table
if (entry->bonus_table && (client->GetPlayer()->GetLevel() < entry->min_adventure_level))
continue;
// build modified entries table
mod_groundspawn_entries.push_back(entry);
LogWrite(GROUNDSPAWN__DEBUG, 5, "GSpawn", "Keeping groundspawn_entry: %i", entry->min_skill_level);
}
// if anything remains, find lowest min_skill_level in remaining set(s)
if (mod_groundspawn_entries.size() > 0) {
vector<GroundSpawnEntry*>::iterator itr;
GroundSpawnEntry* entry = 0;
for (itr = mod_groundspawn_entries.begin(); itr != mod_groundspawn_entries.end(); itr++) {
entry = *itr;
// find the low range of available tables for random roll
if (lowest_skill_level > entry->min_skill_level || lowest_skill_level == 0)
lowest_skill_level = entry->min_skill_level;
}
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Lowest Skill Level: %i", lowest_skill_level);
}
else {
// if no tables chosen, you must lack the skills
// TODO: move this check to LUA when harvest command is first selected
client->Message(CHANNEL_COLOR_RED, "You lack the skills to harvest this node!");
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "All groundspawn_entry tables tossed! No Skills? Something broke?");
MHarvest.unlock();
return;
}
// now roll to see which table to use
table_choice = MakeRandomInt(lowest_skill_level, totalSkill);
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Random INT for Table by skill level: %i", table_choice);
int16 highest_score = 0;
for (itr = mod_groundspawn_entries.begin(); itr != mod_groundspawn_entries.end(); itr++) {
entry = *itr;
// determines the highest min_skill_level in the current set of tables (if multiple tables)
if (table_choice >= entry->min_skill_level && (highest_score == 0 || highest_score < table_choice)) {
// removes old highest for the new one
highest_match.clear();
highest_score = entry->min_skill_level;
}
// if the score = level, push into highest_match set
if (highest_score == entry->min_skill_level)
highest_match.push_back(entry);
}
// if there is STILL more than 1 table player qualifies for, rand() and pick one
if (highest_match.size() > 1) {
int16 rand_index = rand() % highest_match.size();
selected_table = highest_match.at(rand_index);
}
else if (highest_match.size() > 0)
selected_table = highest_match.at(0);
// by this point, we should have 1 table who's min skill matches the score (selected_table)
if (selected_table) {
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Using Table: %i, %i, %i, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %i",
selected_table->min_skill_level,
selected_table->min_adventure_level,
selected_table->bonus_table,
selected_table->harvest1,
selected_table->harvest3,
selected_table->harvest5,
selected_table->harvest_imbue,
selected_table->harvest_rare,
selected_table->harvest10,
selected_table->harvest_coin);
// roll 1-100 for chance-to-harvest percentage
float chance = MakeRandomFloat(0, 100);
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Random FLOAT for harvest percentages: %.2f", chance);
// starting with the lowest %, select a harvest type + reward qty
if (chance <= selected_table->harvest10 && is_collection == false) {
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest 10 items + Rare Item from table : %i", selected_table->min_skill_level);
harvest_type = 6;
reward_total = 10;
}
else if (chance <= selected_table->harvest_rare && is_collection == false) {
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest Rare Item from table : %i", selected_table->min_skill_level);
harvest_type = 5;
}
else if (chance <= selected_table->harvest_imbue && is_collection == false) {
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest Imbue Item from table : %i", selected_table->min_skill_level);
harvest_type = 4;
}
else if (chance <= selected_table->harvest5 && is_collection == false) {
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest 5 Items from table : %i", selected_table->min_skill_level);
harvest_type = 3;
reward_total = 5;
}
else if (chance <= selected_table->harvest3 && is_collection == false) {
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest 3 Items from table : %i", selected_table->min_skill_level);
harvest_type = 2;
reward_total = 3;
}
else if (chance <= selected_table->harvest1 || totalSkill >= skill->max_val || is_collection) {
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest 1 Item from table : %i", selected_table->min_skill_level);
harvest_type = 1;
}
else
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Harvest nothing...");
float node_maxskill_multiplier = rule_manager.GetGlobalRule(R_Player, HarvestSkillUpMultiplier)->GetFloat();
if(node_maxskill_multiplier <= 0.0f) {
node_maxskill_multiplier = 1.0f;
}
int16 skillup_max_skill_allowed = (int16)((float)max_skill_req_groundspawn*node_maxskill_multiplier);
if (!is_collection && skill && skill->current_val < skillup_max_skill_allowed) {
skill = client->GetPlayer()->GetSkillByName(collection_skill.c_str(), true); // Fix: #576 - skill up after min skill and adv level checks
}
}
// once you know how many and what type of item to harvest, pick an item from the list
if (harvest_type) {
vector<GroundSpawnEntryItem*> mod_groundspawn_items;
vector<GroundSpawnEntryItem*> mod_groundspawn_rares;
vector<GroundSpawnEntryItem*> mod_groundspawn_imbue;
vector<GroundSpawnEntryItem*>::iterator itr;
GroundSpawnEntryItem* entry = 0;
// iterate through groundspawn_items, discard items player cannot roll for
for (itr = groundspawn_items->begin(); itr != groundspawn_items->end(); itr++) {
entry = *itr;
// if this is a Rare, or an Imbue, but is_rare flag is 0, skip item
if ((harvest_type == 5 || harvest_type == 4) && entry->is_rare == 0)
continue;
// if it is a 1, 3, or 5 and is_rare = 1, skip
else if (harvest_type < 4 && entry->is_rare == 1)
continue;
// if the grid_id on the item matches player grid, or is 0, keep the item
if (!entry->grid_id || (entry->grid_id == client->GetPlayer()->GetLocation())) {
// build modified entries table
if ((entry->is_rare == 1 && harvest_type == 5) || (entry->is_rare == 1 && harvest_type == 6)) {
// if the matching item is rare, or harvest10 push to mod rares
mod_groundspawn_rares.push_back(entry);
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Keeping groundspawn_rare_item: %u", entry->item_id);
}
if (entry->is_rare == 0 && harvest_type != 4 && harvest_type != 5) {
// if the matching item is normal,or harvest 10 push to mod items
mod_groundspawn_items.push_back(entry);
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Keeping groundspawn_common_item: %u", entry->item_id);
}
if (entry->is_rare == 2 && harvest_type == 4) {
// if the matching item is imbue item, push to mod imbue
mod_groundspawn_imbue.push_back(entry);
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Keeping groundspawn_imbue_item: %u", entry->item_id);
}
}
}
// if any items remain in the list, random to see which one gets awarded
if (mod_groundspawn_items.size() > 0) {
// roll to see which item index to use
item_choice = rand() % mod_groundspawn_items.size();
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Random INT for which item to award: %i", item_choice);
// set item_id to be awarded
item_harvested = mod_groundspawn_items[item_choice]->item_id;
// if reward is rare, set flag
rare_item = mod_groundspawn_items[item_choice]->is_rare;
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Item ID to award: %u, Rare = %i", item_harvested, item_rare);
// if 10+rare, handle additional "rare" reward
if (harvest_type == 6) {
// make sure there is a rare table to choose from!
if (mod_groundspawn_rares.size() > 0) {
// roll to see which rare index to use
rare_choice = rand() % mod_groundspawn_rares.size();
// set (rare) item_id to be awarded
rare_harvested = mod_groundspawn_rares[rare_choice]->item_id;
// we're picking a rare here, so obviously this is true ;)
rare_item = 1;
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "RARE Item ID to award: %u", rare_harvested);
}
else {
// all rare entries were eliminated above, or none are assigned. Either way, shouldn't be here!
LogWrite(GROUNDSPAWN__ERROR, 3, "GSpawn", "Groundspawn Entry for '%s' (%i) has no RARE items!", GetName(), GetID());
}
}
}
else if (mod_groundspawn_rares.size() > 0) {
// roll to see which rare index to use
item_choice = rand() % mod_groundspawn_rares.size();
// set (rare) item_id to be awarded
item_harvested = mod_groundspawn_rares[item_choice]->item_id;
// we're picking a rare here, so obviously this is true ;)
rare_item = 1;
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "RARE Item ID to award: %u", rare_harvested);
}
else if (mod_groundspawn_imbue.size() > 0) {
// roll to see which rare index to use
item_choice = rand() % mod_groundspawn_imbue.size();
// set (rare) item_id to be awarded
item_harvested = mod_groundspawn_imbue[item_choice]->item_id;
// we're picking a rare here, so obviously this is true ;)
rare_item = 0;
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "imbue Item ID to award: %u", rare_harvested);
}
else {
// all item entries were eliminated above, or none are assigned. Either way, shouldn't be here!
LogWrite(GROUNDSPAWN__ERROR, 0, "GSpawn", "Groundspawn Entry for '%s' (%i) has no items!", GetName(), GetID());
}
// if an item was harvested, send updates to client, add item to inventory
if (item_harvested) {
char tmp[200] = { 0 };
// set Normal item harvested
master_item = master_item_list.GetItem(item_harvested);
if (master_item) {
// set details of Normal item
item = new Item(master_item);
// set how many of this item the player receives
item->details.count = reward_total;
// chat box update for normal item (todo: verify output text)
client->Message(CHANNEL_HARVESTING, "You %s %i %s from the %s.", GetHarvestMessageName(true).c_str(), item->details.count, item->CreateItemLink(client->GetVersion(), true).c_str(), GetName());
// add Normal item to player inventory
bool itemDeleted = false;
client->AddItem(item, &itemDeleted);
if(!itemDeleted) {
//Check if the player has a harvesting quest for this
client->GetPlayer()->CheckQuestsHarvestUpdate(item, reward_total);
// if this is a 10+rare, handle sepErately
if (harvest_type == 6 && rare_item == 1) {
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Item ID %u is Normal. Qty %i", item_harvested, item->details.count);
// send Normal harvest message to client
sprintf(tmp, "\\#64FFFFYou have %s:\12\\#C8FFFF%i %s", GetHarvestMessageName().c_str(), item->details.count, item->name.c_str());
client->SendPopupMessage(10, tmp, "ui_harvested_normal", 2.25, 0xFF, 0xFF, 0xFF);
client->GetPlayer()->UpdatePlayerStatistic(STAT_PLAYER_ITEMS_HARVESTED, item->details.count);
// set Rare item harvested
master_rare = master_item_list.GetItem(rare_harvested);
if (master_rare) {
// set details of Rare item
item_rare = new Item(master_rare);
// count of Rare is always 1
item_rare->details.count = 1;
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Item ID %u is RARE!", rare_harvested);
// send Rare harvest message to client
sprintf(tmp, "\\#FFFF6ERare item found!\12%s: \\#C8FFFF%i %s", GetHarvestMessageName().c_str(), item_rare->details.count, item_rare->name.c_str());
client->Message(CHANNEL_HARVESTING, "You have found a rare item!");
client->SendPopupMessage(11, tmp, "ui_harvested_rare", 2.25, 0xFF, 0xFF, 0xFF);
client->GetPlayer()->UpdatePlayerStatistic(STAT_PLAYER_RARES_HARVESTED, item_rare->details.count);
// chat box update for rare item (todo: verify output text)
client->Message(CHANNEL_HARVESTING, "You %s %i %s from the %s.", GetHarvestMessageName(true).c_str(), item_rare->details.count, item->CreateItemLink(client->GetVersion(), true).c_str(), GetName());
// add Rare item to player inventory
client->AddItem(item_rare);
//Check if the player has a harvesting quest for this
client->GetPlayer()->CheckQuestsHarvestUpdate(item_rare, 1);
}
}
else if (rare_item == 1) {
// if harvest signaled rare or imbue type
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Item ID %u is RARE! Qty: %i", item_harvested, item->details.count);
// send Rare harvest message to client
sprintf(tmp, "\\#FFFF6ERare item found!\12%s: \\#C8FFFF%i %s", GetHarvestMessageName().c_str(), item->details.count, item->name.c_str());
client->Message(CHANNEL_HARVESTING, "You have found a rare item!");
client->SendPopupMessage(11, tmp, "ui_harvested_rare", 2.25, 0xFF, 0xFF, 0xFF);
client->GetPlayer()->UpdatePlayerStatistic(STAT_PLAYER_RARES_HARVESTED, item->details.count);
}
else {
// send Normal harvest message to client
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "Item ID %u is Normal. Qty %i", item_harvested, item->details.count);
sprintf(tmp, "\\#64FFFFYou have %s:\12\\#C8FFFF%i %s", GetHarvestMessageName().c_str(), item->details.count, item->name.c_str());
client->SendPopupMessage(10, tmp, "ui_harvested_normal", 2.25, 0xFF, 0xFF, 0xFF);
client->GetPlayer()->UpdatePlayerStatistic(STAT_PLAYER_ITEMS_HARVESTED, item->details.count);
}
}
}
else {
// error!
LogWrite(GROUNDSPAWN__ERROR, 0, "GSpawn", "Error: Item ID Not Found - %u", item_harvested);
client->Message(CHANNEL_COLOR_RED, "Error: Unable to find item id %u", item_harvested);
}
// decrement # of pulls on this node before it despawns
number_harvests--;
}
else {
// if no item harvested
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "No item_harvested");
client->Message(CHANNEL_HARVESTING, "You failed to %s anything from %s.", GetHarvestMessageName(true, true).c_str(), GetName());
}
}
else {
// if no harvest type
LogWrite(GROUNDSPAWN__DEBUG, 3, "GSpawn", "No harvest_type");
client->Message(CHANNEL_HARVESTING, "You failed to %s anything from %s.", GetHarvestMessageName(true, true).c_str(), GetName());
}
}
} // cycle through num_attempts_per_harvest
MHarvest.unlock();
LogWrite(GROUNDSPAWN__DEBUG, 0, "GSpawn", "Process harvest complete for player '%s' (%u)", client->GetPlayer()->GetName(), client->GetPlayer()->GetID());
}
string GroundSpawn::GetHarvestMessageName(bool present_tense, bool failure){
string ret = "";
if((collection_skill == "Gathering" ||collection_skill == "Collecting") && !present_tense)
ret = "gathered";
else if(collection_skill == "Gathering" || collection_skill == "Collecting")
ret = "gather";
else if(collection_skill == "Mining" && !present_tense)
ret = "mined";
else if(collection_skill == "Mining")
ret = "mine";
else if (collection_skill == "Fishing" && !present_tense)
ret = "fished";
else if(collection_skill == "Fishing")
ret = "fish";
else if(collection_skill == "Trapping" && !present_tense && !failure)
ret = "acquired";
else if(collection_skill == "Trapping" && failure)
ret = "trap";
else if(collection_skill == "Trapping")
ret = "acquire";
else if(collection_skill == "Foresting" && !present_tense)
ret = "forested";
else if(collection_skill == "Foresting")
ret = "forest";
else if (collection_skill == "Collecting")
ret = "collect";
return ret;
}
string GroundSpawn::GetHarvestSpellType(){
string ret = "";
if(collection_skill == "Gathering" || collection_skill == "Collecting")
ret = "gather";
else if(collection_skill == "Mining")
ret = "mine";
else if(collection_skill == "Trapping")
ret = "trap";
else if(collection_skill == "Foresting")
ret = "chop";
else if(collection_skill == "Fishing")
ret = "fish";
return ret;
}
string GroundSpawn::GetHarvestSpellName() {
string ret = "";
if (collection_skill == "Collecting")
ret = "Gathering";
else
ret = collection_skill;
return ret;
}
void GroundSpawn::HandleUse(Client* client, string type){
if(!client || type.length() == 0)
return;
//The following check disables the use of the groundspawn if spawn access is not granted
if (client) {
bool meets_quest_reqs = MeetsSpawnAccessRequirements(client->GetPlayer());
if (!meets_quest_reqs && (GetQuestsRequiredOverride() & 2) == 0)
return;
else if (meets_quest_reqs && appearance.show_command_icon != 1)
return;
}
MHarvestUse.lock();
if (type == GetHarvestSpellType() && MeetsSpawnAccessRequirements(client->GetPlayer())) {
Spell* spell = master_spell_list.GetSpellByName(GetHarvestSpellName().c_str());
if (spell)
client->GetCurrentZone()->ProcessSpell(spell, client->GetPlayer(), client->GetPlayer()->GetTarget(), true, true);
}
else if (appearance.show_command_icon == 1 && MeetsSpawnAccessRequirements(client->GetPlayer())) {
EntityCommand* entity_command = FindEntityCommand(type);
if (entity_command)
client->GetCurrentZone()->ProcessEntityCommand(entity_command, client->GetPlayer(), client->GetPlayer()->GetTarget());
}
MHarvestUse.unlock();
}

View File

@ -0,0 +1,86 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __EQ2_GroundSpawn__
#define __EQ2_GroundSpawn__
#include "Spawn.h"
#include "client.h"
#include "../common/Mutex.h"
class GroundSpawn : public Spawn {
public:
GroundSpawn();
virtual ~GroundSpawn();
GroundSpawn* Copy(){
GroundSpawn* new_spawn = new GroundSpawn();
new_spawn->size = size;
new_spawn->SetPrimaryCommands(&primary_command_list);
new_spawn->SetSecondaryCommands(&secondary_command_list);
new_spawn->database_id = database_id;
new_spawn->primary_command_list_id = primary_command_list_id;
new_spawn->secondary_command_list_id = secondary_command_list_id;
memcpy(&new_spawn->appearance, &appearance, sizeof(AppearanceData));
new_spawn->faction_id = faction_id;
new_spawn->target = 0;
new_spawn->SetTotalHP(GetTotalHP());
new_spawn->SetTotalPower(GetTotalPower());
new_spawn->SetHP(GetHP());
new_spawn->SetPower(GetPower());
new_spawn->SetNumberHarvests(number_harvests);
new_spawn->SetAttemptsPerHarvest(num_attempts_per_harvest);
new_spawn->SetGroundSpawnEntryID(groundspawn_id);
new_spawn->SetCollectionSkill(collection_skill.c_str());
SetQuestsRequired(new_spawn);
new_spawn->forceMapCheck = forceMapCheck;
new_spawn->SetOmittedByDBFlag(IsOmittedByDBFlag());
new_spawn->SetLootTier(GetLootTier());
new_spawn->SetLootDropType(GetLootDropType());
new_spawn->SetRandomizeHeading(GetRandomizeHeading());
return new_spawn;
}
bool IsGroundSpawn(){ return true; }
EQ2Packet* serialize(Player* player, int16 version);
int8 GetNumberHarvests();
void SetNumberHarvests(int8 val);
int8 GetAttemptsPerHarvest();
void SetAttemptsPerHarvest(int8 val);
int32 GetGroundSpawnEntryID();
void SetGroundSpawnEntryID(int32 val);
void ProcessHarvest(Client* client);
void SetCollectionSkill(const char* val);
const char* GetCollectionSkill();
string GetHarvestMessageName(bool present_tense = false, bool failure = false);
string GetHarvestSpellType();
string GetHarvestSpellName();
void HandleUse(Client* client, string type);
void SetRandomizeHeading(bool val) { randomize_heading = val; }
bool GetRandomizeHeading() { return randomize_heading; }
private:
int8 number_harvests;
int8 num_attempts_per_harvest;
int32 groundspawn_id;
string collection_skill;
Mutex MHarvest;
Mutex MHarvestUse;
bool randomize_heading;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,450 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GUILD_H_
#define GUILD_H_
#include <vector>
#include <deque>
#include <map>
#include "../../common/Mutex.h"
#include "../MutexMap.h"
using namespace std;
class ZoneServer;
class Client;
class Player;
#define GUILD_RANK_LEADER 0
#define GUILD_RANK_SENIOR_OFFICER 1
#define GUILD_RANK_OFFICER 2
#define GUILD_RANK_SENIOR_MEMBER 3
#define GUILD_RANK_MEMBER 4
#define GUILD_RANK_JUNIOR_MEMBER 5
#define GUILD_RANK_INITIATE 6
#define GUILD_RANK_RECRUIT 7
#define GUILD_PERMISSIONS_INVITE 0
#define GUILD_PERMISSIONS_RMEOVE_MEMBER 1
#define GUILD_PERMISSIONS_PROMOTE_MEMBER 2
#define GUILD_PERMISSIONS_DEMOTE_MEMBER 3
#define GUILD_PERMISSIONS_CHANGE_MOTD 6
#define GUILD_PERMISSIONS_CHANGE_PERMISSIONS 7
#define GUILD_PERMISSIONS_CHANGE_RANK_NAMES 8
#define GUILD_PERMISSIONS_SEE_OFFICER_NOTES 9
#define GUILD_PERMISSIONS_EDIT_OFFICER_NOTES 10
#define GUILD_PERMISSIONS_SEE_OFFICER_CHAT 11
#define GUILD_PERMISSIONS_SPEAK_IN_OFFICER_CHAT 12
#define GUILD_PERMISSIONS_SEE_GUILD_CHAT 13
#define GUILD_PERMISSIONS_SPEAK_IN_GUILD_CHAT 14
#define GUILD_PERMISSIONS_EDIT_PERSONAL_NOTES 15
#define GUILD_PERMISSIONS_EDIT_PERSONAL_NOTES_OTHERS 16
#define GUILD_PERMISSIONS_EDIT_EVENT_FILTERS 17
#define GUILD_PERMISSIONS_EDIT_EVENTS 18
#define GUILD_PERMISSIONS_PURCHASE_STATUS_ITEMS 19
#define GUILD_PERMISSIONS_DISPLAY_GUILD_NAME 20
#define GUILD_PERMISSIONS_SEND_EMAIL_TO_GUILD 21
#define GUILD_PERMISSIONS_BANK1_SEE_CONTENTS 22
#define GUILD_PERMISSIONS_BANK2_SEE_CONTENTS 23
#define GUILD_PERMISSIONS_BANK3_SEE_CONTENTS 24
#define GUILD_PERMISSIONS_BANK4_SEE_CONTENTS 25
#define GUILD_PERMISSIONS_BANK1_DEPOSIT 26
#define GUILD_PERMISSIONS_BANK2_DEPOSIT 27
#define GUILD_PERMISSIONS_BANK3_DEPOSIT 28
#define GUILD_PERMISSIONS_BANK4_DEPOSIT 29
#define GUILD_PERMISSIONS_BANK1_WITHDRAWL 30
#define GUILD_PERMISSIONS_BANK2_WITHDRAWL 31
#define GUILD_PERMISSIONS_BANK3_WITHDRAWL 32
#define GUILD_PERMISSIONS_BANK4_WITHDRAWL 33
#define GUILD_PERMISSIONS_EDIT_RECRUITING_SETTINGS 35
#define GUILD_PERMISSIONS_MAKE_OTHERS_RECRUITERS 36
#define GUILD_PERMISSIONS_SEE_RECRUITING_SETTINGS 37
#define GUILD_PERMISSIONS_ASSIGN_POINTS 43
#define GUILD_PERMISSIONS_RECEIVE_POINTS 44
#define GUILD_EVENT_FILTER_CATEGORY_RETAIN_HISTORY 0
#define GUILD_EVENT_FILTER_CATEGORY_BROADCAST 1
#define GUILD_EVENT_GUILD_LEVEL_UP 0
#define GUILD_EVENT_GUILD_LEVEL_DOWN 1
#define GUILD_EVENT_DISCOVERS_ITEM 2
#define GUILD_EVENT_GAINS_ADV_LEVEL_1_10 3
#define GUILD_EVENT_GAINS_ADV_LEVEL_11_20 4
#define GUILD_EVENT_GAINS_ADV_LEVEL_21_30 5
#define GUILD_EVENT_GAINS_ADV_LEVEL_31_40 6
#define GUILD_EVENT_GAINS_ADV_LEVEL_41_50 7
#define GUILD_EVENT_GAINS_TS_LEVEL_1_10 8
#define GUILD_EVENT_GAINS_TS_LEVEL_11_20 9
#define GUILD_EVENT_GAINS_TS_LEVEL_21_30 10
#define GUILD_EVENT_GAINS_TS_LEVEL_31_40 11
#define GUILD_EVENT_GAINS_TS_LEVEL_41_50 12
#define GUILD_EVENT_MEMBER_JOINS 13
#define GUILD_EVENT_MEMBER_LEAVES 14
#define GUILD_EVENT_MEMBER_PROMOTED 15
#define GUILD_EVENT_MEMBER_DEMOTED 16
#define GUILD_EVENT_COMPLETES_HERITAGE_QUEST 19
#define GUILD_EVENT_KILLS_EPIC_MONSTER 20
#define GUILD_EVENT_LOOTS_ARTIFACT 21
#define GUILD_EVENT_LOOTS_FABELED_ITEM 22
#define GUILD_EVENT_LOOTS_LEGENDARY_ITEM 23
#define GUILD_EVENT_COMPLETES_WRIT 24
#define GUILD_EVENT_LOOTS_MYTHICAL_ITEM 25
#define GUILD_EVENT_GAINS_ADV_LEVEL_10 26
#define GUILD_EVENT_GAINS_ADV_LEVEL_20 27
#define GUILD_EVENT_GAINS_ADV_LEVEL_30 28
#define GUILD_EVENT_GAINS_ADV_LEVEL_40 29
#define GUILD_EVENT_GAINS_ADV_LEVEL_50 30
#define GUILD_EVENT_GAINS_TS_LEVEL_10 31
#define GUILD_EVENT_GAINS_TS_LEVEL_20 32
#define GUILD_EVENT_GAINS_TS_LEVEL_30 33
#define GUILD_EVENT_GAINS_TS_LEVEL_40 34
#define GUILD_EVENT_GAINS_TS_LEVEL_50 35
#define GUILD_EVENT_GAINS_ADV_LEVEL_51_60 37
#define GUILD_EVENT_GAINS_TS_LEVEL_51_60 38
#define GUILD_EVENT_GAINS_ADV_LEVEL_60 39
#define GUILD_EVENT_GAINS_TS_LEVEL_60 40
#define GUILD_EVENT_GAINS_ADV_LEVEL_61_70 41
#define GUILD_EVENT_GAINS_TS_LEVEL_61_70 42
#define GUILD_EVENT_GAINS_ADV_LEVEL_70 43
#define GUILD_EVENT_GAINS_TS_LEVEL_70 44
#define GUILD_EVENT_GAINS_AA_10 45
#define GUILD_EVENT_GAINS_AA_20 46
#define GUILD_EVENT_GAINS_AA_30 47
#define GUILD_EVENT_GAINS_AA_40 48
#define GUILD_EVENT_GAINS_AA_50 49
#define GUILD_EVENT_GAINS_AA_1_10 50
#define GUILD_EVENT_GAINS_AA_11_20 51
#define GUILD_EVENT_GAINS_AA_21_30 52
#define GUILD_EVENT_GAINS_AA_31_40 53
#define GUILD_EVENT_GAINS_AA_41_50 54
#define GUILD_EVENT_BECOMES_RECRUITER 55
#define GUILD_EVENT_NO_LONGER_RECRUITER 56
#define GUILD_EVENT_HERALDY_CHANGE 57
#define GUILD_EVENT_GAINS_AA_60 58
#define GUILD_EVENT_GAINS_AA_70 59
#define GUILD_EVENT_GAINS_AA_80 60
#define GUILD_EVENT_GAINS_AA_90 61
#define GUILD_EVENT_GAINS_AA_100 62
#define GUILD_EVENT_GAINS_AA_51_60 63
#define GUILD_EVENT_GAINS_AA_61_70 64
#define GUILD_EVENT_GAINS_AA_71_80 65
#define GUILD_EVENT_GAINS_AA_81_90 66
#define GUILD_EVENT_GAINS_AA_91_100 67
#define GUILD_EVENT_GAINS_ADV_LEVEL_80 68
#define GUILD_EVENT_GAINS_TS_LEVEL_80 69
#define GUILD_EVENT_GAINS_ADV_LEVEL_71_80 70
#define GUILD_EVENT_GAINS_TS_LEVEL_71_80 71
#define GUILD_EVENT_GAINS_AA_110 72
#define GUILD_EVENT_GAINS_AA_120 73
#define GUILD_EVENT_GAINS_AA_130 74
#define GUILD_EVENT_GAINS_AA_140 75
#define GUILD_EVENT_GAINS_AA_101_110 76
#define GUILD_EVENT_GAINS_AA_111_120 77
#define GUILD_EVENT_GAINS_AA_121_130 78
#define GUILD_EVENT_GAINS_AA_131_140 79
#define GUILD_EVENT_GAINS_AA_150 80
#define GUILD_EVENT_GAINS_AA_141_150 81
#define GUILD_EVENT_GAINS_AA_160 82
#define GUILD_EVENT_GAINS_AA_170 83
#define GUILD_EVENT_GAINS_AA_180 84
#define GUILD_EVENT_GAINS_AA_190 85
#define GUILD_EVENT_GAINS_AA_200 86
#define GUILD_EVENT_GAINS_AA_151_160 87
#define GUILD_EVENT_GAINS_AA_161_170 88
#define GUILD_EVENT_GAINS_AA_171_180 89
#define GUILD_EVENT_GAINS_AA_181_190 90
#define GUILD_EVENT_GAINS_AA_191_200 91
#define GUILD_EVENT_EARNS_ACHIEVEMENT 92
#define GUILD_RECRUITING_FLAG_TRAINING 0
#define GUILD_RECRUITING_FLAG_FIGHTERS 1
#define GUILD_RECRUITING_FLAG_PRIESTS 2
#define GUILD_RECRUITING_FLAG_SCOUTS 3
#define GUILD_RECRUITING_FLAG_MAGES 4
#define GUILD_RECRUITING_FLAG_TRADESKILLERS 5
#define GUILD_RECRUITING_PLAYSTYLE_NONE 0
#define GUILD_RECRUITING_PLAYSTYLE_CASUAL 1
#define GUILD_RECRUITING_PLAYSTYLE_HARDCORE 2
#define GUILD_RECRUITING_DESC_TAG_NONE 0
#define GUILD_RECRUITING_DESC_TAG_GOOD 1
#define GUILD_RECRUITING_DESC_TAG_EVIL 2
#define GUILD_RECRUITING_DESC_TAG_CHATTY 3
#define GUILD_RECRUITING_DESC_TAG_ORGANIZED 4
#define GUILD_RECRUITING_DESC_TAG_ROLEPLAY 5
#define GUILD_RECRUITING_DESC_TAG_ENJOY_QUESTS 6
#define GUILD_RECRUITING_DESC_TAG_ENJOY_RAIDS 7
#define GUILD_RECRUITING_DESC_TAG_ODD_HOURS 8
#define GUILD_RECRUITING_DESC_TAG_CRAFTER_ORIENTED 9
#define GUILD_RECRUITING_DESC_TAG_FAMILY_FRIENDLY 10
#define GUILD_RECRUITING_DESC_TAG_MATURE_HUMOR 11
#define GUILD_RECRUITING_DESC_TAG_INMATES_RUN 12
#define GUILD_RECRUITING_DESC_TAG_VERY_FUNNY 13
#define GUILD_RECRUITING_DESC_TAG_HUMOR_CAUES_PAIN 14
#define GUILD_RECRUITING_DESC_TAG_SERIOUS 15
#define GUILD_MEMBER_FLAGS_RECRUITING_FOR_GUILD 1
#define GUILD_MEMBER_FLAGS_NOTIFY_LOGINS 2
#define GUILD_MEMBER_FLAGS_DONT_GENERATE_EVENTS 4
#define GUILD_EVENT_ACTION_LOCK 0
#define GUILD_EVENT_ACTION_UNLOCK 1
#define GUILD_EVENT_ACTION_DELETE 2
#define GUILD_MAX_LEVEL 80
#define GUILD_MAX_POINT_HISTORY 50
#define GUILD_MAX_EVENTS 500
#define GUILD_MAX_LOCKED_EVENTS 200
struct PointHistory {
int32 date;
string modified_by;
string comment;
float points;
bool saved_needed;
};
struct GuildMember {
int32 character_id;
int32 account_id;
int32 recruiter_id; //00 00 00 00 if not a guild recruiter
char name[64];
int32 guild_status;
float points;
int8 adventure_class;
int8 adventure_level;
int8 tradeskill_class;
int8 tradeskill_level;
int8 rank;
int8 member_flags;
string zone;
int32 join_date;
int32 last_login_date;
string note;
string officer_note;
string recruiter_description;
unsigned char* recruiter_picture_data;
int16 recruiter_picture_data_size;
int8 recruiting_show_adventure_class;
deque<PointHistory*> point_history;
};
struct GuildEvent {
int64 event_id;
int32 date;
int32 type;
string description;
int8 locked;
bool save_needed;
};
struct GuildBankEvent {
int64 event_id;
int32 date;
int32 type;
string description;
};
struct Bank {
string name;
deque<GuildBankEvent*> events;
};
class Guild {
public:
Guild();
virtual ~Guild();
void SetID(int32 id_in) {id = id_in;}
void SetName(const char* name, bool send_packet = true);
void SetLevel(int8 level, bool send_packet = true);
void SetFormedDate(int32 formed_date_in) {formed_date = formed_date_in;}
void SetMOTD(const char *motd, bool send_packet = true);
int32 GetID() const {return id;}
const char* GetName() const {return name;}
int8 GetLevel() const {return level;}
int32 GetFormedDate() const {return formed_date;}
const char * GetMOTD() const {return motd;}
void SetEXPCurrent(int64 exp, bool send_packet = true);
void AddEXPCurrent(sint64 exp, bool send_packet = true);
int64 GetEXPCurrent() const {return exp_current;}
void SetEXPToNextLevel(int64 exp, bool send_packet = true);
int64 GetEXPToNextLevel() const {return exp_to_next_level;}
void SetRecruitingShortDesc(const char* new_desc, bool send_packet = true);
string GetRecruitingShortDesc() const {return recruiting_short_desc;}
void SetRecruitingFullDesc(const char* new_desc, bool send_packet = true);
string GetRecruitingFullDesc() const {return recruiting_full_desc;}
void SetRecruitingMinLevel(int8 new_level, bool send_packet = true);
int8 GetRecruitingMinLevel() const {return recruiting_min_level;}
void SetRecruitingPlayStyle(int8 new_play_style, bool send_packet = true);
int8 GetRecruitingPlayStyle() const {return recruiting_play_style;}
bool SetRecruitingDescTag(int8 index, int8 tag, bool send_packet = true);
int8 GetRecruitingDescTag(int8 index);
bool SetPermission(int8 rank, int8 permission, int8 value, bool send_packet = true);
int8 GetPermission(int8 rank, int8 permission);
bool SetEventFilter(int8 event_id, int8 category, int8 value, bool send_packet = true);
int8 GetEventFilter(int8 event_id, int8 category);
int32 GetNumUniqueAccounts();
int32 GetNumRecruiters();
int32 GetNextRecruiterID();
int64 GetNextEventID();
GuildMember* GetGuildMemberOnline(Client* client);
GuildMember* GetGuildMember(Player* player);
GuildMember* GetGuildMember(int32 character_id);
GuildMember* GetGuildMember(const char* player_name);
vector<GuildMember*>* GetGuildRecruiters();
GuildEvent* GetGuildEvent(int64 event_id);
bool SetRankName(int8 rank, const char* name, bool send_packet = true);
const char* GetRankName(int8 rank);
bool SetRecruitingFlag(int8 flag, int8 value, bool send_packet = true);
int8 GetRecruitingFlag(int8 flag);
bool SetGuildRecruiter(Client* client, const char* name, bool value, bool send_packet = true);
bool SetGuildRecruiterDescription(Client* client, const char* description, bool send_packet = true);
bool ToggleGuildRecruiterAdventureClass(Client* client, bool send_packet = true);
bool SetGuildMemberNote(const char* name, const char* note, bool send_packet = true);
bool SetGuildOfficerNote(const char* name, const char* note, bool send_packet = true);
bool AddNewGuildMember(Client* client, const char* invited_by = 0, int8 rank = GUILD_RANK_RECRUIT);
bool AddGuildMember(GuildMember* guild_member);
void RemoveGuildMember(int32 character_id, bool send_packet = true);
void RemoveAllGuildMembers();
bool DemoteGuildMember(Client* client, const char* name, bool send_packet = true);
bool PromoteGuildMember(Client* client, const char* name, bool send_packet = true);
bool KickGuildMember(Client* client, const char* name, bool send_packet = true);
bool InvitePlayer(Client* client, const char* name, bool send_packet = true);
bool AddPointsToAll(Client* client, float points, const char* comment = 0, bool send_packet = true);
bool AddPointsToAllOnline(Client* client, float points, const char* comment = 0, bool send_packet = true);
bool AddPointsToGroup(Client* client, float points, const char* comment = 0, bool send_packet = true);
bool AddPointsToRaid(Client* client, float points, const char* comment = 0, bool send_packet = true);
bool AddPointsToGuildMember(Client* client, float points, const char* name, const char* comment = 0, bool send_packet = true);
bool AddPointHistory(GuildMember* guild_member, int32 date, const char* modified_by, float points, const char* comment = 0, bool new_point_history = true);
void ViewGuildMemberPoints(Client* client, const char* name);
bool ChangeMemberFlag(Client* client, int8 member_flag, int8 value, bool send_packet = true);
bool UpdateGuildMemberInfo(Player* player);
bool UpdateGuildStatus(Player *player, int32 Status);
void AddGuildEvent(int64 event_id, int32 type, const char* description, int32 date, int8 locked);
void AddNewGuildEvent(int32 type, const char* description, int32 date, bool send_packet = true, ...);
bool LockGuildEvent(int64 event_id, bool lock, bool send_packet = true);
bool DeleteGuildEvent(int64 event_id, bool send_packet = true);
void SendGuildMOTD(Client* client);
void SendGuildEventList();
void SendGuildEventList(Client* client);
void SendGuildEventDetails();
void SendGuildEventDetails(Client* client);
void SendAllGuildEvents();
void SendAllGuildEvents(Client* client);
void SendOldGuildEvent(Client* client, GuildEvent* guild_event);
void SendNewGuildEvent(GuildEvent* guild_event);
void SendNewGuildEvent(Client* client, GuildEvent* guild_event);
void SendGuildEventAction(int8 action, GuildEvent* guild_event);
void SendGuildEventAction(Client* client, int8 action, GuildEvent* guild_event);
void SendGuildBankEventList();
void SendGuildBankEventList(Client* client);
void SendGuildUpdate();
void SendGuildUpdate(Client* client);
void SendGuildMemberList();
void SendGuildMemberList(Client* client);
void SendGuildMember(Player* player, bool include_zone = true);
void SendGuildMember(GuildMember* gm, bool include_zone = true);
void SendGuildMember(Client* client, GuildMember* gm, bool include_zone = true);
void SendGuildModification(float points, vector<int32>* character_ids);
void SendGuildModification(Client* client, float points, vector<int32>* character_ids);
void GuildMemberLogin(Client *client, bool first_login = false);
void GuildMemberLogoff(Player *player);
void SendGuildMemberLeave(int32 character_id);
void SendGuildMemberLeave(Client* client, int32 character_id);
void SendGuildRecruitingDetails(Client* client);
void SendGuildRecruitingImages(Client* client);
void SendGuildRecruiterInfo(Client* client, Player* player);
void HandleGuildSay(Client* sender, const char* message);
void HandleOfficerSay(Client* sender, const char* message);
void SendMessageToGuild(int8 event_type, const char* message, ...);
void SetSaveNeeded(bool val) {save_needed = val;}
bool GetSaveNeeded() {return save_needed;}
void SetMemberSaveNeeded(bool val) {member_save_needed = val;}
bool GetMemberSaveNeeded() {return member_save_needed;}
void SetEventsSaveNeeded(bool val) {events_save_needed = val;}
bool GetEventsSaveNeeded() {return events_save_needed;}
void SetRanksSaveNeeded(bool val) {ranks_save_needed = val;}
bool GetRanksSaveNeeded() {return ranks_save_needed;}
void SetEventFiltersSaveNeeded(bool val) {event_filters_save_needed = val;}
bool GetEventFiltersSaveNeeded() {return event_filters_save_needed;}
void SetPointsHistorySaveNeeded(bool val) {points_history_save_needed = val;}
bool GetPointsHistorySaveNeeded() {return points_history_save_needed;}
void SetRecruitingSaveNeeded(bool val) {recruiting_save_needed = val;}
bool GetRecruitingSaveNeeded() {return recruiting_save_needed;}
map<int32, GuildMember*>* GetGuildMembers() {return &members;}
Mutex * GetGuildMembersMutex() {return &mMembers;}
deque<GuildEvent*>* GetGuildEvents() {return &guild_events;}
MutexMap<int8, MutexMap<int8, int8>*>* GetPermissions() {return &permissions;}
MutexMap<int8, string>* GetGuildRanks() {return &ranks;}
MutexMap<int8, int8>* GetRecruitingFlags() {return &recruiting_flags;}
MutexMap<int8, int8>* GetRecruitingDescTags() {return &recruiting_desc_tags;}
int8 GetRecruitingLookingForPacketValue();
static string GetEpicMobDeathMessage(const char* player_name, const char* mob_name);
private:
int32 id;
char name[64];
int8 level;
int32 formed_date;
char motd[256];
int64 exp_current;
int64 exp_to_next_level;
string recruiting_short_desc;
string recruiting_full_desc;
int8 recruiting_min_level;
int8 recruiting_play_style;
MutexMap<int8, string> ranks;
map<int32, GuildMember*> members;
Mutex mMembers;
deque<GuildEvent*> guild_events;
MutexMap<int8, MutexMap<int8, int8>*> permissions;
MutexMap<int8, MutexMap<int8, int8>*> event_filters;
MutexMap<int8, int8> recruiting_flags;
MutexMap<int8, int8> recruiting_desc_tags;
Bank banks[4];
int32 GetPermissionsPacketValue(int8 rank, int32 start, int32 end);
int32 GetEventFilterPacketValue(int8 category, int32 start, int32 end);
bool save_needed;
bool member_save_needed;
bool events_save_needed;
bool event_filters_save_needed;
bool ranks_save_needed;
bool points_history_save_needed;
bool recruiting_save_needed;
};
class GuildList {
public:
GuildList();
virtual ~GuildList();
bool AddGuild(Guild* guild);
Guild* GetGuild(int32 guild_id);
Guild* GetGuild(const char* guild_name);
bool RemoveGuild(Guild* guild, bool delete_data = false);
bool RemoveGuild(int32 guild_id, bool delete_data = false);
int32 GetNumGuilds() {return guild_list.size();}
MutexMap<int32, Guild*>* GetGuilds() {return &guild_list;}
private:
MutexMap<int32, Guild*> guild_list;
};
#endif

View File

@ -0,0 +1,582 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef WIN32
#include <WinSock2.h>
#include <windows.h>
#endif
#include <math.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <ios>
#include <mysql.h>
#include <assert.h>
#include "../../common/Log.h"
#include "../WorldDatabase.h"
#include "Guild.h"
extern GuildList guild_list;
extern RuleManager rule_manager;
void WorldDatabase::LoadGuilds() {
int32 num_guilds = 0;
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `id`, `name`, `motd`, `level`, `xp`, `xp_needed`, `formed_on` FROM `guilds`");
while (result && (row = mysql_fetch_row(result))) {
LogWrite(GUILD__DEBUG, 1, "Guilds", "%u. %s", atoul(row[0]), row[1]);
Guild* guild = new Guild;
guild->SetID(atoul(row[0]));
guild->SetName(row[1]);
if (row[2])
guild->SetMOTD(row[2], false);
guild->SetLevel(atoi(row[3]), false);
guild->SetEXPCurrent(atoul(row[4]), false);
guild->SetEXPToNextLevel(atoul(row[5]), false);
guild->SetFormedDate(atoul(row[6]));
LogWrite(GUILD__DEBUG, 3, "Guilds", "\tLoaded %i guild members.", LoadGuildMembers(guild));
LogWrite(GUILD__DEBUG, 3, "Guilds", "\tLoading Guild Ranks...");
LoadGuildRanks(guild);
LogWrite(GUILD__DEBUG, 3, "Guilds", "\tLoading Guild Event Filters...");
LoadGuildEventFilters(guild);
LogWrite(GUILD__DEBUG, 3, "Guilds", "\tLoading Guild Events...");
LoadGuildEvents(guild);
LogWrite(GUILD__DEBUG, 3, "Guilds", "\tLoading Guild Recruiting...");
LoadGuildRecruiting(guild);
guild_list.AddGuild(guild);
num_guilds++;
}
LogWrite(GUILD__INFO, 0, "Guilds", "\tLoaded %u Guild(s)", num_guilds);
}
int32 WorldDatabase::LoadGuildMembers(Guild* guild) {
int32 num_members = 0;
Query query;
MYSQL_ROW row;
char *name;
int32 char_id;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `char_id`, `recruiter_id`, `guild_status`, `points`, `rank_id`, `member_flags`, `join_date`, `note`, `officer_note`, `recruiting_message`, `recruiter_picture_data` FROM `guild_members` WHERE `guild_id`=%u", guild->GetID());
while (result && (row = mysql_fetch_row(result))) {
char_id = atoul(row[0]);
if (!(name = GetCharacterName(char_id))) {
LogWrite(GUILD__ERROR, 0, "Guilds", "WorldDatabase::LoadGuildMembers Cannot find guild member with character id %u.", char_id);
continue;
}
GuildMember* gm = new GuildMember;
gm->character_id = char_id;
gm->recruiter_id = atoul(row[1]);
gm->guild_status = atoul(row[2]);
gm->points = atof(row[3]);
gm->rank = atoi(row[4]);
gm->member_flags = atoi(row[5]);
gm->join_date = atoul(row[6]);
if (row[7])
gm->note = string(row[7]);
if (row[8])
gm->officer_note = string(row[8]);
if (row[9])
gm->recruiter_description = string(row[9]);
int16 recruiter_picture_data_size = 0;
if (row[10] && (recruiter_picture_data_size = strlen(row[10])) > 0) {
gm->recruiter_picture_data_size = recruiter_picture_data_size / 2;
gm->recruiter_picture_data = new unsigned char[gm->recruiter_picture_data_size];
unsigned char* cpy = gm->recruiter_picture_data;
const char* str = row[10];
char high, low;
for (const char* ptr = str; *ptr; ptr += 2) {
high = tolower(*ptr);
low = tolower(*(ptr+1));
if (isdigit(high))
high = high - '0';
else if (high >= 'a' && high <= 'f')
high = (high - 'a') + 10;
else {
LogWrite(GUILD__ERROR, 0, "Guilds", "Guild mate with id %u has corrupt picture data. Data not loading.", gm->character_id);
safe_delete_array(gm->recruiter_picture_data);
gm->recruiter_picture_data_size = 0;
break;
}
if (isdigit(low))
low = low - '0';
else if (low >= 'a' && low <= 'f')
low = (low - 'a') + 10;
else {
LogWrite(GUILD__ERROR, 0, "Guilds", "Guild mate with id %u has corrupt picture data. Data not loading.", gm->character_id);
safe_delete_array(gm->recruiter_picture_data);
gm->recruiter_picture_data_size = 0;
break;
}
*cpy++ = low | (high << 4);
}
/*for (int16 i = 0; i < gm->recruiter_picture_data_size; i++)
if (i<10)
printf("int:%u hex:%x\n", gm->recruiter_picture_data[i], gm->recruiter_picture_data[i]);*/
}
else {
gm->recruiter_picture_data_size = 0;
gm->recruiter_picture_data = 0;
}
strncpy(gm->name, name, sizeof(gm->name));
gm->account_id = GetCharacterAccountID(char_id);
gm->adventure_class = GetCharacterClass(char_id);
gm->adventure_level = GetCharacterLevel(char_id);
gm->tradeskill_class = 0;
gm->tradeskill_level = 0;
gm->last_login_date = GetCharacterTimeStamp(char_id);
gm->zone = GetZoneDescription(GetCharacterCurrentZoneID(char_id));
gm->recruiting_show_adventure_class = 1;
LoadGuildPointsHistory(guild, gm);
guild->AddGuildMember(gm);
safe_delete_array(name);
num_members++;
}
return num_members;
}
void WorldDatabase::LoadGuildEvents(Guild* guild) {
if (guild) {
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `event_id`, `event_date`, `event_type`, `description`, `locked` FROM `guild_events` WHERE `guild_id`=%u AND `display`=1 AND `archived`=0 ORDER BY `event_date` DESC LIMIT 0, %u", guild->GetID(), GUILD_MAX_EVENTS);
while (result && (row = mysql_fetch_row(result)))
guild->AddGuildEvent(atoi64(row[0]), atoul(row[2]), row[3], atoul(row[1]), atoi(row[4]));
}
}
void WorldDatabase::LoadGuildRanks(Guild* guild) {
if (guild) {
LogWrite(GUILD__DEBUG, 3, "Guilds", "Loading Ranks for guild id: %u", guild->GetID());
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `rank_id`, `rank_name`, `permission1`, `permission2` FROM `guild_ranks` WHERE `guild_id`=%u", guild->GetID());
while (result && (row = mysql_fetch_row(result))) {
int8 rank_id = atoi(row[0]);
int32 permission1 = atoul(row[2]);
int32 permission2 = atoul(row[3]);
guild->SetRankName(rank_id, row[1], false);
LogWrite(GUILD__DEBUG, 5, "Guilds", "\tLoading rank_id: %i", rank_id);
LogWrite(GUILD__DEBUG, 5, "Guilds", "\tPermission1: %ul, Permission2: %ul", permission1, permission2);
for (int32 i = 0; i <= 44; i++) {
int32 bitwise_val;
if (i < 32) {
bitwise_val = (int32)pow(2.0, (double)(i));
guild->SetPermission(rank_id, i, permission1 & bitwise_val ? 1 : 0, false);
LogWrite(GUILD__DEBUG, 5, "Guilds", "\tSetting Permission %u to %u", i, permission1 & bitwise_val ? 1 : 0);
}
else {
bitwise_val = (int32)pow(2.0, (double)(i - 32));
guild->SetPermission(rank_id, i, permission2 & bitwise_val ? 1 : 0, false);
LogWrite(GUILD__DEBUG, 5, "Guilds", "\tSetting Permission %u to %u", i, permission2 & bitwise_val ? 1 : 0);
}
}
}
}
}
void WorldDatabase::LoadGuildEventFilters(Guild* guild) {
if (guild) {
Query query;
MYSQL_ROW row;
bool event_filter_added = false;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `event_id`, `retain`, `broadcast` FROM `guild_event_filters` WHERE `guild_id`=%u", guild->GetID());
while (result && (row = mysql_fetch_row(result))) {
guild->SetEventFilter(atoi(row[0]), GUILD_EVENT_FILTER_CATEGORY_RETAIN_HISTORY, atoi(row[1]), false);
guild->SetEventFilter(atoi(row[0]), GUILD_EVENT_FILTER_CATEGORY_BROADCAST, atoi(row[2]), false);
if (!event_filter_added)
event_filter_added = true;
}
if (!event_filter_added)
LoadGuildDefaultEventFilters(guild);
}
}
void WorldDatabase::LoadGuildPointsHistory(Guild* guild, GuildMember* guild_member) {
Query query;
MYSQL_ROW row;
MYSQL_RES* result;
assert(guild);
assert(guild_member);
result = query.RunQuery2(Q_SELECT, "SELECT `points_date`, `modified_by`, `comment`, `points` FROM `guild_points_history` WHERE `guild_id`=%u AND `char_id`=%u ORDER BY `points_date` DESC", guild->GetID(), guild_member->character_id);
while (result && (row = mysql_fetch_row(result)))
guild->AddPointHistory(guild_member, atoul(row[0]), row[1], atof(row[3]), row[2], false);
}
void WorldDatabase::LoadGuildRecruiting(Guild* guild) {
if (guild) {
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `short_desc`, `full_desc`, `min_level`, `play_style`, `looking_for`, `descriptive_tag1`, `descriptive_tag2`, `descriptive_tag3`, `descriptive_tag4` FROM `guild_recruiting` WHERE `guild_id`=%u", guild->GetID());
while (result && (row = mysql_fetch_row(result))) {
if (row[0])
guild->SetRecruitingShortDesc(row[0], false);
if (row[1])
guild->SetRecruitingFullDesc(row[1], false);
guild->SetRecruitingMinLevel(atoi(row[2]), false);
guild->SetRecruitingPlayStyle(atoi(row[3]), false);
for (int32 i = 0; i <= 5; i++) {
int32 bitwise_val = (int32)pow(2.0, (double)i);
guild->SetRecruitingFlag(i, atoi(row[4]) & bitwise_val ? 1 : 0, false);
}
guild->SetRecruitingDescTag(0, atoi(row[5]), false);
guild->SetRecruitingDescTag(1, atoi(row[6]), false);
guild->SetRecruitingDescTag(2, atoi(row[7]), false);
guild->SetRecruitingDescTag(3, atoi(row[8]), false);
}
}
}
void WorldDatabase::SaveGuild(Guild* guild, bool new_guild) {
Query query;
assert(guild);
if (new_guild) {
LogWrite(GUILD__DEBUG, 3, "Guilds", "Saving NEW Guild '%s' (%u) data...", guild->GetName(), guild->GetID());
query.RunQuery2(Q_INSERT, "INSERT INTO `guilds` (`name`, `motd`, `level`, `xp`, `xp_needed`, `formed_on`) "
"VALUES ('%s', '%s', %i, %llu, %llu, %u)",
getSafeEscapeString(guild->GetName()).c_str(), getSafeEscapeString(guild->GetMOTD()).c_str(), guild->GetLevel(), guild->GetEXPCurrent(), guild->GetEXPToNextLevel(), guild->GetFormedDate());
guild->SetID(query.GetLastInsertedID());
}
else {
LogWrite(GUILD__DEBUG, 3, "Guilds", "Saving Guild '%s' (%u) data...", guild->GetName(), guild->GetID());
query.RunQuery2(Q_UPDATE, "UPDATE `guilds` "
"SET `name`='%s', `motd`='%s', `level`=%i, `xp`=%llu, `xp_needed`=%llu, `formed_on`=%u WHERE `id`=%u",
getSafeEscapeString(guild->GetName()).c_str(), getSafeEscapeString(guild->GetMOTD()).c_str(), guild->GetLevel(), guild->GetEXPCurrent(), guild->GetEXPToNextLevel(), guild->GetFormedDate(), guild->GetID());
}
guild->SetSaveNeeded(false);
}
void WorldDatabase::SaveGuildMembers(Guild* guild) {
map<int32, GuildMember *>* members;
map<int32, GuildMember *>::iterator itr;
Mutex *mMembers;
GuildMember *gm;
Query query, query2;
assert(guild);
members = guild->GetGuildMembers();
mMembers = guild->GetGuildMembersMutex();
mMembers->readlock(__FUNCTION__, __LINE__);
for (itr = members->begin(); itr != members->end(); itr++) {
gm = itr->second;
LogWrite(GUILD__DEBUG, 5, "Guilds", "Saving Guild Member '%s' (%u) data...", gm->name, gm->character_id);
query.RunQuery2(Q_INSERT, "INSERT INTO `guild_members` (`guild_id`, `char_id`, `recruiter_id`, `guild_status`, `points`, `rank_id`, `member_flags`, `join_date`, `note`, `officer_note`, `recruiting_message`, `recruiter_picture_data`) VALUES (%u, %u, %u, %u, %f, %u, %u, %u, '%s', '%s', '%s', NULL) ON DUPLICATE KEY UPDATE `guild_id`=%u, `recruiter_id`=%u, `guild_status`=%u, `points`=%f, `rank_id`=%u, `member_flags`=%u, `join_date`=%u, `note`='%s', `officer_note`='%s', `recruiting_message`='%s', `recruiter_picture_data`=NULL", guild->GetID(), gm->character_id, gm->recruiter_id, gm->guild_status, gm->points, gm->rank, gm->member_flags, gm->join_date, getSafeEscapeString(gm->note.c_str()).c_str(), getSafeEscapeString(gm->officer_note.c_str()).c_str(), getSafeEscapeString(gm->recruiter_description.c_str()).c_str(), guild->GetID(), gm->recruiter_id, gm->guild_status, gm->points, gm->rank, gm->member_flags, gm->join_date, getSafeEscapeString(gm->note.c_str()).c_str(), getSafeEscapeString(gm->officer_note.c_str()).c_str(), getSafeEscapeString(gm->recruiter_description.c_str()).c_str());
if (gm && gm->recruiter_picture_data_size > 0 && gm->recruiter_picture_data) {
stringstream ss_hex;
stringstream ss_query;
ss_hex.flags(ios::hex);
for (int16 i = 0; i < gm->recruiter_picture_data_size; i++)
ss_hex << setfill('0') << setw(2) << (int)gm->recruiter_picture_data[i];
ss_query << "UPDATE `guild_members` SET `recruiter_picture_data`='" << ss_hex.str() << "' WHERE `char_id`=" << gm->character_id;
query2.RunQuery2(ss_query.str(), Q_UPDATE);
}
}
guild->SetMemberSaveNeeded(false);
mMembers->releasereadlock(__FUNCTION__, __LINE__);
}
void WorldDatabase::SaveGuildEvents(Guild* guild) {
if (guild) {
deque<GuildEvent*>* guild_events = guild->GetGuildEvents();
deque<GuildEvent*>::iterator itr;
for (itr = guild_events->begin(); itr != guild_events->end(); itr++) {
GuildEvent* ge = *itr;
if (!ge->save_needed)
continue;
LogWrite(GUILD__DEBUG, 5, "Guilds", "Saving Guild Events for guild '%s' (%u)...", guild->GetName(), guild->GetID());
Query query;
query.RunQuery2(Q_INSERT, "INSERT INTO `guild_events` (`guild_id`, `event_id`, `event_date`, `event_type`, `description`, `display`, `locked`, `archived`) "
"VALUES (%u, %llu, %u, %u, '%s', 1, %u, 0) "
"ON DUPLICATE KEY UPDATE `locked`=%i",
guild->GetID(), ge->event_id, ge->date, ge->type, getSafeEscapeString(ge->description.c_str()).c_str(), ge->locked, ge->locked);
ge->save_needed = false;
}
guild->SetEventsSaveNeeded(false);
}
}
void WorldDatabase::SaveGuildRanks(Guild* guild) {
if (guild) {
MutexMap<int8, MutexMap<int8, int8>*>* permissions = guild->GetPermissions();
MutexMap<int8, string>* ranks = guild->GetGuildRanks();
MutexMap<int8, string>::iterator ranks_itr = ranks->begin();
while (ranks_itr.Next()) {
int32 permission1 = 0;
int32 permission2 = 0;
for (int32 i = 0; i <= 44; i++) {
if (permissions->count(ranks_itr.first) > 0 && permissions->Get(ranks_itr.first)->count(i) > 0 && permissions->Get(ranks_itr.first)->Get(i)) {
if (i < 32)
permission1 += (int32)pow(2.0, (double)i);
else
permission2 += (int32)pow(2.0, (double)(i - 32));
}
}
LogWrite(GUILD__DEBUG, 5, "Guilds", "Saving Guild Ranks for guild '%s' (%u)...", guild->GetName(), guild->GetID());
Query query;
query.RunQuery2(Q_INSERT, "INSERT INTO `guild_ranks` (`guild_id`, `rank_id`, `rank_name`, `permission1`, `permission2`) "
"VALUES (%u, %u, '%s', %u, %u) "
"ON DUPLICATE KEY UPDATE `rank_name`='%s', `permission1`=%u, permission2=%u",
guild->GetID(), ranks_itr.first, getSafeEscapeString(ranks_itr.second.c_str()).c_str(), permission1, permission2, getSafeEscapeString(ranks_itr.second.c_str()).c_str(), permission1, permission2);
}
guild->SetRanksSaveNeeded(false);
}
}
void WorldDatabase::SaveGuildEventFilters(Guild* guild) {
int32 i;
assert(guild);
for (i = 0; i < 93; i++) {
LogWrite(GUILD__DEBUG, 5, "Guilds", "Saving Guild EventFilters for guild '%s' (%u)...", guild->GetName(), guild->GetID());
Query query;
query.RunQuery2(Q_INSERT, "INSERT INTO `guild_event_filters` (`guild_id`, `event_id`, `retain`, `broadcast`) "
"VALUES (%u, %u, %u, %u) "
"ON DUPLICATE KEY UPDATE `retain`=%u, `broadcast`=%u",
guild->GetID(), i, guild->GetEventFilter(i, GUILD_EVENT_FILTER_CATEGORY_RETAIN_HISTORY), guild->GetEventFilter(i, GUILD_EVENT_FILTER_CATEGORY_BROADCAST), guild->GetEventFilter(i, GUILD_EVENT_FILTER_CATEGORY_RETAIN_HISTORY), guild->GetEventFilter(i, GUILD_EVENT_FILTER_CATEGORY_BROADCAST));
}
guild->SetEventFiltersSaveNeeded(false);
}
void WorldDatabase::SaveGuildPointsHistory(Guild* guild) {
map<int32, GuildMember *> *members;
map<int32, GuildMember *>::iterator itr;
Mutex *mMembers;
deque<PointHistory *> *ph_list;
deque<PointHistory*>::iterator ph_itr;
PointHistory* ph;
assert (guild);
members = guild->GetGuildMembers();
mMembers = guild->GetGuildMembersMutex();
mMembers->readlock(__FUNCTION__, __LINE__);
for (itr = members->begin(); itr != members->end(); itr++) {
ph_list = &itr->second->point_history;
for (ph_itr = ph_list->begin(); ph_itr != ph_list->end(); ph_itr++) {
ph = *ph_itr;
if (!ph->saved_needed)
continue;
LogWrite(GUILD__DEBUG, 5, "Guilds", "Saving Guild Point History for guild '%s' (%u)...", guild->GetName(), guild->GetID());
Query query;
query.RunQuery2(Q_INSERT, "INSERT INTO `guild_points_history` (`guild_id`, `char_id`, `points_date`, `modified_by`, `comment`, `points`) "
"VALUES (%u, %u, %u, '%s', '%s', %f)",
guild->GetID(), itr->first, ph->date, getSafeEscapeString(ph->modified_by.c_str()).c_str(), getSafeEscapeString(ph->comment.c_str()).c_str(), ph->points);
ph->saved_needed = false;
}
}
guild->SetPointsHistorySaveNeeded(false);
mMembers->releasereadlock(__FUNCTION__, __LINE__);
}
void WorldDatabase::SaveGuildRecruiting(Guild* guild) {
if (guild) {
LogWrite(GUILD__DEBUG, 3, "Guilds", "Saving Recruiting info for guild '%s' (%u)...", guild->GetName(), guild->GetID());
Query query;
query.RunQuery2(Q_INSERT, "INSERT INTO `guild_recruiting` (`guild_id`, `short_desc`, `full_desc`, `min_level`, `play_style`, `looking_for`, `descriptive_tag1`, `descriptive_tag2`, `descriptive_tag3`, `descriptive_tag4`) VALUES (%u, '%s', '%s', %u, %u, %u, %u, %u, %u, %u) ON DUPLICATE KEY UPDATE `short_desc`='%s', `full_desc`='%s', `min_level`=%u, `play_style`=%u, `looking_for`=%u, `descriptive_tag1`=%u, `descriptive_tag2`=%u, `descriptive_tag3`=%u, `descriptive_tag4`=%u", guild->GetID(), getSafeEscapeString(guild->GetRecruitingShortDesc().c_str()).c_str(), getSafeEscapeString(guild->GetRecruitingFullDesc().c_str()).c_str(), guild->GetRecruitingMinLevel(), guild->GetRecruitingPlayStyle(), guild->GetRecruitingLookingForPacketValue(), guild->GetRecruitingDescTag(0), guild->GetRecruitingDescTag(1), guild->GetRecruitingDescTag(2), guild->GetRecruitingDescTag(3), getSafeEscapeString(guild->GetRecruitingShortDesc().c_str()).c_str(), getSafeEscapeString(guild->GetRecruitingFullDesc().c_str()).c_str(), guild->GetRecruitingMinLevel(), guild->GetRecruitingPlayStyle(), guild->GetRecruitingLookingForPacketValue(), guild->GetRecruitingDescTag(0), guild->GetRecruitingDescTag(1), guild->GetRecruitingDescTag(2), guild->GetRecruitingDescTag(3));
guild->SetRecruitingSaveNeeded(false);
}
}
void WorldDatabase::DeleteGuild(Guild* guild) {
if (guild) {
LogWrite(GUILD__DEBUG, 3, "Guilds", "Deleting Guild '%s' (%u)...", guild->GetName(), guild->GetID());
Query query;
query.RunQuery2(Q_DELETE, "DELETE FROM `guilds` WHERE `id`=%u", guild->GetID());
}
}
void WorldDatabase::DeleteGuildMember(Guild* guild, int32 character_id) {
if (guild) {
LogWrite(GUILD__DEBUG, 3, "Guilds", "Deleting Character (%u) from guild '%s' (%u)...", character_id, guild->GetName(), guild->GetID());
Query query;
query.RunQuery2(Q_DELETE, "DELETE FROM `guild_members` WHERE `guild_id`=%u AND `char_id`=%u", guild->GetID(), character_id);
}
}
void WorldDatabase::DeleteGuildEvent(Guild* guild, int64 event_id) {
if (guild) {
LogWrite(GUILD__DEBUG, 3, "Guilds", "Deleting Event (%u) from guild '%s' (%u)...", event_id, guild->GetName(), guild->GetID());
Query query;
query.RunQuery2(Q_DELETE, "DELETE FROM `guild_events` WHERE `guild_id`=%u AND `event_id`=%u", guild->GetID(), event_id);
}
}
void WorldDatabase::DeleteGuildPointHistory(Guild* guild, int32 character_id, PointHistory* point_history) {
if (guild && point_history) {
LogWrite(GUILD__DEBUG, 3, "Guilds", "Deleting PointHistory for Character (%u) from guild '%s' (%u)...", character_id, guild->GetName(), guild->GetID());
Query query;
query.RunQuery2(Q_DELETE, "DELETE FROM `guild_points_history` WHERE `guild_id`=%u AND `char_id`=%u AND `points_date`=%u", guild->GetID(), character_id, point_history->date);
}
}
void WorldDatabase::ArchiveGuildEvent(Guild* guild, GuildEvent* guild_event) {
if (guild && guild_event) {
LogWrite(GUILD__DEBUG, 3, "Guilds", "Archiving Event (%u) for guild '%s' (%u)...", guild_event->event_id, guild->GetName(), guild->GetID());
Query query;
query.RunQuery2(Q_UPDATE, "UPDATE `guild_events` SET `archived`=1 WHERE `guild_id`=%u AND `event_id`=%u", guild->GetID(), guild_event->event_id);
}
}
void WorldDatabase::SaveHiddenGuildEvent(Guild* guild, GuildEvent* guild_event) {
if (guild && guild_event) {
LogWrite(GUILD__DEBUG, 3, "Guilds", "Saving Hidden Event (%u) for guild '%s' (%u)...", guild_event->event_id, guild->GetName(), guild->GetID());
Query query;
query.RunQuery2(Q_INSERT, "INSERT INTO `guild_events` (`guild_id`, `event_id`, `event_date`, `event_type`, `description`, `display`, `locked`, `archived`) VALUES (%u, %u, %u, %u, '%s', 0, %u, 0)", guild->GetID(), guild_event->event_id, guild_event->type, guild_event->date, getSafeEscapeString(guild_event->description.c_str()).c_str(), guild_event->locked);
}
}
int32 WorldDatabase::GetGuildIDByCharacterID(int32 char_id) {
if(char_id > 0)
{
LogWrite(GUILD__DEBUG, 3, "Guilds", "Look up guild ID for player ID: '%u'...", char_id);
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT name FROM guilds, guild_members WHERE guilds.id = guild_members.guild_id AND char_id = %u ", char_id);
while (result && (row = mysql_fetch_row(result))) {
if( row[0] )
return atoul(row[0]);
}
}
return 0;
}
void WorldDatabase::LoadGuildDefaultRanks(Guild* guild) {
if (guild) {
LogWrite(GUILD__DEBUG, 3, "Guilds", "Load/Set Default Ranks for guild '%s' (%u)...", guild->GetName(), guild->GetID());
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT DISTINCT `rank_id`, `rank_name`, `permission1`, `permission2` FROM `guild_ranks_defaults`");
while (result && (row = mysql_fetch_row(result))) {
int8 rank_id = atoi(row[0]);
int32 permission1 = atoul(row[2]);
int32 permission2 = atoul(row[3]);
LogWrite(GUILD__DEBUG, 3, "Guilds", "\tSetting RankID %i, permission1: %u, permission2: %u", rank_id, permission1, permission2);
guild->SetRankName(rank_id, row[1], false);
for (int32 i = 0; i <= 44; i++) {
int32 bitwise_val;
if (i < 32) {
bitwise_val = (int32)pow(2.0, (double)i);
guild->SetPermission(rank_id, i, permission1 & bitwise_val ? 1 : 0, false);
}
else {
bitwise_val = (int32)pow(2.0, (double)(i - 32));
guild->SetPermission(rank_id, i, permission2 & bitwise_val ? 1 : 0, false);
}
}
}
}
}
void WorldDatabase::LoadGuildDefaultEventFilters(Guild* guild) {
if (guild) {
LogWrite(GUILD__DEBUG, 3, "Guilds", "Load/Set Default Event Filters for guild '%s' (%u)...", guild->GetName(), guild->GetID());
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT DISTINCT `event_id`, `retain`, `broadcast` FROM `guild_event_defaults`");
while (result && (row = mysql_fetch_row(result))) {
LogWrite(GUILD__DEBUG, 3, "Guilds", "\tSetting Event Filter %i, retain: %i, broadcast: %i", atoi(row[0]), atoi(row[1]), atoi(row[2]));
guild->SetEventFilter(atoi(row[0]), GUILD_EVENT_FILTER_CATEGORY_RETAIN_HISTORY, atoi(row[1]), false);
guild->SetEventFilter(atoi(row[0]), GUILD_EVENT_FILTER_CATEGORY_BROADCAST, atoi(row[2]), false);
}
}
}
bool WorldDatabase::AddNewPlayerToServerGuild(int32 account_id, int32 char_id)
{
// Check if this servers rule allow auto-joining Server guild
int8 autojoin = rule_manager.GetGlobalRule(R_World, GuildAutoJoin)->GetInt8();
if( autojoin )
{
// if so, what is the guild ID of the default server guild?
int32 guild_id = rule_manager.GetGlobalRule(R_World, GuildAutoJoinID)->GetInt32();
Guild* guild = 0;
guild = guild_list.GetGuild(guild_id);
if (!guild)
{
// guild was not valid, abort!
LogWrite(GUILD__ERROR, 1, "Guilds", "Guild ID %u not found! Cannot autojoin members!", guild_id);
return false;
}
else
{
// guild was found, so what default Rank to make the players? if not set, use 7 (recruit)
int8 rank_id = rule_manager.GetGlobalRule(R_World, GuildAutoJoinDefaultRankID)->GetInt8();
if(!rank_id)
rank_id = 7;
// assuming all is good, insert the new guild member here...
GuildMember *gm = new GuildMember();
gm->account_id = account_id;
gm->character_id = char_id;
char* name = GetCharacterName(gm->character_id);
strncpy(gm->name, name, sizeof(gm->name));
gm->guild_status = 0;
gm->points = 0.0;
//gm->adventure_class = player->GetAdventureClass();
//gm->adventure_level = player->GetLevel();
//gm->tradeskill_class = player->GetTradeskillClass();
//gm->tradeskill_level = player->GetTSLevel();
gm->rank = rank_id;
gm->zone = string("");
gm->join_date = Timer::GetUnixTimeStamp();
gm->last_login_date = gm->join_date;
gm->recruiter_id = 0;
gm->member_flags = GUILD_MEMBER_FLAGS_NOTIFY_LOGINS;
gm->recruiting_show_adventure_class = 1;
gm->recruiter_picture_data_size = 0;
gm->recruiter_picture_data = 0;
guild->AddGuildMember(gm);
Query query;
query.RunQuery2(Q_INSERT, "INSERT INTO `guild_members` (`guild_id`, `char_id`, `join_date`, `rank_id`) VALUES (%u, %u, %u, %i)",
guild_id, char_id, gm->join_date, rank_id);
LogWrite(GUILD__DEBUG, 3, "Guilds", "Auto-join player (%u) to server guild '%s' (%u) at rank %i...", char_id, guild->GetName(), guild_id, rank_id);
// success!
return true;
}
}
// do not auto-join server guild
return false;
}

View File

@ -0,0 +1,315 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "HeroicOp.h"
#include "../../common/Log.h"
#include "../Rules/Rules.h"
extern MasterHeroicOPList master_ho_list;
extern RuleManager rule_manager;
HeroicOP::HeroicOP() {
m_complete = 0;
m_currentStage = 0;
m_wheel = 0;
m_target = 0;
m_startTime = 0;
m_totalTime = 0;
m_shifted = false;
for (int8 i = 0; i < 6; i++)
countered[i] = 0;
}
HeroicOP::~HeroicOP() {
starters.clear();
}
void HeroicOP::SetWheel(HeroicOPWheel* val) {
if (!m_wheel)
m_wheel = val;
else
LogWrite(SPELL__ERROR, 0, "HO", "Attempted to set the wheel on a heroic op with a wheel already set");
}
void HeroicOP::SetTarget(int32 val) {
m_target = val;
}
bool HeroicOP::UpdateHeroicOP(int16 icon) {
bool ret = false;
vector<HeroicOPStarter*>::iterator itr;
vector<HeroicOPStarter*> temp;
HeroicOPStarter* starter = 0;
LogWrite(SPELL__DEBUG, 0, "HO", "Current Stage %u, wheel exists: %u, looking for icon %u", m_currentStage, m_wheel ? 1 : 0, icon);
// If no wheel is set we are dealing with a starter chain still.
if (!m_wheel) {
// Loop through the starter chains
for (itr = starters.begin(); itr != starters.end(); itr++) {
starter = *itr;
// See if the icon matches the ability at our current stage, if not add it to a list to be removed
if (starter->abilities[m_currentStage] == icon)
ret = true;
else
temp.push_back(*itr);
}
if (ret) {
// ret = true so we had a match, first thing to do is remove those that didn't match
vector<HeroicOPStarter*>::iterator remove_itr;
for (remove_itr = temp.begin(); remove_itr != temp.end(); remove_itr++)
{
std::vector<HeroicOPStarter*>::iterator it = std::find(starters.begin(), starters.end(), *remove_itr);
starters.erase(it);
}
// now advance the current stage
m_currentStage++;
// Temp pointer to hold the completed chain, if any
HeroicOPStarter* complete_starter = 0;
// now loop through those that are left and check the next stage abilities for a 0xFFFF
for (itr = starters.begin(); itr != starters.end(); itr++) {
starter = *itr;
// Found one that is 0xFFFF, means the starter chain is done, get a wheel and reset the stage to 0
if ((starter->abilities[m_currentStage] == 0xFFFF)) {
LogWrite(SPELL__DEBUG, 0, "HO", "Current Stage %u, starter reset (new stage 0)", m_currentStage);
// reset the stage
ResetStage();
// geth the wheel
m_wheel = master_ho_list.GetWheel(starter);
// store the starter chain that is completed
complete_starter = starter;
// set the start time to now
SetStartTime(Timer::GetCurrentTime2());
// set the total time to complete the real to was the admin set in rules (default 10.0f)
SetTotalTime(rule_manager.GetGlobalRule(R_Zone, HOTime)->GetFloat());
// We set a wheel so we are done, kill the loop
break;
}
}
// Check to see if the completed start chain pointer was set
if (complete_starter) {
LogWrite(SPELL__DEBUG, 0, "HO", "Current Stage %u, complete_starter set", m_currentStage);
// clear the starter list
starters.clear();
// add the completed starter back in, we do this in case we need this starter again we can just do starters.at(0), for example shifting the wheel
starters.push_back(complete_starter);
}
}
}
else {
LogWrite(SPELL__DEBUG, 0, "HO", "Current Stage %u, wheel order: %u", m_currentStage, m_wheel->order);
// Wheel was set so we need to check the order it needs to be completed in.
if (m_wheel->order == 0) {
// No order
// Flag used to see if we can shift the wheel
bool can_shift = true;
// Check the icons and flag the ability as countered if there is a match
for (int8 i = 0; i < 6; i++) {
if (countered[i] == 1) {
// progress made on this wheel so we can't shift it
can_shift = false;
}
if (m_wheel->abilities[i] == icon) {
countered[i] = 1;
ret = true;
}
}
if (ret) {
// As we found a match lets loop through to see if we completed the ho
bool finished = true;
for (int8 i = 0; i < 6; i++) {
// if the ability is not 0xFFFF and countered is 0 then we still have more to go
if (m_wheel->abilities[i] != 0xFFFF && countered[i] == 0) {
finished = false;
break;
}
}
// is we finished the ho set the complete flag
if (finished)
SetComplete(2);
}
if (!ret && can_shift && m_wheel->shift_icon == icon) {
// can shift, icon matched shift icon, and no progress made
ret = ShiftWheel();
}
}
else {
// In order
// Check to see if we can shift the wheel
if (countered[0] == 0 && icon == m_wheel->shift_icon) {
// Can only shift the icon if nothing has completed yet (countered[0] = 0)
ret = ShiftWheel();
}
// Check the current stage and compare it to the icon
else if (m_wheel->abilities[m_currentStage] == icon) {
// Is a match so flag this stage as done
countered[m_currentStage] = 1;
// Advance the stage
m_currentStage++;
// Set the return value to true
ret = true;
// Check the next stage, if it is over 6 or equal to 0xFFFF flag the HO as complete
if (m_currentStage > 6 || m_wheel->abilities[m_currentStage] == 0xFFFF)
SetComplete(2);
}
}
}
return ret;
}
void HeroicOP::AddStarterChain(HeroicOPStarter* starter) {
starters.push_back(starter);
}
bool HeroicOP::ShiftWheel() {
// Can only shift once so if we already have return out
if (HasShifted())
return false;
// Clear the wheel
m_wheel = 0;
// Get a new Wheel
SetWheel(master_ho_list.GetWheel(starters.at(0)));
// Set the ho as shifted
m_shifted = true;
return true;
}
MasterHeroicOPList::MasterHeroicOPList() {
}
MasterHeroicOPList::~MasterHeroicOPList() {
map<int8, map<HeroicOPStarter*, vector<HeroicOPWheel*> > >::iterator itr;
map<HeroicOPStarter*, vector<HeroicOPWheel*> >::iterator itr2;
vector<HeroicOPWheel*>::iterator itr3;
vector<HeroicOPStarter*> temp;
vector<HeroicOPStarter*>::iterator itr4;
// loop through the m_hoList to delete the pointers
for (itr = m_hoList.begin(); itr != m_hoList.end(); itr++) {
// loop through the second map of the m_hoList
for (itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++) {
// loop through the vector of the second map and delete the pointers
for (itr3 = itr2->second.begin(); itr3 != itr2->second.end(); itr3++)
safe_delete(*itr3);
// clear the vector
itr2->second.clear();
// put the starter in a temp list to delete later
temp.push_back(itr2->first);
}
// clear the seond map
itr->second.clear();
}
// clear the m_hoList
m_hoList.clear();
// Delete the starters
for (itr4 = temp.begin(); itr4 != temp.end(); itr4++)
safe_delete(*itr4);
// clear the temp vector
temp.clear();
}
void MasterHeroicOPList::AddStarter(int8 start_class, HeroicOPStarter* starter) {
if (m_hoList.count(start_class) == 0 || m_hoList[start_class].count(starter) == 0) {
m_hoList[start_class][starter]; // This adds the starter with out giving it a vector of wheels yet.
}
}
void MasterHeroicOPList::AddWheel(int32 starter_id, HeroicOPWheel* wheel) {
map<int8, map<HeroicOPStarter*, vector<HeroicOPWheel*> > >::iterator itr;
map<HeroicOPStarter*, vector<HeroicOPWheel*> >::iterator itr2;
bool found = false;
// Loop through the list and add the wheel to the correct starter
for (itr = m_hoList.begin(); itr != m_hoList.end(); itr++) {
for (itr2 = itr->second.begin(); itr2 != itr->second.end(); itr2++) {
if (itr2->first->id == starter_id) {
// Found a match, add the wheel, set the flag to break the first loop, and break this loop
itr2->second.push_back(wheel);
found = true;
break;
}
}
// If we found a match break the first loop
if (found)
break;
}
// No match found give an error.
if (!found)
LogWrite(SPELL__DEBUG, 0, "HO", "Attempted to add a wheel to a starter (%u) that doesn't exsist", starter_id);
}
HeroicOP* MasterHeroicOPList::GetHeroicOP(int8 class_id) {
if (m_hoList.count(class_id) == 0) {
LogWrite(SPELL__ERROR, 0, "HO", "No HO's found for the given class (%i)", class_id);
return 0;
}
map<HeroicOPStarter*, vector<HeroicOPWheel*> >::iterator itr;
HeroicOP* ret = new HeroicOP();
// Loop through the starters for this class and add them to the HO
for (itr = m_hoList[class_id].begin(); itr != m_hoList[class_id].end(); itr++)
ret->AddStarterChain(itr->first);
return ret;
}
HeroicOPWheel* MasterHeroicOPList::GetWheel(HeroicOPStarter* starter) {
if (!starter)
return 0;
if (m_hoList.count(starter->start_class) == 0) {
LogWrite(SPELL__ERROR, 0, "HO", "Start class (%u) not found", starter->start_class);
return 0;
}
if (m_hoList[starter->start_class].count(starter) == 0) {
LogWrite(SPELL__ERROR, 0, "HO", "Wheel not found for the provided starter (%u)", starter->id);
return 0;
}
int index = MakeRandomInt(0, m_hoList[starter->start_class][starter].size() - 1);
if(index < m_hoList[starter->start_class][starter].size())
return m_hoList[starter->start_class][starter].at(index);
else
LogWrite(SPELL__ERROR, 0, "HO", "Wheel index %u for heroic_ops starter ID %u NOT Found!! Wheel starter_class %u, wheel size: %u. Wheels that match starter_link_id -> Starter 'id' missing.", index, starter->id, starter->start_class, m_hoList[starter->start_class][starter].size());
return nullptr;
}

View File

@ -0,0 +1,156 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __HEROICOP_H__
#define __HEROICOP_H__
#include <map>
#include <vector>
#include "../../common/types.h"
using namespace std;
struct HeroicOPStarter {
int32 id;
int8 start_class;
int16 starter_icon;
int16 abilities[6];
};
struct HeroicOPWheel {
int8 order;
int16 shift_icon;
float chance;
int16 abilities[6];
int32 spell_id;
};
class HeroicOP {
public:
HeroicOP();
~HeroicOP();
/// <summary>Sets the complete flag for this Heroic OP</summary>
/// <param name='val'>The value to set the complete flag to, 1 = failed 2 = finished</param>
void SetComplete(int8 val) { m_complete = val; }
/// <summary>Sets the current stage of the starter chain or the wheel chain is at</summary>
/// <param name='val'>The stage to set this Heroic OP to</param>
void SetStage(int8 val) { m_currentStage = val; }
/// <summary>Sets the wheel for this Heroic OP</summary>
/// <param name='val'>The wheel we are setting the Heroic OP to</param>
void SetWheel(HeroicOPWheel* val);
/// <summary>Sets the start time for the wheel</summary>
/// <param name='val'>Value to set the start time to</param>
void SetStartTime(int32 val) { m_startTime = val; }
/// <summary>Sets the total time to complete the wheel</summary>
/// <param name='val'>Value to set the total time to</param>
void SetTotalTime(float val) { m_totalTime = val; }
/// <summary>Sets the target of this HO</summary>
/// <param name='val'>The ID of the spawn</param>
void SetTarget(int32 val);
/// <summary>Gets the complete flag for this Heroic OP</summary>
/// <returns>0 = not complete, 1 = complete, 2+= failed</returns>
int8 GetComplete() { return m_complete; }
/// <summary>Gets the wheel for this heroic op</summary>
HeroicOPWheel* GetWheel() { return m_wheel; }
/// <summary>Gets a pointer to the list of starter chains</summary>
vector<HeroicOPStarter*>* GetStarterChains() { return &starters; }
/// <summary>Gets the current stage the HO is on</summary>
int8 GetStage() { return m_currentStage; }
/// <summary>Gets the start time for the wheel</summary>
int32 GetStartTime() { return m_startTime; }
/// <summary>Gets the total time players have to complete the wheel</summary>
float GetTotalTime() { return m_totalTime; }
/// <summary>Gets the ID of this HO's target</summary>
int32 GetTarget() { return m_target; }
/// <summary></summary>
bool HasShifted() { return m_shifted; }
/// <summary>Checks to see if the given icon will advance the Heroic OP</summary>
/// <param name='icon'>The icon that is trying to advance the Heroic OP</param>
/// <returns>True if the icon advanced the HO</returns>
bool UpdateHeroicOP(int16 icon);
/// <summary>Reset the stage to 0</summary>
void ResetStage() { m_currentStage = 0; }
/// <summary>Adds a starter chain to the Heroic OP</summary>
/// <param name='starter'>The starter chain to add</param>
void AddStarterChain(HeroicOPStarter* starter);
/// <summary>Attempts to shift the wheel</summary>
bool ShiftWheel();
int8 countered[6];
private:
int8 m_complete;
int8 m_currentStage;
int32 m_startTime;
float m_totalTime;
int32 m_target;
bool m_shifted;
HeroicOPWheel* m_wheel;
vector<HeroicOPStarter*> starters;
};
class MasterHeroicOPList {
public:
MasterHeroicOPList();
~MasterHeroicOPList();
/// <summary>Adds the starter chain to the list</summary>
/// <param name='start_class'>Class id for the starter chain</param>
/// <param name='starter'>Starter chain to add</param>
void AddStarter(int8 start_class, HeroicOPStarter* starter);
/// <summary>Add the wheel chain to the list</summary>
/// <param name='starter_id'>Id of the starter this wheel belongs to</param>
/// <param name='wheel'>Wheel to add</param>
void AddWheel(int32 starter_id, HeroicOPWheel* wheel);
/// <summary>Creates a new HO</summary>
/// <param name='class_id'>Class ID starting the HO</param>
HeroicOP* GetHeroicOP(int8 class_id);
/// <summary>Gets a random wheel from the given starter</summary>
/// <param name='starter'>The starter to determine what wheels to choose from</param>
HeroicOPWheel* GetWheel(HeroicOPStarter* starter);
private:
// map<class, map<starter, vector<wheel> > >
map<int8, map<HeroicOPStarter*, vector<HeroicOPWheel*> > > m_hoList;
};
#endif

View File

@ -0,0 +1,79 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../WorldDatabase.h"
#include "../../common/Log.h"
#include "HeroicOp.h"
extern MasterHeroicOPList master_ho_list;
void WorldDatabase::LoadHOStarters() {
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `id`, `starter_class`, `starter_icon`, `ability1`, `ability2`, `ability3`, `ability4`, `ability5`, `ability6` FROM `heroic_ops` WHERE `ho_type`='Starter'");
if (result && mysql_num_rows(result) > 0) {
int32 count = 0;
while ((row = mysql_fetch_row(result))) {
HeroicOPStarter* starter = new HeroicOPStarter;
starter->id = atoul(row[0]);
starter->start_class = atoi(row[1]);
starter->starter_icon = atoi(row[2]);
starter->abilities[0] = atoi(row[3]);
starter->abilities[1] = atoi(row[4]);
starter->abilities[2] = atoi(row[5]);
starter->abilities[3] = atoi(row[6]);
starter->abilities[4] = atoi(row[7]);
starter->abilities[5] = atoi(row[8]);
master_ho_list.AddStarter(starter->start_class, starter);
count++;
}
LogWrite(WORLD__INFO, 0, "World", "- Loaded %u starter chains", count);
}
}
void WorldDatabase::LoadHOWheel() {
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `starter_link_id`, `chain_order`, `shift_icon`, `spell_id`, `chance`, `ability1`, `ability2`, `ability3`, `ability4`, `ability5`, `ability6` FROM `heroic_ops` WHERE `ho_type`='Wheel'");
if (result && mysql_num_rows(result) > 0) {
int32 count = 0;
while ((row = mysql_fetch_row(result))) {
HeroicOPWheel* wheel = new HeroicOPWheel;
wheel->order = atoi(row[1]);
wheel->shift_icon = atoi(row[2]);
wheel->spell_id = atoul(row[3]);
wheel->chance = atof(row[4]);
wheel->abilities[0] = atoi(row[5]);
wheel->abilities[1] = atoi(row[6]);
wheel->abilities[2] = atoi(row[7]);
wheel->abilities[3] = atoi(row[8]);
wheel->abilities[4] = atoi(row[9]);
wheel->abilities[5] = atoi(row[10]);
master_ho_list.AddWheel(atoul(row[0]), wheel);
count++;
}
LogWrite(WORLD__INFO, 0, "World", "- Loaded %u HO wheels", count);
}
}

View File

@ -0,0 +1,158 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../ClientPacketFunctions.h"
#include "../../common/Log.h"
#include "HeroicOp.h"
#include "../Spells.h"
extern ConfigReader configReader;
extern MasterSpellList master_spell_list;
void ClientPacketFunctions::SendHeroicOPUpdate(Client* client, HeroicOP* ho) {
if (!client) {
LogWrite(PACKET__ERROR, 0, "Packets", "SendHeroicOPUpdate() called without a valid client");
return;
}
if (!ho) {
LogWrite(PACKET__ERROR, 0, "Packets", "SendHeroicOPUpdate() called without a valid HO");
return;
}
PacketStruct* packet = configReader.getStruct("WS_HeroicOpportunity", client->GetVersion());
Spell* spell = 0;
if (packet) {
packet->setDataByName("id", client->GetPlayer()->GetIDWithPlayerSpawn(client->GetPlayer()));
if (ho->GetWheel()) {
spell = master_spell_list.GetSpell(ho->GetWheel()->spell_id, 1);
if (!spell) {
LogWrite(SPELL__ERROR, 0, "HO", "Unable to get the spell (%u)", ho->GetWheel()->spell_id);
return;
}
packet->setDataByName("name", spell->GetName());
packet->setDataByName("description", spell->GetDescription());
packet->setDataByName("order", ho->GetWheel()->order);
packet->setDataByName("time_total", ho->GetTotalTime());
packet->setDataByName("time_left", max(0.0f, (float)(((ho->GetStartTime() + (ho->GetTotalTime() * 1000)) - Timer::GetCurrentTime2()) / 1000)));
// This is not displayed in the wheel so set it to 0xFFFF
packet->setDataByName("starter_icon", 0xFFFF);
if (ho->HasShifted())
packet->setDataByName("shift_icon", 0xFFFF);
else
packet->setDataByName("shift_icon", ho->GetWheel()->shift_icon);
// If completed set special values
if (ho->GetComplete() > 0) {
packet->setDataByName("wheel_type", 2);
packet->setDataByName("unknown", ho->GetComplete());
}
char temp[20];
char ability[20];
// Set the icons for the whee;
for (int8 i = 1; i < 7; i++) {
strcpy(ability, "icon");
itoa(i, temp, 10);
strcat(ability, temp);
packet->setDataByName(ability, ho->GetWheel()->abilities[i-1]);
}
// Flag the icons that are completed
for (int8 i = 1; i < 7; i++) {
strcpy(ability, "countered");
itoa(i, temp, 10);
strcat(ability, temp);
packet->setDataByName(ability, ho->countered[i-1]);
}
}
else {
if (ho->GetComplete() > 0) {
// This will make the ui element vanish
packet->setDataByName("wheel_type", 5);
packet->setDataByName("unknown", 8);
}
else {
packet->setDataByName("wheel_type", 4);
}
packet->setDataByName("icon1", 0xFFFF);
packet->setDataByName("icon2", 0xFFFF);
packet->setDataByName("icon3", 0xFFFF);
packet->setDataByName("icon4", 0xFFFF);
packet->setDataByName("icon5", 0xFFFF);
packet->setDataByName("icon6", 0xFFFF);
packet->setDataByName("shift_icon", 0xFFFF);
int8 index = 1;
char temp[20];
char ability[20];
vector<HeroicOPStarter*>::iterator itr;
for (itr = ho->GetStarterChains()->begin(); itr != ho->GetStarterChains()->end(); itr++, index++) {
if (index > 6 )
break;
strcpy(ability, "icon");
itoa(index, temp, 10);
strcat(ability, temp);
packet->setDataByName(ability, (*itr)->abilities[ho->GetStage()]);
// Only set this once
if (index == 1)
packet->setDataByName("starter_icon", (*itr)->starter_icon);
}
}
client->QueuePacket(packet->serialize());
}
safe_delete(packet);
}
/*
<Struct Name="WS_HeroicOpportunity" ClientVersion="1" OpcodeName="OP_UpdateOpportunityMsg">
<Data ElementName="name" Type="EQ2_16Bit_String" />
<Data ElementName="description" Type="EQ2_16Bit_String" />
<Data ElementName="id" Type="int32" />
<Data ElementName="wheel_type" Type="int8" />
<Data ElementName="unknown" Type="int8" />
<Data ElementName="order" Type="int8" />
<Data ElementName="shift_icon" Type="int16" />
<Data ElementName="starter_icon" Type="int16" />
<Data ElementName="time_total" Type="float" />
<Data ElementName="time_left" Type="float" />
<Data ElementName="icon1" Type="int16" />
<Data ElementName="icon2" Type="int16" />
<Data ElementName="icon3" Type="int16" />
<Data ElementName="icon4" Type="int16" />
<Data ElementName="icon5" Type="int16" />
<Data ElementName="icon6" Type="int16" />
<Data ElementName="countered1" Type="int16" />
<Data ElementName="countered2" Type="int16" />
<Data ElementName="countered3" Type="int16" />
<Data ElementName="countered4" Type="int16" />
<Data ElementName="countered5" Type="int16" />
<Data ElementName="countered6" Type="int16" />
</Struct>
*/

View File

@ -0,0 +1,131 @@
#include "../WorldDatabase.h"
#include "../World.h"
extern World world;
void WorldDatabase::LoadHouseZones() {
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT * FROM `houses`");
if (result && mysql_num_rows(result) > 0) {
while ((row = mysql_fetch_row(result))) {
world.AddHouseZone(atoul(row[0]), row[1], atoi64(row[2]), atoul(row[3]), atoi64(row[4]), atoul(row[5]), atoi(row[6]), atoi(row[7]), atoi(row[8]), atoul(row[9]), atoul(row[10]), atof(row[11]), atof(row[12]), atof(row[13]), atof(row[14]));
}
}
}
int64 WorldDatabase::AddPlayerHouse(int32 char_id, int32 house_id, int32 instance_id, int32 upkeep_due) {
Query query;
string insert = string("INSERT INTO character_houses (char_id, house_id, instance_id, upkeep_due) VALUES (%u, %u, %u, %u) ");
query.RunQuery2(Q_INSERT, insert.c_str(), char_id, house_id, instance_id, upkeep_due);
int64 unique_id = query.GetLastInsertedID();
return unique_id;
}
void WorldDatabase::SetHouseUpkeepDue(int32 char_id, int32 house_id, int32 instance_id, int32 upkeep_due) {
Query query;
string update = string("UPDATE character_houses set upkeep_due=%u where char_id = %u and house_id = %u and instance_id = %u");
query.RunQuery2(Q_UPDATE, update.c_str(), upkeep_due, char_id, house_id, instance_id);
}
void WorldDatabase::UpdateHouseEscrow(int32 house_id, int32 instance_id, int64 amount_coins, int32 amount_status) {
Query query;
string update = string("UPDATE character_houses set escrow_coins = %llu, escrow_status = %u where house_id = %u and instance_id = %u");
query.RunQuery2(Q_UPDATE, update.c_str(), amount_coins, amount_status, house_id, instance_id);
}
void WorldDatabase::RemovePlayerHouse(int32 char_id, int32 house_id) {
}
void WorldDatabase::LoadPlayerHouses() {
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT h.id, h.char_id, h.house_id, h.instance_id, h.upkeep_due, h.escrow_coins, h.escrow_status, c.name FROM character_houses h, characters c WHERE h.char_id = c.id");
if (result && mysql_num_rows(result) > 0) {
while ((row = mysql_fetch_row(result))) {
world.AddPlayerHouse(atoul(row[1]), atoul(row[2]), atoi64(row[0]), atoul(row[3]), atoul(row[4]), atoi64(row[5]), atoul(row[6]), row[7]);
}
}
}
void WorldDatabase::LoadDeposits(PlayerHouse* ph)
{
if (!ph)
return;
ph->deposits.clear();
ph->depositsMap.clear();
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "select timestamp, amount, last_amount, status, last_status, name from character_house_deposits where house_id = %u and instance_id = %u order by timestamp asc limit 255", ph->house_id, ph->instance_id);
if (result && mysql_num_rows(result) > 0) {
while ((row = mysql_fetch_row(result))) {
Deposit d;
d.timestamp = atoul(row[0]);
int64 outVal = strtoull(row[1], NULL, 0);
d.amount = outVal;
outVal = strtoull(row[2], NULL, 0);
d.last_amount = outVal;
d.status = atoul(row[3]);
d.last_status = atoul(row[4]);
d.name = string(row[5]);
ph->deposits.push_back(d);
ph->depositsMap.insert(make_pair(d.name, d));
}
}
}
void WorldDatabase::LoadHistory(PlayerHouse* ph)
{
if (!ph)
return;
ph->history.clear();
Query query;
MYSQL_ROW row;
MYSQL_RES* result = query.RunQuery2(Q_SELECT, "select timestamp, amount, status, reason, name, pos_flag from character_house_history where house_id = %u and instance_id = %u order by timestamp asc limit 255", ph->house_id, ph->instance_id);
if (result && mysql_num_rows(result) > 0) {
while ((row = mysql_fetch_row(result))) {
HouseHistory h;
h.timestamp = atoul(row[0]);
int64 outVal = strtoull(row[1], NULL, 0);
h.amount = outVal;
h.status = atoul(row[2]);
h.reason = string(row[3]);
h.name = string(row[4]);
h.pos_flag = atoul(row[5]);
ph->history.push_back(h);
}
}
}
void WorldDatabase::AddHistory(PlayerHouse* house, char* name, char* reason, int32 timestamp, int64 amount, int32 status, int8 pos_flag)
{
if (!house)
return;
HouseHistory h(Timer::GetUnixTimeStamp(), amount, string(name), string(reason), status, pos_flag);
house->history.push_back(h);
Query query;
string insert = string("INSERT INTO character_house_history (timestamp, house_id, instance_id, name, amount, status, reason, pos_flag) VALUES (%u, %u, %u, '%s', %llu, %u, '%s', %u) ");
query.RunQuery2(Q_INSERT, insert.c_str(), timestamp, house->house_id, house->instance_id, name, amount, status, reason, pos_flag);
}

View File

@ -0,0 +1,454 @@
#include "../ClientPacketFunctions.h"
#include "../World.h"
#include "../client.h"
#include "../WorldDatabase.h"
#include "../Rules/Rules.h"
extern ConfigReader configReader;
extern World world;
extern WorldDatabase database;
extern RuleManager rule_manager;
void ClientPacketFunctions::SendHousePurchase(Client* client, HouseZone* hz, int32 spawnID) {
PacketStruct* packet = configReader.getStruct("WS_PlayerHousePurchase", client->GetVersion());
if (packet) {
int8 disable_alignment_req = rule_manager.GetGlobalRule(R_Player, DisableHouseAlignmentRequirement)->GetInt8();
packet->setDataByName("house_name", hz->name.c_str());
packet->setDataByName("house_id", hz->id);
packet->setDataByName("spawn_id", spawnID);
packet->setDataByName("purchase_coins", hz->cost_coin);
packet->setDataByName("purchase_status", hz->cost_status);
packet->setDataByName("upkeep_coins", hz->upkeep_coin);
packet->setDataByName("upkeep_status", hz->upkeep_status);
packet->setDataByName("vendor_vault_slots", hz->vault_slots);
string req;
if (hz->alignment > 0 && !disable_alignment_req) {
req = "You must be of ";
if (hz->alignment == 1)
req.append("Good");
else
req.append("Evil");
req.append(" alignment");
}
if (hz->guild_level > 0) {
if (req.length() > 0) {
req.append(", and a guild level of ");
char temp[5];
sprintf(temp, "%i", hz->guild_level);
req.append(temp);
//req.append(std::to_string(static_cast<long long>(hz->guild_level)));
}
else {
req.append("Requires a guild of level ");
char temp[5];
sprintf(temp, "%i", hz->guild_level);
req.append(temp);
//req.append(std::to_string(static_cast<long long>(hz->guild_level)))
req.append(" or above");
}
}
if (req.length() > 0) {
req.append(" in order to purchase a home within the ");
req.append(hz->name);
req.append(".");
}
packet->setDataByName("additional_reqs", req.c_str());
bool enable_buy = true;
if (hz->alignment > 0 && client->GetPlayer()->GetAlignment() != hz->alignment && !disable_alignment_req)
enable_buy = false;
if (hz->guild_level > 0 && (!client->GetPlayer()->GetGuild() || (client->GetPlayer()->GetGuild() && client->GetPlayer()->GetGuild()->GetLevel() < hz->guild_level)))
enable_buy = false;
packet->setDataByName("enable_buy", enable_buy ? 1 : 0);
//packet->PrintPacket();
client->QueuePacket(packet->serialize());
}
safe_delete(packet);
}
void ClientPacketFunctions::SendHousingList(Client* client) {
if(client->GetVersion() <= 561) {
return; // not supported
}
std::vector<PlayerHouse*> houses = world.GetAllPlayerHouses(client->GetCharacterID());
// this packet must be sent first otherwise it blocks out the enter house option after paying upkeep
PacketStruct* packet = configReader.getStruct("WS_CharacterHousingList", client->GetVersion());
if(!packet) {
return;
}
packet->setArrayLengthByName("num_houses", houses.size());
for (int i = 0; i < houses.size(); i++)
{
PlayerHouse* ph = (PlayerHouse*)houses[i];
HouseZone* hz = world.GetHouseZone(ph->house_id);
string name;
name = ph->player_name;
name.append("'s ");
name.append(hz->name);
packet->setArrayDataByName("house_id", ph->unique_id, i);
string zone_name = database.GetZoneName(hz->zone_id);
if(zone_name.length() > 0)
packet->setArrayDataByName("zone", zone_name.c_str(), i);
packet->setArrayDataByName("house_city", hz->name.c_str(), i);
packet->setArrayDataByName("house_address", "", i); // need this pulled from live
packet->setArrayDataByName("house_description", name.c_str(), i);
packet->setArrayDataByName("index", i, i); // they send 2, 4, 6, 8 as the index ID's on the client..
// this seems to be some kind of timestamp, if we keep updating then in conjunction with upkeep_due
// in SendBaseHouseWindow/WS_PlayerHouseBaseScreen being a >0 number we can access 'enter house'
int32 upkeep_due = 0;
if (((sint64)ph->upkeep_due - (sint64)Timer::GetUnixTimeStamp()) > 0)
upkeep_due = ph->upkeep_due - Timer::GetUnixTimeStamp();
if ( client->GetVersion() >= 63119 )
packet->setArrayDataByName("unknown2a", 0xFFFFFFFF, i);
else
packet->setArrayDataByName("unknown2", 0xFFFFFFFF, i);
}
client->QueuePacket(packet->serialize());
safe_delete(packet);
}
void ClientPacketFunctions::SendBaseHouseWindow(Client* client, HouseZone* hz, PlayerHouse* ph, int32 spawnID) {
// if we don't send this then the enter house option won't be available if upkeep is paid
if (!hz || !ph)
{
client->SimpleMessage(CHANNEL_COLOR_RED, "HouseZone or PlayerHouse missing and cannot send SendBaseHouseWindow");
return;
}
string name;
name = ph->player_name;
name.append("'s ");
name.append(hz->name);
if (spawnID)
SendHousingList(client);
int32 upkeep_due = 0;
if (((sint64)ph->upkeep_due - (sint64)Timer::GetUnixTimeStamp()) > 0)
upkeep_due = ph->upkeep_due - Timer::GetUnixTimeStamp();
// need this to enable the "enter house" button
PacketStruct* packet = nullptr;
if(client->GetVersion() > 561 && client->GetCurrentZone()->GetInstanceType() != PERSONAL_HOUSE_INSTANCE
&& client->GetCurrentZone()->GetInstanceType() != GUILD_HOUSE_INSTANCE) {
packet = configReader.getStruct("WS_UpdateHouseAccessDataMsg", client->GetVersion());
if(!packet) {
return; // we need this for these clients or enter house will not work properly
}
if (packet) {
packet->setDataByName("house_id", 0xFFFFFFFFFFFFFFFF);
packet->setDataByName("success", (upkeep_due > 0) ? 0xFFFFFFFF : 0);
packet->setDataByName("unknown2", 0xFFFFFFFF);
packet->setDataByName("unknown3", 0xFFFFFFFF);
}
client->QueuePacket(packet->serialize());
}
safe_delete(packet);
packet = configReader.getStruct("WS_PlayerHouseBaseScreen", client->GetVersion());
if (packet) {
packet->setDataByName("house_id", ph->unique_id);
packet->setDataByName("spawn_id", spawnID);
packet->setDataByName("character_id", client->GetPlayer()->GetCharacterID());
packet->setDataByName("house_name", name.c_str());
packet->setDataByName("zone_name", hz->name.c_str());
packet->setDataByName("upkeep_cost_coins", hz->upkeep_coin);
packet->setDataByName("upkeep_cost_status", hz->upkeep_status);
packet->setDataByName("upkeep_due", upkeep_due);
packet->setDataByName("escrow_balance_coins", ph->escrow_coins);
packet->setDataByName("escrow_balance_status", ph->escrow_status);
// temp - set priv level to owner for now
packet->setDataByName("privlage_level", 4);
// temp - set house type to personal house for now
packet->setDataByName("house_type", 0);
if(client->GetCurrentZone()->GetInstanceType() == PERSONAL_HOUSE_INSTANCE
|| client->GetCurrentZone()->GetInstanceType() == GUILD_HOUSE_INSTANCE) {
packet->setDataByName("inside_house", 1);
packet->setDataByName("public_access_level", 1);
}
packet->setDataByName("num_access", 0);
packet->setDataByName("num_history", 0);
// allows deposits/history to be seen -- at this point seems plausible supposed to be 'inside_house'..?
packet->setDataByName("unknown3", (ph->deposits.size() || ph->history.size()) ? 1 : 0);
packet->setArrayLengthByName("num_deposit", ph->deposits.size());
list<Deposit>::iterator itr;
int d = 0;
for (itr = ph->deposits.begin(); itr != ph->deposits.end(); itr++)
{
packet->setArrayDataByName("deposit_name", itr->name.c_str(), d);
packet->setArrayDataByName("deposit_total_coin", itr->amount, d);
packet->setArrayDataByName("deposit_time_stamp", itr->timestamp, d);
packet->setArrayDataByName("deposit_last_coin", itr->last_amount, d);
packet->setArrayDataByName("deposit_total_status", itr->status, d);
packet->setArrayDataByName("deposit_last_status", itr->last_status, d);
d++;
}
packet->setArrayLengthByName("num_history", ph->history.size());
list<HouseHistory>::iterator hitr;
d = 0;
for (hitr = ph->history.begin(); hitr != ph->history.end(); hitr++)
{
packet->setArrayDataByName("history_name", hitr->name.c_str(), d);
packet->setArrayDataByName("history_coins", hitr->amount, d);
packet->setArrayDataByName("history_status", hitr->status, d);
packet->setArrayDataByName("history_time_stamp", hitr->timestamp, d);
packet->setArrayDataByName("history_reason", hitr->reason.c_str(), d);
packet->setArrayDataByName("history_add_flag", hitr->pos_flag, d);
d++;
}
EQ2Packet* pack = packet->serialize();
//DumpPacket(pack);
client->QueuePacket(pack);
}
safe_delete(packet);
}
void ClientPacketFunctions::SendHouseVisitWindow(Client* client, vector<PlayerHouse*> houses) {
PacketStruct* packet = configReader.getStruct("WS_DisplayVisitScreen", client->GetVersion());
if (packet) {
vector<PlayerHouse*>::iterator itr;
packet->setArrayLengthByName("num_houses", houses.size());
int16 i = 0;
for (itr = houses.begin(); itr != houses.end(); itr++) {
PlayerHouse* ph = *itr;
if (ph) {
HouseZone* hz = world.GetHouseZone(ph->house_id);
if (hz) {
packet->setArrayDataByName("house_id", ph->unique_id, i);
packet->setArrayDataByName("house_owner", ph->player_name.c_str(), i);
packet->setArrayDataByName("house_location", hz->name.c_str(), i);
packet->setArrayDataByName("house_zone", client->GetCurrentZone()->GetZoneName(), i);
if ( string(client->GetPlayer()->GetName()).compare(ph->player_name) == 0 )
packet->setArrayDataByName("access_level", 4, i);
else
packet->setArrayDataByName("access_level", 1, i);
packet->setArrayDataByName("visit_flag", 0, i); // 0 = allowed to visit, 1 = owner hasn't paid upkeep
i++;
}
}
}
client->QueuePacket(packet->serialize());
}
safe_delete(packet);
}
/*
<Struct Name="WS_DisplayVisitScreen" ClientVersion="1193" OpcodeName="OP_DisplayInnVisitScreenMsg">
<Data ElementName="num_houses" Type="int16" Size="1" />
<Data ElementName="visithouse_array" Type="Array" ArraySizeVariable="num_houses">
<Data ElementName="house_id" Type="int64" />
<Data ElementName="house_owner" Type="EQ2_16Bit_String" />
<Data ElementName="house_location" Type="EQ2_16Bit_string" />
<Data ElementName="house_zone" Type="EQ2_16Bit_String" />
<Data ElementName="access_level" Type="int8" Size="1" />
<Data ElementName="unknown3" Type="int8" Size="3" />
<Data ElementName="visit_flag" Type="int8" Size="1" />
</Data>
<Data ElementName="unknown4" Type="int32" Size="1" />
<Data ElementName="unknown5" Type="int8" Size="1" />
</Struct>
*/
void ClientPacketFunctions::SendLocalizedTextMessage(Client* client)
{
/***
-- OP_ReloadLocalizedTxtMsg --
5/26/2020 19:08:41
69.174.200.100 -> 192.168.1.1
0000: 01 FF 63 01 62 00 00 00 1C 00 49 72 6F 6E 74 6F ..c.b.....Ironto
0010: 65 73 20 45 61 73 74 20 4C 61 72 67 65 20 49 6E es East Large In
0020: 6E 20 52 6F 6F 6D 07 01 00 00 00 1C 00 49 72 6F n Room.......Iro
0030: 6E 74 6F 65 73 20 45 61 73 74 20 4C 61 72 67 65 ntoes East Large
0040: 20 49 6E 6E 20 52 6F 6F 6D 07 02 00 00 00 1C 00 Inn Room.......
0050: 49 72 6F 6E 74 6F 65 73 20 45 61 73 74 20 4C 61 Irontoes East La
0060: 72 67 65 20 49 6E 6E 20 52 6F 6F 6D 07 03 00 00 rge Inn Room....
0070: 00 1C 00 49 72 6F 6E 74 6F 65 73 20 45 61 73 74 ...Irontoes East
0080: 20 4C 61 72 67 65 20 49 6E 6E 20 52 6F 6F 6D 07 Large Inn Room.
0090: 04 00 00 00 1C 00 49 72 6F 6E 74 6F 65 73 20 45 ......Irontoes E
00A0: 61 73 74 20 4C 61 72 67 65 20 49 6E 6E 20 52 6F ast Large Inn Ro
00B0: 6F 6D 07 05 00 00 00 1C 00 49 72 6F 6E 74 6F 65 om.......Irontoe
00C0: 73 20 45 61 73 74 20 4C 61 72 67 65 20 49 6E 6E s East Large Inn
00D0: 20 52 6F 6F 6D 07 06 00 00 00 1C 00 49 72 6F 6E Room.......Iron
00E0: 74 6F 65 73 20 45 61 73 74 20 4C 61 72 67 65 20 toes East Large
00F0: 49 6E 6E 20 52 6F 6F 6D 07 07 00 00 00 19 00 51 Inn Room.......Q
0100: 65 79 6E 6F 73 20 47 75 69 6C 64 20 48 61 6C 6C eynos Guild Hall
0110: 2C 20 54 69 65 72 20 31 07 08 00 00 00 16 00 4C , Tier 1.......L
0120: 69 6F 6E 27 73 20 4D 61 6E 65 20 53 75 69 74 65 ion's Mane Suite
0130: 20 52 6F 6F 6D 07 09 00 00 00 16 00 4C 69 6F 6E Room.......Lion
0140: 27 73 20 4D 61 6E 65 20 53 75 69 74 65 20 52 6F 's Mane Suite Ro
0150: 6F 6D 07 0A 00 00 00 16 00 4C 69 6F 6E 27 73 20 om.......Lion's
0160: 4D 61 6E 65 20 53 75 69 74 65 20 52 6F 6F 6D 07 Mane Suite Room.
0170: 0B 00 00 00 16 00 4C 69 6F 6E 27 73 20 4D 61 6E ......Lion's Man
0180: 65 20 53 75 69 74 65 20 52 6F 6F 6D 07 0C 00 00 e Suite Room....
0190: 00 0E 00 32 20 4C 75 63 69 65 20 53 74 72 65 65 ...2 Lucie Stree
01A0: 74 07 0D 00 00 00 0F 00 31 37 20 54 72 61 6E 71 t.......17 Tranq
01B0: 75 69 6C 20 57 61 79 07 0E 00 00 00 0E 00 38 20 uil Way.......8
01C0: 4C 75 63 69 65 20 53 74 72 65 65 74 07 0F 00 00 Lucie Street....
01D0: 00 0F 00 31 32 20 4C 75 63 69 65 20 53 74 72 65 ...12 Lucie Stre
01E0: 65 74 07 10 00 00 00 0F 00 31 38 20 4C 75 63 69 et.......18 Luci
01F0: 65 20 53 74 72 65 65 74 07 11 00 00 00 0F 00 32 e Street.......2
0200: 30 20 4C 75 63 69 65 20 53 74 72 65 65 74 07 12 0 Lucie Street..
0210: 00 00 00 0E 00 33 20 54 72 61 6E 71 75 69 6C 20 .....3 Tranquil
0220: 57 61 79 07 13 00 00 00 0E 00 37 20 54 72 61 6E Way.......7 Tran
0230: 71 75 69 6C 20 57 61 79 07 14 00 00 00 0F 00 31 quil Way.......1
0240: 33 20 54 72 61 6E 71 75 69 6C 20 57 61 79 07 15 3 Tranquil Way..
0250: 00 00 00 0F 00 31 35 20 54 72 61 6E 71 75 69 6C .....15 Tranquil
0260: 20 57 61 79 07 16 00 00 00 19 00 51 65 79 6E 6F Way.......Qeyno
0270: 73 20 47 75 69 6C 64 20 48 61 6C 6C 2C 20 54 69 s Guild Hall, Ti
0280: 65 72 20 32 07 17 00 00 00 0F 00 38 20 45 72 6F er 2.......8 Ero
0290: 6C 6C 69 73 69 20 4C 61 6E 65 07 18 00 00 00 0F llisi Lane......
02A0: 00 35 20 45 72 6F 6C 6C 69 73 69 20 4C 61 6E 65 .5 Erollisi Lane
02B0: 07 19 00 00 00 0E 00 35 20 4B 61 72 61 6E 61 20 .......5 Karana
02C0: 43 6F 75 72 74 07 1A 00 00 00 0D 00 32 20 42 61 Court.......2 Ba
02D0: 79 6C 65 20 43 6F 75 72 74 07 1B 00 00 00 0D 00 yle Court.......
02E0: 34 20 42 61 79 6C 65 20 43 6F 75 72 74 07 1C 00 4 Bayle Court...
02F0: 00 00 16 00 4C 69 6F 6E 27 73 20 4D 61 6E 65 20 ....Lion's Mane
0300: 53 75 69 74 65 20 52 6F 6F 6D 07 1D 00 00 00 16 Suite Room......
0310: 00 4C 69 6F 6E 27 73 20 4D 61 6E 65 20 53 75 69 .Lion's Mane Sui
0320: 74 65 20 52 6F 6F 6D 07 1E 00 00 00 16 00 4C 69 te Room.......Li
0330: 6F 6E 27 73 20 4D 61 6E 65 20 53 75 69 74 65 20 on's Mane Suite
0340: 52 6F 6F 6D 07 1F 00 00 00 16 00 4C 69 6F 6E 27 Room.......Lion'
0350: 73 20 4D 61 6E 65 20 53 75 69 74 65 20 52 6F 6F s Mane Suite Roo
0360: 6D 07 20 00 00 00 0E 00 35 20 4C 75 63 69 65 20 m. .....5 Lucie
0370: 53 74 72 65 65 74 07 21 00 00 00 0F 00 32 30 20 Street.!.....20
0380: 4B 61 72 61 6E 61 20 43 6F 75 72 74 07 22 00 00 Karana Court."..
0390: 00 0E 00 39 20 4C 75 63 69 65 20 53 74 72 65 65 ...9 Lucie Stree
03A0: 74 07 23 00 00 00 0F 00 31 35 20 4C 75 63 69 65 t.#.....15 Lucie
03B0: 20 53 74 72 65 65 74 07 24 00 00 00 0F 00 31 37 Street.$.....17
03C0: 20 4C 75 63 69 65 20 53 74 72 65 65 74 07 25 00 Lucie Street.%.
03D0: 00 00 0F 00 32 31 20 4C 75 63 69 65 20 53 74 72 ....21 Lucie Str
03E0: 65 65 74 07 26 00 00 00 0E 00 36 20 4B 61 72 61 eet.&.....6 Kara
03F0: 6E 61 20 43 6F 75 72 74 07 27 00 00 00 0F 00 31 na Court.'.....1
0400: 32 20 4B 61 72 61 6E 61 20 43 6F 75 72 74 07 28 2 Karana Court.(
0410: 00 00 00 0F 00 31 34 20 4B 61 72 61 6E 61 20 43 .....14 Karana C
0420: 6F 75 72 74 07 29 00 00 00 0F 00 31 38 20 4B 61 ourt.).....18 Ka
0430: 72 61 6E 61 20 43 6F 75 72 74 07 2A 00 00 00 1E rana Court.*....
0440: 00 43 6F 6E 63 6F 72 64 69 75 6D 20 54 6F 77 65 .Concordium Towe
0450: 72 20 4D 61 67 69 63 61 6C 20 4D 61 6E 6F 72 07 r Magical Manor.
0460: 2B 00 00 00 15 00 41 72 63 61 6E 65 20 41 63 61 +.....Arcane Aca
0470: 64 65 6D 79 20 50 6F 72 74 61 6C 07 2C 00 00 00 demy Portal.,...
0480: 13 00 43 6F 75 72 74 20 6F 66 20 74 68 65 20 4D ..Court of the M
0490: 61 73 74 65 72 07 2D 00 00 00 13 00 43 69 74 79 aster.-.....City
04A0: 20 6F 66 20 4D 69 73 74 20 45 73 74 61 74 65 07 of Mist Estate.
04B0: 2E 00 00 00 10 00 44 61 72 6B 6C 69 67 68 74 20 ......Darklight
04C0: 50 61 6C 61 63 65 07 2F 00 00 00 11 00 44 65 65 Palace./.....Dee
04D0: 70 77 61 74 65 72 20 52 65 74 72 65 61 74 07 30 pwater Retreat.0
04E0: 00 00 00 24 00 44 68 61 6C 67 61 72 20 50 72 65 ...$.Dhalgar Pre
04F0: 63 69 70 69 63 65 20 6F 66 20 74 68 65 20 44 65 cipice of the De
0500: 65 70 20 50 6F 72 74 61 6C 07 31 00 00 00 12 00 ep Portal.1.....
0510: 44 69 6D 65 6E 73 69 6F 6E 61 6C 20 50 6F 63 6B Dimensional Pock
0520: 65 74 07 32 00 00 00 0B 00 44 6F 6A 6F 20 50 6F et.2.....Dojo Po
0530: 72 74 61 6C 07 33 00 00 00 21 00 45 6C 61 62 6F rtal.3...!.Elabo
0540: 72 61 74 65 20 45 73 74 61 74 65 20 6F 66 20 55 rate Estate of U
0550: 6E 72 65 73 74 20 50 6F 72 74 61 6C 07 34 00 00 nrest Portal.4..
0560: 00 11 00 45 74 68 65 72 6E 65 72 65 20 45 6E 63 ...Ethernere Enc
0570: 6C 61 76 65 07 35 00 00 00 10 00 45 76 65 72 66 lave.5.....Everf
0580: 72 6F 73 74 20 50 6F 72 74 61 6C 07 36 00 00 00 rost Portal.6...
0590: 16 00 46 65 61 72 66 75 6C 20 52 65 74 72 65 61 ..Fearful Retrea
05A0: 74 20 50 6F 72 74 61 6C 07 37 00 00 00 0F 00 46 t Portal.7.....F
05B0: 65 6C 77 69 74 68 65 20 50 6F 72 74 61 6C 07 38 elwithe Portal.8
05C0: 00 00 00 10 00 46 72 65 65 62 6C 6F 6F 64 20 50 .....Freeblood P
05D0: 6F 72 74 61 6C 07 39 00 00 00 0C 00 46 72 69 67 ortal.9.....Frig
05E0: 68 74 20 4D 61 6E 6F 72 07 3A 00 00 00 11 00 47 ht Manor.:.....G
05F0: 61 6C 6C 65 6F 6E 20 6F 66 20 44 72 65 61 6D 73 alleon of Dreams
0600: 07 3B 00 00 00 14 00 48 61 6C 6C 20 6F 66 20 74 .;.....Hall of t
0610: 68 65 20 43 68 61 6D 70 69 6F 6E 07 3C 00 00 00 he Champion.<...
0620: 10 00 48 75 61 20 4D 65 69 6E 20 52 65 74 72 65 ..Hua Mein Retre
0630: 61 74 07 3D 00 00 00 1C 00 49 73 6C 65 20 6F 66 at.=.....Isle of
0640: 20 52 65 66 75 67 65 20 50 72 65 73 74 69 67 65 Refuge Prestige
0650: 20 48 6F 6D 65 07 3E 00 00 00 0F 00 4B 65 72 61 Home.>.....Kera
0660: 66 79 72 6D 27 73 20 4C 61 69 72 07 3F 00 00 00 fyrm's Lair.?...
0670: 0E 00 4B 72 6F 6D 7A 65 6B 20 50 6F 72 74 61 6C ..Kromzek Portal
0680: 07 40 00 00 00 10 00 4C 61 76 61 73 74 6F 72 6D .@.....Lavastorm
0690: 20 50 6F 72 74 61 6C 07 41 00 00 00 0E 00 4C 69 Portal.A.....Li
06A0: 62 72 61 72 79 20 50 6F 72 74 61 6C 07 42 00 00 brary Portal.B..
06B0: 00 0B 00 4D 61 72 61 20 45 73 74 61 74 65 07 43 ...Mara Estate.C
06C0: 00 00 00 21 00 4D 61 6A 27 44 75 6C 20 41 73 74 ...!.Maj'Dul Ast
06D0: 72 6F 6E 6F 6D 65 72 27 73 20 54 6F 77 65 72 20 ronomer's Tower
06E0: 50 6F 72 74 61 6C 07 44 00 00 00 14 00 4D 61 6A Portal.D.....Maj
06F0: 27 44 75 6C 20 53 75 69 74 65 20 50 6F 72 74 61 'Dul Suite Porta
0700: 6C 07 45 00 00 00 17 00 4D 69 73 74 6D 6F 6F 72 l.E.....Mistmoor
0710: 65 20 43 72 61 67 73 20 45 73 74 61 74 65 73 07 e Crags Estates.
0720: 46 00 00 00 0D 00 4F 61 6B 6D 79 73 74 20 47 6C F.....Oakmyst Gl
0730: 61 64 65 07 47 00 00 00 12 00 4F 70 65 72 61 20 ade.G.....Opera
0740: 48 6F 75 73 65 20 50 6F 72 74 61 6C 07 48 00 00 House Portal.H..
0750: 00 16 00 50 65 72 73 6F 6E 61 6C 20 47 72 6F 74 ...Personal Grot
0760: 74 6F 20 50 6F 72 74 61 6C 07 49 00 00 00 17 00 to Portal.I.....
0770: 52 75 6D 20 52 75 6E 6E 65 72 73 20 43 6F 76 65 Rum Runners Cove
0780: 20 50 6F 72 74 61 6C 07 4A 00 00 00 12 00 50 6C Portal.J.....Pl
0790: 61 6E 65 74 61 72 69 75 6D 20 50 6F 72 74 61 6C anetarium Portal
07A0: 07 4B 00 00 00 14 00 52 65 73 65 61 72 63 68 65 .K.....Researche
07B0: 72 27 73 20 53 61 6E 63 74 75 6D 07 4C 00 00 00 r's Sanctum.L...
07C0: 1E 00 52 65 73 69 64 65 6E 63 65 20 6F 66 20 74 ..Residence of t
07D0: 68 65 20 42 6C 61 64 65 73 20 50 6F 72 74 61 6C he Blades Portal
07E0: 07 4D 00 00 00 16 00 53 61 6E 63 74 75 73 20 53 .M.....Sanctus S
07F0: 65 72 75 20 50 72 6F 6D 65 6E 61 64 65 07 4E 00 eru Promenade.N.
0800: 00 00 22 00 53 61 6E 74 61 20 47 6C 75 67 27 73 ..".Santa Glug's
0810: 20 43 68 65 65 72 66 75 6C 20 48 6F 6C 69 64 61 Cheerful Holida
0820: 79 20 48 6F 6D 65 07 4F 00 00 00 17 00 53 65 63 y Home.O.....Sec
0830: 6C 75 64 65 64 20 53 61 6E 63 74 75 6D 20 50 6F luded Sanctum Po
0840: 72 74 61 6C 07 50 00 00 00 18 00 53 6B 79 62 6C rtal.P.....Skybl
0850: 61 64 65 20 53 6B 69 66 66 20 4C 61 75 6E 63 68 ade Skiff Launch
0860: 70 61 64 07 51 00 00 00 0E 00 53 6E 6F 77 79 20 pad.Q.....Snowy
0870: 44 77 65 6C 6C 69 6E 67 07 52 00 00 00 1D 00 53 Dwelling.R.....S
0880: 70 72 6F 63 6B 65 74 27 73 20 49 6E 74 65 72 6C procket's Interl
0890: 6F 63 6B 69 6E 67 20 50 6C 61 6E 65 07 53 00 00 ocking Plane.S..
08A0: 00 17 00 53 74 6F 72 6D 20 54 6F 77 65 72 20 49 ...Storm Tower I
08B0: 73 6C 65 20 50 6F 72 74 61 6C 07 54 00 00 00 21 sle Portal.T...!
08C0: 00 52 65 6C 69 63 20 54 69 6E 6B 65 72 20 50 72 .Relic Tinker Pr
08D0: 65 73 74 69 67 65 20 48 6F 6D 65 20 50 6F 72 74 estige Home Port
08E0: 61 6C 07 55 00 00 00 10 00 54 65 6E 65 62 72 6F al.U.....Tenebro
08F0: 75 73 20 50 6F 72 74 61 6C 07 56 00 00 00 10 00 us Portal.V.....
0900: 54 68 65 20 42 61 75 62 62 6C 65 73 68 69 72 65 The Baubbleshire
0910: 07 57 00 00 00 0F 00 54 69 6E 6B 65 72 65 72 27 .W.....Tinkerer'
0920: 73 20 49 73 6C 65 07 58 00 00 00 12 00 54 6F 77 s Isle.X.....Tow
0930: 65 72 20 6F 66 20 4B 6E 6F 77 6C 65 64 67 65 07 er of Knowledge.
0940: 59 00 00 00 15 00 55 6E 63 61 6E 6E 79 20 45 73 Y.....Uncanny Es
0950: 74 61 74 65 20 50 6F 72 74 61 6C 07 5A 00 00 00 tate Portal.Z...
0960: 1E 00 56 61 63 61 6E 74 20 45 73 74 61 74 65 20 ..Vacant Estate
0970: 6F 66 20 55 6E 72 65 73 74 20 50 6F 72 74 61 6C of Unrest Portal
0980: 07 5B 00 00 00 18 00 56 61 6C 65 20 6F 66 20 48 .[.....Vale of H
0990: 61 6C 66 70 69 6E 74 20 44 65 6C 69 67 68 74 07 alfpint Delight.
09A0: 5C 00 00 00 26 00 4C 69 6F 6E 27 73 20 4D 61 6E \...&.Lion's Man
09B0: 65 20 56 65 73 74 69 67 65 20 52 6F 6F 6D 20 2D e Vestige Room -
09C0: 20 4E 65 74 74 6C 65 76 69 6C 6C 65 07 5D 00 00 Nettleville.]..
09D0: 00 2C 00 4C 69 6F 6E 27 73 20 4D 61 6E 65 20 56 .,.Lion's Mane V
09E0: 65 73 74 69 67 65 20 52 6F 6F 6D 20 2D 20 53 74 estige Room - St
09F0: 61 72 63 72 65 73 74 20 43 6F 6D 6D 75 6E 65 07 arcrest Commune.
0A00: 5E 00 00 00 29 00 4C 69 6F 6E 27 73 20 4D 61 6E ^...).Lion's Man
0A10: 65 20 56 65 73 74 69 67 65 20 52 6F 6F 6D 20 2D e Vestige Room -
0A20: 20 47 72 61 79 73 74 6F 6E 65 20 59 61 72 64 07 Graystone Yard.
0A30: 5F 00 00 00 2C 00 4C 69 6F 6E 27 73 20 4D 61 6E _...,.Lion's Man
0A40: 65 20 56 65 73 74 69 67 65 20 52 6F 6F 6D 20 2D e Vestige Room -
0A50: 20 43 61 73 74 6C 65 76 69 65 77 20 48 61 6D 6C Castleview Haml
0A60: 65 74 07 60 00 00 00 2A 00 4C 69 6F 6E 27 73 20 et.`...*.Lion's
0A70: 4D 61 6E 65 20 56 65 73 74 69 67 65 20 52 6F 6F Mane Vestige Roo
0A80: 6D 20 2D 20 54 68 65 20 57 69 6C 6C 6F 77 20 57 m - The Willow W
0A90: 6F 6F 64 07 61 00 00 00 2B 00 4C 69 6F 6E 27 73 ood.a...+.Lion's
0AA0: 20 4D 61 6E 65 20 56 65 73 74 69 67 65 20 52 6F Mane Vestige Ro
0AB0: 6F 6D 20 2D 20 54 68 65 20 42 61 75 62 62 6C 65 om - The Baubble
0AC0: 73 68 69 72 65 07 62 00 00 00 FF FF FF FF shire.b.......
*/
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,817 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __EQ2_ITEMS__
#define __EQ2_ITEMS__
#include <map>
#include <vector>
#include "../../common/types.h"
#include "../../common/DataBuffer.h"
#include "../../common/MiscFunctions.h"
#include "../Commands/Commands.h"
#include "../../common/ConfigReader.h"
using namespace std;
class MasterItemList;
class Player;
extern MasterItemList master_item_list;
#define EQ2_PRIMARY_SLOT 0
#define EQ2_SECONDARY_SLOT 1
#define EQ2_HEAD_SLOT 2
#define EQ2_CHEST_SLOT 3
#define EQ2_SHOULDERS_SLOT 4
#define EQ2_FOREARMS_SLOT 5
#define EQ2_HANDS_SLOT 6
#define EQ2_LEGS_SLOT 7
#define EQ2_FEET_SLOT 8
#define EQ2_LRING_SLOT 9
#define EQ2_RRING_SLOT 10
#define EQ2_EARS_SLOT_1 11
#define EQ2_EARS_SLOT_2 12
#define EQ2_NECK_SLOT 13
#define EQ2_LWRIST_SLOT 14
#define EQ2_RWRIST_SLOT 15
#define EQ2_RANGE_SLOT 16
#define EQ2_AMMO_SLOT 17
#define EQ2_WAIST_SLOT 18
#define EQ2_CLOAK_SLOT 19
#define EQ2_CHARM_SLOT_1 20
#define EQ2_CHARM_SLOT_2 21
#define EQ2_FOOD_SLOT 22
#define EQ2_DRINK_SLOT 23
#define EQ2_TEXTURES_SLOT 24
#define EQ2_UNKNOWN_SLOT 25
#define PRIMARY_SLOT 1
#define SECONDARY_SLOT 2
#define HEAD_SLOT 4
#define CHEST_SLOT 8
#define SHOULDERS_SLOT 16
#define FOREARMS_SLOT 32
#define HANDS_SLOT 64
#define LEGS_SLOT 128
#define FEET_SLOT 256
#define LRING_SLOT 512
#define RRING_SLOT 1024
#define EARS_SLOT_1 2048
#define EARS_SLOT_2 4096
#define NECK_SLOT 8192
#define LWRIST_SLOT 16384
#define RWRIST_SLOT 32768
#define RANGE_SLOT 65536
#define AMMO_SLOT 131072
#define WAIST_SLOT 262144
#define CLOAK_SLOT 524288
#define CHARM_SLOT_1 1048576
#define CHARM_SLOT_2 2097152
#define FOOD_SLOT 4194304
#define DRINK_SLOT 8388608
#define TEXTURES_SLOT 16777216
#define NUM_BANK_SLOTS 12
#define NUM_SHARED_BANK_SLOTS 8
#define NUM_SLOTS 25
#define NUM_INV_SLOTS 6
#define INV_SLOT1 0
#define INV_SLOT2 50
#define INV_SLOT3 100
#define INV_SLOT4 150
#define INV_SLOT5 200
#define INV_SLOT6 250
#define BANK_SLOT1 1000
#define BANK_SLOT2 1100
#define BANK_SLOT3 1200
#define BANK_SLOT4 1300
#define BANK_SLOT5 1400
#define BANK_SLOT6 1500
#define BANK_SLOT7 1600
#define BANK_SLOT8 1700
#define ATTUNED 1
#define ATTUNEABLE 2
#define ARTIFACT 4
#define LORE 8
#define TEMPORARY 16
#define NO_TRADE 32
#define NO_VALUE 64
#define NO_ZONE 128
#define NO_DESTROY 256
#define CRAFTED 512
#define GOOD_ONLY 1024
#define EVIL_ONLY 2048
#define ITEM_WIELD_TYPE_DUAL 1
#define ITEM_WIELD_TYPE_SINGLE 2
#define ITEM_WIELD_TYPE_TWO_HAND 4
#define ITEM_TYPE_NORMAL 0
#define ITEM_TYPE_WEAPON 1
#define ITEM_TYPE_RANGED 2
#define ITEM_TYPE_ARMOR 3
#define ITEM_TYPE_SHIELD 4
#define ITEM_TYPE_BAG 5
#define ITEM_TYPE_SKILL 6
#define ITEM_TYPE_RECIPE 7
#define ITEM_TYPE_FOOD 8
#define ITEM_TYPE_BAUBLE 9
#define ITEM_TYPE_HOUSE 10
#define ITEM_TYPE_THROWN 11
#define ITEM_TYPE_HOUSE_CONTAINER 12
#define ITEM_TYPE_BOOK 13
#define ITEM_TYPE_ADORNMENT 14
#define ITEM_TYPE_PATTERN 15
#define ITEM_TYPE_ARMORSET 16
#define ITEM_MENU_TYPE_GENERIC 1
#define ITEM_MENU_TYPE_EQUIP 2
#define ITEM_MENU_TYPE_BAG 4
#define ITEM_MENU_TYPE_HOUSE 8
#define ITEM_MENU_TYPE_SCRIBE 32
#define ITEM_MENU_TYPE_INVALID 128
#define ITEM_MENU_TYPE_BROKEN 512
#define ITEM_MENU_TYPE_ATTUNED 2048
#define ITEM_MENU_TYPE_ATTUNEABLE 4096
#define ITEM_MENU_TYPE_BOOK 8192
#define ITEM_MENU_TYPE_DISPLAY_CHARGES 16384
#define ITEM_MENU_TYPE_NAMEPET 65536
#define ITEM_MENU_TYPE_USE 524288
#define ITEM_MENU_TYPE_DRINK 8388608
#define ITEM_MENU_TYPE_REDEEM 536870912
#define ITEM_TAG_UNCOMMON 3 //tier tags
#define ITEM_TAG_TREASURED 4
#define ITEM_TAG_LEGENDARY 7
#define ITEM_TAG_FABLED 9
#define ITEM_TAG_MYTHICAL 12
#define ITEM_BROKER_TYPE_ANY 0xFFFFFFFF
#define ITEM_BROKER_TYPE_ADORNMENT 134217728
#define ITEM_BROKER_TYPE_AMMO 1024
#define ITEM_BROKER_TYPE_ATTUNEABLE 16384
#define ITEM_BROKER_TYPE_BAG 2048
#define ITEM_BROKER_TYPE_BAUBLE 16777216
#define ITEM_BROKER_TYPE_BOOK 128
#define ITEM_BROKER_TYPE_CHAINARMOR 2097152
#define ITEM_BROKER_TYPE_CLOAK 1073741824
#define ITEM_BROKER_TYPE_CLOTHARMOR 524288
#define ITEM_BROKER_TYPE_COLLECTABLE 67108864
#define ITEM_BROKER_TYPE_CRUSHWEAPON 4
#define ITEM_BROKER_TYPE_DRINK 131072
#define ITEM_BROKER_TYPE_FOOD 4096
#define ITEM_BROKER_TYPE_HOUSEITEM 512
#define ITEM_BROKER_TYPE_JEWELRY 262144
#define ITEM_BROKER_TYPE_LEATHERARMOR 1048576
#define ITEM_BROKER_TYPE_LORE 8192
#define ITEM_BROKER_TYPE_MISC 1
#define ITEM_BROKER_TYPE_PIERCEWEAPON 8
#define ITEM_BROKER_TYPE_PLATEARMOR 4194304
#define ITEM_BROKER_TYPE_POISON 65536
#define ITEM_BROKER_TYPE_POTION 32768
#define ITEM_BROKER_TYPE_RECIPEBOOK 8388608
#define ITEM_BROKER_TYPE_SALESDISPLAY 33554432
#define ITEM_BROKER_TYPE_SHIELD 32
#define ITEM_BROKER_TYPE_SLASHWEAPON 2
#define ITEM_BROKER_TYPE_SPELLSCROLL 64
#define ITEM_BROKER_TYPE_TINKERED 268435456
#define ITEM_BROKER_TYPE_TRADESKILL 256
#define ITEM_BROKER_SLOT_ANY 0xFFFFFFFF
#define ITEM_BROKER_SLOT_AMMO 65536
#define ITEM_BROKER_SLOT_CHARM 524288
#define ITEM_BROKER_SLOT_CHEST 32
#define ITEM_BROKER_SLOT_CLOAK 262144
#define ITEM_BROKER_SLOT_DRINK 2097152
#define ITEM_BROKER_SLOT_EARS 4096
#define ITEM_BROKER_SLOT_FEET 1024
#define ITEM_BROKER_SLOT_FOOD 1048576
#define ITEM_BROKER_SLOT_FOREARMS 128
#define ITEM_BROKER_SLOT_HANDS 256
#define ITEM_BROKER_SLOT_HEAD 16
#define ITEM_BROKER_SLOT_LEGS 512
#define ITEM_BROKER_SLOT_NECK 8192
#define ITEM_BROKER_SLOT_PRIMARY 1
#define ITEM_BROKER_SLOT_PRIMARY_2H 2
#define ITEM_BROKER_SLOT_RANGE_WEAPON 32768
#define ITEM_BROKER_SLOT_RING 2048
#define ITEM_BROKER_SLOT_SECONDARY 8
#define ITEM_BROKER_SLOT_SHOULDERS 64
#define ITEM_BROKER_SLOT_WAIST 131072
#define ITEM_BROKER_SLOT_WRIST 16384
#define ITEM_BROKER_STAT_TYPE_NONE 0
#define ITEM_BROKER_STAT_TYPE_DEF 2
#define ITEM_BROKER_STAT_TYPE_STR 4
#define ITEM_BROKER_STAT_TYPE_STA 8
#define ITEM_BROKER_STAT_TYPE_AGI 16
#define ITEM_BROKER_STAT_TYPE_WIS 32
#define ITEM_BROKER_STAT_TYPE_INT 64
#define ITEM_BROKER_STAT_TYPE_HEALTH 128
#define ITEM_BROKER_STAT_TYPE_POWER 256
#define ITEM_BROKER_STAT_TYPE_HEAT 512
#define ITEM_BROKER_STAT_TYPE_COLD 1024
#define ITEM_BROKER_STAT_TYPE_MAGIC 2048
#define ITEM_BROKER_STAT_TYPE_MENTAL 4096
#define ITEM_BROKER_STAT_TYPE_DIVINE 8192
#define ITEM_BROKER_STAT_TYPE_POISON 16384
#define ITEM_BROKER_STAT_TYPE_DISEASE 32768
#define ITEM_BROKER_STAT_TYPE_CRUSH 65536
#define ITEM_BROKER_STAT_TYPE_SLASH 131072
#define ITEM_BROKER_STAT_TYPE_PIERCE 262144
#define ITEM_BROKER_STAT_TYPE_CRITICAL 524288
#define ITEM_BROKER_STAT_TYPE_DBL_ATTACK 1048576
#define ITEM_BROKER_STAT_TYPE_ABILITY_MOD 2097152
#define ITEM_BROKER_STAT_TYPE_POTENCY 4194304
#define OVERFLOW_SLOT 0xFFFFFFFE
#define SLOT_INVALID 0xFFFF
#define ITEM_STAT_STR 0
#define ITEM_STAT_STA 1
#define ITEM_STAT_AGI 2
#define ITEM_STAT_WIS 3
#define ITEM_STAT_INT 4
#define ITEM_STAT_ADORNING 100
#define ITEM_STAT_AGGRESSION 101
#define ITEM_STAT_ARTIFICING 102
#define ITEM_STAT_ARTISTRY 103
#define ITEM_STAT_CHEMISTRY 104
#define ITEM_STAT_CRUSHING 105
#define ITEM_STAT_DEFENSE 106
#define ITEM_STAT_DEFLECTION 107
#define ITEM_STAT_DISRUPTION 108
#define ITEM_STAT_FISHING 109
#define ITEM_STAT_FLETCHING 110
#define ITEM_STAT_FOCUS 111
#define ITEM_STAT_FORESTING 112
#define ITEM_STAT_GATHERING 113
#define ITEM_STAT_METAL_SHAPING 114
#define ITEM_STAT_METALWORKING 115
#define ITEM_STAT_MINING 116
#define ITEM_STAT_MINISTRATION 117
#define ITEM_STAT_ORDINATION 118
#define ITEM_STAT_PARRY 119
#define ITEM_STAT_PIERCING 120
#define ITEM_STAT_RANGED 121
#define ITEM_STAT_SAFE_FALL 122
#define ITEM_STAT_SCRIBING 123
#define ITEM_STAT_SCULPTING 124
#define ITEM_STAT_SLASHING 125
#define ITEM_STAT_SUBJUGATION 126
#define ITEM_STAT_SWIMMING 127
#define ITEM_STAT_TAILORING 128
#define ITEM_STAT_TINKERING 129
#define ITEM_STAT_TRANSMUTING 130
#define ITEM_STAT_TRAPPING 131
#define ITEM_STAT_WEAPON_SKILLS 132
#define ITEM_STAT_VS_PHYSICAL 200
#define ITEM_STAT_VS_ELEMENTAL 201
#define ITEM_STAT_VS_NOXIOUS 202
#define ITEM_STAT_VS_ARCANE 203
//#define ITEM_STAT_VS_SLASH 200
//#define ITEM_STAT_VS_CRUSH 201
//#define ITEM_STAT_VS_PIERCE 202
//#define ITEM_STAT_VS_HEAT 203
//#define ITEM_STAT_VS_COLD 204
//#define ITEM_STAT_VS_MAGIC 205
//#define ITEM_STAT_VS_MENTAL 206
//#define ITEM_STAT_VS_DIVINE 207
//#define ITEM_STAT_VS_DISEASE 208
//#define ITEM_STAT_VS_POISON 209
//#define ITEM_STAT_VS_DROWNING 210
//#define ITEM_STAT_VS_FALLING 211
//#define ITEM_STAT_VS_PAIN 212
//#define ITEM_STAT_VS_MELEE 213
#define ITEM_STAT_DMG_SLASH 300
#define ITEM_STAT_DMG_CRUSH 301
#define ITEM_STAT_DMG_PIERCE 302
#define ITEM_STAT_DMG_HEAT 303
#define ITEM_STAT_DMG_COLD 304
#define ITEM_STAT_DMG_MAGIC 305
#define ITEM_STAT_DMG_MENTAL 306
#define ITEM_STAT_DMG_DIVINE 307
#define ITEM_STAT_DMG_DISEASE 308
#define ITEM_STAT_DMG_POISON 309
#define ITEM_STAT_DMG_DROWNING 310
#define ITEM_STAT_DMG_FALLING 311
#define ITEM_STAT_DMG_PAIN 312
#define ITEM_STAT_DMG_MELEE 313
#define ITEM_STAT_HEALTH 500
#define ITEM_STAT_POWER 501
#define ITEM_STAT_CONCENTRATION 502
#define ITEM_STAT_SAVAGERY 503
#define ITEM_STAT_HPREGEN 600
#define ITEM_STAT_MANAREGEN 601
#define ITEM_STAT_HPREGENPPT 602
#define ITEM_STAT_MPREGENPPT 603
#define ITEM_STAT_COMBATHPREGENPPT 604
#define ITEM_STAT_COMBATMPREGENPPT 605
#define ITEM_STAT_MAXHP 606
#define ITEM_STAT_MAXHPPERC 607
#define ITEM_STAT_MAXHPPERCFINAL 608
#define ITEM_STAT_SPEED 609
#define ITEM_STAT_SLOW 610
#define ITEM_STAT_MOUNTSPEED 611
#define ITEM_STAT_MOUNTAIRSPEED 612
#define ITEM_STAT_LEAPSPEED 613
#define ITEM_STAT_LEAPTIME 614
#define ITEM_STAT_GLIDEEFFICIENCY 615
#define ITEM_STAT_OFFENSIVESPEED 616
#define ITEM_STAT_ATTACKSPEED 617
#define ITEM_STAT_SPELLWEAPONATTACKSPEED 618
#define ITEM_STAT_MAXMANA 619
#define ITEM_STAT_MAXMANAPERC 620
#define ITEM_STAT_MAXATTPERC 621
#define ITEM_STAT_BLURVISION 622
#define ITEM_STAT_MAGICLEVELIMMUNITY 623
#define ITEM_STAT_HATEGAINMOD 624
#define ITEM_STAT_COMBATEXPMOD 625
#define ITEM_STAT_TRADESKILLEXPMOD 626
#define ITEM_STAT_ACHIEVEMENTEXPMOD 627
#define ITEM_STAT_SIZEMOD 628
#define ITEM_STAT_DPS 629
#define ITEM_STAT_SPELLWEAPONDPS 630
#define ITEM_STAT_STEALTH 631
#define ITEM_STAT_INVIS 632
#define ITEM_STAT_SEESTEALTH 633
#define ITEM_STAT_SEEINVIS 634
#define ITEM_STAT_EFFECTIVELEVELMOD 635
#define ITEM_STAT_RIPOSTECHANCE 636
#define ITEM_STAT_PARRYCHANCE 637
#define ITEM_STAT_DODGECHANCE 638
#define ITEM_STAT_AEAUTOATTACKCHANCE 639
#define ITEM_STAT_SPELLWEAPONAEAUTOATTACKCHANCE 640
#define ITEM_STAT_DOUBLEATTACKCHANCE 641
#define ITEM_STAT_PVPDOUBLEATTACKCHANCE 642
#define ITEM_STAT_SPELLWEAPONAEAUTOATTACKCHANCE 643
#define ITEM_STAT_PVPSPELLWEAPONDOUBLEATTACKCHANCE 644
#define ITEM_STAT_SPELLDOUBLEATTACKCHANCE 645
#define ITEM_STAT_PVPSPELLDOUBLEATTACKCHANCE 646
#define ITEM_STAT_FLURRY 647
#define ITEM_STAT_SPELLWEAPONFLURRY 648
#define ITEM_STAT_MELEEDAMAGEMULTIPLIER 649
#define ITEM_STAT_EXTRAHARVESTCHANCE 650
#define ITEM_STAT_EXTRASHIELDBLOCKCHANCE 651
#define ITEM_STAT_ITEMHPREGENPPT 652
#define ITEM_STAT_ITEMPPREGENPPT 653
#define ITEM_STAT_MELEECRITCHANCE 654
#define ITEM_STAT_CRITAVOIDANCE 655
#define ITEM_STAT_BENEFICIALCRITCHANCE 656
#define ITEM_STAT_CRITBONUS 657
#define ITEM_STAT_PVPCRITBONUS 658
#define ITEM_STAT_BASEMODIFIER 659
#define ITEM_STAT_PVPBASEMODIFIER 660
#define ITEM_STAT_UNCONSCIOUSHPMOD 661
#define ITEM_STAT_SPELLTIMEREUSEPCT 662
#define ITEM_STAT_SPELLTIMERECOVERYPCT 663
#define ITEM_STAT_SPELLTIMECASTPCT 664
#define ITEM_STAT_SPELLTIMEREUSESPELLONLY 665
#define ITEM_STAT_MELEEWEAPONRANGE 666
#define ITEM_STAT_RANGEDWEAPONRANGE 667
#define ITEM_STAT_FALLINGDAMAGEREDUCTION 668
#define ITEM_STAT_RIPOSTEDAMAGE 669
#define ITEM_STAT_MINIMUMDEFLECTIONCHANCE 670
#define ITEM_STAT_MOVEMENTWEAVE 671
#define ITEM_STAT_COMBATHPREGEN 672
#define ITEM_STAT_COMBATMANAREGEN 673
#define ITEM_STAT_CONTESTSPEEDBOOST 674
#define ITEM_STAT_TRACKINGAVOIDANCE 675
#define ITEM_STAT_STEALTHINVISSPEEDMOD 676
#define ITEM_STAT_LOOT_COIN 677
#define ITEM_STAT_ARMORMITIGATIONINCREASE 678
#define ITEM_STAT_AMMOCONSERVATION 679
#define ITEM_STAT_STRIKETHROUGH 680
#define ITEM_STAT_STATUSBONUS 681
#define ITEM_STAT_ACCURACY 682
#define ITEM_STAT_COUNTERSTRIKE 683
#define ITEM_STAT_SHIELDBASH 684
#define ITEM_STAT_WEAPONDAMAGEBONUS 685
#define ITEM_STAT_WEAPONDAMAGEBONUSMELEEONLY 686
#define ITEM_STAT_ADDITIONALRIPOSTECHANCE 687
#define ITEM_STAT_CRITICALMITIGATION 688
#define ITEM_STAT_PVPTOUGHNESS 689
#define ITEM_STAT_PVPLETHALITY 690
#define ITEM_STAT_STAMINABONUS 691
#define ITEM_STAT_WISDOMMITBONUS 692
#define ITEM_STAT_HEALRECEIVE 693
#define ITEM_STAT_HEALRECEIVEPERC 694
#define ITEM_STAT_PVPCRITICALMITIGATION 695
#define ITEM_STAT_BASEAVOIDANCEBONUS 696
#define ITEM_STAT_INCOMBATSAVAGERYREGEN 697
#define ITEM_STAT_OUTOFCOMBATSAVAGERYREGEN 698
#define ITEM_STAT_SAVAGERYREGEN 699
#define ITEM_STAT_SAVAGERYGAINMOD 6100
#define ITEM_STAT_MAXSAVAGERYLEVEL 6101
#define ITEM_STAT_SPELL_DAMAGE 700
#define ITEM_STAT_HEAL_AMOUNT 701
#define ITEM_STAT_SPELL_AND_HEAL 702
#define ITEM_STAT_COMBAT_ART_DAMAGE 703
#define ITEM_STAT_SPELL_AND_COMBAT_ART_DAMAGE 704
#define ITEM_STAT_TAUNT_AMOUNT 705
#define ITEM_STAT_TAUNT_AND_COMBAT_ART_DAMAGE 706
#define ITEM_STAT_ABILITY_MODIFIER 707
#pragma pack(1)
struct ItemStatsValues{
sint16 str;
sint16 sta;
sint16 agi;
sint16 wis;
sint16 int_;
sint16 vs_slash;
sint16 vs_crush;
sint16 vs_pierce;
sint16 vs_heat;
sint16 vs_cold;
sint16 vs_magic;
sint16 vs_mental;
sint16 vs_divine;
sint16 vs_disease;
sint16 vs_poison;
sint16 health;
sint16 power;
sint8 concentration;
};
struct ItemCore{
int32 item_id;
sint32 soe_id;
int32 bag_id;
sint32 inv_slot_id;
sint16 slot_id;
int8 index;
int16 icon;
int16 count;
int8 tier;
int8 num_slots;
int32 unique_id;
int8 num_free_slots;
int16 recommended_level;
bool item_locked;
};
#pragma pack()
struct ItemStat{
string stat_name;
int8 stat_type;
sint16 stat_subtype;
int16 stat_type_combined;
float value;
};
struct ItemLevelOverride{
int8 adventure_class;
int8 tradeskill_class;
int16 level;
};
struct ItemClass{
int8 adventure_class;
int8 tradeskill_class;
int16 level;
};
struct ItemAppearance{
int16 type;
int8 red;
int8 green;
int8 blue;
int8 highlight_red;
int8 highlight_green;
int8 highlight_blue;
};
class PlayerItemList;
class Item{
public:
#pragma pack(1)
struct ItemStatString{
EQ2_8BitString stat_string;
};
struct Generic_Info{
int8 show_name;
int8 creator_flag;
int16 item_flags;
int8 condition;
int32 weight; // num/10
int32 skill_req1;
int32 skill_req2;
int16 skill_min;
int8 item_type; //0=normal, 1=weapon, 2=range, 3=armor, 4=shield, 5=container, 6=spell scroll, 7=recipe book, 8=food/drink, 9=bauble, 10=house item, 11=ammo, 12=house container
int16 appearance_id;
int8 appearance_red;
int8 appearance_green;
int8 appearance_blue;
int8 appearance_highlight_red;
int8 appearance_highlight_green;
int8 appearance_highlight_blue;
int8 collectable;
int32 offers_quest_id;
int32 part_of_quest_id;
int16 max_charges;
int8 display_charges;
int64 adventure_classes;
int64 tradeskill_classes;
int16 adventure_default_level;
int16 tradeskill_default_level;
int8 usable;
};
struct Armor_Info {
int16 mitigation_low;
int16 mitigation_high;
};
struct Weapon_Info {
int16 wield_type;
int16 damage_low1;
int16 damage_high1;
int16 damage_low2;
int16 damage_high2;
int16 damage_low3;
int16 damage_high3;
int16 delay;
float rating;
};
struct Shield_Info {
Armor_Info armor_info;
};
struct Ranged_Info {
Weapon_Info weapon_info;
int16 range_low;
int16 range_high;
};
struct Bag_Info {
int8 num_slots;
int16 weight_reduction;
};
struct Food_Info{
int8 type; //0=water, 1=food
int8 level;
float duration;
int8 satiation;
};
struct Bauble_Info{
int16 cast;
int16 recovery;
int32 duration;
float recast;
int8 display_slot_optional;
int8 display_cast_time;
int8 display_bauble_type;
float effect_radius;
int32 max_aoe_targets;
int8 display_until_cancelled;
};
struct Book_Info{
int8 language;
EQ2_16BitString author;
EQ2_16BitString title;
};
struct Skill_Info{
int32 spell_id;
int32 spell_tier;
};
struct House_Info{
int32 status_rent_reduction;
};
struct HouseContainer_Info{
int16 disallowed_types;
int16 allowed_types;
int8 num_slots;
};
struct RecipeBook_Info{
vector<string> recipes;
int8 uses;
};
struct Thrown_Info{
sint32 range;
sint32 damage_modifier;
float hit_bonus;
int32 damage_type;
};
struct ItemEffect{
EQ2_16BitString effect;
int8 percentage;
int8 subbulletflag;
};
#pragma pack()
Item();
Item(Item* in_item);
~Item();
string lowername;
string name;
string description;
int8 stack_count;
int32 sell_price;
int32 max_sell_value;
bool save_needed;
int8 weapon_type;
string adornment;
string creator;
vector<ItemStat*> item_stats;
vector<ItemStatString*> item_string_stats;
vector<ItemLevelOverride*> item_level_overrides;
vector<ItemEffect*> item_effects;
Generic_Info generic_info;
Weapon_Info* weapon_info;
Ranged_Info* ranged_info;
Armor_Info* armor_info;
Bag_Info* bag_info;
Food_Info* food_info;
Bauble_Info* bauble_info;
Book_Info* book_info;
Skill_Info* skill_info;
RecipeBook_Info* recipebook_info;
Thrown_Info* thrown_info;
vector<int8> slot_data;
ItemCore details;
int32 spell_id;
int8 spell_tier;
string item_script;
void AddEffect(string effect, int8 percentage, int8 subbulletflag);
int32 GetMaxSellValue();
void SetMaxSellValue(int32 val);
void SetItem(Item* old_item);
int16 GetOverrideLevel(int8 adventure_class, int8 tradeskill_class);
void AddLevelOverride(int8 adventure_class, int8 tradeskill_class, int16 level);
void AddLevelOverride(ItemLevelOverride* class_);
bool CheckClassLevel(int8 adventure_class, int8 tradeskill_class, int16 level);
bool CheckClass(int8 adventure_class, int8 tradeskill_class);
bool CheckLevel(int8 adventure_class, int8 tradeskill_class, int16 level);
void SetAppearance(int16 type, int8 red, int8 green, int8 blue, int8 highlight_red, int8 highlight_green, int8 highlight_blue);
void SetAppearance(ItemAppearance* appearance);
void AddStat(ItemStat* in_stat);
void AddStatString(ItemStatString* in_stat);
void AddStat(int8 type, int16 subtype, float value, char* name = 0);
void SetWeaponType(int8 type);
int8 GetWeaponType();
bool HasSlot(int8 slot, int8 slot2 = 255);
bool IsNormal();
bool IsWeapon();
bool IsArmor();
bool IsRanged();
bool IsBag();
bool IsFood();
bool IsBauble();
bool IsSkill();
bool IsHouseItem();
bool IsHouseContainer();
bool IsShield();
bool IsAdornment();
bool IsAmmo();
bool IsBook();
bool IsChainArmor();
bool IsClothArmor();
bool IsCollectable();
bool IsCloak();
bool IsCrushWeapon();
bool IsFoodFood();
bool IsFoodDrink();
bool IsJewelry();
bool IsLeatherArmor();
bool IsMisc();
bool IsPierceWeapon();
bool IsPlateArmor();
bool IsPoison();
bool IsPotion();
bool IsRecipeBook();
bool IsSalesDisplay();
bool IsSlashWeapon();
bool IsSpellScroll();
bool IsTinkered();
bool IsTradeskill();
bool IsThrown();
void SetItemScript(string name);
const char* GetItemScript();
int32 CalculateRepairCost();
void SetItemType(int8 in_type);
void serialize(PacketStruct* packet, bool show_name = false, Player* player = 0, int16 packet_type = 0, int8 subtype = 0, bool loot_item = false);
EQ2Packet* serialize(int16 version, bool show_name = false, Player* player = 0, bool include_twice = true, int16 packet_type = 0, int8 subtype = 0, bool merchant_item = false, bool loot_item = false);
PacketStruct* PrepareItem(int16 version, bool merchant_item = false, bool loot_item = false);
bool CheckFlag(int32 flag);
void AddSlot(int8 slot_id);
void SetSlots(int32 slots);
bool needs_deletion;
};
class MasterItemList{
public:
~MasterItemList();
map<int32,Item*> items;
Item* GetItem(int32 id);
Item* GetItemByName(const char *name);
ItemStatsValues* CalculateItemBonuses(int32 item_id);
ItemStatsValues* CalculateItemBonuses(Item* desc, ItemStatsValues* values = 0);
vector<Item*>* GetItems(string name, int32 itype, int32 ltype, int32 btype, int64 minprice, int64 maxprice, int8 minskill, int8 maxskill, string seller, string adornment, int8 mintier, int8 maxtier, int16 minlevel, int16 maxlevel, sint8 itemclass);
vector<Item*>* GetItems(map<string, string> criteria);
void AddItem(Item* item);
bool IsBag(int32 item_id);
void RemoveAll();
static int32 NextUniqueID();
static void ResetUniqueID(int32 new_id);
static int32 next_unique_id;
};
class PlayerItemList {
public:
PlayerItemList();
~PlayerItemList();
// int16 number;
map<int32, Item*> indexed_items;
map<sint32, map<int16, Item*> > items;
// map< int8, Item* > inv_items;
// map< int8, Item* > bank_items;
bool SharedBankAddAllowed(Item* item);
vector<Item*>* GetItemsFromBagID(sint32 bag_id);
vector<Item*>* GetItemsInBag(Item* bag);
Item* GetBag(int8 inventory_slot, bool lock = true);
bool HasItem(int32 id, bool include_bank = false);
Item* GetItemFromIndex(int32 index);
void MoveItem(Item* item, sint32 inv_slot, int16 slot, bool erase_old = true);
bool MoveItem(sint32 to_bag_id, int16 from_index, sint8 to, int8 charges);
Item* GetItemFromUniqueID(int32 item_id, bool include_bank = false, bool lock = true);
Item* GetItemFromID(int32 item_id, int8 count = 0, bool include_bank = false, bool lock = true);
bool AssignItemToFreeSlot(Item* item);
int16 GetNumberOfFreeSlots();
int16 GetNumberOfItems();
bool HasFreeSlot();
bool HasFreeBagSlot();
void DestroyItem(int16 index);
Item* CanStack(Item* item, bool include_bank = false);
void RemoveItem(Item* item, bool delete_item = false);
void AddItem(Item* item);
Item* GetItem(sint32 bag_slot, int16 slot);
EQ2Packet* serialize(Player* player, int16 version);
uchar* xor_packet;
uchar* orig_packet;
map<int32, Item*>* GetAllItems();
bool HasFreeBankSlot();
int8 FindFreeBankSlot();
private:
void Stack(Item* orig_item, Item* item);
Mutex MPlayerItems;
int16 packet_count;
};
class OverFlowItemList : public PlayerItemList {
public:
bool OverFlowSlotFull();
int8 GetNextOverFlowSlot();
bool AddItem(Item* item);
Item* GetOverFlowItem();
};
class EquipmentItemList{
public:
EquipmentItemList();
EquipmentItemList(const EquipmentItemList& list);
~EquipmentItemList();
Item* items[NUM_SLOTS];
vector<Item*>* GetAllEquippedItems();
bool HasItem(int32 id);
int8 GetNumberOfItems();
Item* GetItemFromUniqueID(int32 item_id);
Item* GetItemFromItemID(int32 item_id);
void SetItem(int8 slot_id, Item* item);
void RemoveItem(int8 slot, bool delete_item = false);
Item* GetItem(int8 slot_id);
bool AddItem(int8 slot, Item* item);
bool CheckEquipSlot(Item* tmp, int8 slot);
bool CanItemBeEquippedInSlot(Item* tmp, int8 slot);
int8 GetFreeSlot(Item* tmp, int8 slot_id = 255);
ItemStatsValues* CalculateEquipmentBonuses();
EQ2Packet* serialize(int16 version);
uchar* xor_packet;
uchar* orig_packet;
private:
Mutex MEquipmentItems;
};
#endif

View File

@ -0,0 +1,916 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __EQ2_ITEMS__
#define __EQ2_ITEMS__
#include <map>
#include <vector>
#include "../../common/types.h"
#include "../../common/DataBuffer.h"
#include "../../common/MiscFunctions.h"
#include "../Commands/Commands.h"
#include "../../common/ConfigReader.h"
using namespace std;
class MasterItemList;
class Player;
class Entity;
extern MasterItemList master_item_list;
#define EQ2_PRIMARY_SLOT 0
#define EQ2_SECONDARY_SLOT 1
#define EQ2_HEAD_SLOT 2
#define EQ2_CHEST_SLOT 3
#define EQ2_SHOULDERS_SLOT 4
#define EQ2_FOREARMS_SLOT 5
#define EQ2_HANDS_SLOT 6
#define EQ2_LEGS_SLOT 7
#define EQ2_FEET_SLOT 8
#define EQ2_LRING_SLOT 9
#define EQ2_RRING_SLOT 10
#define EQ2_EARS_SLOT_1 11
#define EQ2_EARS_SLOT_2 12
#define EQ2_NECK_SLOT 13
#define EQ2_LWRIST_SLOT 14
#define EQ2_RWRIST_SLOT 15
#define EQ2_RANGE_SLOT 16
#define EQ2_AMMO_SLOT 17
#define EQ2_WAIST_SLOT 18
#define EQ2_CLOAK_SLOT 19
#define EQ2_CHARM_SLOT_1 20
#define EQ2_CHARM_SLOT_2 21
#define EQ2_FOOD_SLOT 22
#define EQ2_DRINK_SLOT 23
#define EQ2_TEXTURES_SLOT 24
#define EQ2_HAIR_SLOT 25
#define EQ2_BEARD_SLOT 26
#define EQ2_WINGS_SLOT 27
#define EQ2_NAKED_CHEST_SLOT 28
#define EQ2_NAKED_LEGS_SLOT 29
#define EQ2_BACK_SLOT 30
#define PRIMARY_SLOT 1
#define SECONDARY_SLOT 2
#define HEAD_SLOT 4
#define CHEST_SLOT 8
#define SHOULDERS_SLOT 16
#define FOREARMS_SLOT 32
#define HANDS_SLOT 64
#define LEGS_SLOT 128
#define FEET_SLOT 256
#define LRING_SLOT 512
#define RRING_SLOT 1024
#define EARS_SLOT_1 2048
#define EARS_SLOT_2 4096
#define NECK_SLOT 8192
#define LWRIST_SLOT 16384
#define RWRIST_SLOT 32768
#define RANGE_SLOT 65536
#define AMMO_SLOT 131072
#define WAIST_SLOT 262144
#define CLOAK_SLOT 524288
#define CHARM_SLOT_1 1048576
#define CHARM_SLOT_2 2097152
#define FOOD_SLOT 4194304
#define DRINK_SLOT 8388608
#define TEXTURES_SLOT 16777216
#define HAIR_SLOT 33554432
#define BEARD_SLOT 67108864
#define WINGS_SLOT 134217728
#define NAKED_CHEST_SLOT 268435456
#define NAKED_LEGS_SLOT 536870912
#define BACK_SLOT 1073741824
#define NUM_BANK_SLOTS 12
#define NUM_SHARED_BANK_SLOTS 8
#define NUM_SLOTS 25
#define NUM_INV_SLOTS 6
#define INV_SLOT1 0
#define INV_SLOT2 50
#define INV_SLOT3 100
#define INV_SLOT4 150
#define INV_SLOT5 200
#define INV_SLOT6 250
#define BANK_SLOT1 1000
#define BANK_SLOT2 1100
#define BANK_SLOT3 1200
#define BANK_SLOT4 1300
#define BANK_SLOT5 1400
#define BANK_SLOT6 1500
#define BANK_SLOT7 1600
#define BANK_SLOT8 1700
#define ATTUNED 1
#define ATTUNEABLE 2
#define ARTIFACT 4
#define LORE 8
#define TEMPORARY 16
#define NO_TRADE 32
#define NO_VALUE 64
#define NO_ZONE 128
#define NO_DESTROY 256
#define CRAFTED 512
#define GOOD_ONLY 1024
#define EVIL_ONLY 2048
#define ITEM_WIELD_TYPE_DUAL 1
#define ITEM_WIELD_TYPE_SINGLE 2
#define ITEM_WIELD_TYPE_TWO_HAND 4
#define ITEM_TYPE_NORMAL 0
#define ITEM_TYPE_WEAPON 1
#define ITEM_TYPE_RANGED 2
#define ITEM_TYPE_ARMOR 3
#define ITEM_TYPE_SHIELD 4
#define ITEM_TYPE_BAG 5
#define ITEM_TYPE_SKILL 6
#define ITEM_TYPE_RECIPE 7
#define ITEM_TYPE_FOOD 8
#define ITEM_TYPE_BAUBLE 9
#define ITEM_TYPE_HOUSE 10
#define ITEM_TYPE_THROWN 11
#define ITEM_TYPE_HOUSE_CONTAINER 12
#define ITEM_TYPE_BOOK 13
#define ITEM_TYPE_ADORNMENT 14
#define ITEM_TYPE_PATTERN 15
#define ITEM_TYPE_ARMORSET 16
#define ITEM_MENU_TYPE_GENERIC 1
#define ITEM_MENU_TYPE_EQUIP 2
#define ITEM_MENU_TYPE_BAG 4
#define ITEM_MENU_TYPE_HOUSE 8
#define ITEM_MENU_TYPE_SCRIBE 32
#define ITEM_MENU_TYPE_INVALID 128
#define ITEM_MENU_TYPE_BROKEN 512
#define ITEM_MENU_TYPE_ATTUNED 2048
#define ITEM_MENU_TYPE_ATTUNEABLE 4096
#define ITEM_MENU_TYPE_BOOK 8192
#define ITEM_MENU_TYPE_DISPLAY_CHARGES 16384
#define ITEM_MENU_TYPE_NAMEPET 65536
#define ITEM_MENU_TYPE_CONSUME 262144
#define ITEM_MENU_TYPE_USE 524288
#define ITEM_MENU_TYPE_DRINK 8388608
#define ITEM_MENU_TYPE_REDEEM 536870912
#define ITEM_TAG_UNCOMMON 3 //tier tags
#define ITEM_TAG_TREASURED 4
#define ITEM_TAG_LEGENDARY 7
#define ITEM_TAG_FABLED 9
#define ITEM_TAG_MYTHICAL 12
#define ITEM_BROKER_TYPE_ANY 0xFFFFFFFF
#define ITEM_BROKER_TYPE_ADORNMENT 134217728
#define ITEM_BROKER_TYPE_AMMO 1024
#define ITEM_BROKER_TYPE_ATTUNEABLE 16384
#define ITEM_BROKER_TYPE_BAG 2048
#define ITEM_BROKER_TYPE_BAUBLE 16777216
#define ITEM_BROKER_TYPE_BOOK 128
#define ITEM_BROKER_TYPE_CHAINARMOR 2097152
#define ITEM_BROKER_TYPE_CLOAK 1073741824
#define ITEM_BROKER_TYPE_CLOTHARMOR 524288
#define ITEM_BROKER_TYPE_COLLECTABLE 67108864
#define ITEM_BROKER_TYPE_CRUSHWEAPON 4
#define ITEM_BROKER_TYPE_DRINK 131072
#define ITEM_BROKER_TYPE_FOOD 4096
#define ITEM_BROKER_TYPE_HOUSEITEM 512
#define ITEM_BROKER_TYPE_JEWELRY 262144
#define ITEM_BROKER_TYPE_LEATHERARMOR 1048576
#define ITEM_BROKER_TYPE_LORE 8192
#define ITEM_BROKER_TYPE_MISC 1
#define ITEM_BROKER_TYPE_PIERCEWEAPON 8
#define ITEM_BROKER_TYPE_PLATEARMOR 4194304
#define ITEM_BROKER_TYPE_POISON 65536
#define ITEM_BROKER_TYPE_POTION 32768
#define ITEM_BROKER_TYPE_RECIPEBOOK 8388608
#define ITEM_BROKER_TYPE_SALESDISPLAY 33554432
#define ITEM_BROKER_TYPE_SHIELD 32
#define ITEM_BROKER_TYPE_SLASHWEAPON 2
#define ITEM_BROKER_TYPE_SPELLSCROLL 64
#define ITEM_BROKER_TYPE_TINKERED 268435456
#define ITEM_BROKER_TYPE_TRADESKILL 256
#define ITEM_BROKER_SLOT_ANY 0xFFFFFFFF
#define ITEM_BROKER_SLOT_AMMO 65536
#define ITEM_BROKER_SLOT_CHARM 524288
#define ITEM_BROKER_SLOT_CHEST 32
#define ITEM_BROKER_SLOT_CLOAK 262144
#define ITEM_BROKER_SLOT_DRINK 2097152
#define ITEM_BROKER_SLOT_EARS 4096
#define ITEM_BROKER_SLOT_FEET 1024
#define ITEM_BROKER_SLOT_FOOD 1048576
#define ITEM_BROKER_SLOT_FOREARMS 128
#define ITEM_BROKER_SLOT_HANDS 256
#define ITEM_BROKER_SLOT_HEAD 16
#define ITEM_BROKER_SLOT_LEGS 512
#define ITEM_BROKER_SLOT_NECK 8192
#define ITEM_BROKER_SLOT_PRIMARY 1
#define ITEM_BROKER_SLOT_PRIMARY_2H 2
#define ITEM_BROKER_SLOT_RANGE_WEAPON 32768
#define ITEM_BROKER_SLOT_RING 2048
#define ITEM_BROKER_SLOT_SECONDARY 8
#define ITEM_BROKER_SLOT_SHOULDERS 64
#define ITEM_BROKER_SLOT_WAIST 131072
#define ITEM_BROKER_SLOT_WRIST 16384
#define ITEM_BROKER_STAT_TYPE_NONE 0
#define ITEM_BROKER_STAT_TYPE_DEF 2
#define ITEM_BROKER_STAT_TYPE_STR 4
#define ITEM_BROKER_STAT_TYPE_STA 8
#define ITEM_BROKER_STAT_TYPE_AGI 16
#define ITEM_BROKER_STAT_TYPE_WIS 32
#define ITEM_BROKER_STAT_TYPE_INT 64
#define ITEM_BROKER_STAT_TYPE_HEALTH 128
#define ITEM_BROKER_STAT_TYPE_POWER 256
#define ITEM_BROKER_STAT_TYPE_HEAT 512
#define ITEM_BROKER_STAT_TYPE_COLD 1024
#define ITEM_BROKER_STAT_TYPE_MAGIC 2048
#define ITEM_BROKER_STAT_TYPE_MENTAL 4096
#define ITEM_BROKER_STAT_TYPE_DIVINE 8192
#define ITEM_BROKER_STAT_TYPE_POISON 16384
#define ITEM_BROKER_STAT_TYPE_DISEASE 32768
#define ITEM_BROKER_STAT_TYPE_CRUSH 65536
#define ITEM_BROKER_STAT_TYPE_SLASH 131072
#define ITEM_BROKER_STAT_TYPE_PIERCE 262144
#define ITEM_BROKER_STAT_TYPE_CRITICAL 524288
#define ITEM_BROKER_STAT_TYPE_DBL_ATTACK 1048576
#define ITEM_BROKER_STAT_TYPE_ABILITY_MOD 2097152
#define ITEM_BROKER_STAT_TYPE_POTENCY 4194304
#define OVERFLOW_SLOT 0xFFFFFFFE
#define SLOT_INVALID 0xFFFF
#define ITEM_STAT_STR 0
#define ITEM_STAT_STA 1
#define ITEM_STAT_AGI 2
#define ITEM_STAT_WIS 3
#define ITEM_STAT_INT 4
#define ITEM_STAT_ADORNING 100
#define ITEM_STAT_AGGRESSION 101
#define ITEM_STAT_ARTIFICING 102
#define ITEM_STAT_ARTISTRY 103
#define ITEM_STAT_CHEMISTRY 104
#define ITEM_STAT_CRUSHING 105
#define ITEM_STAT_DEFENSE 106
#define ITEM_STAT_DEFLECTION 107
#define ITEM_STAT_DISRUPTION 108
#define ITEM_STAT_FISHING 109
#define ITEM_STAT_FLETCHING 110
#define ITEM_STAT_FOCUS 111
#define ITEM_STAT_FORESTING 112
#define ITEM_STAT_GATHERING 113
#define ITEM_STAT_METAL_SHAPING 114
#define ITEM_STAT_METALWORKING 115
#define ITEM_STAT_MINING 116
#define ITEM_STAT_MINISTRATION 117
#define ITEM_STAT_ORDINATION 118
#define ITEM_STAT_PARRY 119
#define ITEM_STAT_PIERCING 120
#define ITEM_STAT_RANGED 121
#define ITEM_STAT_SAFE_FALL 122
#define ITEM_STAT_SCRIBING 123
#define ITEM_STAT_SCULPTING 124
#define ITEM_STAT_SLASHING 125
#define ITEM_STAT_SUBJUGATION 126
#define ITEM_STAT_SWIMMING 127
#define ITEM_STAT_TAILORING 128
#define ITEM_STAT_TINKERING 129
#define ITEM_STAT_TRANSMUTING 130
#define ITEM_STAT_TRAPPING 131
#define ITEM_STAT_WEAPON_SKILLS 132
#define ITEM_STAT_VS_PHYSICAL 200
#define ITEM_STAT_VS_HEAT 201 //elemental
#define ITEM_STAT_VS_POISON 202 //noxious
#define ITEM_STAT_VS_MAGIC 203 //arcane
#define ITEM_STAT_VS_DROWNING 210
#define ITEM_STAT_VS_FALLING 211
#define ITEM_STAT_VS_PAIN 212
#define ITEM_STAT_VS_MELEE 213
#define ITEM_STAT_VS_SLASH 204
#define ITEM_STAT_VS_CRUSH 205
#define ITEM_STAT_VS_PIERCE 206
//#define ITEM_STAT_VS_HEAT 203 //just so no build error
#define ITEM_STAT_VS_COLD 207
//#define ITEM_STAT_VS_MAGIC 205 //just so no build error
#define ITEM_STAT_VS_MENTAL 208
#define ITEM_STAT_VS_DIVINE 209
#define ITEM_STAT_VS_DISEASE 214
//#define ITEM_STAT_VS_POISON 209 //just so no build error
//#define ITEM_STAT_VS_DROWNING 210 //just so no build error
//#define ITEM_STAT_VS_FALLING 211 //just so no build error
//#define ITEM_STAT_VS_PAIN 212 //just so no build error
//#define ITEM_STAT_VS_MELEE 213 //just so no build error
#define ITEM_STAT_DMG_SLASH 300
#define ITEM_STAT_DMG_CRUSH 301
#define ITEM_STAT_DMG_PIERCE 302
#define ITEM_STAT_DMG_HEAT 303
#define ITEM_STAT_DMG_COLD 304
#define ITEM_STAT_DMG_MAGIC 305
#define ITEM_STAT_DMG_MENTAL 306
#define ITEM_STAT_DMG_DIVINE 307
#define ITEM_STAT_DMG_DISEASE 308
#define ITEM_STAT_DMG_POISON 309
#define ITEM_STAT_DMG_DROWNING 310
#define ITEM_STAT_DMG_FALLING 311
#define ITEM_STAT_DMG_PAIN 312
#define ITEM_STAT_DMG_MELEE 313
#define ITEM_STAT_HEALTH 500
#define ITEM_STAT_POWER 501
#define ITEM_STAT_CONCENTRATION 502
#define ITEM_STAT_HPREGEN 600
#define ITEM_STAT_MANAREGEN 601
#define ITEM_STAT_HPREGENPPT 602
#define ITEM_STAT_MPREGENPPT 603
#define ITEM_STAT_COMBATHPREGENPPT 604
#define ITEM_STAT_COMBATMPREGENPPT 605
#define ITEM_STAT_MAXHP 606
#define ITEM_STAT_MAXHPPERC 607
#define ITEM_STAT_SPEED 608
#define ITEM_STAT_SLOW 609
#define ITEM_STAT_MOUNTSPEED 610
#define ITEM_STAT_MOUNTAIRSPEED 611
#define ITEM_STAT_OFFENSIVESPEED 612
#define ITEM_STAT_ATTACKSPEED 613
#define ITEM_STAT_MAXMANA 614
#define ITEM_STAT_MAXMANAPERC 615
#define ITEM_STAT_MAXATTPERC 616
#define ITEM_STAT_BLURVISION 617
#define ITEM_STAT_MAGICLEVELIMMUNITY 618
#define ITEM_STAT_HATEGAINMOD 619
#define ITEM_STAT_COMBATEXPMOD 620
#define ITEM_STAT_TRADESKILLEXPMOD 621
#define ITEM_STAT_ACHIEVEMENTEXPMOD 622
#define ITEM_STAT_SIZEMOD 623
#define ITEM_STAT_DPS 624
#define ITEM_STAT_STEALTH 625
#define ITEM_STAT_INVIS 626
#define ITEM_STAT_SEESTEALTH 627
#define ITEM_STAT_SEEINVIS 628
#define ITEM_STAT_EFFECTIVELEVELMOD 629
#define ITEM_STAT_RIPOSTECHANCE 630
#define ITEM_STAT_PARRYCHANCE 631
#define ITEM_STAT_DODGECHANCE 632
#define ITEM_STAT_AEAUTOATTACKCHANCE 633
#define ITEM_STAT_MULTIATTACKCHANCE 634
#define ITEM_STAT_SPELLMULTIATTACKCHANCE 635
#define ITEM_STAT_FLURRY 636
#define ITEM_STAT_MELEEDAMAGEMULTIPLIER 637
#define ITEM_STAT_EXTRAHARVESTCHANCE 638
#define ITEM_STAT_EXTRASHIELDBLOCKCHANCE 639
#define ITEM_STAT_ITEMHPREGENPPT 640
#define ITEM_STAT_ITEMPPREGENPPT 641
#define ITEM_STAT_MELEECRITCHANCE 642
#define ITEM_STAT_CRITAVOIDANCE 643
#define ITEM_STAT_BENEFICIALCRITCHANCE 644
#define ITEM_STAT_CRITBONUS 645
#define ITEM_STAT_POTENCY 646
#define ITEM_STAT_UNCONSCIOUSHPMOD 647
#define ITEM_STAT_ABILITYREUSESPEED 648
#define ITEM_STAT_ABILITYRECOVERYSPEED 649
#define ITEM_STAT_ABILITYCASTINGSPEED 650
#define ITEM_STAT_SPELLREUSESPEED 651
#define ITEM_STAT_MELEEWEAPONRANGE 652
#define ITEM_STAT_RANGEDWEAPONRANGE 653
#define ITEM_STAT_FALLINGDAMAGEREDUCTION 654
#define ITEM_STAT_RIPOSTEDAMAGE 655
#define ITEM_STAT_MINIMUMDEFLECTIONCHANCE 656
#define ITEM_STAT_MOVEMENTWEAVE 657
#define ITEM_STAT_COMBATHPREGEN 658
#define ITEM_STAT_COMBATMANAREGEN 659
#define ITEM_STAT_CONTESTSPEEDBOOST 660
#define ITEM_STAT_TRACKINGAVOIDANCE 661
#define ITEM_STAT_STEALTHINVISSPEEDMOD 662
#define ITEM_STAT_LOOT_COIN 663
#define ITEM_STAT_ARMORMITIGATIONINCREASE 664
#define ITEM_STAT_AMMOCONSERVATION 665
#define ITEM_STAT_STRIKETHROUGH 666
#define ITEM_STAT_STATUSBONUS 667
#define ITEM_STAT_ACCURACY 668
#define ITEM_STAT_COUNTERSTRIKE 669
#define ITEM_STAT_SHIELDBASH 670
#define ITEM_STAT_WEAPONDAMAGEBONUS 671
#define ITEM_STAT_ADDITIONALRIPOSTECHANCE 672
#define ITEM_STAT_CRITICALMITIGATION 673
#define ITEM_STAT_PVPTOUGHNESS 674
#define ITEM_STAT_STAMINABONUS 675
#define ITEM_STAT_WISDOMITBONUS 676
#define ITEM_STAT_HEALRECEIVE 677
#define ITEM_STAT_HEALRECEIVEPERC 678
#define ITEM_STAT_PVPCRITICALMITIGATION 679
#define ITEM_STAT_BASEAVOIDANCEBONUS 680
//#define ITEM_STAT_HPREGEN 600
//#define ITEM_STAT_MANAREGEN 601
//#define ITEM_STAT_HPREGENPPT 602
//#define ITEM_STAT_MPREGENPPT 603
//#define ITEM_STAT_COMBATHPREGENPPT 604
//#define ITEM_STAT_COMBATMPREGENPPT 605
//#define ITEM_STAT_MAXHP 606
//#define ITEM_STAT_MAXHPPERC 607
//#define ITEM_STAT_SPEED 608
//#define ITEM_STAT_SLOW 609
//#define ITEM_STAT_MOUNTSPEED 610
//#define ITEM_STAT_OFFENSIVESPEED 611
//#define ITEM_STAT_ATTACKSPEED 612
//#define ITEM_STAT_MAXMANA 613
//#define ITEM_STAT_MAXMANAPERC 614
//#define ITEM_STAT_MAXATTPERC 615
//#define ITEM_STAT_BLURVISION 616
//#define ITEM_STAT_MAGICLEVELIMMUNITY 617
//#define ITEM_STAT_HATEGAINMOD 618
//#define ITEM_STAT_COMBATEXPMOD 619
//#define ITEM_STAT_TRADESKILLEXPMOD 620
//#define ITEM_STAT_ACHIEVEMENTEXPMOD 621
//#define ITEM_STAT_SIZEMOD 622
//#define ITEM_STAT_UNKNOWN 623
//#define ITEM_STAT_STEALTH 624
//#define ITEM_STAT_INVIS 625
//#define ITEM_STAT_SEESTEALTH 626
//#define ITEM_STAT_SEEINVIS 627
//#define ITEM_STAT_EFFECTIVELEVELMOD 628
//#define ITEM_STAT_RIPOSTECHANCE 629
//#define ITEM_STAT_PARRYCHANCE 630
//#define ITEM_STAT_DODGECHANCE 631
//#define ITEM_STAT_AEAUTOATTACKCHANCE 632
//#define ITEM_STAT_DOUBLEATTACKCHANCE 633
//#define ITEM_STAT_RANGEDDOUBLEATTACKCHANCE 634
//#define ITEM_STAT_SPELLDOUBLEATTACKCHANCE 635
//#define ITEM_STAT_FLURRY 636
//#define ITEM_STAT_EXTRAHARVESTCHANCE 637
//#define ITEM_STAT_EXTRASHIELDBLOCKCHANCE 638
#define ITEM_STAT_DEFLECTIONCHANCE 400 //just so no build error
//#define ITEM_STAT_ITEMHPREGENPPT 640
//#define ITEM_STAT_ITEMPPREGENPPT 641
//#define ITEM_STAT_MELEECRITCHANCE 642
//#define ITEM_STAT_RANGEDCRITCHANCE 643
//#define ITEM_STAT_DMGSPELLCRITCHANCE 644
//#define ITEM_STAT_HEALSPELLCRITCHANCE 645
//#define ITEM_STAT_MELEECRITBONUS 646
//#define ITEM_STAT_RANGEDCRITBONUS 647
//#define ITEM_STAT_DMGSPELLCRITBONUS 648
//#define ITEM_STAT_HEALSPELLCRITBONUS 649
//#define ITEM_STAT_UNCONSCIOUSHPMOD 650
//#define ITEM_STAT_SPELLTIMEREUSEPCT 651
//#define ITEM_STAT_SPELLTIMERECOVERYPCT 652
//#define ITEM_STAT_SPELLTIMECASTPCT 653
//#define ITEM_STAT_MELEEWEAPONRANGE 654
//#define ITEM_STAT_RANGEDWEAPONRANGE 655
//#define ITEM_STAT_FALLINGDAMAGEREDUCTION 656
//#define ITEM_STAT_SHIELDEFFECTIVENESS 657
//#define ITEM_STAT_RIPOSTEDAMAGE 658
//#define ITEM_STAT_MINIMUMDEFLECTIONCHANCE 659
//#define ITEM_STAT_MOVEMENTWEAVE 660
//#define ITEM_STAT_COMBATHPREGEN 661
//#define ITEM_STAT_COMBATMANAREGEN 662
//#define ITEM_STAT_CONTESTSPEEDBOOST 663
//#define ITEM_STAT_TRACKINGAVOIDANCE 664
//#define ITEM_STAT_STEALTHINVISSPEEDMOD 665
//#define ITEM_STAT_LOOT_COIN 666
//#define ITEM_STAT_ARMORMITIGATIONINCREASE 667
//#define ITEM_STAT_AMMOCONSERVATION 668
//#define ITEM_STAT_STRIKETHROUGH 669
//#define ITEM_STAT_STATUSBONUS 670
//#define ITEM_STAT_ACCURACY 671
//#define ITEM_STAT_COUNTERSTRIKE 672
//#define ITEM_STAT_SHIELDBASH 673
//#define ITEM_STAT_WEAPONDAMAGEBONUS 674
//#define ITEM_STAT_ADDITIONALRIPOSTECHANCE 675
//#define ITEM_STAT_CRITICALMITIGATION 676
//#define ITEM_STAT_COMBATARTDAMAGE 677
//#define ITEM_STAT_SPELLDAMAGE 678
//#define ITEM_STAT_HEALAMOUNT 679
//#define ITEM_STAT_TAUNTAMOUNT 680
#define ITEM_STAT_SPELL_DAMAGE 700
#define ITEM_STAT_HEAL_AMOUNT 701
#define ITEM_STAT_SPELL_AND_HEAL 702
#define ITEM_STAT_COMBAT_ART_DAMAGE 703
#define ITEM_STAT_SPELL_AND_COMBAT_ART_DAMAGE 704
#define ITEM_STAT_TAUNT_AMOUNT 705
#define ITEM_STAT_TAUNT_AND_COMBAT_ART_DAMAGE 706
#define ITEM_STAT_ABILITY_MODIFIER 707
#pragma pack(1)
struct ItemStatsValues{
sint16 str;
sint16 sta;
sint16 agi;
sint16 wis;
sint16 int_;
sint16 vs_slash;
sint16 vs_crush;
sint16 vs_pierce;
sint16 vs_heat;
sint16 vs_cold;
sint16 vs_magic;
sint16 vs_mental;
sint16 vs_divine;
sint16 vs_disease;
sint16 vs_poison;
sint16 health;
sint16 power;
sint8 concentration;
sint16 ability_modifier;
sint16 criticalmitigation;
sint16 extrashieldblockchance;
sint16 beneficialcritchance;
sint16 critbonus;
sint16 potency;
sint16 hategainmod;
sint16 abilityreusespeed;
sint16 abilitycastingspeed;
sint16 abilityrecoveryspeed;
sint16 spellreusespeed;
sint16 spellmultiattackchance;
sint16 dps;
sint16 attackspeed;
sint16 multiattackchance;
sint16 aeautoattackchance;
sint16 strikethrough;
sint16 accuracy;
sint16 offensivespeed;
};
struct ItemCore{
int32 item_id;
sint32 soe_id;
int32 bag_id;
sint32 inv_slot_id;
sint16 slot_id;
int8 index;
int16 icon;
int16 count;
int8 tier;
int8 num_slots;
int32 unique_id;
int8 num_free_slots;
int16 recommended_level;
bool item_locked;
};
#pragma pack()
struct ItemStat{
string stat_name;
int8 stat_type;
sint16 stat_subtype;
int16 stat_type_combined;
float value;
};
struct ItemLevelOverride{
int8 adventure_class;
int8 tradeskill_class;
int16 level;
};
struct ItemClass{
int8 adventure_class;
int8 tradeskill_class;
int16 level;
};
struct ItemAppearance{
int16 type;
int8 red;
int8 green;
int8 blue;
int8 highlight_red;
int8 highlight_green;
int8 highlight_blue;
};
class PlayerItemList;
class Item{
public:
#pragma pack(1)
struct ItemStatString{
EQ2_8BitString stat_string;
};
struct Generic_Info{
int8 show_name;
int8 creator_flag;
int16 item_flags;
int8 condition;
int32 weight; // num/10
int32 skill_req1;
int32 skill_req2;
int16 skill_min;
int8 item_type; //0=normal, 1=weapon, 2=range, 3=armor, 4=shield, 5=bag, 6=scroll, 7=recipe, 8=food, 9=bauble, 10=house item, 11=thrown, 12=house container, 13=adormnet, 14=??, 16=profile, 17=patter set, 18=item set, 19=book, 20=decoration, 21=dungeon maker, 22=marketplace
int16 appearance_id;
int8 appearance_red;
int8 appearance_green;
int8 appearance_blue;
int8 appearance_highlight_red;
int8 appearance_highlight_green;
int8 appearance_highlight_blue;
int8 collectable;
int32 offers_quest_id;
int32 part_of_quest_id;
int16 max_charges;
int8 display_charges;
int64 adventure_classes;
int64 tradeskill_classes;
int16 adventure_default_level;
int16 tradeskill_default_level;
int8 usable;
};
struct Armor_Info {
int16 mitigation_low;
int16 mitigation_high;
};
struct Weapon_Info {
int16 wield_type;
int16 damage_low1;
int16 damage_high1;
int16 damage_low2;
int16 damage_high2;
int16 damage_low3;
int16 damage_high3;
int16 delay;
float rating;
};
struct Shield_Info {
Armor_Info armor_info;
};
struct Ranged_Info {
Weapon_Info weapon_info;
int16 range_low;
int16 range_high;
};
struct Bag_Info {
int8 num_slots;
int16 weight_reduction;
};
struct Food_Info{
int8 type; //0=water, 1=food
int8 level;
float duration;
int8 satiation;
};
struct Bauble_Info{
int16 cast;
int16 recovery;
int32 duration;
float recast;
int8 display_slot_optional;
int8 display_cast_time;
int8 display_bauble_type;
float effect_radius;
int32 max_aoe_targets;
int8 display_until_cancelled;
};
struct Book_Info{
int8 language;
EQ2_16BitString author;
EQ2_16BitString title;
};
struct Skill_Info{
int32 spell_id;
int32 spell_tier;
};
struct House_Info{
int32 status_rent_reduction;
};
struct HouseContainer_Info{
int16 disallowed_types;
int16 allowed_types;
int8 num_slots;
};
struct RecipeBook_Info{
vector<string> recipes;
int8 uses;
};
struct Thrown_Info{
sint32 range;
sint32 damage_modifier;
float hit_bonus;
int32 damage_type;
};
struct ItemEffect{
EQ2_16BitString effect;
int8 percentage;
int8 subbulletflag;
};
#pragma pack()
Item();
Item(Item* in_item);
~Item();
string lowername;
string name;
string description;
int8 stack_count;
int32 sell_price;
int32 max_sell_value;
bool save_needed;
int8 weapon_type;
string adornment;
string creator;
vector<ItemStat*> item_stats;
vector<ItemStatString*> item_string_stats;
vector<ItemLevelOverride*> item_level_overrides;
vector<ItemEffect*> item_effects;
Generic_Info generic_info;
Weapon_Info* weapon_info;
Ranged_Info* ranged_info;
Armor_Info* armor_info;
Bag_Info* bag_info;
Food_Info* food_info;
Bauble_Info* bauble_info;
Book_Info* book_info;
Skill_Info* skill_info;
RecipeBook_Info* recipebook_info;
Thrown_Info* thrown_info;
vector<int8> slot_data;
ItemCore details;
int32 spell_id;
int8 spell_tier;
string item_script;
void AddEffect(string effect, int8 percentage, int8 subbulletflag);
int32 GetMaxSellValue();
void SetMaxSellValue(int32 val);
void SetItem(Item* old_item);
int16 GetOverrideLevel(int8 adventure_class, int8 tradeskill_class);
void AddLevelOverride(int8 adventure_class, int8 tradeskill_class, int16 level);
void AddLevelOverride(ItemLevelOverride* class_);
bool CheckClassLevel(int8 adventure_class, int8 tradeskill_class, int16 level);
bool CheckClass(int8 adventure_class, int8 tradeskill_class);
bool CheckLevel(int8 adventure_class, int8 tradeskill_class, int16 level);
void SetAppearance(int16 type, int8 red, int8 green, int8 blue, int8 highlight_red, int8 highlight_green, int8 highlight_blue);
void SetAppearance(ItemAppearance* appearance);
void AddStat(ItemStat* in_stat);
void AddStatString(ItemStatString* in_stat);
void AddStat(int8 type, int16 subtype, float value, char* name = 0);
void SetWeaponType(int8 type);
int8 GetWeaponType();
bool HasSlot(int8 slot, int8 slot2 = 255);
bool IsNormal();
bool IsWeapon();
bool IsArmor();
bool IsRanged();
bool IsBag();
bool IsFood();
bool IsBauble();
bool IsSkill();
bool IsHouseItem();
bool IsHouseContainer();
bool IsShield();
bool IsAdornment();
bool IsAmmo();
bool IsBook();
bool IsChainArmor();
bool IsClothArmor();
bool IsCollectable();
bool IsCloak();
bool IsCrushWeapon();
bool IsFoodFood();
bool IsFoodDrink();
bool IsJewelry();
bool IsLeatherArmor();
bool IsMisc();
bool IsPierceWeapon();
bool IsPlateArmor();
bool IsPoison();
bool IsPotion();
bool IsRecipeBook();
bool IsSalesDisplay();
bool IsSlashWeapon();
bool IsSpellScroll();
bool IsTinkered();
bool IsTradeskill();
bool IsThrown();
void SetItemScript(string name);
const char* GetItemScript();
int32 CalculateRepairCost();
void SetItemType(int8 in_type);
void serialize(PacketStruct* packet, bool show_name = false, Player* player = 0, int16 packet_type = 0, int8 subtype = 0, bool loot_item = false);
EQ2Packet* serialize(int16 version, bool show_name = false, Player* player = 0, bool include_twice = true, int16 packet_type = 0, int8 subtype = 0, bool merchant_item = false, bool loot_item = false);
PacketStruct* PrepareItem(int16 version, bool merchant_item = false, bool loot_item = false);
bool CheckFlag(int32 flag);
void AddSlot(int8 slot_id);
void SetSlots(int32 slots);
bool needs_deletion;
};
class MasterItemList{
public:
~MasterItemList();
map<int32,Item*> items;
Item* GetItem(int32 id);
Item* GetItemByName(const char *name);
ItemStatsValues* CalculateItemBonuses(int32 item_id, Entity* entity = 0);
ItemStatsValues* CalculateItemBonuses(Item* desc, Entity* entity = 0, ItemStatsValues* values = 0);
vector<Item*>* GetItems(string name, int32 itype, int32 ltype, int32 btype, int64 minprice, int64 maxprice, int8 minskill, int8 maxskill, string seller, string adornment, int8 mintier, int8 maxtier, int16 minlevel, int16 maxlevel, sint8 itemclass);
vector<Item*>* GetItems(map<string, string> criteria);
void AddItem(Item* item);
bool IsBag(int32 item_id);
void RemoveAll();
static int32 NextUniqueID();
static void ResetUniqueID(int32 new_id);
static int32 next_unique_id;
};
class PlayerItemList {
public:
PlayerItemList();
~PlayerItemList();
// int16 number;
map<int32, Item*> indexed_items;
map<sint32, map<int16, Item*> > items;
// map< int8, Item* > inv_items;
// map< int8, Item* > bank_items;
bool SharedBankAddAllowed(Item* item);
vector<Item*>* GetItemsFromBagID(sint32 bag_id);
vector<Item*>* GetItemsInBag(Item* bag);
Item* GetBag(int8 inventory_slot, bool lock = true);
bool HasItem(int32 id, bool include_bank = false);
Item* GetItemFromIndex(int32 index);
void MoveItem(Item* item, sint32 inv_slot, int16 slot, bool erase_old = true);
bool MoveItem(sint32 to_bag_id, int16 from_index, sint8 to, int8 charges);
Item* GetItemFromUniqueID(int32 item_id, bool include_bank = false, bool lock = true);
Item* GetItemFromID(int32 item_id, int8 count = 0, bool include_bank = false, bool lock = true);
bool AssignItemToFreeSlot(Item* item);
int16 GetNumberOfFreeSlots();
int16 GetNumberOfItems();
bool HasFreeSlot();
bool HasFreeBagSlot();
void DestroyItem(int16 index);
Item* CanStack(Item* item, bool include_bank = false);
void RemoveItem(Item* item, bool delete_item = false);
void AddItem(Item* item);
Item* GetItem(sint32 bag_slot, int16 slot);
EQ2Packet* serialize(Player* player, int16 version);
uchar* xor_packet;
uchar* orig_packet;
map<int32, Item*>* GetAllItems();
bool HasFreeBankSlot();
int8 FindFreeBankSlot();
///<summary>Get the first free slot and stor them in the provided variables</summary>
///<param name='bag_id'>Will contain the bag id of the first free spot</param>
///<param name='slot'>Will contain the slot id of the first free slot</param>
///<returns>True if a free slot was found</returns>
bool GetFirstFreeSlot(sint32* bag_id, sint16* slot);
private:
void Stack(Item* orig_item, Item* item);
Mutex MPlayerItems;
int16 packet_count;
};
class OverFlowItemList : public PlayerItemList {
public:
bool OverFlowSlotFull();
int8 GetNextOverFlowSlot();
bool AddItem(Item* item);
Item* GetOverFlowItem();
};
class EquipmentItemList{
public:
EquipmentItemList();
EquipmentItemList(const EquipmentItemList& list);
~EquipmentItemList();
Item* items[NUM_SLOTS];
vector<Item*>* GetAllEquippedItems();
bool HasItem(int32 id);
int8 GetNumberOfItems();
Item* GetItemFromUniqueID(int32 item_id);
Item* GetItemFromItemID(int32 item_id);
void SetItem(int8 slot_id, Item* item);
void RemoveItem(int8 slot, bool delete_item = false);
Item* GetItem(int8 slot_id);
bool AddItem(int8 slot, Item* item);
bool CheckEquipSlot(Item* tmp, int8 slot);
bool CanItemBeEquippedInSlot(Item* tmp, int8 slot);
int8 GetFreeSlot(Item* tmp, int8 slot_id = 255);
ItemStatsValues* CalculateEquipmentBonuses(Entity* entity = 0);
EQ2Packet* serialize(int16 version);
uchar* xor_packet;
uchar* orig_packet;
private:
Mutex MEquipmentItems;
};
#endif

View File

@ -0,0 +1,211 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
//Item Stat defines for ToV Client
//Stat type 6 (blue stats)
#define TOV_ITEM_STAT_HPREGEN 600
#define TOV_ITEM_STAT_MANAREGEN 601
#define TOV_ITEM_STAT_HPREGENPPT 602
#define TOV_ITEM_STAT_MPREGENPPT 603
#define TOV_ITEM_STAT_COMBATHPREGENPPT 604
#define TOV_ITEM_STAT_COMBATMPREGENPPT 605
#define TOV_ITEM_STAT_MAXHP 606
#define TOV_ITEM_STAT_MAXHPPERC 607
#define TOV_ITEM_STAT_MAXHPPERCFINAL 608
#define TOV_ITEM_STAT_SPEED 609
#define TOV_ITEM_STAT_SLOW 610
#define TOV_ITEM_STAT_MOUNTSPEED 611
#define TOV_ITEM_STAT_MOUNTAIRSPEED 612
#define TOV_ITEM_STAT_LEAPSPEED 613
#define TOV_ITEM_STAT_LEAPTIME 614
#define TOV_ITEM_STAT_GLIDEEFFICIENCY 615
#define TOV_ITEM_STAT_OFFENSIVESPEED 616
#define TOV_ITEM_STAT_ATTACKSPEED 617
#define TOV_ITEM_STAT_MAXMANA 618
#define TOV_ITEM_STAT_MAXMANAPERC 619
#define TOV_ITEM_STAT_MAXATTPERC 620
#define TOV_ITEM_STAT_BLURVISION 621
#define TOV_ITEM_STAT_MAGICLEVELIMMUNITY 622
#define TOV_ITEM_STAT_HATEGAINMOD 623
#define TOV_ITEM_STAT_COMBATEXPMOD 624
#define TOV_ITEM_STAT_TRADESKILLEXPMOD 625
#define TOV_ITEM_STAT_ACHIEVEMENTEXPMOD 626
#define TOV_ITEM_STAT_SIZEMOD 627
#define TOV_ITEM_STAT_DPS 628
#define TOV_ITEM_STAT_STEALTH 629
#define TOV_ITEM_STAT_INVIS 630
#define TOV_ITEM_STAT_SEESTEALTH 631
#define TOV_ITEM_STAT_SEEINVIS 632
#define TOV_ITEM_STAT_EFFECTIVELEVELMOD 633
#define TOV_ITEM_STAT_RIPOSTECHANCE 634
#define TOV_ITEM_STAT_PARRYCHANCE 635
#define TOV_ITEM_STAT_DODGECHANCE 636
#define TOV_ITEM_STAT_AEAUTOATTACKCHANCE 637
#define TOV_ITEM_STAT_MULTIATTACKCHANCE 638 //DOUBLEATTACKCHANCE
#define TOV_ITEM_STAT_SPELLMULTIATTACKCHANCE 639
#define TOV_ITEM_STAT_FLURRY 640
#define TOV_ITEM_STAT_MELEEDAMAGEMULTIPLIER 641
#define TOV_ITEM_STAT_EXTRAHARVESTCHANCE 642
#define TOV_ITEM_STAT_EXTRASHIELDBLOCKCHANCE 643
#define TOV_ITEM_STAT_ITEMHPREGENPPT 644
#define TOV_ITEM_STAT_ITEMPPREGENPPT 645
#define TOV_ITEM_STAT_MELEECRITCHANCE 646
#define TOV_ITEM_STAT_CRITAVOIDANCE 647
#define TOV_ITEM_STAT_BENEFICIALCRITCHANCE 648
#define TOV_ITEM_STAT_CRITBONUS 649
#define TOV_ITEM_STAT_POTENCY 650 //BASEMODIFIER
#define TOV_ITEM_STAT_UNCONSCIOUSHPMOD 651
#define TOV_ITEM_STAT_ABILITYREUSESPEED 652 //SPELLTIMEREUSEPCT
#define TOV_ITEM_STAT_ABILITYRECOVERYSPEED 653 //SPELLTIMERECOVERYPCT
#define TOV_ITEM_STAT_ABILITYCASTINGSPEED 654 //SPELLTIMECASTPCT
#define TOV_ITEM_STAT_SPELLREUSESPEED 655 //SPELLTIMEREUSESPELLONLY
#define TOV_ITEM_STAT_MELEEWEAPONRANGE 656
#define TOV_ITEM_STAT_RANGEDWEAPONRANGE 657
#define TOV_ITEM_STAT_FALLINGDAMAGEREDUCTION 658
#define TOV_ITEM_STAT_RIPOSTEDAMAGE 659
#define TOV_ITEM_STAT_MINIMUMDEFLECTIONCHANCE 660
#define TOV_ITEM_STAT_MOVEMENTWEAVE 661
#define TOV_ITEM_STAT_COMBATHPREGEN 662
#define TOV_ITEM_STAT_COMBATMANAREGEN 663
#define TOV_ITEM_STAT_CONTESTSPEEDBOOST 664
#define TOV_ITEM_STAT_TRACKINGAVOIDANCE 665
#define TOV_ITEM_STAT_STEALTHINVISSPEEDMOD 666
#define TOV_ITEM_STAT_LOOT_COIN 667
#define TOV_ITEM_STAT_ARMORMITIGATIONINCREASE 668
#define TOV_ITEM_STAT_AMMOCONSERVATION 669
#define TOV_ITEM_STAT_STRIKETHROUGH 670
#define TOV_ITEM_STAT_STATUSBONUS 671
#define TOV_ITEM_STAT_ACCURACY 672
#define TOV_ITEM_STAT_COUNTERSTRIKE 673
#define TOV_ITEM_STAT_SHIELDBASH 674
#define TOV_ITEM_STAT_WEAPONDAMAGEBONUS 675
#define TOV_ITEM_STAT_SPELLWEAPONDAMAGEBONUS 676
#define TOV_ITEM_STAT_WEAPONDAMAGEBONUSMELEEONLY 677
#define TOV_ITEM_STAT_ADDITIONALRIPOSTECHANCE 678
#define TOV_ITEM_STAT_PVPTOUGHNESS 680
#define TOV_ITEM_STAT_PVPLETHALITY 681
#define TOV_ITEM_STAT_STAMINABONUS 682
#define TOV_ITEM_STAT_WISDOMMITBONUS 683
#define TOV_ITEM_STAT_HEALRECEIVE 684
#define TOV_ITEM_STAT_HEALRECEIVEPERC 685
#define TOV_ITEM_STAT_PVPCRITICALMITIGATION 686
#define TOV_ITEM_STAT_BASEAVOIDANCEBONUS 687
#define TOV_ITEM_STAT_INCOMBATSAVAGERYREGEN 688
#define TOV_ITEM_STAT_OUTOFCOMBATSAVAGERYREGEN 689
#define TOV_ITEM_STAT_SAVAGERYREGEN 690
#define TOV_ITEM_STAT_SAVAGERYGAINMOD 691
#define TOV_ITEM_STAT_MAXSAVAGERYLEVEL 692
#define TOV_ITEM_STAT_INCOMBATDISSONANCEREGEN 693
#define TOV_ITEM_STAT_OUTOFCOMBATDISSONANCEREGEN 694
#define TOV_ITEM_STAT_DISSONANCEREGEN 695
#define TOV_ITEM_STAT_DISSONANCEGAINMOD 696
#define TOV_ITEM_STAT_AEAUTOATTACKAVOID 697
//End of stat type 6 (blue stats)
//Item stat type 5 (health,power,savagery,dissonance,concentration)
#define TOV_ITEM_STAT_HEALTH 500
#define TOV_ITEM_STAT_POWER 501
#define TOV_ITEM_STAT_CONCENTRATION 502
#define TOV_ITEM_STAT_SAVAGERY 503
#define TOV_ITEM_STAT_DISSONANCE 504
//End of stat type 5
//Item stat type 3 (damage mods)
#define TOV_ITEM_STAT_DMG_SLASH 300
#define TOV_ITEM_STAT_DMG_CRUSH 301
#define TOV_ITEM_STAT_DMG_PIERCE 302
#define TOV_ITEM_STAT_DMG_HEAT 303
#define TOV_ITEM_STAT_DMG_COLD 304
#define TOV_ITEM_STAT_DMG_MAGIC 305
#define TOV_ITEM_STAT_DMG_MENTAL 306
#define TOV_ITEM_STAT_DMG_DIVINE 307
#define TOV_ITEM_STAT_DMG_DISEASE 308
#define TOV_ITEM_STAT_DMG_POISON 309
#define TOV_ITEM_STAT_DMG_DROWNING 310
#define TOV_ITEM_STAT_DMG_FALLING 311
#define TOV_ITEM_STAT_DMG_PAIN 312
#define TOV_ITEM_STAT_DMG_MELEE 313
//End of item stat 3
#define TOV_ITEM_STAT_DEFLECTIONCHANCE 400 //just so no build error
// Other stats not listed above (not sent from the server), never send these to the client
// using type 8 as it is not used by the client as far as we know
#define TOV_ITEM_STAT_DURABILITY_MOD 800
#define TOV_ITEM_STAT_DURABILITY_ADD 801
#define TOV_ITEM_STAT_PROGRESS_ADD 802
#define TOV_ITEM_STAT_PROGRESS_MOD 803
#define TOV_ITEM_STAT_SUCCESS_MOD 804
#define TOV_ITEM_STAT_CRIT_SUCCESS_MOD 805
#define TOV_ITEM_STAT_EX_DURABILITY_MOD 806
#define TOV_ITEM_STAT_EX_DURABILITY_ADD 807
#define TOV_ITEM_STAT_EX_PROGRESS_MOD 808
#define TOV_ITEM_STAT_EX_PROGRESS_ADD 809
#define TOV_ITEM_STAT_EX_SUCCESS_MOD 810
#define TOV_ITEM_STAT_EX_CRIT_SUCCESS_MOD 811
#define TOV_ITEM_STAT_EX_CRIT_FAILURE_MOD 812
#define TOV_ITEM_STAT_RARE_HARVEST_CHANCE 813
#define TOV_ITEM_STAT_MAX_CRAFTING 814
#define TOV_ITEM_STAT_COMPONENT_REFUND 815
#define TOV_ITEM_STAT_BOUNTIFUL_HARVEST 816
#define TOV_ITEM_STAT_STR 0
#define TOV_ITEM_STAT_STA 1
#define TOV_ITEM_STAT_AGI 2
#define TOV_ITEM_STAT_WIS 3
#define TOV_ITEM_STAT_INT 4
#define TOV_ITEM_STAT_ADORNING 100
#define TOV_ITEM_STAT_AGGRESSION 101
#define TOV_ITEM_STAT_ARTIFICING 102
#define TOV_ITEM_STAT_ARTISTRY 103
#define TOV_ITEM_STAT_CHEMISTRY 104
#define TOV_ITEM_STAT_CRUSHING 105
#define TOV_ITEM_STAT_DEFENSE 106
#define TOV_ITEM_STAT_DEFLECTION 107
#define TOV_ITEM_STAT_DISRUPTION 108
#define TOV_ITEM_STAT_FISHING 109
#define TOV_ITEM_STAT_FLETCHING 110
#define TOV_ITEM_STAT_FOCUS 111
#define TOV_ITEM_STAT_FORESTING 112
#define TOV_ITEM_STAT_GATHERING 113
#define TOV_ITEM_STAT_METAL_SHAPING 114
#define TOV_ITEM_STAT_METALWORKING 115
#define TOV_ITEM_STAT_MINING 116
#define TOV_ITEM_STAT_MINISTRATION 117
#define TOV_ITEM_STAT_ORDINATION 118
#define TOV_ITEM_STAT_PARRY 119
#define TOV_ITEM_STAT_PIERCING 120
#define TOV_ITEM_STAT_RANGED 121
#define TOV_ITEM_STAT_SAFE_FALL 122
#define TOV_ITEM_STAT_SCRIBING 123
#define TOV_ITEM_STAT_SCULPTING 124
#define TOV_ITEM_STAT_SLASHING 125
#define TOV_ITEM_STAT_SUBJUGATION 126
#define TOV_ITEM_STAT_SWIMMING 127
#define TOV_ITEM_STAT_TAILORING 128
#define TOV_ITEM_STAT_TINKERING 129
#define TOV_ITEM_STAT_TRANSMUTING 130
#define TOV_ITEM_STAT_TRAPPING 131
#define TOV_ITEM_STAT_WEAPON_SKILLS 132

View File

@ -0,0 +1,134 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Loot.h"
#include "../client.h"
#include "../../common/ConfigReader.h"
#include "../classes.h"
#include "../../common/debug.h"
#include "../zoneserver.h"
#include "../Skills.h"
#include "../classes.h"
#include "../World.h"
#include "../LuaInterface.h"
#include "../../common/Log.h"
#include "../Entity.h"
#include "../Rules/Rules.h"
extern Classes classes;
extern ConfigReader configReader;
extern MasterSkillList master_skill_list;
extern RuleManager rule_manager;
// If we want to transfer functions to this file then we should just do it, but for now we don't need all this commented code here
NPC* Entity::DropChest() {
// Check to see if treasure chests are disabled in the rules
if (rule_manager.GetGlobalRule(R_World, TreasureChestDisabled)->GetBool())
return 0;
if(GetChestDropTime()) {
return 0; // this is a chest! It doesn't drop itself!
}
NPC* chest = 0;
chest = new NPC();
chest->SetAttackable(0);
chest->SetShowLevel(0);
chest->SetShowName(1);
chest->SetTargetable(1);
chest->SetLevel(GetLevel());
chest->SetChestDropTime();
chest->SetTotalHP(100);
chest->SetHP(100);
chest->SetAlive(false);
// Set the brain to a blank brain so it does nothing
chest->SetBrain(new BlankBrain(chest));
// Set the x, y, z, heading, location (grid id) to that of the dead spawn
chest->SetZone(GetZone());
// heading needs to be GetHeading() - 180 so the chest faces the proper way
chest->SetHeading(GetHeading() - 180);
// Set the primary command to loot and the secondary to disarm
chest->AddPrimaryEntityCommand("loot", rule_manager.GetGlobalRule(R_Loot, LootRadius)->GetFloat(), "loot", "", 0, 0);
chest->AddSecondaryEntityCommand("Disarm", rule_manager.GetGlobalRule(R_Loot, LootRadius)->GetFloat(), "Disarm", "", 0, 0);
// 32 = loot icon for the mouse
chest->SetIcon(32);
// 1 = show the right click menu
chest->SetShowCommandIcon(1);
chest->SetLootMethod(this->GetLootMethod(), this->GetLootRarity(), this->GetLootGroupID());
chest->SetLootName(this->GetName());
int8 highest_tier = 0;
vector<Item*>::iterator itr;
for (itr = ((Spawn*)this)->GetLootItems()->begin(); itr != ((Spawn*)this)->GetLootItems()->end(); ) {
if ((*itr)->details.tier >= ITEM_TAG_COMMON && !(*itr)->IsBodyDrop()) {
if ((*itr)->details.tier > highest_tier)
highest_tier = (*itr)->details.tier;
// Add the item to the chest
chest->AddLootItem((*itr)->details.item_id, (*itr)->details.count);
// Remove the item from the corpse
itr = ((Spawn*)this)->GetLootItems()->erase(itr);
}
else
itr++;
}
/*4034 = small chest | 5864 = treasure chest | 5865 = ornate treasure chest | 4015 = exquisite chest*/
if (highest_tier >= ITEM_TAG_FABLED) {
chest->SetModelType(4015);
chest->SetName("Exquisite Chest");
}
else if (highest_tier >= ITEM_TAG_LEGENDARY) {
chest->SetModelType(5865);
chest->SetName("Ornate Chest");
}
else if (highest_tier >= ITEM_TAG_TREASURED) {
chest->SetModelType(5864);
chest->SetName("Treasure Chest");
}
else if (highest_tier >= ITEM_TAG_COMMON) {
chest->SetModelType(4034);
chest->SetName("Small Chest");
}
else {
safe_delete(chest);
chest = nullptr;
}
if (chest) {
chest->SetID(Spawn::NextID());
chest->SetShowHandIcon(1);
chest->SetLocation(GetLocation());
chest->SetX(GetX());
chest->SetZ(GetZ());
((Entity*)chest)->GetInfoStruct()->set_flying_type(false);
chest->is_flying_creature = false;
if(GetMap()) {
auto loc = glm::vec3(GetX(), GetZ(), GetY());
float new_z = FindBestZ(loc, nullptr);
chest->appearance.pos.Y = new_z; // don't use SetY here can cause a loop
}
else {
chest->appearance.pos.Y = GetY();
}
}
return chest;
}

View File

@ -0,0 +1,23 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __EQ2_LOOT__
#define __EQ2_LOOT__
#endif

View File

@ -0,0 +1,210 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../../common/Log.h"
#include "../WorldDatabase.h"
#include "../World.h"
extern World world;
void WorldDatabase::LoadLoot(ZoneServer* zone)
{
// First, clear previous loot tables...
zone->ClearLootTables();
DatabaseResult result;
int32 count = 0;
if (database_new.Select(&result, "SELECT id, name, mincoin, maxcoin, maxlootitems, lootdrop_probability, coin_probability FROM loottable")) {
LogWrite(LOOT__DEBUG, 0, "Loot", "--Loading LootTables...");
LootTable* table = 0;
// Load loottable from DB
while(result.Next()) {
int32 id = result.GetInt32Str("id");
table = new LootTable;
table->name = result.GetStringStr("name");
table->mincoin = result.GetInt32Str("mincoin");
table->maxcoin = result.GetInt32Str("maxcoin");
table->maxlootitems = result.GetInt16Str("maxlootitems");
table->lootdrop_probability = result.GetFloatStr("lootdrop_probability");
table->coin_probability = result.GetFloatStr("coin_probability");
zone->AddLootTable(id, table);
LogWrite(LOOT__DEBUG, 5, "Loot", "---Loading LootTable '%s' (id: %u)", table->name.c_str(), id);
LogWrite(LOOT__DEBUG, 5, "Loot", "---min_coin: %u, max_coin: %u, max_items: %i, prob: %.2f, coin_prob: %.2f", table->mincoin, table->maxcoin, table->maxlootitems, table->lootdrop_probability, table->coin_probability);
count++;
}
LogWrite(LOOT__DEBUG, 0, "Loot", "--Loaded %u loot table%s.", count, count == 1 ? "" : "s");
}
// Now, load Loot Drops for configured loot tables
if (database_new.Select(&result, "SELECT loot_table_id, item_id, item_charges, equip_item, probability, no_drop_quest_completed FROM lootdrop")) {
count = 0;
LogWrite(LOOT__DEBUG, 0, "Loot", "--Loading LootDrops...");
LootDrop* drop = 0;
while(result.Next()) {
int32 id = result.GetInt32Str("loot_table_id");
drop = new LootDrop;
drop->item_id = result.GetInt32Str("item_id");
drop->item_charges = result.GetInt16Str("item_charges");
drop->equip_item = (result.GetInt8Str("equip_item") == 1);
drop->probability = result.GetFloatStr("probability");
drop->no_drop_quest_completed_id = result.GetInt32Str("no_drop_quest_completed");
zone->AddLootDrop(id, drop);
LogWrite(LOOT__DEBUG, 5, "Loot", "---Loading LootDrop item_id %u (tableID: %u", drop->item_id, id);
LogWrite(LOOT__DEBUG, 5, "Loot", "---charges: %i, equip_item: %i, prob: %.2f", drop->item_charges, drop->equip_item, drop->probability);
count++;
}
LogWrite(LOOT__DEBUG, 0, "Loot", "--Loaded %u loot drop%s.", count, count == 1 ? "" : "s");
}
// Finally, load loot tables into spawns that are set to use these loot tables
if (database_new.Select(&result, "SELECT spawn_id, loottable_id FROM spawn_loot")) {
count = 0;
LogWrite(LOOT__DEBUG, 0, "Loot", "--Assigning loot table(s) to spawn(s)...");
while(result.Next()) {
int32 spawn_id = result.GetInt32Str("spawn_id");
int32 table_id = result.GetInt32Str("loottable_id");
zone->AddSpawnLootList(spawn_id, table_id);
LogWrite(LOOT__DEBUG, 5, "Loot", "---Adding loot table %u to spawn %u", table_id, spawn_id);
count++;
}
LogWrite(LOOT__DEBUG, 0, "Loot", "--Loaded %u spawn loot list%s.", count, count == 1 ? "" : "s");
}
// Load global loot lists
LoadGlobalLoot(zone);
}
void WorldDatabase::LoadGlobalLoot(ZoneServer* zone) {
LogWrite(LOOT__INFO, 0, "Loot", "-Loading Global loot data...");
DatabaseResult result;
int32 count = 0;
if (database_new.Select(&result, "SELECT type, loot_table, value1, value2, value3, value4 FROM loot_global")) {
while(result.Next()) {
const char* type = result.GetStringStr("type");
int32 table_id = result.GetInt32Str("loot_table");
if (strcmp(type, "Level") == 0) {
GlobalLoot* loot = new GlobalLoot();
loot->minLevel = result.GetInt8Str("value1");
loot->maxLevel = result.GetInt8Str("value2");
loot->table_id = table_id;
loot->loot_tier = result.GetInt32Str("value4");
if (loot->minLevel > loot->maxLevel)
loot->maxLevel = loot->minLevel;
zone->AddLevelLootList(loot);
LogWrite(LOOT__DEBUG, 5, "Loot", "---Loading Level %i loot table (id: %u)", loot->minLevel, table_id);
LogWrite(LOOT__DEBUG, 5, "Loot", "---minlevel: %i, maxlevel: %i", loot->minLevel, loot->maxLevel);
}
else if (strcmp(type, "Racial") == 0) {
GlobalLoot* loot = new GlobalLoot();
int16 race_id = result.GetInt16Str("value1");
loot->minLevel = result.GetInt8Str("value2");
loot->maxLevel = result.GetInt8Str("value3");
loot->table_id = table_id;
loot->loot_tier = result.GetInt32Str("value4");
if (loot->minLevel > loot->maxLevel)
loot->maxLevel = loot->minLevel;
zone->AddRacialLootList(race_id, loot);
LogWrite(LOOT__DEBUG, 5, "Loot", "---Loading Racial %i loot table (id: %u)", race_id, table_id);
LogWrite(LOOT__DEBUG, 5, "Loot", "---minlevel: %i, maxlevel: %i", loot->minLevel, loot->maxLevel);
}
else if (strcmp(type, "Zone") == 0) {
GlobalLoot* loot = new GlobalLoot();
int32 zoneID = result.GetInt32Str("value1");
loot->minLevel = result.GetInt8Str("value2");
loot->maxLevel = result.GetInt8Str("value3");
loot->table_id = table_id;
loot->loot_tier = result.GetInt32Str("value4");
if (loot->minLevel > loot->maxLevel)
loot->maxLevel = loot->minLevel;
zone->AddZoneLootList(zoneID, loot);
LogWrite(LOOT__DEBUG, 5, "Loot", "---Loading Zone %i loot table (id: %u)", zoneID, table_id);
LogWrite(LOOT__DEBUG, 5, "Loot", "---minlevel: %i, maxlevel: %i", loot->minLevel, loot->maxLevel);
}
count++;
}
LogWrite(LOOT__DEBUG, 0, "Loot", "--Loaded %u Global loot list%s.", count, count == 1 ? "" : "s");
}
}
bool WorldDatabase::LoadSpawnLoot(ZoneServer* zone, Spawn* spawn)
{
if (!spawn->GetDatabaseID())
return false;
DatabaseResult result;
int32 count = 0;
zone->ClearSpawnLootList(spawn->GetDatabaseID());
// Finally, load loot tables into spawns that are set to use these loot tables
if (database_new.Select(&result, "SELECT spawn_id, loottable_id FROM spawn_loot where spawn_id=%u",spawn->GetDatabaseID())) {
count = 0;
LogWrite(LOOT__DEBUG, 0, "Loot", "--Assigning loot table(s) to spawn(s)...");
while (result.Next()) {
int32 spawn_id = result.GetInt32Str("spawn_id");
int32 table_id = result.GetInt32Str("loottable_id");
zone->AddSpawnLootList(spawn_id, table_id);
LogWrite(LOOT__DEBUG, 5, "Loot", "---Adding loot table %u to spawn %u", table_id, spawn_id);
count++;
}
LogWrite(LOOT__DEBUG, 0, "Loot", "--Loaded %u spawn loot list%s.", count, count == 1 ? "" : "s");
return true;
}
return false;
}
void WorldDatabase::AddLootTableToSpawn(Spawn* spawn, int32 loottable_id) {
Query query;
query.RunQuery2(Q_INSERT, "insert into spawn_loot set spawn_id=%u,loottable_id=%u", spawn->GetDatabaseID(), loottable_id);
}
bool WorldDatabase::RemoveSpawnLootTable(Spawn* spawn, int32 loottable_id) {
Query query;
if (loottable_id)
{
string delete_char = string("delete from spawn_loot where spawn_id=%i and loottable_id=%i");
query.RunQuery2(Q_DELETE, delete_char.c_str(), spawn->GetDatabaseID(), loottable_id);
}
else
{
string delete_char = string("delete from spawn_loot where spawn_id=%i");
query.RunQuery2(Q_DELETE, delete_char.c_str(), spawn->GetDatabaseID());
}
if (!query.GetAffectedRows())
{
//No error just in case ppl try doing stupid stuff
return false;
}
return true;
}

View File

@ -0,0 +1,153 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <string.h>
#include "Languages.h"
Language::Language(){
id = 0;
memset(name, 0, sizeof(name));
save_needed = false;
}
Language::Language(Language* language){
id = language->id;
strncpy(name, language->GetName(), sizeof(name));
save_needed = language->save_needed;
}
MasterLanguagesList::MasterLanguagesList(){
}
MasterLanguagesList::~MasterLanguagesList(){
Clear();
}
// don't bother calling this beyond its deconstructor its not thread-safe
void MasterLanguagesList::Clear(){
list<Language*>::iterator itr;
Language* language = 0;
for(itr = languages_list.begin(); itr != languages_list.end(); itr++){
language = *itr;
safe_delete(language);
}
languages_list.clear();
}
int32 MasterLanguagesList::Size(){
return languages_list.size();
}
void MasterLanguagesList::AddLanguage(Language* language){
assert(language);
languages_list.push_back(language);
}
Language* MasterLanguagesList::GetLanguage(int32 id){
list<Language*>::iterator itr;
Language* language = 0;
Language* ret = 0;
for(itr = languages_list.begin(); itr != languages_list.end(); itr++){
language = *itr;
if(language->GetID() == id){
ret = language;
break;
}
}
return ret;
}
Language* MasterLanguagesList::GetLanguageByName(const char* name){
list<Language*>::iterator itr;
Language* language = 0;
Language* ret = 0;
for(itr = languages_list.begin(); itr != languages_list.end(); itr++){
language = *itr;
if(!language)
continue;
if(!strncmp(language->GetName(), name, strlen(name))){
ret = language;
break;
}
}
return ret;
}
list<Language*>* MasterLanguagesList::GetAllLanguages(){
return &languages_list;
}
PlayerLanguagesList::PlayerLanguagesList(){
}
PlayerLanguagesList::~PlayerLanguagesList(){
}
void PlayerLanguagesList::Clear() {
list<Language*>::iterator itr;
Language* language = 0;
Language* ret = 0;
for(itr = player_languages_list.begin(); itr != player_languages_list.end(); itr++){
language = *itr;
safe_delete(language);
}
player_languages_list.clear();
}
void PlayerLanguagesList::Add(Language* language){
player_languages_list.push_back(language);
}
Language* PlayerLanguagesList::GetLanguage(int32 id){
list<Language*>::iterator itr;
Language* language = 0;
Language* ret = 0;
for(itr = player_languages_list.begin(); itr != player_languages_list.end(); itr++){
language = *itr;
if(language->GetID() == id){
ret = language;
break;
}
}
return ret;
}
Language* PlayerLanguagesList::GetLanguageByName(const char* name){
list<Language*>::iterator itr;
Language* language = 0;
Language* ret = 0;
for(itr = player_languages_list.begin(); itr != player_languages_list.end(); itr++){
language = *itr;
if(!language)
continue;
if(!strncmp(language->GetName(), name, strlen(name))){
ret = language;
break;
}
}
return ret;
}
list<Language*>* PlayerLanguagesList::GetAllLanguages(){
return &player_languages_list;
}

View File

@ -0,0 +1,76 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LANGUAGES_H_
#define LANGUAGES_H_
#include <string>
#include <list>
#include "../common/types.h"
using namespace std;
class Language {
public:
Language();
Language(Language* language);
void SetID(int32 id) {this->id = id;}
void SetName(const char *name) {strncpy(this->name, name, sizeof(this->name));}
void SetSaveNeeded(bool save_needed) {this->save_needed = save_needed;}
int32 GetID() {return id;}
const char* GetName() {return name;}
bool GetSaveNeeded() {return save_needed;}
private:
int32 id;
char name[50];
bool save_needed;
};
class MasterLanguagesList {
public:
MasterLanguagesList();
~MasterLanguagesList();
void Clear();
int32 Size();
void AddLanguage(Language* language);
Language* GetLanguage(int32 id);
Language* GetLanguageByName(const char* name);
list<Language*>* GetAllLanguages();
private:
list<Language*> languages_list;
};
class PlayerLanguagesList {
public:
PlayerLanguagesList();
~PlayerLanguagesList();
void Clear();
void Add(Language* language);
Language* GetLanguage(int32 id);
Language* GetLanguageByName(const char* name);
list<Language*>* GetAllLanguages();
private:
list<Language*> player_languages_list;
};
#endif

View File

@ -0,0 +1,667 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../common/debug.h"
#include "../common/Log.h"
#include <iostream>
using namespace std;
#include <string.h>
#include <stdio.h>
#include <iomanip>
using namespace std;
#include <stdlib.h>
#include "../common/version.h"
#include "../common/GlobalHeaders.h"
#include "../common/sha512.h"
#ifdef WIN32
#include <process.h>
#include <WinSock2.h>
#include <Ws2tcpip.h>
#include <windows.h>
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#else // Pyro: fix for linux
#include <sys/socket.h>
#ifdef FREEBSD //Timothy Whitman - January 7, 2003
#include <sys/types.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include "../common/unix.h"
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1
extern int errno;
#endif
#include "../common/servertalk.h"
#include "LoginServer.h"
#include "../common/packet_dump.h"
#include "net.h"
#include "zoneserver.h"
#include "WorldDatabase.h"
#include "Variables.h"
#include "World.h"
#include "../common/ConfigReader.h"
#include "Rules/Rules.h"
extern sint32 numzones;
extern sint32 numclients;
extern NetConnection net;
extern LoginServer loginserver;
extern WorldDatabase database;
extern ZoneAuth zone_auth;
extern Variables variables;
extern ZoneList zone_list;
extern ClientList client_list;
extern volatile bool RunLoops;
volatile bool LoginLoopRunning = false;
extern ConfigReader configReader;
extern RuleManager rule_manager;
bool AttemptingConnect = false;
LoginServer::LoginServer(const char* iAddress, int16 iPort) {
LoginServerIP = ResolveIP(iAddress);
LoginServerPort = iPort;
statusupdate_timer = new Timer(LoginServer_StatusUpdateInterval);
tcpc = new TCPConnection(false);
pTryReconnect = true;
minLockedStatus = 100;
maxPlayers = -1;
minGameFullStatus = 100;
last_checked_time = 0;
zone_updates = 0;
loginEquip_updates = 0;
}
LoginServer::~LoginServer() {
delete statusupdate_timer;
delete tcpc;
}
void LoginServer::SendImmediateEquipmentUpdatesForChar(int32 char_id) {
LogWrite(WORLD__DEBUG, 5, "World", "Sending login equipment updates for char_id: %u", char_id);
int16 count = 0;
if(!loginEquip_updates)
loginEquip_updates = database.GetEquipmentUpdates(char_id);
if(loginEquip_updates && loginEquip_updates->size() > 0)
{
map<int32, LoginEquipmentUpdate> send_map;
int32 size = 0;
MutexMap<int32, LoginEquipmentUpdate>::iterator itr = loginEquip_updates->begin();
while(itr.Next())
{
send_map[itr->first] = itr->second;
size += sizeof(EquipmentUpdate_Struct);
loginEquip_updates->erase(itr->first);
count++;
}
ServerPacket* outpack = new ServerPacket(ServerOP_LoginEquipment, size + sizeof(EquipmentUpdateList_Struct)+5);
EquipmentUpdateList_Struct* updates = (EquipmentUpdateList_Struct*)outpack->pBuffer;
updates->total_updates = count;
int32 pos = sizeof(EquipmentUpdateList_Struct);
map<int32, LoginEquipmentUpdate>::iterator send_itr;
for(send_itr = send_map.begin(); send_itr != send_map.end(); send_itr++)
{
EquipmentUpdate_Struct* update = (EquipmentUpdate_Struct*)(outpack->pBuffer + pos);
update->id = send_itr->first;
update->world_char_id = send_itr->second.world_char_id;
update->equip_type = send_itr->second.equip_type;
update->red = send_itr->second.red;
update->green = send_itr->second.green;
update->blue = send_itr->second.blue;
update->highlight_red = send_itr->second.red;
update->highlight_green = send_itr->second.green;
update->highlight_blue = send_itr->second.blue;
update->slot = send_itr->second.slot;
pos += sizeof(EquipmentUpdate_Struct);
}
SendPacket(outpack);
outpack->Deflate();
safe_delete(outpack);
}
if(loginEquip_updates && count)
loginEquip_updates->clear();
if(loginEquip_updates && loginEquip_updates->size() == 0)
{
database.UpdateLoginEquipment();
safe_delete(loginEquip_updates);
}
}
bool LoginServer::Process() {
if(last_checked_time > Timer::GetCurrentTime2())
return true;
last_checked_time = Timer::GetCurrentTime2() + 50;
bool ret = true;
if (statusupdate_timer->Check()) {
this->SendStatus();
}
/************ Get all packets from packet manager out queue and process them ************/
ServerPacket *pack = 0;
while((pack = tcpc->PopPacket()))
{
switch(pack->opcode)
{
case ServerOP_LSFatalError:
{
LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): ServerOP_LSFatalError", pack->opcode, pack->opcode);
LogWrite(WORLD__ERROR, 0, "World", "Login Server returned a fatal error: %s\n", pack->pBuffer);
tcpc->Disconnect();
ret = false;
net.ReadLoginINI();
break;
}
case ServerOP_CharTimeStamp:
{
LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): ServerOP_CharTimeStamp", pack->opcode, pack->opcode);
if(pack->size != sizeof(CharacterTimeStamp_Struct))
break;
CharacterTimeStamp_Struct* cts = (CharacterTimeStamp_Struct*) pack->pBuffer;
// determine if the character exists and retrieve its latest timestamp from the world server
bool char_exist = false;
//int32 character_timestamp = database.GetCharacterTimeStamp(cts->char_id,cts->account_id,&char_exist);
if(!char_exist)
{
//Character doesn't exist, get rid of it
SendDeleteCharacter ( cts );
break;
}
break;
}
// Push Character Select "item appearances" to login_equipment table
case ServerOP_LoginEquipment:{
LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): ServerOP_LoginEquipment", pack->opcode, pack->opcode);
LogWrite(MISC__TODO, 0, "TODO", "Implement map<character id <map<slot id, updatestruct> > method to update Login.\n%s, %s, %i", __FILE__, __FUNCTION__, __LINE__);
if( pack->size == sizeof(EquipmentUpdateRequest_Struct) )
{
int16 max = ((EquipmentUpdateRequest_Struct*)pack->pBuffer)->max_per_batch;
int16 count = 0;
if(!loginEquip_updates)
loginEquip_updates = database.GetEquipmentUpdates();
if(loginEquip_updates && loginEquip_updates->size() > 0)
{
map<int32, LoginEquipmentUpdate> send_map;
int32 size = 0;
MutexMap<int32, LoginEquipmentUpdate>::iterator itr = loginEquip_updates->begin();
while(itr.Next() && count < max)
{
send_map[itr->first] = itr->second;
size += sizeof(EquipmentUpdate_Struct);
loginEquip_updates->erase(itr->first);
count++;
}
ServerPacket* outpack = new ServerPacket(ServerOP_LoginEquipment, size + sizeof(EquipmentUpdateList_Struct)+5);
EquipmentUpdateList_Struct* updates = (EquipmentUpdateList_Struct*)outpack->pBuffer;
updates->total_updates = count;
int32 pos = sizeof(EquipmentUpdateList_Struct);
map<int32, LoginEquipmentUpdate>::iterator send_itr;
for(send_itr = send_map.begin(); send_itr != send_map.end(); send_itr++)
{
EquipmentUpdate_Struct* update = (EquipmentUpdate_Struct*)(outpack->pBuffer + pos);
update->id = send_itr->first;
update->world_char_id = send_itr->second.world_char_id;
update->equip_type = send_itr->second.equip_type;
update->red = send_itr->second.red;
update->green = send_itr->second.green;
update->blue = send_itr->second.blue;
update->highlight_red = send_itr->second.red;
update->highlight_green = send_itr->second.green;
update->highlight_blue = send_itr->second.blue;
update->slot = send_itr->second.slot;
pos += sizeof(EquipmentUpdate_Struct);
}
SendPacket(outpack);
outpack->Deflate();
safe_delete(outpack);
}
if(loginEquip_updates && count < max)
loginEquip_updates->clear();
if(loginEquip_updates && loginEquip_updates->size() == 0)
{
database.UpdateLoginEquipment();
safe_delete(loginEquip_updates);
}
}
break;
}
case ServerOP_ZoneUpdates:{
LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): ServerOP_ZoneUpdates", pack->opcode, pack->opcode);
if(pack->size == sizeof(ZoneUpdateRequest_Struct)){
int16 max = ((ZoneUpdateRequest_Struct*)pack->pBuffer)->max_per_batch;
int16 count = 0;
if(!zone_updates)
zone_updates = database.GetZoneUpdates();
if(zone_updates && zone_updates->size() > 0){
map<int32, LoginZoneUpdate> send_map;
int32 size = 0;
MutexMap<int32, LoginZoneUpdate>::iterator itr = zone_updates->begin();
while(itr.Next() && count < max){
send_map[itr->first] = itr->second;
size += sizeof(ZoneUpdate_Struct) + itr->second.name.length() + itr->second.description.length();
zone_updates->erase(itr->first);
count++;
}
ServerPacket* outpack = new ServerPacket(ServerOP_ZoneUpdates, size + sizeof(ZoneUpdateList_Struct)+5);
ZoneUpdateList_Struct* updates = (ZoneUpdateList_Struct*)outpack->pBuffer;
updates->total_updates = count;
int32 pos = sizeof(ZoneUpdateList_Struct);
map<int32, LoginZoneUpdate>::iterator send_itr;
for(send_itr = send_map.begin(); send_itr != send_map.end(); send_itr++){
ZoneUpdate_Struct* update = (ZoneUpdate_Struct*)(outpack->pBuffer + pos);
update->zone_id = send_itr->first;
update->zone_name_length = send_itr->second.name.length();
update->zone_desc_length = send_itr->second.description.length();
strcpy(update->data, send_itr->second.name.c_str());
strcpy(update->data + send_itr->second.name.length(), send_itr->second.description.c_str());
pos += sizeof(ZoneUpdate_Struct) + send_itr->second.name.length() + send_itr->second.description.length();
}
SendPacket(outpack);
outpack->Deflate();
safe_delete(outpack);
}
if(zone_updates && count < max)
zone_updates->clear();
if(zone_updates && zone_updates->size() == 0){
database.UpdateLoginZones();
safe_delete(zone_updates);
}
}
break;
}
case ServerOP_CharacterCreate:{
LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): ServerOP_CharacterCreate", pack->opcode, pack->opcode);
int16 version = 1;
if(pack->pBuffer[0] > 0)
memcpy(&version, pack->pBuffer, sizeof(int16));
//DumpPacket(pack->pBuffer,pack->size);
PacketStruct* packet = configReader.getStruct("CreateCharacter", version);
int8 resp = 0;
int32 acct_id = 0;
int32 char_id = 0;
if(packet && packet->LoadPacketData(pack->pBuffer+sizeof(int16),pack->size - sizeof(int16), version <= 561 ? false : true)){
EQ2_16BitString name = packet->getType_EQ2_16BitString_ByName("name");
resp = database.CheckNameFilter(name.data.c_str());
acct_id = packet->getType_int32_ByName("account_id");
LogWrite(WORLD__DEBUG, 0, "World", "Response: %i", (int)resp);
sint16 lowestStatus = database.GetLowestCharacterAdminStatus(acct_id);
if(lowestStatus == -2)
resp = UNKNOWNERROR_REPLY2;
else if(resp == CREATESUCCESS_REPLY)
char_id = database.SaveCharacter(packet, acct_id);
}
else{
LogWrite(WORLD__ERROR, 0, "World", "Invalid creation request!");
resp = UNKNOWNERROR_REPLY;
}
// send name filter response data back to the login server
SendFilterNameResponse ( resp , acct_id , char_id );
safe_delete(packet);
break;
}
case ServerOP_BasicCharUpdate: {
LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): ServerOP_BasicCharUpdate", pack->opcode, pack->opcode);
if(pack->size != sizeof(CharDataUpdate_Struct))
break;
CharDataUpdate_Struct* cdu = (CharDataUpdate_Struct*) pack->pBuffer;
switch(cdu->update_field)
{
case DELETE_UPDATE_FLAG:
{
LogWrite(WORLD__DEBUG, 0, "World", "Delete character request: %i %i",cdu->account_id,cdu->char_id );
database.DeleteCharacter(cdu->account_id,cdu->char_id);
break;
}
}
break;
}
case ServerOP_UsertoWorldReq:{
LogWrite(OPCODE__DEBUG, 0, "Opcode", "Opcode 0x%X (%i): ServerOP_UsertoWorldReq", pack->opcode, pack->opcode);
UsertoWorldRequest_Struct* utwr = (UsertoWorldRequest_Struct*) pack->pBuffer;
/*int32 id = database.GetAccountIDFromLSID(utwr->lsaccountid);
sint16 status = database.CheckStatus(id);
*/
int32 access_key = 0;
// if it is a accepted login, we add the zone auth request
access_key = DetermineCharacterLoginRequest ( utwr );
if ( access_key != 0 )
{
zone_auth.PurgeInactiveAuth();
char* characterName = database.GetCharacterName( utwr->char_id );
if(characterName != 0){
ZoneAuthRequest* zar = new ZoneAuthRequest(utwr->lsaccountid,characterName,access_key);
zar->setFirstLogin ( true );
zone_auth.AddAuth(zar);
safe_delete_array(characterName);
}
}
break;
}
case ServerOP_ResetDatabase:{
LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): ServerOP_ResetDatabase", pack->opcode, pack->opcode);
database.ResetDatabase();
break;
}
default:
{
LogWrite(WORLD__ERROR, 0, "World", "Unhandled opcode: %i", pack->opcode);
DumpPacket(pack);
}
}
safe_delete(pack);
// break out if ret is now false
if (!ret)
break;
}
return ret;
}
// this should always be called in a new thread
#ifdef WIN32
void AutoInitLoginServer(void *tmp) {
#else
void *AutoInitLoginServer(void *tmp) {
#endif
if (loginserver.GetState() == TCPS_Ready) {
InitLoginServer();
}
#ifndef WIN32
return 0;
#endif
}
bool InitLoginServer() {
if (loginserver.GetState() != TCPS_Ready) {
LogWrite(WORLD__ERROR, 0, "World", "InitLoginServer() while already attempting connect.");
return false;
}
if (!net.LoginServerInfo) {
LogWrite(WORLD__ERROR, 0, "World", "Login server info not loaded.");
return false;
}
AttemptingConnect = true;
int16 port;
char* address = net.GetLoginInfo(&port);
LogWrite(WORLD__INFO, 0, "World", "InitLoginServer() attempt connect to %s on port %u.", address, port);
loginserver.Connect(address, port);
return true;
}
void LoginServer::InitLoginServerVariables()
{
minLockedStatus = rule_manager.GetGlobalRule(R_World, ServerLockedOverrideStatus)->GetSInt16();
maxPlayers = rule_manager.GetGlobalRule(R_World, MaxPlayers)->GetSInt16();
minGameFullStatus = rule_manager.GetGlobalRule(R_World, MaxPlayersOverrideStatus)->GetSInt16();
}
bool LoginServer::Connect(const char* iAddress, int16 iPort) {
if(!pTryReconnect)
return false;
char errbuf[TCPConnection_ErrorBufferSize];
memset(errbuf, 0, TCPConnection_ErrorBufferSize);
if (iAddress == 0) {
LogWrite(WORLD__ERROR, 0, "World", "LoginServer::Connect: address == 0");
return false;
}
else {
if ((LoginServerIP = ResolveIP(iAddress, errbuf)) == 0) {
LogWrite(WORLD__ERROR, 0, "World", "LoginServer::Connect: Resolving IP address: '%s'", errbuf);
return false;
}
}
if (iPort != 0)
LoginServerPort = iPort;
if (LoginServerIP == 0 || LoginServerPort == 0) {
LogWrite(WORLD__ERROR, 0, "World", "LoginServer::Connect: Connect info incomplete, cannot connect");
return false;
}
if (tcpc->Connect(LoginServerIP, LoginServerPort, errbuf)) {
LogWrite(WORLD__INFO, 0, "World", "Connected to LoginServer: %s: %i", iAddress, LoginServerPort);
SendInfo();
SendStatus();
return true;
}
else {
LogWrite(WORLD__ERROR, 0, "World", "LoginServer::Connect: '%s'", errbuf);
return false;
}
}
void LoginServer::GetLatestTables(){
ServerPacket* pack = new ServerPacket(ServerOP_GetLatestTables, sizeof(GetLatestTables_Struct));
GetLatestTables_Struct* data = (GetLatestTables_Struct*)pack->pBuffer;
data->table_version = CURRENT_DATABASE_MAJORVERSION*100 + CURRENT_DATABASE_MINORVERSION;
data->data_version = CURRENT_DATABASE_MAJORVERSION*100 + CURRENT_DATABASE_MINORVERSION;
SendPacket(pack);
delete pack;
}
void LoginServer::SendInfo() {
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_LSInfo;
pack->size = sizeof(ServerLSInfo_Struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, pack->size);
ServerLSInfo_Struct* lsi = (ServerLSInfo_Struct*) pack->pBuffer;
strcpy(lsi->protocolversion, EQEMU_PROTOCOL_VERSION);
strcpy(lsi->serverversion, CURRENT_VERSION);
strcpy(lsi->name, net.GetWorldName());
strcpy(lsi->account, net.GetWorldAccount());
lsi->dbversion = CURRENT_DATABASE_MAJORVERSION*100 + CURRENT_DATABASE_MINORVERSION;
#ifdef _DEBUG
lsi->servertype = 4;
#endif
string passwdSha512 = sha512(net.GetWorldPassword());
memcpy(lsi->password, (char*)passwdSha512.c_str(), passwdSha512.length());
strcpy(lsi->address, net.GetWorldAddress());
SendPacket(pack);
delete pack;
}
void LoginServer::SendStatus() {
statusupdate_timer->Start();
ServerPacket* pack = new ServerPacket;
pack->opcode = ServerOP_LSStatus;
pack->size = sizeof(ServerLSStatus_Struct);
pack->pBuffer = new uchar[pack->size];
memset(pack->pBuffer, 0, pack->size);
ServerLSStatus_Struct* lss = (ServerLSStatus_Struct*) pack->pBuffer;
if (net.world_locked)
lss->status = -2;
else if(loginserver.maxPlayers > -1 && numclients >= loginserver.maxPlayers)
lss->status = -3;
else
lss->status = 1;
lss->num_zones = numzones;
lss->num_players = numclients;
lss->world_max_level = rule_manager.GetGlobalRule(R_Player, MaxLevel)->GetInt8();
SendPacket(pack);
delete pack;
}
void LoginServer::SendDeleteCharacter ( CharacterTimeStamp_Struct* cts ) {
ServerPacket* outpack = new ServerPacket(ServerOP_BasicCharUpdate, sizeof(CharDataUpdate_Struct));
CharDataUpdate_Struct* cdu = (CharDataUpdate_Struct*)outpack->pBuffer;
cdu->account_id = cts->account_id;
cdu->char_id = cts->char_id;
cdu->update_field = DELETE_UPDATE_FLAG;
cdu->update_data = 1;
SendPacket(outpack);
safe_delete(outpack);
}
void LoginServer::SendFilterNameResponse ( int8 resp, int32 acct_id , int32 char_id ) {
ServerPacket* outpack = new ServerPacket(ServerOP_CharacterCreate, sizeof(WorldCharNameFilterResponse_Struct));
WorldCharNameFilterResponse_Struct* wcfr = (WorldCharNameFilterResponse_Struct*)outpack->pBuffer;
wcfr->response = resp;
wcfr->account_id = acct_id;
wcfr->char_id = char_id;
SendPacket(outpack);
safe_delete(outpack);
}
int32 LoginServer::DetermineCharacterLoginRequest ( UsertoWorldRequest_Struct* utwr ) {
LogWrite(LOGIN__TRACE, 9, "Login", "Enter: %s", __FUNCTION__);
ServerPacket* outpack = new ServerPacket;
outpack->opcode = ServerOP_UsertoWorldResp;
outpack->size = sizeof(UsertoWorldResponse_Struct);
outpack->pBuffer = new uchar[outpack->size];
memset(outpack->pBuffer, 0, outpack->size);
UsertoWorldResponse_Struct* utwrs = (UsertoWorldResponse_Struct*) outpack->pBuffer;
utwrs->lsaccountid = utwr->lsaccountid;
utwrs->char_id = utwr->char_id;
utwrs->ToID = utwr->FromID;
int32 timestamp = Timer::GetUnixTimeStamp();
utwrs->access_key = timestamp;
// set default response to 0
utwrs->response = 0;
sint16 lowestStatus = database.GetLowestCharacterAdminStatus( utwr->lsaccountid );
sint16 status = 0;
if(lowestStatus == -2)
status = -1;
else
status = database.GetCharacterAdminStatus ( utwr->lsaccountid , utwr->char_id );
if(status < 100 && zone_list.ClientConnected(utwr->lsaccountid))
status = -9;
if(status < 0){
LogWrite(WORLD__ERROR, 0, "World", "Login Rejected based on PLAY_ERROR (UserStatus) (MinStatus: %i), UserStatus: %i, CharID: %i",loginserver.minLockedStatus,status,utwr->char_id );
switch(status){
case -10:
utwrs->response = PLAY_ERROR_CHAR_NOT_LOADED;
break;
case -9:
utwrs->response = 0;//PLAY_ERROR_ACCOUNT_IN_USE;
break;
case -8:
utwrs->response = PLAY_ERROR_LOADING_ERROR;
break;
case -1:
utwrs->response = PLAY_ERROR_ACCOUNT_BANNED;
break;
default:
utwrs->response = PLAY_ERROR_PROBLEM;
}
}
else if(net.world_locked == true){
LogWrite(WORLD__INFO, 0, "World", "Login Lock Check (MinStatus: %i):, UserStatus: %i, CharID: %i",loginserver.minLockedStatus,status,utwr->char_id );
// has high enough status, allow it
if(status >= loginserver.minLockedStatus)
utwrs->response = 1;
}
else if(loginserver.maxPlayers > -1 && ((sint16)client_list.Count()) >= loginserver.maxPlayers)
{
LogWrite(WORLD__INFO, 0, "World", "Login GameFull Check (MinStatus: %i):, UserStatus: %i, CharID: %i",loginserver.minGameFullStatus,status,utwr->char_id );
// has high enough status, allow it
if(status >= loginserver.minGameFullStatus)
{
utwrs->response = 1;
}
else
utwrs->response = -3; // server full response is -3
}
else
utwrs->response = 1;
/*sint32 x = database.CommandRequirement("$MAXCLIENTS");
if( (sint32)numplayers >= x && x != -1 && x != 255 && status < 80)
utwrs->response = -3;
if(status == -1)
utwrs->response = -1;
if(status == -2)
utwrs->response = -2;
*/
//printf("Response is %i for %i\n",utwrs->response,id);struct sockaddr_in sa;
int32 ipv4addr = 0;
int result = 0;
#ifdef WIN32
struct sockaddr_in myaddr;
ZeroMemory(&myaddr, sizeof(myaddr));
result = InetPton(AF_INET, utwr->ip_address, &(myaddr.sin_addr));
if(result)
ipv4addr = ntohl(myaddr.sin_addr.s_addr);
#else
result = inet_pton(AF_INET, utwr->ip_address, &ipv4addr);
if(result)
ipv4addr = ntohl(ipv4addr);
#endif
if (((result > 0 && IsPrivateAddress(ipv4addr)) || (strcmp(net.GetWorldAddress(), utwr->ip_address) == 0)) && (strlen(net.GetInternalWorldAddress()) > 0))
strcpy(utwrs->ip_address, net.GetInternalWorldAddress());
else
strcpy(utwrs->ip_address, net.GetWorldAddress());
LogWrite(CCLIENT__INFO, 0, "World", "New client login attempt from %s, providing %s as the world server address.",utwr->ip_address, utwrs->ip_address );
utwrs->port = net.GetWorldPort();
utwrs->worldid = utwr->worldid;
SendPacket(outpack);
delete outpack;
LogWrite(LOGIN__TRACE, 9, "Login", "Exit: %s with timestamp=%u", __FUNCTION__, timestamp);
// depending on the response determined above, this could return 0 (for failure)
return timestamp;
}

View File

@ -0,0 +1,88 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOGINSERVER_H
#define LOGINSERVER_H
#include "../common/servertalk.h"
#include "../common/linked_list.h"
#include "../common/timer.h"
#include "../common/queue.h"
#include "../common/Mutex.h"
#include "../common/TCPConnection.h"
#include <deque>
#include "MutexMap.h"
#ifdef WIN32
void AutoInitLoginServer(void *tmp);
#else
void *AutoInitLoginServer(void *tmp);
#endif
bool InitLoginServer();
class LoginServer{
public:
LoginServer(const char* iAddress = 0, int16 iPort = 5999);
~LoginServer();
bool Process();
bool Connect(const char* iAddress = 0, int16 iPort = 0);
bool ConnectToUpdateServer(const char* iAddress = 0, int16 iPort = 0);
void SendInfo();
void SendStatus();
void GetLatestTables();
void SendPacket(ServerPacket* pack) { tcpc->SendPacket(pack); }
int8 GetState() { return tcpc->GetState(); }
bool Connected() { return tcpc->Connected(); }
void SendFilterNameResponse ( int8 resp , int32 acct_id , int32 char_id );
void SendDeleteCharacter ( CharacterTimeStamp_Struct* cts );
int32 DetermineCharacterLoginRequest ( UsertoWorldRequest_Struct* utwr );
void InitLoginServerVariables();
sint16 minLockedStatus;
sint16 maxPlayers;
sint16 minGameFullStatus;
void SendImmediateEquipmentUpdatesForChar(int32 char_id);
bool CanReconnect() { return pTryReconnect; }
private:
bool try_auto_update;
bool pTryReconnect;
TCPConnection* tcpc;
int32 LoginServerIP;
int32 UpdateServerIP;
int16 LoginServerPort;
uchar* data_waiting;
MutexMap<int32, LoginZoneUpdate>* zone_updates;
MutexMap<int32, LoginEquipmentUpdate>* loginEquip_updates;
int32 last_checked_time;
Timer* statusupdate_timer;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,660 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LUA_FUNCTIONS_H
#define LUA_FUNCTIONS_H
#include "../LUA/lua.hpp"
#include <vector>
#include <string>
#include <map>
using namespace std;
vector<string> ParseString(string strVal, char delim=',');
vector<unsigned int> ParseStringToInt32(string strVal, char delim=',');
map<string, signed int> ParseStringMap(string strVal, char delim=',');
map<unsigned int, unsigned short> ParseIntMap(string strVal, char delim = ',');
map<unsigned int, signed int> ParseSInt32Map(string strVal, char delim = ',');
//Sets
int EQ2Emu_lua_SetCurrentHP(lua_State* state);
int EQ2Emu_lua_SetMaxHP(lua_State* state);
int EQ2Emu_lua_SetMaxHPBase(lua_State* state);
int EQ2Emu_lua_SetCurrentPower(lua_State* state);
int EQ2Emu_lua_SetMaxPower(lua_State* state);
int EQ2Emu_lua_SetMaxPowerBase(lua_State* state);
int EQ2Emu_lua_ModifyMaxHP(lua_State* state);
int EQ2Emu_lua_ModifyMaxPower(lua_State* state);
int EQ2Emu_lua_SetHeading(lua_State* state);
int EQ2Emu_lua_SetModelType(lua_State* state);
int EQ2Emu_lua_SetAdventureClass(lua_State* state);
int EQ2Emu_lua_SetTradeskillClass(lua_State* state);
int EQ2Emu_lua_SetMount(lua_State* state);
int EQ2Emu_lua_SetMountColor(lua_State* state);
int EQ2Emu_lua_SetSpeed(lua_State* state);
int EQ2Emu_lua_SetPosition(lua_State* state);
int EQ2Emu_lua_AddSpellBonus(lua_State* state);
int EQ2Emu_lua_RemoveSpellBonus(lua_State* state);
int EQ2Emu_lua_AddSkillBonus(lua_State* state);
int EQ2Emu_lua_RemoveSkillBonus(lua_State* state);
int EQ2Emu_lua_AddControlEffect(lua_State* state);
int EQ2Emu_lua_RemoveControlEffect(lua_State* state);
int EQ2Emu_lua_HasControlEffect(lua_State* state);
int EQ2Emu_lua_GetBaseAggroRadius(lua_State* state);
int EQ2Emu_lua_GetAggroRadius(lua_State* state);
int EQ2Emu_lua_SetAggroRadius(lua_State* state);
int EQ2Emu_lua_SetDeity(lua_State* state);
int EQ2Emu_lua_GetDeity(lua_State* state);
int EQ2Emu_lua_SetInt(lua_State* state);
int EQ2Emu_lua_SetWis(lua_State* state);
int EQ2Emu_lua_SetSta(lua_State* state);
int EQ2Emu_lua_SetStr(lua_State* state);
int EQ2Emu_lua_SetAgi(lua_State* state);
int EQ2Emu_lua_SetIntBase(lua_State* state);
int EQ2Emu_lua_SetWisBase(lua_State* state);
int EQ2Emu_lua_SetStaBase(lua_State* state);
int EQ2Emu_lua_SetStrBase(lua_State* state);
int EQ2Emu_lua_SetAgiBase(lua_State* state);
int EQ2Emu_lua_SetLootCoin(lua_State* state);
int EQ2Emu_lua_HasCoin(lua_State* state);
int EQ2Emu_lua_SetQuestYellow(lua_State* state);
//Gets
int EQ2Emu_lua_GetLevel(lua_State* state);
int EQ2Emu_lua_GetDifficulty(lua_State* state);
int EQ2Emu_lua_GetCurrentHP(lua_State* state);
int EQ2Emu_lua_GetMaxHP(lua_State* state);
int EQ2Emu_lua_GetMaxHPBase(lua_State* state);
int EQ2Emu_lua_GetCurrentPower(lua_State* state);
int EQ2Emu_lua_GetName(lua_State* state);
int EQ2Emu_lua_GetMaxPower(lua_State* state);
int EQ2Emu_lua_GetMaxPowerBase(lua_State* state);
int EQ2Emu_lua_GetDistance(lua_State* state);
int EQ2Emu_lua_GetX(lua_State* state);
int EQ2Emu_lua_GetY(lua_State* state);
int EQ2Emu_lua_GetZ(lua_State* state);
int EQ2Emu_lua_GetHeading(lua_State* state);
int EQ2Emu_lua_GetModelType(lua_State* state);
int EQ2Emu_lua_GetRace(lua_State* state);
int EQ2Emu_lua_GetRaceName(lua_State* state);
int EQ2Emu_lua_GetMount(lua_State* state);
int EQ2Emu_lua_GetClass(lua_State* state);
int EQ2Emu_lua_GetClassName(lua_State* state);
int EQ2Emu_lua_GetArchetypeName(lua_State* state);
int EQ2Emu_lua_GetSpeed(lua_State* state);
int EQ2Emu_lua_HasMoved(lua_State* state);
int EQ2Emu_lua_GetInt(lua_State* state);
int EQ2Emu_lua_GetWis(lua_State* state);
int EQ2Emu_lua_GetSta(lua_State* state);
int EQ2Emu_lua_GetStr(lua_State* state);
int EQ2Emu_lua_GetAgi(lua_State* state);
int EQ2Emu_lua_GetIntBase(lua_State* state);
int EQ2Emu_lua_GetWisBase(lua_State* state);
int EQ2Emu_lua_GetStaBase(lua_State* state);
int EQ2Emu_lua_GetStrBase(lua_State* state);
int EQ2Emu_lua_GetAgiBase(lua_State* state);
int EQ2Emu_lua_GetLootCoin(lua_State* state);
int EQ2Emu_lua_GetSpawn(lua_State* state);
int EQ2Emu_lua_GetSpawnFromList(lua_State* state);
int EQ2Emu_lua_GetSpawnListSize(lua_State* state);
int EQ2Emu_lua_CreateSpawnList(lua_State* state);
int EQ2Emu_lua_AddSpawnToSpawnList(lua_State* state);
int EQ2Emu_lua_RemoveSpawnFromSpawnList(lua_State* state);
int EQ2Emu_lua_GetSpawnListBySpawnID(lua_State* state);
int EQ2Emu_lua_GetSpawnListByRailID(lua_State* state);
int EQ2Emu_lua_GetPassengerSpawnList(lua_State* state);
int EQ2Emu_lua_GetVariableValue(lua_State* state);
int EQ2Emu_lua_GetCoinMessage(lua_State* state);
int EQ2Emu_lua_GetSpawnByGroupID(lua_State* state);
int EQ2Emu_lua_GetSpawnByLocationID(lua_State* state);
int EQ2Emu_lua_GetSpawnID(lua_State* state);
int EQ2Emu_lua_GetSpawnGroupID(lua_State* state);
int EQ2Emu_lua_SetSpawnGroupID(lua_State* state);
int EQ2Emu_lua_AddSpawnToGroup(lua_State* state);
int EQ2Emu_lua_GetSpawnLocationID(lua_State* state);
int EQ2Emu_lua_GetSpawnLocationPlacementID(lua_State* state);
int EQ2Emu_lua_GetFactionAmount(lua_State* state);
int EQ2Emu_lua_SetFactionID(lua_State* state);
int EQ2Emu_lua_GetFactionID(lua_State* state);
int EQ2Emu_lua_ChangeFaction(lua_State* state);
int EQ2Emu_lua_GetGender(lua_State* state);
int EQ2Emu_lua_GetTarget(lua_State* state);
int EQ2Emu_lua_HasFreeSlot(lua_State* state);
int EQ2Emu_lua_HasItemEquipped(lua_State* state);
int EQ2Emu_lua_GetEquippedItemBySlot(lua_State* state);
int EQ2Emu_lua_GetEquippedItemByID(lua_State* state);
int EQ2Emu_lua_SetEquippedItemByID(lua_State* state);
int EQ2Emu_lua_SetEquippedItem(lua_State* state);
int EQ2Emu_lua_UnequipSlot(lua_State* state);
int EQ2Emu_lua_SetEquipment(lua_State* state);
int EQ2Emu_lua_GetItemByID(lua_State* state);
int EQ2Emu_lua_GetItemType(lua_State* state);
int EQ2Emu_lua_GetItemEffectType(lua_State* state);
int EQ2Emu_lua_GetSpellName(lua_State* state);
//Misc
int EQ2Emu_lua_SetAttackable(lua_State* state);
int EQ2Emu_lua_SendStateCommand(lua_State* state);
int EQ2Emu_lua_SpawnSet(lua_State* state);
int EQ2Emu_lua_KillSpawn(lua_State* state);
int EQ2Emu_lua_KillSpawnByDistance(lua_State* state);
int EQ2Emu_lua_SpawnSetByDistance(lua_State* state);
int EQ2Emu_lua_SetRequiredQuest(lua_State* state);
int EQ2Emu_lua_SetRequiredHistory(lua_State* state);
int EQ2Emu_lua_Despawn(lua_State* state);
int EQ2Emu_lua_ChangeHandIcon(lua_State* state);
int EQ2Emu_lua_SetVisualFlag(lua_State* state);
int EQ2Emu_lua_SetInfoFlag(lua_State* state);
int EQ2Emu_lua_AddHate(lua_State* state);
int EQ2Emu_lua_GetZone(lua_State* state);
int EQ2Emu_lua_GetZoneName(lua_State* state);
int EQ2Emu_lua_GetZoneID(lua_State* state);
int EQ2Emu_lua_Zone(lua_State* state);
int EQ2Emu_lua_ModifyPower(lua_State* state);
int EQ2Emu_lua_ModifyHP(lua_State* state);
int EQ2Emu_lua_ModifyTotalPower(lua_State* state);
int EQ2Emu_lua_ModifyTotalHP(lua_State* state);
int EQ2Emu_lua_SpellHeal(lua_State* state);
int EQ2Emu_lua_SpellHealPct(lua_State* state);
int EQ2Emu_lua_AddItem(lua_State* state);
int EQ2Emu_lua_SummonItem(lua_State* state);
int EQ2Emu_lua_RemoveItem(lua_State* state);
int EQ2Emu_lua_HasItem(lua_State* state);
int EQ2Emu_lua_Spawn(lua_State* state);
int EQ2Emu_lua_AddSpawnAccess(lua_State* state);
int EQ2Emu_lua_CastSpell(lua_State* state);
int EQ2Emu_lua_SpellDamage(lua_State* state);
int EQ2Emu_lua_SpellDamageExt(lua_State* state);
int EQ2Emu_lua_FaceTarget(lua_State* state);
int EQ2Emu_lua_MoveToLocation(lua_State* state);
int EQ2Emu_lua_ClearRunningLocations(lua_State* state);
int EQ2Emu_lua_Say(lua_State* state);
int EQ2Emu_lua_Shout(lua_State* state);
int EQ2Emu_lua_SayOOC(lua_State* state);
int EQ2Emu_lua_Emote(lua_State* state);
int EQ2Emu_lua_IsPlayer(lua_State* state);
int EQ2Emu_lua_GetCharacterID(lua_State* state);
int EQ2Emu_lua_MovementLoopAdd(lua_State* state);
int EQ2Emu_lua_GetCurrentZoneSafeLocation(lua_State* state);
int EQ2Emu_lua_PlayFlavor(lua_State* state);
int EQ2Emu_lua_PlayFlavorID(lua_State* state);
int EQ2Emu_lua_PlaySound(lua_State* state);
int EQ2Emu_lua_PlayVoice(lua_State* state);
int EQ2Emu_lua_PlayAnimation(lua_State* state);
int EQ2Emu_lua_AddLootItem(lua_State* state);
int EQ2Emu_lua_HasLootItem(lua_State* state);
int EQ2Emu_lua_RemoveLootItem(lua_State* state);
int EQ2Emu_lua_AddLootCoin(lua_State* state);
int EQ2Emu_lua_GiveLoot(lua_State* state);
int EQ2Emu_lua_HasPendingLoot(lua_State* state);
int EQ2Emu_lua_HasPendingLootItem(lua_State* state);
int EQ2Emu_lua_CreateConversation(lua_State* state);
int EQ2Emu_lua_AddConversationOption(lua_State* state);
int EQ2Emu_lua_StartConversation(lua_State* state);
int EQ2Emu_lua_StartDialogConversation(lua_State* state);
//int EQ2Emu_lua_StartItemConversation(lua_State* state);
int EQ2Emu_lua_CloseConversation(lua_State* state);
int EQ2Emu_lua_CloseItemConversation(lua_State* state);
int EQ2Emu_lua_SetPlayerProximityFunction(lua_State* state);
int EQ2Emu_lua_SetLocationProximityFunction(lua_State* state);
int EQ2Emu_lua_IsBindAllowed(lua_State* state);
int EQ2Emu_lua_IsGateAllowed(lua_State* state);
int EQ2Emu_lua_Bind(lua_State* state);
int EQ2Emu_lua_Gate(lua_State* state);
int EQ2Emu_lua_IsAlive(lua_State* state);
int EQ2Emu_lua_IsInCombat(lua_State* state);
int EQ2Emu_lua_SendMessage(lua_State* state);
int EQ2Emu_lua_SendPopUpMessage(lua_State* state);
int EQ2Emu_lua_SetServerControlFlag(lua_State* state);
int EQ2Emu_lua_ToggleTracking(lua_State* state);
int EQ2Emu_lua_AddPrimaryEntityCommand(lua_State* state);
int EQ2Emu_lua_AddSpellBookEntry(lua_State* state);
int EQ2Emu_lua_DeleteSpellBook(lua_State* state);
int EQ2Emu_lua_RemoveSpellBookEntry(lua_State* state);
int EQ2Emu_lua_SendNewAdventureSpells(lua_State* state);
int EQ2Emu_lua_SendNewTradeskillSpells(lua_State* state);
int EQ2Emu_lua_HasSpell(lua_State* state);
int EQ2Emu_lua_Attack(lua_State* state);
int EQ2Emu_lua_ApplySpellVisual(lua_State* state);
int EQ2Emu_lua_Interrupt(lua_State* state);
int EQ2Emu_lua_Stealth(lua_State* state);
int EQ2Emu_lua_IsStealthed(lua_State* state);
int EQ2Emu_lua_IsInvis(lua_State* state);
int EQ2Emu_lua_AddSpawnIDAccess(lua_State* state);
int EQ2Emu_lua_RemoveSpawnIDAccess(lua_State* state);
int EQ2Emu_lua_HasRecipeBook(lua_State* state);
int EQ2Emu_lua_SpawnMove(lua_State* state);
int EQ2Emu_lua_AddTransportSpawn(lua_State* state);
int EQ2Emu_lua_IsTransportSpawn(lua_State* state);
int EQ2Emu_lua_PerformCameraShake(lua_State* state);
//Quest Stuff
int EQ2Emu_lua_SetStepComplete(lua_State* state);
int EQ2Emu_lua_AddStepProgress(lua_State* state);
int EQ2Emu_lua_GetTaskGroupStep(lua_State* state);
int EQ2Emu_lua_QuestStepIsComplete(lua_State* state);
int EQ2Emu_lua_GetQuestStep(lua_State* state);
int EQ2Emu_lua_RegisterQuest(lua_State* state);
int EQ2Emu_lua_OfferQuest(lua_State* state);
int EQ2Emu_lua_SetQuestPrereqLevel(lua_State* state);
int EQ2Emu_lua_AddQuestPrereqQuest(lua_State* state);
int EQ2Emu_lua_AddQuestPrereqItem(lua_State* state);
int EQ2Emu_lua_AddQuestPrereqFaction(lua_State* state);
int EQ2Emu_lua_AddQuestPrereqClass(lua_State* state);
int EQ2Emu_lua_AddQuestPrereqRace(lua_State* state);
int EQ2Emu_lua_AddQuestPrereqModelType(lua_State* state);
int EQ2Emu_lua_AddQuestPrereqTradeskillLevel(lua_State* state);
int EQ2Emu_lua_AddQuestPrereqTradeskillClass(lua_State* state);
int EQ2Emu_lua_HasQuestRewardItem(lua_State* state);
int EQ2Emu_lua_AddQuestRewardItem(lua_State* state);
int EQ2Emu_lua_AddQuestSelectableRewardItem(lua_State* state);
int EQ2Emu_lua_AddQuestRewardCoin(lua_State* state);
int EQ2Emu_lua_AddQuestRewardFaction(lua_State* state);
int EQ2Emu_lua_SetQuestRewardStatus(lua_State* state);
int EQ2Emu_lua_SetStatusTmpReward(lua_State* state);
int EQ2Emu_lua_SetCoinTmpReward(lua_State* state);
int EQ2Emu_lua_SetQuestRewardComment(lua_State* state);
int EQ2Emu_lua_SetQuestRewardExp(lua_State* state);
int EQ2Emu_lua_AddQuestStep(lua_State* state);
int EQ2Emu_lua_AddQuestStepKillLogic(lua_State* state);
int EQ2Emu_lua_AddQuestStepKill(lua_State* state);
int EQ2Emu_lua_AddQuestStepKillByRace(lua_State* state);
int EQ2Emu_lua_AddQuestStepChat(lua_State* state);
int EQ2Emu_lua_AddQuestStepObtainItem(lua_State* state);
int EQ2Emu_lua_AddQuestStepZoneLoc(lua_State* state);
int EQ2Emu_lua_AddQuestStepLocation(lua_State* state);
int EQ2Emu_lua_AddQuestStepLoc(lua_State* state);
int EQ2Emu_lua_AddQuestStepSpell(lua_State* state);
int EQ2Emu_lua_AddQuestStepCraft(lua_State* state);
int EQ2Emu_lua_AddQuestStepHarvest(lua_State* state);
int EQ2Emu_lua_AddQuestStepCompleteAction(lua_State* state);
int EQ2Emu_lua_AddQuestStepProgressAction(lua_State* state);
int EQ2Emu_lua_SetQuestCompleteAction(lua_State* state);
int EQ2Emu_lua_GiveQuestReward(lua_State* state);
int EQ2Emu_lua_UpdateQuestTaskGroupDescription(lua_State* state);
int EQ2Emu_lua_UpdateQuestStepDescription(lua_State* state);
int EQ2Emu_lua_UpdateQuestDescription(lua_State* state);
int EQ2Emu_lua_UpdateQuestZone(lua_State* state);
int EQ2Emu_lua_SetCompletedDescription(lua_State* state);
int EQ2Emu_lua_ProvidesQuest(lua_State* state);
int EQ2Emu_lua_HasQuest(lua_State* state);
int EQ2Emu_lua_HasCompletedQuest(lua_State* state);
int EQ2Emu_lua_QuestIsComplete(lua_State* state);
int EQ2Emu_lua_QuestReturnNPC(lua_State* state);
int EQ2Emu_lua_GetQuest(lua_State* state);
int EQ2Emu_lua_AddTimer(lua_State* state);
int EQ2Emu_lua_StopTimer(lua_State* state);
int EQ2Emu_lua_Harvest(lua_State* state);
int EQ2Emu_lua_SetCompleteFlag(lua_State* state);
int EQ2Emu_lua_CanReceiveQuest(lua_State* state);
int EQ2Emu_lua_HasCollectionsToHandIn(lua_State *state);
int EQ2Emu_lua_HandInCollections(lua_State *state);
int EQ2Emu_lua_UseWidget(lua_State* state);
int EQ2Emu_lua_SummonPet(lua_State* state);
int EQ2Emu_lua_Charm(lua_State* state);
int EQ2Emu_lua_SetSpellList(lua_State* state);
int EQ2Emu_lua_GetPet(lua_State* state);
int EQ2Emu_lua_GetGroup(lua_State* state);
int EQ2Emu_lua_CreateOptionWindow(lua_State* state);
int EQ2Emu_lua_AddOptionWindowOption(lua_State* state);
int EQ2Emu_lua_SendOptionWindow(lua_State* state);
int EQ2Emu_lua_GetTradeskillClass(lua_State* state);
int EQ2Emu_lua_GetTradeskillLevel(lua_State* state);
int EQ2Emu_lua_GetTradeskillClassName(lua_State* state);
int EQ2Emu_lua_SetTradeskillLevel(lua_State* state);
int EQ2Emu_lua_SummonDeityPet(lua_State* state);
int EQ2Emu_lua_SummonCosmeticPet(lua_State* state);
int EQ2Emu_lua_DismissPet(lua_State* state);
int EQ2Emu_lua_GetCharmedPet(lua_State* state);
int EQ2Emu_lua_GetDeityPet(lua_State* state);
int EQ2Emu_lua_GetCosmeticPet(lua_State* state);
int EQ2Emu_lua_SetQuestFeatherColor(lua_State* state);
int EQ2Emu_lua_RemoveSpawnAccess(lua_State* state);
int EQ2Emu_lua_SpawnByLocationID(lua_State* state);
int EQ2Emu_lua_SpawnGroupByID(lua_State* state);
int EQ2Emu_lua_CastEntityCommand(lua_State* state);
int EQ2Emu_lua_SetLuaBrain(lua_State* state);
int EQ2Emu_lua_SetBrainTick(lua_State* state);
int EQ2Emu_lua_SetFollowTarget(lua_State* state);
int EQ2Emu_lua_GetFollowTarget(lua_State* state);
int EQ2Emu_lua_ToggleFollow(lua_State* state);
int EQ2Emu_lua_IsFollowing(lua_State* state);
int EQ2Emu_lua_SetTempVariable(lua_State* state);
int EQ2Emu_lua_GetTempVariable(lua_State* state);
int EQ2Emu_lua_GiveQuestItem(lua_State*state);
int EQ2Emu_lua_SetQuestRepeatable(lua_State* state);
int EQ2Emu_lua_AddWaypoint(lua_State* state);
int EQ2Emu_lua_RemoveWaypoint(lua_State* state);
int EQ2Emu_lua_SendWaypoints(lua_State* state);
int EQ2Emu_lua_AddWard(lua_State* state);
int EQ2Emu_lua_AddToWard(lua_State* state);
int EQ2Emu_lua_RemoveWard(lua_State* state);
int EQ2Emu_lua_GetWardAmountLeft(lua_State* state);
int EQ2Emu_lua_GetWardValue(lua_State* state);
//Combat AI related
int EQ2Emu_lua_SetTarget(lua_State* state);
int EQ2Emu_lua_IsPet(lua_State* state);
int EQ2Emu_lua_GetOwner(lua_State* state);
int EQ2Emu_lua_SetInCombat(lua_State* state);
int EQ2Emu_lua_CompareSpawns(lua_State* state);
int EQ2Emu_lua_ClearRunback(lua_State* state);
int EQ2Emu_lua_Runback(lua_State* state);
int EQ2Emu_lua_GetRunbackDistance(lua_State* state);
int EQ2Emu_lua_IsCasting(lua_State* state);
int EQ2Emu_lua_IsMezzed(lua_State* state);
int EQ2Emu_lua_IsStunned(lua_State* state);
int EQ2Emu_lua_IsMezzedOrStunned(lua_State* state);
int EQ2Emu_lua_ClearEncounter(lua_State* state);
int EQ2Emu_lua_ClearHate(lua_State* state);
int EQ2Emu_lua_GetMostHated(lua_State* state);
int EQ2Emu_lua_GetEncounterSize(lua_State* state);
int EQ2Emu_lua_HasRecovered(lua_State* state);
int EQ2Emu_lua_ProcessMelee(lua_State* state);
int EQ2Emu_lua_ProcessSpell(lua_State* state);
int EQ2Emu_lua_GetEncounter(lua_State* state);
int EQ2Emu_lua_GetHateList(lua_State* state);
int EQ2Emu_lua_HasGroup(lua_State* state);
int EQ2Emu_lua_HasSpellEffect(lua_State* state);
int EQ2Emu_lua_SetSuccessTimer(lua_State* state);
int EQ2Emu_lua_SetFailureTimer(lua_State* state);
int EQ2Emu_lua_IsGroundSpawn(lua_State* state);
int EQ2Emu_lua_CanHarvest(lua_State* state);
int EQ2Emu_lua_SummonDumbFirePet(lua_State* state);
int EQ2Emu_lua_GetSkillValue(lua_State* state);
int EQ2Emu_lua_GetSkillMaxValue(lua_State* state);
int EQ2Emu_lua_GetSkillName(lua_State* state);
int EQ2Emu_lua_SetSkillMaxValue(lua_State* state);
int EQ2Emu_lua_SetSkillValue(lua_State* state);
int EQ2Emu_lua_GetSkill(lua_State* state);
int EQ2Emu_lua_GetSkillIDByName(lua_State* state);
int EQ2Emu_lua_HasSkill(lua_State* state);
int EQ2Emu_lua_AddSkill(lua_State* state);
int EQ2Emu_lua_RemoveSkill(lua_State* state);
int EQ2Emu_lua_IncreaseSkillCapsByType(lua_State* state);
int EQ2Emu_lua_AddProc(lua_State* state);
int EQ2Emu_lua_AddProcExt(lua_State* state);
int EQ2Emu_lua_RemoveProc(lua_State* state);
int EQ2Emu_lua_Knockback(lua_State* state);
int EQ2Emu_lua_IsEpic(lua_State* state);
int EQ2Emu_lua_IsHeroic(lua_State* state);
int EQ2Emu_lua_ProcDamage(lua_State* state);
int EQ2Emu_lua_LastSpellAttackHit(lua_State* state);
int EQ2Emu_lua_IsBehind(lua_State* state);
int EQ2Emu_lua_IsFlanking(lua_State* state);
int EQ2Emu_lua_InFront(lua_State* state);
int EQ2Emu_lua_AddSpellTimer(lua_State* state);
int EQ2Emu_lua_SetItemCount(lua_State* state);
int EQ2Emu_lua_GetItemCount(lua_State* state);
int EQ2Emu_lua_Resurrect(lua_State* state);
int EQ2Emu_lua_BreatheUnderwater(lua_State* state);
int EQ2Emu_lua_BlurVision(lua_State* state);
int EQ2Emu_lua_SetVision(lua_State* state);
int EQ2Emu_lua_GetItemSkillReq(lua_State* state);
int EQ2Emu_lua_SetSpeedMultiplier(lua_State* state);
int EQ2Emu_lua_SetIllusion(lua_State* state);
int EQ2Emu_lua_ResetIllusion(lua_State* state);
int EQ2Emu_lua_AddThreatTransfer(lua_State* state);
int EQ2Emu_lua_RemoveThreatTransfer(lua_State* state);
int EQ2Emu_lua_CureByType(lua_State* state);
int EQ2Emu_lua_CureByControlEffect(lua_State* state);
int EQ2Emu_lua_AddSpawnSpellBonus(lua_State* state);
int EQ2Emu_lua_RemoveSpawnSpellBonus(lua_State* state);
int EQ2Emu_lua_CancelSpell(lua_State* state);
int EQ2Emu_lua_RemoveStealth(lua_State* state);
int EQ2Emu_lua_RemoveInvis(lua_State* state);
int EQ2Emu_lua_StartHeroicOpportunity(lua_State* state);
int EQ2Emu_lua_CopySpawnAppearance(lua_State* state);
int EQ2Emu_lua_RemoveTriggerFromSpell(lua_State* state);
int EQ2Emu_lua_GetSpellTriggerCount(lua_State* state);
int EQ2Emu_lua_SetSpellTriggerCount(lua_State* state);
int EQ2Emu_lua_HasSpellImmunity(lua_State* state);
int EQ2Emu_lua_AddImmunitySpell(lua_State* state);
int EQ2Emu_lua_RemoveImmunitySpell(lua_State* state);
int EQ2Emu_lua_SetSpellSnareValue(lua_State* state);
int EQ2Emu_lua_CheckRaceType(lua_State* state);
int EQ2Emu_lua_GetRaceType(lua_State* state);
int EQ2Emu_lua_GetRaceBaseType(lua_State* state);
int EQ2Emu_lua_GetQuestFlags(lua_State* state);
int EQ2Emu_lua_SetQuestFlags(lua_State* state);
int EQ2Emu_lua_SetQuestTimer(lua_State* state);
int EQ2Emu_lua_RemoveQuestStep(lua_State* state);
int EQ2Emu_lua_ResetQuestStep(lua_State* state);
int EQ2Emu_lua_SetQuestTimerComplete(lua_State* state);
int EQ2Emu_lua_AddQuestStepFailureAction(lua_State* state);
int EQ2Emu_lua_SetStepFailed(lua_State* state);
int EQ2Emu_lua_GetQuestCompleteCount(lua_State* state);
int EQ2Emu_lua_SetServerVariable(lua_State* state);
int EQ2Emu_lua_GetServerVariable(lua_State* state);
int EQ2Emu_lua_HasLanguage(lua_State* state);
int EQ2Emu_lua_AddLanguage(lua_State* state);
int EQ2Emu_lua_IsNight(lua_State* state);
int EQ2Emu_lua_AddMultiFloorLift(lua_State* state);
int EQ2Emu_lua_StartAutoMount(lua_State* state);
int EQ2Emu_lua_EndAutoMount(lua_State* state);
int EQ2Emu_lua_IsOnAutoMount(lua_State* state);
int EQ2Emu_lua_SetPlayerHistory(lua_State* state);
int EQ2Emu_lua_GetPlayerHistory(lua_State* state);
int EQ2Emu_lua_SetGridID(lua_State* state);
int EQ2Emu_lua_GetQuestStepProgress(lua_State* state);
int EQ2Emu_lua_SetPlayerLevel(lua_State* state);
int EQ2Emu_lua_AddCoin(lua_State* state);
int EQ2Emu_lua_RemoveCoin(lua_State* state);
int EQ2Emu_lua_GetPlayersInZone(lua_State* state);
int EQ2Emu_lua_SetSpawnAnimation(lua_State* state);
int EQ2Emu_lua_GetClientVersion(lua_State* state);
int EQ2Emu_lua_GetItemID(lua_State* state);
int EQ2Emu_lua_IsEntity(lua_State* state);
int EQ2Emu_lua_GetOrigX(lua_State* state);
int EQ2Emu_lua_GetOrigY(lua_State* state);
int EQ2Emu_lua_GetOrigZ(lua_State* state);
int EQ2Emu_lua_GetPCTOfHP(lua_State* state);
int EQ2Emu_lua_GetPCTOfPower(lua_State* state);
int EQ2Emu_lua_GetBoundZoneID(lua_State* state);
int EQ2Emu_lua_Evac(lua_State* state);
int EQ2Emu_lua_GetSpellTier(lua_State* state);
int EQ2Emu_lua_GetSpellID(lua_State* state);
int EQ2Emu_lua_StartTransmute(lua_State* state);
int EQ2Emu_lua_CompleteTransmute(lua_State* state);
int EQ2Emu_lua_ProcHate(lua_State* state);
int EQ2Emu_lua_GiveExp(lua_State* state);
int EQ2Emu_lua_DisplayText(lua_State* state);
int EQ2Emu_lua_ShowLootWindow(lua_State* state);
int EQ2Emu_lua_GetRandomSpawnByID(lua_State* state);
int EQ2Emu_lua_AddPrimaryEntityCommandAllSpawns(lua_State* state);
int EQ2Emu_lua_InstructionWindow(lua_State* state);
int EQ2Emu_lua_InstructionWindowClose(lua_State* state);
int EQ2Emu_lua_InstructionWindowGoal(lua_State* state);
int EQ2Emu_lua_ShowWindow(lua_State* state);
int EQ2Emu_lua_FlashWindow(lua_State* state);
int EQ2Emu_lua_EnableGameEvent(lua_State* state);
int EQ2Emu_lua_GetTutorialStep(lua_State* state);
int EQ2Emu_lua_SetTutorialStep(lua_State* state);
int EQ2Emu_lua_CheckLOS(lua_State* state);
int EQ2Emu_lua_CheckLOSByCoordinates(lua_State* state);
int EQ2Emu_lua_SetZoneExpansionFlag(lua_State* state);
int EQ2Emu_lua_GetZoneExpansionFlag(lua_State* state);
int EQ2Emu_lua_SetZoneHolidayFlag(lua_State* state);
int EQ2Emu_lua_GetZoneHolidayFlag(lua_State* state);
int EQ2Emu_lua_SetCanBind(lua_State* state);
int EQ2Emu_lua_GetCanBind(lua_State* state);
int EQ2Emu_lua_GetCanGate(lua_State* state);
int EQ2Emu_lua_SetCanGate(lua_State* state);
int EQ2Emu_lua_GetCanEvac(lua_State* state);
int EQ2Emu_lua_SetCanEvac(lua_State* state);
int EQ2Emu_lua_AddSpawnProximity(lua_State* state);
int EQ2Emu_lua_CanSeeInvis(lua_State* state);
int EQ2Emu_lua_SetSeeInvis(lua_State* state);
int EQ2Emu_lua_SetSeeHide(lua_State* state);
int EQ2Emu_lua_SetAccessToEntityCommand(lua_State* state);
int EQ2Emu_lua_SetAccessToEntityCommandByCharID(lua_State* state);
int EQ2Emu_lua_RemovePrimaryEntityCommand(lua_State* state);
int EQ2Emu_lua_SendUpdateDefaultCommand(lua_State* state);
int EQ2Emu_lua_SendTransporters(lua_State* state);
int EQ2Emu_lua_SetTemporaryTransportID(lua_State* state);
int EQ2Emu_lua_GetTemporaryTransportID(lua_State* state);
int EQ2Emu_lua_GetAlignment(lua_State* state);
int EQ2Emu_lua_SetAlignment(lua_State* state);
int EQ2Emu_lua_GetSpell(lua_State* state);
int EQ2Emu_lua_GetSpellData(lua_State* state);
int EQ2Emu_lua_SetSpellData(lua_State* state);
int EQ2Emu_lua_CastCustomSpell(lua_State* state);
int EQ2Emu_lua_SetSpellDataIndex(lua_State* state);
int EQ2Emu_lua_GetSpellDataIndex(lua_State* state);
int EQ2Emu_lua_SetSpellDisplayEffect(lua_State* state);
int EQ2Emu_lua_GetSpellDisplayEffect(lua_State* state);
int EQ2Emu_lua_InWater(lua_State* state);
int EQ2Emu_lua_InLava(lua_State* state);
int EQ2Emu_lua_DamageSpawn(lua_State* state);
int EQ2Emu_lua_IsInvulnerable(lua_State* state);
int EQ2Emu_lua_SetInvulnerable(lua_State* state);
int EQ2Emu_lua_GetRuleFlagBool(lua_State* state);
int EQ2Emu_lua_GetRuleFlagInt32(lua_State* state);
int EQ2Emu_lua_GetRuleFlagFloat(lua_State* state);
int EQ2Emu_lua_GetAAInfo(lua_State* state);
int EQ2Emu_lua_SetAAInfo(lua_State* state);
int EQ2Emu_lua_AddMasterTitle(lua_State* state);
int EQ2Emu_lua_AddCharacterTitle(lua_State* state);
int EQ2Emu_lua_SetCharacterTitleSuffix(lua_State* state);
int EQ2Emu_lua_SetCharacterTitlePrefix(lua_State* state);
int EQ2Emu_lua_ResetCharacterTitleSuffix(lua_State* state);
int EQ2Emu_lua_ResetCharacterTitlePrefix(lua_State* state);
int EQ2Emu_lua_GetInfoStructString(lua_State* state);
int EQ2Emu_lua_GetInfoStructUInt(lua_State* state);
int EQ2Emu_lua_GetInfoStructSInt(lua_State* state);
int EQ2Emu_lua_GetInfoStructFloat(lua_State* state);
int EQ2Emu_lua_SetInfoStructString(lua_State* state);
int EQ2Emu_lua_SetInfoStructUInt(lua_State* state);
int EQ2Emu_lua_SetInfoStructSInt(lua_State* state);
int EQ2Emu_lua_SetInfoStructFloat(lua_State* state);
int EQ2Emu_lua_SetCharSheetChanged(lua_State* state);
int EQ2Emu_lua_AddPlayerMail(lua_State* state);
int EQ2Emu_lua_AddPlayerMailByCharID(lua_State* state);
int EQ2Emu_lua_OpenDoor(lua_State* state);
int EQ2Emu_lua_CloseDoor(lua_State* state);
int EQ2Emu_lua_IsOpen(lua_State* state);
int EQ2Emu_lua_MakeRandomInt(lua_State* state);
int EQ2Emu_lua_MakeRandomFloat(lua_State* state);
int EQ2Emu_lua_AddIconValue(lua_State* state);
int EQ2Emu_lua_RemoveIconValue(lua_State* state);
int EQ2Emu_lua_GetShardID(lua_State* state);
int EQ2Emu_lua_GetShardCharID(lua_State* state);
int EQ2Emu_lua_GetShardCreatedTimestamp(lua_State* state);
int EQ2Emu_lua_DeleteDBShardID(lua_State* state);
int EQ2Emu_lua_PauseMovement(lua_State* state);
int EQ2Emu_lua_StopMovement(lua_State* state);
int EQ2Emu_lua_GetArrowColor(lua_State* state);
int EQ2Emu_lua_GetTSArrowColor(lua_State* state);
int EQ2Emu_lua_GetSpawnByRailID(lua_State* state);
int EQ2Emu_lua_SetRailID(lua_State* state);
int EQ2Emu_lua_IsZoneLoading(lua_State* state);
int EQ2Emu_lua_IsRunning(lua_State* state);
int EQ2Emu_lua_GetZoneLockoutTimer(lua_State* state);
int EQ2Emu_lua_SetWorldTime(lua_State* state);
int EQ2Emu_lua_GetWorldTimeYear(lua_State* state);
int EQ2Emu_lua_GetWorldTimeMonth(lua_State* state);
int EQ2Emu_lua_GetWorldTimeHour(lua_State* state);
int EQ2Emu_lua_GetWorldTimeMinute(lua_State* state);
int EQ2Emu_lua_SendTimeUpdate(lua_State* state);
int EQ2Emu_lua_SetLootTier(lua_State* state);
int EQ2Emu_lua_GetLootTier(lua_State* state);
int EQ2Emu_lua_SetLootDropType(lua_State* state);
int EQ2Emu_lua_GetLootDropType(lua_State* state);
int EQ2Emu_lua_DamageEquippedItems(lua_State* state);
int EQ2Emu_lua_CreateWidgetRegion(lua_State* state);
int EQ2Emu_lua_RemoveRegion(lua_State* state);
int EQ2Emu_lua_SetPlayerPOVGhost(lua_State* state);
int EQ2Emu_lua_SetCastOnAggroComplete(lua_State* state);
int EQ2Emu_lua_IsCastOnAggroComplete(lua_State* state);
int EQ2Emu_lua_AddRecipeBookToPlayer(lua_State* state);
int EQ2Emu_lua_RemoveRecipeFromPlayer(lua_State* state);
int EQ2Emu_lua_ReplaceWidgetFromClient(lua_State* state);
int EQ2Emu_lua_RemoveWidgetFromSpawnMap(lua_State* state);
int EQ2Emu_lua_RemoveWidgetFromZoneMap(lua_State* state);
int EQ2Emu_lua_SendHearCast(lua_State* state);
int EQ2Emu_lua_GetCharacterFlag(lua_State* state);
int EQ2Emu_lua_ToggleCharacterFlag(lua_State* state);
int EQ2Emu_lua_GetSpellInitialTarget(lua_State* state);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,357 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LUA_INTERFACE_H
#define LUA_INTERFACE_H
#include <mutex>
#include <shared_mutex>
#include "Spawn.h"
#include "Spells.h"
#include "../common/Mutex.h"
#include "Quests.h"
#include "zoneserver.h"
#include "client.h"
#include "../LUA/lua.hpp"
using namespace std;
struct ConversationOption{
string option;
string function;
};
struct OptionWindowOption {
string optionName;
string optionDescription;
string optionCommand;
int32 optionIconSheet;
int16 optionIconID;
string optionConfirmTitle;
};
//Bitmask Values
#define EFFECT_FLAG_STUN 1
#define EFFECT_FLAG_ROOT 2
#define EFFECT_FLAG_MEZ 4
#define EFFECT_FLAG_STIFLE 8
#define EFFECT_FLAG_DAZE 16
#define EFFECT_FLAG_FEAR 32
#define EFFECT_FLAG_SPELLBONUS 64
#define EFFECT_FLAG_SKILLBONUS 128
#define EFFECT_FLAG_STEALTH 256
#define EFFECT_FLAG_INVIS 512
#define EFFECT_FLAG_SNARE 1024
#define EFFECT_FLAG_WATERWALK 2048
#define EFFECT_FLAG_WATERJUMP 4096
#define EFFECT_FLAG_FLIGHT 8192
#define EFFECT_FLAG_GLIDE 16384
#define EFFECT_FLAG_AOE_IMMUNE 32768
#define EFFECT_FLAG_STUN_IMMUNE 65536
#define EFFECT_FLAG_MEZ_IMMUNE 131072
#define EFFECT_FLAG_DAZE_IMMUNE 262144
#define EFFECT_FLAG_ROOT_IMMUNE 524288
#define EFFECT_FLAG_STIFLE_IMMUNE 1048576
#define EFFECT_FLAG_FEAR_IMMUNE 2097152
#define EFFECT_FLAG_SAFEFALL 4194304
struct LuaSpell{
Entity* caster;
int32 initial_caster_char_id;
int32 initial_target;
int32 initial_target_char_id;
vector<int32> targets;
vector<int32> removed_targets; // previously cancelled, expired, used, so on
multimap<int32, int8> char_id_targets;
Spell* spell;
lua_State* state;
string file_name;
Timer timer;
bool is_recast_timer;
int16 num_calls;
int16 num_triggers;
int8 slot_pos;
int32 damage_remaining;
bool resisted;
bool has_damaged;
bool is_damage_spell;
bool interrupted;
bool crit;
bool last_spellattack_hit;
bool cancel_after_all_triggers;
bool had_triggers;
bool had_dmg_remaining;
Mutex MSpellTargets;
int32 effect_bitmask;
bool restored; // restored spell cross zone
};
class LUAUserData{
public:
LUAUserData();
virtual ~LUAUserData(){};
virtual bool IsCorrectlyInitialized();
virtual bool IsConversationOption();
virtual bool IsOptionWindow();
virtual bool IsSpawn();
virtual bool IsQuest();
virtual bool IsZone();
virtual bool IsItem();
virtual bool IsSkill();
virtual bool IsSpell();
bool correctly_initialized;
Item* item;
ZoneServer* zone;
Spawn* spawn;
vector<ConversationOption>* conversation_options;
vector<OptionWindowOption>* option_window_option;
vector<Spawn*>* spawn_list;
Quest* quest;
Skill* skill;
LuaSpell* spell;
};
class LUAConversationOptionWrapper : public LUAUserData{
public:
LUAConversationOptionWrapper();
bool IsConversationOption();
};
class LUAOptionWindowWrapper : public LUAUserData {
public:
LUAOptionWindowWrapper();
bool IsOptionWindow();
};
class LUASpawnWrapper : public LUAUserData{
public:
LUASpawnWrapper();
bool IsSpawn();
};
class LUAZoneWrapper : public LUAUserData{
public:
LUAZoneWrapper();
bool IsZone();
};
class LUAQuestWrapper : public LUAUserData{
public:
LUAQuestWrapper();
bool IsQuest();
};
class LUAItemWrapper : public LUAUserData{
public:
LUAItemWrapper();
bool IsItem();
};
class LUASkillWrapper: public LUAUserData {
public:
LUASkillWrapper();
bool IsSkill();
};
class LUASpellWrapper : public LUAUserData {
public:
LUASpellWrapper();
bool IsSpell();
};
class LuaInterface {
public:
LuaInterface();
~LuaInterface();
int GetNumberOfArgs(lua_State* state);
bool LoadLuaSpell(const char* name);
bool LoadLuaSpell(string name);
bool LoadItemScript(string name);
bool LoadItemScript(const char* name);
bool LoadSpawnScript(string name);
bool LoadSpawnScript(const char* name);
bool LoadZoneScript(string name);
bool LoadZoneScript(const char* name);
bool LoadRegionScript(string name);
bool LoadRegionScript(const char* name);
void RemoveSpell(LuaSpell* spell, bool call_remove_function = true, bool can_delete = true, string reason = "", bool removing_all_spells = false);
Spawn* GetSpawn(lua_State* state, int8 arg_num = 1);
Item* GetItem(lua_State* state, int8 arg_num = 1);
Quest* GetQuest(lua_State* state, int8 arg_num = 1);
ZoneServer* GetZone(lua_State* state, int8 arg_num = 1);
Skill* GetSkill(lua_State* state, int8 arg_num = 1);
LuaSpell* GetSpell(lua_State* state, int8 arg_num = 1);
vector<ConversationOption>* GetConversation(lua_State* state, int8 arg_num = 1);
vector<OptionWindowOption>* GetOptionWindow(lua_State* state, int8 arg_num = 1);
int8 GetInt8Value(lua_State* state, int8 arg_num = 1);
int16 GetInt16Value(lua_State* state, int8 arg_num = 1);
int32 GetInt32Value(lua_State* state, int8 arg_num = 1);
sint32 GetSInt32Value(lua_State* state, int8 arg_num = 1);
int64 GetInt64Value(lua_State* state, int8 arg_num = 1);
sint64 GetSInt64Value(lua_State* state, int8 arg_num = 1);
float GetFloatValue(lua_State* state, int8 arg_num = 1);
string GetStringValue(lua_State* state, int8 arg_num = 1);
bool GetBooleanValue(lua_State*state, int8 arg_num = 1);
void Process();
void SetInt32Value(lua_State* state, int32 value);
void SetSInt32Value(lua_State* state, sint32 value);
void SetInt64Value(lua_State* state, int64 value);
void SetSInt64Value(lua_State* state, sint64 value);
void SetFloatValue(lua_State* state, float value);
void SetBooleanValue(lua_State* state, bool value);
void SetStringValue(lua_State* state, const char* value);
void SetSpawnValue(lua_State* state, Spawn* spawn);
void SetSkillValue(lua_State* state, Skill* skill);
void SetItemValue(lua_State* state, Item* item);
void SetQuestValue(lua_State* state, Quest* quest);
void SetZoneValue(lua_State* state, ZoneServer* zone);
void SetSpellValue(lua_State* state, LuaSpell* spell);
void SetConversationValue(lua_State* state, vector<ConversationOption>* conversation);
void SetOptionWindowValue(lua_State* state, vector<OptionWindowOption>* optionWindow);
std::string AddSpawnPointers(LuaSpell* spell, bool first_cast, bool precast = false, const char* function = 0, SpellScriptTimer* timer = 0, bool passLuaSpell=false, Spawn* altTarget = 0);
LuaSpell* GetCurrentSpell(lua_State* state, bool needsLock = true);
void RemoveCurrentSpell(lua_State* state, bool needsLock = true);
bool CallSpellProcess(LuaSpell* spell, int8 num_parameters, std::string functionCalled);
LuaSpell* GetSpell(const char* name);
void UseItemScript(const char* name, lua_State* state, bool val);
void UseSpawnScript(const char* name, lua_State* state, bool val);
void UseZoneScript(const char* name, lua_State* state, bool val);
void UseRegionScript(const char* name, lua_State* state, bool val);
lua_State* GetItemScript(const char* name, bool create_new = true, bool use = false);
lua_State* GetSpawnScript(const char* name, bool create_new = true, bool use = false);
lua_State* GetZoneScript(const char* name, bool create_new = true, bool use = false);
lua_State* GetRegionScript(const char* name, bool create_new = true, bool use = false);
Quest* LoadQuest(int32 id, const char* name, const char* type, const char* zone, int8 level, const char* description, char* script_name);
const char* GetScriptName(lua_State* state);
void RemoveSpawnScript(const char* name);
bool RunItemScript(string script_name, const char* function_name, Item* item, Spawn* spawn = 0, Spawn* target = 0, sint64* returnValue = 0);
bool RunItemScriptWithReturnString(string script_name, const char* function_name, Item* item, Spawn* spawn = 0, std::string* returnValue = 0);
bool CallItemScript(lua_State* state, int8 num_parameters, std::string* returnValue = 0);
bool CallItemScript(lua_State* state, int8 num_parameters, sint64* returnValue = 0);
bool RunSpawnScript(string script_name, const char* function_name, Spawn* npc, Spawn* spawn = 0, const char* message = 0, bool is_door_open = false, sint32 input_value = 0, sint32* return_value = 0);
bool CallSpawnScript(lua_State* state, int8 num_parameters);
bool RunZoneScript(string script_name, const char* function_name, ZoneServer* zone, Spawn* spawn = 0, int32 int32_arg1 = 0, const char* str_arg1 = 0, Spawn* spawn_arg1 = 0, int32 int32_arg2 = 0, const char* str_arg2 = 0, Spawn* spawn_arg2 = 0);
bool RunZoneScriptWithReturn(string script_name, const char* function_name, ZoneServer* zone, Spawn* spawn, int32 int32_arg1, int32 int32_arg2, int32 int32_arg3, int32* returnValue = 0);
bool CallScriptInt32(lua_State* state, int8 num_parameters, int32* returnValue = 0);
bool CallScriptSInt32(lua_State* state, int8 num_parameters, sint32* returnValue = 0);
bool RunRegionScript(string script_name, const char* function_name, ZoneServer* zone, Spawn* spawn = 0, sint32 int32_arg1 = 0, int32* returnValue = 0);
bool CallRegionScript(lua_State* state, int8 num_parameters, int32* returnValue);
void ResetFunctionStack(lua_State* state);
void DestroySpells();
void DestroySpawnScripts();
void DestroyItemScripts();
void ReloadSpells();
void DestroyQuests(bool reload = false);
void DestroyZoneScripts();
void DestroyRegionScripts();
void SimpleLogError(const char* error);
void LogError(const char* error, ...);
bool CallQuestFunction(Quest* quest, const char* function, Spawn* player, int32 step_id = 0xFFFFFFFF, int32* returnValue = 0);
void RemoveDebugClients(Client* client);
void UpdateDebugClients(Client* client);
void ProcessErrorMessage(const char* message);
map<Client*, int32> GetDebugClients(){ return debug_clients; }
void AddUserDataPtr(LUAUserData* data, void* data_ptr = 0);
void DeleteUserDataPtrs(bool all);
void DeletePendingSpells(bool all);
void DeletePendingSpell(LuaSpell* spell);
Mutex* GetSpawnScriptMutex(const char* name);
Mutex* GetItemScriptMutex(const char* name);
Mutex* GetZoneScriptMutex(const char* name);
Mutex* GetRegionScriptMutex(const char* name);
Mutex* GetQuestMutex(Quest* quest);
void SetLuaSystemReloading(bool val) { lua_system_reloading = val; }
bool IsLuaSystemReloading() { return lua_system_reloading; }
void AddPendingSpellDelete(LuaSpell* spell);
void AddCustomSpell(LuaSpell* spell);
void RemoveCustomSpell(int32 id);
void FindCustomSpellLock() { MCustomSpell.readlock(); }
void FindCustomSpellUnlock() { MCustomSpell.releasereadlock(); }
LuaSpell* FindCustomSpell(int32 id);
int32 GetFreeCustomSpellID();
void SetLuaUserDataStale(void* ptr);
private:
bool shutting_down;
bool lua_system_reloading;
map<LuaSpell*, int32> spells_pending_delete;
Timer* user_data_timer;
Timer* spell_delete_timer;
map<LUAUserData*, int32> user_data;
map<void*, LUAUserData*> user_data_ptr;
map<Client*, int32> debug_clients;
map<lua_State*, LuaSpell*> current_spells;
vector<string>* GetDirectoryListing(const char* directory);
lua_State* LoadLuaFile(const char* name);
void RegisterFunctions(lua_State* state);
map<string, LuaSpell*> spells;
map<lua_State*, string> inverse_spells;
map<int32, Quest*> quests;
map<int32, lua_State*> quest_states;
map<string, map<lua_State*, bool> > item_scripts;
map<string, map<lua_State*, bool> > spawn_scripts;
map<string, map<lua_State*, bool> > zone_scripts;
map<string, map<lua_State*, bool> > region_scripts;
map<int32, LuaSpell*> custom_spells;
std::deque<int32> custom_free_spell_ids;
map<lua_State*, string> item_inverse_scripts;
map<lua_State*, string> spawn_inverse_scripts;
map<lua_State*, string> zone_inverse_scripts;
map<lua_State*, string> region_inverse_scripts;
map<string, Mutex*> item_scripts_mutex;
map<string, Mutex*> spawn_scripts_mutex;
map<string, Mutex*> zone_scripts_mutex;
map<int32, Mutex*> quests_mutex;
map<string, Mutex*> region_scripts_mutex;
Mutex MDebugClients;
Mutex MSpells;
Mutex MSpawnScripts;
Mutex MItemScripts;
Mutex MZoneScripts;
Mutex MQuests;
Mutex MLUAMain;
Mutex MSpellDelete;
Mutex MCustomSpell;
Mutex MRegionScripts;
mutable std::shared_mutex MLUAUserData;
};
#endif

View File

@ -0,0 +1,202 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MUTEXHELPER_H
#define MUTEXHELPER_H
#include "../common/timer.h"
#include "../common/Mutex.h"
#include <list>
#include <map>
template<typename T>
class IsPointer {
public:
static bool ValidPointer(T key){
return false;
}
static void Delete(T key){
}
};
class Locker{
public:
Locker(){
#ifdef WIN32
InitializeCriticalSection(&CSMutex);
#else
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutex_init(&CSMutex, &attr);
pthread_mutexattr_destroy(&attr);
#endif
}
Locker(const Locker& locker){
#ifdef WIN32
InitializeCriticalSection(&CSMutex);
#else
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutex_init(&CSMutex, &attr);
pthread_mutexattr_destroy(&attr);
#endif
}
~Locker(){
#ifdef WIN32
DeleteCriticalSection(&CSMutex);
#else
// pthread_mutex_destroy(&CSMutex);
#endif
}
void lock(){
#ifdef WIN32
EnterCriticalSection(&CSMutex);
#else
pthread_mutex_lock(&CSMutex);
#endif
}
void unlock(){
#ifdef WIN32
LeaveCriticalSection(&CSMutex);
#else
pthread_mutex_unlock(&CSMutex);
#endif
}
private:
#ifdef WIN32
CRITICAL_SECTION CSMutex;
#else
pthread_mutex_t CSMutex;
#endif
};
template<typename T>
class IsPointer<T*> {
public:
static bool ValidPointer(T* key){
return true;
}
static void Delete(T* key){
if(key){
delete key;
key = 0;
}
}
};
template <typename KeyT, typename ValueT>
class DeleteData{
public:
void SetData(int type, KeyT key, ValueT value, unsigned int time){
this->type = type;
this->key = key;
this->value = value;
this->time = time;
}
void DeleteKey(){
IsPointer<KeyT>::Delete(key);
}
void DeleteValue(){
IsPointer<ValueT>::Delete(value);
}
unsigned int GetTime(){
return time;
}
int GetType(){
return type;
}
private:
int type;
KeyT key;
ValueT value;
unsigned int time;
};
template<typename T>
class HandleDeletes {
public:
HandleDeletes(){
access_count = 0;
next_delete_attempt = 0;
changing = false;
has_pending_deletes = false;
}
~HandleDeletes(){
CheckDeletes(true);
}
void AddPendingDelete(T value, unsigned int time){
if(IsPointer<T>::ValidPointer(value)){
while(changing){
Sleep(1);
}
++access_count;
pending_deletes[value] = time;
has_pending_deletes = true;
--access_count;
}
}
void CheckDeletes(bool force = false){
while(changing){
Sleep(1);
}
if(has_pending_deletes && (force || (Timer::GetCurrentTime2() > next_delete_attempt && access_count == 0))){
changing = true;
while(access_count > 0){
Sleep(1);
}
++access_count;
next_delete_attempt = Timer::GetCurrentTime2();
std::list<T> deletes;
typename std::map<T, unsigned int>::iterator pending_delete_itr;
for(pending_delete_itr = pending_deletes.begin(); pending_delete_itr != pending_deletes.end(); pending_delete_itr++){
if(force || next_delete_attempt >= pending_delete_itr->second)
deletes.push_back(pending_delete_itr->first);
}
if(deletes.size() > 0){
typename std::list<T>::iterator delete_itr;
for(delete_itr = deletes.begin(); delete_itr != deletes.end(); delete_itr++){
IsPointer<T>::Delete(*delete_itr);
pending_deletes.erase(*delete_itr);
}
has_pending_deletes = (pending_deletes.size() > 0);
}
next_delete_attempt += 1000;
--access_count;
changing = false;
}
}
private:
volatile bool changing;
volatile int access_count;
volatile unsigned int next_delete_attempt;
volatile bool has_pending_deletes;
std::map<T, unsigned int> pending_deletes;
};
#endif

View File

@ -0,0 +1,277 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MUTEXLIST_H
#define MUTEXLIST_H
#include <list>
#include "MutexHelper.h"
#define MUTEXLIST_PENDING_ADD 1
#define MUTEXLIST_PENDING_REMOVE 2
#define MUTEXLIST_PENDING_DELETE 3
template <typename T>
class MutexList{
public:
MutexList(){
pending_changing = false;
has_pending_data = false;
pending_clear = false;
changing = false;
access_count = 0;
access_pending = 0;
}
MutexList(const MutexList& list){
pending_changing = false;
has_pending_data = false;
pending_clear = false;
changing = false;
access_count = 0;
access_pending = 0;
/*if(list.has_pending_data)
pending_data = list.pending_data;
current_data = list.current_data; */
}
~MutexList(){
while(!update(true)){
Sleep(1);
}
}
class iterator {
private:
typename std::list<T>::iterator itr; // Current element
MutexList<T>* list;
bool first_itr;
public:
iterator(){
}
iterator(MutexList<T>* list){
if(list){
this->list = list;
list->update();
this->list->AddAccess();
first_itr = true;
itr = list->current_data.begin();
if(itr != list->current_data.end())
value = *itr;
}
else
this->list = 0;
}
~iterator(){
if(list)
list->RemoveAccess();
}
bool HasNext(){
return itr != list->current_data.end();
}
bool Next(){
if(list->pending_clear)
return false;
if(first_itr)
first_itr = false;
else
itr++;
if(itr != list->current_data.end()){
value = *itr;
if(list->PendingContains(value)) //pending delete
return Next();
return true;
}
return false;
}
iterator* operator->() {
return this;
}
T value;
};
void SetChanging(){
ChangingLock.lock();
changing = true;
ChangingLock.unlock();
}
void SetNotChanging(){
ChangingLock.lock();
changing = false;
ChangingLock.unlock();
}
void AddAccess(){
AccessLock.lock();
++access_count;
AccessLock.unlock();
}
void RemoveAccess(){
AccessLock.lock();
--access_count;
AccessLock.unlock();
}
unsigned int size(bool include_pending = false){
if(include_pending){
update();
return current_data.size() + pending_data.size();
}
return current_data.size();
}
iterator begin(){
return iterator(this);
}
void clear(bool erase_all = false){
pending_clear = true;
if(erase_all){
AddAccess();
PendingLock.lock();
typename std::list<T>::iterator itr;
for(itr = current_data.begin(); itr != current_data.end(); itr++){
RemoveData(*itr);
}
PendingLock.unlock();
RemoveAccess();
}
update();
}
bool PendingContains(T key){
if(!has_pending_data)
return false;
bool ret = false;
PendingLock.lock();
ret = (pending_data.count(key) > 0 && pending_data[key] == false);
PendingLock.unlock();
return ret;
}
unsigned int count(T key){
unsigned int ret = 0;
while(changing){
Sleep(1);
}
AddAccess();
bool retry = false;
if(!changing){
typename std::list<T>::iterator iter;
for(iter = current_data.begin(); iter != current_data.end(); iter++){
if(*iter == key)
ret++;
}
}
else
retry = true;
RemoveAccess();
if(retry)
return count(key); //only occurs whenever we change to changing state at the same time as a reading state
return ret;
}
void RemoveData(T key, int32 erase_time = 0){
handle_deletes.AddPendingDelete(key, Timer::GetCurrentTime2() + erase_time);
}
void Remove(T key, bool erase = false, int32 erase_time = 0){
while(changing){
Sleep(1);
}
AddAccess();
PendingLock.lock();
pending_data[key] = false;
PendingLock.unlock();
if(erase)
RemoveData(key, erase_time);
has_pending_data = true;
RemoveAccess();
update();
}
void Add(T key){
if(count(key) > 0)
return;
while(changing){
Sleep(1);
}
AddAccess();
PendingLock.lock();
pending_data[key] = true;
PendingLock.unlock();
has_pending_data = true;
RemoveAccess();
update();
}
private:
bool update(bool force = false){
//if(access_count > 5)
// cout << "Possible error.\n";
while(changing){
Sleep(1);
}
if(pending_clear && access_count == 0){
SetChanging();
while(access_count > 0){
Sleep(1);
}
AddAccess();
PendingLock.lock();
current_data.clear();
has_pending_data = (pending_data.size() > 0);
PendingLock.unlock();
pending_clear = false;
RemoveAccess();
SetNotChanging();
}
if(!pending_clear && has_pending_data && access_count == 0){
SetChanging();
while(access_count > 0){
Sleep(1);
}
AddAccess();
PendingLock.lock();
typename std::map<T, bool>::iterator pending_itr;
for(pending_itr = pending_data.begin(); pending_itr != pending_data.end(); pending_itr++){
if(pending_itr->second)
current_data.push_back(pending_itr->first);
else
current_data.remove(pending_itr->first);
}
pending_data.clear();
PendingLock.unlock();
has_pending_data = false;
RemoveAccess();
SetNotChanging();
}
handle_deletes.CheckDeletes(force);
return !pending_clear && !has_pending_data;
}
Locker PendingLock;
Locker AccessLock;
Locker ChangingLock;
volatile int access_count;
std::list<T> current_data;
std::map<T, bool> pending_data;
HandleDeletes<T> handle_deletes;
volatile int access_pending;
volatile bool pending_changing;
volatile bool changing;
volatile bool has_pending_data;
volatile bool pending_clear;
};
#endif

View File

@ -0,0 +1,304 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MUTEXMAP_H
#define MUTEXMAP_H
#include <map>
#include "MutexHelper.h"
#define MUTEXMAP_DELETE_TYPE_KEY 1
#define MUTEXMAP_DELETE_TYPE_VALUE 2
template <typename KeyT, typename ValueT>
class MutexMap{
public:
MutexMap(){
has_pending_data = false;
pending_clear = false;
changing = false;
access_count = 0;
has_pending_deletes = false;
next_delete_attempt = 0;
delete_all = false;
}
~MutexMap(){
update(true);
PendingLock.lock();
pending_add.clear();
pending_remove.clear();
PendingLock.unlock();
}
class iterator {
private:
typename std::map<KeyT, ValueT>::iterator itr; // Current element
MutexMap* map;
bool first_itr;
public:
iterator(){
}
iterator(MutexMap* map){
this->map = map;
map->update();
map->SetChanging();
this->map->AddAccess();
map->SetNotChanging();
first_itr = true;
itr = map->current_data.begin();
if(itr != map->current_data.end()){
first = itr->first;
second = itr->second;
}
}
~iterator(){
map->RemoveAccess();
}
bool HasNext(){
return itr != map->current_data.end();
}
bool Next(){
if(map->pending_clear)
return false;
if(first_itr)
first_itr = false;
else
itr++;
if(itr != map->current_data.end()){
first = itr->first;
second = itr->second;
map->PendingLock.lock();
if(map->pending_remove.count(first) > 0){
map->PendingLock.unlock();
return Next();
}
map->PendingLock.unlock();
return true;
}
return false;
}
iterator* operator->() {
return this;
}
KeyT first;
ValueT second;
};
int count(KeyT key, bool include_pending = false){
while(changing){
Sleep(1);
}
AddAccess();
int ret = current_data.count(key);
if(include_pending){
PendingLock.lock();
ret += pending_add.count(key);
PendingLock.unlock();
}
RemoveAccess();
return ret;
}
void clear(bool delete_all = false){
pending_clear = true;
if(delete_all){
SetChanging();
while(access_count > 0){
Sleep(1);
}
AddAccess();
PendingLock.lock();
typename std::map<KeyT, ValueT>::iterator itr;
for(itr = current_data.begin(); itr != current_data.end(); itr++){
deleteData(itr->first, MUTEXMAP_DELETE_TYPE_VALUE);
}
PendingLock.unlock();
RemoveAccess();
SetNotChanging();
}
update();
}
unsigned int size(bool include_pending = false){
if(include_pending)
return current_data.size() + pending_add.size();
return current_data.size();
}
void deleteData(KeyT key, int8 type, int32 erase_time = 0){
DeleteData<KeyT, ValueT>* del = new DeleteData<KeyT, ValueT>();
del->SetData(type, key, current_data[key], Timer::GetCurrentTime2() + erase_time);
pending_deletes[del] = true;
has_pending_deletes = true;
}
void erase(KeyT key, bool erase_key = false, bool erase_value = false, int32 erase_time = 0){
while(changing){
Sleep(1);
}
AddAccess();
if(current_data.count(key) != 0){
PendingLock.lock();
pending_remove[key] = true;
if(erase_key || erase_value){
int type = 0;
if(erase_key)
type = MUTEXMAP_DELETE_TYPE_KEY;
if(erase_value)
type += MUTEXMAP_DELETE_TYPE_VALUE;
deleteData(key, type, erase_time);
}
has_pending_data = true;
PendingLock.unlock();
}
RemoveAccess();
update();
}
iterator begin(){
return iterator(this);
}
void Put(KeyT key, ValueT value){
while(changing){
Sleep(1);
}
AddAccess();
PendingLock.lock();
pending_add[key] = value;
has_pending_data = true;
PendingLock.unlock();
RemoveAccess();
update();
}
ValueT& Get(KeyT key){
while(changing){
Sleep(1);
}
AddAccess();
if(current_data.count(key) > 0 || pending_add.count(key) == 0){
RemoveAccess();
return current_data[key];
}
RemoveAccess();
return pending_add[key];
}
private:
void AddAccess(){
AccessLock.lock();
++access_count;
AccessLock.unlock();
}
void RemoveAccess(){
AccessLock.lock();
--access_count;
AccessLock.unlock();
}
void SetChanging(){
ChangingLock.lock();
changing = true;
}
void SetNotChanging(){
changing = false;
ChangingLock.unlock();
}
void update(bool force = false){
if(pending_clear && (force || access_count == 0)){
SetChanging();
while(access_count > 0){
Sleep(1);
}
AddAccess();
PendingLock.lock();
current_data.clear();
has_pending_data = (pending_add.size() > 0 || pending_remove.size() > 0);
pending_clear = false;
PendingLock.unlock();
RemoveAccess();
SetNotChanging();
}
if(!pending_clear && has_pending_data && (force || access_count == 0)){
SetChanging();
while(access_count > 0){
Sleep(1);
}
AddAccess();
PendingLock.lock();
typename std::map<KeyT, bool>::iterator remove_itr;
for(remove_itr = pending_remove.begin(); remove_itr != pending_remove.end(); remove_itr++){
current_data.erase(remove_itr->first);
}
typename std::map<KeyT, ValueT>::iterator add_itr;
for(add_itr = pending_add.begin(); add_itr != pending_add.end(); add_itr++){
current_data[add_itr->first] = add_itr->second;
}
pending_add.clear();
pending_remove.clear();
has_pending_data = false;
PendingLock.unlock();
RemoveAccess();
SetNotChanging();
}
if(has_pending_deletes && (force || (Timer::GetCurrentTime2() > next_delete_attempt && access_count == 0))){
SetChanging();
while(access_count > 0){
Sleep(1);
}
AddAccess();
PendingLock.lock();
unsigned int time = Timer::GetCurrentTime2();
typename std::list<DeleteData<KeyT, ValueT>*> deleteData;
typename std::map<DeleteData<KeyT, ValueT>*, bool>::iterator remove_itr;
for(remove_itr = pending_deletes.begin(); remove_itr != pending_deletes.end(); remove_itr++){
if(force || time >= remove_itr->first->GetTime())
deleteData.push_back(remove_itr->first);
}
DeleteData<KeyT, ValueT>* data = 0;
typename std::list<DeleteData<KeyT, ValueT>*>::iterator remove_data_itr;
for(remove_data_itr = deleteData.begin(); remove_data_itr != deleteData.end(); remove_data_itr++){
data = *remove_data_itr;
if((data->GetType() & MUTEXMAP_DELETE_TYPE_KEY) == MUTEXMAP_DELETE_TYPE_KEY){
data->DeleteKey();
}
if((data->GetType() & MUTEXMAP_DELETE_TYPE_VALUE) == MUTEXMAP_DELETE_TYPE_VALUE){
data->DeleteValue();
}
pending_deletes.erase(data);
delete data;
}
next_delete_attempt = Timer::GetCurrentTime2() + 1000;
PendingLock.unlock();
RemoveAccess();
SetNotChanging();
has_pending_deletes = (pending_deletes.size() > 0);
}
}
Locker PendingLock;
Locker AccessLock;
Locker ChangingLock;
std::map<KeyT, ValueT> current_data;
std::map<KeyT, ValueT> pending_add;
std::map<DeleteData<KeyT, ValueT>*, bool > pending_deletes;
std::map<KeyT, bool> pending_remove;
volatile unsigned int next_delete_attempt;
volatile int access_count;
volatile bool delete_all;
volatile bool changing;
volatile bool has_pending_data;
volatile bool has_pending_deletes;
volatile bool pending_clear;
};
#endif

View File

@ -0,0 +1,202 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MUTEXVECTOR_H
#define MUTEXVECTOR_H
#include <vector>
#include "MutexHelper.h"
#define MUTEXVECTOR_PENDING_ADD 1
#define MUTEXVECTOR_PENDING_REMOVE 2
#define MUTEXVECTOR_PENDING_DELETE 3
template <typename T>
class MutexVector{
public:
MutexVector(){
has_pending_data = false;
pending_clear = false;
changing = false;
access_count = 0;
}
~MutexVector(){
}
class iterator {
private:
typename std::vector<T>::iterator itr; // Current element
MutexVector<T>* vector;
bool first_itr;
public:
iterator(){
}
iterator(MutexVector<T>* vector){
if(vector){
this->vector = vector;
vector->update();
++this->vector->access_count;
first_itr = true;
itr = vector->current_data.begin();
if(itr != vector->current_data.end())
value = *itr;
}
else
this->vector = 0;
}
~iterator(){
if(vector)
--vector->access_count;
}
bool HasNext(){
return itr != vector->current_data.end();
}
bool Next(){
if(vector->pending_clear)
return false;
if(first_itr)
first_itr = false;
else
itr++;
if(itr != vector->current_data.end()){
value = *itr;
if(vector->pending_data.count(value) > 0 && vector->pending_data[value] == false) //pending delete
return Next();
return true;
}
return false;
}
iterator* operator->() {
return this;
}
T value;
};
void update(){
//if(access_count > 5)
// cout << "Possible error.\n";
while(changing){
Sleep(1);
}
if(pending_clear && access_count == 0){
changing = true;
while(access_count > 0){
Sleep(1);
}
++access_count;
current_data.clear();
has_pending_data = (pending_data.size() > 0);
pending_clear = false;
--access_count;
changing = false;
}
if(!pending_clear && has_pending_data && access_count == 0){
changing = true;
while(access_count > 0){
Sleep(1);
}
++access_count;
typename std::map<T, bool>::iterator pending_itr;
for(pending_itr = pending_data.begin(); pending_itr != pending_data.end(); pending_itr++){
if(pending_itr->second)
current_data.push_back(pending_itr->first);
else{
typename std::vector<T>::iterator data_itr;
for(data_itr = current_data.begin(); data_itr != current_data.end(); data_itr++){
if(*data_itr == pending_itr->first){
current_data.erase(data_itr);
break;
}
}
}
}
pending_data.clear();
has_pending_data = false;
--access_count;
changing = false;
}
handle_deletes.CheckDeletes();
}
unsigned int size(bool include_pending = false){
if(include_pending)
return current_data.size() + pending_data.size();
return current_data.size();
}
iterator begin(){
return iterator(this);
}
void clear(){
pending_clear = true;
update();
}
unsigned int count(T key){
unsigned int ret = 0;
while(changing){
Sleep(1);
}
++access_count;
typename std::list<T>::iterator iter;
for(iter = current_data.begin(); iter != current_data.end(); iter++){
if(*iter == key)
ret++;
}
--access_count;
return ret;
}
void Remove(T key, bool erase = false, unsigned int erase_time = 0){
while(changing){
Sleep(1);
}
++access_count;
pending_data[key] = false;
if(erase)
handle_deletes.AddPendingDelete(key, erase_time);
has_pending_data = true;
--access_count;
update();
}
void Add(T key){
while(changing){
Sleep(1);
}
++access_count;
pending_data[key] = true;
has_pending_data = true;
--access_count;
update();
}
T Get(unsigned int index){
while(changing){
Sleep(1);
}
return current_data[index];
}
private:
volatile int access_count;
std::vector<T> current_data;
std::map<T, bool> pending_data;
HandleDeletes<T> handle_deletes;
volatile bool changing;
volatile bool has_pending_data;
volatile bool pending_clear;
};
#endif

1075
source/WorldServer/NPC.cpp Normal file

File diff suppressed because it is too large Load Diff

217
source/WorldServer/NPC.h Normal file
View File

@ -0,0 +1,217 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __EQ2_NPC__
#define __EQ2_NPC__
#include <atomic>
#include "Entity.h"
#include "MutexMap.h"
#define AI_STRATEGY_BALANCED 1
#define AI_STRATEGY_OFFENSIVE 2
#define AI_STRATEGY_DEFENSIVE 3
// Randomize Appearances
#define RANDOMIZE_GENDER 1
#define RANDOMIZE_RACE 2
#define RANDOMIZE_MODEL_TYPE 4
// Randomize appearance id (spawn_npcs table values)
#define RANDOMIZE_FACIAL_HAIR_TYPE 8 // was RANDOMIZE_FACIAL_HAIR
#define RANDOMIZE_HAIR_TYPE 16 // was RANDOMIZE_HAIR
//#define RANDOMIZE_LEGS_TYPE 32 // spare!
#define RANDOMIZE_WING_TYPE 64
// Randomize parameters (npc_appearances, sInt values)
#define RANDOMIZE_CHEEK_TYPE 128
#define RANDOMIZE_CHIN_TYPE 256
#define RANDOMIZE_EAR_TYPE 512
#define RANDOMIZE_EYE_BROW_TYPE 1024
#define RANDOMIZE_EYE_TYPE 2048
#define RANDOMIZE_LIP_TYPE 4096
#define RANDOMIZE_NOSE_TYPE 8192
// Randomize colors/hues (npc_appearances, RGB values)
#define RANDOMIZE_EYE_COLOR 16384
#define RANDOMIZE_HAIR_COLOR1 32768
#define RANDOMIZE_HAIR_COLOR2 65536
#define RANDOMIZE_HAIR_HIGHLIGHT 131072
#define RANDOMIZE_HAIR_FACE_COLOR 262144 // was RANDOMIZE_FACIAL_HAIR_COLOR
#define RANDOMIZE_HAIR_FACE_HIGHLIGHT_COLOR 524288
#define RANDOMIZE_HAIR_TYPE_COLOR 1048576 // was RANDOMIZE_HAIR_COLOR
#define RANDOMIZE_HAIR_TYPE_HIGHLIGHT_COLOR 2097152
#define RANDOMIZE_SKIN_COLOR 4194304
#define RANDOMIZE_WING_COLOR1 8388608
#define RANDOMIZE_WING_COLOR2 16777216
// All Flags On: 33554431
#define PET_TYPE_COMBAT 1
#define PET_TYPE_CHARMED 2
#define PET_TYPE_DEITY 3
#define PET_TYPE_COSMETIC 4
#define PET_TYPE_DUMBFIRE 5
enum CAST_TYPE {
CAST_ON_SPAWN=0,
CAST_ON_AGGRO=1,
MAX_CAST_TYPES=2
};
class Brain;
class NPCSpell {
public:
NPCSpell() {
}
NPCSpell(NPCSpell* inherit) {
list_id = inherit->list_id;
spell_id = inherit->spell_id;
tier = inherit->tier;
cast_on_spawn = inherit->cast_on_spawn;
cast_on_initial_aggro = inherit->cast_on_initial_aggro;
required_hp_ratio = inherit->required_hp_ratio;
}
int32 list_id;
int32 spell_id;
int8 tier;
bool cast_on_spawn;
bool cast_on_initial_aggro;
sint8 required_hp_ratio;
};
class NPC : public Entity {
public:
NPC();
NPC(NPC* old_npc);
virtual ~NPC();
void Initialize();
EQ2Packet* serialize(Player* player, int16 version);
void SetAppearanceID(int32 id){ appearance_id = id; }
int32 GetAppearanceID(){ return appearance_id; }
bool IsNPC(){ return true; }
void StartRunback(bool reset_hp_on_runback = false);
void InCombat(bool val);
bool HandleUse(Client* client, string type);
void SetRandomize(int32 value) {appearance.randomize = value;}
void AddRandomize(sint32 value) {appearance.randomize += value;}
int32 GetRandomize() {return appearance.randomize;}
bool CheckSameAppearance(string name, int16 id);
void Randomize(NPC* npc, int32 flags);
Skill* GetSkillByName(const char* name, bool check_update = false);
Skill* GetSkillByID(int32 id, bool check_update = false);
int8 GetAttackType();
void SetAIStrategy(int8 strategy);
int8 GetAIStrategy();
void SetPrimarySpellList(int32 id);
int32 GetPrimarySpellList();
void SetSecondarySpellList(int32 id);
int32 GetSecondarySpellList();
void SetPrimarySkillList(int32 id);
int32 GetPrimarySkillList();
void SetSecondarySkillList(int32 id);
int32 GetSecondarySkillList();
void SetEquipmentListID(int32 id);
int32 GetEquipmentListID();
Spell* GetNextSpell(Spawn* target, float distance);
virtual Spell* GetNextBuffSpell(Spawn* target = 0);
void SetAggroRadius(float radius, bool overrideBaseValue = false);
float GetAggroRadius();
float GetBaseAggroRadius() { return base_aggro_radius; }
void SetCastPercentage(int8 percentage);
int8 GetCastPercentage();
void SetSkills(map<string, Skill*>* in_skills);
void SetSpells(vector<NPCSpell*>* in_spells);
void SetRunbackLocation(float x, float y, float z, int32 gridid, bool set_hp_runback = false);
MovementLocation* GetRunbackLocation();
float GetRunbackDistance();
void Runback(float distance=0.0f, bool stopFollowing = true);
void ClearRunback();
virtual bool PauseMovement(int32 period_of_time_ms);
virtual bool IsPauseMovementTimerActive();
void AddSkillBonus(int32 spell_id, int32 skill_id, float value);
virtual void RemoveSkillBonus(int32 spell_id);
virtual void SetZone(ZoneServer* zone, int32 version=0);
void SetMaxPetLevel(int8 val) { m_petMaxLevel = val; }
int8 GetMaxPetLevel() { return m_petMaxLevel; }
void ProcessCombat();
/// <summary>Sets the brain this NPC should use</summary>
/// <param name="brain">The brain this npc should use</param>
void SetBrain(Brain* brain);
/// <summary>Gets the current brain this NPC uses</summary>
/// <returns>The Brain this NPC uses</returns>
::Brain* Brain() { return m_brain; }
bool m_runningBack;
sint16 m_runbackHeadingDir1;
sint16 m_runbackHeadingDir2;
int32 GetShardID() { return m_ShardID; }
void SetShardID(int32 shardid) { m_ShardID = shardid; }
int32 GetShardCharID() { return m_ShardCharID; }
void SetShardCharID(int32 charid) { m_ShardCharID = charid; }
sint64 GetShardCreatedTimestamp() { return m_ShardCreatedTimestamp; }
void SetShardCreatedTimestamp(sint64 timestamp) { m_ShardCreatedTimestamp = timestamp; }
bool HasSpells() { return has_spells; }
std::atomic<bool> m_call_runback;
std::atomic<bool> cast_on_aggro_completed;
private:
MovementLocation* runback;
int8 cast_percentage;
float aggro_radius;
float base_aggro_radius;
Spell* GetNextSpell(float distance, int8 type);
map<string, Skill*>* skills;
vector<NPCSpell*>* spells;
vector<NPCSpell*> cast_on_spells[CAST_TYPE::MAX_CAST_TYPES];
int32 primary_spell_list;
int32 secondary_spell_list;
int32 primary_skill_list;
int32 secondary_skill_list;
int32 equipment_list_id;
int8 attack_type;
int8 ai_strategy;
int32 appearance_id;
int32 npc_id;
MutexMap<int32, SkillBonus*> skill_bonus_list;
int8 m_petMaxLevel;
// Because I named the get function Brain() as well we need to use '::' to specify we are refering to
// the brain class and not the function defined above
::Brain* m_brain;
Mutex MBrain;
int32 m_ShardID;
int32 m_ShardCharID;
sint64 m_ShardCreatedTimestamp;
bool has_spells;
};
#endif

View File

@ -0,0 +1,902 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "NPC_AI.h"
#include "Combat.h"
#include "zoneserver.h"
#include "Spells.h"
#include "../common/Log.h"
#include "LuaInterface.h"
#include "World.h"
#include "Rules/Rules.h"
extern RuleManager rule_manager;
extern LuaInterface* lua_interface;
extern World world;
/* The NEW AI code */
Brain::Brain(NPC* npc) {
// Set the npc this brain will controll
m_body = npc;
// Set the default time between calls to think to 250 miliseconds (1/4 a second)
m_tick = 250;
m_lastTick = Timer::GetCurrentTime2();
m_spellRecovery = 0;
m_playerInEncounter = false;
// Set up the mutex for the hate list
MHateList.SetName("Brain::m_hatelist");
// Set up the mutex for the encounter list
MEncounter.SetName("Brain::m_encounter");
}
Brain::~Brain() {
}
void Brain::Think() {
if (m_body->IsPet() && m_body->GetOwner() && m_body->GetOwner()->IsPlayer()) {
Player* player = (Player*)m_body->GetOwner();
if(player->GetInfoStruct()->get_pet_id() == 0) {
player->GetInfoStruct()->set_pet_id(player->GetIDWithPlayerSpawn(m_body));
player->SetCharSheetChanged(true);
}
}
// Get the entity this NPC hates the most,
// GetMostHated() will handle dead spawns so no need to check the health in this function
Entity* target = GetMostHated();
// If mezzed, stunned or feared we can't do anything so skip
if (!m_body->IsMezzedOrStunned()) {
// Not mezzed or stunned
// Get the distance to the runback location
float run_back_distance = m_body->GetRunbackDistance();
if (target) {
LogWrite(NPC_AI__DEBUG, 7, "NPC_AI", "%s has %s targeted.", m_body->GetName(), target->GetName());
// NPC has an entity that it hates
// Set the NPC's target to the most hated entity if it is not already.
if (m_body->GetTarget() != target) {
m_body->SetTarget(target);
}
m_body->FaceTarget(target, false);
// target needs to be set before in combat is engaged
// If the NPC is not in combat then put them in combat
if (!m_body->EngagedInCombat()) {
m_body->ClearRunningLocations();
m_body->InCombat(true);
m_body->cast_on_aggro_completed = false;
m_body->GetZone()->CallSpawnScript(m_body, SPAWN_SCRIPT_AGGRO, target);
}
bool breakWaterPursuit = false;
if (m_body->IsWaterCreature() && !m_body->IsFlyingCreature() && !target->InWater())
breakWaterPursuit = true;
// Check to see if the NPC has exceeded the max chase distance
if (run_back_distance > MAX_CHASE_DISTANCE || breakWaterPursuit) {
LogWrite(NPC_AI__DEBUG, 7, "NPC_AI", "Run back distance is greater then max chase distance, run_back_distance = %f", run_back_distance);
// Over the max chase distance, Check to see if the target is is a client
if (target->IsPlayer() && ((Player*)target)->GetClient())
{
// Target is a client so send encounter break messages
if (m_body->HasSpawnGroup())
((Player*)target)->GetClient()->SimpleMessage(CHANNEL_NARRATIVE, "This encounter will no longer give encounter rewards.");
else
((Player*)target)->GetClient()->Message(CHANNEL_NARRATIVE, "%s is no longer worth any experience or treasure.", m_body->GetName());
}
// Clear the hate list for this NPC
ClearHate();
// Clear the encounter list
ClearEncounter();
}
else {
// Still within max chase distance lets to the combat stuff now
float distance = m_body->GetDistance(target);
if(!m_body->IsCasting() && (!HasRecovered() || !ProcessSpell(target, distance))) {
LogWrite(NPC_AI__DEBUG, 7, "NPC_AI", "%s is attempting melee on %s.", m_body->GetName(), target->GetName());
m_body->FaceTarget(target, false);
ProcessMelee(target, distance);
}
}
}
else {
// Nothing in the hate list
bool wasInCombat = m_body->EngagedInCombat();
// Check to see if the NPC is still flagged as in combat for some reason
if (m_body->EngagedInCombat()) {
// If it is set the combat flag to false
m_body->InCombat(false);
// Do not set a players pet to full health once they stop combat
if (!m_body->IsPet() || (m_body->IsPet() && m_body->GetOwner() && !m_body->GetOwner()->IsPlayer()))
m_body->SetHP(m_body->GetTotalHP());
}
CheckBuffs();
// If run back distance is greater then 0 then run back
if(!m_body->EngagedInCombat() && !m_body->IsPauseMovementTimerActive())
{
if (run_back_distance > 1 || (m_body->m_call_runback && !m_body->following)) {
m_body->SetLockedNoLoot(ENCOUNTER_STATE_BROKEN);
m_body->UpdateEncounterState(ENCOUNTER_STATE_BROKEN);
m_body->GetZone()->AddChangedSpawn(m_body);
m_body->Runback(run_back_distance);
m_body->m_call_runback = false;
}
else if (m_body->GetRunbackLocation())
{
switch(m_body->GetRunbackLocation()->stage)
{
case 0:
m_body->GetZone()->movementMgr->StopNavigation((Entity*)m_body);
m_body->ClearRunningLocations();
m_body->SetX(m_body->GetRunbackLocation()->x,false);
m_body->SetZ(m_body->GetRunbackLocation()->z,false);
m_body->SetY(m_body->GetRunbackLocation()->y,false);
m_body->CalculateRunningLocation(true);
m_body->GetRunbackLocation()->stage = 1;
m_body->GetZone()->AddChangedSpawn(m_body);
break;
case 6: // artificially 1500ms per 250ms Think() call
if (m_body->GetRunbackLocation()->gridid > 0)
m_body->SetLocation(m_body->GetRunbackLocation()->gridid);
if(m_body->GetTempActionState() == 0)
m_body->SetTempActionState(-1);
m_body->SetHeading(m_body->m_runbackHeadingDir1,m_body->m_runbackHeadingDir2,false);
if(m_body->GetRunbackLocation()->reset_hp_on_runback)
m_body->SetHP(m_body->GetTotalHP());
m_body->ClearRunback();
if(m_body->GetLockedNoLoot() != ENCOUNTER_STATE_AVAILABLE && m_body->Alive()) {
m_body->SetLockedNoLoot(ENCOUNTER_STATE_AVAILABLE);
m_body->UpdateEncounterState(ENCOUNTER_STATE_AVAILABLE);
}
m_body->GetZone()->AddChangedSpawn(m_body);
break;
default: // captures case 1 up to case 5 to turn around / reset hp
m_body->GetRunbackLocation()->stage++; // artificially delay
break;
}
}
}
// If encounter size is greater then 0 then clear it
if (GetEncounterSize() > 0)
ClearEncounter();
}
}
}
sint32 Brain::GetHate(Entity* entity) {
// We will use this variable to return the value, default to 0
sint32 ret = 0;
// Lock the hate list, not altering it so do a read lock
MHateList.readlock(__FUNCTION__, __LINE__);
// First check to see if the given entity is even in the hate list
if (m_hatelist.count(entity->GetID()) > 0)
// Entity in the hate list so get the hate value for the entity
ret = m_hatelist[entity->GetID()];
// Unlock the hate list
MHateList.releasereadlock(__FUNCTION__, __LINE__);
// return the hate
return ret;
}
void Brain::AddHate(Entity* entity, sint32 hate) {
// do not aggro when running back, despite taking damage
if (m_body->IsNPC() && ((NPC*)m_body)->m_runningBack)
return;
else if (m_body->IsPet() && m_body->IsEntity() && ((Entity*)m_body)->GetOwner() == entity)
return;
if(m_body->IsImmune(IMMUNITY_TYPE_TAUNT))
{
LogWrite(NPC_AI__DEBUG, 7, "NPC_AI", "%s is immune to taunt from entity %s.", m_body->GetName(), entity ? entity->GetName() : "(null)");
if(entity && entity->IsPlayer())
((Player*)entity)->GetClient()->GetCurrentZone()->SendDamagePacket((Spawn*)entity, (Spawn*)m_body, DAMAGE_PACKET_TYPE_RANGE_SPELL_DMG, DAMAGE_PACKET_RESULT_IMMUNE, 0, 0, "Hate");
return;
}
// Lock the hate list, we are altering the list so use write lock
MHateList.writelock(__FUNCTION__, __LINE__);
if (m_hatelist.count(entity->GetID()) > 0) {
m_hatelist[entity->GetID()] += hate;
// take into consideration that 0 or negative hate is not valid, we need to properly reset the value
if(m_hatelist[entity->GetID()] < 1) {
m_hatelist[entity->GetID()] = 1;
}
}
else
m_hatelist.insert(std::pair<int32, sint32>(entity->GetID(), hate));
entity->MHatedBy.lock();
if (entity->HatedBy.count(m_body->GetID()) == 0)
entity->HatedBy.insert(m_body->GetID());
entity->MHatedBy.unlock();
// Unlock the list
bool ownerExistsAddHate = false;
if(entity->IsPet() && entity->GetOwner()) {
map<int32, sint32>::iterator itr = m_hatelist.find(entity->GetOwner()->GetID());
if(itr == m_hatelist.end()) {
ownerExistsAddHate = true;
}
}
MHateList.releasewritelock(__FUNCTION__, __LINE__);
if(ownerExistsAddHate) {
AddHate(entity->GetOwner(), 0);
}
}
void Brain::ClearHate() {
// Lock the hate list, we are altering the list so use a write lock
MHateList.writelock(__FUNCTION__, __LINE__);
map<int32, sint32>::iterator itr;
for (itr = m_hatelist.begin(); itr != m_hatelist.end(); itr++) {
Spawn* spawn = m_body->GetZone()->GetSpawnByID(itr->first);
if (spawn && spawn->IsEntity())
{
((Entity*)spawn)->MHatedBy.lock();
((Entity*)spawn)->HatedBy.erase(m_body->GetID());
((Entity*)spawn)->MHatedBy.unlock();
}
}
// Clear the list
m_hatelist.clear();
// Unlock the hate list
MHateList.releasewritelock(__FUNCTION__, __LINE__);
}
void Brain::ClearHate(Entity* entity) {
// Lock the hate list, we could potentially modify the list so use write lock
MHateList.writelock(__FUNCTION__, __LINE__);
// Check to see if the given entity is in the hate list
if (m_hatelist.count(entity->GetID()) > 0)
// Erase the entity from the hate list
m_hatelist.erase(entity->GetID());
entity->MHatedBy.lock();
entity->HatedBy.erase(m_body->GetID());
entity->MHatedBy.unlock();
// Unlock the hate list
MHateList.releasewritelock(__FUNCTION__, __LINE__);
}
Entity* Brain::GetMostHated() {
map<int32, sint32>::iterator itr;
int32 ret = 0;
sint32 hate = 0;
// Lock the hate list, not going to alter it so use a read lock
MHateList.readlock(__FUNCTION__, __LINE__);
if (m_hatelist.size() > 0) {
// Loop through the list looking for the entity that this NPC hates the most
for(itr = m_hatelist.begin(); itr != m_hatelist.end(); itr++) {
// Compare the hate value for the current iteration to our stored highest value
if(itr->second > hate) {
// New high value store the entity
ret = itr->first;
// Store the value to compare with the rest of the entities
hate = itr->second;
}
}
}
// Unlock the list
MHateList.releasereadlock(__FUNCTION__, __LINE__);
Entity* hated = (Entity*)GetBody()->GetZone()->GetSpawnByID(ret);
// Check the reult to see if it is still alive
if(hated && hated->GetHP() <= 0) {
// Entity we got was dead so remove it from the list
ClearHate(hated);
// Call this function again now that we removed the dead entity
hated = GetMostHated();
}
// Return our result
return hated;
}
sint8 Brain::GetHatePercentage(Entity* entity) {
float percentage = 0.0;
MHateList.readlock(__FUNCTION__, __LINE__);
if (entity && m_hatelist.count(entity->GetID()) > 0 && m_hatelist[entity->GetID()] > 0) {
sint32 total_hate = 0;
map<int32, sint32>::iterator itr;
for (itr = m_hatelist.begin(); itr != m_hatelist.end(); itr++)
total_hate += itr->second;
percentage = m_hatelist[entity->GetID()] / total_hate;
}
MHateList.releasereadlock(__FUNCTION__, __LINE__);
return (sint8)(percentage * 100);
}
void Brain::SendHateList(Client* client) {
MHateList.readlock(__FUNCTION__, __LINE__);
client->Message(CHANNEL_COLOR_YELLOW, "%s's HateList", m_body->GetName());
client->Message(CHANNEL_COLOR_YELLOW, "-------------------");
map<int32, sint32>::iterator itr;
if (m_hatelist.size() > 0) {
// Loop through the list looking for the entity that this NPC hates the most
for(itr = m_hatelist.begin(); itr != m_hatelist.end(); itr++) {
Entity* ent = (Entity*)GetBody()->GetZone()->GetSpawnByID(itr->first);
// Compare the hate value for the current iteration to our stored highest value
if(ent) {
client->Message(CHANNEL_COLOR_YELLOW, "%s : %i", ent->GetName(), itr->second);
}
else {
client->Message(CHANNEL_COLOR_YELLOW, "%u (cannot identity spawn id->entity) : %i", itr->first, itr->second);
}
}
}
client->Message(CHANNEL_COLOR_YELLOW, "-------------------");
MHateList.releasereadlock(__FUNCTION__, __LINE__);
}
vector<Entity*>* Brain::GetHateList() {
vector<Entity*>* ret = new vector<Entity*>;
map<int32, sint32>::iterator itr;
// Lock the list
MHateList.readlock(__FUNCTION__, __LINE__);
// Loop over the list storing the values into the new list
for (itr = m_hatelist.begin(); itr != m_hatelist.end(); itr++) {
Entity* ent = (Entity*)GetBody()->GetZone()->GetSpawnByID(itr->first);
if (ent)
ret->push_back(ent);
}
// Unlock the list
MHateList.releasereadlock(__FUNCTION__, __LINE__);
// Return the copy of the list
return ret;
}
void Brain::MoveCloser(Spawn* target) {
if (target && m_body->GetFollowTarget() != target)
m_body->SetFollowTarget(target, rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat());
if (m_body->GetFollowTarget() && !m_body->following) {
m_body->CalculateRunningLocation(true);
//m_body->ClearRunningLocations();
m_body->following = true;
}
}
bool Brain::ProcessSpell(Entity* target, float distance) {
if(rand()%100 > m_body->GetCastPercentage() || m_body->IsStifled() || m_body->IsFeared())
return false;
Spell* spell = m_body->GetNextSpell(target, distance);
if(spell){
Spawn* spell_target = 0;
if(spell->GetSpellData()->friendly_spell == 1){
vector<Spawn*>* group = m_body->GetSpawnGroup();
if(group && group->size() > 0){
vector<Spawn*>::iterator itr;
for(itr = group->begin(); itr != group->end(); itr++){
if((!spell_target && (*itr)->GetHP() > 0 && (*itr)->GetHP() < (*itr)->GetTotalHP()) || (spell_target && (*itr)->GetHP() > 0 && spell_target->GetHP() > (*itr)->GetHP()))
spell_target = *itr;
}
}
if(!spell_target)
spell_target = m_body;
safe_delete(group);
}
else
spell_target = target;
BrainCastSpell(spell, spell_target, false);
return true;
}
return false;
}
bool Brain::BrainCastSpell(Spell* spell, Spawn* cast_on, bool calculate_run_loc) {
if (spell) {
if(calculate_run_loc) {
m_body->CalculateRunningLocation(true);
}
m_body->GetZone()->ProcessSpell(spell, m_body, cast_on);
m_spellRecovery = (int32)(Timer::GetCurrentTime2() + (spell->GetSpellData()->cast_time * 10) + (spell->GetSpellData()->recovery * 10) + 2000);
return true;
}
return false;
}
bool Brain::CheckBuffs() {
if (!m_body->GetZone()->GetSpellProcess() || m_body->EngagedInCombat() || m_body->IsCasting() || m_body->IsMezzedOrStunned() || !m_body->Alive() || m_body->IsStifled() || !HasRecovered())
return false;
Spell* spell = m_body->GetNextBuffSpell(m_body);
bool casted_on = false;
if(!(casted_on = BrainCastSpell(spell, m_body)) && m_body->IsNPC() && ((NPC*)m_body)->HasSpells()) {
Spawn* target = nullptr;
vector<Spawn*>* group = m_body->GetSpawnGroup();
if(group && group->size() > 0){
vector<Spawn*>::iterator itr;
for(itr = group->begin(); itr != group->end(); itr++){
Spawn* spawn = (*itr);
if(spawn->IsEntity() && spawn != m_body) {
if(target) {
Spell* spell = m_body->GetNextBuffSpell(spawn);
SpellEffects* se = ((Entity*)spawn)->GetSpellEffect(spell->GetSpellData()->id);
if(!se && BrainCastSpell(spell, spawn)) {
casted_on = true;
break;
}
}
}
}
}
safe_delete(group);
}
return casted_on;
}
void Brain::ProcessMelee(Entity* target, float distance) {
if(distance > rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat())
MoveCloser((Spawn*)target);
else {
if (target) {
LogWrite(NPC_AI__DEBUG, 7, "NPC_AI", "%s is within melee range of %s.", m_body->GetName(), target->GetName());
if (m_body->AttackAllowed(target)) {
LogWrite(NPC_AI__DEBUG, 7, "NPC_AI", "%s is allowed to attack %s.", m_body->GetName(), target->GetName());
if (m_body->PrimaryWeaponReady() && !m_body->IsDazed() && !m_body->IsFeared()) {
LogWrite(NPC_AI__DEBUG, 7, "NPC_AI", "%s swings its primary weapon at %s.", m_body->GetName(), target->GetName());
m_body->SetPrimaryLastAttackTime(Timer::GetCurrentTime2());
m_body->MeleeAttack(target, distance, true);
m_body->GetZone()->CallSpawnScript(m_body, SPAWN_SCRIPT_AUTO_ATTACK_TICK, target);
}
if (m_body->SecondaryWeaponReady() && !m_body->IsDazed()) {
m_body->SetSecondaryLastAttackTime(Timer::GetCurrentTime2());
m_body->MeleeAttack(target, distance, false);
}
}
}
}
}
bool Brain::HasRecovered() {
if(m_spellRecovery > Timer::GetCurrentTime2())
return false;
m_spellRecovery = 0;
return true;
}
void Brain::AddToEncounter(Entity* entity) {
// If player pet then set the entity to the pets owner
if (entity->IsPet() && entity->GetOwner() && !entity->IsBot()) {
MEncounter.writelock(__FUNCTION__, __LINE__);
bool success = AddToEncounter(entity->GetID());
MEncounter.releasewritelock(__FUNCTION__, __LINE__);
if(!success)
return;
entity = entity->GetOwner();
}
else if(entity->HasPet() && entity->GetPet()) {
MEncounter.writelock(__FUNCTION__, __LINE__);
bool success = AddToEncounter(entity->GetPet()->GetID());
MEncounter.releasewritelock(__FUNCTION__, __LINE__);
if(!success)
return;
}
// If player or bot then get the group
int32 group_id = 0;
if (entity->IsPlayer() || entity->IsBot()) {
m_playerInEncounter = true;
if (entity->GetGroupMemberInfo())
group_id = entity->GetGroupMemberInfo()->group_id;
}
// Insert the entity into the encounter list, if there is a group add all group members as well
// TODO: add raid members
MEncounter.writelock(__FUNCTION__, __LINE__);
if (group_id > 0) {
world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
deque<GroupMemberInfo*>::iterator itr;
PlayerGroup* group = world.GetGroupManager()->GetGroup(group_id);
if (group)
{
group->MGroupMembers.readlock(__FUNCTION__, __LINE__);
deque<GroupMemberInfo*>* members = group->GetMembers();
for (itr = members->begin(); itr != members->end(); itr++) {
if ((*itr)->member)
{
bool success = AddToEncounter((*itr)->member->GetID());
if((*itr)->client && success) {
m_encounter_playerlist.insert(make_pair((*itr)->client->GetPlayer()->GetCharacterID(), (*itr)->client->GetPlayer()->GetID()));
}
}
}
group->MGroupMembers.releasereadlock(__FUNCTION__, __LINE__);
}
world.GetGroupManager()->ReleaseGroupLock(__FUNCTION__, __LINE__);
}
else {
bool success = AddToEncounter(entity->GetID());
if (success && entity->IsPlayer())
{
Player* plyr = (Player*)entity;
m_encounter_playerlist.insert(make_pair(plyr->GetCharacterID(), entity->GetID()));
}
}
MEncounter.releasewritelock(__FUNCTION__, __LINE__);
}
bool Brain::CheckLootAllowed(Entity* entity) {
bool ret = false;
vector<int32>::iterator itr;
if (m_body)
{
if ((m_body->GetLootMethod() != GroupLootMethod::METHOD_LOTTO && m_body->GetLootMethod() != GroupLootMethod::METHOD_NEED_BEFORE_GREED) && m_body->GetLooterSpawnID() > 0 && m_body->GetLooterSpawnID() != entity->GetID()) {
LogWrite(LOOT__INFO, 0, "Loot", "%s: CheckLootAllowed failed, looter spawn id %u does not match received %s(%u)", GetBody()->GetName(), m_body->GetLooterSpawnID(), entity->GetName(), entity->GetID());
return false;
}
if (rule_manager.GetGlobalRule(R_Loot, AllowChestUnlockByDropTime)->GetInt8()
&& m_body->GetChestDropTime() > 0 && Timer::GetCurrentTime2() >= m_body->GetChestDropTime() + (rule_manager.GetGlobalRule(R_Loot, ChestUnlockedTimeDrop)->GetInt32() * 1000)) {
return true;
}
if (rule_manager.GetGlobalRule(R_Loot, AllowChestUnlockByTrapTime)->GetInt8()
&& m_body->GetTrapOpenedTime() > 0 && Timer::GetCurrentTime2() >= m_body->GetChestDropTime() + (rule_manager.GetGlobalRule(R_Loot, ChestUnlockedTimeTrap)->GetInt32() * 1000)) {
return true;
}
if ((m_body->GetLootMethod() == GroupLootMethod::METHOD_LOTTO || m_body->GetLootMethod() == GroupLootMethod::METHOD_NEED_BEFORE_GREED) && m_body->HasSpawnLootWindowCompleted(entity->GetID())) {
LogWrite(LOOT__INFO, 0, "Loot", "%s: CheckLootAllowed failed, looter %s(%u) has already completed their lotto selections.", GetBody()->GetName(), entity->GetName(), entity->GetID());
return false;
}
}
// Check the encounter list to see if the given entity is in it, if so return true.
MEncounter.readlock(__FUNCTION__, __LINE__);
if (entity->IsPlayer())
{
Player* plyr = (Player*)entity;
map<int32, int32>::iterator itr = m_encounter_playerlist.find(plyr->GetCharacterID());
if (itr != m_encounter_playerlist.end())
{
MEncounter.releasereadlock(__FUNCTION__, __LINE__);
return true;
}
MEncounter.releasereadlock(__FUNCTION__, __LINE__);
return false;
}
for (itr = m_encounter.begin(); itr != m_encounter.end(); itr++) {
if ((*itr) == entity->GetID()) {
// found the entity in the encounter list, set return value to true and break the loop
ret = true;
break;
}
}
MEncounter.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
int8 Brain::GetEncounterSize() {
int8 ret = 0;
MEncounter.readlock(__FUNCTION__, __LINE__);
ret = (int8)m_encounter.size();
MEncounter.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
vector<int32>* Brain::GetEncounter() {
vector<int32>* ret = new vector<int32>;
vector<int32>::iterator itr;
// Lock the list
MEncounter.readlock(__FUNCTION__, __LINE__);
// Loop over the list storing the values into the new list
for (itr = m_encounter.begin(); itr != m_encounter.end(); itr++)
ret->push_back(*itr);
// Unlock the list
MEncounter.releasereadlock(__FUNCTION__, __LINE__);
// Return the copy of the list
return ret;
}
bool Brain::IsPlayerInEncounter(int32 char_id) {
bool ret = false;
MEncounter.readlock(__FUNCTION__, __LINE__);
std::map<int32,int32>::iterator itr = m_encounter_playerlist.find(char_id);
if(itr != m_encounter_playerlist.end()) {
ret = true;
}
MEncounter.releasereadlock(__FUNCTION__, __LINE__);
return ret;
}
bool Brain::IsEntityInEncounter(int32 id, bool skip_read_lock) {
bool ret = false;
if(!skip_read_lock) {
MEncounter.readlock(__FUNCTION__, __LINE__);
}
vector<int32>::iterator itr;
for (itr = m_encounter.begin(); itr != m_encounter.end(); itr++) {
if ((*itr) == id) {
// found the entity in the encounter list, set return value to true and break the loop
ret = true;
break;
}
}
if(!skip_read_lock) {
MEncounter.releasereadlock(__FUNCTION__, __LINE__);
}
return ret;
}
int32 Brain::CountPlayerBotInEncounter() {
int32 count = 0;
vector<int32>::iterator itr;
MEncounter.readlock(__FUNCTION__, __LINE__);
for (itr = m_encounter.begin(); itr != m_encounter.end(); itr++) {
Entity* ent = (Entity*)GetBody()->GetZone()->GetSpawnByID((*itr));
if (ent && (ent->IsPlayer() || ent->IsBot())) {
count++;
}
}
MEncounter.releasereadlock(__FUNCTION__, __LINE__);
return count;
}
bool Brain::AddToEncounter(int32 id) {
if(!IsEntityInEncounter(id, true)) {
m_encounter.push_back(id);
return true;
}
return false;
}
void Brain::ClearEncounter() {
MEncounter.writelock(__FUNCTION__, __LINE__);
if(m_body) {
m_body->RemoveSpells(true);
}
m_encounter.clear();
m_encounter_playerlist.clear();
m_playerInEncounter = false;
MEncounter.releasewritelock(__FUNCTION__, __LINE__);
}
void Brain::SendEncounterList(Client* client) {
client->Message(CHANNEL_COLOR_YELLOW, "%s's EncounterList", m_body->GetName());
client->Message(CHANNEL_COLOR_YELLOW, "-------------------");
vector<int32>::iterator itr;
// Check the encounter list to see if the given entity is in it, if so return true.
MEncounter.readlock(__FUNCTION__, __LINE__);
for (itr = m_encounter.begin(); itr != m_encounter.end(); itr++) {
Entity* ent = (Entity*)GetBody()->GetZone()->GetSpawnByID((*itr));
// Compare the hate value for the current iteration to our stored highest value
if(ent) {
client->Message(CHANNEL_COLOR_YELLOW, "%s", ent->GetName());
}
else {
client->Message(CHANNEL_COLOR_YELLOW, "%u (cannot identity spawn id->entity)", (*itr));
}
}
client->Message(CHANNEL_COLOR_YELLOW, "-------------------");
MEncounter.releasereadlock(__FUNCTION__, __LINE__);
}
/* Example of how to extend the default AI */
CombatPetBrain::CombatPetBrain(NPC* body) : Brain(body) {
// Make sure to have the " : Brain(body)" so it calls the parent class constructor
// to set up the AI properly
}
CombatPetBrain::~CombatPetBrain() {
}
void CombatPetBrain::Think() {
// We are extending the base brain so make sure to call the parent Think() function.
// If we want to override then we could remove Brain::Think()
Brain::Think();
// All this Brain does is make the pet follow its owner, the combat comes from the default brain
if (GetBody()->EngagedInCombat() || !GetBody()->IsPet() || GetBody()->IsMezzedOrStunned())
return;
LogWrite(NPC_AI__DEBUG, 7, "NPC_AI", "Pet AI code called for %s", GetBody()->GetName());
// If owner is a player and player has stay set then return out
if (GetBody()->GetOwner() && GetBody()->GetOwner()->IsPlayer() && ((Player*)GetBody()->GetOwner())->GetInfoStruct()->get_pet_movement() == 1)
return;
// Set target to owner
Entity* target = GetBody()->GetOwner();
GetBody()->SetTarget(target);
// Get distance from the owner
float distance = GetBody()->GetDistance(target);
// If out of melee range then move closer
if (distance > rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat())
MoveCloser((Spawn*)target);
}
/* Example of how to override the default AI */
NonCombatPetBrain::NonCombatPetBrain(NPC* body) : Brain(body) {
// Make sure to have the " : Brain(body)" so it calls the parent class constructor
// to set up the AI properly
}
NonCombatPetBrain::~NonCombatPetBrain() {
}
void NonCombatPetBrain::Think() {
// All this Brain does is make the pet follow its owner
if (!GetBody()->IsPet() || GetBody()->IsMezzedOrStunned())
return;
LogWrite(NPC_AI__DEBUG, 7, "NPC_AI", "Pet AI code called for %s", GetBody()->GetName());
// Set target to owner
Entity* target = GetBody()->GetOwner();
GetBody()->SetTarget(target);
// Get distance from the owner
float distance = GetBody()->GetDistance(target);
// If out of melee range then move closer
if (distance > rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat())
MoveCloser((Spawn*)target);
}
BlankBrain::BlankBrain(NPC* body) : Brain(body) {
// Make sure to have the " : Brain(body)" so it calls the parent class constructor
// to set up the AI properly
SetTick(50000);
}
BlankBrain::~BlankBrain() {
}
void BlankBrain::Think() {
}
LuaBrain::LuaBrain(NPC* body) : Brain(body) {
}
LuaBrain::~LuaBrain() {
}
void LuaBrain::Think() {
if (!lua_interface)
return;
const char* script = GetBody()->GetSpawnScript();
if(script) {
if (!lua_interface->RunSpawnScript(script, "Think", GetBody(), GetBody()->GetTarget())) {
lua_interface->LogError("LUA LuaBrain error: was unable to call the Think function in the spawn script (%s)", script);
}
}
else {
LogWrite(NPC_AI__ERROR, 0, "NPC_AI", "Lua brain set on a spawn that doesn't have a script...");
}
}
DumbFirePetBrain::DumbFirePetBrain(NPC* body, Entity* target, int32 expire_time) : Brain(body) {
m_expireTime = Timer::GetCurrentTime2() + expire_time;
AddHate(target, INT_MAX);
}
DumbFirePetBrain::~DumbFirePetBrain() {
}
void DumbFirePetBrain::AddHate(Entity* entity, sint32 hate) {
if (!GetMostHated())
Brain::AddHate(entity, hate);
}
void DumbFirePetBrain::Think() {
Entity* target = GetMostHated();
if (target) {
if (!GetBody()->IsMezzedOrStunned()) {
// Set the NPC's target to the most hated entity if it is not already.
if (GetBody()->GetTarget() != target) {
GetBody()->SetTarget(target);
GetBody()->FaceTarget(target, false);
}
// target needs to be identified before combat setting
// If the NPC is not in combat then put them in combat
if (!GetBody()->EngagedInCombat()) {
//GetBody()->ClearRunningLocations();
GetBody()->CalculateRunningLocation(true);
GetBody()->InCombat(true);
}
float distance = GetBody()->GetDistance(target);
if(GetBody()->CheckLoS(target) && !GetBody()->IsCasting() && (!HasRecovered() || !ProcessSpell(target, distance))) {
LogWrite(NPC_AI__DEBUG, 7, "NPC_AI", "%s is attempting melee on %s.", GetBody()->GetName(), target->GetName());
GetBody()->FaceTarget(target, false);
ProcessMelee(target, distance);
}
}
}
else {
// No hated target or time expired, kill this mob
if (GetBody()->GetHP() > 0) {
GetBody()->KillSpawn(GetBody());
LogWrite(NPC_AI__DEBUG, 7, "NPC AI", "Dumbfire being killed because there is no target.");
}
}
if (Timer::GetCurrentTime2() > m_expireTime) {
if (GetBody()->GetHP() > 0) {
GetBody()->KillSpawn(GetBody());
LogWrite(NPC_AI__DEBUG, 7, "NPC AI", "Dumbfire being killed because timer expired.");
}
}
}

198
source/WorldServer/NPC_AI.h Normal file
View File

@ -0,0 +1,198 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NPC_AI_H__
#define __NPC_AI_H__
#include "NPC.h"
#include <vector>
#include <map>
using namespace std;
class Brain {
public:
Brain(NPC* npc);
virtual ~Brain();
/// <summary>The main loop for the brain. This will do all the AI work</summary>
virtual void Think();
/* Timer related functions */
/// <summary>Gets the time between calls to Think()</summary>
/// <returns>Time in miliseconds between calls to Think()</returns>
int16 Tick() { return m_tick; }
/// <summary>Sets the time between calls to Think()</summary>
/// <param name="time">Time in miliseconds</param>
void SetTick(int16 time) { m_tick = time; }
/// <summary>Gets the timestamp of the last call to Think()</summary>
/// <returns>Timestamp of the last call to Think()</returns>
int32 LastTick() { return m_lastTick; }
/// <summary>Sets the last tick to the given time</summary>
/// <param name="time">The time to set the last tick to</param>
void SetLastTick(int32 time) { m_lastTick = time; }
/* Hate related functions */
/// <summary>Gets the amount of hate this npc has towards the given entity</summary>
/// <param name="entity">The entity to check</param>
/// <returns>The amount of hate towards the given entity</returns>
sint32 GetHate(Entity* entity);
/// <summary>Add hate for the given entity to this NPC</summary>
/// <param name="entity">The entity we are adding to this NPC's hate list</param>
/// <param name="hate">The amount of hate to add</param>
virtual void AddHate(Entity* entity, sint32 hate);
/// <summary>Completely clears the hate list for this npc</summary>
void ClearHate();
/// <summary>Removes the given entity from this NPC's hate list</summary>
/// <param name="entity">Entity to remove from this NPC's hate list</param>
void ClearHate(Entity* entity);
/// <summary>Get the entity this NPC hates the most</summary>
/// <returns>The entity this NPC hates the most</returns>
Entity* GetMostHated();
/// <summary>Gets a percentage of hate owned by the given entity</summary>
/// <param name="entity">Entity to get the percentage for</param>
/// <returns>Percentage of hate as a sint8</returns>
sint8 GetHatePercentage(Entity* entity);
void SendHateList(Client* client);
///<summary>Gets a list of all the entities in the hate list</summary>
vector<Entity*>* GetHateList();
/* Combat related functions */
bool BrainCastSpell(Spell* spell, Spawn* cast_on, bool calculate_run_loc = true);
/// <summary></summary>
/// <param name=""></param>
/// <param name=""></param>
virtual bool ProcessSpell(Entity* target, float distance);
/// <summary></summary>
/// <returns>True if a buff starts casting</returns>
bool CheckBuffs();
/// <summary>Has the NPC make a melee attack</summary>
/// <param name="target">The target to attack</param>
/// <param name="distance">The current distance from the target</param>
void ProcessMelee(Entity* target, float distance);
/* Encounter related functions */
/// <summary>Adds the given entity and its group and raid members to the encounter list</summary>
/// <param name="entity">Entity we are adding to the encounter list</param>
void AddToEncounter(Entity* entity);
/// <summary>Checks to see if the given entity can loot the corpse</summary>
/// <param name="entity">Entity trying to loot</param>
/// <returns>True if the entity can loot</returns>
bool CheckLootAllowed(Entity* entity);
/// <summary>Gets the size of the encounter list</summary>
/// <returns>The size of the list as an int8</returns>
int8 GetEncounterSize();
/// <summary>Clears the encounter list</summary>
void ClearEncounter();
void SendEncounterList(Client* client);
/// <summary>Gets a copy of the encounter list</summary>
/// <returns>A copy of the encounter list as a vector<Entity*>*</returns>
vector<int32>* GetEncounter();
/// <summary>Checks to see if a player is in the encounter</summary>
/// <returns>True if the encounter list contains a player</returns>
bool PlayerInEncounter() { return m_playerInEncounter; }
bool IsPlayerInEncounter(int32 char_id);
bool IsEntityInEncounter(int32 id, bool skip_read_lock = false);
int32 CountPlayerBotInEncounter();
bool AddToEncounter(int32 id);
/* Helper functions*/
/// <summary>Gets the NPC this brain controls</summary>
/// <returns>The NPC this brain controls</returns>
NPC* GetBody() { return m_body; }
/// <summary>Checks to see if the NPC can cast</summary>
/// <returns>True if the NPC can cast</returns>
bool HasRecovered();
/// <summary>Tells the NPC to move closer to the given target</summary>
/// <param name="target">The target to move closer to</param>
void MoveCloser(Spawn* target);
protected:
// m_body = the npc this brain controls
NPC* m_body;
// m_spellRecovery = time stamp for when the npc can cast again
int32 m_spellRecovery;
private:
// MHateList = mutex to lock and unlock the hate list
Mutex MHateList;
// m_hatelist = the list that stores all the hate,
// entity is the entity this npc hates and the int32 is the value for how much we hate the entity
map<int32, sint32> m_hatelist;
// m_lastTick = the last time we ran this brain
int32 m_lastTick;
// m_tick = the amount of time between Think() calls in milliseconds
int16 m_tick;
// m_encounter = list of players (entities) that will get a reward (xp/loot) for killing this npc
vector<int32> m_encounter;
map<int32, int32> m_encounter_playerlist;
// MEncounter = mutex to lock and unlock the encounter list
Mutex MEncounter;
//m_playerInEncounter = true if a player is added to the encounter
bool m_playerInEncounter;
};
// Extension of the default brain for combat pets
class CombatPetBrain : public Brain {
public:
CombatPetBrain(NPC* body);
virtual ~CombatPetBrain();
void Think();
};
class NonCombatPetBrain : public Brain {
public:
NonCombatPetBrain(NPC* body);
virtual ~NonCombatPetBrain();
void Think();
};
class BlankBrain : public Brain {
public:
BlankBrain(NPC* body);
virtual ~BlankBrain();
void Think();
};
class LuaBrain : public Brain {
public:
LuaBrain(NPC* body);
virtual ~LuaBrain();
void Think();
};
class DumbFirePetBrain : public Brain {
public:
DumbFirePetBrain(NPC* body, Entity* target, int32 expire_time);
virtual ~DumbFirePetBrain();
void Think();
void AddHate(Entity* entity, sint32 hate);
private:
int32 m_expireTime;
};
#endif

View File

@ -0,0 +1,99 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#include "World.h"
#include "Object.h"
#include "Spells.h"
extern World world;
extern ConfigReader configReader;
extern MasterSpellList master_spell_list;
Object::Object(){
clickable = false;
zone_name = 0;
packet_num = 0;
appearance.activity_status = 64;
appearance.pos.state = 1;
appearance.difficulty = 0;
spawn_type = 2;
m_deviceID = 0;
}
Object::~Object(){
}
EQ2Packet* Object::serialize(Player* player, int16 version){
return spawn_serialize(player, version);
}
void Object::HandleUse(Client* client, string command){
vector<TransportDestination*> destinations;
if(GetTransporterID() > 0)
GetZone()->GetTransporters(&destinations, client, GetTransporterID());
if (destinations.size())
{
client->SetTemporaryTransportID(0);
client->ProcessTeleport(this, &destinations, GetTransporterID());
}
else if (client && command.length() > 0 && appearance.show_command_icon == 1 && MeetsSpawnAccessRequirements(client->GetPlayer())){
EntityCommand* entity_command = FindEntityCommand(command);
if (entity_command)
client->GetCurrentZone()->ProcessEntityCommand(entity_command, client->GetPlayer(), client->GetPlayer()->GetTarget());
}
}
Object* Object::Copy(){
Object* new_spawn = new Object();
new_spawn->SetCollector(IsCollector());
new_spawn->SetMerchantID(merchant_id);
new_spawn->SetMerchantType(merchant_type);
new_spawn->SetMerchantLevelRange(GetMerchantMinLevel(), GetMerchantMaxLevel());
if(GetSizeOffset() > 0){
int8 offset = GetSizeOffset()+1;
sint32 tmp_size = size + (rand()%offset - rand()%offset);
if(tmp_size < 0)
tmp_size = 1;
else if(tmp_size >= 0xFFFF)
tmp_size = 0xFFFF;
new_spawn->size = (int16)tmp_size;
}
else
new_spawn->size = size;
new_spawn->SetPrimaryCommands(&primary_command_list);
new_spawn->SetSecondaryCommands(&secondary_command_list);
new_spawn->database_id = database_id;
new_spawn->primary_command_list_id = primary_command_list_id;
new_spawn->secondary_command_list_id = secondary_command_list_id;
memcpy(&new_spawn->appearance, &appearance, sizeof(AppearanceData));
new_spawn->faction_id = faction_id;
new_spawn->target = 0;
new_spawn->SetTotalHP(GetTotalHP());
new_spawn->SetTotalPower(GetTotalPower());
new_spawn->SetHP(GetHP());
new_spawn->SetPower(GetPower());
SetQuestsRequired(new_spawn);
new_spawn->SetTransporterID(GetTransporterID());
new_spawn->SetDeviceID(GetDeviceID());
new_spawn->SetSoundsDisabled(IsSoundsDisabled());
new_spawn->SetOmittedByDBFlag(IsOmittedByDBFlag());
new_spawn->SetLootTier(GetLootTier());
new_spawn->SetLootDropType(GetLootDropType());
return new_spawn;
}

View File

@ -0,0 +1,49 @@
/*
EQ2Emulator: Everquest II Server Emulator
Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
This file is part of EQ2Emulator.
EQ2Emulator 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, either version 3 of the License, or
(at your option) any later version.
EQ2Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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 EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __EQ2_OBJECT__
#define __EQ2_OBJECT__
#include "Spawn.h"
class Object : public Spawn{
public:
Object();
virtual ~Object();
void SetClickable(bool click){
clickable = click;
}
void SetZone(char* zone){
zone_name = zone;
}
Object* Copy();
bool IsObject(){ return true; }
void HandleUse(Client* client, string command);
bool clickable;
char* zone_name;
EQ2Packet* serialize(Player* player, int16 version);
void SetDeviceID(int8 val) { m_deviceID = val; }
int8 GetDeviceID() { return m_deviceID; }
private:
int8 m_deviceID;
};
#endif

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More