-#include <cstring>\r
-#include "Common/Includes.hxx"\r
-\r
-PConfig::PConfig()\r
-{\r
- mOptValRegEx = new RegEx("^\\s*([[:graph:]]+)\\s*=\\s*(.+?)\\s*$", PCRE_CASELESS);\r
- mIncludeRegEx = new RegEx("^\\s*include\\s+([[:graph:]]+)\\s*$", PCRE_CASELESS);\r
-}\r
-\r
-PConfig::~PConfig()\r
-{\r
- delete mOptValRegEx;\r
- delete mIncludeRegEx;\r
-}\r
-\r
-bool PConfig::LoadOptions(const char* nConfigTemplate[][2], const char* nConfigFile, int nDepth)\r
-{\r
- FILE *ConfigFile;\r
- char line[255];\r
- std::string Opt, Val;\r
- //int numOptions = 0;\r
- int i;\r
- bool Found;\r
- bool NoError = true;\r
-\r
- ConfigFile = fopen(nConfigFile,"r");\r
-\r
- if(!ConfigFile)\r
- {\r
- Console->Print("%s Cant open file \"%s\"", Console->ColorText(RED, BLACK, "[Error]"), nConfigFile);\r
- return false;\r
- }\r
-\r
- if(nDepth)\r
- Console->Print("%s Including file %s (nesting level %d)", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigFile, nDepth);\r
- else\r
- Console->Print("%s Loading configuration file %s", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigFile);\r
-\r
- while(!feof(ConfigFile) && fgets(line, 255, ConfigFile))\r
- {\r
- //Console->Print("LINE: '%s'", line);\r
- if (line[0] == '/' && line[1] == '/')\r
- continue;\r
-\r
- if(mOptValRegEx->Search(line))\r
- {\r
- Opt = mOptValRegEx->Match(1);\r
- Val = mOptValRegEx->Match(2);\r
- //Console->Print("'%s'='%s'", Opt.c_str(), Val.c_str());\r
-\r
- Trim(&Opt);\r
- Trim(&Val);\r
- //Console->Print("'%s'='%s'", Opt.c_str(), Val.c_str());\r
- }\r
- else if(mIncludeRegEx->Search(line))\r
- {\r
- if(nDepth < CONFIG_MAXDEPTH)\r
- {\r
- std::string TargetName = mIncludeRegEx->Match(1);\r
- std::string StartName = nConfigFile;\r
- int BasenamePos = StartName.rfind("/");\r
- if(BasenamePos > 0)\r
- TargetName = StartName.substr(0, BasenamePos) + "/" + TargetName;\r
-\r
- NoError = LoadOptions(nConfigTemplate, TargetName.c_str(), nDepth+1) && NoError;\r
- continue;\r
- }\r
- else\r
- {\r
- Console->Print("%s Max nesting level (%d) reached. Can't include configuration file %s", Console->ColorText(RED, BLACK, "[Error]"), CONFIG_MAXDEPTH,mIncludeRegEx->Match(1));\r
- NoError = false;\r
- }\r
- }\r
- else\r
- {\r
- continue;\r
- }\r
-\r
- i = 0;\r
- Found = false;\r
- while(!Found && (nConfigTemplate[i][0][0] != '\0'))\r
- {\r
- if(!strcmp(Opt.c_str(), nConfigTemplate[i++][0]))\r
- {\r
- Found = true;\r
- break;\r
- }\r
- }\r
-\r
- if(!Opt.empty() && !Val.empty())\r
- {\r
- //Console->Print("#%d [%s] [%s]", numOptions, Opt.c_str(), Val.c_str());\r
- if (Found)\r
- {\r
- if (GetOption(Opt) != "")\r
- {\r
- Console->Print("%s trying to set option %s more than once (old value '%s' - new value '%s' ignored)", Console->ColorText(YELLOW, BLACK, "[Warning]"), Opt.c_str(), GetOption(Opt).c_str(), Val.c_str());\r
- }\r
- else\r
- {\r
- //Console->Print(GREEN, BLACK, "New option %s set to %s", Opt.c_str(), Val.c_str());\r
- mOptions.insert(std::make_pair(Opt, Val));\r
- }\r
- }\r
- else\r
- {\r
- Console->Print("%s option %s unknow and ignored (value %s)", Console->ColorText(YELLOW, BLACK, "[Warning]"), Opt.c_str(), Val.c_str());\r
- }\r
- }\r
- }\r
-\r
- // Now check for completeness and set default values when needed and available\r
- if(!nDepth) // Check only if we're at top level (ie. not in an included file)\r
- {\r
- i = 0;\r
- while(nConfigTemplate[i][0][0] != '\0')\r
- {\r
- if (GetOption(nConfigTemplate[i][0]) == "")\r
- {\r
- if(nConfigTemplate[i][1][0] == '\0')\r
- {\r
- Console->Print("%s required option %s missing from config file", Console->ColorText(RED, BLACK, "[Error]"), nConfigTemplate[i][0]);\r
- NoError = false;\r
- }\r
- else\r
- {\r
- Console->Print("%s using default value %s for option %s", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigTemplate[i][1], nConfigTemplate[i][0]);\r
- mOptions.insert(std::make_pair(nConfigTemplate[i][0], nConfigTemplate[i][1]));\r
- }\r
- }\r
- ++i;\r
- }\r
- }\r
-\r
- if (NoError)\r
- {\r
- if(nDepth)\r
- Console->Print("%s file included", Console->ColorText(GREEN, BLACK, "[Info]") );\r
- else\r
- Console->Print("%s Configuration file loaded", Console->ColorText(GREEN, BLACK, "[Success]") );\r
- }\r
- else\r
- Console->Print(RED, BLACK, "[Error] Fatal errors found in configuration file");\r
-\r
- return (NoError);\r
-}\r
-\r
-const std::string &PConfig::GetOption(const std::string Name) const\r
-{\r
- static std::string NullString = "";\r
- OptionsMap::const_iterator i = mOptions.find(Name);\r
- if(i!=mOptions.end())\r
- return i->second;\r
-\r
- return NullString;\r
-}\r
-\r
-int PConfig::GetOptionInt(const std::string Name) const\r
-{\r
- OptionsMap::const_iterator i = mOptions.find(Name);\r
- if(i!=mOptions.end())\r
- return atoi(i->second.c_str());\r
-\r
- return 0;\r
-}\r
+#include <cstring>
+#include "Common/Includes.hxx"
+
+PConfig::PConfig()
+{
+ mOptValRegEx = new RegEx("^\\s*([[:graph:]]+)\\s*=\\s*(.+?)\\s*$", PCRE_CASELESS);
+ mIncludeRegEx = new RegEx("^\\s*include\\s+([[:graph:]]+)\\s*$", PCRE_CASELESS);
+}
+
+PConfig::~PConfig()
+{
+ delete mOptValRegEx;
+ delete mIncludeRegEx;
+}
+
+bool PConfig::LoadOptions(const char* nConfigTemplate[][2], const char* nConfigFile, int nDepth)
+{
+ FILE *ConfigFile;
+ char line[255];
+ std::string Opt, Val;
+ //int numOptions = 0;
+ int i;
+ bool Found;
+ bool NoError = true;
+
+ ConfigFile = fopen(nConfigFile,"r");
+
+ if(!ConfigFile)
+ {
+ Console->Print("%s Cant open file \"%s\"", Console->ColorText(RED, BLACK, "[Error]"), nConfigFile);
+ return false;
+ }
+
+ if(nDepth)
+ Console->Print("%s Including file %s (nesting level %d)", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigFile, nDepth);
+ else
+ Console->Print("%s Loading configuration file %s", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigFile);
+
+ while(!feof(ConfigFile) && fgets(line, 255, ConfigFile))
+ {
+ //Console->Print("LINE: '%s'", line);
+ if (line[0] == '/' && line[1] == '/')
+ continue;
+
+ if(mOptValRegEx->Search(line))
+ {
+ Opt = mOptValRegEx->Match(1);
+ Val = mOptValRegEx->Match(2);
+ //Console->Print("'%s'='%s'", Opt.c_str(), Val.c_str());
+
+ Trim(&Opt);
+ Trim(&Val);
+ //Console->Print("'%s'='%s'", Opt.c_str(), Val.c_str());
+ }
+ else if(mIncludeRegEx->Search(line))
+ {
+ if(nDepth < CONFIG_MAXDEPTH)
+ {
+ std::string TargetName = mIncludeRegEx->Match(1);
+ std::string StartName = nConfigFile;
+ int BasenamePos = StartName.rfind("/");
+ if(BasenamePos > 0)
+ TargetName = StartName.substr(0, BasenamePos) + "/" + TargetName;
+
+ NoError = LoadOptions(nConfigTemplate, TargetName.c_str(), nDepth+1) && NoError;
+ continue;
+ }
+ else
+ {
+ Console->Print("%s Max nesting level (%d) reached. Can't include configuration file %s", Console->ColorText(RED, BLACK, "[Error]"), CONFIG_MAXDEPTH,mIncludeRegEx->Match(1));
+ NoError = false;
+ }
+ }
+ else
+ {
+ continue;
+ }
+
+ i = 0;
+ Found = false;
+ while(!Found && (nConfigTemplate[i][0][0] != '\0'))
+ {
+ if(!strcmp(Opt.c_str(), nConfigTemplate[i++][0]))
+ {
+ Found = true;
+ break;
+ }
+ }
+
+ if(!Opt.empty() && !Val.empty())
+ {
+ //Console->Print("#%d [%s] [%s]", numOptions, Opt.c_str(), Val.c_str());
+ if (Found)
+ {
+ if (GetOption(Opt) != "")
+ {
+ Console->Print("%s trying to set option %s more than once (old value '%s' - new value '%s' ignored)", Console->ColorText(YELLOW, BLACK, "[Warning]"), Opt.c_str(), GetOption(Opt).c_str(), Val.c_str());
+ }
+ else
+ {
+ //Console->Print(GREEN, BLACK, "New option %s set to %s", Opt.c_str(), Val.c_str());
+ mOptions.insert(std::make_pair(Opt, Val));
+ }
+ }
+ else
+ {
+ Console->Print("%s option %s unknow and ignored (value %s)", Console->ColorText(YELLOW, BLACK, "[Warning]"), Opt.c_str(), Val.c_str());
+ }
+ }
+ }
+
+ // Now check for completeness and set default values when needed and available
+ if(!nDepth) // Check only if we're at top level (ie. not in an included file)
+ {
+ i = 0;
+ while(nConfigTemplate[i][0][0] != '\0')
+ {
+ if (GetOption(nConfigTemplate[i][0]) == "")
+ {
+ if(nConfigTemplate[i][1][0] == '\0')
+ {
+ Console->Print("%s required option %s missing from config file", Console->ColorText(RED, BLACK, "[Error]"), nConfigTemplate[i][0]);
+ NoError = false;
+ }
+ else
+ {
+ Console->Print("%s using default value %s for option %s", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigTemplate[i][1], nConfigTemplate[i][0]);
+ mOptions.insert(std::make_pair(nConfigTemplate[i][0], nConfigTemplate[i][1]));
+ }
+ }
+ ++i;
+ }
+ }
+
+ if (NoError)
+ {
+ if(nDepth)
+ Console->Print("%s file included", Console->ColorText(GREEN, BLACK, "[Info]") );
+ else
+ Console->Print("%s Configuration file loaded", Console->ColorText(GREEN, BLACK, "[Success]") );
+ }
+ else
+ Console->Print(RED, BLACK, "[Error] Fatal errors found in configuration file");
+
+ return (NoError);
+}
+
+const std::string &PConfig::GetOption(const std::string Name) const
+{
+ static std::string NullString = "";
+ OptionsMap::const_iterator i = mOptions.find(Name);
+ if(i!=mOptions.end())
+ return i->second;
+
+ return NullString;
+}
+
+int PConfig::GetOptionInt(const std::string Name) const
+{
+ OptionsMap::const_iterator i = mOptions.find(Name);
+ if(i!=mOptions.end())
+ return atoi(i->second.c_str());
+
+ return 0;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <iostream>\r
-#include <map>\r
-#include <string>\r
-\r
-class RegEx;\r
-\r
-class PConfig {\r
-private:\r
- typedef std::map<std::string, std::string> OptionsMap;\r
- OptionsMap mOptions;\r
- RegEx *mOptValRegEx;\r
- RegEx *mIncludeRegEx;\r
-\r
- bool LoadOptions(const char *nConfigTemplate[][2], const char *nConfigFile, int32_t nDepth);\r
-\r
-public:\r
- PConfig();\r
- ~PConfig();\r
-\r
- inline bool LoadOptions(const char *nConfigTemplate[][2], const char *nConfigFile)\r
- { return LoadOptions(nConfigTemplate, nConfigFile, 0); }\r
- inline const std::string &GetOption(const char *Name) const { return GetOption((std::string) Name); }\r
- const std::string &GetOption(const std::string Name) const;\r
- int32_t GetOptionInt(const char *Name) const { return GetOptionInt((std::string) Name); }\r
- int32_t GetOptionInt(const std::string Name) const;\r
-};\r
-\r
-// Max nested includes\r
-#define CONFIG_MAXDEPTH 4\r
-\r
-/*\r
- The list of valid config options is now set in the array ConfigTemplate\r
- A default value can be set for each option, whiches makes the option optionnal in config file\r
- If no default value is set, the option is mandatory.\r
- Duplicate option entries in config file are also checked, and only the first value is kept\r
- Unkown options are rejected\r
- Duplicates, unkown and default use generate a warning in logs but don't break options loading\r
- Missing mandatory option generate an error in log and break option loading (imediate return false)\r
-\r
- The ConfigTemplate parameter must have the structure shown in the following exemple:\r
-\r
-const char* ConfigTemplate[][2] = {\r
- // {option_name, default_value} if default_value is empty string, it means option is mandatory\r
- // List ends with empty string for option_name\r
- {"info_sql_host", "127.0.0.1"},\r
- {"info_sql_port", "3306"},\r
- {"info_sql_username", ""},\r
- {"info_sql_password", ""},\r
- {"", ""} // do not change this line (end mark)\r
-};\r
-\r
-*/\r
-\r
-extern class PConfig* Config;\r
+#pragma once
+
+#include <cstdint>
+#include <iostream>
+#include <map>
+#include <string>
+
+class RegEx;
+
+class PConfig {
+private:
+ typedef std::map<std::string, std::string> OptionsMap;
+ OptionsMap mOptions;
+ RegEx *mOptValRegEx;
+ RegEx *mIncludeRegEx;
+
+ bool LoadOptions(const char *nConfigTemplate[][2], const char *nConfigFile, int32_t nDepth);
+
+public:
+ PConfig();
+ ~PConfig();
+
+ inline bool LoadOptions(const char *nConfigTemplate[][2], const char *nConfigFile)
+ { return LoadOptions(nConfigTemplate, nConfigFile, 0); }
+ inline const std::string &GetOption(const char *Name) const { return GetOption((std::string) Name); }
+ const std::string &GetOption(const std::string Name) const;
+ int32_t GetOptionInt(const char *Name) const { return GetOptionInt((std::string) Name); }
+ int32_t GetOptionInt(const std::string Name) const;
+};
+
+// Max nested includes
+#define CONFIG_MAXDEPTH 4
+
+/*
+ The list of valid config options is now set in the array ConfigTemplate
+ A default value can be set for each option, whiches makes the option optionnal in config file
+ If no default value is set, the option is mandatory.
+ Duplicate option entries in config file are also checked, and only the first value is kept
+ Unkown options are rejected
+ Duplicates, unkown and default use generate a warning in logs but don't break options loading
+ Missing mandatory option generate an error in log and break option loading (imediate return false)
+
+ The ConfigTemplate parameter must have the structure shown in the following exemple:
+
+const char* ConfigTemplate[][2] = {
+ // {option_name, default_value} if default_value is empty string, it means option is mandatory
+ // List ends with empty string for option_name
+ {"info_sql_host", "127.0.0.1"},
+ {"info_sql_port", "3306"},
+ {"info_sql_username", ""},
+ {"info_sql_password", ""},
+ {"", ""} // do not change this line (end mark)
+};
+
+*/
+
+extern class PConfig* Config;
-#include <cstdarg>\r
-#include <sstream>\r
-#include <cstring>\r
-#include "Common/Includes.hxx"\r
-\r
-PConsole::PConsole(const char *nLogFile)\r
-{\r
- std::time(&mLastLogTime);\r
- mLogFile.open(nLogFile);\r
-}\r
-\r
-PConsole::~PConsole()\r
-{\r
- Print("%s Shutdown complete", ColorText(GREEN, BLACK, "[Done]"));\r
- mLogFile.close();\r
-}\r
-\r
-void PConsole::Print(const char *Fmt, ...)\r
-{\r
- static char Str[2048];\r
- va_list args;\r
- va_start(args, Fmt);\r
- vsnprintf(Str, 2047, Fmt, args);\r
- va_end(args);\r
-\r
- std::time(&mLastLogTime);\r
- std::tm *now = std::localtime(&mLastLogTime);\r
-\r
- static char datestr[64];\r
- std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);\r
- std::stringstream str;\r
- str << datestr << Str << std::endl;\r
-\r
- std::printf("%s", str.str().c_str());\r
- mLogFile << str.str();\r
- mLogFile.flush();\r
-}\r
-\r
-void PConsole::Print(COLORS foreground, COLORS background, const char *Fmt, ...)\r
-{\r
- static char Str[2048];\r
- va_list args;\r
- va_start(args, Fmt);\r
- vsnprintf(Str, 2047, Fmt, args);\r
- va_end(args);\r
-\r
- char c_color[13];\r
- char c_reset[13];\r
- std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40);\r
- std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40);\r
-\r
- std::time(&mLastLogTime);\r
- std::tm *now = std::localtime(&mLastLogTime);\r
-\r
- static char datestr[64];\r
- std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);\r
- std::stringstream str;\r
- str << datestr << c_color << Str << c_reset << std::endl;\r
-\r
- std::printf("%s", str.str().c_str());\r
- mLogFile << str.str();\r
-\r
- mLogFile.flush();\r
-}\r
-\r
-char *PConsole::ColorText(COLORS foreground, COLORS background, const char *Fmt, ...)\r
-{\r
- static char Str[2048];\r
- va_list args;\r
- va_start(args, Fmt);\r
- vsnprintf(Str, 2047, Fmt, args);\r
- va_end(args);\r
-\r
- char c_color[13];\r
- char c_reset[13];\r
- std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40);\r
- std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40);\r
-\r
- static char returnbuffer[2048];\r
- strncpy (returnbuffer, c_color, 2048);\r
- strncat (returnbuffer, Str, 2047 - strlen(returnbuffer));\r
- strncat (returnbuffer, c_reset, 2047 - strlen(returnbuffer));\r
-\r
- return returnbuffer;\r
-}\r
-\r
-void PConsole::LPrint(const char *Fmt, ...)\r
-{\r
- static char Str[2048];\r
- va_list args;\r
- va_start(args, Fmt);\r
- vsnprintf(Str, 2047, Fmt, args);\r
- va_end(args);\r
-\r
- std::time(&mLastLogTime);\r
- std::tm *now = std::localtime(&mLastLogTime);\r
-\r
- static char datestr[64];\r
- std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);\r
- std::stringstream str;\r
- str << datestr << Str;\r
-\r
- std::printf("%s", str.str().c_str());\r
- mLogFile << str.str();\r
- mLogFile.flush();\r
-}\r
-\r
-void PConsole::LPrint(COLORS foreground, COLORS background, const char *Fmt, ...)\r
-{\r
- static char Str[2048];\r
- va_list args;\r
- va_start(args, Fmt);\r
- vsnprintf(Str, 2047, Fmt, args);\r
- va_end(args);\r
-\r
- char c_color[13];\r
- char c_reset[13];\r
- std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40);\r
- std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40);\r
-\r
- std::stringstream str;\r
- str << c_color << Str << c_reset;\r
-\r
- std::printf("%s", str.str().c_str());\r
- mLogFile << str.str();\r
-\r
- mLogFile.flush();\r
-}\r
-\r
-void PConsole::LClose()\r
-{\r
- std::stringstream str;\r
- str << std::endl;\r
-\r
- std::printf("%s", str.str().c_str());\r
- mLogFile << str.str();\r
-\r
- mLogFile.flush();\r
-}\r
-\r
-void PConsole::Update()\r
-{\r
- // place a marker into the log each 15 minutes if no output has been generated\r
- std::time_t t;\r
- std::time(&t);\r
- if(std::difftime(t, mLastLogTime) >= 900)\r
- Print("--MARK--");\r
-}\r
+#include <cstdarg>
+#include <sstream>
+#include <cstring>
+#include "Common/Includes.hxx"
+
+PConsole::PConsole(const char *nLogFile)
+{
+ std::time(&mLastLogTime);
+ mLogFile.open(nLogFile);
+}
+
+PConsole::~PConsole()
+{
+ Print("%s Shutdown complete", ColorText(GREEN, BLACK, "[Done]"));
+ mLogFile.close();
+}
+
+void PConsole::Print(const char *Fmt, ...)
+{
+ static char Str[2048];
+ va_list args;
+ va_start(args, Fmt);
+ vsnprintf(Str, 2047, Fmt, args);
+ va_end(args);
+
+ std::time(&mLastLogTime);
+ std::tm *now = std::localtime(&mLastLogTime);
+
+ static char datestr[64];
+ std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
+ std::stringstream str;
+ str << datestr << Str << std::endl;
+
+ std::printf("%s", str.str().c_str());
+ mLogFile << str.str();
+ mLogFile.flush();
+}
+
+void PConsole::Print(COLORS foreground, COLORS background, const char *Fmt, ...)
+{
+ static char Str[2048];
+ va_list args;
+ va_start(args, Fmt);
+ vsnprintf(Str, 2047, Fmt, args);
+ va_end(args);
+
+ char c_color[13];
+ char c_reset[13];
+ std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40);
+ std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40);
+
+ std::time(&mLastLogTime);
+ std::tm *now = std::localtime(&mLastLogTime);
+
+ static char datestr[64];
+ std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
+ std::stringstream str;
+ str << datestr << c_color << Str << c_reset << std::endl;
+
+ std::printf("%s", str.str().c_str());
+ mLogFile << str.str();
+
+ mLogFile.flush();
+}
+
+char *PConsole::ColorText(COLORS foreground, COLORS background, const char *Fmt, ...)
+{
+ static char Str[2048];
+ va_list args;
+ va_start(args, Fmt);
+ vsnprintf(Str, 2047, Fmt, args);
+ va_end(args);
+
+ char c_color[13];
+ char c_reset[13];
+ std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40);
+ std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40);
+
+ static char returnbuffer[2048];
+ strncpy (returnbuffer, c_color, 2048);
+ strncat (returnbuffer, Str, 2047 - strlen(returnbuffer));
+ strncat (returnbuffer, c_reset, 2047 - strlen(returnbuffer));
+
+ return returnbuffer;
+}
+
+void PConsole::LPrint(const char *Fmt, ...)
+{
+ static char Str[2048];
+ va_list args;
+ va_start(args, Fmt);
+ vsnprintf(Str, 2047, Fmt, args);
+ va_end(args);
+
+ std::time(&mLastLogTime);
+ std::tm *now = std::localtime(&mLastLogTime);
+
+ static char datestr[64];
+ std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
+ std::stringstream str;
+ str << datestr << Str;
+
+ std::printf("%s", str.str().c_str());
+ mLogFile << str.str();
+ mLogFile.flush();
+}
+
+void PConsole::LPrint(COLORS foreground, COLORS background, const char *Fmt, ...)
+{
+ static char Str[2048];
+ va_list args;
+ va_start(args, Fmt);
+ vsnprintf(Str, 2047, Fmt, args);
+ va_end(args);
+
+ char c_color[13];
+ char c_reset[13];
+ std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40);
+ std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40);
+
+ std::stringstream str;
+ str << c_color << Str << c_reset;
+
+ std::printf("%s", str.str().c_str());
+ mLogFile << str.str();
+
+ mLogFile.flush();
+}
+
+void PConsole::LClose()
+{
+ std::stringstream str;
+ str << std::endl;
+
+ std::printf("%s", str.str().c_str());
+ mLogFile << str.str();
+
+ mLogFile.flush();
+}
+
+void PConsole::Update()
+{
+ // place a marker into the log each 15 minutes if no output has been generated
+ std::time_t t;
+ std::time(&t);
+ if(std::difftime(t, mLastLogTime) >= 900)
+ Print("--MARK--");
+}
-#pragma once\r
-\r
-#include <chrono>\r
-#include <fstream>\r
-\r
-enum COLORS {\r
- BLACK,\r
- RED,\r
- GREEN,\r
- YELLOW,\r
- BLUE,\r
- MAGENTA,\r
- CYAN,\r
- WHITE\r
-};\r
-\r
-class PConsole {\r
-private:\r
- std::ofstream mLogFile;\r
- time_t mLastLogTime;\r
-\r
-public:\r
- PConsole(const char *nLogFile);\r
- ~PConsole();\r
- void Print(const char *Fmt_, ...);\r
- void Print(COLORS foreground, COLORS background, const char *Fmt_, ...);\r
- char *ColorText(COLORS foreground, COLORS background, const char *Fmt, ...);\r
-\r
- void LPrint(const char *Fmt_, ...);\r
- void LPrint(COLORS foreground, COLORS background, const char *Fmt_, ...);\r
- void LClose();\r
- void Update();\r
-};\r
-\r
-extern class PConsole *Console;\r
+#pragma once
+
+#include <chrono>
+#include <fstream>
+
+enum COLORS {
+ BLACK,
+ RED,
+ GREEN,
+ YELLOW,
+ BLUE,
+ MAGENTA,
+ CYAN,
+ WHITE
+};
+
+class PConsole {
+private:
+ std::ofstream mLogFile;
+ time_t mLastLogTime;
+
+public:
+ PConsole(const char *nLogFile);
+ ~PConsole();
+ void Print(const char *Fmt_, ...);
+ void Print(COLORS foreground, COLORS background, const char *Fmt_, ...);
+ char *ColorText(COLORS foreground, COLORS background, const char *Fmt, ...);
+
+ void LPrint(const char *Fmt_, ...);
+ void LPrint(COLORS foreground, COLORS background, const char *Fmt_, ...);
+ void LClose();
+ void Update();
+};
+
+extern class PConsole *Console;
-#include <cstring>\r
-#include <sstream>\r
-#include <zlib.h>\r
-#include "Common/Includes.hxx"\r
-\r
-const int8_t DELIM = '/';\r
-\r
-PFile::PFile()\r
-{\r
- mDataSize=0;\r
- mDataOffs=0;\r
-}\r
-\r
-PFile::~PFile()\r
-{\r
-}\r
-\r
-bool PFile::ReadData(FILE *F, uint32_t Size)\r
-{\r
- mBuffer.reserve(Size);\r
- std::fread(&mBuffer[0], 1, Size, F);\r
- mDataSize = Size;\r
- return true;\r
-}\r
-\r
-bool PFile::ReadUnpakData(FILE *F, uint32_t Size, uint32_t UncSize)\r
-{\r
- std::vector<int8_t> temp;\r
- temp.reserve(Size);\r
- mBuffer.reserve(UncSize);\r
-\r
- std::fread(&temp[0], 1, Size, F);\r
-\r
- unsigned long us=UncSize;\r
- unsigned long s=Size;\r
- uncompress(reinterpret_cast<Bytef *>(&mBuffer[0]), &us, reinterpret_cast<const Bytef *>(&temp[0]), s);\r
- mDataSize=us;\r
- return true;\r
-}\r
-\r
-int PFile::Read(void *Dest, uint32_t DestSize)\r
-{\r
- int m = std::min(mDataSize-mDataOffs, DestSize);\r
- if (m <= 0)\r
- return 0;\r
- memcpy(Dest, &mBuffer[mDataOffs], m);\r
- mDataOffs+=m;\r
- return m;\r
-}\r
-\r
-void PFile::Seek(uint32_t Offset)\r
-{\r
- mDataOffs = std::min(mDataSize-1, Offset);\r
-}\r
-\r
-std::string PFile::ReadString()\r
-{\r
- int l=0;\r
- int s=mDataOffs;\r
- char last=0;\r
- while(mDataOffs < mDataSize && last!='\n')\r
- {\r
- last=mBuffer[mDataOffs++];\r
- l++;\r
- }\r
-\r
- char *str = new char[l+1];\r
- std::memcpy(str, &mBuffer[s], l);\r
- str[l]=0;\r
-\r
- std::string Result = str;\r
- delete str;\r
- return Result;\r
-}\r
-\r
-// ---------------\r
-\r
-PFileSystem::PFileSystem()\r
-{\r
-}\r
-\r
-PFileSystem::~PFileSystem()\r
-{\r
- for(PPakFiles::iterator i=mPaks.begin(); i!=mPaks.end(); i++)\r
- {\r
- PPakFileList *list = i->second;\r
- for(PPakFileList::iterator j=list->begin(); j!=list->end(); j++)\r
- delete j->second;\r
- delete i->second;\r
- }\r
-}\r
-\r
-PFileSystem::PPakFileList* PFileSystem::CachePak(const std::string &Pak, FILE *F)\r
-{\r
- PPakFiles::iterator n = mPaks.find(Pak);\r
- if(n != mPaks.end())\r
- return n->second;\r
-\r
- if(!F)\r
- return 0;\r
-\r
- PPakFileList *Result = 0;\r
-\r
- int off = std::ftell(F);\r
- std::fseek(F, 0, SEEK_SET);\r
- PPakHeader header;\r
- std::fread(&header, 1, sizeof(header), F);\r
- if(header.mID==0x3d458cde && header.mNumFiles > 0)\r
- {\r
- Result = new PPakFileList();\r
- for(int i=0; i<header.mNumFiles; i++)\r
- {\r
- PPakFileHeader *h = new PPakFileHeader();\r
- std::fread(h, 1, 20, F);\r
- h->mFilename = new char[h->mNameLen+1];\r
- std::fread(h->mFilename, 1, h->mNameLen, F);\r
- Result->insert(std::make_pair(h->mFilename, h));\r
- }\r
- mPaks.insert(std::make_pair(Pak, Result));\r
-//Console->Print("%s: %i files registered", Pak.c_str(), header.mNumFiles);\r
- } else\r
- {\r
- Console->Print("%s: invalid pakfile", Pak.c_str());\r
- }\r
- std::fseek(F, off, SEEK_SET);\r
- return Result;\r
-}\r
-\r
-void PFileSystem::ClearCache()\r
-{\r
- PFileSystem::PPakFiles::iterator nPak;\r
- PFileSystem::PPakFileList::iterator nFList;\r
- PPakFileHeader* FHeader;\r
- PFileSystem::PPakFileList* FList;\r
- \r
- for( nPak = mPaks.begin(); nPak != mPaks.end(); nPak++)\r
- {\r
- FList = nPak->second;\r
- for( nFList = FList->begin(); nFList != FList->end(); nFList++)\r
- {\r
- FHeader = nFList->second;\r
- FList->erase(nFList);\r
- delete[] FHeader->mFilename;\r
- delete FHeader;\r
- }\r
- mPaks.erase(nPak);\r
- delete FList;\r
- }\r
-}\r
-\r
-void splitpath(const std::string& file, std::string& path, std::string& name, std::string& ext)\r
-{\r
- unsigned long pos = file.rfind(DELIM);\r
-\r
- if (pos == std::string::npos)\r
- {\r
- path = "";\r
- name = file;\r
- }\r
- else\r
- {\r
- path = file.substr(0, pos);\r
- name = file.substr(pos + 1);\r
- }\r
-\r
- pos = name.rfind('.');\r
- if (pos == std::string::npos)\r
- {\r
- ext = "";\r
- }\r
- else\r
- {\r
- ext = name.substr(pos + 1);\r
- name = name.substr(0, pos);\r
- }\r
-}\r
-\r
-PFile *PFileSystem::Open(const std::string& Package, const char *File, std::string BasePath)\r
-{\r
- std::string name = "";\r
- std::string ext = "";\r
- std::string path = "";\r
- splitpath(File, path, name, ext);\r
-\r
- std::string pak2;\r
- std::string name2;\r
-\r
- if ((BasePath == ".") || (BasePath == "./"))\r
- {\r
- BasePath = "";\r
- }\r
- else\r
- {\r
- if (BasePath.substr(0, 2) == "./")\r
- {\r
- BasePath = BasePath.substr(2, BasePath.length() -2);\r
- }\r
- if ( BasePath[BasePath.length()-1] != '/' )\r
- {\r
- BasePath += '/';\r
- }\r
- }\r
-//Console->Print("Basepath:%s", BasePath.c_str());\r
- \r
- std::string pak = Package;\r
- if(pak=="")\r
- {\r
- pak=path;\r
- if (path.substr(0, 2) == "./")\r
- {\r
- path = path.substr(2, path.length() -2);\r
- }\r
- unsigned long pos = path.find(DELIM);\r
- if (pos == std::string::npos)\r
- {\r
- pak2 = path;\r
- name2 = name;\r
- }\r
- else\r
- {\r
- pak2 = path.substr(0, pos);\r
- name2 = path.substr(pos + 1) + '\\' + name;\r
- pos = name2.find(DELIM);\r
- while (pos != std::string::npos)\r
- {\r
- name2[pos] = '\\';\r
- pos = name2.find(DELIM);\r
- }\r
- }\r
- } \r
-\r
- std::stringstream package;\r
- //package << pak << ".pak" << '\0';\r
- package << BasePath << pak2 << ".pak" << '\0';\r
- std::stringstream fname;\r
- fname << BasePath << pak << '/' << name << "." << ext << '\0';\r
- std::stringstream pakname;\r
- pakname << BasePath << pak << "/pak_" << name << "." << ext << '\0';\r
-\r
- std::FILE *f = std::fopen(fname.str().c_str(), "rb");\r
- if(f)\r
- {\r
- PFile *Result = new PFile();\r
- std::fseek(f, 0, SEEK_END);\r
- int s = std::ftell(f);\r
- std::fseek(f, 0, SEEK_SET);\r
- Result->ReadData(f, s);\r
- std::fclose(f);\r
- return Result;\r
- }\r
-//else\r
-// Console->Print("File not found:%s", fname.str().c_str());\r
- f = std::fopen(pakname.str().c_str(), "rb");\r
- if(f)\r
- {\r
- PFile *Result = new PFile();\r
- std::fseek(f, 0, SEEK_END);\r
- int s = std::ftell(f)-16;\r
- std::fseek(f, 12, SEEK_SET);\r
- int os;\r
- std::fread(&os, 1, 4, f);\r
- Result->ReadUnpakData(f, s, os);\r
- std::fclose(f);\r
- return Result;\r
- }\r
-//else\r
-// Console->Print("Pak_ not found:%s", pakname.str().c_str());\r
- \r
-//Console->Print("Serching package %s, file %s.%s", package.str().c_str(), name2.c_str(), ext.c_str());\r
- f = std::fopen(package.str().c_str(), "rb");\r
- if(f)\r
- {\r
- //std::string filename = name;\r
- std::string filename = name2 + "." + ext;\r
- //filename.append(ext);\r
-\r
- PPakFileHeader *file = 0;\r
- PPakFileList *list = CachePak(std::string(package.str()), f);\r
- for(PPakFileList::iterator i=list->begin(); i!=list->end(); i++)\r
- {\r
- PPakFileHeader *h = i->second;\r
- if(!strcasecmp(i->first.c_str(), filename.c_str()))\r
- {\r
- file = h;\r
- break;\r
- }\r
- }\r
- PFile *Result = 0;\r
- if(list && file)\r
- {\r
- Result = new PFile();\r
- std::fseek(f, file->mOffset, SEEK_SET);\r
- Result->ReadUnpakData(f, file->mCompressedSize, file->mUncompressedSize);\r
-//Console->Print("%s, %s: file found", package.str().c_str(), filename.c_str());\r
- }\r
- else\r
- {\r
- if(!list)\r
- //Console->Print("%s, %s: pak error", Package.c_str(), File);\r
- Console->Print("%s, %s: pak error", package.str().c_str(), File);\r
-//else\r
-//if(!file)\r
-//Console->Print("%s, %s: file not found", Package.c_str(), File);\r
-// Console->Print("%s, %s: file not found", package.str().c_str(), filename.c_str());\r
- }\r
-\r
- std::fclose(f);\r
- return Result;\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-bool PFileSystem::Close(PFile *File)\r
-{\r
- delete File;\r
- return true;\r
-}\r
-\r
+#include <cstring>
+#include <sstream>
+#include <zlib.h>
+#include "Common/Includes.hxx"
+
+const int8_t DELIM = '/';
+
+PFile::PFile()
+{
+ mDataSize=0;
+ mDataOffs=0;
+}
+
+PFile::~PFile()
+{
+}
+
+bool PFile::ReadData(FILE *F, uint32_t Size)
+{
+ mBuffer.reserve(Size);
+ std::fread(&mBuffer[0], 1, Size, F);
+ mDataSize = Size;
+ return true;
+}
+
+bool PFile::ReadUnpakData(FILE *F, uint32_t Size, uint32_t UncSize)
+{
+ std::vector<int8_t> temp;
+ temp.reserve(Size);
+ mBuffer.reserve(UncSize);
+
+ std::fread(&temp[0], 1, Size, F);
+
+ unsigned long us=UncSize;
+ unsigned long s=Size;
+ uncompress(reinterpret_cast<Bytef *>(&mBuffer[0]), &us, reinterpret_cast<const Bytef *>(&temp[0]), s);
+ mDataSize=us;
+ return true;
+}
+
+int PFile::Read(void *Dest, uint32_t DestSize)
+{
+ int m = std::min(mDataSize-mDataOffs, DestSize);
+ if (m <= 0)
+ return 0;
+ memcpy(Dest, &mBuffer[mDataOffs], m);
+ mDataOffs+=m;
+ return m;
+}
+
+void PFile::Seek(uint32_t Offset)
+{
+ mDataOffs = std::min(mDataSize-1, Offset);
+}
+
+std::string PFile::ReadString()
+{
+ int l=0;
+ int s=mDataOffs;
+ char last=0;
+ while(mDataOffs < mDataSize && last!='\n')
+ {
+ last=mBuffer[mDataOffs++];
+ l++;
+ }
+
+ char *str = new char[l+1];
+ std::memcpy(str, &mBuffer[s], l);
+ str[l]=0;
+
+ std::string Result = str;
+ delete str;
+ return Result;
+}
+
+// ---------------
+
+PFileSystem::PFileSystem()
+{
+}
+
+PFileSystem::~PFileSystem()
+{
+ for(PPakFiles::iterator i=mPaks.begin(); i!=mPaks.end(); i++)
+ {
+ PPakFileList *list = i->second;
+ for(PPakFileList::iterator j=list->begin(); j!=list->end(); j++)
+ delete j->second;
+ delete i->second;
+ }
+}
+
+PFileSystem::PPakFileList* PFileSystem::CachePak(const std::string &Pak, FILE *F)
+{
+ PPakFiles::iterator n = mPaks.find(Pak);
+ if(n != mPaks.end())
+ return n->second;
+
+ if(!F)
+ return 0;
+
+ PPakFileList *Result = 0;
+
+ int off = std::ftell(F);
+ std::fseek(F, 0, SEEK_SET);
+ PPakHeader header;
+ std::fread(&header, 1, sizeof(header), F);
+ if(header.mID==0x3d458cde && header.mNumFiles > 0)
+ {
+ Result = new PPakFileList();
+ for(int i=0; i<header.mNumFiles; i++)
+ {
+ PPakFileHeader *h = new PPakFileHeader();
+ std::fread(h, 1, 20, F);
+ h->mFilename = new char[h->mNameLen+1];
+ std::fread(h->mFilename, 1, h->mNameLen, F);
+ Result->insert(std::make_pair(h->mFilename, h));
+ }
+ mPaks.insert(std::make_pair(Pak, Result));
+//Console->Print("%s: %i files registered", Pak.c_str(), header.mNumFiles);
+ } else
+ {
+ Console->Print("%s: invalid pakfile", Pak.c_str());
+ }
+ std::fseek(F, off, SEEK_SET);
+ return Result;
+}
+
+void PFileSystem::ClearCache()
+{
+ PFileSystem::PPakFiles::iterator nPak;
+ PFileSystem::PPakFileList::iterator nFList;
+ PPakFileHeader* FHeader;
+ PFileSystem::PPakFileList* FList;
+
+ for( nPak = mPaks.begin(); nPak != mPaks.end(); nPak++)
+ {
+ FList = nPak->second;
+ for( nFList = FList->begin(); nFList != FList->end(); nFList++)
+ {
+ FHeader = nFList->second;
+ FList->erase(nFList);
+ delete[] FHeader->mFilename;
+ delete FHeader;
+ }
+ mPaks.erase(nPak);
+ delete FList;
+ }
+}
+
+void splitpath(const std::string& file, std::string& path, std::string& name, std::string& ext)
+{
+ unsigned long pos = file.rfind(DELIM);
+
+ if (pos == std::string::npos)
+ {
+ path = "";
+ name = file;
+ }
+ else
+ {
+ path = file.substr(0, pos);
+ name = file.substr(pos + 1);
+ }
+
+ pos = name.rfind('.');
+ if (pos == std::string::npos)
+ {
+ ext = "";
+ }
+ else
+ {
+ ext = name.substr(pos + 1);
+ name = name.substr(0, pos);
+ }
+}
+
+PFile *PFileSystem::Open(const std::string& Package, const char *File, std::string BasePath)
+{
+ std::string name = "";
+ std::string ext = "";
+ std::string path = "";
+ splitpath(File, path, name, ext);
+
+ std::string pak2;
+ std::string name2;
+
+ if ((BasePath == ".") || (BasePath == "./"))
+ {
+ BasePath = "";
+ }
+ else
+ {
+ if (BasePath.substr(0, 2) == "./")
+ {
+ BasePath = BasePath.substr(2, BasePath.length() -2);
+ }
+ if ( BasePath[BasePath.length()-1] != '/' )
+ {
+ BasePath += '/';
+ }
+ }
+//Console->Print("Basepath:%s", BasePath.c_str());
+
+ std::string pak = Package;
+ if(pak=="")
+ {
+ pak=path;
+ if (path.substr(0, 2) == "./")
+ {
+ path = path.substr(2, path.length() -2);
+ }
+ unsigned long pos = path.find(DELIM);
+ if (pos == std::string::npos)
+ {
+ pak2 = path;
+ name2 = name;
+ }
+ else
+ {
+ pak2 = path.substr(0, pos);
+ name2 = path.substr(pos + 1) + '\\' + name;
+ pos = name2.find(DELIM);
+ while (pos != std::string::npos)
+ {
+ name2[pos] = '\\';
+ pos = name2.find(DELIM);
+ }
+ }
+ }
+
+ std::stringstream package;
+ //package << pak << ".pak" << '\0';
+ package << BasePath << pak2 << ".pak" << '\0';
+ std::stringstream fname;
+ fname << BasePath << pak << '/' << name << "." << ext << '\0';
+ std::stringstream pakname;
+ pakname << BasePath << pak << "/pak_" << name << "." << ext << '\0';
+
+ std::FILE *f = std::fopen(fname.str().c_str(), "rb");
+ if(f)
+ {
+ PFile *Result = new PFile();
+ std::fseek(f, 0, SEEK_END);
+ int s = std::ftell(f);
+ std::fseek(f, 0, SEEK_SET);
+ Result->ReadData(f, s);
+ std::fclose(f);
+ return Result;
+ }
+//else
+// Console->Print("File not found:%s", fname.str().c_str());
+ f = std::fopen(pakname.str().c_str(), "rb");
+ if(f)
+ {
+ PFile *Result = new PFile();
+ std::fseek(f, 0, SEEK_END);
+ int s = std::ftell(f)-16;
+ std::fseek(f, 12, SEEK_SET);
+ int os;
+ std::fread(&os, 1, 4, f);
+ Result->ReadUnpakData(f, s, os);
+ std::fclose(f);
+ return Result;
+ }
+//else
+// Console->Print("Pak_ not found:%s", pakname.str().c_str());
+
+//Console->Print("Serching package %s, file %s.%s", package.str().c_str(), name2.c_str(), ext.c_str());
+ f = std::fopen(package.str().c_str(), "rb");
+ if(f)
+ {
+ //std::string filename = name;
+ std::string filename = name2 + "." + ext;
+ //filename.append(ext);
+
+ PPakFileHeader *file = 0;
+ PPakFileList *list = CachePak(std::string(package.str()), f);
+ for(PPakFileList::iterator i=list->begin(); i!=list->end(); i++)
+ {
+ PPakFileHeader *h = i->second;
+ if(!strcasecmp(i->first.c_str(), filename.c_str()))
+ {
+ file = h;
+ break;
+ }
+ }
+ PFile *Result = 0;
+ if(list && file)
+ {
+ Result = new PFile();
+ std::fseek(f, file->mOffset, SEEK_SET);
+ Result->ReadUnpakData(f, file->mCompressedSize, file->mUncompressedSize);
+//Console->Print("%s, %s: file found", package.str().c_str(), filename.c_str());
+ }
+ else
+ {
+ if(!list)
+ //Console->Print("%s, %s: pak error", Package.c_str(), File);
+ Console->Print("%s, %s: pak error", package.str().c_str(), File);
+//else
+//if(!file)
+//Console->Print("%s, %s: file not found", Package.c_str(), File);
+// Console->Print("%s, %s: file not found", package.str().c_str(), filename.c_str());
+ }
+
+ std::fclose(f);
+ return Result;
+ }
+
+ return 0;
+}
+
+bool PFileSystem::Close(PFile *File)
+{
+ delete File;
+ return true;
+}
+
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <map>\r
-#include <vector>\r
-\r
-class PFile {\r
- friend class PFileSystem;\r
-private:\r
- std::vector<int8_t> mBuffer;\r
- uint32_t mDataSize;\r
- uint32_t mDataOffs;\r
- bool ReadData(FILE *F, uint32_t Size);\r
- bool ReadUnpakData(FILE *F, uint32_t Size, uint32_t UncSize);\r
-\r
-public:\r
- PFile();\r
- ~PFile();\r
- inline bool Eof() { return mDataOffs>=mDataSize; }\r
- int Read(void *Dest, uint32_t DestSize);\r
- void Seek(uint32_t Offset);\r
- std::string ReadString();\r
- inline uint32_t GetSize() const { return mDataSize; }\r
-};\r
-\r
-#pragma pack(push, 1)\r
-struct PPakHeader {\r
- int mID;\r
- int mNumFiles;\r
-};\r
-\r
-struct PPakFileHeader {\r
- int mUnknown0;\r
- int mOffset;\r
- int mCompressedSize;\r
- int mUncompressedSize;\r
- int mNameLen; // including 0\r
- char *mFilename;\r
-};\r
-#pragma pack(pop)\r
-\r
-class PFileSystem {\r
-private:\r
- typedef std::map<std::string, PPakFileHeader*> PPakFileList;\r
- typedef std::map<std::string, PPakFileList*> PPakFiles;\r
- PPakFiles mPaks;\r
- PPakFileList *CachePak(const std::string &Pak, FILE *F);\r
-\r
-public:\r
- PFileSystem();\r
- ~PFileSystem();\r
- PFile *Open(const std::string &Package, const char *File, std::string BasePath);\r
- bool Close(PFile *File);\r
- void ClearCache();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <map>
+#include <vector>
+
+class PFile {
+ friend class PFileSystem;
+private:
+ std::vector<int8_t> mBuffer;
+ uint32_t mDataSize;
+ uint32_t mDataOffs;
+ bool ReadData(FILE *F, uint32_t Size);
+ bool ReadUnpakData(FILE *F, uint32_t Size, uint32_t UncSize);
+
+public:
+ PFile();
+ ~PFile();
+ inline bool Eof() { return mDataOffs>=mDataSize; }
+ int Read(void *Dest, uint32_t DestSize);
+ void Seek(uint32_t Offset);
+ std::string ReadString();
+ inline uint32_t GetSize() const { return mDataSize; }
+};
+
+#pragma pack(push, 1)
+struct PPakHeader {
+ int mID;
+ int mNumFiles;
+};
+
+struct PPakFileHeader {
+ int mUnknown0;
+ int mOffset;
+ int mCompressedSize;
+ int mUncompressedSize;
+ int mNameLen; // including 0
+ char *mFilename;
+};
+#pragma pack(pop)
+
+class PFileSystem {
+private:
+ typedef std::map<std::string, PPakFileHeader*> PPakFileList;
+ typedef std::map<std::string, PPakFileList*> PPakFiles;
+ PPakFiles mPaks;
+ PPakFileList *CachePak(const std::string &Pak, FILE *F);
+
+public:
+ PFileSystem();
+ ~PFileSystem();
+ PFile *Open(const std::string &Package, const char *File, std::string BasePath);
+ bool Close(PFile *File);
+ void ClearCache();
+};
-#include <cstdarg>\r
-#include <cstring>\r
-#include <arpa/inet.h>\r
-#include "Common/Includes.hxx"\r
-\r
-uint32_t IPStringToDWord( const char *IP )\r
-{\r
- if ( !IP )\r
- return 0;\r
-\r
- uint32_t a, b, c, d;\r
- if ( std::sscanf( IP, "%u.%u.%u.%u", &a, &b, &c, &d ) != 4 )\r
- return 0;\r
-\r
- return ( d << 24 ) | ( c << 16 ) | ( b << 8 ) | a;\r
-}\r
-\r
-char *IPlongToString( const uint32_t IP )\r
-{\r
- struct in_addr in_IP;\r
-\r
- in_IP.s_addr = IP;\r
- return inet_ntoa( in_IP );\r
-}\r
-\r
-//NEW\r
-//this function allow to print a packet\r
-//just for tracking values\r
-void PrintPacket( uint8_t *Packet, int PacketSize )\r
-{\r
- Console->Print( "inside : PrintPacket" );\r
-\r
- if ( PacketSize < 1 ){Console->Print( "Wrong packet" );}//do nothing\r
- else\r
- {\r
- Console->Print( "PacketSize is : %d", PacketSize );\r
-\r
- uint8_t value = 0;\r
- for ( int i = 0;i < PacketSize;i++ )\r
- {\r
- value = *( uint8_t* ) & Packet[i];\r
- Console->Print( "value[%d] is : %x", i, value );\r
- }\r
- }\r
-\r
-}//end function\r
-\r
-void CleanUpString(std::string *nString)\r
-{\r
- if(!nString)\r
- return;\r
-\r
- // Skip if string is >" "<\r
- if(nString->length() > 3)\r
- {\r
- size_t tfound;\r
- std::string t_replacechr ("\"");\r
-\r
- tfound = nString->find(t_replacechr);\r
- while(tfound != std::string::npos)\r
- {\r
- nString->replace(tfound, 1, " ");\r
- tfound = nString->find( t_replacechr, tfound +1 );\r
- }\r
- // Skip if string consists of spaces now\r
- if(strncmp(nString->c_str(), " ", 3) == 0)\r
- {\r
- // Set empty\r
- *nString = "";\r
- }\r
- else\r
- {\r
- // Trim spaces\r
- Trim(nString);\r
- }\r
- }\r
- else\r
- {\r
- *nString = "";\r
- }\r
-}\r
-\r
-\r
-void Trim( char *t )\r
-{\r
- RTrim( t );\r
- if ( strlen( t ) )\r
- LTrim( t );\r
-}\r
-\r
-void Trim( std::string *stString )\r
-{\r
- RTrim( stString );\r
- if ( stString->length() )\r
- LTrim( stString );\r
-}\r
-\r
-void RTrim( char *t )\r
-{\r
- char *buf;\r
-\r
- if ( !strlen( t ) ) return;\r
-\r
- buf = t;\r
- buf += strlen( t ) - 1;\r
-\r
- while ( *buf == ' ' && strlen( t ) )\r
- *buf-- = '\0';\r
-}\r
-\r
-void RTrim( std::string *stString )\r
-{\r
- int i; //Count VAR\r
-\r
- if ( !stString->length() ) //If There Is No Length\r
- return;\r
-\r
- i = stString->length() - 1; //Set The Counter To The String Length -1\r
-\r
- while ( stString->substr( i, 1 ) == " " ) //While There Is Still " "\r
- {\r
- *stString = stString->substr( 0, i ); //Remove Off The End Of The String\r
- i--; //Advance The Counter\r
- }\r
-\r
-}\r
-\r
-void LTrim( char *t )\r
-{\r
- char tmp[2048]; //Temp Char VAR\r
- char *buf; //Pointer\r
-\r
- if ( !strlen( t ) ) return;\r
-\r
- strncpy( tmp, t, 2048 );\r
- tmp[2047] = 0;\r
- buf = tmp;\r
-\r
- while ( *buf == ' ' && strlen( buf ) ) *buf++;\r
-\r
- strncpy( t, buf, 2048 ); // just because without length is forbidden !\r
-}\r
-\r
-void LTrim( std::string *stString )\r
-{\r
- unsigned int i; //Count VAR\r
- std::string buf; //Temp String VAR\r
-\r
- if ( !stString->length() ) return; //If The Length Is 0\r
-\r
- i = 0; //Setup The Counter VAR\r
-\r
- while ( stString->substr( i, 1 ) == " " ) //While " "\r
- i++; //Increase Counter\r
-\r
- if ( i == stString->length() ) //If The Whole String Is " "\r
- {\r
- *stString = ""; //Return Blank String\r
- return;\r
- }\r
-\r
- try\r
- {\r
- *stString = stString->substr( i, stString->length() - i ); //Send The String Back Without The Spaces\r
- }\r
- catch ( ... )\r
- {\r
- *stString = ""; //Return Blank String\r
- return;\r
- }\r
-\r
-}\r
-\r
-std::string GetAccessString( int level )\r
-{\r
- switch ( level )\r
- {\r
- case 0: return "Unregistered";\r
- case 1: return "Registered";\r
- case 30: return "Volunteer";\r
- case 50: return "Gamemaster";\r
- case 100: return "Administrator";\r
- }\r
- return "Error";\r
-}\r
-\r
-std::string &Ssprintf( const char *fmt, ... )\r
-{\r
- static std::string tmpstring;\r
- char buff[1024];\r
- va_list args;\r
-\r
- va_start( args, fmt );\r
- vsnprintf( buff, 1024, fmt, args );\r
- va_end( args );\r
- buff[1023] = '\0';\r
- tmpstring = buff;\r
- return tmpstring;\r
-}\r
-\r
-uint16_t DistanceApprox( const uint16_t x1, const uint16_t y1, const uint16_t z1, const uint16_t x2, const uint16_t y2, const uint16_t z2 )\r
-{\r
- uint16_t DX, DY, DZ, DMax;\r
- uint32_t DMinSum, DApprox;\r
-\r
- DMax = DX = ( x1 >= x2 ) ? x1 - x2 : x2 - x1;\r
- DMinSum = DY = ( y1 >= y2 ) ? y1 - y2 : y2 - y1;\r
- DZ = ( z1 >= z2 ) ? z1 - z2 : z2 - z1;\r
- if ( DX < DY )\r
- {\r
- DMax = DY;\r
- DMinSum = DX;\r
- }\r
- if ( DMax < DZ )\r
- {\r
- DMinSum += DMax;\r
- DMax = DZ;\r
- }\r
- else\r
- {\r
- DMinSum += DZ;\r
- }\r
-\r
- DApprox = DMax + ( uint32_t )( 0.33 * DMinSum );\r
- if ( DApprox > 65535 )\r
- {\r
- DApprox = 65535;\r
- }\r
-\r
- // We use Dapprox = max(dx, dy) + K * min(dx, dy)\r
- // Dapprox = (DX > DY) ? DX + (DY >> 1) : DY + (DX >> 1); // Fastest, but max error on dist is around 10% real dist\r
- //Dapprox = (u16)((DX > DY) ? DX + 0.33*DY : DY + 0.33*DX); // max error on dist is around 5%, which should be enough\r
- /*\r
- // for dist approx debug\r
- float fDX, fDY, fDZ, fDist;\r
- fDX=(x1 - x2);\r
- fDY=(y1 - y2);\r
- fDZ=(z1 - z2);\r
- fDist=sqrt(fDX*fDX + fDY*fDY + fDZ*fDZ);\r
- if (fDist != 0) Console->Print("Dist: %f\tApprox: %d\tError: %d (%d%)", fDist, DApprox, (int)(DApprox-fDist), (int)(100*(DApprox-fDist)/fDist));\r
- */\r
-\r
- return ( uint16_t )DApprox;\r
-}\r
-\r
-/*** Portable pseudo-random number generator ***/\r
-// until native standardized C++ lib support\r
-\r
-uint32_t mInternalRand = 1;\r
-\r
-void InitRandom( uint32_t nInitialisationValue )\r
-{\r
- mInternalRand = nInitialisationValue;\r
-}\r
-\r
-uint16_t GetRandom( uint16_t MaxVal, uint16_t MinVal )\r
-{\r
- mInternalRand = mInternalRand * 1103515245 + 12345; //from rand() manpage\r
- return ( uint16_t )( MinVal + (( mInternalRand >> 16 ) % 32768 % ( MaxVal - MinVal + 1 ) ) );\r
-}\r
-\r
-float GetRandomFloat()\r
-{\r
- mInternalRand = mInternalRand * 1103515245 + 12345; //from rand() manpage\r
- return (( float )(( mInternalRand >> 16 ) % 32768 ) / ( float )32768 );\r
-}\r
+#include <cstdarg>
+#include <cstring>
+#include <arpa/inet.h>
+#include "Common/Includes.hxx"
+
+uint32_t IPStringToDWord( const char *IP )
+{
+ if ( !IP )
+ return 0;
+
+ uint32_t a, b, c, d;
+ if ( std::sscanf( IP, "%u.%u.%u.%u", &a, &b, &c, &d ) != 4 )
+ return 0;
+
+ return ( d << 24 ) | ( c << 16 ) | ( b << 8 ) | a;
+}
+
+char *IPlongToString( const uint32_t IP )
+{
+ struct in_addr in_IP;
+
+ in_IP.s_addr = IP;
+ return inet_ntoa( in_IP );
+}
+
+//NEW
+//this function allow to print a packet
+//just for tracking values
+void PrintPacket( uint8_t *Packet, int PacketSize )
+{
+ Console->Print( "inside : PrintPacket" );
+
+ if ( PacketSize < 1 ){Console->Print( "Wrong packet" );}//do nothing
+ else
+ {
+ Console->Print( "PacketSize is : %d", PacketSize );
+
+ uint8_t value = 0;
+ for ( int i = 0;i < PacketSize;i++ )
+ {
+ value = *( uint8_t* ) & Packet[i];
+ Console->Print( "value[%d] is : %x", i, value );
+ }
+ }
+
+}//end function
+
+void CleanUpString(std::string *nString)
+{
+ if(!nString)
+ return;
+
+ // Skip if string is >" "<
+ if(nString->length() > 3)
+ {
+ size_t tfound;
+ std::string t_replacechr ("\"");
+
+ tfound = nString->find(t_replacechr);
+ while(tfound != std::string::npos)
+ {
+ nString->replace(tfound, 1, " ");
+ tfound = nString->find( t_replacechr, tfound +1 );
+ }
+ // Skip if string consists of spaces now
+ if(strncmp(nString->c_str(), " ", 3) == 0)
+ {
+ // Set empty
+ *nString = "";
+ }
+ else
+ {
+ // Trim spaces
+ Trim(nString);
+ }
+ }
+ else
+ {
+ *nString = "";
+ }
+}
+
+
+void Trim( char *t )
+{
+ RTrim( t );
+ if ( strlen( t ) )
+ LTrim( t );
+}
+
+void Trim( std::string *stString )
+{
+ RTrim( stString );
+ if ( stString->length() )
+ LTrim( stString );
+}
+
+void RTrim( char *t )
+{
+ char *buf;
+
+ if ( !strlen( t ) ) return;
+
+ buf = t;
+ buf += strlen( t ) - 1;
+
+ while ( *buf == ' ' && strlen( t ) )
+ *buf-- = '\0';
+}
+
+void RTrim( std::string *stString )
+{
+ int i; //Count VAR
+
+ if ( !stString->length() ) //If There Is No Length
+ return;
+
+ i = stString->length() - 1; //Set The Counter To The String Length -1
+
+ while ( stString->substr( i, 1 ) == " " ) //While There Is Still " "
+ {
+ *stString = stString->substr( 0, i ); //Remove Off The End Of The String
+ i--; //Advance The Counter
+ }
+
+}
+
+void LTrim( char *t )
+{
+ char tmp[2048]; //Temp Char VAR
+ char *buf; //Pointer
+
+ if ( !strlen( t ) ) return;
+
+ strncpy( tmp, t, 2048 );
+ tmp[2047] = 0;
+ buf = tmp;
+
+ while ( *buf == ' ' && strlen( buf ) ) *buf++;
+
+ strncpy( t, buf, 2048 ); // just because without length is forbidden !
+}
+
+void LTrim( std::string *stString )
+{
+ unsigned int i; //Count VAR
+ std::string buf; //Temp String VAR
+
+ if ( !stString->length() ) return; //If The Length Is 0
+
+ i = 0; //Setup The Counter VAR
+
+ while ( stString->substr( i, 1 ) == " " ) //While " "
+ i++; //Increase Counter
+
+ if ( i == stString->length() ) //If The Whole String Is " "
+ {
+ *stString = ""; //Return Blank String
+ return;
+ }
+
+ try
+ {
+ *stString = stString->substr( i, stString->length() - i ); //Send The String Back Without The Spaces
+ }
+ catch ( ... )
+ {
+ *stString = ""; //Return Blank String
+ return;
+ }
+
+}
+
+std::string GetAccessString( int level )
+{
+ switch ( level )
+ {
+ case 0: return "Unregistered";
+ case 1: return "Registered";
+ case 30: return "Volunteer";
+ case 50: return "Gamemaster";
+ case 100: return "Administrator";
+ }
+ return "Error";
+}
+
+std::string &Ssprintf( const char *fmt, ... )
+{
+ static std::string tmpstring;
+ char buff[1024];
+ va_list args;
+
+ va_start( args, fmt );
+ vsnprintf( buff, 1024, fmt, args );
+ va_end( args );
+ buff[1023] = '\0';
+ tmpstring = buff;
+ return tmpstring;
+}
+
+uint16_t DistanceApprox( const uint16_t x1, const uint16_t y1, const uint16_t z1, const uint16_t x2, const uint16_t y2, const uint16_t z2 )
+{
+ uint16_t DX, DY, DZ, DMax;
+ uint32_t DMinSum, DApprox;
+
+ DMax = DX = ( x1 >= x2 ) ? x1 - x2 : x2 - x1;
+ DMinSum = DY = ( y1 >= y2 ) ? y1 - y2 : y2 - y1;
+ DZ = ( z1 >= z2 ) ? z1 - z2 : z2 - z1;
+ if ( DX < DY )
+ {
+ DMax = DY;
+ DMinSum = DX;
+ }
+ if ( DMax < DZ )
+ {
+ DMinSum += DMax;
+ DMax = DZ;
+ }
+ else
+ {
+ DMinSum += DZ;
+ }
+
+ DApprox = DMax + ( uint32_t )( 0.33 * DMinSum );
+ if ( DApprox > 65535 )
+ {
+ DApprox = 65535;
+ }
+
+ // We use Dapprox = max(dx, dy) + K * min(dx, dy)
+ // Dapprox = (DX > DY) ? DX + (DY >> 1) : DY + (DX >> 1); // Fastest, but max error on dist is around 10% real dist
+ //Dapprox = (u16)((DX > DY) ? DX + 0.33*DY : DY + 0.33*DX); // max error on dist is around 5%, which should be enough
+ /*
+ // for dist approx debug
+ float fDX, fDY, fDZ, fDist;
+ fDX=(x1 - x2);
+ fDY=(y1 - y2);
+ fDZ=(z1 - z2);
+ fDist=sqrt(fDX*fDX + fDY*fDY + fDZ*fDZ);
+ if (fDist != 0) Console->Print("Dist: %f\tApprox: %d\tError: %d (%d%)", fDist, DApprox, (int)(DApprox-fDist), (int)(100*(DApprox-fDist)/fDist));
+ */
+
+ return ( uint16_t )DApprox;
+}
+
+/*** Portable pseudo-random number generator ***/
+// until native standardized C++ lib support
+
+uint32_t mInternalRand = 1;
+
+void InitRandom( uint32_t nInitialisationValue )
+{
+ mInternalRand = nInitialisationValue;
+}
+
+uint16_t GetRandom( uint16_t MaxVal, uint16_t MinVal )
+{
+ mInternalRand = mInternalRand * 1103515245 + 12345; //from rand() manpage
+ return ( uint16_t )( MinVal + (( mInternalRand >> 16 ) % 32768 % ( MaxVal - MinVal + 1 ) ) );
+}
+
+float GetRandomFloat()
+{
+ mInternalRand = mInternalRand * 1103515245 + 12345; //from rand() manpage
+ return (( float )(( mInternalRand >> 16 ) % 32768 ) / ( float )32768 );
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-\r
-uint32_t IPStringToDWord(const char *IP);\r
-char *IPlongToString(const uint32_t IP);\r
-std::string GetAccessString(int32_t level);\r
-//void GetSVNRev(char *version);\r
-\r
-void PrintPacket(uint8_t *Packet, int32_t PacketSize);\r
-\r
-// Cleanup for strings read from .def\r
-void CleanUpString(std::string *nString);\r
-void Trim(char *t);\r
-void Trim(std::string *stString);\r
-void RTrim(char *t);\r
-void RTrim(std::string *stString);\r
-void LTrim(char *t);\r
-void LTrim(std::string *stString);\r
-std::string &Ssprintf(const char *fmt, ...);\r
-\r
-uint16_t DistanceApprox(const uint16_t x1, const uint16_t y1, const uint16_t z1, const uint16_t x2, const uint16_t y2, const uint16_t z2);\r
-float Distance(const float x1, const float y1, const float z1, const float x2, const float y2, const float z2);\r
-float Distance(const float x1, const float y1, const float x2, const float y2); // 2D only version\r
-\r
-void InitRandom(uint32_t nInitialisationValue);\r
-uint16_t GetRandom(uint16_t MaxVal, uint16_t MinVal = 0); // u16 value between MinVal and MaxVal (inclusive) with max range 32768\r
-float GetRandomFloat(); // f32 value between 0 and 1\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+uint32_t IPStringToDWord(const char *IP);
+char *IPlongToString(const uint32_t IP);
+std::string GetAccessString(int32_t level);
+//void GetSVNRev(char *version);
+
+void PrintPacket(uint8_t *Packet, int32_t PacketSize);
+
+// Cleanup for strings read from .def
+void CleanUpString(std::string *nString);
+void Trim(char *t);
+void Trim(std::string *stString);
+void RTrim(char *t);
+void RTrim(std::string *stString);
+void LTrim(char *t);
+void LTrim(std::string *stString);
+std::string &Ssprintf(const char *fmt, ...);
+
+uint16_t DistanceApprox(const uint16_t x1, const uint16_t y1, const uint16_t z1, const uint16_t x2, const uint16_t y2, const uint16_t z2);
+float Distance(const float x1, const float y1, const float z1, const float x2, const float y2, const float z2);
+float Distance(const float x1, const float y1, const float x2, const float y2); // 2D only version
+
+void InitRandom(uint32_t nInitialisationValue);
+uint16_t GetRandom(uint16_t MaxVal, uint16_t MinVal = 0); // u16 value between MinVal and MaxVal (inclusive) with max range 32768
+float GetRandomFloat(); // f32 value between 0 and 1
-#pragma once\r
-\r
-#include <pthread.h>\r
-\r
-class Mutex {\r
-private:\r
- mutable pthread_mutex_t mut;\r
-\r
- void operator = (Mutex &mut) {}\r
-\r
- Mutex(const Mutex &mut) {}\r
-\r
-public:\r
- Mutex()\r
- {\r
- pthread_mutexattr_t attr;\r
- pthread_mutexattr_init(&attr);\r
- pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);\r
- pthread_mutex_init(&mut, &attr);\r
- pthread_mutexattr_destroy(&attr);\r
- }\r
-\r
- virtual ~Mutex()\r
- {\r
- pthread_mutex_unlock(&mut);\r
- pthread_mutex_destroy(&mut);\r
- }\r
-\r
- int Lock() const\r
- {\r
- return (pthread_mutex_lock(&mut));\r
- }\r
-\r
- int TryLock() const\r
- {\r
- return (pthread_mutex_trylock(&mut));\r
- }\r
-\r
- int Unlock() const\r
- {\r
- return (pthread_mutex_unlock(&mut));\r
- }\r
-};\r
+#pragma once
+
+#include <pthread.h>
+
+class Mutex {
+private:
+ mutable pthread_mutex_t mut;
+
+ void operator = (Mutex &mut) {}
+
+ Mutex(const Mutex &mut) {}
+
+public:
+ Mutex()
+ {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&mut, &attr);
+ pthread_mutexattr_destroy(&attr);
+ }
+
+ virtual ~Mutex()
+ {
+ pthread_mutex_unlock(&mut);
+ pthread_mutex_destroy(&mut);
+ }
+
+ int Lock() const
+ {
+ return (pthread_mutex_lock(&mut));
+ }
+
+ int TryLock() const
+ {
+ return (pthread_mutex_trylock(&mut));
+ }
+
+ int Unlock() const
+ {
+ return (pthread_mutex_unlock(&mut));
+ }
+};
-#pragma once\r
-\r
-#include <semaphore.h>\r
-\r
-class Semaphore {\r
-private:\r
- sem_t sem;\r
-\r
-public:\r
- Semaphore(int init = 0)\r
- {\r
- sem_init(&sem, 0, init);\r
- }\r
-\r
- virtual ~Semaphore()\r
- {\r
- sem_destroy(&sem);\r
- }\r
-\r
- void Wait() const\r
- {\r
- sem_wait((sem_t *)&sem);\r
- }\r
-\r
- int TryWait() const\r
- {\r
- return (sem_trywait((sem_t *)&sem) ? errno : 0);\r
- }\r
-\r
- int Post() const\r
- {\r
- return (sem_post((sem_t *)&sem) ? errno : 0);\r
- }\r
-\r
- int GetValue() const\r
- {\r
- int val = -1;\r
-\r
- sem_getvalue((sem_t *)&sem, &val);\r
-\r
- return (val);\r
- }\r
-\r
- void Reset(int init = 0)\r
- {\r
- sem_destroy(&sem);\r
- sem_init(&sem, 0, init);\r
- }\r
-};\r
+#pragma once
+
+#include <semaphore.h>
+
+class Semaphore {
+private:
+ sem_t sem;
+
+public:
+ Semaphore(int init = 0)
+ {
+ sem_init(&sem, 0, init);
+ }
+
+ virtual ~Semaphore()
+ {
+ sem_destroy(&sem);
+ }
+
+ void Wait() const
+ {
+ sem_wait((sem_t *)&sem);
+ }
+
+ int TryWait() const
+ {
+ return (sem_trywait((sem_t *)&sem) ? errno : 0);
+ }
+
+ int Post() const
+ {
+ return (sem_post((sem_t *)&sem) ? errno : 0);
+ }
+
+ int GetValue() const
+ {
+ int val = -1;
+
+ sem_getvalue((sem_t *)&sem, &val);
+
+ return (val);
+ }
+
+ void Reset(int init = 0)
+ {
+ sem_destroy(&sem);
+ sem_init(&sem, 0, init);
+ }
+};
-#pragma once\r
-\r
-#include <mutex.h>\r
-#include <semaphore.h>\r
-#include <pthread.h>\r
-\r
-#define INVALID_HANDLE 0\r
-\r
-typedef void *(*pthread_fn)(void*);\r
-\r
-template <typename Thread_T>\r
-class Thread {\r
- private:\r
- typedef struct Instance;\r
-\r
- public:\r
- typedef Thread_T &Thread_;\r
- typedef const Thread_T &Thread__;\r
- typedef pthread_t Handle;\r
- typedef void (*Handler)(Thread_);\r
-\r
- protected:\r
- Thread() {\r
- }\r
-\r
- virtual void ThreadMain(Thread_) = 0;\r
-\r
- static void Exit() {\r
- pthread_exit(0);\r
- }\r
-\r
- static void TestCancel() {\r
- pthread_testcancel();\r
- }\r
-\r
- static Handle Self() {\r
- return(Handle)pthread_self();\r
- }\r
-\r
- public:\r
- static int Create(const Handler &Func, Thread__ Param, Handle *const &H = 0,\r
- const bool &CreateDetached = false, const unsigned int &StackSize = 0,\r
- const bool &CancelEnable = false, const bool &CancelAsync = false) {\r
- M_Create().Lock();\r
- pthread_attr_t attr;\r
- pthread_attr_init(&attr);\r
-\r
- if(CreateDetached)\r
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);\r
-\r
- if(StackSize)\r
- pthread_attr_setstacksize(&attr, StackSize);\r
-\r
- Instance I(Param, 0, Func, CancelEnable, CancelAsync);\r
-\r
- Handle h = INVALID_HANDLE;\r
- int run = pthread_create((pthread_t *)&h, &attr, (pthread_fn)ThreadMainHandler, (void *)&I);\r
-\r
- pthread_attr_destroy(&attr);\r
-\r
- if(H)\r
- *H = h;\r
- if(!run)\r
- S_Create().Wait();\r
-\r
- M_Create().Unlock();\r
-\r
- return(errno);\r
- }\r
-\r
- int Create(Thread__ Param, Handle *const &H = 0, const bool &CreateDetached = false,\r
- const unsigned int &StackSize = 0, const bool &CancelEnable = false,\r
- const bool &CancelAsync = false ) const {\r
- M_Create().Lock();\r
- pthread_attr_t attr;\r
- pthread_attr_init(&attr);\r
-\r
- if(CreateDetached)\r
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);\r
-\r
- if(StackSize)\r
- pthread_attr_setstacksize(&attr, StackSize);\r
-\r
- Instance I(Param, const_cast<Thread *>(this), 0, CancelEnable, CancelAsync);\r
-\r
- Handle h = INVALID_HANDLE;\r
- int run = pthread_create((pthread_t *)&h, &attr, (pthread_fn)ThreadMainHandler, (void *)&I);\r
-\r
- pthread_attr_destroy(&attr);\r
-\r
- if(H)\r
- *H = h;\r
- if(!run)\r
- S_Create().Wait();\r
-\r
- M_Create().Unlock();\r
-\r
- return(errno);\r
- }\r
-\r
- static int Join(Handle H) {\r
- return(pthread_join(H, 0));\r
- }\r
-\r
- static int Kill(Handle H) {\r
- return(pthread_cancel(H));\r
- }\r
-\r
- static int Detach(Handle H) {\r
- return(pthread_detach(H));\r
- }\r
-\r
- private:\r
- static const Mutex &M_Create() {\r
- static Mutex M;\r
-\r
- return(M);\r
- }\r
-\r
- static const Semaphore &S_Create() {\r
- static Semaphore S;\r
-\r
- return(S);\r
- }\r
-\r
- static void ThreadMainHandler(Instance *Param) {\r
- Instance I(*Param);\r
- Thread_T Data(I.Data);\r
-\r
- S_Create().Post();\r
-\r
- if(I.Flags & 1) {\r
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);\r
-\r
- if(I.Flags & 2)\r
- pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);\r
- else\r
- pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);\r
- }\r
- else\r
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);\r
-\r
- if(I.Owner)\r
- I.Owner->ThreadMain(Data);\r
- else\r
- I.pFN(Data);\r
-\r
- return(0);\r
- }\r
-\r
- struct Instance {\r
- Instance(Thread__ P, Thread<Thread_T> *const &O, const Thread<Thread_T>::Handler &pH = 0,\r
- const bool &CE = false, const bool &CA = false) : Data(P), Owner(O), pFN(pH),\r
- Flags(0) {\r
- if(CE)\r
- Flags |= 1;\r
- if(CA)\r
- Flags |= 2;\r
- }\r
-\r
- Thread__ Data;\r
- Thread<Thread_T> *Owner;\r
- Handler pFN;\r
- unsigned char Flags;\r
- };\r
-};\r
+#pragma once
+
+#include <mutex.h>
+#include <semaphore.h>
+#include <pthread.h>
+
+#define INVALID_HANDLE 0
+
+typedef void *(*pthread_fn)(void*);
+
+template <typename Thread_T>
+class Thread {
+ private:
+ typedef struct Instance;
+
+ public:
+ typedef Thread_T &Thread_;
+ typedef const Thread_T &Thread__;
+ typedef pthread_t Handle;
+ typedef void (*Handler)(Thread_);
+
+ protected:
+ Thread() {
+ }
+
+ virtual void ThreadMain(Thread_) = 0;
+
+ static void Exit() {
+ pthread_exit(0);
+ }
+
+ static void TestCancel() {
+ pthread_testcancel();
+ }
+
+ static Handle Self() {
+ return(Handle)pthread_self();
+ }
+
+ public:
+ static int Create(const Handler &Func, Thread__ Param, Handle *const &H = 0,
+ const bool &CreateDetached = false, const unsigned int &StackSize = 0,
+ const bool &CancelEnable = false, const bool &CancelAsync = false) {
+ M_Create().Lock();
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+
+ if(CreateDetached)
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ if(StackSize)
+ pthread_attr_setstacksize(&attr, StackSize);
+
+ Instance I(Param, 0, Func, CancelEnable, CancelAsync);
+
+ Handle h = INVALID_HANDLE;
+ int run = pthread_create((pthread_t *)&h, &attr, (pthread_fn)ThreadMainHandler, (void *)&I);
+
+ pthread_attr_destroy(&attr);
+
+ if(H)
+ *H = h;
+ if(!run)
+ S_Create().Wait();
+
+ M_Create().Unlock();
+
+ return(errno);
+ }
+
+ int Create(Thread__ Param, Handle *const &H = 0, const bool &CreateDetached = false,
+ const unsigned int &StackSize = 0, const bool &CancelEnable = false,
+ const bool &CancelAsync = false ) const {
+ M_Create().Lock();
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+
+ if(CreateDetached)
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ if(StackSize)
+ pthread_attr_setstacksize(&attr, StackSize);
+
+ Instance I(Param, const_cast<Thread *>(this), 0, CancelEnable, CancelAsync);
+
+ Handle h = INVALID_HANDLE;
+ int run = pthread_create((pthread_t *)&h, &attr, (pthread_fn)ThreadMainHandler, (void *)&I);
+
+ pthread_attr_destroy(&attr);
+
+ if(H)
+ *H = h;
+ if(!run)
+ S_Create().Wait();
+
+ M_Create().Unlock();
+
+ return(errno);
+ }
+
+ static int Join(Handle H) {
+ return(pthread_join(H, 0));
+ }
+
+ static int Kill(Handle H) {
+ return(pthread_cancel(H));
+ }
+
+ static int Detach(Handle H) {
+ return(pthread_detach(H));
+ }
+
+ private:
+ static const Mutex &M_Create() {
+ static Mutex M;
+
+ return(M);
+ }
+
+ static const Semaphore &S_Create() {
+ static Semaphore S;
+
+ return(S);
+ }
+
+ static void ThreadMainHandler(Instance *Param) {
+ Instance I(*Param);
+ Thread_T Data(I.Data);
+
+ S_Create().Post();
+
+ if(I.Flags & 1) {
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+ if(I.Flags & 2)
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+ else
+ pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
+ }
+ else
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
+ if(I.Owner)
+ I.Owner->ThreadMain(Data);
+ else
+ I.pFN(Data);
+
+ return(0);
+ }
+
+ struct Instance {
+ Instance(Thread__ P, Thread<Thread_T> *const &O, const Thread<Thread_T>::Handler &pH = 0,
+ const bool &CE = false, const bool &CA = false) : Data(P), Owner(O), pFN(pH),
+ Flags(0) {
+ if(CE)
+ Flags |= 1;
+ if(CA)
+ Flags |= 2;
+ }
+
+ Thread__ Data;
+ Thread<Thread_T> *Owner;
+ Handler pFN;
+ unsigned char Flags;
+ };
+};
-#pragma once\r
-\r
-#include "Common/SVNrevision.hxx"\r
-\r
-#define TINNS_PATCH_VERSION "0.0.2 Dev"\r
-#define TINNS_INFO_VERSION "0.0.2 Dev"\r
-#define TINNS_GAME_VERSION "0.1.38 Dev"\r
+#pragma once
+
+#include "Common/SVNrevision.hxx"
+
+#define TINNS_PATCH_VERSION "0.0.2 Dev"
+#define TINNS_INFO_VERSION "0.0.2 Dev"
+#define TINNS_GAME_VERSION "0.1.38 Dev"
-ADD_EXECUTABLE (getsvnrev getsvnrev.cpp)
+ADD_EXECUTABLE (getsvnrev getsvnrev.cxx)
ADD_EXECUTABLE (cleandepfile cleandepfile.c)
-/*\r
- TinNS (TinNS is not a Neocron Server)\r
- Copyright (C) 2005 Linux Addicted Community\r
- maintainer Akiko <akiko@gmx.org>\r
-\r
- This program is free software; you can redistribute it and/or\r
- modify it under the terms of the GNU General Public License\r
- as published by the Free Software Foundation; either version 2\r
- of the License, or (at your option) any later version.\r
-\r
- This program is distributed in the hope that it will be useful,\r
- but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- GNU General Public License for more details.\r
-\r
- You should have received a copy of the GNU General Public License\r
- along with this program; if not, write to the Free Software\r
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA\r
- 02110-1301, USA.\r
-*/\r
-\r
-\r
-\r
-/*\r
- getsvnrev - a simple tool to read out actual SVN revision-number\r
-\r
- Why?\r
- Well for example my server doesnt have any SVN libs installed. Therefore,\r
- the getsvnrev script fails. I need this little tool, and maybe someone else too ^^\r
-\r
- Usage: \r
- call getsvnrev either without parameters or with the directory you\r
- want to know the SVN revision.\r
- \r
- Console output:\r
- If no .svn directory is found, the tool returns 0.\r
- Otherwise it will return the SVN revision of the target dir\r
-\r
- MODIFIED: 22 Dec 2006 Namikon\r
- REASON: - started this tool\r
- MODIFIED: 09 Jun 2009 Akiko\r
- REASON: - more C++ stylish\r
- - missing libs (cstring, cstdlib)\r
-\r
- TODO:\r
- - Better way to get SVN rev than this (2nd number in file)\r
-*/\r
-\r
-\r
-#include <cstdio>\r
-#include <cstring>\r
-#include <cstdlib>\r
-#include <iostream>\r
-\r
-int main(int argc, char **argv)\r
-{\r
- std::string targetdir;\r
- FILE *f;\r
-\r
- if(argc == 2)\r
- {\r
- int i = 0;\r
- while(argv[1][i] != '\0') { i++; };\r
- if(argv[1][i-1] == '/')\r
- {\r
- targetdir = strcat(argv[1], ".svn/entries");\r
- }\r
- else\r
- {\r
- targetdir = strcat(argv[1], "/.svn/entries");\r
- }\r
- }\r
- else\r
- {\r
- targetdir = ".svn/entries";\r
- }\r
-\r
-\r
- if ((f = fopen(targetdir.c_str(), "r")) != NULL) {\r
- char line[255];\r
- int rev;\r
- bool firstnrfound = false;\r
- \r
- do\r
- {\r
- fgets (line, 255, f);\r
- rev = atoi(line);\r
- if(rev > 0 && firstnrfound == false)\r
- {\r
- firstnrfound = true;\r
- rev = 0;\r
- }\r
- } while (rev == 0);\r
- \r
- fclose(f);\r
-\r
- std::cout << rev << std::endl;\r
- }\r
- else\r
- {\r
- std::cout << "0" << std::endl;\r
- }\r
- return(0);\r
-}\r
+/*
+ TinNS (TinNS is not a Neocron Server)
+ Copyright (C) 2005 Linux Addicted Community
+ maintainer Akiko <akiko@gmx.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+
+
+/*
+ getsvnrev - a simple tool to read out actual SVN revision-number
+
+ Why?
+ Well for example my server doesnt have any SVN libs installed. Therefore,
+ the getsvnrev script fails. I need this little tool, and maybe someone else too ^^
+
+ Usage:
+ call getsvnrev either without parameters or with the directory you
+ want to know the SVN revision.
+
+ Console output:
+ If no .svn directory is found, the tool returns 0.
+ Otherwise it will return the SVN revision of the target dir
+
+ MODIFIED: 22 Dec 2006 Namikon
+ REASON: - started this tool
+ MODIFIED: 09 Jun 2009 Akiko
+ REASON: - more C++ stylish
+ - missing libs (cstring, cstdlib)
+
+ TODO:
+ - Better way to get SVN rev than this (2nd number in file)
+*/
+
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <iostream>
+
+int main(int argc, char **argv)
+{
+ std::string targetdir;
+ FILE *f;
+
+ if(argc == 2)
+ {
+ int i = 0;
+ while(argv[1][i] != '\0') { i++; };
+ if(argv[1][i-1] == '/')
+ {
+ targetdir = strcat(argv[1], ".svn/entries");
+ }
+ else
+ {
+ targetdir = strcat(argv[1], "/.svn/entries");
+ }
+ }
+ else
+ {
+ targetdir = ".svn/entries";
+ }
+
+
+ if ((f = fopen(targetdir.c_str(), "r")) != NULL) {
+ char line[255];
+ int rev;
+ bool firstnrfound = false;
+
+ do
+ {
+ fgets (line, 255, f);
+ rev = atoi(line);
+ if(rev > 0 && firstnrfound == false)
+ {
+ firstnrfound = true;
+ rev = 0;
+ }
+ } while (rev == 0);
+
+ fclose(f);
+
+ std::cout << rev << std::endl;
+ }
+ else
+ {
+ std::cout << "0" << std::endl;
+ }
+ return(0);
+}
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-/*\r
-NOTE ABOUT ACCESS LEVELS IN THE MYSQL DATABASE:\r
-a_priv:\r
-0 = unregistered user\r
-1 = Registered user\r
-30 = volunteer\r
-50 = GM\r
-100 = Admin\r
-\r
-a_status:\r
-0 = Offline\r
-1 = Online\r
-2 = Banned\r
-*/\r
-\r
-/** Static members **/\r
-RegEx* PAccount::mUsernameRegexFilter = NULL;\r
-RegEx* PAccount::mPasswordRegexFilter = NULL;\r
-\r
-bool PAccount::SetUsernameRegexFilter(const char* RegexStr)\r
-{\r
- if(mUsernameRegexFilter)\r
- {\r
- delete mUsernameRegexFilter;\r
- mUsernameRegexFilter = NULL;\r
- }\r
-\r
- if(RegexStr)\r
- {\r
- try {\r
- mUsernameRegexFilter = new RegEx(RegexStr, PCRE_CASELESS);\r
- }\r
- catch (...) {\r
- return false;\r
- }\r
- }\r
- return true;\r
-}\r
-\r
-bool PAccount::SetPasswordRegexFilter(const char* RegexStr)\r
-{\r
- if(mPasswordRegexFilter)\r
- {\r
- delete mPasswordRegexFilter;\r
- mPasswordRegexFilter = NULL;\r
- }\r
-\r
- if(RegexStr)\r
- {\r
- try {\r
- mPasswordRegexFilter = new RegEx(RegexStr, PCRE_CASELESS);\r
- }\r
- catch (...) {\r
- return false;\r
- }\r
- }\r
- return true;\r
-}\r
-\r
-bool PAccount::IsUsernameWellFormed(const char *Username)\r
-{\r
- if(mUsernameRegexFilter)\r
- {\r
- return mUsernameRegexFilter->Search(Username);\r
- }\r
- else\r
- return true;\r
-}\r
-\r
-bool PAccount::IsPasswordWellFormed(const char *Password)\r
-{\r
- if(mPasswordRegexFilter)\r
- {\r
- return mPasswordRegexFilter->Search(Password);\r
- }\r
- else\r
- return true;\r
-}\r
-\r
-/** Instance members **/\r
-PAccount::PAccount()\r
-{\r
- mID = 0;\r
- mLevel = PAL_BANNED;\r
- mStatus = PAS_OFFLINE;\r
- mBannedUntil = 0;\r
-}\r
-\r
-PAccount::PAccount(const uint32_t AccountId)\r
-{\r
- char query[256];\r
- mID = 0;\r
- snprintf(query, 256, "SELECT * FROM accounts WHERE a_id = %d LIMIT 1;", AccountId);\r
- LoadFromQuery(query);\r
-}\r
-\r
-PAccount::PAccount(const char *Username)\r
-{\r
- char query[256];\r
- mID = 0;\r
- if(IsUsernameWellFormed(Username)) {\r
- char escUsername[256];\r
- MySQL->EscapeString(Username, escUsername, 256);\r
- snprintf(query, 256, "SELECT * FROM accounts WHERE a_username = '%s' LIMIT 1;", escUsername);\r
- LoadFromQuery(query);\r
- }\r
-}\r
-\r
-bool PAccount::LoadFromQuery(char* query)\r
-{\r
- MYSQL_ROW row = 0;\r
- MYSQL_RES *result = 0;\r
-\r
- bool FinalResult = false;\r
-\r
- result = MySQL->InfoResQuery(query);\r
- if(result == NULL)\r
- {\r
- Console->Print(RED, BLACK, "Failed to load AccountData from SQL");\r
- MySQL->ShowInfoSQLError();\r
- return false;\r
- }\r
-\r
- if((row = mysql_fetch_row(result)))\r
- {\r
- mID = atoi(row[a_id]);\r
- mName = row[a_username];\r
- mPassword = row[a_password];\r
-\r
- mBannedUntil = atoi(row[a_bandate]);\r
- if(mBannedUntil > time(NULL))\r
- {\r
- mStatus = PAS_BANNED;\r
- mLevel = PAL_BANNED;\r
- }\r
- else\r
- {\r
- mStatus = PAS_OFFLINE;\r
- mLevel = atoi(row[a_priv]);\r
- }\r
-\r
- FinalResult = true;\r
- }\r
- else\r
- {\r
-Console->Print(YELLOW, BLACK, "Failed to load AccountData from SQL; Nothing to load...");\r
- }\r
-\r
- MySQL->FreeInfoSQLResult(result);\r
- return FinalResult;\r
-}\r
-\r
-bool PAccount::SetName(const std::string &Username)\r
-{\r
- if(IsUsernameWellFormed(Username.c_str()))\r
- {\r
- mName = Username;\r
- return true;\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-}\r
-\r
-bool PAccount::SetPassword(const std::string &Password)\r
-{\r
- if(IsPasswordWellFormed(Password.c_str()))\r
- {\r
- mPassword = Password;\r
- return true;\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-}\r
-\r
-bool PAccount::SetPasswordEncoded(const uint8_t* PasswordData, int PassLen, const uint8_t* Key)\r
-{\r
- char Pass[128];\r
-\r
- if(DecodePassword(PasswordData, PassLen, Key, Pass))\r
- {\r
- return SetPassword((std::string)Pass);\r
- }\r
- else\r
- {\r
- Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen);\r
- return false;\r
- }\r
-}\r
-\r
-bool PAccount::SetLevel(int newLevel)\r
-{\r
- if((newLevel >= PAL_BANNED) && (newLevel <= PAL_ADMIN))\r
- {\r
- mLevel = newLevel;\r
- return true;\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-}\r
-\r
-std::string PAccount::GetLevelString() const\r
-{\r
- switch(mLevel)\r
- {\r
- case PAL_BANNED : return "banned";\r
- case PAL_UNREGPLAYER : return "unregplayer";\r
- case PAL_REGPLAYER : return "regplayer";\r
- case PAL_VOLUNTEER : return "volunteer";\r
- case PAL_GM : return "gm";\r
- case PAL_ADMIN : return "admin";\r
- }\r
-\r
- return "custom";\r
-}\r
-\r
-bool PAccount::SetStatus(PAccountStatus Status)\r
-{\r
- mStatus = Status;\r
- return true;\r
-}\r
-\r
-bool PAccount::SetBannedUntilTime(std::time_t BannedUntil)\r
-{\r
- if ((BannedUntil == 0) || (BannedUntil > std::time(NULL)))\r
- {\r
- mBannedUntil = BannedUntil;\r
- return true;\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-}\r
-\r
-bool PAccount::DecodePassword(const uint8_t* PasswordData, int PassLen, const uint8_t *Key, char* ClearPassword)\r
-{\r
- ClearPassword[0] = 0;\r
-\r
- if(PassLen < 128)\r
- {\r
- if(Key[0]>7) // TODO: >7 correct?\r
- {\r
- for(int i=0; i<PassLen; i+=2)\r
- ClearPassword[i>>1] = (char)(((PasswordData[i]&0xf0)>>4)\r
- +((PasswordData[i+1]&0x0f)<<4)-Key[0]);\r
- ClearPassword[PassLen>>1]=0;\r
- }\r
- else\r
- {\r
- for(int i=0; i<PassLen; i++)\r
- ClearPassword[i] = (char)(PasswordData[i]-Key[0]);\r
- ClearPassword[PassLen]=0;\r
- }\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-bool PAccount::Authenticate(const uint8_t* PasswordData, int PassLen, const uint8_t *Key)\r
-{\r
- char Pass[128];\r
-\r
- if(DecodePassword(PasswordData, PassLen, Key, Pass))\r
- {\r
- return Authenticate(Pass);\r
- }\r
- else\r
- {\r
- Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen);\r
- return false;\r
- }\r
-}\r
-\r
-bool PAccount::Authenticate(const char *Password) const\r
-{\r
- if(mID == 0) // User doesn't exist and that hasn't been checked !\r
- {\r
- Console->Print(RED, BLACK, "[Bug]: user %s doesn't exist and was not checked by code !", mName.c_str());\r
- return false;\r
- }\r
-\r
- return(mPassword == Password);\r
-}\r
-\r
-bool PAccount::Create()\r
-{\r
- if(Save(true)) {\r
- mID = MySQL->GetLastInfoInsertId();\r
- return true;\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-}\r
-\r
-bool PAccount::Save(bool CreateMode)\r
-{\r
- char escUsername[256];\r
- char escPassword[256];\r
- MySQL->EscapeString(mName.c_str(), escUsername, 256);\r
- MySQL->EscapeString(mPassword.c_str(), escPassword, 256);\r
-\r
- std::string Query;\r
- Query = CreateMode ? "INSERT INTO" : "UPDATE";\r
- Query += "accounts SET ";\r
- Query += Ssprintf(" accounts SET a_username='%s', a_password = '%s'", escUsername, escPassword);\r
- Query += Ssprintf(", a_priv = %d, a_status = %d, a_bandate = %d", mLevel, mStatus, mBannedUntil);\r
- if(!CreateMode )\r
- {\r
- Query += Ssprintf(" WHERE a_id = %d LIMIT 1", mID);\r
- }\r
-\r
- if(MySQL->InfoQuery(Query.c_str()))\r
- {\r
- Console->Print(RED, BLACK, "[Error] Failed to %s account %s (id %d)", CreateMode ? "create" : "update", mName.c_str(), mID);\r
- MySQL->ShowInfoSQLError();\r
- return false;\r
- }\r
- return true;\r
-}\r
-\r
-uint32_t PAccount::GetCharIdBySlot(const uint32_t SlotId)\r
-{\r
- char query[256];\r
- uint32_t CharId = 0;\r
-\r
- MYSQL_ROW row = 0;\r
- MYSQL_RES *result = 0;\r
-\r
- snprintf(query, 256, "SELECT c_id FROM characters WHERE a_id = %d AND c_slot = %d LIMIT 1;", mID, SlotId);\r
-\r
- result = MySQL->GameResQuery(query);\r
- if(result == NULL)\r
- {\r
- Console->Print(RED, BLACK, "Failed to load CharacterData from SQL");\r
- MySQL->ShowGameSQLError();\r
- return 0;\r
- }\r
-\r
- if((row = mysql_fetch_row(result)))\r
- {\r
- CharId = atoi(row[0]);\r
- }\r
-\r
- MySQL->FreeGameSQLResult(result);\r
-\r
- /*** Temporary workaround to cope with DB where c_slot is not set ***/\r
- if(!CharId)\r
- {\r
- snprintf(query, 256, "SELECT c_id FROM characters WHERE a_id = %d ORDER BY c_slot ASC, c_id ASC LIMIT %d, 1;", mID, SlotId);\r
-\r
- result = MySQL->GameResQuery(query);\r
- if(result == NULL)\r
- {\r
- Console->Print(RED, BLACK, "Failed to load CharacterData from SQL");\r
- MySQL->ShowGameSQLError();\r
- return 0;\r
- }\r
-\r
- if((row = mysql_fetch_row(result)))\r
- {\r
- CharId = atoi(row[0]);\r
- }\r
-\r
- MySQL->FreeGameSQLResult(result);\r
- }\r
- /*** End of workaround ***/\r
-\r
- return CharId;\r
-}\r
-\r
-\r
-std::string PAccount::GetBannedTime() const\r
-{\r
- const char* unit[5] = {"seconds", "minutes", "hours", "days", "weeks"};\r
-\r
- std::time_t timediff = mBannedUntil - std::time(NULL);\r
- if(timediff <=0)\r
- {\r
- return "0 more seconds. Please relog";\r
- }\r
-\r
- long counter;\r
- int type;\r
-\r
- if(timediff > 86400) // days\r
- {\r
- counter = timediff / 86400;\r
- type = 3;\r
- }\r
- else if(timediff > 3600) // hours\r
- {\r
- counter = timediff / 3600;\r
- type = 2;\r
- }\r
- else if(timediff > 60) // Minutes\r
- {\r
- counter = timediff / 60;\r
- type = 1;\r
- }\r
- else // Seconds\r
- {\r
- counter = timediff;\r
- type = 0;\r
- }\r
-\r
- return Ssprintf("%d more %s", counter, unit[type]);\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+/*
+NOTE ABOUT ACCESS LEVELS IN THE MYSQL DATABASE:
+a_priv:
+0 = unregistered user
+1 = Registered user
+30 = volunteer
+50 = GM
+100 = Admin
+
+a_status:
+0 = Offline
+1 = Online
+2 = Banned
+*/
+
+/** Static members **/
+RegEx* PAccount::mUsernameRegexFilter = NULL;
+RegEx* PAccount::mPasswordRegexFilter = NULL;
+
+bool PAccount::SetUsernameRegexFilter(const char* RegexStr)
+{
+ if(mUsernameRegexFilter)
+ {
+ delete mUsernameRegexFilter;
+ mUsernameRegexFilter = NULL;
+ }
+
+ if(RegexStr)
+ {
+ try {
+ mUsernameRegexFilter = new RegEx(RegexStr, PCRE_CASELESS);
+ }
+ catch (...) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool PAccount::SetPasswordRegexFilter(const char* RegexStr)
+{
+ if(mPasswordRegexFilter)
+ {
+ delete mPasswordRegexFilter;
+ mPasswordRegexFilter = NULL;
+ }
+
+ if(RegexStr)
+ {
+ try {
+ mPasswordRegexFilter = new RegEx(RegexStr, PCRE_CASELESS);
+ }
+ catch (...) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool PAccount::IsUsernameWellFormed(const char *Username)
+{
+ if(mUsernameRegexFilter)
+ {
+ return mUsernameRegexFilter->Search(Username);
+ }
+ else
+ return true;
+}
+
+bool PAccount::IsPasswordWellFormed(const char *Password)
+{
+ if(mPasswordRegexFilter)
+ {
+ return mPasswordRegexFilter->Search(Password);
+ }
+ else
+ return true;
+}
+
+/** Instance members **/
+PAccount::PAccount()
+{
+ mID = 0;
+ mLevel = PAL_BANNED;
+ mStatus = PAS_OFFLINE;
+ mBannedUntil = 0;
+}
+
+PAccount::PAccount(const uint32_t AccountId)
+{
+ char query[256];
+ mID = 0;
+ snprintf(query, 256, "SELECT * FROM accounts WHERE a_id = %d LIMIT 1;", AccountId);
+ LoadFromQuery(query);
+}
+
+PAccount::PAccount(const char *Username)
+{
+ char query[256];
+ mID = 0;
+ if(IsUsernameWellFormed(Username)) {
+ char escUsername[256];
+ MySQL->EscapeString(Username, escUsername, 256);
+ snprintf(query, 256, "SELECT * FROM accounts WHERE a_username = '%s' LIMIT 1;", escUsername);
+ LoadFromQuery(query);
+ }
+}
+
+bool PAccount::LoadFromQuery(char* query)
+{
+ MYSQL_ROW row = 0;
+ MYSQL_RES *result = 0;
+
+ bool FinalResult = false;
+
+ result = MySQL->InfoResQuery(query);
+ if(result == NULL)
+ {
+ Console->Print(RED, BLACK, "Failed to load AccountData from SQL");
+ MySQL->ShowInfoSQLError();
+ return false;
+ }
+
+ if((row = mysql_fetch_row(result)))
+ {
+ mID = atoi(row[a_id]);
+ mName = row[a_username];
+ mPassword = row[a_password];
+
+ mBannedUntil = atoi(row[a_bandate]);
+ if(mBannedUntil > time(NULL))
+ {
+ mStatus = PAS_BANNED;
+ mLevel = PAL_BANNED;
+ }
+ else
+ {
+ mStatus = PAS_OFFLINE;
+ mLevel = atoi(row[a_priv]);
+ }
+
+ FinalResult = true;
+ }
+ else
+ {
+Console->Print(YELLOW, BLACK, "Failed to load AccountData from SQL; Nothing to load...");
+ }
+
+ MySQL->FreeInfoSQLResult(result);
+ return FinalResult;
+}
+
+bool PAccount::SetName(const std::string &Username)
+{
+ if(IsUsernameWellFormed(Username.c_str()))
+ {
+ mName = Username;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool PAccount::SetPassword(const std::string &Password)
+{
+ if(IsPasswordWellFormed(Password.c_str()))
+ {
+ mPassword = Password;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool PAccount::SetPasswordEncoded(const uint8_t* PasswordData, int PassLen, const uint8_t* Key)
+{
+ char Pass[128];
+
+ if(DecodePassword(PasswordData, PassLen, Key, Pass))
+ {
+ return SetPassword((std::string)Pass);
+ }
+ else
+ {
+ Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen);
+ return false;
+ }
+}
+
+bool PAccount::SetLevel(int newLevel)
+{
+ if((newLevel >= PAL_BANNED) && (newLevel <= PAL_ADMIN))
+ {
+ mLevel = newLevel;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+std::string PAccount::GetLevelString() const
+{
+ switch(mLevel)
+ {
+ case PAL_BANNED : return "banned";
+ case PAL_UNREGPLAYER : return "unregplayer";
+ case PAL_REGPLAYER : return "regplayer";
+ case PAL_VOLUNTEER : return "volunteer";
+ case PAL_GM : return "gm";
+ case PAL_ADMIN : return "admin";
+ }
+
+ return "custom";
+}
+
+bool PAccount::SetStatus(PAccountStatus Status)
+{
+ mStatus = Status;
+ return true;
+}
+
+bool PAccount::SetBannedUntilTime(std::time_t BannedUntil)
+{
+ if ((BannedUntil == 0) || (BannedUntil > std::time(NULL)))
+ {
+ mBannedUntil = BannedUntil;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool PAccount::DecodePassword(const uint8_t* PasswordData, int PassLen, const uint8_t *Key, char* ClearPassword)
+{
+ ClearPassword[0] = 0;
+
+ if(PassLen < 128)
+ {
+ if(Key[0]>7) // TODO: >7 correct?
+ {
+ for(int i=0; i<PassLen; i+=2)
+ ClearPassword[i>>1] = (char)(((PasswordData[i]&0xf0)>>4)
+ +((PasswordData[i+1]&0x0f)<<4)-Key[0]);
+ ClearPassword[PassLen>>1]=0;
+ }
+ else
+ {
+ for(int i=0; i<PassLen; i++)
+ ClearPassword[i] = (char)(PasswordData[i]-Key[0]);
+ ClearPassword[PassLen]=0;
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+bool PAccount::Authenticate(const uint8_t* PasswordData, int PassLen, const uint8_t *Key)
+{
+ char Pass[128];
+
+ if(DecodePassword(PasswordData, PassLen, Key, Pass))
+ {
+ return Authenticate(Pass);
+ }
+ else
+ {
+ Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen);
+ return false;
+ }
+}
+
+bool PAccount::Authenticate(const char *Password) const
+{
+ if(mID == 0) // User doesn't exist and that hasn't been checked !
+ {
+ Console->Print(RED, BLACK, "[Bug]: user %s doesn't exist and was not checked by code !", mName.c_str());
+ return false;
+ }
+
+ return(mPassword == Password);
+}
+
+bool PAccount::Create()
+{
+ if(Save(true)) {
+ mID = MySQL->GetLastInfoInsertId();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool PAccount::Save(bool CreateMode)
+{
+ char escUsername[256];
+ char escPassword[256];
+ MySQL->EscapeString(mName.c_str(), escUsername, 256);
+ MySQL->EscapeString(mPassword.c_str(), escPassword, 256);
+
+ std::string Query;
+ Query = CreateMode ? "INSERT INTO" : "UPDATE";
+ Query += "accounts SET ";
+ Query += Ssprintf(" accounts SET a_username='%s', a_password = '%s'", escUsername, escPassword);
+ Query += Ssprintf(", a_priv = %d, a_status = %d, a_bandate = %d", mLevel, mStatus, mBannedUntil);
+ if(!CreateMode )
+ {
+ Query += Ssprintf(" WHERE a_id = %d LIMIT 1", mID);
+ }
+
+ if(MySQL->InfoQuery(Query.c_str()))
+ {
+ Console->Print(RED, BLACK, "[Error] Failed to %s account %s (id %d)", CreateMode ? "create" : "update", mName.c_str(), mID);
+ MySQL->ShowInfoSQLError();
+ return false;
+ }
+ return true;
+}
+
+uint32_t PAccount::GetCharIdBySlot(const uint32_t SlotId)
+{
+ char query[256];
+ uint32_t CharId = 0;
+
+ MYSQL_ROW row = 0;
+ MYSQL_RES *result = 0;
+
+ snprintf(query, 256, "SELECT c_id FROM characters WHERE a_id = %d AND c_slot = %d LIMIT 1;", mID, SlotId);
+
+ result = MySQL->GameResQuery(query);
+ if(result == NULL)
+ {
+ Console->Print(RED, BLACK, "Failed to load CharacterData from SQL");
+ MySQL->ShowGameSQLError();
+ return 0;
+ }
+
+ if((row = mysql_fetch_row(result)))
+ {
+ CharId = atoi(row[0]);
+ }
+
+ MySQL->FreeGameSQLResult(result);
+
+ /*** Temporary workaround to cope with DB where c_slot is not set ***/
+ if(!CharId)
+ {
+ snprintf(query, 256, "SELECT c_id FROM characters WHERE a_id = %d ORDER BY c_slot ASC, c_id ASC LIMIT %d, 1;", mID, SlotId);
+
+ result = MySQL->GameResQuery(query);
+ if(result == NULL)
+ {
+ Console->Print(RED, BLACK, "Failed to load CharacterData from SQL");
+ MySQL->ShowGameSQLError();
+ return 0;
+ }
+
+ if((row = mysql_fetch_row(result)))
+ {
+ CharId = atoi(row[0]);
+ }
+
+ MySQL->FreeGameSQLResult(result);
+ }
+ /*** End of workaround ***/
+
+ return CharId;
+}
+
+
+std::string PAccount::GetBannedTime() const
+{
+ const char* unit[5] = {"seconds", "minutes", "hours", "days", "weeks"};
+
+ std::time_t timediff = mBannedUntil - std::time(NULL);
+ if(timediff <=0)
+ {
+ return "0 more seconds. Please relog";
+ }
+
+ long counter;
+ int type;
+
+ if(timediff > 86400) // days
+ {
+ counter = timediff / 86400;
+ type = 3;
+ }
+ else if(timediff > 3600) // hours
+ {
+ counter = timediff / 3600;
+ type = 2;
+ }
+ else if(timediff > 60) // Minutes
+ {
+ counter = timediff / 60;
+ type = 1;
+ }
+ else // Seconds
+ {
+ counter = timediff;
+ type = 0;
+ }
+
+ return Ssprintf("%d more %s", counter, unit[type]);
+}
-#pragma once\r
-\r
-#include <chrono>\r
-#include <cstdint>\r
-#include <string>\r
-\r
-class RegEx;\r
-\r
-/*\r
-0 = unregistered user\r
-1 = Registered user\r
-30 = volunteer\r
-50 = GM\r
-100 = Admin\r
-*/\r
-\r
-// New way of AccountLevel handling:\r
-// Every level is possible, the following values are only edge values. We need a bit control about that\r
-#define PAL_BANNED -1\r
-#define PAL_UNREGPLAYER 0\r
-#define PAL_REGPLAYER 1\r
-#define PAL_VOLUNTEER 30 // Special Rank: 50/50\r
-#define PAL_GM 50 // Special Rank: 120/120\r
-#define PAL_ADMIN 100 // Special Rank: 127/127\r
-\r
-// Max number of char slots per account\r
-#define MAX_CHARS_PER_ACCOUNT 4\r
-\r
-/*\r
-0 = Offline\r
-1 = Online\r
-2 = Banned\r
-*/\r
-\r
-enum PAccountStatus\r
-{\r
- PAS_OFFLINE = 0,\r
- PAS_ONLINE = 1,\r
- PAS_BANNED = 2\r
-};\r
-\r
-class PAccount {\r
- private :\r
- // SQL Layout\r
- enum {\r
- a_id,\r
- a_username,\r
- a_password,\r
- a_priv,\r
- a_status,\r
- a_bandate\r
- };\r
-\r
- // static members\r
- static RegEx* mUsernameRegexFilter;\r
- static RegEx* mPasswordRegexFilter;\r
-\r
- // instance members\r
- uint32_t mID;\r
- std::string mName;\r
- std::string mPassword;\r
- int mLevel;\r
- PAccountStatus mStatus;\r
- time_t mBannedUntil;\r
-\r
- bool LoadFromQuery(char* query);\r
- bool DecodePassword(const uint8_t* PasswordData, int PassLen, const uint8_t *Key, char* ClearPassword);\r
-\r
- public :\r
- PAccount();\r
- PAccount(const uint32_t AccountId);\r
- PAccount(const char *Username);\r
-\r
- static bool SetUsernameRegexFilter(const char* RegexStr);\r
- static bool SetPasswordRegexFilter(const char* RegexStr);\r
- static bool IsUsernameWellFormed(const char *Username);\r
- static bool IsPasswordWellFormed(const char *Password);\r
-\r
- inline uint32_t GetID() const { return mID; }\r
- bool SetName(const std::string &Pass);\r
- inline const std::string &GetName() const { return mName; }\r
- bool SetPassword(const std::string &Pass);\r
- bool SetPasswordEncoded(const uint8_t* PasswordData, int PassLen, const uint8_t *Key);\r
- inline const std::string &GetPassword() const { return mPassword; }\r
- bool SetLevel(int newLevel);\r
- inline int GetLevel() const { return mLevel; }\r
- std::string GetLevelString() const;\r
- bool SetStatus(PAccountStatus Status);\r
- inline PAccountStatus GetStatus() const { return mStatus; }\r
- bool SetBannedUntilTime(time_t BannedUntil);\r
- inline bool IsBanned() const { return (mBannedUntil > std::time(NULL)); }\r
- std::string GetBannedTime() const;\r
-\r
- bool Authenticate(const uint8_t* PasswordData, int PassLen, const uint8_t *Key);\r
- bool Authenticate(const char *Password) const;\r
-\r
- bool Create();\r
- bool Save(bool CreateMode = false);\r
-\r
- uint32_t GetCharIdBySlot(const uint32_t SlotId);\r
-};\r
+#pragma once
+
+#include <chrono>
+#include <cstdint>
+#include <string>
+
+class RegEx;
+
+/*
+0 = unregistered user
+1 = Registered user
+30 = volunteer
+50 = GM
+100 = Admin
+*/
+
+// New way of AccountLevel handling:
+// Every level is possible, the following values are only edge values. We need a bit control about that
+#define PAL_BANNED -1
+#define PAL_UNREGPLAYER 0
+#define PAL_REGPLAYER 1
+#define PAL_VOLUNTEER 30 // Special Rank: 50/50
+#define PAL_GM 50 // Special Rank: 120/120
+#define PAL_ADMIN 100 // Special Rank: 127/127
+
+// Max number of char slots per account
+#define MAX_CHARS_PER_ACCOUNT 4
+
+/*
+0 = Offline
+1 = Online
+2 = Banned
+*/
+
+enum PAccountStatus
+{
+ PAS_OFFLINE = 0,
+ PAS_ONLINE = 1,
+ PAS_BANNED = 2
+};
+
+class PAccount {
+ private :
+ // SQL Layout
+ enum {
+ a_id,
+ a_username,
+ a_password,
+ a_priv,
+ a_status,
+ a_bandate
+ };
+
+ // static members
+ static RegEx* mUsernameRegexFilter;
+ static RegEx* mPasswordRegexFilter;
+
+ // instance members
+ uint32_t mID;
+ std::string mName;
+ std::string mPassword;
+ int mLevel;
+ PAccountStatus mStatus;
+ time_t mBannedUntil;
+
+ bool LoadFromQuery(char* query);
+ bool DecodePassword(const uint8_t* PasswordData, int PassLen, const uint8_t *Key, char* ClearPassword);
+
+ public :
+ PAccount();
+ PAccount(const uint32_t AccountId);
+ PAccount(const char *Username);
+
+ static bool SetUsernameRegexFilter(const char* RegexStr);
+ static bool SetPasswordRegexFilter(const char* RegexStr);
+ static bool IsUsernameWellFormed(const char *Username);
+ static bool IsPasswordWellFormed(const char *Password);
+
+ inline uint32_t GetID() const { return mID; }
+ bool SetName(const std::string &Pass);
+ inline const std::string &GetName() const { return mName; }
+ bool SetPassword(const std::string &Pass);
+ bool SetPasswordEncoded(const uint8_t* PasswordData, int PassLen, const uint8_t *Key);
+ inline const std::string &GetPassword() const { return mPassword; }
+ bool SetLevel(int newLevel);
+ inline int GetLevel() const { return mLevel; }
+ std::string GetLevelString() const;
+ bool SetStatus(PAccountStatus Status);
+ inline PAccountStatus GetStatus() const { return mStatus; }
+ bool SetBannedUntilTime(time_t BannedUntil);
+ inline bool IsBanned() const { return (mBannedUntil > std::time(NULL)); }
+ std::string GetBannedTime() const;
+
+ bool Authenticate(const uint8_t* PasswordData, int PassLen, const uint8_t *Key);
+ bool Authenticate(const char *Password) const;
+
+ bool Create();
+ bool Save(bool CreateMode = false);
+
+ uint32_t GetCharIdBySlot(const uint32_t SlotId);
+};
-#include <cstring>\r
-#include "GameServer/Includes.hxx"\r
-#include "GameServer/Definitions/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-PAppartements::PAppartements()\r
-{\r
-}\r
-\r
-//PAppartements::~PAppartements() {};\r
-\r
-uint32_t PAppartements::CreateBaseAppartement(uint32_t nCharID, std::string nPassword, uint8_t nFactionID)\r
-{\r
- typedef std::vector< std::pair<int, int> > PAppVector; //<AppType, AppPlace>\r
-\r
- PAppVector CandidateApts;\r
- CandidateApts.reserve(32);\r
- uint16_t j;\r
- int AppType;\r
-\r
- for (std::map<int, PDefAppartement*>::const_iterator i=GameDefs->Appartements()->ConstIteratorBegin(); i!=GameDefs->Appartements()->ConstIteratorEnd(); i++)\r
- {\r
- if (i->second->GetFaction() == nFactionID)\r
- {\r
- for (j = 0; j < i->second->GetPlaceCount(); j++)\r
- {\r
- AppType = i->second->GetID();\r
- if ((AppType < 220) || (AppType >= 250))\r
- {\r
-if (gDevDebug) Console->Print("Added potential Apt of type %d in place %d", AppType, i->second->GetPlace(j));\r
- CandidateApts.push_back(std::make_pair(AppType, i->second->GetPlace(j)));\r
- }\r
- }\r
- }\r
- }\r
-\r
- if(CandidateApts.size())\r
- {\r
- j = GetRandom(CandidateApts.size()-1);\r
-if (gDevDebug) Console->Print("Apt n� %d chosen in %d for faction %d", j+1, CandidateApts.size(), nFactionID);\r
-\r
-if (gDevDebug) Console->Print("Choosed Apt of type %d in place %d", CandidateApts[j].first, CandidateApts[j].second);\r
-\r
- char escPassword[256];\r
- MySQL->EscapeString(nPassword.c_str(), escPassword, 256);\r
- char query[256];\r
- snprintf(query, 256, "INSERT INTO apartments (apt_id,apt_location,apt_type,apt_password, apt_owner) VALUES (NULL,'%d','%d','%s','%d');", CandidateApts[j].second, CandidateApts[j].first, escPassword, nCharID);\r
- if ( MySQL->GameQuery(query) )\r
- {\r
- Console->Print(RED, BLACK, "PAppartements::CreateBaseAppartement could not add some appartement entry in the database");\r
- Console->Print("Query was:");\r
- Console->Print("%s", query);\r
- MySQL->ShowGameSQLError();\r
- return 0;\r
- }\r
- return (MySQL->GetLastGameInsertId());\r
- }\r
- else\r
- return 0;\r
-}\r
-\r
-void PAppartements::DeleteCharAppartements(uint32_t nCharID)\r
-{\r
- char query[256];\r
- snprintf(query, 256, "DELETE FROM apartments WHERE (apt_owner='%u');", nCharID);\r
- if ( MySQL->GameQuery(query) )\r
- {\r
- Console->Print(RED, BLACK, "PAppartements::DeleteCharAppartements could not delete some char %d appartement(s) entry from the database", nCharID);\r
- Console->Print("Query was:");\r
- Console->Print("%s", query);\r
- MySQL->ShowGameSQLError();\r
- }\r
- else\r
-if (gDevDebug) Console->Print(YELLOW, BLACK, "PAppartements::DeleteCharAppartements does not delete appartements content yet"); \r
-}\r
-\r
-bool PAppartements::CanFreelyEnter(PChar* nChar, uint32_t nLocation)\r
-{\r
- uint32_t OwnerID = GetAptOwner(nLocation);\r
- return (OwnerID == nChar->GetID());\r
-\r
- // here we could manage Clan appartements access too.\r
-}\r
-\r
-int PAppartements::GetAptID(unsigned int AptLoc, const uint8_t *pass)\r
-{\r
- int type;\r
- MYSQL_RES *result;\r
- MYSQL_ROW row;\r
- char query[255];\r
-\r
- if(!strcmp((const char*)pass, "Exit"))\r
- return 1;\r
-\r
- char escPassword[255];\r
- MySQL->EscapeString((char*)pass, escPassword, 255);\r
- snprintf(query, 255, "SELECT apt_id FROM apartments WHERE apt_location = %i AND apt_password = '%s'", AptLoc, escPassword);\r
- result = MySQL->GameResQuery(query);\r
-\r
- if(!result)\r
- {\r
- Console->Print("%s Cannot get AppartmentID; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
- MySQL->ShowGameSQLError();\r
- return 0;\r
- }\r
-\r
- if(mysql_num_rows(result) == 0)\r
- {\r
- MySQL->FreeGameSQLResult(result);\r
- return 0;\r
- }\r
- else\r
- {\r
- row = mysql_fetch_row(result);\r
- type = atoi(row[0]);\r
- MySQL->FreeGameSQLResult(result);\r
- }\r
-\r
- return (type + PWorlds::mAptBaseWorldId);\r
-}\r
-\r
-int PAppartements::GetAptType(int AptID)\r
-{\r
- int type;\r
- MYSQL_RES *result;\r
- MYSQL_ROW row;\r
- char query[255];\r
-\r
- snprintf(query, 225, "SELECT apt_type FROM apartments WHERE apt_id = %i", AptID - PWorlds::mAptBaseWorldId);\r
- result = MySQL->GameResQuery(query);\r
-\r
- if(!result)\r
- {\r
- Console->Print("%s Cannot get AppartmentType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
- MySQL->ShowGameSQLError();\r
- return 0;\r
- }\r
-\r
- if(mysql_num_rows(result) == 0)\r
- {\r
- MySQL->FreeGameSQLResult(result);\r
- return 0;\r
- }\r
- else\r
- {\r
- row = mysql_fetch_row(result);\r
- type = atoi(row[0]);\r
- MySQL->FreeGameSQLResult(result);\r
- }\r
-\r
- return type;\r
-}\r
-\r
-int PAppartements::GetAptOwner(int loc)\r
-{\r
- int owner;\r
- MYSQL_RES *result;\r
- MYSQL_ROW row;\r
- char query[255];\r
-\r
- snprintf (query, 255, "SELECT apt_owner FROM apartments WHERE apt_id = %i", loc - PWorlds::mAptBaseWorldId);\r
-\r
- result = MySQL->GameResQuery(query);\r
- if(!result)\r
- {\r
- Console->Print("%s Cannot get AppartmentOwner; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
- MySQL->ShowGameSQLError();\r
- return 0;\r
- }\r
-\r
- if(mysql_num_rows(result) == 0)\r
- {\r
- MySQL->FreeGameSQLResult(result);\r
- return 0;\r
- }\r
- else\r
- {\r
- row = mysql_fetch_row(result);\r
- owner = atoi(row[0]);\r
- MySQL->FreeGameSQLResult(result);\r
- }\r
-\r
- return owner;\r
-}\r
-\r
-int PAppartements::GetAptLocation(int loc)\r
-{\r
- int Location;\r
- MYSQL_RES *result;\r
- MYSQL_ROW row;\r
- char query[255];\r
-\r
- if((uint32_t)loc > PWorlds::mAptBaseWorldId)\r
- loc = loc - PWorlds::mAptBaseWorldId;\r
-\r
- snprintf (query, 255, "SELECT apt_location FROM apartments WHERE apt_id = %i", loc);\r
-\r
-//Console->Print("Q: %s", query);\r
- result = MySQL->GameResQuery(query);\r
- if(!result)\r
- {\r
- Console->Print("%s Cannot get AppartmentLocation; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
- MySQL->ShowGameSQLError();\r
- return 0;\r
- }\r
-\r
- if(mysql_num_rows(result) == 0)\r
- {\r
- MySQL->FreeGameSQLResult(result);\r
- return 0;\r
- }\r
- else\r
- {\r
- row = mysql_fetch_row(result);\r
- Location = atoi(row[0]);\r
- MySQL->FreeGameSQLResult(result);\r
- }\r
-\r
- return Location;\r
-}\r
+#include <cstring>
+#include "GameServer/Includes.hxx"
+#include "GameServer/Definitions/Includes.hxx"
+#include "Common/Includes.hxx"
+
+PAppartements::PAppartements()
+{
+}
+
+//PAppartements::~PAppartements() {};
+
+uint32_t PAppartements::CreateBaseAppartement(uint32_t nCharID, std::string nPassword, uint8_t nFactionID)
+{
+ typedef std::vector< std::pair<int, int> > PAppVector; //<AppType, AppPlace>
+
+ PAppVector CandidateApts;
+ CandidateApts.reserve(32);
+ uint16_t j;
+ int AppType;
+
+ for (std::map<int, PDefAppartement*>::const_iterator i=GameDefs->Appartements()->ConstIteratorBegin(); i!=GameDefs->Appartements()->ConstIteratorEnd(); i++)
+ {
+ if (i->second->GetFaction() == nFactionID)
+ {
+ for (j = 0; j < i->second->GetPlaceCount(); j++)
+ {
+ AppType = i->second->GetID();
+ if ((AppType < 220) || (AppType >= 250))
+ {
+if (gDevDebug) Console->Print("Added potential Apt of type %d in place %d", AppType, i->second->GetPlace(j));
+ CandidateApts.push_back(std::make_pair(AppType, i->second->GetPlace(j)));
+ }
+ }
+ }
+ }
+
+ if(CandidateApts.size())
+ {
+ j = GetRandom(CandidateApts.size()-1);
+if (gDevDebug) Console->Print("Apt n� %d chosen in %d for faction %d", j+1, CandidateApts.size(), nFactionID);
+
+if (gDevDebug) Console->Print("Choosed Apt of type %d in place %d", CandidateApts[j].first, CandidateApts[j].second);
+
+ char escPassword[256];
+ MySQL->EscapeString(nPassword.c_str(), escPassword, 256);
+ char query[256];
+ snprintf(query, 256, "INSERT INTO apartments (apt_id,apt_location,apt_type,apt_password, apt_owner) VALUES (NULL,'%d','%d','%s','%d');", CandidateApts[j].second, CandidateApts[j].first, escPassword, nCharID);
+ if ( MySQL->GameQuery(query) )
+ {
+ Console->Print(RED, BLACK, "PAppartements::CreateBaseAppartement could not add some appartement entry in the database");
+ Console->Print("Query was:");
+ Console->Print("%s", query);
+ MySQL->ShowGameSQLError();
+ return 0;
+ }
+ return (MySQL->GetLastGameInsertId());
+ }
+ else
+ return 0;
+}
+
+void PAppartements::DeleteCharAppartements(uint32_t nCharID)
+{
+ char query[256];
+ snprintf(query, 256, "DELETE FROM apartments WHERE (apt_owner='%u');", nCharID);
+ if ( MySQL->GameQuery(query) )
+ {
+ Console->Print(RED, BLACK, "PAppartements::DeleteCharAppartements could not delete some char %d appartement(s) entry from the database", nCharID);
+ Console->Print("Query was:");
+ Console->Print("%s", query);
+ MySQL->ShowGameSQLError();
+ }
+ else
+if (gDevDebug) Console->Print(YELLOW, BLACK, "PAppartements::DeleteCharAppartements does not delete appartements content yet");
+}
+
+bool PAppartements::CanFreelyEnter(PChar* nChar, uint32_t nLocation)
+{
+ uint32_t OwnerID = GetAptOwner(nLocation);
+ return (OwnerID == nChar->GetID());
+
+ // here we could manage Clan appartements access too.
+}
+
+int PAppartements::GetAptID(unsigned int AptLoc, const uint8_t *pass)
+{
+ int type;
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char query[255];
+
+ if(!strcmp((const char*)pass, "Exit"))
+ return 1;
+
+ char escPassword[255];
+ MySQL->EscapeString((char*)pass, escPassword, 255);
+ snprintf(query, 255, "SELECT apt_id FROM apartments WHERE apt_location = %i AND apt_password = '%s'", AptLoc, escPassword);
+ result = MySQL->GameResQuery(query);
+
+ if(!result)
+ {
+ Console->Print("%s Cannot get AppartmentID; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));
+ MySQL->ShowGameSQLError();
+ return 0;
+ }
+
+ if(mysql_num_rows(result) == 0)
+ {
+ MySQL->FreeGameSQLResult(result);
+ return 0;
+ }
+ else
+ {
+ row = mysql_fetch_row(result);
+ type = atoi(row[0]);
+ MySQL->FreeGameSQLResult(result);
+ }
+
+ return (type + PWorlds::mAptBaseWorldId);
+}
+
+int PAppartements::GetAptType(int AptID)
+{
+ int type;
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char query[255];
+
+ snprintf(query, 225, "SELECT apt_type FROM apartments WHERE apt_id = %i", AptID - PWorlds::mAptBaseWorldId);
+ result = MySQL->GameResQuery(query);
+
+ if(!result)
+ {
+ Console->Print("%s Cannot get AppartmentType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));
+ MySQL->ShowGameSQLError();
+ return 0;
+ }
+
+ if(mysql_num_rows(result) == 0)
+ {
+ MySQL->FreeGameSQLResult(result);
+ return 0;
+ }
+ else
+ {
+ row = mysql_fetch_row(result);
+ type = atoi(row[0]);
+ MySQL->FreeGameSQLResult(result);
+ }
+
+ return type;
+}
+
+int PAppartements::GetAptOwner(int loc)
+{
+ int owner;
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char query[255];
+
+ snprintf (query, 255, "SELECT apt_owner FROM apartments WHERE apt_id = %i", loc - PWorlds::mAptBaseWorldId);
+
+ result = MySQL->GameResQuery(query);
+ if(!result)
+ {
+ Console->Print("%s Cannot get AppartmentOwner; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));
+ MySQL->ShowGameSQLError();
+ return 0;
+ }
+
+ if(mysql_num_rows(result) == 0)
+ {
+ MySQL->FreeGameSQLResult(result);
+ return 0;
+ }
+ else
+ {
+ row = mysql_fetch_row(result);
+ owner = atoi(row[0]);
+ MySQL->FreeGameSQLResult(result);
+ }
+
+ return owner;
+}
+
+int PAppartements::GetAptLocation(int loc)
+{
+ int Location;
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char query[255];
+
+ if((uint32_t)loc > PWorlds::mAptBaseWorldId)
+ loc = loc - PWorlds::mAptBaseWorldId;
+
+ snprintf (query, 255, "SELECT apt_location FROM apartments WHERE apt_id = %i", loc);
+
+//Console->Print("Q: %s", query);
+ result = MySQL->GameResQuery(query);
+ if(!result)
+ {
+ Console->Print("%s Cannot get AppartmentLocation; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));
+ MySQL->ShowGameSQLError();
+ return 0;
+ }
+
+ if(mysql_num_rows(result) == 0)
+ {
+ MySQL->FreeGameSQLResult(result);
+ return 0;
+ }
+ else
+ {
+ row = mysql_fetch_row(result);
+ Location = atoi(row[0]);
+ MySQL->FreeGameSQLResult(result);
+ }
+
+ return Location;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-\r
-class PChar;\r
-\r
-class PAppartements {\r
-public:\r
- PAppartements();\r
- //~PAppartements();\r
-\r
- uint32_t CreateBaseAppartement(uint32_t nCharID, std::string nPassword, uint8_t nFactionID);\r
- void DeleteCharAppartements(uint32_t nCharID);\r
- bool CanFreelyEnter(PChar* nChar, uint32_t nLocation);\r
- int GetAptID(unsigned int AptLoc, const uint8_t *pass);\r
- int GetAptType(int AptID);\r
- int GetAptOwner(int loc);\r
- int GetAptLocation(int loc);\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+class PChar;
+
+class PAppartements {
+public:
+ PAppartements();
+ //~PAppartements();
+
+ uint32_t CreateBaseAppartement(uint32_t nCharID, std::string nPassword, uint8_t nFactionID);
+ void DeleteCharAppartements(uint32_t nCharID);
+ bool CanFreelyEnter(PChar* nChar, uint32_t nLocation);
+ int GetAptID(unsigned int AptLoc, const uint8_t *pass);
+ int GetAptType(int AptID);
+ int GetAptOwner(int loc);
+ int GetAptLocation(int loc);
+};
-#include <cstring>\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-PBuddyList::PBuddyList(uint32_t nOwnerCharID)\r
-{\r
- mOwnerCharID = nOwnerCharID;\r
- mListMaxSize = mListSize = 0;\r
- mCharIDList = NULL;\r
-}\r
-\r
-PBuddyList::~PBuddyList()\r
-{\r
-\r
- if (mCharIDList)\r
- delete[] mCharIDList;\r
-}\r
-\r
-bool PBuddyList::AddChar(uint32_t nBuddyCharID)\r
-{\r
- char query[256];\r
-\r
- if ((FindEntry(nBuddyCharID) >= mListSize) && (mListSize < 255))\r
- {\r
- if (mListSize == mListMaxSize)\r
- {\r
- IncreaseMaxSize();\r
- }\r
- mCharIDList[mListSize++] = nBuddyCharID;\r
-\r
- snprintf(query, 256, "INSERT INTO buddy_list (bud_id,bud_charid,bud_buddyid) VALUES (NULL,'%u','%u');", mOwnerCharID, nBuddyCharID);\r
- if ( MySQL->GameQuery(query) )\r
- {\r
- Console->Print(RED, BLACK, "PBuddyList::AddChar could not add some buddylisdt entry in the database");\r
- Console->Print("Query was:");\r
- Console->Print("%s", query);\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
-\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-bool PBuddyList::RemoveChar(uint32_t nBuddyCharID)\r
-{\r
- char query[256];\r
- uint8_t rEntry, i;\r
-\r
- if ((rEntry = FindEntry(nBuddyCharID)) < mListSize)\r
- {\r
- --mListSize;\r
- for (i = rEntry; i < mListSize; i++)\r
- {\r
- mCharIDList[i] = mCharIDList[i+1];\r
- }\r
- // Remove from DB here\r
- snprintf(query, 256, "DELETE FROM buddy_list WHERE ((bud_charid='%u') AND (bud_buddyid='%u')) LIMIT 1;", mOwnerCharID, nBuddyCharID);\r
- if ( MySQL->GameQuery(query) )\r
- {\r
- Console->Print(RED, BLACK, "PBuddyList::AddChar could not delete some buddylist entry from the database");\r
- Console->Print("Query was:");\r
- Console->Print("%s", query);\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
-\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-bool PBuddyList::SQLLoad()\r
-{\r
- char query[256];\r
- MYSQL_RES *result;\r
- MYSQL_ROW row;\r
- uint8_t EntriesNum;\r
-\r
- snprintf(query, 256, "SELECT * FROM buddy_list WHERE (bud_charid='%u')", mOwnerCharID);\r
- result = MySQL->GameResQuery(query);\r
- if(result == NULL)\r
- {\r
- Console->Print(RED, BLACK, "PBuddyList::SQLLoad could not load buddylist entry from the database");\r
- Console->Print("Query was:");\r
- Console->Print("%s", query);\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
- //Console->Print(GREEN, BLACK, "PBuddyList::SQLLoad Loading buddylist for char %d", mOwnerCharID);\r
- mListSize = 0;\r
- if((EntriesNum = mysql_num_rows(result)))\r
- {\r
- IncreaseMaxSize(EntriesNum);\r
-\r
- while((row = mysql_fetch_row(result)))\r
- {\r
- mCharIDList[mListSize++] = atoi(row[bud_buddyid]);\r
- //Console->Print(GREEN, BLACK, "PBuddyList::SQLLoad Buddylist entry %d : char %d", mListSize, mCharIDList[mListSize-1]);\r
- }\r
- }\r
- MySQL->FreeGameSQLResult(result);\r
- return true;\r
-}\r
-\r
-void PBuddyList::IncreaseMaxSize(uint8_t nNewMax)\r
-{\r
- uint16_t tmpSize;\r
-\r
- if (!nNewMax)\r
- {\r
- tmpSize = mListMaxSize + BUDDYLIST_ALLOC_SIZE;\r
- }\r
- else if (nNewMax > mListMaxSize)\r
- {\r
- tmpSize = nNewMax / BUDDYLIST_ALLOC_SIZE;\r
- if (nNewMax % BUDDYLIST_ALLOC_SIZE)\r
- ++tmpSize;\r
- tmpSize *= BUDDYLIST_ALLOC_SIZE;\r
- }\r
- else\r
- return;\r
-\r
- mListMaxSize = (tmpSize < 256) ? tmpSize : 255;\r
-\r
- uint32_t* tmpList = new uint32_t[mListMaxSize];\r
- if (mCharIDList)\r
- {\r
- if (mListSize)\r
- {\r
- memcpy(tmpList, mCharIDList, sizeof(uint32_t) * mListSize);\r
- }\r
-\r
- delete[] mCharIDList;\r
- }\r
- mCharIDList = tmpList;\r
-}\r
-\r
-uint8_t PBuddyList::FindEntry(uint32_t CharID)\r
-{\r
- uint8_t i = 255;\r
-\r
- if (mCharIDList)\r
- {\r
- for (i = 0; i < mListSize; i++)\r
- {\r
- if (mCharIDList[i] == CharID)\r
- break;\r
- }\r
- }\r
-\r
- return i;\r
-}\r
-\r
-bool PBuddyList::IsInBuddy(uint32_t CharID)\r
-{\r
- if (mCharIDList)\r
- {\r
- for (uint8_t i = 0; i < mListSize; i++)\r
- {\r
- if (mCharIDList[i] == CharID)\r
- return true;\r
- }\r
- }\r
- return false;\r
-}\r
+#include <cstring>
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+PBuddyList::PBuddyList(uint32_t nOwnerCharID)
+{
+ mOwnerCharID = nOwnerCharID;
+ mListMaxSize = mListSize = 0;
+ mCharIDList = NULL;
+}
+
+PBuddyList::~PBuddyList()
+{
+
+ if (mCharIDList)
+ delete[] mCharIDList;
+}
+
+bool PBuddyList::AddChar(uint32_t nBuddyCharID)
+{
+ char query[256];
+
+ if ((FindEntry(nBuddyCharID) >= mListSize) && (mListSize < 255))
+ {
+ if (mListSize == mListMaxSize)
+ {
+ IncreaseMaxSize();
+ }
+ mCharIDList[mListSize++] = nBuddyCharID;
+
+ snprintf(query, 256, "INSERT INTO buddy_list (bud_id,bud_charid,bud_buddyid) VALUES (NULL,'%u','%u');", mOwnerCharID, nBuddyCharID);
+ if ( MySQL->GameQuery(query) )
+ {
+ Console->Print(RED, BLACK, "PBuddyList::AddChar could not add some buddylisdt entry in the database");
+ Console->Print("Query was:");
+ Console->Print("%s", query);
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+
+ return true;
+ }
+ else
+ return false;
+}
+
+bool PBuddyList::RemoveChar(uint32_t nBuddyCharID)
+{
+ char query[256];
+ uint8_t rEntry, i;
+
+ if ((rEntry = FindEntry(nBuddyCharID)) < mListSize)
+ {
+ --mListSize;
+ for (i = rEntry; i < mListSize; i++)
+ {
+ mCharIDList[i] = mCharIDList[i+1];
+ }
+ // Remove from DB here
+ snprintf(query, 256, "DELETE FROM buddy_list WHERE ((bud_charid='%u') AND (bud_buddyid='%u')) LIMIT 1;", mOwnerCharID, nBuddyCharID);
+ if ( MySQL->GameQuery(query) )
+ {
+ Console->Print(RED, BLACK, "PBuddyList::AddChar could not delete some buddylist entry from the database");
+ Console->Print("Query was:");
+ Console->Print("%s", query);
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+
+ return true;
+ }
+ else
+ return false;
+}
+
+bool PBuddyList::SQLLoad()
+{
+ char query[256];
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ uint8_t EntriesNum;
+
+ snprintf(query, 256, "SELECT * FROM buddy_list WHERE (bud_charid='%u')", mOwnerCharID);
+ result = MySQL->GameResQuery(query);
+ if(result == NULL)
+ {
+ Console->Print(RED, BLACK, "PBuddyList::SQLLoad could not load buddylist entry from the database");
+ Console->Print("Query was:");
+ Console->Print("%s", query);
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+ //Console->Print(GREEN, BLACK, "PBuddyList::SQLLoad Loading buddylist for char %d", mOwnerCharID);
+ mListSize = 0;
+ if((EntriesNum = mysql_num_rows(result)))
+ {
+ IncreaseMaxSize(EntriesNum);
+
+ while((row = mysql_fetch_row(result)))
+ {
+ mCharIDList[mListSize++] = atoi(row[bud_buddyid]);
+ //Console->Print(GREEN, BLACK, "PBuddyList::SQLLoad Buddylist entry %d : char %d", mListSize, mCharIDList[mListSize-1]);
+ }
+ }
+ MySQL->FreeGameSQLResult(result);
+ return true;
+}
+
+void PBuddyList::IncreaseMaxSize(uint8_t nNewMax)
+{
+ uint16_t tmpSize;
+
+ if (!nNewMax)
+ {
+ tmpSize = mListMaxSize + BUDDYLIST_ALLOC_SIZE;
+ }
+ else if (nNewMax > mListMaxSize)
+ {
+ tmpSize = nNewMax / BUDDYLIST_ALLOC_SIZE;
+ if (nNewMax % BUDDYLIST_ALLOC_SIZE)
+ ++tmpSize;
+ tmpSize *= BUDDYLIST_ALLOC_SIZE;
+ }
+ else
+ return;
+
+ mListMaxSize = (tmpSize < 256) ? tmpSize : 255;
+
+ uint32_t* tmpList = new uint32_t[mListMaxSize];
+ if (mCharIDList)
+ {
+ if (mListSize)
+ {
+ memcpy(tmpList, mCharIDList, sizeof(uint32_t) * mListSize);
+ }
+
+ delete[] mCharIDList;
+ }
+ mCharIDList = tmpList;
+}
+
+uint8_t PBuddyList::FindEntry(uint32_t CharID)
+{
+ uint8_t i = 255;
+
+ if (mCharIDList)
+ {
+ for (i = 0; i < mListSize; i++)
+ {
+ if (mCharIDList[i] == CharID)
+ break;
+ }
+ }
+
+ return i;
+}
+
+bool PBuddyList::IsInBuddy(uint32_t CharID)
+{
+ if (mCharIDList)
+ {
+ for (uint8_t i = 0; i < mListSize; i++)
+ {
+ if (mCharIDList[i] == CharID)
+ return true;
+ }
+ }
+ return false;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-\r
-#define BUDDYLIST_ALLOC_SIZE 4 // atomicity of list entries allocation\r
-\r
-class PBuddyList {\r
- private:\r
- enum { // buddy_list DB Table fields\r
- bud_id = 0,\r
- bud_charid,\r
- bud_buddyid\r
- };\r
-\r
- uint32_t mOwnerCharID;\r
- uint8_t mListMaxSize;\r
- uint8_t mListSize;\r
- uint32_t* mCharIDList;\r
-\r
- void IncreaseMaxSize(uint8_t nNewMax = 0);\r
- uint8_t FindEntry(uint32_t CharID);\r
-\r
- public:\r
- PBuddyList(uint32_t nOwnerCharID);\r
- ~PBuddyList();\r
- bool AddChar(uint32_t nBuddyCharID);\r
- bool RemoveChar(uint32_t nBuddyCharID);\r
- inline uint8_t Count() { return mListSize; }\r
- uint16_t GetListDataSize() { return (sizeof(uint32_t) * mListSize); }\r
- const void* GetListData() { return (const void*)mCharIDList; }\r
- bool SQLLoad();\r
-\r
- bool IsInBuddy(uint32_t CharID);\r
-// bool SQLSave();\r
-};\r
+#pragma once
+
+#include <cstdint>
+
+#define BUDDYLIST_ALLOC_SIZE 4 // atomicity of list entries allocation
+
+class PBuddyList {
+ private:
+ enum { // buddy_list DB Table fields
+ bud_id = 0,
+ bud_charid,
+ bud_buddyid
+ };
+
+ uint32_t mOwnerCharID;
+ uint8_t mListMaxSize;
+ uint8_t mListSize;
+ uint32_t* mCharIDList;
+
+ void IncreaseMaxSize(uint8_t nNewMax = 0);
+ uint8_t FindEntry(uint32_t CharID);
+
+ public:
+ PBuddyList(uint32_t nOwnerCharID);
+ ~PBuddyList();
+ bool AddChar(uint32_t nBuddyCharID);
+ bool RemoveChar(uint32_t nBuddyCharID);
+ inline uint8_t Count() { return mListSize; }
+ uint16_t GetListDataSize() { return (sizeof(uint32_t) * mListSize); }
+ const void* GetListData() { return (const void*)mCharIDList; }
+ bool SQLLoad();
+
+ bool IsInBuddy(uint32_t CharID);
+// bool SQLSave();
+};
-#include <cstring>\r
-#include "GameServer/Includes.hxx"\r
-#include "GameServer/Definitions/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-// PCharCoordinates\r
-void PCharCoordinates::SetInterpolate( PCharCoordinates& Pos1, PCharCoordinates& Pos2, float nCoef )\r
-{\r
- if (( nCoef < 0 ) || ( nCoef > 1 ) )\r
- {\r
- Console->Print( RED, BLACK, "[Error] PCharCoordinates::Interpolate : Invalid nCoef value: %f", nCoef );\r
- nCoef = 0;\r
- }\r
- float rCoef = 1 - nCoef;\r
-\r
- mY = ( uint16_t )( rCoef * Pos1.mY + nCoef * Pos2.mY );\r
- mZ = ( uint16_t )( rCoef * Pos1.mZ + nCoef * Pos2.mZ );\r
- mX = ( uint16_t )( rCoef * Pos1.mX + nCoef * Pos2.mX );\r
- mUD = ( uint8_t )( rCoef * Pos1.mUD + nCoef * Pos2.mUD );\r
- if ( abs( Pos1.mLR - Pos2.mLR ) < 90 )\r
- {\r
- mLR = ( uint8_t )( rCoef * Pos1.mLR + nCoef * Pos2.mLR );\r
- }\r
- else\r
- {\r
- mLR = ( uint8_t )(( uint16_t )( rCoef * ( 180.0 + ( float )Pos1.mLR ) + nCoef * Pos2.mLR ) % 180 );\r
- }\r
-}\r
-\r
-uint16_t mY; // Y-Position in world\r
-uint16_t mZ; // Z-Position in world\r
-uint16_t mX; // X-Position in world\r
-uint8_t mUD; // Up - Mid - Down (d6 - 80 - 2a)\r
-uint8_t mLR; // Compass direction (S..E..N..W..S [0-45-90-135-179])\r
-uint8_t mAct; // Last user action state\r
-\r
-void PCharCoordinates::SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD, uint8_t nLR )\r
-{\r
- mY = nY;\r
- mZ = nZ;\r
- mX = nX;\r
- mUD = nUD;\r
- if ( mUD < 0x2a )\r
- {\r
- mUD = 0x2a;\r
- }\r
- else if ( mUD > 0xd6 )\r
- {\r
- mUD = 0xd6;\r
- }\r
- mLR = nLR % 180;\r
-}\r
-\r
-\r
-// SQL Layout\r
-enum\r
-{\r
- c_id,\r
- c_name,\r
- c_str_lvl,\r
- c_str_pts,\r
- c_int_lvl,\r
- c_int_pts,\r
- c_dex_lvl,\r
- c_dex_pts,\r
- c_con_lvl,\r
- c_con_pts,\r
- c_psi_lvl,\r
- c_psi_pts,\r
- a_id,\r
- c_class,\r
- c_profession,\r
- c_sex,\r
- c_location,\r
- c_mc,\r
- c_hc,\r
- c_tra,\r
- c_pc,\r
- c_rc,\r
- c_tc,\r
- c_vhc,\r
- c_agl,\r
- c_rep,\r
- c_rec,\r
- c_rcl,\r
- c_atl,\r
- c_end,\r
- c_for,\r
- c_fir,\r
- c_enr,\r
- c_xrr,\r
- c_por,\r
- c_hlt,\r
- c_hck,\r
- c_brt,\r
- c_psu,\r
- c_wep,\r
- c_cst,\r
- c_res,\r
- c_imp,\r
- c_ppu,\r
- c_apu,\r
- c_mst,\r
- c_ppw,\r
- c_psr,\r
- c_wpw,\r
- c_apt,\r
- c_cash,\r
- c_head,\r
- c_torso,\r
- c_legs,\r
- c_str_xp,\r
- c_int_xp,\r
- c_dex_xp,\r
- c_psi_xp,\r
- c_con_xp,\r
- c_pos_x,\r
- c_pos_y,\r
- c_pos_z,\r
- c_angle_ud,\r
- c_angle_lr,\r
- c_faction,\r
- c_slot,\r
- c_online,\r
- c_clan,\r
- c_soullight\r
-};\r
-\r
-RegEx* PChar::mCharnameRegexFilter = NULL;\r
-\r
-PChar::PChar()\r
-{\r
- mID = 0;\r
- mAccount = 0;\r
- mGender = 0;\r
- mClass = 0;\r
- mProfession = 1;\r
- mFaction = 1;\r
- //mModel = 0;\r
- //mType = 0;\r
- mRealHead = 0; // Base Skin elements, in complement of (computed) mType\r
- mRealTorso = 0; // " Head shouldn't be changeable, except in case of surgery !!!\r
- mRealLegs = 0; // "\r
- mSkin = 0; // Current Skin elements\r
- mHead = 0; // "\r
- mTorso = 0; // "\r
- mLegs = 0; // "\r
- mHeadColor = mTorsoColor = mLegsColor = 0; // "\r
- mHeadDarkness = mTorsoDarkness = mLegsDarkness = 0; // "\r
-\r
- mBodyEffect = 0;\r
- mBodyEffectDensity = 0;\r
- mQuickBeltActiveSlot = INV_WORN_QB_NONE;\r
-\r
- mLookingAt = 0;\r
- mLookAtTimestamp = 0;\r
- mLastUsedWorldObjectId = 0;\r
-\r
- mSpeedOverride = 255; // means no override. Value 0 can be used to forbid any move.\r
-\r
- mLocationLeased = false; // temp until char on-demand load/unload\r
- mLocation = 0;\r
- mStartApt = 0;\r
- mPrimaryApt = 0;\r
- mCash = 0;\r
-\r
- mSeatInUseType = seat_none;\r
- mSeatInUseObjectId = 0;\r
- mSeatInUseSeatId = 0;\r
- mVhcAccessRequestList = NULL;\r
-\r
- mContainerInExclusiveUse = NULL;\r
-\r
- mIsOnline = false;\r
- mDirtyFlag = false;\r
-\r
- mShunned = false;\r
- mJailed = false;\r
-\r
- mDialogNPC = 0;\r
- mCurrentDialogNode = 0;\r
-\r
- Skill = new PSkillHandler();\r
- mBuddyList = NULL;\r
- mGenrepList = NULL;\r
-\r
- // Required for initial OOC Broadcast welcome message.\r
- //Gets overwritten as soon as the first PingPacket arrives\r
- mActiveChatChannels = 262144;\r
- mClanLevel = 0;\r
- mClanID = 0;\r
-}\r
-\r
-PChar::~PChar()\r
-{\r
- // Addition; Set char's online status to OFFLINE\r
- char sqlqry[50];\r
- snprintf(sqlqry, 50, "UPDATE characters SET c_online = 0 WHERE c_id = %d", mID);\r
- MySQL->GameQuery(sqlqry);\r
-\r
- delete Skill;\r
- delete mBuddyList;\r
- delete mGenrepList;\r
- delete mVhcAccessRequestList;\r
-\r
- if ( mContainerInExclusiveUse )\r
- {\r
- mContainerInExclusiveUse->EndUse( mID );\r
- Console->Print( RED, BLACK, "Warning: PChar::~PChar : Char still had exclusive use of container. Now freed." );\r
- }\r
-\r
- if ( mSeatInUseType != seat_none )\r
- {\r
- Console->Print( RED, BLACK, "Warning: PChar::~PChar : Char still using seat %d of vhc or chair %d.", mSeatInUseSeatId, mSeatInUseObjectId );\r
- }\r
-}\r
-\r
-bool PChar::SetCharnameRegexFilter( const char* RegexStr )\r
-{\r
- if ( mCharnameRegexFilter )\r
- {\r
- delete mCharnameRegexFilter;\r
- mCharnameRegexFilter = NULL;\r
- }\r
-\r
- if ( RegexStr )\r
- {\r
- try\r
- {\r
- mCharnameRegexFilter = new RegEx( RegexStr, PCRE_CASELESS );\r
- }\r
- catch ( ... )\r
- {\r
- return false;\r
- }\r
- }\r
- return true;\r
-}\r
-\r
-bool PChar::IsCharnameWellFormed( const char *Charname )\r
-{\r
- if ( mCharnameRegexFilter )\r
- {\r
- return mCharnameRegexFilter->Search( Charname );\r
- }\r
- else\r
- return true;\r
-}\r
-\r
-void PChar::SetProfession( uint32_t Profession )\r
-{\r
- const PDefCharKind *def = GameDefs->CharKinds()->GetDef( Profession );\r
- if ( def == NULL )\r
- {\r
- Console->Print( RED, BLACK, "Char %d: Invalid profession %d", mID, Profession );\r
- mProfession = 10;\r
- mClass = 0;\r
- }\r
- else\r
- {\r
- mProfession = Profession;\r
- mClass = def->GetType();\r
- }\r
- SetDirtyFlag();\r
-}\r
-\r
-uint32_t PChar::GetSkinFromCharType( uint32_t nType )\r
-{\r
- const PDefCharacter* nDefCharacter = GameDefs->Chars()->GetDef( nType );\r
- if ( nDefCharacter )\r
- {\r
- return (( uint32_t )( nDefCharacter->GetModel() ) );\r
- }\r
- else\r
- return 0;\r
-}\r
-\r
-inline uint32_t PChar::GetBaseModel()\r
-{\r
- return GetSkinFromCharType( GetType() );\r
-}\r
-\r
-void PChar::SetRealLook( uint32_t nHead, uint32_t nTorso, uint32_t nLegs )\r
-{\r
- mRealHead = nHead;\r
- mRealTorso = nTorso;\r
- mRealLegs = nLegs;\r
- SetDirtyFlag();\r
- ResetCurrentLook();\r
-}\r
-\r
-void PChar::GetRealLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs )\r
-{\r
- nSkin = GetBaseModel();\r
- nHead = mRealHead;\r
- nTorso = mRealTorso;\r
- nLegs = mRealLegs;\r
-}\r
-\r
-void PChar::SetCurrentLookFromCharType( uint32_t nType )\r
-{\r
- int iHead, iTorso, iLegs;\r
- uint32_t nSkin, nHead, nTorso, nLegs;\r
- uint8_t nColor, nBrightness;\r
-\r
- const PDefCharacter* nDefCharacter = GameDefs->Chars()->GetDef( nType );\r
- if ( nDefCharacter )\r
- {\r
- nSkin = ( uint32_t ) nDefCharacter->GetModel();\r
- iHead = nDefCharacter->GetHead();\r
- iTorso = nDefCharacter->GetTorso();\r
- iLegs = nDefCharacter->GetLegs();\r
- nColor = ( uint8_t )( 0xff & nDefCharacter->GetColor() );\r
- nBrightness = ( uint8_t )( 0xff & nDefCharacter->GetBrightness() );\r
-\r
-\r
- if (( iHead < 0 ) || ( iTorso < 0 ) || ( iLegs < 0 ) )\r
- {\r
- nHead = nTorso = nLegs = 0;\r
- }\r
- else\r
- {\r
- nHead = iHead % 10;\r
- nTorso = iTorso % 10;\r
- nLegs = iLegs % 10;\r
- }\r
-\r
- SetCurrentLook( nSkin, nHead, nTorso, nLegs );\r
- SetCurrentBodyColor( nColor, nColor, nColor, nBrightness, nBrightness, nBrightness );\r
- }\r
-}\r
-\r
-void PChar::SetCurrentLook( uint32_t nSkin, uint32_t nHead, uint32_t nTorso, uint32_t nLegs )\r
-{\r
- mSkin = nSkin;\r
- mHead = nHead;\r
- mTorso = nTorso;\r
- mLegs = nLegs;\r
- // Ingame skin update will be done automagically in the normal update flow\r
- // A flag could also be set somewhere (preferably in Char si that we don't have to care if ingame or not)\r
- // to request quicker ingame update\r
-}\r
-\r
-void PChar::ResetCurrentLook()\r
-{\r
- SetCurrentLook( GetSkinFromCharType( GetType() ), mRealHead, mRealTorso, mRealLegs );\r
-}\r
-\r
-// GetCurrentLook will later have to take Power Armors and GM overrides into account\r
-void PChar::GetCurrentLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs )\r
-{\r
- nSkin = mSkin;\r
- nHead = mHead;\r
- nTorso = mTorso;\r
- nLegs = mLegs;\r
-}\r
-\r
-void PChar::SetCurrentBodyColor( uint8_t nHeadColor, uint8_t nTorsoColor, uint8_t nLegsColor, uint8_t nHeadDarkness, uint8_t nTorsoDarkness, uint8_t nLegsDarkness )\r
-{\r
- mHeadColor = nHeadColor;\r
- mTorsoColor = nTorsoColor;\r
- mLegsColor = nLegsColor;\r
- mHeadDarkness = nHeadDarkness;\r
- mTorsoDarkness = nTorsoDarkness;\r
- mLegsDarkness = nLegsDarkness;\r
-}\r
-\r
-void PChar::GetCurrentBodyColor( uint8_t &nHeadColor, uint8_t &nTorsoColor, uint8_t &nLegsColor, uint8_t &nHeadDarkness, uint8_t &nTorsoDarkness, uint8_t &nLegsDarkness )\r
-{\r
- nHeadColor = mHeadColor;\r
- nTorsoColor = mTorsoColor;\r
- nLegsColor = mLegsColor;\r
- nHeadDarkness = mHeadDarkness;\r
- nTorsoDarkness = mTorsoDarkness;\r
- nLegsDarkness = mLegsDarkness;\r
-}\r
-\r
-void PChar::SetBaseSkills()\r
-{\r
- const PDefCharKind *def = GameDefs->CharKinds()->GetDef( mProfession );\r
- //Console->Print(YELLOW, BLACK, "PChar::SetBaseSkills() Profession: %d",def->GetIndex());\r
- if ( def == NULL )\r
- {\r
- Console->Print( RED, BLACK, "PChar::SetBaseSkills: GetCharKindDef=NULL" );\r
- return;\r
- }\r
- Skill->SetMainSkill( MS_INT, def->GetSkillInfo( MS_INT ).mStart );\r
- Skill->SetMainSkill( MS_CON, def->GetSkillInfo( MS_CON ).mStart );\r
- Skill->SetMainSkill( MS_DEX, def->GetSkillInfo( MS_DEX ).mStart );\r
- Skill->SetMainSkill( MS_STR, def->GetSkillInfo( MS_STR ).mStart );\r
- Skill->SetMainSkill( MS_PSI, def->GetSkillInfo( MS_PSI ).mStart );\r
- // management of SP needed ? NC Client seem to calculate what remains ...\r
- // or put SP setting after subskill setting ?\r
- /* Skill->SetSP(MS_INT, (short) ??? ));\r
- Skill->SetSP(MS_CON, ((short) ??? ));\r
- Skill->SetSP(MS_DEX, (short) ??? ));\r
- Skill->SetSP(MS_STR, (short) ??? ));\r
- Skill->SetSP(MS_PSI, ((short) ??? )); */\r
- // what about XPs ?\r
- /* Skill->SetXP(MS_INT, ??? ));\r
- Skill->SetXP(MS_CON, ??? ));\r
- Skill->SetXP(MS_DEX, ??? ));\r
- Skill->SetXP(MS_STR, ??? ));\r
- Skill->SetXP(MS_PSI, ??? )); */\r
- Console->Print( YELLOW, BLACK, "PChar::SetBaseSkills() not fully functionnal - unused skill points will be lost" );\r
-}\r
-\r
-void PChar::SetBaseSubskills( uint8_t NSZNb, const char* NonZeroSubskills )\r
-{\r
- int i;\r
-\r
- if ( NSZNb == 0 )\r
- return;\r
-\r
- for ( i = 0; i < NSZNb; i++ )\r
- {\r
- Skill->SetSubSkill(( SUB_SKILLS ) NonZeroSubskills[2 * i], ( int ) NonZeroSubskills[2 * i +1] );\r
- }\r
-}\r
-\r
-void PChar::SetBaseInventory()\r
-{\r
- uint8_t i;\r
- uint32_t BaseItemID;\r
- const PDefCharKind *def = GameDefs->CharKinds()->GetDef( mProfession );\r
-\r
- //mCash = 5000;\r
- mCash = def->GetStartMoney();\r
-\r
- for ( i = 0; i < 8 ; i++ )\r
- {\r
- BaseItemID = def->GetStartInventory( i );\r
- if ( BaseItemID )\r
- {\r
- if ( gDevDebug ) Console->Print( GREEN, BLACK, "Adding item %d to base inventory", BaseItemID );\r
- PItem* NewItem = new PItem( BaseItemID );\r
- if ( NewItem->GetItemID() )\r
- {\r
- NewItem->MakeItemStandard( 120, 180 ); // global quality range\r
- mInventory.AddItem( NewItem );\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "Invalid item ID %d in base inventory for profession %d", BaseItemID, mProfession );\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChar::LoadClanLevel()\r
-{\r
- MYSQL_RES *result;\r
- char query[200];\r
-\r
- snprintf(query, 200, "SELECT cll_level FROM clanlevels WHERE cll_charid = %d AND cll_clanid = %d", mID, mClanID);\r
- result = MySQL->GameResQuery( query );\r
- if ( result == NULL )\r
- {\r
- mClanID = 0;\r
- Console->Print( RED, BLACK, "PChar::GetClanLevel could not load ClanLevel from the database" );\r
- Console->Print( "Query was:" );\r
- Console->Print( "%s", query );\r
- MySQL->ShowGameSQLError();\r
- return;\r
- }\r
- else if(mysql_num_rows(result) == 0)\r
- {\r
- mClanID = 0;\r
- Console->Print( RED, BLACK, "PChar::GetClanLevel No level entry found for clan!" );\r
- return;\r
- }\r
- mClanLevel = atoi(mysql_fetch_row(result)[0]);\r
- if (gDevDebug) Console->Print("Loaded ClanLevel %d for char %d, clan %d", mClanLevel, mID, mClanID);\r
-}\r
-\r
-bool PChar::SQLLoad( int CharID )\r
-{\r
- MYSQL_RES *result;\r
- MYSQL_ROW row;\r
- char query[1024];\r
-\r
- snprintf( query, 1024, "SELECT * FROM characters WHERE c_id = %d LIMIT 1", CharID );\r
- result = MySQL->GameResQuery( query );\r
- if ( result == NULL )\r
- {\r
- Console->Print( RED, BLACK, "PChar::SQLLoad could not load Chardata from the database" );\r
- Console->Print( "Query was:" );\r
- Console->Print( "%s", query );\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
- if (( row = mysql_fetch_row( result ) ) )\r
- {\r
- SetID( CharID );\r
- SetName( row[c_name] );\r
- SetAccount( atoi( row[a_id] ) );\r
-\r
- // Gender\r
- int genvalue = atoi( row[c_sex] );\r
- if (( genvalue == 0 ) || ( genvalue == 1 ) )\r
- mGender = static_cast<uint32_t>( genvalue );\r
- else\r
- {\r
- Console->Print( RED, BLACK, "Bad gender value: %d (Char ID %d)", genvalue, mID );\r
- mGender = 0;\r
- }\r
-\r
- // Profession\r
- int profvalue = atoi( row[c_profession] );\r
- SetProfession( static_cast<uint32_t>( profvalue ) );\r
-\r
- // Class\r
- //int classvalue = atoi(row[c_class]);\r
- //if(classvalue < 4)\r
- // mClass = static_cast<uint32_t>(classvalue);\r
- //else\r
- //{\r
- // Console->Print(RED, BLACK, "Bad class value: %d (Char ID %d)", classvalue, mID);\r
- // classvalue = 0;\r
- //}\r
-\r
- // Faction\r
- int facvalue = atoi( row[c_faction] );\r
- if ( GameDefs->Factions()->GetDef( facvalue ) )\r
- mFaction = static_cast<uint32_t>( facvalue );\r
- else\r
- mFaction = 1;\r
-\r
- /* // Model\r
- int modvalue = atoi(row[c_model]);\r
- mModel = static_cast<uint32_t>(modvalue);\r
- mModel = 10; */\r
- int headvalue = atoi( row[c_head] );\r
- int torsovalue = atoi( row[c_torso] );\r
- int legsvalue = atoi( row[c_legs] );\r
- SetRealLook( static_cast<uint32_t>( headvalue ), static_cast<uint32_t>( torsovalue ), static_cast<uint32_t>( legsvalue ) );\r
-\r
- // Type\r
- /*\r
- int typevalue = std::atoi(row[c_type]);\r
- mType = static_cast<uint32_t>(typevalue);\r
- //mType = 1; */\r
-\r
- // Location\r
- int locvalue = atoi( row[c_location] );\r
- mLocation = static_cast<uint32_t>( locvalue );\r
-\r
-//This assumption is not so good ... hardcoding jailed state linked with location ...\r
- if ( mLocation == 550 || mLocation == 551 )\r
- mJailed = true;\r
-\r
- int posvalue = atoi( row[c_pos_x] );\r
- Coords.mX = static_cast<uint16_t>( posvalue );\r
- posvalue = atoi( row[c_pos_y] );\r
- Coords.mY = static_cast<uint16_t>( posvalue );\r
- posvalue = atoi( row[c_pos_z] );\r
- Coords.mZ = static_cast<uint16_t>( posvalue );\r
- posvalue = atoi( row[c_angle_ud] );\r
- Coords.mUD = static_cast<uint8_t>( posvalue );\r
- posvalue = atoi( row[c_angle_lr] );\r
- Coords.mLR = static_cast<uint8_t>( posvalue );\r
-\r
- int primapt = atoi( row[c_apt] );\r
- mPrimaryApt = static_cast<uint32_t>( primapt );\r
- mStartApt = mPrimaryApt;\r
-\r
- mSoullight = atoi( row[c_soullight] );\r
- mClanID = atoi( row[c_clan] );\r
- if(mClanID > 0)\r
- LoadClanLevel();\r
-\r
- // Cash\r
- float cashvalue = atof( row[c_cash] );\r
- mCash = static_cast<uint32_t>( cashvalue );\r
-\r
- // ---------------------------------------------\r
- // Loading skills --- MAIN Skills with SP and XP\r
- // ---------------------------------------------\r
- Skill->SetMainSkill( MS_INT, atoi( row[c_int_lvl] ) );\r
- Skill->SetMainSkill( MS_CON, atoi( row[c_con_lvl] ) );\r
- Skill->SetMainSkill( MS_DEX, atoi( row[c_dex_lvl] ) );\r
- Skill->SetMainSkill( MS_STR, atoi( row[c_str_lvl] ) );\r
- Skill->SetMainSkill( MS_PSI, atoi( row[c_psi_lvl] ) );\r
- // ---------------------------------------------\r
- Skill->SetSP( MS_INT, ( short )atoi( row[c_int_pts] ) );\r
- Skill->SetSP( MS_CON, ( short )atoi( row[c_con_pts] ) );\r
- Skill->SetSP( MS_DEX, ( short )atoi( row[c_dex_pts] ) );\r
- Skill->SetSP( MS_STR, ( short )atoi( row[c_str_pts] ) );\r
- Skill->SetSP( MS_PSI, ( short )atoi( row[c_psi_pts] ) );\r
- // ---------------------------------------------\r
- Skill->SetXP( MS_INT, atof( row[c_int_xp] ) );\r
- Skill->SetXP( MS_CON, atof( row[c_con_xp] ) );\r
- Skill->SetXP( MS_DEX, atof( row[c_dex_xp] ) );\r
- Skill->SetXP( MS_STR, atof( row[c_str_xp] ) );\r
- Skill->SetXP( MS_PSI, atof( row[c_psi_xp] ) );\r
- // ---------------------------------------------\r
- // SubSkills\r
- // ---------------------------------------------\r
- Skill->SetSubSkill( SK_MC, atoi( row[c_mc] ) );\r
- Skill->SetSubSkill( SK_HC, atoi( row[c_hc] ) );\r
- Skill->SetSubSkill( SK_TRA, atoi( row[c_tra] ) );\r
- Skill->SetSubSkill( SK_FOR, atoi( row[c_for] ) );\r
- Skill->SetSubSkill( SK_PC, atoi( row[c_pc] ) );\r
- Skill->SetSubSkill( SK_RC, atoi( row[c_rc] ) );\r
- Skill->SetSubSkill( SK_TC, atoi( row[c_tc] ) );\r
- Skill->SetSubSkill( SK_VHC, atoi( row[c_vhc] ) );\r
- Skill->SetSubSkill( SK_AGL, atoi( row[c_agl] ) );\r
- Skill->SetSubSkill( SK_REP, atoi( row[c_rep] ) );\r
- Skill->SetSubSkill( SK_REC, atoi( row[c_rec] ) );\r
- Skill->SetSubSkill( SK_RCL, atoi( row[c_rcl] ) );\r
- Skill->SetSubSkill( SK_ATL, atoi( row[c_atl] ) );\r
- Skill->SetSubSkill( SK_END, atoi( row[c_end] ) );\r
- Skill->SetSubSkill( SK_FIR, atoi( row[c_fir] ) );\r
- Skill->SetSubSkill( SK_ENR, atoi( row[c_enr] ) );\r
- Skill->SetSubSkill( SK_XRR, atoi( row[c_xrr] ) );\r
- Skill->SetSubSkill( SK_POR, atoi( row[c_por] ) );\r
- Skill->SetSubSkill( SK_HLT, atoi( row[c_hlt] ) );\r
- Skill->SetSubSkill( SK_HCK, atoi( row[c_hck] ) );\r
- Skill->SetSubSkill( SK_BRT, atoi( row[c_brt] ) );\r
- Skill->SetSubSkill( SK_PSU, atoi( row[c_psu] ) );\r
- Skill->SetSubSkill( SK_WEP, atoi( row[c_wep] ) );\r
- Skill->SetSubSkill( SK_CST, atoi( row[c_cst] ) );\r
- Skill->SetSubSkill( SK_RES, atoi( row[c_res] ) );\r
- Skill->SetSubSkill( SK_IMP, atoi( row[c_imp] ) );\r
- Skill->SetSubSkill( SK_PPU, atoi( row[c_ppu] ) );\r
- Skill->SetSubSkill( SK_APU, atoi( row[c_apu] ) );\r
- Skill->SetSubSkill( SK_MST, atoi( row[c_mst] ) );\r
- Skill->SetSubSkill( SK_PPW, atoi( row[c_ppw] ) );\r
- Skill->SetSubSkill( SK_PSR, atoi( row[c_psr] ) );\r
- Skill->SetSubSkill( SK_WPW, atoi( row[c_wpw] ) );\r
- // --------------------------------------------\r
- // Inventory\r
- // ---------------------------------------------\r
- mInventory.SetCharId( mID );\r
- mInventory.SQLLoad();\r
-\r
- // temp value forcing, not get/saved from DB atm\r
- mCombatRank = ( uint8_t )( random() % 127 ); // bad result there on randomness\r
- mSynaptic = 0;\r
- mIsDead = false;\r
-\r
- mDirectCharID = 0; // until saved/loaded with char\r
- mBuddyList = new PBuddyList( mID );\r
- if ( !mBuddyList->SQLLoad() )\r
- {\r
- Console->Print( RED, BLACK, "Char ID %d : Can't load buddy list", mID );\r
- }\r
- //to add: Chats settings\r
-\r
- mGenrepList = new PGenrepList( mID );\r
- if ( !mGenrepList->SQLLoad() )\r
- {\r
- Console->Print( RED, BLACK, "Char ID %d : Can't load genrep list", mID );\r
- }\r
-\r
- }\r
- MySQL->FreeGameSQLResult( result );\r
-\r
- // Addition; Set char's online status to ONLINE\r
- char sqlqry[50];\r
- snprintf(sqlqry, 50, "UPDATE characters SET c_online = 1 WHERE c_id = %d", mID);\r
- MySQL->GameQuery(sqlqry);\r
-\r
- return true;\r
-}\r
-\r
-bool PChar::SQLCreate() // Specific method for creation in order to avoid existence check with each save\r
-{\r
- std::string query, queryv;\r
-\r
- query = "INSERT INTO characters (c_id";\r
- queryv = ") VALUES (NULL";\r
-\r
- query += ",c_name";\r
- queryv = queryv + ",'" + mName + "'";\r
-\r
- query += ",a_id";\r
- queryv += Ssprintf( ",'%u'", mAccount );\r
- query += ",c_class";\r
- queryv += Ssprintf( ",'%u'", mClass );\r
- query += ",c_sex";\r
- queryv += Ssprintf( ",'%u'", mGender );\r
- query += ",c_profession";\r
- queryv += Ssprintf( ",'%u'", mProfession );\r
- query += ",c_faction";\r
- queryv += Ssprintf( ",'%u'", mFaction );\r
- query += ",c_head";\r
- queryv += Ssprintf( ",'%u'", mRealHead );\r
- query += ",c_torso";\r
- queryv += Ssprintf( ",'%u'", mRealTorso );\r
- query += ",c_legs";\r
- queryv += Ssprintf( ",'%u'", mRealLegs );\r
- //query += ",c_model";\r
- //queryv += Ssprintf(",'%u'", mModel);\r
- //query += ",c_type";\r
- //queryv += Ssprintf(",'%u'", mType);\r
- query += ",c_location";\r
- queryv += Ssprintf( ",'%u'", mLocation );\r
- query += ",c_cash";\r
- queryv += Ssprintf( ",'%u'", mCash );\r
- query += ",c_slot";\r
- queryv += Ssprintf( ",'%u'", mSlot );\r
-\r
- query = query + queryv + ");";\r
-\r
- if ( MySQL->GameQuery( query.c_str() ) )\r
- {\r
- Console->Print( RED, BLACK, "PChar::SQLCreate could not add char %s to database", mName.c_str() );\r
- Console->Print( "Query was:" );\r
- Console->Print( "%s", query.c_str() );\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
- else\r
- {\r
- mID = MySQL->GetLastGameInsertId();\r
-//Console->Print(GREEN, BLACK, "New char %s got ID %d", mName.c_str(), mID);\r
- mDirtyFlag = true;\r
- return true;\r
- }\r
-}\r
-\r
-bool PChar::CreateNewChar( uint32_t Account, const std::string &Name, uint32_t Gender, uint32_t Profession, uint32_t Faction,\r
- uint32_t Head, uint32_t Torso, uint32_t Legs, uint8_t NZSNb, const char *NonZeroSubskills, uint32_t Slot )\r
-{\r
- SetName( Name );\r
- SetGender( Gender );\r
- SetProfession( Profession );\r
- SetFaction( Faction );\r
- SetRealLook( Head, Torso, Legs );\r
- SetBaseSkills();\r
- SetBaseSubskills( NZSNb, NonZeroSubskills );\r
- SetBaseInventory();\r
- SetAccount( Account );\r
- SetCharSlot( Slot );\r
- mLocation = Config->GetOptionInt( "new_char_location" );\r
-\r
- // This part will have to be rewritten with proper methods\r
- mSoullight = 10;\r
- mCombatRank = ( uint8_t )( random() % 80 ); // bad result there on randomness\r
- mSynaptic = 0;\r
- mIsDead = false;\r
-\r
- mDirectCharID = 0; // until saved/loaded with char\r
-\r
- SetDirtyFlag();\r
-\r
- if ( SQLCreate() ) // mID isn't defined before that\r
- {\r
- mBuddyList = new PBuddyList( mID );\r
- mGenrepList = new PGenrepList( mID );\r
- mStartApt = mPrimaryApt = Appartements->CreateBaseAppartement( mID, mName, mFaction );\r
- mInventory.SetCharId( mID );\r
-\r
- if ( mStartApt && SQLSave() && mInventory.SQLSave() )\r
- {\r
- return true;\r
- }\r
- else\r
- {\r
- Console->Print( YELLOW, BLACK, "New char %s (id %d) : creation aborted", mName.c_str(), mID );\r
- if ( mID )\r
- {\r
- SQLDelete();\r
- if ( mStartApt )\r
- {\r
- Appartements->DeleteCharAppartements( mID );\r
- }\r
- }\r
- }\r
- }\r
- return false;\r
-}\r
-\r
-bool PChar::SQLSave()\r
-{\r
- std::string query;\r
- //std::string ts;\r
-\r
- /* TODO:\r
- - Mostly at creation/load :\r
- c_apt, (or when first GR to primary apt to avoid creation of unused apt?)\r
- (c_slot)\r
- - At save/load :\r
- SoulLight ???\r
- FactionSymp[] ???\r
- Chest change: style, brightness, color\r
- Legs change: style, brightness, color\r
- mHealt, mStamina, mMana (not in DB !!!)\r
- How to compute MaxHealth etc. ?\r
- */\r
- query = "UPDATE characters SET";\r
-\r
- query += Ssprintf( " c_location='%u'", mLocation );\r
- query += Ssprintf( ",c_pos_x='%u'", Coords.mX );\r
- query += Ssprintf( ",c_pos_y='%u'", Coords.mY );\r
- query += Ssprintf( ",c_pos_z='%u'", Coords.mZ );\r
- query += Ssprintf( ",c_angle_ud='%u'", Coords.mUD );\r
- query += Ssprintf( ",c_angle_lr='%u'", Coords.mLR );\r
- query += Ssprintf( ",c_cash='%u'", mCash );\r
- query += Ssprintf( ",c_apt='%u'", mPrimaryApt );\r
-\r
- query += Ssprintf( ",c_head='%u'", mRealHead );\r
- query += Ssprintf( ",c_torso='%u'", mRealTorso );\r
- query += Ssprintf( ",c_legs='%u'", mRealLegs );\r
-\r
- query += Ssprintf( ",c_faction='%u'", mFaction );\r
-\r
- /* This group of fiels shouldn't change in-game\r
- query = query + ",c_name='" + mName + "'";\r
- query += Ssprintf(",a_id='%u'", mAccount);\r
- query += Ssprintf(",c_class='%u'", mClass);\r
- query += Ssprintf(",c_sex='%u'", mGender);\r
- query += Ssprintf(",c_profession='%u'", mProfession);\r
- query += Ssprintf(",c_slot='%u'", mSlot);\r
- // query += Ssprintf(",c_model='%u'", mModel);\r
- // query += Ssprintf(",c_type='%u'", mType);\r
- */\r
-\r
- // ---------------------------------------------\r
- // Saving skills --- MAIN Skills with SP and XP\r
- // ---------------------------------------------\r
- query += Ssprintf( ",c_int_lvl='%u'", Skill->GetMainSkill( MS_INT ) );\r
- query += Ssprintf( ",c_con_lvl='%u'", Skill->GetMainSkill( MS_CON ) );\r
- query += Ssprintf( ",c_dex_lvl='%u'", Skill->GetMainSkill( MS_DEX ) );\r
- query += Ssprintf( ",c_str_lvl='%u'", Skill->GetMainSkill( MS_STR ) );\r
- query += Ssprintf( ",c_psi_lvl='%u'", Skill->GetMainSkill( MS_PSI ) );\r
- // ---------------------------------------------\r
- query += Ssprintf( ",c_int_pts='%u'", Skill->GetSP( MS_INT ) );\r
- query += Ssprintf( ",c_con_pts='%u'", Skill->GetSP( MS_CON ) );\r
- query += Ssprintf( ",c_dex_pts='%u'", Skill->GetSP( MS_DEX ) );\r
- query += Ssprintf( ",c_str_pts='%u'", Skill->GetSP( MS_STR ) );\r
- query += Ssprintf( ",c_psi_pts='%u'", Skill->GetSP( MS_PSI ) );\r
- // ---------------------------------------------\r
- query += Ssprintf( ",c_int_xp='%u'", Skill->GetXP( MS_INT ) );\r
- query += Ssprintf( ",c_con_xp='%u'", Skill->GetXP( MS_CON ) );\r
- query += Ssprintf( ",c_dex_xp='%u'", Skill->GetXP( MS_DEX ) );\r
- query += Ssprintf( ",c_str_xp='%u'", Skill->GetXP( MS_STR ) );\r
- query += Ssprintf( ",c_psi_xp='%u'", Skill->GetXP( MS_PSI ) );\r
- // ---------------------------------------------\r
- // SubSkills\r
- // ---------------------------------------------\r
- query += Ssprintf( ",c_mc='%u'", Skill->GetSubSkill( SK_MC ) );\r
- query += Ssprintf( ",c_hc='%u'", Skill->GetSubSkill( SK_HC ) );\r
- query += Ssprintf( ",c_tra='%u'", Skill->GetSubSkill( SK_TRA ) );\r
- query += Ssprintf( ",c_for='%u'", Skill->GetSubSkill( SK_FOR ) );\r
- query += Ssprintf( ",c_pc='%u'", Skill->GetSubSkill( SK_PC ) );\r
- query += Ssprintf( ",c_rc='%u'", Skill->GetSubSkill( SK_RC ) );\r
- query += Ssprintf( ",c_tc='%u'", Skill->GetSubSkill( SK_TC ) );\r
- query += Ssprintf( ",c_vhc='%u'", Skill->GetSubSkill( SK_VHC ) );\r
- query += Ssprintf( ",c_agl='%u'", Skill->GetSubSkill( SK_AGL ) );\r
- query += Ssprintf( ",c_rep='%u'", Skill->GetSubSkill( SK_REP ) );\r
- query += Ssprintf( ",c_rec='%u'", Skill->GetSubSkill( SK_REC ) );\r
- query += Ssprintf( ",c_rcl='%u'", Skill->GetSubSkill( SK_RCL ) );\r
- query += Ssprintf( ",c_atl='%u'", Skill->GetSubSkill( SK_ATL ) );\r
- query += Ssprintf( ",c_end='%u'", Skill->GetSubSkill( SK_END ) );\r
- query += Ssprintf( ",c_fir='%u'", Skill->GetSubSkill( SK_FIR ) );\r
- query += Ssprintf( ",c_enr='%u'", Skill->GetSubSkill( SK_ENR ) );\r
- query += Ssprintf( ",c_xrr='%u'", Skill->GetSubSkill( SK_XRR ) );\r
- query += Ssprintf( ",c_por='%u'", Skill->GetSubSkill( SK_POR ) );\r
- query += Ssprintf( ",c_htl='%u'", Skill->GetSubSkill( SK_HLT ) );\r
- query += Ssprintf( ",c_hck='%u'", Skill->GetSubSkill( SK_HCK ) );\r
- query += Ssprintf( ",c_brt='%u'", Skill->GetSubSkill( SK_BRT ) );\r
- query += Ssprintf( ",c_psu='%u'", Skill->GetSubSkill( SK_PSU ) );\r
- query += Ssprintf( ",c_wep='%u'", Skill->GetSubSkill( SK_WEP ) );\r
- query += Ssprintf( ",c_cst='%u'", Skill->GetSubSkill( SK_CST ) );\r
- query += Ssprintf( ",c_res='%u'", Skill->GetSubSkill( SK_RES ) );\r
- query += Ssprintf( ",c_imp='%u'", Skill->GetSubSkill( SK_IMP ) );\r
- query += Ssprintf( ",c_ppu='%u'", Skill->GetSubSkill( SK_PPU ) );\r
- query += Ssprintf( ",c_apu='%u'", Skill->GetSubSkill( SK_APU ) );\r
- query += Ssprintf( ",c_mst='%u'", Skill->GetSubSkill( SK_MST ) );\r
- query += Ssprintf( ",c_ppw='%u'", Skill->GetSubSkill( SK_PPW ) );\r
- query += Ssprintf( ",c_psr='%u'", Skill->GetSubSkill( SK_PSR ) );\r
- query += Ssprintf( ",c_wpw='%u'", Skill->GetSubSkill( SK_WPW ) );\r
- // ---------------------------------------------\r
-\r
- query += Ssprintf( " WHERE c_id='%u' LIMIT 1;", mID );\r
-\r
- if ( MySQL->GameQuery( query.c_str() ) )\r
- {\r
- Console->Print( RED, BLACK, "PChar::SQLSave could not save char %s (%u) to database", mName.c_str(), mID );\r
- Console->Print( "Query was:" );\r
- Console->Print( "%s", query.c_str() );\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
-\r
- // Chats settings (?), directs\r
-\r
- mDirtyFlag = false;\r
- return true;\r
-}\r
-\r
-bool PChar::SQLDelete()\r
-{\r
- return true;\r
-}\r
-\r
-void PChar::SetOnlineStatus( bool IsOnline )\r
-{\r
- // Deactivated, until Maxx added c_isonline row to `characters`\r
- //char query[255];\r
- int onlinestatus = 0;\r
-\r
- if ( IsOnline )\r
- {\r
- onlinestatus = 0; // Strange ????\r
- mIsOnline = true;\r
- }\r
- else\r
- {\r
- onlinestatus = 1; // Strange ????\r
- mIsOnline = false;\r
- }\r
-\r
-// snprintf(query, 255, "UPDATE charlist SET c_isonline = %d WHERE a_id = %d AND c_id = %d", onlinestatus, mAccount, mID);\r
-// if(MySQL->Query(query))\r
-// {\r
-// Console->Print("Error: Cant set onlinestatus to '%d' for Account: %d, Char: %d", onlinestatus, mAccount, mID);\r
-// MySQL->ShowSQLError();\r
-// return;\r
-// }\r
- return;\r
-}\r
-\r
-uint8_t PChar::GetCombatRank()\r
-{\r
- // Override for Special Account Levels\r
- PAccount Acc(mAccount);\r
- if(Acc.GetLevel() == PAL_ADMIN)\r
- return 127;\r
- else if(Acc.GetLevel() >= PAL_GM)\r
- return 120;\r
- else if(Acc.GetLevel() >= PAL_VOLUNTEER)\r
- return 50;\r
- else\r
- return mCombatRank;\r
-}\r
-\r
-\r
-uint8_t PChar::GetMainRank()\r
-{\r
- // Override for Special Account Levels\r
- PAccount Acc(mAccount);\r
- if(Acc.GetLevel() == PAL_ADMIN)\r
- return 127;\r
- else if(Acc.GetLevel() >= PAL_GM)\r
- return 120;\r
- else if(Acc.GetLevel() >= PAL_VOLUNTEER)\r
- return 50;\r
- else\r
- {\r
- uint16_t total;\r
- total = Skill->GetMainSkill( MS_STR ) + Skill->GetMainSkill( MS_DEX );\r
- total += Skill->GetMainSkill( MS_CON ) + Skill->GetMainSkill( MS_INT );\r
- total += Skill->GetMainSkill( MS_PSI );\r
- return (( uint8_t )( total / 5 ) );\r
- }\r
-}\r
-\r
-bool PChar::AddGenrep(uint16_t nWorldID, uint16_t nStationID)\r
-{\r
- return mGenrepList->AddGenrep(nWorldID, nStationID );\r
-}\r
-\r
-uint16_t PChar::GetGenrepListDataSize()\r
-{\r
- return mGenrepList->GetListDataSize();\r
-}\r
-\r
-const void *PChar::GetGenrepListData()\r
-{\r
- return mGenrepList->GetListData();\r
-}\r
-\r
-uint8_t PChar::GetGenrepCount()\r
-{\r
- return mGenrepList->Count();\r
-}\r
-\r
-uint32_t PChar::AddCash( uint32_t nAmount )\r
-{\r
- return SetCash(nAmount + mCash);\r
-}\r
-\r
-uint32_t PChar::TakeCash( uint32_t nAmount )\r
-{\r
- if(nAmount > mCash)\r
- {\r
- //Tries to take away more cash that user has, set to zero\r
- return SetCash(0);\r
- }\r
- else\r
- {\r
- return SetCash(mCash-nAmount);\r
- }\r
-}\r
-\r
-uint32_t PChar::SetCash( uint32_t nCash )\r
-{\r
- //Console->Print("Trying to set cash to nCash: %d", nCash);\r
- if (( int )nCash > Config->GetOptionInt( "max_cash" ) )\r
- {\r
- //Console->Print("Newcash would be more than dynamic maxcash, setting to maxcash");\r
- mCash = ( uint32_t )Config->GetOptionInt( "max_cash" );\r
- }\r
- else if ( nCash > MAXCASH )\r
- {\r
- //Console->Print("Newcash would be more than hardcoded maxcash, setting to maxcash");\r
- mCash = MAXCASH;\r
- }\r
- else\r
- {\r
- //Console->Print("Allright, setting to new value");\r
- mCash = nCash;\r
- }\r
- //Console->Print("Returning mCash: %d", mCash);\r
- return mCash;\r
-}\r
-\r
-\r
-bool PChar::SetQuickBeltActiveSlot( uint8_t nSlotID )\r
-{\r
- if (( nSlotID == INV_WORN_QB_HAND ) || ( nSlotID == INV_WORN_QB_NONE ) )\r
- {\r
- mQuickBeltActiveSlot = nSlotID;\r
- return true;\r
- }\r
- else if ( nSlotID <= ( INV_WORN_QB_END - INV_WORN_QB_START ) )\r
- {\r
- PContainer* tWorn = mInventory.GetContainer( INV_LOC_WORN );\r
-\r
- if ( ! tWorn->IsSlotFree( nSlotID ) ) // => TODO: MUST ALSO CHECK that item is currently usable and can be held in hand\r
- {\r
- mQuickBeltActiveSlot = nSlotID;\r
- return true;\r
- }\r
- else\r
- {\r
- Console->Print( "SetQuickBeltActiveSlot: SlotID %d greater than %d or free (%d)", nSlotID, INV_WORN_QB_END - INV_WORN_QB_START, tWorn->IsSlotFree( nSlotID ) );\r
- }\r
- }\r
- return false;\r
-}\r
-\r
-PSeatType PChar::GetSeatInUse( uint32_t* nObjectId, uint8_t* nSeatId )\r
-{\r
- if ( nObjectId )\r
- {\r
- *nObjectId = mSeatInUseObjectId;\r
- }\r
- if ( nSeatId )\r
- {\r
- *nSeatId = mSeatInUseSeatId;\r
- }\r
-\r
- return mSeatInUseType;\r
-}\r
-\r
-void PChar::SetSeatInUse( PSeatType nSeatType, uint32_t nObjectId, uint8_t nSeatId )\r
-{\r
- mSeatInUseType = nSeatType;\r
- mSeatInUseObjectId = nObjectId;\r
- mSeatInUseSeatId = nSeatId;\r
-}\r
-\r
-PVhcAccessRequestList* PChar::GetVhcAccessRequestList()\r
-{\r
- if( ! mVhcAccessRequestList )\r
- mVhcAccessRequestList = new PVhcAccessRequestList();\r
-\r
- return mVhcAccessRequestList;\r
-}\r
-\r
-void PChar::SetLookingAt( uint16_t nLocalCharID )\r
-{\r
- mLookingAt = nLocalCharID;\r
- mLookAtTimestamp = std::time( NULL );\r
-}\r
-\r
-uint16_t PChar::GetLookingAt( uint16_t nMaxDelaySec )\r
-{\r
- return ((( mLookAtTimestamp + nMaxDelaySec ) >= std::time( NULL ) ) ? mLookingAt : 0 );\r
-}\r
-\r
-// ===================================\r
-\r
-PChars::PChars()\r
-{\r
- mLastID = 0;\r
- mLastSave = std::time( NULL );\r
-\r
- mAutoSavePeriod = Config->GetOptionInt( "auto_save_period" );\r
- if ( mAutoSavePeriod < 0 )\r
- {\r
- Console->Print( "%s auto_save_period (%d) must be strict positive.", Console->ColorText( RED, BLACK, "[Error]" ), mAutoSavePeriod );\r
- mAutoSavePeriod = 0;\r
- }\r
- else if ( mAutoSavePeriod > 3600 )\r
- {\r
- Console->Print( "%s auto_save_period (%d) too high. Forced to 3600 sec.", Console->ColorText( YELLOW, BLACK, "[Warning]" ), mAutoSavePeriod );\r
- mAutoSavePeriod = 0;\r
- }\r
-\r
- if ( mAutoSavePeriod == 0 )\r
- {\r
- Console->Print( "%s Auto-save disabled.", Console->ColorText( YELLOW, BLACK, "[Info]" ) );\r
- }\r
- else if ( mAutoSavePeriod < 60 )\r
- {\r
- Console->Print( "%s auto_save_period (%d) is low and might lead to high server load.", Console->ColorText( YELLOW, BLACK, "[Warning]" ), mAutoSavePeriod );\r
- }\r
-\r
-}\r
-\r
-PChars::~PChars()\r
-{\r
- for ( CharMap::iterator i = mChars.begin(); i != mChars.end(); i++ )\r
- delete i->second;\r
-}\r
-\r
-bool PChars::LoadChar( uint32_t CharID )\r
-{\r
- if ( !CharID )\r
- return false;\r
-\r
- PChar *nChar = new PChar();\r
- if ( nChar->SQLLoad( CharID ) )\r
- {\r
- nChar->SetDirtyFlag( false );\r
- return AddChar( nChar );\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Could not load char id %d from database", CharID );\r
- return false;\r
- }\r
-}\r
-\r
-bool PChars::AddChar( PChar* nChar )\r
-{\r
- if ( !nChar )\r
- return false;\r
-\r
- mLastID = std::max( mLastID, nChar->GetID() );\r
- if ( mChars.insert( std::make_pair( nChar->GetID(), nChar ) ).second )\r
- {\r
- if ( gDevDebug )\r
- Console->Print( "%s Char: %s (id %d) added", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nChar->GetName().c_str() , nChar->GetID() );\r
- return true;\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Trying to load char twice : %s (id %d)", nChar->GetName().c_str(), nChar->GetID() );\r
- return false;\r
- }\r
-}\r
-\r
-PChar* PChars::RemoveChar( uint32_t CharID )\r
-{\r
- PChar* Result = NULL;\r
-\r
- CharMap::iterator i = mChars.find( CharID );\r
- if ( i != mChars.end() )\r
- {\r
- Result = i->second;\r
- mChars.erase( i );\r
- if ( gDevDebug )\r
- Console->Print( "%s Char: %s (id %d) removed", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), Result->GetName().c_str() , Result->GetID() );\r
- }\r
-\r
- return Result;\r
-}\r
-\r
-void PChars::SQLSave()\r
-{\r
- // saves all dirty-flagged chars\r
- int nDirtyChars = 0, nSavedChars = 0;\r
- int nDirtyInv = 0, nSavedInv = 0;\r
-\r
- for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ )\r
- {\r
- PChar* Char = i->second;\r
- if ( Char->IsDirty() )\r
- {\r
- ++nDirtyChars;\r
- if ( Char->SQLSave() )\r
- ++nSavedChars;\r
- }\r
- if ( Char->GetInventory()->IsDirty() )\r
- {\r
- ++nDirtyInv;\r
- if ( Char->GetInventory()->SQLSave() )\r
- ++nSavedInv;\r
- }\r
- }\r
- Console->Print( "%s %i chars saved on %i dirty, %i inventories saved on %i dirty", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), nSavedChars, nDirtyChars, nSavedInv, nDirtyInv );\r
- return;\r
-}\r
-\r
-PChar* PChars::GetChar( uint32_t CharID ) const\r
-{\r
- PChar *Result = 0;\r
- CharMap::const_iterator i = mChars.find( CharID );\r
- if ( i != mChars.end() )\r
- Result = i->second;\r
-\r
- return Result;\r
-}\r
-\r
-PChar* PChars::GetChar( const std::string &Name ) const\r
-{\r
- PChar *Result = 0;\r
- for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ )\r
- {\r
- if ( !/*std::*/strcasecmp( i->second->GetName().c_str(), Name.c_str() ) )\r
- {\r
- Result = i->second;\r
- break;\r
- }\r
- }\r
- return Result;\r
-}\r
-\r
-bool PChars::CharExist( const std::string &Name ) const\r
-{\r
- char query[256];\r
- int EntriesNb;\r
- MYSQL_RES *result = 0;\r
-\r
- char escUsername[256];\r
- MySQL->EscapeString( Name.c_str(), escUsername, 256 );\r
- snprintf( query, 256, "SELECT 1 FROM characters WHERE c_name = '%s' LIMIT 1;", escUsername );\r
-\r
- result = MySQL->GameResQuery( query );\r
- if ( result == NULL )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Failed to get CharacterData from SQL" );\r
- MySQL->ShowGameSQLError();\r
- return true;\r
- }\r
-\r
- EntriesNb = mysql_num_rows( result );\r
- MySQL->FreeGameSQLResult( result );\r
- return( EntriesNb > 0 );\r
-}\r
-\r
-void PChars::Update()\r
-{\r
- std::time_t t = std::time( NULL ); // changed to time() to have real time instead of cpu used time\r
-\r
- if ( mAutoSavePeriod && (( t - mLastSave ) >= mAutoSavePeriod ) )\r
- {\r
- bool NeedSave = false;\r
- for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ )\r
- {\r
- if ( i->second->IsAnyDirty() )\r
- {\r
- NeedSave = true;\r
- break;\r
- }\r
- }\r
-\r
- if ( NeedSave )\r
- {\r
- if ( gDevDebug ) Console->Print( "%s Some characters need autosaving...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- SQLSave();\r
- if ( gDevDebug ) Console->Print( "%s Autosave done.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- }\r
- mLastSave = t;\r
- }\r
-}\r
-\r
-//MAX_CHARS_PER_ACCOUNT\r
-int PChars::GetCharProfiles( const uint32_t AccountID, PCharProfile* CharSlotsArray, const uint8_t ArraySize )\r
-{\r
- char query[256];\r
- int EntriesNb = 0;\r
-\r
- MYSQL_ROW row = 0;\r
- MYSQL_RES *result = 0;\r
-\r
- snprintf( query, 256, "SELECT * FROM characters WHERE a_id = %d ORDER BY c_slot ASC", AccountID );\r
-\r
- result = MySQL->GameResQuery( query );\r
- if ( result == NULL )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Failed to load CharacterData from SQL" );\r
- MySQL->ShowGameSQLError();\r
- return 0;\r
- }\r
-\r
- //EntriesNb = mysql_num_rows(result);\r
- int SlotID;\r
- uint32_t CharID;\r
- PChar* tmpChar = new PChar();\r
-\r
- while (( row = mysql_fetch_row( result ) ) )\r
- {\r
- SlotID = atoi( row[c_slot] );\r
- CharID = atoi( row[c_id] );\r
- if (( SlotID >= 0 ) && ( SlotID < ArraySize ) )\r
- {\r
- if ( !CharSlotsArray[SlotID].in_use )\r
- {\r
- tmpChar->SetID( CharID );\r
- tmpChar->SetGender( atoi( row[c_sex] ) );\r
- tmpChar->SetProfession( atoi( row[c_profession] ) );\r
-\r
- CharSlotsArray[SlotID].CharID = CharID;\r
- CharSlotsArray[SlotID].Type = tmpChar->GetType();\r
- CharSlotsArray[SlotID].Location = static_cast<uint32_t>( atoi( row[c_location] ) );\r
- CharSlotsArray[SlotID].Head = atoi( row[c_head] );\r
- CharSlotsArray[SlotID].Torso = atoi( row[c_torso] );\r
- CharSlotsArray[SlotID].Legs = atoi( row[c_legs] );\r
- CharSlotsArray[SlotID].Name = row[c_name];\r
- CharSlotsArray[SlotID].NameLen = CharSlotsArray[SlotID].Name.length() + 1;\r
-\r
- CharSlotsArray[SlotID].in_use = true;\r
- ++EntriesNb;\r
- }\r
- else\r
- {\r
- Console->Print( YELLOW, BLACK, "[Warning]Character %d using slot %d already used by char %d - Ignored", \\r
- CharID, SlotID, CharSlotsArray[SlotID].CharID );\r
- }\r
- }\r
- else\r
- {\r
- Console->Print( YELLOW, BLACK, "[Warning]Character %d using invialid slot %d - Ignored", CharID, SlotID );\r
- }\r
- }\r
-\r
- delete tmpChar;\r
- MySQL->FreeGameSQLResult( result );\r
- return EntriesNb;\r
-}\r
+#include <cstring>
+#include "GameServer/Includes.hxx"
+#include "GameServer/Definitions/Includes.hxx"
+#include "Common/Includes.hxx"
+
+// PCharCoordinates
+void PCharCoordinates::SetInterpolate( PCharCoordinates& Pos1, PCharCoordinates& Pos2, float nCoef )
+{
+ if (( nCoef < 0 ) || ( nCoef > 1 ) )
+ {
+ Console->Print( RED, BLACK, "[Error] PCharCoordinates::Interpolate : Invalid nCoef value: %f", nCoef );
+ nCoef = 0;
+ }
+ float rCoef = 1 - nCoef;
+
+ mY = ( uint16_t )( rCoef * Pos1.mY + nCoef * Pos2.mY );
+ mZ = ( uint16_t )( rCoef * Pos1.mZ + nCoef * Pos2.mZ );
+ mX = ( uint16_t )( rCoef * Pos1.mX + nCoef * Pos2.mX );
+ mUD = ( uint8_t )( rCoef * Pos1.mUD + nCoef * Pos2.mUD );
+ if ( abs( Pos1.mLR - Pos2.mLR ) < 90 )
+ {
+ mLR = ( uint8_t )( rCoef * Pos1.mLR + nCoef * Pos2.mLR );
+ }
+ else
+ {
+ mLR = ( uint8_t )(( uint16_t )( rCoef * ( 180.0 + ( float )Pos1.mLR ) + nCoef * Pos2.mLR ) % 180 );
+ }
+}
+
+uint16_t mY; // Y-Position in world
+uint16_t mZ; // Z-Position in world
+uint16_t mX; // X-Position in world
+uint8_t mUD; // Up - Mid - Down (d6 - 80 - 2a)
+uint8_t mLR; // Compass direction (S..E..N..W..S [0-45-90-135-179])
+uint8_t mAct; // Last user action state
+
+void PCharCoordinates::SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD, uint8_t nLR )
+{
+ mY = nY;
+ mZ = nZ;
+ mX = nX;
+ mUD = nUD;
+ if ( mUD < 0x2a )
+ {
+ mUD = 0x2a;
+ }
+ else if ( mUD > 0xd6 )
+ {
+ mUD = 0xd6;
+ }
+ mLR = nLR % 180;
+}
+
+
+// SQL Layout
+enum
+{
+ c_id,
+ c_name,
+ c_str_lvl,
+ c_str_pts,
+ c_int_lvl,
+ c_int_pts,
+ c_dex_lvl,
+ c_dex_pts,
+ c_con_lvl,
+ c_con_pts,
+ c_psi_lvl,
+ c_psi_pts,
+ a_id,
+ c_class,
+ c_profession,
+ c_sex,
+ c_location,
+ c_mc,
+ c_hc,
+ c_tra,
+ c_pc,
+ c_rc,
+ c_tc,
+ c_vhc,
+ c_agl,
+ c_rep,
+ c_rec,
+ c_rcl,
+ c_atl,
+ c_end,
+ c_for,
+ c_fir,
+ c_enr,
+ c_xrr,
+ c_por,
+ c_hlt,
+ c_hck,
+ c_brt,
+ c_psu,
+ c_wep,
+ c_cst,
+ c_res,
+ c_imp,
+ c_ppu,
+ c_apu,
+ c_mst,
+ c_ppw,
+ c_psr,
+ c_wpw,
+ c_apt,
+ c_cash,
+ c_head,
+ c_torso,
+ c_legs,
+ c_str_xp,
+ c_int_xp,
+ c_dex_xp,
+ c_psi_xp,
+ c_con_xp,
+ c_pos_x,
+ c_pos_y,
+ c_pos_z,
+ c_angle_ud,
+ c_angle_lr,
+ c_faction,
+ c_slot,
+ c_online,
+ c_clan,
+ c_soullight
+};
+
+RegEx* PChar::mCharnameRegexFilter = NULL;
+
+PChar::PChar()
+{
+ mID = 0;
+ mAccount = 0;
+ mGender = 0;
+ mClass = 0;
+ mProfession = 1;
+ mFaction = 1;
+ //mModel = 0;
+ //mType = 0;
+ mRealHead = 0; // Base Skin elements, in complement of (computed) mType
+ mRealTorso = 0; // " Head shouldn't be changeable, except in case of surgery !!!
+ mRealLegs = 0; // "
+ mSkin = 0; // Current Skin elements
+ mHead = 0; // "
+ mTorso = 0; // "
+ mLegs = 0; // "
+ mHeadColor = mTorsoColor = mLegsColor = 0; // "
+ mHeadDarkness = mTorsoDarkness = mLegsDarkness = 0; // "
+
+ mBodyEffect = 0;
+ mBodyEffectDensity = 0;
+ mQuickBeltActiveSlot = INV_WORN_QB_NONE;
+
+ mLookingAt = 0;
+ mLookAtTimestamp = 0;
+ mLastUsedWorldObjectId = 0;
+
+ mSpeedOverride = 255; // means no override. Value 0 can be used to forbid any move.
+
+ mLocationLeased = false; // temp until char on-demand load/unload
+ mLocation = 0;
+ mStartApt = 0;
+ mPrimaryApt = 0;
+ mCash = 0;
+
+ mSeatInUseType = seat_none;
+ mSeatInUseObjectId = 0;
+ mSeatInUseSeatId = 0;
+ mVhcAccessRequestList = NULL;
+
+ mContainerInExclusiveUse = NULL;
+
+ mIsOnline = false;
+ mDirtyFlag = false;
+
+ mShunned = false;
+ mJailed = false;
+
+ mDialogNPC = 0;
+ mCurrentDialogNode = 0;
+
+ Skill = new PSkillHandler();
+ mBuddyList = NULL;
+ mGenrepList = NULL;
+
+ // Required for initial OOC Broadcast welcome message.
+ //Gets overwritten as soon as the first PingPacket arrives
+ mActiveChatChannels = 262144;
+ mClanLevel = 0;
+ mClanID = 0;
+}
+
+PChar::~PChar()
+{
+ // Addition; Set char's online status to OFFLINE
+ char sqlqry[50];
+ snprintf(sqlqry, 50, "UPDATE characters SET c_online = 0 WHERE c_id = %d", mID);
+ MySQL->GameQuery(sqlqry);
+
+ delete Skill;
+ delete mBuddyList;
+ delete mGenrepList;
+ delete mVhcAccessRequestList;
+
+ if ( mContainerInExclusiveUse )
+ {
+ mContainerInExclusiveUse->EndUse( mID );
+ Console->Print( RED, BLACK, "Warning: PChar::~PChar : Char still had exclusive use of container. Now freed." );
+ }
+
+ if ( mSeatInUseType != seat_none )
+ {
+ Console->Print( RED, BLACK, "Warning: PChar::~PChar : Char still using seat %d of vhc or chair %d.", mSeatInUseSeatId, mSeatInUseObjectId );
+ }
+}
+
+bool PChar::SetCharnameRegexFilter( const char* RegexStr )
+{
+ if ( mCharnameRegexFilter )
+ {
+ delete mCharnameRegexFilter;
+ mCharnameRegexFilter = NULL;
+ }
+
+ if ( RegexStr )
+ {
+ try
+ {
+ mCharnameRegexFilter = new RegEx( RegexStr, PCRE_CASELESS );
+ }
+ catch ( ... )
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool PChar::IsCharnameWellFormed( const char *Charname )
+{
+ if ( mCharnameRegexFilter )
+ {
+ return mCharnameRegexFilter->Search( Charname );
+ }
+ else
+ return true;
+}
+
+void PChar::SetProfession( uint32_t Profession )
+{
+ const PDefCharKind *def = GameDefs->CharKinds()->GetDef( Profession );
+ if ( def == NULL )
+ {
+ Console->Print( RED, BLACK, "Char %d: Invalid profession %d", mID, Profession );
+ mProfession = 10;
+ mClass = 0;
+ }
+ else
+ {
+ mProfession = Profession;
+ mClass = def->GetType();
+ }
+ SetDirtyFlag();
+}
+
+uint32_t PChar::GetSkinFromCharType( uint32_t nType )
+{
+ const PDefCharacter* nDefCharacter = GameDefs->Chars()->GetDef( nType );
+ if ( nDefCharacter )
+ {
+ return (( uint32_t )( nDefCharacter->GetModel() ) );
+ }
+ else
+ return 0;
+}
+
+inline uint32_t PChar::GetBaseModel()
+{
+ return GetSkinFromCharType( GetType() );
+}
+
+void PChar::SetRealLook( uint32_t nHead, uint32_t nTorso, uint32_t nLegs )
+{
+ mRealHead = nHead;
+ mRealTorso = nTorso;
+ mRealLegs = nLegs;
+ SetDirtyFlag();
+ ResetCurrentLook();
+}
+
+void PChar::GetRealLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs )
+{
+ nSkin = GetBaseModel();
+ nHead = mRealHead;
+ nTorso = mRealTorso;
+ nLegs = mRealLegs;
+}
+
+void PChar::SetCurrentLookFromCharType( uint32_t nType )
+{
+ int iHead, iTorso, iLegs;
+ uint32_t nSkin, nHead, nTorso, nLegs;
+ uint8_t nColor, nBrightness;
+
+ const PDefCharacter* nDefCharacter = GameDefs->Chars()->GetDef( nType );
+ if ( nDefCharacter )
+ {
+ nSkin = ( uint32_t ) nDefCharacter->GetModel();
+ iHead = nDefCharacter->GetHead();
+ iTorso = nDefCharacter->GetTorso();
+ iLegs = nDefCharacter->GetLegs();
+ nColor = ( uint8_t )( 0xff & nDefCharacter->GetColor() );
+ nBrightness = ( uint8_t )( 0xff & nDefCharacter->GetBrightness() );
+
+
+ if (( iHead < 0 ) || ( iTorso < 0 ) || ( iLegs < 0 ) )
+ {
+ nHead = nTorso = nLegs = 0;
+ }
+ else
+ {
+ nHead = iHead % 10;
+ nTorso = iTorso % 10;
+ nLegs = iLegs % 10;
+ }
+
+ SetCurrentLook( nSkin, nHead, nTorso, nLegs );
+ SetCurrentBodyColor( nColor, nColor, nColor, nBrightness, nBrightness, nBrightness );
+ }
+}
+
+void PChar::SetCurrentLook( uint32_t nSkin, uint32_t nHead, uint32_t nTorso, uint32_t nLegs )
+{
+ mSkin = nSkin;
+ mHead = nHead;
+ mTorso = nTorso;
+ mLegs = nLegs;
+ // Ingame skin update will be done automagically in the normal update flow
+ // A flag could also be set somewhere (preferably in Char si that we don't have to care if ingame or not)
+ // to request quicker ingame update
+}
+
+void PChar::ResetCurrentLook()
+{
+ SetCurrentLook( GetSkinFromCharType( GetType() ), mRealHead, mRealTorso, mRealLegs );
+}
+
+// GetCurrentLook will later have to take Power Armors and GM overrides into account
+void PChar::GetCurrentLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs )
+{
+ nSkin = mSkin;
+ nHead = mHead;
+ nTorso = mTorso;
+ nLegs = mLegs;
+}
+
+void PChar::SetCurrentBodyColor( uint8_t nHeadColor, uint8_t nTorsoColor, uint8_t nLegsColor, uint8_t nHeadDarkness, uint8_t nTorsoDarkness, uint8_t nLegsDarkness )
+{
+ mHeadColor = nHeadColor;
+ mTorsoColor = nTorsoColor;
+ mLegsColor = nLegsColor;
+ mHeadDarkness = nHeadDarkness;
+ mTorsoDarkness = nTorsoDarkness;
+ mLegsDarkness = nLegsDarkness;
+}
+
+void PChar::GetCurrentBodyColor( uint8_t &nHeadColor, uint8_t &nTorsoColor, uint8_t &nLegsColor, uint8_t &nHeadDarkness, uint8_t &nTorsoDarkness, uint8_t &nLegsDarkness )
+{
+ nHeadColor = mHeadColor;
+ nTorsoColor = mTorsoColor;
+ nLegsColor = mLegsColor;
+ nHeadDarkness = mHeadDarkness;
+ nTorsoDarkness = mTorsoDarkness;
+ nLegsDarkness = mLegsDarkness;
+}
+
+void PChar::SetBaseSkills()
+{
+ const PDefCharKind *def = GameDefs->CharKinds()->GetDef( mProfession );
+ //Console->Print(YELLOW, BLACK, "PChar::SetBaseSkills() Profession: %d",def->GetIndex());
+ if ( def == NULL )
+ {
+ Console->Print( RED, BLACK, "PChar::SetBaseSkills: GetCharKindDef=NULL" );
+ return;
+ }
+ Skill->SetMainSkill( MS_INT, def->GetSkillInfo( MS_INT ).mStart );
+ Skill->SetMainSkill( MS_CON, def->GetSkillInfo( MS_CON ).mStart );
+ Skill->SetMainSkill( MS_DEX, def->GetSkillInfo( MS_DEX ).mStart );
+ Skill->SetMainSkill( MS_STR, def->GetSkillInfo( MS_STR ).mStart );
+ Skill->SetMainSkill( MS_PSI, def->GetSkillInfo( MS_PSI ).mStart );
+ // management of SP needed ? NC Client seem to calculate what remains ...
+ // or put SP setting after subskill setting ?
+ /* Skill->SetSP(MS_INT, (short) ??? ));
+ Skill->SetSP(MS_CON, ((short) ??? ));
+ Skill->SetSP(MS_DEX, (short) ??? ));
+ Skill->SetSP(MS_STR, (short) ??? ));
+ Skill->SetSP(MS_PSI, ((short) ??? )); */
+ // what about XPs ?
+ /* Skill->SetXP(MS_INT, ??? ));
+ Skill->SetXP(MS_CON, ??? ));
+ Skill->SetXP(MS_DEX, ??? ));
+ Skill->SetXP(MS_STR, ??? ));
+ Skill->SetXP(MS_PSI, ??? )); */
+ Console->Print( YELLOW, BLACK, "PChar::SetBaseSkills() not fully functionnal - unused skill points will be lost" );
+}
+
+void PChar::SetBaseSubskills( uint8_t NSZNb, const char* NonZeroSubskills )
+{
+ int i;
+
+ if ( NSZNb == 0 )
+ return;
+
+ for ( i = 0; i < NSZNb; i++ )
+ {
+ Skill->SetSubSkill(( SUB_SKILLS ) NonZeroSubskills[2 * i], ( int ) NonZeroSubskills[2 * i +1] );
+ }
+}
+
+void PChar::SetBaseInventory()
+{
+ uint8_t i;
+ uint32_t BaseItemID;
+ const PDefCharKind *def = GameDefs->CharKinds()->GetDef( mProfession );
+
+ //mCash = 5000;
+ mCash = def->GetStartMoney();
+
+ for ( i = 0; i < 8 ; i++ )
+ {
+ BaseItemID = def->GetStartInventory( i );
+ if ( BaseItemID )
+ {
+ if ( gDevDebug ) Console->Print( GREEN, BLACK, "Adding item %d to base inventory", BaseItemID );
+ PItem* NewItem = new PItem( BaseItemID );
+ if ( NewItem->GetItemID() )
+ {
+ NewItem->MakeItemStandard( 120, 180 ); // global quality range
+ mInventory.AddItem( NewItem );
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "Invalid item ID %d in base inventory for profession %d", BaseItemID, mProfession );
+ }
+ }
+ }
+}
+
+void PChar::LoadClanLevel()
+{
+ MYSQL_RES *result;
+ char query[200];
+
+ snprintf(query, 200, "SELECT cll_level FROM clanlevels WHERE cll_charid = %d AND cll_clanid = %d", mID, mClanID);
+ result = MySQL->GameResQuery( query );
+ if ( result == NULL )
+ {
+ mClanID = 0;
+ Console->Print( RED, BLACK, "PChar::GetClanLevel could not load ClanLevel from the database" );
+ Console->Print( "Query was:" );
+ Console->Print( "%s", query );
+ MySQL->ShowGameSQLError();
+ return;
+ }
+ else if(mysql_num_rows(result) == 0)
+ {
+ mClanID = 0;
+ Console->Print( RED, BLACK, "PChar::GetClanLevel No level entry found for clan!" );
+ return;
+ }
+ mClanLevel = atoi(mysql_fetch_row(result)[0]);
+ if (gDevDebug) Console->Print("Loaded ClanLevel %d for char %d, clan %d", mClanLevel, mID, mClanID);
+}
+
+bool PChar::SQLLoad( int CharID )
+{
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char query[1024];
+
+ snprintf( query, 1024, "SELECT * FROM characters WHERE c_id = %d LIMIT 1", CharID );
+ result = MySQL->GameResQuery( query );
+ if ( result == NULL )
+ {
+ Console->Print( RED, BLACK, "PChar::SQLLoad could not load Chardata from the database" );
+ Console->Print( "Query was:" );
+ Console->Print( "%s", query );
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+ if (( row = mysql_fetch_row( result ) ) )
+ {
+ SetID( CharID );
+ SetName( row[c_name] );
+ SetAccount( atoi( row[a_id] ) );
+
+ // Gender
+ int genvalue = atoi( row[c_sex] );
+ if (( genvalue == 0 ) || ( genvalue == 1 ) )
+ mGender = static_cast<uint32_t>( genvalue );
+ else
+ {
+ Console->Print( RED, BLACK, "Bad gender value: %d (Char ID %d)", genvalue, mID );
+ mGender = 0;
+ }
+
+ // Profession
+ int profvalue = atoi( row[c_profession] );
+ SetProfession( static_cast<uint32_t>( profvalue ) );
+
+ // Class
+ //int classvalue = atoi(row[c_class]);
+ //if(classvalue < 4)
+ // mClass = static_cast<uint32_t>(classvalue);
+ //else
+ //{
+ // Console->Print(RED, BLACK, "Bad class value: %d (Char ID %d)", classvalue, mID);
+ // classvalue = 0;
+ //}
+
+ // Faction
+ int facvalue = atoi( row[c_faction] );
+ if ( GameDefs->Factions()->GetDef( facvalue ) )
+ mFaction = static_cast<uint32_t>( facvalue );
+ else
+ mFaction = 1;
+
+ /* // Model
+ int modvalue = atoi(row[c_model]);
+ mModel = static_cast<uint32_t>(modvalue);
+ mModel = 10; */
+ int headvalue = atoi( row[c_head] );
+ int torsovalue = atoi( row[c_torso] );
+ int legsvalue = atoi( row[c_legs] );
+ SetRealLook( static_cast<uint32_t>( headvalue ), static_cast<uint32_t>( torsovalue ), static_cast<uint32_t>( legsvalue ) );
+
+ // Type
+ /*
+ int typevalue = std::atoi(row[c_type]);
+ mType = static_cast<uint32_t>(typevalue);
+ //mType = 1; */
+
+ // Location
+ int locvalue = atoi( row[c_location] );
+ mLocation = static_cast<uint32_t>( locvalue );
+
+//This assumption is not so good ... hardcoding jailed state linked with location ...
+ if ( mLocation == 550 || mLocation == 551 )
+ mJailed = true;
+
+ int posvalue = atoi( row[c_pos_x] );
+ Coords.mX = static_cast<uint16_t>( posvalue );
+ posvalue = atoi( row[c_pos_y] );
+ Coords.mY = static_cast<uint16_t>( posvalue );
+ posvalue = atoi( row[c_pos_z] );
+ Coords.mZ = static_cast<uint16_t>( posvalue );
+ posvalue = atoi( row[c_angle_ud] );
+ Coords.mUD = static_cast<uint8_t>( posvalue );
+ posvalue = atoi( row[c_angle_lr] );
+ Coords.mLR = static_cast<uint8_t>( posvalue );
+
+ int primapt = atoi( row[c_apt] );
+ mPrimaryApt = static_cast<uint32_t>( primapt );
+ mStartApt = mPrimaryApt;
+
+ mSoullight = atoi( row[c_soullight] );
+ mClanID = atoi( row[c_clan] );
+ if(mClanID > 0)
+ LoadClanLevel();
+
+ // Cash
+ float cashvalue = atof( row[c_cash] );
+ mCash = static_cast<uint32_t>( cashvalue );
+
+ // ---------------------------------------------
+ // Loading skills --- MAIN Skills with SP and XP
+ // ---------------------------------------------
+ Skill->SetMainSkill( MS_INT, atoi( row[c_int_lvl] ) );
+ Skill->SetMainSkill( MS_CON, atoi( row[c_con_lvl] ) );
+ Skill->SetMainSkill( MS_DEX, atoi( row[c_dex_lvl] ) );
+ Skill->SetMainSkill( MS_STR, atoi( row[c_str_lvl] ) );
+ Skill->SetMainSkill( MS_PSI, atoi( row[c_psi_lvl] ) );
+ // ---------------------------------------------
+ Skill->SetSP( MS_INT, ( short )atoi( row[c_int_pts] ) );
+ Skill->SetSP( MS_CON, ( short )atoi( row[c_con_pts] ) );
+ Skill->SetSP( MS_DEX, ( short )atoi( row[c_dex_pts] ) );
+ Skill->SetSP( MS_STR, ( short )atoi( row[c_str_pts] ) );
+ Skill->SetSP( MS_PSI, ( short )atoi( row[c_psi_pts] ) );
+ // ---------------------------------------------
+ Skill->SetXP( MS_INT, atof( row[c_int_xp] ) );
+ Skill->SetXP( MS_CON, atof( row[c_con_xp] ) );
+ Skill->SetXP( MS_DEX, atof( row[c_dex_xp] ) );
+ Skill->SetXP( MS_STR, atof( row[c_str_xp] ) );
+ Skill->SetXP( MS_PSI, atof( row[c_psi_xp] ) );
+ // ---------------------------------------------
+ // SubSkills
+ // ---------------------------------------------
+ Skill->SetSubSkill( SK_MC, atoi( row[c_mc] ) );
+ Skill->SetSubSkill( SK_HC, atoi( row[c_hc] ) );
+ Skill->SetSubSkill( SK_TRA, atoi( row[c_tra] ) );
+ Skill->SetSubSkill( SK_FOR, atoi( row[c_for] ) );
+ Skill->SetSubSkill( SK_PC, atoi( row[c_pc] ) );
+ Skill->SetSubSkill( SK_RC, atoi( row[c_rc] ) );
+ Skill->SetSubSkill( SK_TC, atoi( row[c_tc] ) );
+ Skill->SetSubSkill( SK_VHC, atoi( row[c_vhc] ) );
+ Skill->SetSubSkill( SK_AGL, atoi( row[c_agl] ) );
+ Skill->SetSubSkill( SK_REP, atoi( row[c_rep] ) );
+ Skill->SetSubSkill( SK_REC, atoi( row[c_rec] ) );
+ Skill->SetSubSkill( SK_RCL, atoi( row[c_rcl] ) );
+ Skill->SetSubSkill( SK_ATL, atoi( row[c_atl] ) );
+ Skill->SetSubSkill( SK_END, atoi( row[c_end] ) );
+ Skill->SetSubSkill( SK_FIR, atoi( row[c_fir] ) );
+ Skill->SetSubSkill( SK_ENR, atoi( row[c_enr] ) );
+ Skill->SetSubSkill( SK_XRR, atoi( row[c_xrr] ) );
+ Skill->SetSubSkill( SK_POR, atoi( row[c_por] ) );
+ Skill->SetSubSkill( SK_HLT, atoi( row[c_hlt] ) );
+ Skill->SetSubSkill( SK_HCK, atoi( row[c_hck] ) );
+ Skill->SetSubSkill( SK_BRT, atoi( row[c_brt] ) );
+ Skill->SetSubSkill( SK_PSU, atoi( row[c_psu] ) );
+ Skill->SetSubSkill( SK_WEP, atoi( row[c_wep] ) );
+ Skill->SetSubSkill( SK_CST, atoi( row[c_cst] ) );
+ Skill->SetSubSkill( SK_RES, atoi( row[c_res] ) );
+ Skill->SetSubSkill( SK_IMP, atoi( row[c_imp] ) );
+ Skill->SetSubSkill( SK_PPU, atoi( row[c_ppu] ) );
+ Skill->SetSubSkill( SK_APU, atoi( row[c_apu] ) );
+ Skill->SetSubSkill( SK_MST, atoi( row[c_mst] ) );
+ Skill->SetSubSkill( SK_PPW, atoi( row[c_ppw] ) );
+ Skill->SetSubSkill( SK_PSR, atoi( row[c_psr] ) );
+ Skill->SetSubSkill( SK_WPW, atoi( row[c_wpw] ) );
+ // --------------------------------------------
+ // Inventory
+ // ---------------------------------------------
+ mInventory.SetCharId( mID );
+ mInventory.SQLLoad();
+
+ // temp value forcing, not get/saved from DB atm
+ mCombatRank = ( uint8_t )( random() % 127 ); // bad result there on randomness
+ mSynaptic = 0;
+ mIsDead = false;
+
+ mDirectCharID = 0; // until saved/loaded with char
+ mBuddyList = new PBuddyList( mID );
+ if ( !mBuddyList->SQLLoad() )
+ {
+ Console->Print( RED, BLACK, "Char ID %d : Can't load buddy list", mID );
+ }
+ //to add: Chats settings
+
+ mGenrepList = new PGenrepList( mID );
+ if ( !mGenrepList->SQLLoad() )
+ {
+ Console->Print( RED, BLACK, "Char ID %d : Can't load genrep list", mID );
+ }
+
+ }
+ MySQL->FreeGameSQLResult( result );
+
+ // Addition; Set char's online status to ONLINE
+ char sqlqry[50];
+ snprintf(sqlqry, 50, "UPDATE characters SET c_online = 1 WHERE c_id = %d", mID);
+ MySQL->GameQuery(sqlqry);
+
+ return true;
+}
+
+bool PChar::SQLCreate() // Specific method for creation in order to avoid existence check with each save
+{
+ std::string query, queryv;
+
+ query = "INSERT INTO characters (c_id";
+ queryv = ") VALUES (NULL";
+
+ query += ",c_name";
+ queryv = queryv + ",'" + mName + "'";
+
+ query += ",a_id";
+ queryv += Ssprintf( ",'%u'", mAccount );
+ query += ",c_class";
+ queryv += Ssprintf( ",'%u'", mClass );
+ query += ",c_sex";
+ queryv += Ssprintf( ",'%u'", mGender );
+ query += ",c_profession";
+ queryv += Ssprintf( ",'%u'", mProfession );
+ query += ",c_faction";
+ queryv += Ssprintf( ",'%u'", mFaction );
+ query += ",c_head";
+ queryv += Ssprintf( ",'%u'", mRealHead );
+ query += ",c_torso";
+ queryv += Ssprintf( ",'%u'", mRealTorso );
+ query += ",c_legs";
+ queryv += Ssprintf( ",'%u'", mRealLegs );
+ //query += ",c_model";
+ //queryv += Ssprintf(",'%u'", mModel);
+ //query += ",c_type";
+ //queryv += Ssprintf(",'%u'", mType);
+ query += ",c_location";
+ queryv += Ssprintf( ",'%u'", mLocation );
+ query += ",c_cash";
+ queryv += Ssprintf( ",'%u'", mCash );
+ query += ",c_slot";
+ queryv += Ssprintf( ",'%u'", mSlot );
+
+ query = query + queryv + ");";
+
+ if ( MySQL->GameQuery( query.c_str() ) )
+ {
+ Console->Print( RED, BLACK, "PChar::SQLCreate could not add char %s to database", mName.c_str() );
+ Console->Print( "Query was:" );
+ Console->Print( "%s", query.c_str() );
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+ else
+ {
+ mID = MySQL->GetLastGameInsertId();
+//Console->Print(GREEN, BLACK, "New char %s got ID %d", mName.c_str(), mID);
+ mDirtyFlag = true;
+ return true;
+ }
+}
+
+bool PChar::CreateNewChar( uint32_t Account, const std::string &Name, uint32_t Gender, uint32_t Profession, uint32_t Faction,
+ uint32_t Head, uint32_t Torso, uint32_t Legs, uint8_t NZSNb, const char *NonZeroSubskills, uint32_t Slot )
+{
+ SetName( Name );
+ SetGender( Gender );
+ SetProfession( Profession );
+ SetFaction( Faction );
+ SetRealLook( Head, Torso, Legs );
+ SetBaseSkills();
+ SetBaseSubskills( NZSNb, NonZeroSubskills );
+ SetBaseInventory();
+ SetAccount( Account );
+ SetCharSlot( Slot );
+ mLocation = Config->GetOptionInt( "new_char_location" );
+
+ // This part will have to be rewritten with proper methods
+ mSoullight = 10;
+ mCombatRank = ( uint8_t )( random() % 80 ); // bad result there on randomness
+ mSynaptic = 0;
+ mIsDead = false;
+
+ mDirectCharID = 0; // until saved/loaded with char
+
+ SetDirtyFlag();
+
+ if ( SQLCreate() ) // mID isn't defined before that
+ {
+ mBuddyList = new PBuddyList( mID );
+ mGenrepList = new PGenrepList( mID );
+ mStartApt = mPrimaryApt = Appartements->CreateBaseAppartement( mID, mName, mFaction );
+ mInventory.SetCharId( mID );
+
+ if ( mStartApt && SQLSave() && mInventory.SQLSave() )
+ {
+ return true;
+ }
+ else
+ {
+ Console->Print( YELLOW, BLACK, "New char %s (id %d) : creation aborted", mName.c_str(), mID );
+ if ( mID )
+ {
+ SQLDelete();
+ if ( mStartApt )
+ {
+ Appartements->DeleteCharAppartements( mID );
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool PChar::SQLSave()
+{
+ std::string query;
+ //std::string ts;
+
+ /* TODO:
+ - Mostly at creation/load :
+ c_apt, (or when first GR to primary apt to avoid creation of unused apt?)
+ (c_slot)
+ - At save/load :
+ SoulLight ???
+ FactionSymp[] ???
+ Chest change: style, brightness, color
+ Legs change: style, brightness, color
+ mHealt, mStamina, mMana (not in DB !!!)
+ How to compute MaxHealth etc. ?
+ */
+ query = "UPDATE characters SET";
+
+ query += Ssprintf( " c_location='%u'", mLocation );
+ query += Ssprintf( ",c_pos_x='%u'", Coords.mX );
+ query += Ssprintf( ",c_pos_y='%u'", Coords.mY );
+ query += Ssprintf( ",c_pos_z='%u'", Coords.mZ );
+ query += Ssprintf( ",c_angle_ud='%u'", Coords.mUD );
+ query += Ssprintf( ",c_angle_lr='%u'", Coords.mLR );
+ query += Ssprintf( ",c_cash='%u'", mCash );
+ query += Ssprintf( ",c_apt='%u'", mPrimaryApt );
+
+ query += Ssprintf( ",c_head='%u'", mRealHead );
+ query += Ssprintf( ",c_torso='%u'", mRealTorso );
+ query += Ssprintf( ",c_legs='%u'", mRealLegs );
+
+ query += Ssprintf( ",c_faction='%u'", mFaction );
+
+ /* This group of fiels shouldn't change in-game
+ query = query + ",c_name='" + mName + "'";
+ query += Ssprintf(",a_id='%u'", mAccount);
+ query += Ssprintf(",c_class='%u'", mClass);
+ query += Ssprintf(",c_sex='%u'", mGender);
+ query += Ssprintf(",c_profession='%u'", mProfession);
+ query += Ssprintf(",c_slot='%u'", mSlot);
+ // query += Ssprintf(",c_model='%u'", mModel);
+ // query += Ssprintf(",c_type='%u'", mType);
+ */
+
+ // ---------------------------------------------
+ // Saving skills --- MAIN Skills with SP and XP
+ // ---------------------------------------------
+ query += Ssprintf( ",c_int_lvl='%u'", Skill->GetMainSkill( MS_INT ) );
+ query += Ssprintf( ",c_con_lvl='%u'", Skill->GetMainSkill( MS_CON ) );
+ query += Ssprintf( ",c_dex_lvl='%u'", Skill->GetMainSkill( MS_DEX ) );
+ query += Ssprintf( ",c_str_lvl='%u'", Skill->GetMainSkill( MS_STR ) );
+ query += Ssprintf( ",c_psi_lvl='%u'", Skill->GetMainSkill( MS_PSI ) );
+ // ---------------------------------------------
+ query += Ssprintf( ",c_int_pts='%u'", Skill->GetSP( MS_INT ) );
+ query += Ssprintf( ",c_con_pts='%u'", Skill->GetSP( MS_CON ) );
+ query += Ssprintf( ",c_dex_pts='%u'", Skill->GetSP( MS_DEX ) );
+ query += Ssprintf( ",c_str_pts='%u'", Skill->GetSP( MS_STR ) );
+ query += Ssprintf( ",c_psi_pts='%u'", Skill->GetSP( MS_PSI ) );
+ // ---------------------------------------------
+ query += Ssprintf( ",c_int_xp='%u'", Skill->GetXP( MS_INT ) );
+ query += Ssprintf( ",c_con_xp='%u'", Skill->GetXP( MS_CON ) );
+ query += Ssprintf( ",c_dex_xp='%u'", Skill->GetXP( MS_DEX ) );
+ query += Ssprintf( ",c_str_xp='%u'", Skill->GetXP( MS_STR ) );
+ query += Ssprintf( ",c_psi_xp='%u'", Skill->GetXP( MS_PSI ) );
+ // ---------------------------------------------
+ // SubSkills
+ // ---------------------------------------------
+ query += Ssprintf( ",c_mc='%u'", Skill->GetSubSkill( SK_MC ) );
+ query += Ssprintf( ",c_hc='%u'", Skill->GetSubSkill( SK_HC ) );
+ query += Ssprintf( ",c_tra='%u'", Skill->GetSubSkill( SK_TRA ) );
+ query += Ssprintf( ",c_for='%u'", Skill->GetSubSkill( SK_FOR ) );
+ query += Ssprintf( ",c_pc='%u'", Skill->GetSubSkill( SK_PC ) );
+ query += Ssprintf( ",c_rc='%u'", Skill->GetSubSkill( SK_RC ) );
+ query += Ssprintf( ",c_tc='%u'", Skill->GetSubSkill( SK_TC ) );
+ query += Ssprintf( ",c_vhc='%u'", Skill->GetSubSkill( SK_VHC ) );
+ query += Ssprintf( ",c_agl='%u'", Skill->GetSubSkill( SK_AGL ) );
+ query += Ssprintf( ",c_rep='%u'", Skill->GetSubSkill( SK_REP ) );
+ query += Ssprintf( ",c_rec='%u'", Skill->GetSubSkill( SK_REC ) );
+ query += Ssprintf( ",c_rcl='%u'", Skill->GetSubSkill( SK_RCL ) );
+ query += Ssprintf( ",c_atl='%u'", Skill->GetSubSkill( SK_ATL ) );
+ query += Ssprintf( ",c_end='%u'", Skill->GetSubSkill( SK_END ) );
+ query += Ssprintf( ",c_fir='%u'", Skill->GetSubSkill( SK_FIR ) );
+ query += Ssprintf( ",c_enr='%u'", Skill->GetSubSkill( SK_ENR ) );
+ query += Ssprintf( ",c_xrr='%u'", Skill->GetSubSkill( SK_XRR ) );
+ query += Ssprintf( ",c_por='%u'", Skill->GetSubSkill( SK_POR ) );
+ query += Ssprintf( ",c_htl='%u'", Skill->GetSubSkill( SK_HLT ) );
+ query += Ssprintf( ",c_hck='%u'", Skill->GetSubSkill( SK_HCK ) );
+ query += Ssprintf( ",c_brt='%u'", Skill->GetSubSkill( SK_BRT ) );
+ query += Ssprintf( ",c_psu='%u'", Skill->GetSubSkill( SK_PSU ) );
+ query += Ssprintf( ",c_wep='%u'", Skill->GetSubSkill( SK_WEP ) );
+ query += Ssprintf( ",c_cst='%u'", Skill->GetSubSkill( SK_CST ) );
+ query += Ssprintf( ",c_res='%u'", Skill->GetSubSkill( SK_RES ) );
+ query += Ssprintf( ",c_imp='%u'", Skill->GetSubSkill( SK_IMP ) );
+ query += Ssprintf( ",c_ppu='%u'", Skill->GetSubSkill( SK_PPU ) );
+ query += Ssprintf( ",c_apu='%u'", Skill->GetSubSkill( SK_APU ) );
+ query += Ssprintf( ",c_mst='%u'", Skill->GetSubSkill( SK_MST ) );
+ query += Ssprintf( ",c_ppw='%u'", Skill->GetSubSkill( SK_PPW ) );
+ query += Ssprintf( ",c_psr='%u'", Skill->GetSubSkill( SK_PSR ) );
+ query += Ssprintf( ",c_wpw='%u'", Skill->GetSubSkill( SK_WPW ) );
+ // ---------------------------------------------
+
+ query += Ssprintf( " WHERE c_id='%u' LIMIT 1;", mID );
+
+ if ( MySQL->GameQuery( query.c_str() ) )
+ {
+ Console->Print( RED, BLACK, "PChar::SQLSave could not save char %s (%u) to database", mName.c_str(), mID );
+ Console->Print( "Query was:" );
+ Console->Print( "%s", query.c_str() );
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+
+ // Chats settings (?), directs
+
+ mDirtyFlag = false;
+ return true;
+}
+
+bool PChar::SQLDelete()
+{
+ return true;
+}
+
+void PChar::SetOnlineStatus( bool IsOnline )
+{
+ // Deactivated, until Maxx added c_isonline row to `characters`
+ //char query[255];
+ int onlinestatus = 0;
+
+ if ( IsOnline )
+ {
+ onlinestatus = 0; // Strange ????
+ mIsOnline = true;
+ }
+ else
+ {
+ onlinestatus = 1; // Strange ????
+ mIsOnline = false;
+ }
+
+// snprintf(query, 255, "UPDATE charlist SET c_isonline = %d WHERE a_id = %d AND c_id = %d", onlinestatus, mAccount, mID);
+// if(MySQL->Query(query))
+// {
+// Console->Print("Error: Cant set onlinestatus to '%d' for Account: %d, Char: %d", onlinestatus, mAccount, mID);
+// MySQL->ShowSQLError();
+// return;
+// }
+ return;
+}
+
+uint8_t PChar::GetCombatRank()
+{
+ // Override for Special Account Levels
+ PAccount Acc(mAccount);
+ if(Acc.GetLevel() == PAL_ADMIN)
+ return 127;
+ else if(Acc.GetLevel() >= PAL_GM)
+ return 120;
+ else if(Acc.GetLevel() >= PAL_VOLUNTEER)
+ return 50;
+ else
+ return mCombatRank;
+}
+
+
+uint8_t PChar::GetMainRank()
+{
+ // Override for Special Account Levels
+ PAccount Acc(mAccount);
+ if(Acc.GetLevel() == PAL_ADMIN)
+ return 127;
+ else if(Acc.GetLevel() >= PAL_GM)
+ return 120;
+ else if(Acc.GetLevel() >= PAL_VOLUNTEER)
+ return 50;
+ else
+ {
+ uint16_t total;
+ total = Skill->GetMainSkill( MS_STR ) + Skill->GetMainSkill( MS_DEX );
+ total += Skill->GetMainSkill( MS_CON ) + Skill->GetMainSkill( MS_INT );
+ total += Skill->GetMainSkill( MS_PSI );
+ return (( uint8_t )( total / 5 ) );
+ }
+}
+
+bool PChar::AddGenrep(uint16_t nWorldID, uint16_t nStationID)
+{
+ return mGenrepList->AddGenrep(nWorldID, nStationID );
+}
+
+uint16_t PChar::GetGenrepListDataSize()
+{
+ return mGenrepList->GetListDataSize();
+}
+
+const void *PChar::GetGenrepListData()
+{
+ return mGenrepList->GetListData();
+}
+
+uint8_t PChar::GetGenrepCount()
+{
+ return mGenrepList->Count();
+}
+
+uint32_t PChar::AddCash( uint32_t nAmount )
+{
+ return SetCash(nAmount + mCash);
+}
+
+uint32_t PChar::TakeCash( uint32_t nAmount )
+{
+ if(nAmount > mCash)
+ {
+ //Tries to take away more cash that user has, set to zero
+ return SetCash(0);
+ }
+ else
+ {
+ return SetCash(mCash-nAmount);
+ }
+}
+
+uint32_t PChar::SetCash( uint32_t nCash )
+{
+ //Console->Print("Trying to set cash to nCash: %d", nCash);
+ if (( int )nCash > Config->GetOptionInt( "max_cash" ) )
+ {
+ //Console->Print("Newcash would be more than dynamic maxcash, setting to maxcash");
+ mCash = ( uint32_t )Config->GetOptionInt( "max_cash" );
+ }
+ else if ( nCash > MAXCASH )
+ {
+ //Console->Print("Newcash would be more than hardcoded maxcash, setting to maxcash");
+ mCash = MAXCASH;
+ }
+ else
+ {
+ //Console->Print("Allright, setting to new value");
+ mCash = nCash;
+ }
+ //Console->Print("Returning mCash: %d", mCash);
+ return mCash;
+}
+
+
+bool PChar::SetQuickBeltActiveSlot( uint8_t nSlotID )
+{
+ if (( nSlotID == INV_WORN_QB_HAND ) || ( nSlotID == INV_WORN_QB_NONE ) )
+ {
+ mQuickBeltActiveSlot = nSlotID;
+ return true;
+ }
+ else if ( nSlotID <= ( INV_WORN_QB_END - INV_WORN_QB_START ) )
+ {
+ PContainer* tWorn = mInventory.GetContainer( INV_LOC_WORN );
+
+ if ( ! tWorn->IsSlotFree( nSlotID ) ) // => TODO: MUST ALSO CHECK that item is currently usable and can be held in hand
+ {
+ mQuickBeltActiveSlot = nSlotID;
+ return true;
+ }
+ else
+ {
+ Console->Print( "SetQuickBeltActiveSlot: SlotID %d greater than %d or free (%d)", nSlotID, INV_WORN_QB_END - INV_WORN_QB_START, tWorn->IsSlotFree( nSlotID ) );
+ }
+ }
+ return false;
+}
+
+PSeatType PChar::GetSeatInUse( uint32_t* nObjectId, uint8_t* nSeatId )
+{
+ if ( nObjectId )
+ {
+ *nObjectId = mSeatInUseObjectId;
+ }
+ if ( nSeatId )
+ {
+ *nSeatId = mSeatInUseSeatId;
+ }
+
+ return mSeatInUseType;
+}
+
+void PChar::SetSeatInUse( PSeatType nSeatType, uint32_t nObjectId, uint8_t nSeatId )
+{
+ mSeatInUseType = nSeatType;
+ mSeatInUseObjectId = nObjectId;
+ mSeatInUseSeatId = nSeatId;
+}
+
+PVhcAccessRequestList* PChar::GetVhcAccessRequestList()
+{
+ if( ! mVhcAccessRequestList )
+ mVhcAccessRequestList = new PVhcAccessRequestList();
+
+ return mVhcAccessRequestList;
+}
+
+void PChar::SetLookingAt( uint16_t nLocalCharID )
+{
+ mLookingAt = nLocalCharID;
+ mLookAtTimestamp = std::time( NULL );
+}
+
+uint16_t PChar::GetLookingAt( uint16_t nMaxDelaySec )
+{
+ return ((( mLookAtTimestamp + nMaxDelaySec ) >= std::time( NULL ) ) ? mLookingAt : 0 );
+}
+
+// ===================================
+
+PChars::PChars()
+{
+ mLastID = 0;
+ mLastSave = std::time( NULL );
+
+ mAutoSavePeriod = Config->GetOptionInt( "auto_save_period" );
+ if ( mAutoSavePeriod < 0 )
+ {
+ Console->Print( "%s auto_save_period (%d) must be strict positive.", Console->ColorText( RED, BLACK, "[Error]" ), mAutoSavePeriod );
+ mAutoSavePeriod = 0;
+ }
+ else if ( mAutoSavePeriod > 3600 )
+ {
+ Console->Print( "%s auto_save_period (%d) too high. Forced to 3600 sec.", Console->ColorText( YELLOW, BLACK, "[Warning]" ), mAutoSavePeriod );
+ mAutoSavePeriod = 0;
+ }
+
+ if ( mAutoSavePeriod == 0 )
+ {
+ Console->Print( "%s Auto-save disabled.", Console->ColorText( YELLOW, BLACK, "[Info]" ) );
+ }
+ else if ( mAutoSavePeriod < 60 )
+ {
+ Console->Print( "%s auto_save_period (%d) is low and might lead to high server load.", Console->ColorText( YELLOW, BLACK, "[Warning]" ), mAutoSavePeriod );
+ }
+
+}
+
+PChars::~PChars()
+{
+ for ( CharMap::iterator i = mChars.begin(); i != mChars.end(); i++ )
+ delete i->second;
+}
+
+bool PChars::LoadChar( uint32_t CharID )
+{
+ if ( !CharID )
+ return false;
+
+ PChar *nChar = new PChar();
+ if ( nChar->SQLLoad( CharID ) )
+ {
+ nChar->SetDirtyFlag( false );
+ return AddChar( nChar );
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[ERROR] Could not load char id %d from database", CharID );
+ return false;
+ }
+}
+
+bool PChars::AddChar( PChar* nChar )
+{
+ if ( !nChar )
+ return false;
+
+ mLastID = std::max( mLastID, nChar->GetID() );
+ if ( mChars.insert( std::make_pair( nChar->GetID(), nChar ) ).second )
+ {
+ if ( gDevDebug )
+ Console->Print( "%s Char: %s (id %d) added", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nChar->GetName().c_str() , nChar->GetID() );
+ return true;
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[ERROR] Trying to load char twice : %s (id %d)", nChar->GetName().c_str(), nChar->GetID() );
+ return false;
+ }
+}
+
+PChar* PChars::RemoveChar( uint32_t CharID )
+{
+ PChar* Result = NULL;
+
+ CharMap::iterator i = mChars.find( CharID );
+ if ( i != mChars.end() )
+ {
+ Result = i->second;
+ mChars.erase( i );
+ if ( gDevDebug )
+ Console->Print( "%s Char: %s (id %d) removed", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), Result->GetName().c_str() , Result->GetID() );
+ }
+
+ return Result;
+}
+
+void PChars::SQLSave()
+{
+ // saves all dirty-flagged chars
+ int nDirtyChars = 0, nSavedChars = 0;
+ int nDirtyInv = 0, nSavedInv = 0;
+
+ for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ )
+ {
+ PChar* Char = i->second;
+ if ( Char->IsDirty() )
+ {
+ ++nDirtyChars;
+ if ( Char->SQLSave() )
+ ++nSavedChars;
+ }
+ if ( Char->GetInventory()->IsDirty() )
+ {
+ ++nDirtyInv;
+ if ( Char->GetInventory()->SQLSave() )
+ ++nSavedInv;
+ }
+ }
+ Console->Print( "%s %i chars saved on %i dirty, %i inventories saved on %i dirty", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), nSavedChars, nDirtyChars, nSavedInv, nDirtyInv );
+ return;
+}
+
+PChar* PChars::GetChar( uint32_t CharID ) const
+{
+ PChar *Result = 0;
+ CharMap::const_iterator i = mChars.find( CharID );
+ if ( i != mChars.end() )
+ Result = i->second;
+
+ return Result;
+}
+
+PChar* PChars::GetChar( const std::string &Name ) const
+{
+ PChar *Result = 0;
+ for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ )
+ {
+ if ( !/*std::*/strcasecmp( i->second->GetName().c_str(), Name.c_str() ) )
+ {
+ Result = i->second;
+ break;
+ }
+ }
+ return Result;
+}
+
+bool PChars::CharExist( const std::string &Name ) const
+{
+ char query[256];
+ int EntriesNb;
+ MYSQL_RES *result = 0;
+
+ char escUsername[256];
+ MySQL->EscapeString( Name.c_str(), escUsername, 256 );
+ snprintf( query, 256, "SELECT 1 FROM characters WHERE c_name = '%s' LIMIT 1;", escUsername );
+
+ result = MySQL->GameResQuery( query );
+ if ( result == NULL )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Failed to get CharacterData from SQL" );
+ MySQL->ShowGameSQLError();
+ return true;
+ }
+
+ EntriesNb = mysql_num_rows( result );
+ MySQL->FreeGameSQLResult( result );
+ return( EntriesNb > 0 );
+}
+
+void PChars::Update()
+{
+ std::time_t t = std::time( NULL ); // changed to time() to have real time instead of cpu used time
+
+ if ( mAutoSavePeriod && (( t - mLastSave ) >= mAutoSavePeriod ) )
+ {
+ bool NeedSave = false;
+ for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ )
+ {
+ if ( i->second->IsAnyDirty() )
+ {
+ NeedSave = true;
+ break;
+ }
+ }
+
+ if ( NeedSave )
+ {
+ if ( gDevDebug ) Console->Print( "%s Some characters need autosaving...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ SQLSave();
+ if ( gDevDebug ) Console->Print( "%s Autosave done.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ }
+ mLastSave = t;
+ }
+}
+
+//MAX_CHARS_PER_ACCOUNT
+int PChars::GetCharProfiles( const uint32_t AccountID, PCharProfile* CharSlotsArray, const uint8_t ArraySize )
+{
+ char query[256];
+ int EntriesNb = 0;
+
+ MYSQL_ROW row = 0;
+ MYSQL_RES *result = 0;
+
+ snprintf( query, 256, "SELECT * FROM characters WHERE a_id = %d ORDER BY c_slot ASC", AccountID );
+
+ result = MySQL->GameResQuery( query );
+ if ( result == NULL )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Failed to load CharacterData from SQL" );
+ MySQL->ShowGameSQLError();
+ return 0;
+ }
+
+ //EntriesNb = mysql_num_rows(result);
+ int SlotID;
+ uint32_t CharID;
+ PChar* tmpChar = new PChar();
+
+ while (( row = mysql_fetch_row( result ) ) )
+ {
+ SlotID = atoi( row[c_slot] );
+ CharID = atoi( row[c_id] );
+ if (( SlotID >= 0 ) && ( SlotID < ArraySize ) )
+ {
+ if ( !CharSlotsArray[SlotID].in_use )
+ {
+ tmpChar->SetID( CharID );
+ tmpChar->SetGender( atoi( row[c_sex] ) );
+ tmpChar->SetProfession( atoi( row[c_profession] ) );
+
+ CharSlotsArray[SlotID].CharID = CharID;
+ CharSlotsArray[SlotID].Type = tmpChar->GetType();
+ CharSlotsArray[SlotID].Location = static_cast<uint32_t>( atoi( row[c_location] ) );
+ CharSlotsArray[SlotID].Head = atoi( row[c_head] );
+ CharSlotsArray[SlotID].Torso = atoi( row[c_torso] );
+ CharSlotsArray[SlotID].Legs = atoi( row[c_legs] );
+ CharSlotsArray[SlotID].Name = row[c_name];
+ CharSlotsArray[SlotID].NameLen = CharSlotsArray[SlotID].Name.length() + 1;
+
+ CharSlotsArray[SlotID].in_use = true;
+ ++EntriesNb;
+ }
+ else
+ {
+ Console->Print( YELLOW, BLACK, "[Warning]Character %d using slot %d already used by char %d - Ignored", \
+ CharID, SlotID, CharSlotsArray[SlotID].CharID );
+ }
+ }
+ else
+ {
+ Console->Print( YELLOW, BLACK, "[Warning]Character %d using invialid slot %d - Ignored", CharID, SlotID );
+ }
+ }
+
+ delete tmpChar;
+ MySQL->FreeGameSQLResult( result );
+ return EntriesNb;
+}
-#pragma once\r
-\r
-#include <chrono>\r
-#include <cstdint>\r
-#include <map>\r
-#include "GameServer/Inventory.hxx" // FIXME: class design fault\r
-\r
-#define MAXCASH 1000000000\r
-\r
-class PGenrepList;\r
-class PSkillHandler;\r
-class PVhcAccessRequestList;\r
-\r
-enum PSeatType {\r
- seat_none = 0,\r
- seat_chair,\r
- seat_subway,\r
- seat_vhc\r
-};\r
-\r
-class PCharCoordinates {\r
- public:\r
- uint16_t mY; // Y-Position in world // Y increases when going East\r
- uint16_t mZ; // Z-Position in world // Z increases when going up\r
- uint16_t mX; // X-Position in world // X increases when going South\r
- uint8_t mUD; // Up - Mid - Down (d6 - 80 - 2a)\r
- uint8_t mLR; // Compass direction (S..E..N..W..S [0-45-90-135-179])\r
- uint8_t mAct; // Last user action state\r
- uint8_t mUnknown;// sometime sent by client with value != 0 (usual case)\r
- // mAct:\r
- // 0x00 NC has no focus (player alt+tab'ed out)\r
- // 0x04 Char on ground/dead 00000100\r
- // 0x20 Char does nothing 00100000\r
- // 0x22 kneeing 00100010\r
- // 0x28 left step 00101000\r
- // 0x30 right step 00110000\r
- // 0x40 walking (not running) 01000000 // Seems to mean Running ? - to be verfied, with default walk/run mode !!!\r
- // 0x60 forward 01100000\r
- // 0xA0 backward 10100000\r
- // bits: BFWRL.K.\r
-\r
- uint8_t mJumpingState;\r
-\r
- //inline PCharCoordinates() { mX = mY = mZ = mUD = mLR = mAct = mUnknown = mJumpingState = 0;}\r
- void SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD = 0x80, uint8_t nLR = 0 );\r
- void SetInterpolate( PCharCoordinates& Pos1, PCharCoordinates& Pos2, float nCoef );\r
-\r
- //Temp\r
- uint16_t minPos[3];\r
- uint16_t maxPos[3];\r
- inline PCharCoordinates() { mX = mY = mZ = mUD = mLR = mAct = mUnknown = mJumpingState = 0; for(int i=0; i<3; ++i) { minPos[i] = 0xffff; maxPos[i] = 0; } }\r
-};\r
-\r
-class PChar\r
-{\r
- private :\r
- // static members\r
- static RegEx* mCharnameRegexFilter;\r
-\r
- // instance members\r
- uint32_t mID;\r
- uint32_t mAccount;\r
- uint8_t mSlot;\r
- std::string mName;\r
- uint32_t mGender;\r
- uint32_t mClass;\r
- //uint32_t mType; // Removed that and only keep GetType()\r
- uint32_t mProfession;\r
- uint32_t mFaction;\r
- uint32_t mRealHead; // Base Skin elements, in complement of (computed) mType\r
- uint32_t mRealTorso; // " Head shouldn't be changeable, except in case of surgery !!!\r
- uint32_t mRealLegs; // "\r
- uint32_t mSkin; // Current Skin elements. *** Not saved in DB atm ***\r
- uint32_t mHead; // "\r
- uint32_t mTorso; // "\r
- uint32_t mLegs; // "\r
- uint8_t mHeadColor; // "\r
- uint8_t mTorsoColor; // "\r
- uint8_t mLegsColor; // "\r
- uint8_t mHeadDarkness; // " // 0=Bright, 255=dark\r
- uint8_t mTorsoDarkness; // "\r
- uint8_t mLegsDarkness; // "\r
- // Skin scale factor setting remain to discover, provided they are somewhere for player chars ...\r
-\r
- bool mLocationLeased; // temp until char on-demand load/unload\r
- uint32_t mLocation;\r
- uint32_t mCash;\r
- uint32_t mStartApt; // set same as PrimaryApt atm\r
- uint32_t mPrimaryApt;\r
-\r
- // not saved in DB atm\r
- PSeatType mSeatInUseType;\r
- uint32_t mSeatInUseObjectId;\r
- uint8_t mSeatInUseSeatId;\r
- PVhcAccessRequestList* mVhcAccessRequestList;\r
-\r
- PContainer* mContainerInExclusiveUse;\r
-\r
- uint16_t mHealth;\r
- uint16_t mMana;\r
- uint16_t mStamina;\r
-\r
- int8_t mSoullight;\r
- uint8_t mCombatRank; // *** Not got/saved from DB atm ***\r
- uint8_t mSynaptic; // *** Not got/saved from DB atm ***\r
- bool mIsDead; // *** Not got/saved from DB atm ***\r
-\r
- // Only one body effect supported atm. Should be extended later to multiple effects\r
- uint8_t mBodyEffect; // *** Not got/saved from DB atm ***\r
- uint8_t mBodyEffectDensity; // *** Not got/saved from DB atm ***\r
-\r
- uint8_t mSpeedOverride; // a hack to control move speed. Not saved in DB\r
-\r
- uint32_t mDirectCharID; // for Direct Chat // *** Not got/saved from DB atm ***\r
- PBuddyList* mBuddyList; // For Buddy list Chat\r
- uint32_t mActiveChatChannels; // Active chat channels flags // *** Not got/saved from DB atm ***\r
-\r
- PGenrepList* mGenrepList; // Character's GR list\r
-\r
- uint8_t mQuickBeltActiveSlot; // QB SlotID of item "in hand", or INV_WORN_QB_HAND or INV_WORN_QB_NONE\r
-\r
- uint16_t mLookingAt; // Zone charID of currently targeted player\r
- std::time_t mLookAtTimestamp; // Lifetimer of lookat var\r
- uint32_t mLastUsedWorldObjectId; // Last world object clicked on\r
-\r
- uint8_t mClanLevel; // 1-15\r
- uint16_t mClanID;\r
-\r
- bool mIsOnline;\r
- bool mDirtyFlag;\r
-\r
- bool mShunned;\r
- bool mJailed;\r
-\r
- uint32_t mDialogNPC; // NPCID the player talks to\r
- uint16_t mCurrentDialogNode; // Node in .lua file we're at right now\r
-\r
- class PInventory mInventory;\r
-\r
- protected :\r
- friend class PChars;\r
- inline void SetID( uint32_t ID ) { mID = ID; }\r
- inline void SetAccount( uint32_t Account ) { mAccount = Account; }\r
- inline void SetCharSlot( uint8_t Slot ) { if ( Slot < 4 ) mSlot = Slot;} // TODO: set max slot according to server config\r
- inline void SetName( const std::string &Name ) { mName = Name; }\r
- inline void SetGender( uint32_t Gender ) { mGender = Gender; }\r
- void SetProfession( uint32_t Profession );\r
- //inline void SetClass(uint32_t nClass) { mClass = nClass; } // mClass is defined by setting Profession\r
- //inline void SetType(uint32_t Type) { mType = Type; } // Removed. Type is computed from Gender & Profession (??? is it not Gender + Class ???)\r
- inline void SetFaction( uint32_t Faction ) { mFaction = Faction; }\r
- //inline void SetModel(uint32_t Model) { mModel = Model; } // Inhibited for the moment. Base model is deduced from from Gender & Class (Profession)\r
- void SetRealLook( uint32_t nHead, uint32_t nTorso, uint32_t nLegs );\r
- void SetBaseSkills();\r
- void SetBaseSubskills( uint8_t NZSNb, const char* NonZeroSubskills );\r
- void SetBaseInventory();\r
-\r
- bool SQLCreate();\r
-\r
- public :\r
- PChar();\r
- ~PChar();\r
-\r
- static bool SetCharnameRegexFilter( const char* RegexStr );\r
- static bool IsCharnameWellFormed( const char *Username );\r
-\r
- PSkillHandler *Skill;\r
- PCharCoordinates Coords;\r
-\r
- void SetCurrentLook( uint32_t nSkin, uint32_t nHead = 0, uint32_t nTorso = 0, uint32_t nLegs = 0 );\r
- void SetCurrentLookFromCharType( uint32_t nType );\r
- void ResetCurrentLook();\r
-\r
- void SetCurrentBodyColor( uint8_t nHeadColor, uint8_t nTorsoColor, uint8_t nLegsColor, uint8_t nHeadDarkness = 0, uint8_t nTorsoDarkness = 0, uint8_t nLegsDarkness = 0 );\r
- inline void SetBodyEffect( uint8_t nEffect, uint8_t nDensity = 0 ) { mBodyEffect = nEffect; mBodyEffectDensity = nDensity; }\r
- inline void SetSpeedOverride( uint8_t nSpeed = 255 ) { mSpeedOverride = nSpeed; }\r
-\r
- void SetLookingAt( uint16_t nLocalCharID );\r
- uint16_t GetLookingAt( uint16_t nMaxDelaySec = 1 );\r
- inline void SetLastUsedObject ( uint32_t nRawItemId ) { mLastUsedWorldObjectId = nRawItemId; }\r
- inline uint32_t GetLastUsedObject () const { return mLastUsedWorldObjectId; }\r
-\r
- inline PInventory* GetInventory() { return &mInventory; }\r
- inline uint32_t GetID() const { return mID; }\r
- inline uint32_t GetAccount() const { return mAccount; }\r
- inline const std::string &GetName() const { return mName; }\r
- inline uint32_t GetGender() const { return mGender; }\r
- inline uint32_t GetClass() const { return mClass; }\r
- inline uint32_t GetType() const { return 2 * mClass + mGender; }\r
- uint32_t GetSkinFromCharType( uint32_t nType );\r
- void GetRealLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs );\r
- void GetCurrentLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs );\r
- inline void GetBodyEffect( uint8_t &nEffect, uint8_t &nDensity ) { nEffect = mBodyEffect; nDensity = mBodyEffectDensity; }\r
-\r
- inline uint8_t GetQuickBeltActiveSlot() { return mQuickBeltActiveSlot; }\r
- bool SetQuickBeltActiveSlot( uint8_t nSlotID );\r
-\r
- void GetCurrentBodyColor( uint8_t &nHeadColor, uint8_t &nTorsoColor, uint8_t &nLegsColor, uint8_t &nHeadDarkness, uint8_t &nTorsoDarkness, uint8_t &nLegsDarkness );\r
- inline uint8_t GetSpeedOverride() { return mSpeedOverride; }\r
- inline uint32_t GetBaseModel();\r
- inline uint32_t GetProfession() const { return mProfession; }\r
- inline uint16_t GetMaxHealth() { return mHealth; }\r
- inline uint16_t GetMaxMana() { return mMana; }\r
- inline uint16_t GetMaxStamina() { return mStamina; }\r
- inline uint16_t GetHealth() { return mHealth; }\r
- inline uint16_t GetMana() { return mMana; }\r
- inline uint16_t GetStamina() { return mStamina; }\r
- inline uint32_t GetFaction() const { return mFaction; }\r
- inline uint32_t GetLocation() const { return mLocation; }\r
-\r
- inline uint32_t GetCash() const { return mCash; }\r
- uint32_t SetCash( uint32_t nCash ); // Does return the new cashvalue, NO udpmessage is sent out!!\r
- uint32_t AddCash( uint32_t nAmount );\r
- uint32_t TakeCash( uint32_t nAmount );\r
-\r
- inline uint32_t GetBaseApartment() const { return mPrimaryApt; }\r
-\r
- inline void SetJail( bool val ) { mJailed = val; };\r
- inline void SetShun( bool val ) { mShunned = val; };\r
-\r
- inline bool IsJailed() { return mJailed; };\r
- inline bool IsShunned() { return mShunned; };\r
-\r
- inline void SetDialogNPC( uint32_t nNPC ) { mDialogNPC = nNPC; };\r
- inline uint32_t GetDialogNPC() const { return mDialogNPC; };\r
-\r
- inline void SetDialogNode( uint16_t nNode ) { mCurrentDialogNode = nNode; };\r
- inline uint16_t GetDialogNode() const { return mCurrentDialogNode; };\r
-\r
- inline uint8_t GetClanLevel() const { return mClanLevel; };\r
- inline uint16_t GetClan() const { return mClanID; };\r
- void LoadClanLevel();\r
-\r
- inline int8_t GetSoullight() const { return mSoullight; }\r
- uint8_t GetMainRank();\r
- uint8_t GetCombatRank();\r
- inline uint8_t GetSynaptic() const { return mSynaptic; }\r
- inline bool IsDead() const { return mIsDead; }\r
-\r
- inline bool SetDirectChat( uint32_t nBuddyCharID ) { mDirectCharID = nBuddyCharID; return true; }\r
- inline uint32_t GetDirectChat() { return mDirectCharID; }\r
- inline void SetActiveChannels( uint32_t nChannels ) { mActiveChatChannels = nChannels; }\r
- inline uint32_t GetActiveChannels() { return mActiveChatChannels; }\r
-\r
- inline bool AddBuddy( uint32_t nBuddyCharID ) { return mBuddyList->AddChar( nBuddyCharID ); }\r
- inline bool RemoveBuddy( uint32_t nBuddyCharID ) { return mBuddyList->RemoveChar( nBuddyCharID ); }\r
- inline uint16_t GetBuddyListDataSize() { return mBuddyList->GetListDataSize(); }\r
- inline const void* GetBuddyListData() { return mBuddyList->GetListData(); }\r
- inline uint8_t GetBuddyCount() { return mBuddyList->Count(); }\r
- inline bool IsBuddy( uint32_t CharID ) { return mBuddyList->IsInBuddy( CharID ); };\r
-\r
- bool AddGenrep(uint16_t nWorldID, uint16_t nStationID);\r
- uint16_t GetGenrepListDataSize();\r
- const void *GetGenrepListData();\r
- uint8_t GetGenrepCount();\r
-\r
- inline bool IsDirty() const { return mDirtyFlag; }\r
- inline bool IsAnyDirty() const { return mDirtyFlag || mInventory.IsDirty(); }\r
- inline bool IsOnline() { return mIsOnline; }\r
- void SetOnlineStatus( bool IsOnline );\r
-\r
- bool CreateNewChar( uint32_t Account, const std::string &Name, uint32_t Gender, uint32_t Profession, uint32_t Faction,\r
- uint32_t Head, uint32_t Torso, uint32_t Legs, uint8_t NZSNb, const char *NonZeroSubskills, uint32_t Slot );\r
- bool SQLLoad( int CharID );\r
- bool SQLSave();\r
- inline bool SQLSaveFull() { return SQLSave() && mInventory.SQLSave(); }\r
- bool SQLDelete(); // not implemented yet\r
-\r
- inline void SetLocation( uint32_t Location ) { mLocation = Location; }\r
- inline void SetDirtyFlag( bool Dirty = true ) { mDirtyFlag = Dirty; }\r
-\r
- // temp until char on-demand load/unload\r
- inline void SetLocationLeased( bool nState = true ) { mLocationLeased = nState; }\r
- inline bool GetLocationLeased() { return mLocationLeased; }\r
-\r
- PSeatType GetSeatInUse( uint32_t* nObjectId = NULL, uint8_t* nSeatId = NULL );\r
- void SetSeatInUse( PSeatType nSeatType, uint32_t nObjectId = 0, uint8_t nSeatId = 0 );\r
-\r
- PVhcAccessRequestList* GetVhcAccessRequestList();\r
-\r
- inline PContainer* GetContainerInExclusiveUse() { return mContainerInExclusiveUse; }\r
- inline void SetContainerInExclusiveUse( PContainer* nContainer ) { mContainerInExclusiveUse = nContainer; }\r
-};\r
-\r
-struct PCharProfile\r
-{\r
- uint32_t CharID;\r
- uint16_t Type;\r
- uint16_t Color0;\r
- uint16_t Unknown1;\r
- uint8_t Head;\r
- uint8_t Torso;\r
- uint8_t Legs;\r
- uint32_t Location;\r
- uint8_t NameLen;\r
- uint8_t Unknown3;\r
- uint8_t Unknown4;\r
- uint8_t Unknown5;\r
- uint8_t Unknown6;\r
- uint8_t Unknown7;\r
- uint8_t Unknown8;\r
- uint8_t Unknown9;\r
- uint8_t Unknown10;\r
- uint8_t Unknown11;\r
- uint8_t Unknown12;\r
- std::string Name;\r
- bool in_use;\r
-};\r
-\r
-class PChars\r
-{\r
- private :\r
- typedef std::map<uint32_t, PChar*> CharMap;\r
- CharMap mChars;\r
- uint32_t mLastID;\r
-\r
- std::time_t mAutoSavePeriod;\r
- std::time_t mLastSave;\r
-\r
- public :\r
- PChars();\r
- ~PChars();\r
-\r
- bool LoadChar( uint32_t CharID );\r
- bool AddChar( PChar* nChar );\r
- PChar* RemoveChar( uint32_t CharID );\r
-\r
- PChar* GetChar( uint32_t CharID ) const;\r
- PChar* GetChar( const std::string &Name ) const;\r
- bool CharExist( const std::string &Name ) const;\r
-\r
- void SQLSave();\r
- void Update();\r
-\r
- int GetCharProfiles( const uint32_t AccountID, PCharProfile* CharSlotsArray, const uint8_t ArraySize ); // return effective entries nb\r
-};\r
+#pragma once
+
+#include <chrono>
+#include <cstdint>
+#include <map>
+#include "GameServer/Inventory.hxx" // FIXME: class design fault
+
+#define MAXCASH 1000000000
+
+class PGenrepList;
+class PSkillHandler;
+class PVhcAccessRequestList;
+
+enum PSeatType {
+ seat_none = 0,
+ seat_chair,
+ seat_subway,
+ seat_vhc
+};
+
+class PCharCoordinates {
+ public:
+ uint16_t mY; // Y-Position in world // Y increases when going East
+ uint16_t mZ; // Z-Position in world // Z increases when going up
+ uint16_t mX; // X-Position in world // X increases when going South
+ uint8_t mUD; // Up - Mid - Down (d6 - 80 - 2a)
+ uint8_t mLR; // Compass direction (S..E..N..W..S [0-45-90-135-179])
+ uint8_t mAct; // Last user action state
+ uint8_t mUnknown;// sometime sent by client with value != 0 (usual case)
+ // mAct:
+ // 0x00 NC has no focus (player alt+tab'ed out)
+ // 0x04 Char on ground/dead 00000100
+ // 0x20 Char does nothing 00100000
+ // 0x22 kneeing 00100010
+ // 0x28 left step 00101000
+ // 0x30 right step 00110000
+ // 0x40 walking (not running) 01000000 // Seems to mean Running ? - to be verfied, with default walk/run mode !!!
+ // 0x60 forward 01100000
+ // 0xA0 backward 10100000
+ // bits: BFWRL.K.
+
+ uint8_t mJumpingState;
+
+ //inline PCharCoordinates() { mX = mY = mZ = mUD = mLR = mAct = mUnknown = mJumpingState = 0;}
+ void SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD = 0x80, uint8_t nLR = 0 );
+ void SetInterpolate( PCharCoordinates& Pos1, PCharCoordinates& Pos2, float nCoef );
+
+ //Temp
+ uint16_t minPos[3];
+ uint16_t maxPos[3];
+ inline PCharCoordinates() { mX = mY = mZ = mUD = mLR = mAct = mUnknown = mJumpingState = 0; for(int i=0; i<3; ++i) { minPos[i] = 0xffff; maxPos[i] = 0; } }
+};
+
+class PChar
+{
+ private :
+ // static members
+ static RegEx* mCharnameRegexFilter;
+
+ // instance members
+ uint32_t mID;
+ uint32_t mAccount;
+ uint8_t mSlot;
+ std::string mName;
+ uint32_t mGender;
+ uint32_t mClass;
+ //uint32_t mType; // Removed that and only keep GetType()
+ uint32_t mProfession;
+ uint32_t mFaction;
+ uint32_t mRealHead; // Base Skin elements, in complement of (computed) mType
+ uint32_t mRealTorso; // " Head shouldn't be changeable, except in case of surgery !!!
+ uint32_t mRealLegs; // "
+ uint32_t mSkin; // Current Skin elements. *** Not saved in DB atm ***
+ uint32_t mHead; // "
+ uint32_t mTorso; // "
+ uint32_t mLegs; // "
+ uint8_t mHeadColor; // "
+ uint8_t mTorsoColor; // "
+ uint8_t mLegsColor; // "
+ uint8_t mHeadDarkness; // " // 0=Bright, 255=dark
+ uint8_t mTorsoDarkness; // "
+ uint8_t mLegsDarkness; // "
+ // Skin scale factor setting remain to discover, provided they are somewhere for player chars ...
+
+ bool mLocationLeased; // temp until char on-demand load/unload
+ uint32_t mLocation;
+ uint32_t mCash;
+ uint32_t mStartApt; // set same as PrimaryApt atm
+ uint32_t mPrimaryApt;
+
+ // not saved in DB atm
+ PSeatType mSeatInUseType;
+ uint32_t mSeatInUseObjectId;
+ uint8_t mSeatInUseSeatId;
+ PVhcAccessRequestList* mVhcAccessRequestList;
+
+ PContainer* mContainerInExclusiveUse;
+
+ uint16_t mHealth;
+ uint16_t mMana;
+ uint16_t mStamina;
+
+ int8_t mSoullight;
+ uint8_t mCombatRank; // *** Not got/saved from DB atm ***
+ uint8_t mSynaptic; // *** Not got/saved from DB atm ***
+ bool mIsDead; // *** Not got/saved from DB atm ***
+
+ // Only one body effect supported atm. Should be extended later to multiple effects
+ uint8_t mBodyEffect; // *** Not got/saved from DB atm ***
+ uint8_t mBodyEffectDensity; // *** Not got/saved from DB atm ***
+
+ uint8_t mSpeedOverride; // a hack to control move speed. Not saved in DB
+
+ uint32_t mDirectCharID; // for Direct Chat // *** Not got/saved from DB atm ***
+ PBuddyList* mBuddyList; // For Buddy list Chat
+ uint32_t mActiveChatChannels; // Active chat channels flags // *** Not got/saved from DB atm ***
+
+ PGenrepList* mGenrepList; // Character's GR list
+
+ uint8_t mQuickBeltActiveSlot; // QB SlotID of item "in hand", or INV_WORN_QB_HAND or INV_WORN_QB_NONE
+
+ uint16_t mLookingAt; // Zone charID of currently targeted player
+ std::time_t mLookAtTimestamp; // Lifetimer of lookat var
+ uint32_t mLastUsedWorldObjectId; // Last world object clicked on
+
+ uint8_t mClanLevel; // 1-15
+ uint16_t mClanID;
+
+ bool mIsOnline;
+ bool mDirtyFlag;
+
+ bool mShunned;
+ bool mJailed;
+
+ uint32_t mDialogNPC; // NPCID the player talks to
+ uint16_t mCurrentDialogNode; // Node in .lua file we're at right now
+
+ class PInventory mInventory;
+
+ protected :
+ friend class PChars;
+ inline void SetID( uint32_t ID ) { mID = ID; }
+ inline void SetAccount( uint32_t Account ) { mAccount = Account; }
+ inline void SetCharSlot( uint8_t Slot ) { if ( Slot < 4 ) mSlot = Slot;} // TODO: set max slot according to server config
+ inline void SetName( const std::string &Name ) { mName = Name; }
+ inline void SetGender( uint32_t Gender ) { mGender = Gender; }
+ void SetProfession( uint32_t Profession );
+ //inline void SetClass(uint32_t nClass) { mClass = nClass; } // mClass is defined by setting Profession
+ //inline void SetType(uint32_t Type) { mType = Type; } // Removed. Type is computed from Gender & Profession (??? is it not Gender + Class ???)
+ inline void SetFaction( uint32_t Faction ) { mFaction = Faction; }
+ //inline void SetModel(uint32_t Model) { mModel = Model; } // Inhibited for the moment. Base model is deduced from from Gender & Class (Profession)
+ void SetRealLook( uint32_t nHead, uint32_t nTorso, uint32_t nLegs );
+ void SetBaseSkills();
+ void SetBaseSubskills( uint8_t NZSNb, const char* NonZeroSubskills );
+ void SetBaseInventory();
+
+ bool SQLCreate();
+
+ public :
+ PChar();
+ ~PChar();
+
+ static bool SetCharnameRegexFilter( const char* RegexStr );
+ static bool IsCharnameWellFormed( const char *Username );
+
+ PSkillHandler *Skill;
+ PCharCoordinates Coords;
+
+ void SetCurrentLook( uint32_t nSkin, uint32_t nHead = 0, uint32_t nTorso = 0, uint32_t nLegs = 0 );
+ void SetCurrentLookFromCharType( uint32_t nType );
+ void ResetCurrentLook();
+
+ void SetCurrentBodyColor( uint8_t nHeadColor, uint8_t nTorsoColor, uint8_t nLegsColor, uint8_t nHeadDarkness = 0, uint8_t nTorsoDarkness = 0, uint8_t nLegsDarkness = 0 );
+ inline void SetBodyEffect( uint8_t nEffect, uint8_t nDensity = 0 ) { mBodyEffect = nEffect; mBodyEffectDensity = nDensity; }
+ inline void SetSpeedOverride( uint8_t nSpeed = 255 ) { mSpeedOverride = nSpeed; }
+
+ void SetLookingAt( uint16_t nLocalCharID );
+ uint16_t GetLookingAt( uint16_t nMaxDelaySec = 1 );
+ inline void SetLastUsedObject ( uint32_t nRawItemId ) { mLastUsedWorldObjectId = nRawItemId; }
+ inline uint32_t GetLastUsedObject () const { return mLastUsedWorldObjectId; }
+
+ inline PInventory* GetInventory() { return &mInventory; }
+ inline uint32_t GetID() const { return mID; }
+ inline uint32_t GetAccount() const { return mAccount; }
+ inline const std::string &GetName() const { return mName; }
+ inline uint32_t GetGender() const { return mGender; }
+ inline uint32_t GetClass() const { return mClass; }
+ inline uint32_t GetType() const { return 2 * mClass + mGender; }
+ uint32_t GetSkinFromCharType( uint32_t nType );
+ void GetRealLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs );
+ void GetCurrentLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs );
+ inline void GetBodyEffect( uint8_t &nEffect, uint8_t &nDensity ) { nEffect = mBodyEffect; nDensity = mBodyEffectDensity; }
+
+ inline uint8_t GetQuickBeltActiveSlot() { return mQuickBeltActiveSlot; }
+ bool SetQuickBeltActiveSlot( uint8_t nSlotID );
+
+ void GetCurrentBodyColor( uint8_t &nHeadColor, uint8_t &nTorsoColor, uint8_t &nLegsColor, uint8_t &nHeadDarkness, uint8_t &nTorsoDarkness, uint8_t &nLegsDarkness );
+ inline uint8_t GetSpeedOverride() { return mSpeedOverride; }
+ inline uint32_t GetBaseModel();
+ inline uint32_t GetProfession() const { return mProfession; }
+ inline uint16_t GetMaxHealth() { return mHealth; }
+ inline uint16_t GetMaxMana() { return mMana; }
+ inline uint16_t GetMaxStamina() { return mStamina; }
+ inline uint16_t GetHealth() { return mHealth; }
+ inline uint16_t GetMana() { return mMana; }
+ inline uint16_t GetStamina() { return mStamina; }
+ inline uint32_t GetFaction() const { return mFaction; }
+ inline uint32_t GetLocation() const { return mLocation; }
+
+ inline uint32_t GetCash() const { return mCash; }
+ uint32_t SetCash( uint32_t nCash ); // Does return the new cashvalue, NO udpmessage is sent out!!
+ uint32_t AddCash( uint32_t nAmount );
+ uint32_t TakeCash( uint32_t nAmount );
+
+ inline uint32_t GetBaseApartment() const { return mPrimaryApt; }
+
+ inline void SetJail( bool val ) { mJailed = val; };
+ inline void SetShun( bool val ) { mShunned = val; };
+
+ inline bool IsJailed() { return mJailed; };
+ inline bool IsShunned() { return mShunned; };
+
+ inline void SetDialogNPC( uint32_t nNPC ) { mDialogNPC = nNPC; };
+ inline uint32_t GetDialogNPC() const { return mDialogNPC; };
+
+ inline void SetDialogNode( uint16_t nNode ) { mCurrentDialogNode = nNode; };
+ inline uint16_t GetDialogNode() const { return mCurrentDialogNode; };
+
+ inline uint8_t GetClanLevel() const { return mClanLevel; };
+ inline uint16_t GetClan() const { return mClanID; };
+ void LoadClanLevel();
+
+ inline int8_t GetSoullight() const { return mSoullight; }
+ uint8_t GetMainRank();
+ uint8_t GetCombatRank();
+ inline uint8_t GetSynaptic() const { return mSynaptic; }
+ inline bool IsDead() const { return mIsDead; }
+
+ inline bool SetDirectChat( uint32_t nBuddyCharID ) { mDirectCharID = nBuddyCharID; return true; }
+ inline uint32_t GetDirectChat() { return mDirectCharID; }
+ inline void SetActiveChannels( uint32_t nChannels ) { mActiveChatChannels = nChannels; }
+ inline uint32_t GetActiveChannels() { return mActiveChatChannels; }
+
+ inline bool AddBuddy( uint32_t nBuddyCharID ) { return mBuddyList->AddChar( nBuddyCharID ); }
+ inline bool RemoveBuddy( uint32_t nBuddyCharID ) { return mBuddyList->RemoveChar( nBuddyCharID ); }
+ inline uint16_t GetBuddyListDataSize() { return mBuddyList->GetListDataSize(); }
+ inline const void* GetBuddyListData() { return mBuddyList->GetListData(); }
+ inline uint8_t GetBuddyCount() { return mBuddyList->Count(); }
+ inline bool IsBuddy( uint32_t CharID ) { return mBuddyList->IsInBuddy( CharID ); };
+
+ bool AddGenrep(uint16_t nWorldID, uint16_t nStationID);
+ uint16_t GetGenrepListDataSize();
+ const void *GetGenrepListData();
+ uint8_t GetGenrepCount();
+
+ inline bool IsDirty() const { return mDirtyFlag; }
+ inline bool IsAnyDirty() const { return mDirtyFlag || mInventory.IsDirty(); }
+ inline bool IsOnline() { return mIsOnline; }
+ void SetOnlineStatus( bool IsOnline );
+
+ bool CreateNewChar( uint32_t Account, const std::string &Name, uint32_t Gender, uint32_t Profession, uint32_t Faction,
+ uint32_t Head, uint32_t Torso, uint32_t Legs, uint8_t NZSNb, const char *NonZeroSubskills, uint32_t Slot );
+ bool SQLLoad( int CharID );
+ bool SQLSave();
+ inline bool SQLSaveFull() { return SQLSave() && mInventory.SQLSave(); }
+ bool SQLDelete(); // not implemented yet
+
+ inline void SetLocation( uint32_t Location ) { mLocation = Location; }
+ inline void SetDirtyFlag( bool Dirty = true ) { mDirtyFlag = Dirty; }
+
+ // temp until char on-demand load/unload
+ inline void SetLocationLeased( bool nState = true ) { mLocationLeased = nState; }
+ inline bool GetLocationLeased() { return mLocationLeased; }
+
+ PSeatType GetSeatInUse( uint32_t* nObjectId = NULL, uint8_t* nSeatId = NULL );
+ void SetSeatInUse( PSeatType nSeatType, uint32_t nObjectId = 0, uint8_t nSeatId = 0 );
+
+ PVhcAccessRequestList* GetVhcAccessRequestList();
+
+ inline PContainer* GetContainerInExclusiveUse() { return mContainerInExclusiveUse; }
+ inline void SetContainerInExclusiveUse( PContainer* nContainer ) { mContainerInExclusiveUse = nContainer; }
+};
+
+struct PCharProfile
+{
+ uint32_t CharID;
+ uint16_t Type;
+ uint16_t Color0;
+ uint16_t Unknown1;
+ uint8_t Head;
+ uint8_t Torso;
+ uint8_t Legs;
+ uint32_t Location;
+ uint8_t NameLen;
+ uint8_t Unknown3;
+ uint8_t Unknown4;
+ uint8_t Unknown5;
+ uint8_t Unknown6;
+ uint8_t Unknown7;
+ uint8_t Unknown8;
+ uint8_t Unknown9;
+ uint8_t Unknown10;
+ uint8_t Unknown11;
+ uint8_t Unknown12;
+ std::string Name;
+ bool in_use;
+};
+
+class PChars
+{
+ private :
+ typedef std::map<uint32_t, PChar*> CharMap;
+ CharMap mChars;
+ uint32_t mLastID;
+
+ std::time_t mAutoSavePeriod;
+ std::time_t mLastSave;
+
+ public :
+ PChars();
+ ~PChars();
+
+ bool LoadChar( uint32_t CharID );
+ bool AddChar( PChar* nChar );
+ PChar* RemoveChar( uint32_t CharID );
+
+ PChar* GetChar( uint32_t CharID ) const;
+ PChar* GetChar( const std::string &Name ) const;
+ bool CharExist( const std::string &Name ) const;
+
+ void SQLSave();
+ void Update();
+
+ int GetCharProfiles( const uint32_t AccountID, PCharProfile* CharSlotsArray, const uint8_t ArraySize ); // return effective entries nb
+};
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-// TODO:- Add "hooks" to process chatevents everywhere in the source <-- kind of done. you can use the global PChat Instance.\r
-// Check:\r
-// Chat->send(PClient* receiver, const uint8_t* Channel, const char* AuthorNickName, char* text, bool debugOut=false);\r
-// Example:\r
-// Chat->send(receiverClient, CHAT_DIRECT, Chars->GetChar(authorClient->GetCharID())->GetName().c_str(), text);\r
-\r
-PChat::PChat()\r
-{\r
-}\r
-\r
-PChat::~PChat()\r
-{\r
-}\r
-\r
-/*\r
-DONE void sendBuddy(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendLocal(PClient* author, char* text, bool debugOut=false);\r
-NEED CLANDATA void sendClan(PClient* author, char* text, bool debugOut=false);\r
-NEED TEAMDATA void sendTeam(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendDirect(PClient* author, PClient* receiver, char* text, bool debugOut=false);\r
-DONE void sendZone(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendFrak(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendTradeCS(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendTradeMB(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendTradeNC(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendTradeTH(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendTradeWL(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendOOC(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendHelp(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendClanSearch(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendServicesCS(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendServicesMB(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendServicesNC(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendServicesTH(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendServicesWL(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendTeam10(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendTeam30(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendTeam50(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendTeam70(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendAdmin(PClient* author, char* text, bool debugOut=false);\r
-DONE void sendGM(PClient* author, char* text, bool debugOut=false);\r
-*/\r
-\r
-\r
-void PChat::sendBuddy(PClient* author, const char* text, bool debugOut)\r
-{\r
- PChar* authorChar = Chars->GetChar(author->GetCharID());\r
- // send the message to all Buddys in list\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second && authorChar->IsBuddy(it->second->GetCharID()) == true)\r
- {\r
- PClient* receiver = it->second;\r
- //Console->Print("DEBUG: Buddychat - Sending msg to %s", Chars->GetChar(receiver->GetCharID())->GetName().c_str());\r
- send(receiver, CHAT_BUDDY, authorChar->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendConnectedList(PClient* receiver, bool debugOut)\r
-{\r
- const char* text = "Connected Players are:]";\r
- send(receiver, CHAT_DIRECT, "[System", text, debugOut);\r
-\r
- int counter = 1;\r
-\r
- // send the list of currently connected players to receiver\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- char counterText[5];\r
- snprintf(counterText, 5, "%d", counter);\r
-\r
- PChar* receiverChar = Chars->GetChar(it->second->GetCharID());\r
- send(receiver, CHAT_DIRECT, (receiverChar ? receiverChar->GetName().c_str() : "*"), counterText, debugOut);\r
-\r
- counter++;\r
- }\r
-}\r
-\r
-\r
-void PChat::sendFrak(PClient* author, const char* text, bool debugOut)\r
-{\r
- // send the message to all clients that have same FactionID\r
- PChar* authorChar = Chars->GetChar(author->GetCharID());\r
- uint32_t FID = authorChar->GetFaction(); // get LocationID of author\r
-\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- PClient* receiver = it->second;\r
- PChar* receiverChar = Chars->GetChar(receiver->GetCharID());\r
- if(receiverChar && (receiverChar->GetFaction() == FID))\r
- {\r
- if(chanEnabled(receiver, C_FRAK) == true)\r
- send(receiver, CHAT_FRAK, authorChar->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendZone(PClient* author, const char* text, bool debugOut)\r
-{\r
- // send the message to all clients that have same ZoneID\r
- PChar* authorChar = Chars->GetChar(author->GetCharID());\r
- uint32_t ZID = authorChar->GetLocation(); // get LocationID of author\r
-\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- PClient* receiver = it->second;\r
- PChar* receiverChar = Chars->GetChar(receiver->GetCharID());\r
- if(receiverChar && (receiverChar->GetLocation() == ZID))\r
- {\r
- if(chanEnabled(receiver, C_ZONE) == true)\r
- send(receiver, CHAT_ZONE, authorChar->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendLocal(PClient* author, const char* text, bool debugOut)\r
-{\r
- PChar* authorChar = Chars->GetChar(author->GetCharID());\r
- uint32_t ZID = authorChar->GetLocation(); // get LocationID of author\r
-\r
- // send the message to all clients that are in Area (Radius = X (needs to be defined somewhere!))\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- PClient* receiver = it->second;\r
- PChar* receiverChar = Chars->GetChar(receiver->GetCharID());\r
- if(receiverChar && (receiverChar->GetLocation() == ZID))\r
- {\r
- uint16_t distance = DistanceApprox((authorChar->Coords).mX, (authorChar->Coords).mY, (authorChar->Coords).mZ, (receiverChar->Coords).mX, (receiverChar->Coords).mY, (receiverChar->Coords).mZ);\r
- if(distance < LOCALCHAT_MAXDISTANCE)\r
- {\r
- //sendLocalchat(receiver, author, text, debugOut); // Doesnt work!\r
- send(receiver, CHAT_LOCAL, authorChar->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendGM(PClient* author, const char* text, bool debugOut)\r
-{\r
- if(author->GetAccountLevel() >= PAL_GM) // Only send GM> chat when user is an Gamemaster or higher\r
- {\r
- // send the message to all GameMasters.\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(receiver->GetAccountLevel() >= PAL_GM) // Only send GM chat if RECEIVER is GM or higher\r
- send(receiver, CHAT_GM, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendGMAdmin(PClient* author, const char* text, bool debugOut)\r
-{\r
- if(author->GetAccountLevel() >= PAL_GM) // Only send GM> chat when user is an Gamemaster or higher\r
- {\r
- // send the message to ALL users online\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- send(receiver, CHAT_GMADMIN, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendAdmin(PClient* author, const char* text, bool debugOut)\r
-{\r
- if(author->GetAccountLevel() >= PAL_ADMIN) // Only send ADMIN> chat when user is an serveradmin\r
- {\r
- // send the message to ALL users online\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- send(receiver, CHAT_ADMIN, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendBroadcast(const char* text, bool debugOut)\r
-{\r
- // send the message to ALL users online\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- send(receiver, CHAT_ADMIN, "Server", text, debugOut);\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendOOCBroadcast(const char* text, bool debugOut)\r
-{\r
- // send the message to ALL users online\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_OOC) == true)\r
- send(receiver, CHAT_OOC, "Server", text, debugOut);\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendClan(PClient* author, const char* text, bool debugOut)\r
-{\r
- /**\r
- NOT ABLE TO IMPLEMENT THIS CHATTYPE YET, ITS SUPERGLOBAL TILL THEN\r
- **/\r
- // send the message to all clients that have same ClanID\r
- PChar* authorChar = Chars->GetChar(author->GetCharID());\r
-\r
-// int ClanID = authorChar->getClanID(); // get clanID of author\r
-\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second)\r
- {\r
- PClient* receiver = it->second;\r
- PChar* receiverChar = Chars->GetChar(receiver->GetCharID());\r
- if(receiverChar /*&& (receiverChar->getClanID() == ClanID)*/)\r
- {\r
- send(receiver, CHAT_CLAN, authorChar->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-\r
-}\r
-\r
-void PChat::sendTeam(PClient* author, const char* text, bool debugOut)\r
-{\r
- /**\r
- NOT ABLE TO IMPLEMENT THIS CHATTYPE YET, ITS SUPERGLOBAL TILL THEN\r
- **/\r
- // send the message to all clients that have same TeamID\r
-\r
- PChar* authorChar = Chars->GetChar(author->GetCharID());\r
-\r
- //int TeamID = authorChar->getTeamID(); // get TeamID of author\r
-\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second)\r
- {\r
- PClient* receiver = it->second;\r
- PChar* receiverChar = Chars->GetChar(receiver->GetCharID());\r
- if(receiverChar /*&& (receiverChar->getTeamID() == TeamID)*/)\r
- {\r
- send(receiver, CHAT_TEAM, authorChar->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendPlayerDirect(PClient* author, const char* text, uint32_t destination, bool debugOut)\r
-{\r
- bool tmpTargetOnline = false;\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- PClient* receiver = it->second;\r
- PChar* receiverChar = Chars->GetChar(receiver->GetCharID());\r
- if(receiverChar && (receiver->GetCharID() == destination)) \r
- {\r
- tmpTargetOnline = true;\r
- sendDirect(author, receiver, text, debugOut);\r
- }\r
- }\r
- if(tmpTargetOnline == false)\r
- {\r
- ConnectionTCP *Socket = author->getTCPConn();\r
- uint8_t DirectTargetNotOnline[] = {0xFE, 0x07, 0x00, 0x83, 0x18, 0x01, 0x81, 0x54, 0x00, 0x00};\r
-\r
- Socket->write(DirectTargetNotOnline, sizeof(DirectTargetNotOnline));\r
- Socket->flushSendBuffer();\r
- }\r
-\r
- if(debugOut == true)\r
- {\r
- if(tmpTargetOnline == false)\r
- Console->Print("[DEBUG] Requested target CharID %d is not online", destination);\r
- else\r
- Console->Print("[DEBUG] CharID %d found and message transmitted!", destination);\r
- }\r
-}\r
-\r
-void PChat::sendDirect(PClient* author, PClient* receiver, const char* text, bool debugOut)\r
-{\r
- PChar* authorChar = Chars->GetChar(author->GetCharID());\r
-\r
- char *DChatPacket;\r
- unsigned int packetsize = 0, c;\r
- int LenText, LenNick, fpp, d, e, loopout;\r
-\r
- ConnectionTCP *Socket = receiver->getTCPConn();\r
-\r
- uint8_t BasicDirectPacket[] = {0xFE, 0x20, 0x00, 0x83, 0x17, 0xB7, 0x5F, 0x00, 0x00, 0x0C, 0x04, 0x00};\r
-\r
- LenText = LenNick = fpp = 0;\r
-\r
- do {\r
- LenText++;\r
- } while(text[LenText] != '\0');\r
-\r
- do {\r
- LenNick++;\r
- } while(authorChar->GetName().c_str()[LenNick] != '\0');\r
-\r
- loopout = 0;\r
-\r
- packetsize = sizeof(BasicDirectPacket) + LenText + LenNick;\r
-\r
- if(debugOut == true) {\r
- Console->Print("Sizeof(TextToSend): %d || Sizeof(Nick): %d", LenText, LenNick);\r
- Console->Print("Whole size: %d", packetsize);\r
- }\r
-\r
- DChatPacket = new char [packetsize];\r
-\r
- // Copy basic packet into final packet\r
- for(c=0;c<sizeof(BasicDirectPacket);c++) {\r
- DChatPacket[fpp] = BasicDirectPacket[c];\r
- fpp++;\r
- }\r
-\r
- // Copy Nickname into final packet\r
- for(d=0;d<LenNick;d++) {\r
- DChatPacket[fpp] = authorChar->GetName().c_str()[d];\r
- fpp++;\r
- }\r
-\r
- // Copy Text into final packet\r
- for(e=0;e<LenText;e++) {\r
- DChatPacket[fpp] = text[e];\r
- fpp++;\r
- }\r
-\r
- // Change Lenght bytes in final packet\r
- DChatPacket[1] = packetsize - 3;\r
- DChatPacket[9] = LenNick;\r
-\r
- if(debugOut == true) {\r
- unsigned int debugout;\r
- for(debugout=0;debugout<packetsize;debugout++) {\r
- Console->Print("Byte %d: %#x", debugout, DChatPacket[debugout]);\r
- }\r
- }\r
-\r
- // Sending direct chat packet and removing dynamic array\r
- Socket->write(DChatPacket, packetsize);\r
- Socket->flushSendBuffer();\r
- delete[] DChatPacket;\r
-}\r
-\r
-void PChat::sendLocalchat(PClient* receiver, PClient* author, const char* text, bool debugOut)\r
-{\r
- return; // IncreaseUDP could cause OOO here. Since this function is doing nothing, we disabled it\r
- char *LocalChatPacket;\r
- int overallsize = 0, LenText = 0;\r
- uint8_t BasicLocal[] = { 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1B };\r
-\r
- // Get size of Text to send\r
- do {\r
- LenText++;\r
- } while(text[LenText] != '\0');\r
-\r
- // Calculate packetsize\r
- overallsize = sizeof(BasicLocal) + LenText + 1;\r
-\r
- if(debugOut == true)\r
- Console->Print("Whole size: %d", overallsize);\r
-\r
- LocalChatPacket = new char [overallsize];\r
-\r
- // Copy basic packet into final packet\r
- int fpp = 0;\r
- for(unsigned int c = 0; c < sizeof(BasicLocal); c++) {\r
- LocalChatPacket[fpp] = BasicLocal[c];\r
- fpp++;\r
- }\r
-\r
- // Copy Text into final packet\r
- for(int e = 0; e < LenText; e++) {\r
- LocalChatPacket[fpp] = text[e];\r
- fpp++;\r
- }\r
-\r
- // Terminate string\r
- LocalChatPacket[fpp] = 0x00;\r
-\r
- // Add UdpID, SessionID, lenght and local charid\r
- receiver->IncreaseUDP_ID();\r
- *(uint16_t*)&LocalChatPacket[1] = receiver->GetUDP_ID(); // UDP\r
- *(uint16_t*)&LocalChatPacket[3] = receiver->GetSessionID(); // Session\r
- *(uint8_t*)&LocalChatPacket[5] = overallsize - 6; // Packetlen\r
- *(uint16_t*)&LocalChatPacket[7] = receiver->GetUDP_ID(); // 2nd UDP\r
- *(uint16_t*)&LocalChatPacket[10] = author->GetLocalID(); // Local ID\r
-\r
- // Sending local chat packet and removing dynamic array\r
- ConnectionUDP *Socket = receiver->getUDPConn();\r
- Socket->write(LocalChatPacket, overallsize);\r
- Socket->flushSendBuffer();\r
- delete[] LocalChatPacket;\r
-}\r
-\r
-void PChat::sendTradeCS(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_TRADECS) == true)\r
- send(receiver, CHAT_TRADECS, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendTradeMB(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_TRADEMB) == true)\r
- send(receiver, CHAT_TRADEMB, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendTradeNC(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_TRADENC) == true)\r
- send(receiver, CHAT_TRADENC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendTradeTH(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_TRADETH) == true)\r
- send(receiver, CHAT_TRADETH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendTradeWL(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_TRADEWL) == true)\r
- send(receiver, CHAT_TRADEWL, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendOOC(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_OOC) == true)\r
- send(receiver, CHAT_OOC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendHelp(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_HELP) == true)\r
- send(receiver, CHAT_HELP, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendClanSearch(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_CLANSEARCH) == true)\r
- send(receiver, CHAT_CLANSEARCH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendServicesCS(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_SERVICECS) == true)\r
- send(receiver, CHAT_SERVICECS, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendServicesMB(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_SERVICEMB) == true)\r
- send(receiver, CHAT_SERVICESMB, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendServicesNC(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_SERVICENC) == true)\r
- send(receiver, CHAT_SERVICESNC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendServicesTH(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_SERVICETH) == true)\r
- send(receiver, CHAT_SERVICESTH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendServicesWL(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_SERVICEWL) == true)\r
- send(receiver, CHAT_SERVICESWL, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendTeam10(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_TEAM10) == true)\r
- send(receiver, CHAT_TEAM10, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendTeam30(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_TEAM30) == true)\r
- send(receiver, CHAT_TEAM30, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendTeam50(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_TEAM50) == true)\r
- send(receiver, CHAT_TEAM50, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PChat::sendTeam70(PClient* author, const char* text, bool debugOut)\r
-{\r
- for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)\r
- {\r
- if(author != it->second) // if its not the client, that send the message to the server\r
- {\r
- if(it->second) // only send if the client is existing!\r
- {\r
- PClient* receiver = it->second;\r
- if(chanEnabled(receiver, C_TEAM70) == true)\r
- send(receiver, CHAT_TEAM70, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);\r
- }\r
- }\r
- }\r
-}\r
-\r
-bool PChat::chanEnabled(PClient* Client, uint32_t channel)\r
-{\r
- // Check if player has target channel enabled or disabled\r
- PChar* TargetChar = Chars->GetChar(Client->GetCharID());\r
- if(!TargetChar)\r
- return false;\r
- \r
- uint32_t actChans = TargetChar->GetActiveChannels();\r
- uint32_t check = actChans & channel;\r
-\r
- if(check == channel)\r
- return true;\r
- else\r
- return false;\r
-}\r
-\r
-bool PChat::send(PClient* receiver, const uint8_t* Channel, const char* AuthorNickName, const char* text, bool debugOut)\r
-{\r
- char *ChatPacket;\r
- unsigned int packetsize = 0, c;\r
- int LenText, LenNick, fpp, d, e, loopout;\r
- uint8_t TargetChannel[2];\r
-\r
-//Console->Print("1: %#x", Channel[0]);\r
-//Console->Print("2: %#x", CHAT_BUDDY[0]);\r
-\r
-\r
- if(cmpr(Channel, CHAT_BUDDY) == true) {\r
- TargetChannel[0] = CHAT_BUDDY[0];\r
- TargetChannel[1] = CHAT_BUDDY[1];\r
- } else if(cmpr(Channel, CHAT_LOCAL) == true) {\r
- TargetChannel[0] = CHAT_LOCAL[0];\r
- TargetChannel[1] = CHAT_LOCAL[1];\r
- } else if(cmpr(Channel, CHAT_CLAN) == true) {\r
- TargetChannel[0] = CHAT_CLAN[0];\r
- TargetChannel[1] = CHAT_CLAN[1];\r
- } else if(cmpr(Channel, CHAT_TEAM) == true) {\r
- TargetChannel[0] = CHAT_TEAM[0];\r
- TargetChannel[1] = CHAT_TEAM[1];\r
- } else if(cmpr(Channel, CHAT_DIRECT) == true) {\r
- TargetChannel[0] = CHAT_DIRECT[0];\r
- TargetChannel[1] = CHAT_DIRECT[1];\r
- } else if(cmpr(Channel, CHAT_ZONE) == true) {\r
- TargetChannel[0] = CHAT_ZONE[0];\r
- TargetChannel[1] = CHAT_ZONE[1];\r
- } else if(cmpr(Channel, CHAT_FRAK) == true) {\r
- TargetChannel[0] = CHAT_FRAK[0];\r
- TargetChannel[1] = CHAT_FRAK[1];\r
- } else if(cmpr(Channel, CHAT_TRADECS) == true) {\r
- TargetChannel[0] = CHAT_TRADECS[0];\r
- TargetChannel[1] = CHAT_TRADECS[1];\r
- } else if(cmpr(Channel, CHAT_TRADEMB) == true) {\r
- TargetChannel[0] = CHAT_TRADEMB[0];\r
- TargetChannel[1] = CHAT_TRADEMB[1];\r
- } else if(cmpr(Channel, CHAT_TRADENC) == true) {\r
- TargetChannel[0] = CHAT_TRADENC[0];\r
- TargetChannel[1] = CHAT_TRADENC[1];\r
- } else if(cmpr(Channel, CHAT_TRADETH) == true) {\r
- TargetChannel[0] = CHAT_TRADETH[0];\r
- TargetChannel[1] = CHAT_TRADETH[1];\r
- } else if(cmpr(Channel, CHAT_TRADEWL) == true) {\r
- TargetChannel[0] = CHAT_TRADEWL[0];\r
- TargetChannel[1] = CHAT_TRADEWL[1];\r
- } else if(cmpr(Channel, CHAT_OOC) == true) {\r
- TargetChannel[0] = CHAT_OOC[0];\r
- TargetChannel[1] = CHAT_OOC[1];\r
- } else if(cmpr(Channel, CHAT_HELP) == true) {\r
- TargetChannel[0] = CHAT_HELP[0];\r
- TargetChannel[1] = CHAT_HELP[1];\r
- } else if(cmpr(Channel, CHAT_CLANSEARCH) == true) {\r
- TargetChannel[0] = CHAT_CLANSEARCH[0];\r
- TargetChannel[1] = CHAT_CLANSEARCH[1];\r
- } else if(cmpr(Channel, CHAT_SERVICECS) == true) {\r
- TargetChannel[0] = CHAT_SERVICECS[0];\r
- TargetChannel[1] = CHAT_SERVICECS[1];\r
- } else if(cmpr(Channel, CHAT_SERVICESMB) == true) {\r
- TargetChannel[0] = CHAT_SERVICESMB[0];\r
- TargetChannel[1] = CHAT_SERVICESMB[1];\r
- } else if(cmpr(Channel, CHAT_SERVICESNC) == true) {\r
- TargetChannel[0] = CHAT_SERVICESNC[0];\r
- TargetChannel[1] = CHAT_SERVICESNC[1];\r
- } else if(cmpr(Channel, CHAT_SERVICESTH) == true) {\r
- TargetChannel[0] = CHAT_SERVICESTH[0];\r
- TargetChannel[1] = CHAT_SERVICESTH[1];\r
- } else if(cmpr(Channel, CHAT_SERVICESWL) == true) {\r
- TargetChannel[0] = CHAT_SERVICESWL[0];\r
- TargetChannel[1] = CHAT_SERVICESWL[1];\r
- } else if(cmpr(Channel, CHAT_TEAM10) == true) {\r
- TargetChannel[0] = CHAT_TEAM10[0];\r
- TargetChannel[1] = CHAT_TEAM10[1];\r
- } else if(cmpr(Channel, CHAT_TEAM30) == true) {\r
- TargetChannel[0] = CHAT_TEAM30[0];\r
- TargetChannel[1] = CHAT_TEAM30[1];\r
- } else if(cmpr(Channel, CHAT_TEAM50) == true) {\r
- TargetChannel[0] = CHAT_TEAM50[0];\r
- TargetChannel[1] = CHAT_TEAM50[1];\r
- } else if(cmpr(Channel, CHAT_TEAM70) == true) {\r
- TargetChannel[0] = CHAT_TEAM70[0];\r
- TargetChannel[1] = CHAT_TEAM70[1];\r
- } else if(cmpr(Channel, CHAT_ADMIN) == true) {\r
- TargetChannel[0] = CHAT_ADMIN[0];\r
- TargetChannel[1] = CHAT_ADMIN[1];\r
- } else if(cmpr(Channel, CHAT_GMADMIN) == true) {\r
- TargetChannel[0] = CHAT_GMADMIN[0];\r
- TargetChannel[1] = CHAT_GMADMIN[1];\r
- } else if(cmpr(Channel, CHAT_GM) == true) {\r
- TargetChannel[0] = CHAT_GM[0];\r
- TargetChannel[1] = CHAT_GM[1];\r
- } else {\r
- Console->Print("SendChat error: Channel %#x unknown", Channel);\r
- return false;\r
- }\r
-\r
- ConnectionTCP *Socket = receiver->getTCPConn();\r
-\r
- uint8_t BasicChatPacket[] = {0xFE, 0x15, 0x00, 0x83, 0x17, 0x90, 0x03, 0x00, 0x00, 0x07, 0x05, 0x0F};\r
-\r
- LenText = LenNick = fpp = 0;\r
-\r
- do {\r
- LenText++;\r
- } while(text[LenText] != '\0');\r
-\r
- do {\r
- LenNick++;\r
- } while(AuthorNickName[LenNick] != '\0');\r
-\r
- if(LenText == 0 || LenNick == 0) {\r
- Console->Print("Error in SendChat, nickname or text is missing");\r
- return false;\r
- }\r
-\r
- loopout = 0;\r
-\r
- packetsize = sizeof(BasicChatPacket) + LenText + LenNick;\r
-\r
- if(debugOut == true) {\r
- Console->Print("Sizeof(TextToSend): %d || Sizeof(Nick): %d", LenText, LenNick);\r
- Console->Print("Whole size: %d", packetsize);\r
- }\r
-\r
- ChatPacket = new char [packetsize];\r
-\r
- // Copy basic packet into final packet\r
- for(c=0;c<sizeof(BasicChatPacket);c++) {\r
- ChatPacket[fpp] = BasicChatPacket[c];\r
- fpp++;\r
- }\r
-\r
- // Copy Nickname into final packet\r
- for(d=0;d<LenNick;d++) {\r
- ChatPacket[fpp] = AuthorNickName[d];\r
- fpp++;\r
- }\r
-\r
- // Copy Text into final packet\r
- for(e=0;e<LenText;e++) {\r
- ChatPacket[fpp] = text[e];\r
- fpp++;\r
- }\r
-\r
- // Change Lenght bytes in final packet\r
- ChatPacket[1] = packetsize - 3;\r
- ChatPacket[9] = LenNick;\r
- ChatPacket[10] = TargetChannel[0];\r
- ChatPacket[11] = TargetChannel[1];\r
-\r
- if(debugOut == true) {\r
- unsigned int debugout;\r
- for(debugout=0;debugout<packetsize;debugout++) {\r
- Console->Print("Byte %d: %#x", debugout, ChatPacket[debugout]);\r
- }\r
- }\r
-\r
- // Sending direct chat packet and removing dynamic array\r
- Socket->write(ChatPacket, packetsize);\r
- Socket->flushSendBuffer();\r
- delete[] ChatPacket;\r
-\r
- return true;\r
-}\r
-\r
-\r
-\r
-bool PChat::HandleGameChat(PClient *Client, const uint8_t *Packet)\r
-{\r
- // if player is shunned, ignore all incomming chat and game commands.\r
- // ServerAdmins are not affected by any shuns. (Should never happen anyways...)\r
- if((Client->GetChar()->IsShunned() == true) && (Client->GetAccountLevel() < PAL_ADMIN)) return true;\r
-\r
- int i, j, k;\r
-\r
- uint8_t chattype = *(uint8_t*)&Packet[7];\r
-// -----------------------------------------------\r
- if(chattype == 0x1B) {\r
- // Local chat\r
- i = 8;\r
- j = 0;\r
-\r
- char ChatText[255];\r
-\r
- do {\r
- ChatText[j] = Packet[i];\r
- i++;\r
- j++;\r
- } while (ChatText[j-1] != 0x00);\r
-\r
- ChatText[j] = '\0';\r
- if(ChatText[0] == '@' && sizeof(ChatText) > 2) {\r
- GameCommands->HandleGameCommand(ChatText, Client);\r
- } else {\r
- // We know its working, so we dont need console output anymore\r
- //Console->Print("Local Chat: %s", ChatText);\r
- //Console->Print("Client CharName is: %s", Chars->GetChar(Client->GetCharID())->GetName().c_str());\r
- sendLocal(Client, ChatText, false);\r
- }\r
-\r
-// -----------------------------------------------\r
- } else if (chattype == 0x3B) {\r
- // Non-Local chat\r
- i = 13;\r
- j = 0;\r
- k = 0;\r
-\r
- char ChatText[255];\r
-\r
- do {\r
- ChatText[j] = Packet[i];\r
- i++;\r
- j++;\r
- } while (ChatText[j-1] != 0x00);\r
-\r
-\r
- ChatText[j] = '\0';\r
- if(ChatText[0] == '@' && sizeof(ChatText) > 2) {\r
- GameCommands->HandleGameCommand(ChatText, Client);\r
- } else {\r
- // Console->Print("CHATLINE: %s HEX: %#X", ChatText, Packet[i-1]);\r
- char Channel[4];\r
-\r
- for(k = 0; k <= 3; k ++) {\r
- Channel[k] = Packet[k+8];\r
- }\r
- // Console->Print("Channel no %#x %#x %#x %#x", Channel[0], Channel[1], Channel[2], Channel[3]);\r
-\r
- // First, check if packet is a direct-chat-packet\r
- if(*(uint8_t*)&Packet[8] == 0x04) {\r
- //Console->Print("Direct Chat: %s", ChatText);\r
- sendPlayerDirect(Client, ChatText, *(uint32_t*)&Packet[9], false);\r
- //sendDirect(Client, ChatText, false);\r
- // "DIRECT> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_BUDDY) {\r
- //Console->Print("Buddy Chat: %s", ChatText);\r
- sendBuddy(Client, ChatText, false);\r
- // "BUDDY> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CLAN) {\r
- //Console->Print("Clan Chat: %s", ChatText);\r
- sendClan(Client, ChatText, false);\r
- // "CLAN> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_TEAM) {\r
- //Console->Print("Team Chat: %s", ChatText);\r
- sendTeam(Client, ChatText, false);\r
- // "TEAM> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_ZONE) {\r
- //Console->Print("Custom - Zone Chat: %s", ChatText);\r
- sendZone(Client, ChatText, false);\r
- // "ZONE> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_FRAKTION) {\r
- //Console->Print("Custom - Fraktion Chat: %s", ChatText);\r
- sendFrak(Client, ChatText, false);\r
- // "FRACTION> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_CANYON) {\r
- //Console->Print("Custom - Trade_Canyon Chat: %s", ChatText);\r
- sendTradeCS(Client, ChatText, false);\r
- // "TRADE - CS> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_MB) {\r
- //Console->Print("Custom - Trade_MB Chat: %s", ChatText);\r
- sendTradeMB(Client, ChatText, false);\r
- // "TRADE - MB> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_NC) {\r
- //Console->Print("Custom - Trade_NC Chat: %s", ChatText);\r
- sendTradeNC(Client, ChatText, false);\r
- // "TRADE - NC> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_TH) {\r
- //Console->Print("Custom - Trade_TH Chat: %s", ChatText);\r
- sendTradeTH(Client, ChatText, false);\r
- // "TRADE - TH> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_WASTE) {\r
- //Console->Print("Custom - Trade_Waste Chat: %s", ChatText);\r
- sendTradeWL(Client, ChatText, false);\r
- // "TRADE - WL> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_OOC) {\r
- //Console->Print("Custom - OOC Chat: %s", ChatText);\r
- sendOOC(Client, ChatText, false);\r
- // "OOC> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_PLAYERHELP) {\r
- //Console->Print("Custom - PlayerToPlayerhelp Chat: %s", ChatText);\r
- sendHelp(Client, ChatText, false);\r
- // "HELP> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_CLANSEARCH) {\r
- //Console->Print("Custom - Clansearch Chat: %s", ChatText);\r
- sendClanSearch(Client, ChatText, false);\r
- // "CLANSEARCH> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_CANYON) {\r
- //Console->Print("Custom - Services_Canyon Chat: %s", ChatText);\r
- sendServicesCS(Client, ChatText, false);\r
- // "SKILL - CS> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_MB) {\r
- //Console->Print("Custom - Services_MB Chat: %s", ChatText);\r
- sendServicesMB(Client, ChatText, false);\r
- // "SKILL - MB> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_NC) {\r
- //Console->Print("Custom - Services_NC Chat: %s", ChatText);\r
- sendServicesNC(Client, ChatText, false);\r
- // "SKILL - NC> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_TH) {\r
- //Console->Print("Custom - Services_TH Chat: %s", ChatText);\r
- sendServicesTH(Client, ChatText, false);\r
- // "SKILL - TH> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_WASTE) {\r
- //Console->Print("Custom - Services_Waste Chat: %s", ChatText);\r
- sendServicesWL(Client, ChatText, false);\r
- // "SKILL - WL> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_10) {\r
- //Console->Print("Custom - Team10 Chat: %s", ChatText);\r
- sendTeam10(Client, ChatText, false);\r
- // "TEAMSEARCH 10> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_30) {\r
- //Console->Print("Custom - Team30 Chat: %s", ChatText);\r
- sendTeam30(Client, ChatText, false);\r
- // "EAMSEARCH 30> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_50) {\r
- //Console->Print("Custom - Team50 Chat: %s", ChatText);\r
- sendTeam50(Client, ChatText, false);\r
- // "EAMSEARCH 50> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_70) {\r
- //Console->Print("Custom - Team70 Chat: %s", ChatText);\r
- sendTeam70(Client, ChatText, false);\r
- // "EAMSEARCH 70> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_ADMIN) {\r
- //Console->Print("Admin Chat: %s", ChatText);\r
- sendAdmin(Client, ChatText, false);\r
- // "ADMIN> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_GMADMIN) {\r
- //Console->Print("Admin Chat: %s", ChatText);\r
- sendGMAdmin(Client, ChatText, false);\r
- // "ADMIN> %s: %s", PlayerName, ChatText\r
- }\r
- else if(*(uint32_t*)Channel == CHANNEL_GMCHAT) {\r
- //Console->Print("GameMaster Chat: %s", ChatText);\r
- sendGM(Client, ChatText, false);\r
- // "GM> %s: %s", PlayerName, ChatText\r
- }\r
- else {\r
- Console->Print("Unknown Chat-Channel: %#x", *(uint32_t*)Channel);\r
- };\r
- }\r
-}\r
-return (true);\r
-}\r
-\r
-bool PChat::cmpr(const uint8_t *Array1, const uint8_t *Array2) {\r
- if(Array1[0] == Array2[0] && Array1[1] == Array2[1]) {\r
- return true;\r
- } else {\r
- return false;\r
- }\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+// TODO:- Add "hooks" to process chatevents everywhere in the source <-- kind of done. you can use the global PChat Instance.
+// Check:
+// Chat->send(PClient* receiver, const uint8_t* Channel, const char* AuthorNickName, char* text, bool debugOut=false);
+// Example:
+// Chat->send(receiverClient, CHAT_DIRECT, Chars->GetChar(authorClient->GetCharID())->GetName().c_str(), text);
+
+PChat::PChat()
+{
+}
+
+PChat::~PChat()
+{
+}
+
+/*
+DONE void sendBuddy(PClient* author, char* text, bool debugOut=false);
+DONE void sendLocal(PClient* author, char* text, bool debugOut=false);
+NEED CLANDATA void sendClan(PClient* author, char* text, bool debugOut=false);
+NEED TEAMDATA void sendTeam(PClient* author, char* text, bool debugOut=false);
+DONE void sendDirect(PClient* author, PClient* receiver, char* text, bool debugOut=false);
+DONE void sendZone(PClient* author, char* text, bool debugOut=false);
+DONE void sendFrak(PClient* author, char* text, bool debugOut=false);
+DONE void sendTradeCS(PClient* author, char* text, bool debugOut=false);
+DONE void sendTradeMB(PClient* author, char* text, bool debugOut=false);
+DONE void sendTradeNC(PClient* author, char* text, bool debugOut=false);
+DONE void sendTradeTH(PClient* author, char* text, bool debugOut=false);
+DONE void sendTradeWL(PClient* author, char* text, bool debugOut=false);
+DONE void sendOOC(PClient* author, char* text, bool debugOut=false);
+DONE void sendHelp(PClient* author, char* text, bool debugOut=false);
+DONE void sendClanSearch(PClient* author, char* text, bool debugOut=false);
+DONE void sendServicesCS(PClient* author, char* text, bool debugOut=false);
+DONE void sendServicesMB(PClient* author, char* text, bool debugOut=false);
+DONE void sendServicesNC(PClient* author, char* text, bool debugOut=false);
+DONE void sendServicesTH(PClient* author, char* text, bool debugOut=false);
+DONE void sendServicesWL(PClient* author, char* text, bool debugOut=false);
+DONE void sendTeam10(PClient* author, char* text, bool debugOut=false);
+DONE void sendTeam30(PClient* author, char* text, bool debugOut=false);
+DONE void sendTeam50(PClient* author, char* text, bool debugOut=false);
+DONE void sendTeam70(PClient* author, char* text, bool debugOut=false);
+DONE void sendAdmin(PClient* author, char* text, bool debugOut=false);
+DONE void sendGM(PClient* author, char* text, bool debugOut=false);
+*/
+
+
+void PChat::sendBuddy(PClient* author, const char* text, bool debugOut)
+{
+ PChar* authorChar = Chars->GetChar(author->GetCharID());
+ // send the message to all Buddys in list
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second && authorChar->IsBuddy(it->second->GetCharID()) == true)
+ {
+ PClient* receiver = it->second;
+ //Console->Print("DEBUG: Buddychat - Sending msg to %s", Chars->GetChar(receiver->GetCharID())->GetName().c_str());
+ send(receiver, CHAT_BUDDY, authorChar->GetName().c_str(), text, debugOut);
+ }
+ }
+}
+
+void PChat::sendConnectedList(PClient* receiver, bool debugOut)
+{
+ const char* text = "Connected Players are:]";
+ send(receiver, CHAT_DIRECT, "[System", text, debugOut);
+
+ int counter = 1;
+
+ // send the list of currently connected players to receiver
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ char counterText[5];
+ snprintf(counterText, 5, "%d", counter);
+
+ PChar* receiverChar = Chars->GetChar(it->second->GetCharID());
+ send(receiver, CHAT_DIRECT, (receiverChar ? receiverChar->GetName().c_str() : "*"), counterText, debugOut);
+
+ counter++;
+ }
+}
+
+
+void PChat::sendFrak(PClient* author, const char* text, bool debugOut)
+{
+ // send the message to all clients that have same FactionID
+ PChar* authorChar = Chars->GetChar(author->GetCharID());
+ uint32_t FID = authorChar->GetFaction(); // get LocationID of author
+
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ PClient* receiver = it->second;
+ PChar* receiverChar = Chars->GetChar(receiver->GetCharID());
+ if(receiverChar && (receiverChar->GetFaction() == FID))
+ {
+ if(chanEnabled(receiver, C_FRAK) == true)
+ send(receiver, CHAT_FRAK, authorChar->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendZone(PClient* author, const char* text, bool debugOut)
+{
+ // send the message to all clients that have same ZoneID
+ PChar* authorChar = Chars->GetChar(author->GetCharID());
+ uint32_t ZID = authorChar->GetLocation(); // get LocationID of author
+
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ PClient* receiver = it->second;
+ PChar* receiverChar = Chars->GetChar(receiver->GetCharID());
+ if(receiverChar && (receiverChar->GetLocation() == ZID))
+ {
+ if(chanEnabled(receiver, C_ZONE) == true)
+ send(receiver, CHAT_ZONE, authorChar->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendLocal(PClient* author, const char* text, bool debugOut)
+{
+ PChar* authorChar = Chars->GetChar(author->GetCharID());
+ uint32_t ZID = authorChar->GetLocation(); // get LocationID of author
+
+ // send the message to all clients that are in Area (Radius = X (needs to be defined somewhere!))
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ PClient* receiver = it->second;
+ PChar* receiverChar = Chars->GetChar(receiver->GetCharID());
+ if(receiverChar && (receiverChar->GetLocation() == ZID))
+ {
+ uint16_t distance = DistanceApprox((authorChar->Coords).mX, (authorChar->Coords).mY, (authorChar->Coords).mZ, (receiverChar->Coords).mX, (receiverChar->Coords).mY, (receiverChar->Coords).mZ);
+ if(distance < LOCALCHAT_MAXDISTANCE)
+ {
+ //sendLocalchat(receiver, author, text, debugOut); // Doesnt work!
+ send(receiver, CHAT_LOCAL, authorChar->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+ }
+}
+
+void PChat::sendGM(PClient* author, const char* text, bool debugOut)
+{
+ if(author->GetAccountLevel() >= PAL_GM) // Only send GM> chat when user is an Gamemaster or higher
+ {
+ // send the message to all GameMasters.
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(receiver->GetAccountLevel() >= PAL_GM) // Only send GM chat if RECEIVER is GM or higher
+ send(receiver, CHAT_GM, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+ }
+}
+
+void PChat::sendGMAdmin(PClient* author, const char* text, bool debugOut)
+{
+ if(author->GetAccountLevel() >= PAL_GM) // Only send GM> chat when user is an Gamemaster or higher
+ {
+ // send the message to ALL users online
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ send(receiver, CHAT_GMADMIN, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+ }
+}
+
+void PChat::sendAdmin(PClient* author, const char* text, bool debugOut)
+{
+ if(author->GetAccountLevel() >= PAL_ADMIN) // Only send ADMIN> chat when user is an serveradmin
+ {
+ // send the message to ALL users online
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ send(receiver, CHAT_ADMIN, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+ }
+}
+
+void PChat::sendBroadcast(const char* text, bool debugOut)
+{
+ // send the message to ALL users online
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ send(receiver, CHAT_ADMIN, "Server", text, debugOut);
+ }
+ }
+}
+
+void PChat::sendOOCBroadcast(const char* text, bool debugOut)
+{
+ // send the message to ALL users online
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_OOC) == true)
+ send(receiver, CHAT_OOC, "Server", text, debugOut);
+ }
+ }
+}
+
+void PChat::sendClan(PClient* author, const char* text, bool debugOut)
+{
+ /**
+ NOT ABLE TO IMPLEMENT THIS CHATTYPE YET, ITS SUPERGLOBAL TILL THEN
+ **/
+ // send the message to all clients that have same ClanID
+ PChar* authorChar = Chars->GetChar(author->GetCharID());
+
+// int ClanID = authorChar->getClanID(); // get clanID of author
+
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second)
+ {
+ PClient* receiver = it->second;
+ PChar* receiverChar = Chars->GetChar(receiver->GetCharID());
+ if(receiverChar /*&& (receiverChar->getClanID() == ClanID)*/)
+ {
+ send(receiver, CHAT_CLAN, authorChar->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+
+}
+
+void PChat::sendTeam(PClient* author, const char* text, bool debugOut)
+{
+ /**
+ NOT ABLE TO IMPLEMENT THIS CHATTYPE YET, ITS SUPERGLOBAL TILL THEN
+ **/
+ // send the message to all clients that have same TeamID
+
+ PChar* authorChar = Chars->GetChar(author->GetCharID());
+
+ //int TeamID = authorChar->getTeamID(); // get TeamID of author
+
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second)
+ {
+ PClient* receiver = it->second;
+ PChar* receiverChar = Chars->GetChar(receiver->GetCharID());
+ if(receiverChar /*&& (receiverChar->getTeamID() == TeamID)*/)
+ {
+ send(receiver, CHAT_TEAM, authorChar->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendPlayerDirect(PClient* author, const char* text, uint32_t destination, bool debugOut)
+{
+ bool tmpTargetOnline = false;
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ PClient* receiver = it->second;
+ PChar* receiverChar = Chars->GetChar(receiver->GetCharID());
+ if(receiverChar && (receiver->GetCharID() == destination))
+ {
+ tmpTargetOnline = true;
+ sendDirect(author, receiver, text, debugOut);
+ }
+ }
+ if(tmpTargetOnline == false)
+ {
+ ConnectionTCP *Socket = author->getTCPConn();
+ uint8_t DirectTargetNotOnline[] = {0xFE, 0x07, 0x00, 0x83, 0x18, 0x01, 0x81, 0x54, 0x00, 0x00};
+
+ Socket->write(DirectTargetNotOnline, sizeof(DirectTargetNotOnline));
+ Socket->flushSendBuffer();
+ }
+
+ if(debugOut == true)
+ {
+ if(tmpTargetOnline == false)
+ Console->Print("[DEBUG] Requested target CharID %d is not online", destination);
+ else
+ Console->Print("[DEBUG] CharID %d found and message transmitted!", destination);
+ }
+}
+
+void PChat::sendDirect(PClient* author, PClient* receiver, const char* text, bool debugOut)
+{
+ PChar* authorChar = Chars->GetChar(author->GetCharID());
+
+ char *DChatPacket;
+ unsigned int packetsize = 0, c;
+ int LenText, LenNick, fpp, d, e, loopout;
+
+ ConnectionTCP *Socket = receiver->getTCPConn();
+
+ uint8_t BasicDirectPacket[] = {0xFE, 0x20, 0x00, 0x83, 0x17, 0xB7, 0x5F, 0x00, 0x00, 0x0C, 0x04, 0x00};
+
+ LenText = LenNick = fpp = 0;
+
+ do {
+ LenText++;
+ } while(text[LenText] != '\0');
+
+ do {
+ LenNick++;
+ } while(authorChar->GetName().c_str()[LenNick] != '\0');
+
+ loopout = 0;
+
+ packetsize = sizeof(BasicDirectPacket) + LenText + LenNick;
+
+ if(debugOut == true) {
+ Console->Print("Sizeof(TextToSend): %d || Sizeof(Nick): %d", LenText, LenNick);
+ Console->Print("Whole size: %d", packetsize);
+ }
+
+ DChatPacket = new char [packetsize];
+
+ // Copy basic packet into final packet
+ for(c=0;c<sizeof(BasicDirectPacket);c++) {
+ DChatPacket[fpp] = BasicDirectPacket[c];
+ fpp++;
+ }
+
+ // Copy Nickname into final packet
+ for(d=0;d<LenNick;d++) {
+ DChatPacket[fpp] = authorChar->GetName().c_str()[d];
+ fpp++;
+ }
+
+ // Copy Text into final packet
+ for(e=0;e<LenText;e++) {
+ DChatPacket[fpp] = text[e];
+ fpp++;
+ }
+
+ // Change Lenght bytes in final packet
+ DChatPacket[1] = packetsize - 3;
+ DChatPacket[9] = LenNick;
+
+ if(debugOut == true) {
+ unsigned int debugout;
+ for(debugout=0;debugout<packetsize;debugout++) {
+ Console->Print("Byte %d: %#x", debugout, DChatPacket[debugout]);
+ }
+ }
+
+ // Sending direct chat packet and removing dynamic array
+ Socket->write(DChatPacket, packetsize);
+ Socket->flushSendBuffer();
+ delete[] DChatPacket;
+}
+
+void PChat::sendLocalchat(PClient* receiver, PClient* author, const char* text, bool debugOut)
+{
+ return; // IncreaseUDP could cause OOO here. Since this function is doing nothing, we disabled it
+ char *LocalChatPacket;
+ int overallsize = 0, LenText = 0;
+ uint8_t BasicLocal[] = { 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1B };
+
+ // Get size of Text to send
+ do {
+ LenText++;
+ } while(text[LenText] != '\0');
+
+ // Calculate packetsize
+ overallsize = sizeof(BasicLocal) + LenText + 1;
+
+ if(debugOut == true)
+ Console->Print("Whole size: %d", overallsize);
+
+ LocalChatPacket = new char [overallsize];
+
+ // Copy basic packet into final packet
+ int fpp = 0;
+ for(unsigned int c = 0; c < sizeof(BasicLocal); c++) {
+ LocalChatPacket[fpp] = BasicLocal[c];
+ fpp++;
+ }
+
+ // Copy Text into final packet
+ for(int e = 0; e < LenText; e++) {
+ LocalChatPacket[fpp] = text[e];
+ fpp++;
+ }
+
+ // Terminate string
+ LocalChatPacket[fpp] = 0x00;
+
+ // Add UdpID, SessionID, lenght and local charid
+ receiver->IncreaseUDP_ID();
+ *(uint16_t*)&LocalChatPacket[1] = receiver->GetUDP_ID(); // UDP
+ *(uint16_t*)&LocalChatPacket[3] = receiver->GetSessionID(); // Session
+ *(uint8_t*)&LocalChatPacket[5] = overallsize - 6; // Packetlen
+ *(uint16_t*)&LocalChatPacket[7] = receiver->GetUDP_ID(); // 2nd UDP
+ *(uint16_t*)&LocalChatPacket[10] = author->GetLocalID(); // Local ID
+
+ // Sending local chat packet and removing dynamic array
+ ConnectionUDP *Socket = receiver->getUDPConn();
+ Socket->write(LocalChatPacket, overallsize);
+ Socket->flushSendBuffer();
+ delete[] LocalChatPacket;
+}
+
+void PChat::sendTradeCS(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_TRADECS) == true)
+ send(receiver, CHAT_TRADECS, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendTradeMB(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_TRADEMB) == true)
+ send(receiver, CHAT_TRADEMB, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendTradeNC(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_TRADENC) == true)
+ send(receiver, CHAT_TRADENC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendTradeTH(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_TRADETH) == true)
+ send(receiver, CHAT_TRADETH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendTradeWL(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_TRADEWL) == true)
+ send(receiver, CHAT_TRADEWL, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendOOC(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_OOC) == true)
+ send(receiver, CHAT_OOC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendHelp(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_HELP) == true)
+ send(receiver, CHAT_HELP, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendClanSearch(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_CLANSEARCH) == true)
+ send(receiver, CHAT_CLANSEARCH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendServicesCS(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_SERVICECS) == true)
+ send(receiver, CHAT_SERVICECS, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendServicesMB(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_SERVICEMB) == true)
+ send(receiver, CHAT_SERVICESMB, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendServicesNC(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_SERVICENC) == true)
+ send(receiver, CHAT_SERVICESNC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendServicesTH(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_SERVICETH) == true)
+ send(receiver, CHAT_SERVICESTH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendServicesWL(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_SERVICEWL) == true)
+ send(receiver, CHAT_SERVICESWL, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendTeam10(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_TEAM10) == true)
+ send(receiver, CHAT_TEAM10, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendTeam30(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_TEAM30) == true)
+ send(receiver, CHAT_TEAM30, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendTeam50(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_TEAM50) == true)
+ send(receiver, CHAT_TEAM50, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+void PChat::sendTeam70(PClient* author, const char* text, bool debugOut)
+{
+ for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++)
+ {
+ if(author != it->second) // if its not the client, that send the message to the server
+ {
+ if(it->second) // only send if the client is existing!
+ {
+ PClient* receiver = it->second;
+ if(chanEnabled(receiver, C_TEAM70) == true)
+ send(receiver, CHAT_TEAM70, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut);
+ }
+ }
+ }
+}
+
+bool PChat::chanEnabled(PClient* Client, uint32_t channel)
+{
+ // Check if player has target channel enabled or disabled
+ PChar* TargetChar = Chars->GetChar(Client->GetCharID());
+ if(!TargetChar)
+ return false;
+
+ uint32_t actChans = TargetChar->GetActiveChannels();
+ uint32_t check = actChans & channel;
+
+ if(check == channel)
+ return true;
+ else
+ return false;
+}
+
+bool PChat::send(PClient* receiver, const uint8_t* Channel, const char* AuthorNickName, const char* text, bool debugOut)
+{
+ char *ChatPacket;
+ unsigned int packetsize = 0, c;
+ int LenText, LenNick, fpp, d, e, loopout;
+ uint8_t TargetChannel[2];
+
+//Console->Print("1: %#x", Channel[0]);
+//Console->Print("2: %#x", CHAT_BUDDY[0]);
+
+
+ if(cmpr(Channel, CHAT_BUDDY) == true) {
+ TargetChannel[0] = CHAT_BUDDY[0];
+ TargetChannel[1] = CHAT_BUDDY[1];
+ } else if(cmpr(Channel, CHAT_LOCAL) == true) {
+ TargetChannel[0] = CHAT_LOCAL[0];
+ TargetChannel[1] = CHAT_LOCAL[1];
+ } else if(cmpr(Channel, CHAT_CLAN) == true) {
+ TargetChannel[0] = CHAT_CLAN[0];
+ TargetChannel[1] = CHAT_CLAN[1];
+ } else if(cmpr(Channel, CHAT_TEAM) == true) {
+ TargetChannel[0] = CHAT_TEAM[0];
+ TargetChannel[1] = CHAT_TEAM[1];
+ } else if(cmpr(Channel, CHAT_DIRECT) == true) {
+ TargetChannel[0] = CHAT_DIRECT[0];
+ TargetChannel[1] = CHAT_DIRECT[1];
+ } else if(cmpr(Channel, CHAT_ZONE) == true) {
+ TargetChannel[0] = CHAT_ZONE[0];
+ TargetChannel[1] = CHAT_ZONE[1];
+ } else if(cmpr(Channel, CHAT_FRAK) == true) {
+ TargetChannel[0] = CHAT_FRAK[0];
+ TargetChannel[1] = CHAT_FRAK[1];
+ } else if(cmpr(Channel, CHAT_TRADECS) == true) {
+ TargetChannel[0] = CHAT_TRADECS[0];
+ TargetChannel[1] = CHAT_TRADECS[1];
+ } else if(cmpr(Channel, CHAT_TRADEMB) == true) {
+ TargetChannel[0] = CHAT_TRADEMB[0];
+ TargetChannel[1] = CHAT_TRADEMB[1];
+ } else if(cmpr(Channel, CHAT_TRADENC) == true) {
+ TargetChannel[0] = CHAT_TRADENC[0];
+ TargetChannel[1] = CHAT_TRADENC[1];
+ } else if(cmpr(Channel, CHAT_TRADETH) == true) {
+ TargetChannel[0] = CHAT_TRADETH[0];
+ TargetChannel[1] = CHAT_TRADETH[1];
+ } else if(cmpr(Channel, CHAT_TRADEWL) == true) {
+ TargetChannel[0] = CHAT_TRADEWL[0];
+ TargetChannel[1] = CHAT_TRADEWL[1];
+ } else if(cmpr(Channel, CHAT_OOC) == true) {
+ TargetChannel[0] = CHAT_OOC[0];
+ TargetChannel[1] = CHAT_OOC[1];
+ } else if(cmpr(Channel, CHAT_HELP) == true) {
+ TargetChannel[0] = CHAT_HELP[0];
+ TargetChannel[1] = CHAT_HELP[1];
+ } else if(cmpr(Channel, CHAT_CLANSEARCH) == true) {
+ TargetChannel[0] = CHAT_CLANSEARCH[0];
+ TargetChannel[1] = CHAT_CLANSEARCH[1];
+ } else if(cmpr(Channel, CHAT_SERVICECS) == true) {
+ TargetChannel[0] = CHAT_SERVICECS[0];
+ TargetChannel[1] = CHAT_SERVICECS[1];
+ } else if(cmpr(Channel, CHAT_SERVICESMB) == true) {
+ TargetChannel[0] = CHAT_SERVICESMB[0];
+ TargetChannel[1] = CHAT_SERVICESMB[1];
+ } else if(cmpr(Channel, CHAT_SERVICESNC) == true) {
+ TargetChannel[0] = CHAT_SERVICESNC[0];
+ TargetChannel[1] = CHAT_SERVICESNC[1];
+ } else if(cmpr(Channel, CHAT_SERVICESTH) == true) {
+ TargetChannel[0] = CHAT_SERVICESTH[0];
+ TargetChannel[1] = CHAT_SERVICESTH[1];
+ } else if(cmpr(Channel, CHAT_SERVICESWL) == true) {
+ TargetChannel[0] = CHAT_SERVICESWL[0];
+ TargetChannel[1] = CHAT_SERVICESWL[1];
+ } else if(cmpr(Channel, CHAT_TEAM10) == true) {
+ TargetChannel[0] = CHAT_TEAM10[0];
+ TargetChannel[1] = CHAT_TEAM10[1];
+ } else if(cmpr(Channel, CHAT_TEAM30) == true) {
+ TargetChannel[0] = CHAT_TEAM30[0];
+ TargetChannel[1] = CHAT_TEAM30[1];
+ } else if(cmpr(Channel, CHAT_TEAM50) == true) {
+ TargetChannel[0] = CHAT_TEAM50[0];
+ TargetChannel[1] = CHAT_TEAM50[1];
+ } else if(cmpr(Channel, CHAT_TEAM70) == true) {
+ TargetChannel[0] = CHAT_TEAM70[0];
+ TargetChannel[1] = CHAT_TEAM70[1];
+ } else if(cmpr(Channel, CHAT_ADMIN) == true) {
+ TargetChannel[0] = CHAT_ADMIN[0];
+ TargetChannel[1] = CHAT_ADMIN[1];
+ } else if(cmpr(Channel, CHAT_GMADMIN) == true) {
+ TargetChannel[0] = CHAT_GMADMIN[0];
+ TargetChannel[1] = CHAT_GMADMIN[1];
+ } else if(cmpr(Channel, CHAT_GM) == true) {
+ TargetChannel[0] = CHAT_GM[0];
+ TargetChannel[1] = CHAT_GM[1];
+ } else {
+ Console->Print("SendChat error: Channel %#x unknown", Channel);
+ return false;
+ }
+
+ ConnectionTCP *Socket = receiver->getTCPConn();
+
+ uint8_t BasicChatPacket[] = {0xFE, 0x15, 0x00, 0x83, 0x17, 0x90, 0x03, 0x00, 0x00, 0x07, 0x05, 0x0F};
+
+ LenText = LenNick = fpp = 0;
+
+ do {
+ LenText++;
+ } while(text[LenText] != '\0');
+
+ do {
+ LenNick++;
+ } while(AuthorNickName[LenNick] != '\0');
+
+ if(LenText == 0 || LenNick == 0) {
+ Console->Print("Error in SendChat, nickname or text is missing");
+ return false;
+ }
+
+ loopout = 0;
+
+ packetsize = sizeof(BasicChatPacket) + LenText + LenNick;
+
+ if(debugOut == true) {
+ Console->Print("Sizeof(TextToSend): %d || Sizeof(Nick): %d", LenText, LenNick);
+ Console->Print("Whole size: %d", packetsize);
+ }
+
+ ChatPacket = new char [packetsize];
+
+ // Copy basic packet into final packet
+ for(c=0;c<sizeof(BasicChatPacket);c++) {
+ ChatPacket[fpp] = BasicChatPacket[c];
+ fpp++;
+ }
+
+ // Copy Nickname into final packet
+ for(d=0;d<LenNick;d++) {
+ ChatPacket[fpp] = AuthorNickName[d];
+ fpp++;
+ }
+
+ // Copy Text into final packet
+ for(e=0;e<LenText;e++) {
+ ChatPacket[fpp] = text[e];
+ fpp++;
+ }
+
+ // Change Lenght bytes in final packet
+ ChatPacket[1] = packetsize - 3;
+ ChatPacket[9] = LenNick;
+ ChatPacket[10] = TargetChannel[0];
+ ChatPacket[11] = TargetChannel[1];
+
+ if(debugOut == true) {
+ unsigned int debugout;
+ for(debugout=0;debugout<packetsize;debugout++) {
+ Console->Print("Byte %d: %#x", debugout, ChatPacket[debugout]);
+ }
+ }
+
+ // Sending direct chat packet and removing dynamic array
+ Socket->write(ChatPacket, packetsize);
+ Socket->flushSendBuffer();
+ delete[] ChatPacket;
+
+ return true;
+}
+
+
+
+bool PChat::HandleGameChat(PClient *Client, const uint8_t *Packet)
+{
+ // if player is shunned, ignore all incomming chat and game commands.
+ // ServerAdmins are not affected by any shuns. (Should never happen anyways...)
+ if((Client->GetChar()->IsShunned() == true) && (Client->GetAccountLevel() < PAL_ADMIN)) return true;
+
+ int i, j, k;
+
+ uint8_t chattype = *(uint8_t*)&Packet[7];
+// -----------------------------------------------
+ if(chattype == 0x1B) {
+ // Local chat
+ i = 8;
+ j = 0;
+
+ char ChatText[255];
+
+ do {
+ ChatText[j] = Packet[i];
+ i++;
+ j++;
+ } while (ChatText[j-1] != 0x00);
+
+ ChatText[j] = '\0';
+ if(ChatText[0] == '@' && sizeof(ChatText) > 2) {
+ GameCommands->HandleGameCommand(ChatText, Client);
+ } else {
+ // We know its working, so we dont need console output anymore
+ //Console->Print("Local Chat: %s", ChatText);
+ //Console->Print("Client CharName is: %s", Chars->GetChar(Client->GetCharID())->GetName().c_str());
+ sendLocal(Client, ChatText, false);
+ }
+
+// -----------------------------------------------
+ } else if (chattype == 0x3B) {
+ // Non-Local chat
+ i = 13;
+ j = 0;
+ k = 0;
+
+ char ChatText[255];
+
+ do {
+ ChatText[j] = Packet[i];
+ i++;
+ j++;
+ } while (ChatText[j-1] != 0x00);
+
+
+ ChatText[j] = '\0';
+ if(ChatText[0] == '@' && sizeof(ChatText) > 2) {
+ GameCommands->HandleGameCommand(ChatText, Client);
+ } else {
+ // Console->Print("CHATLINE: %s HEX: %#X", ChatText, Packet[i-1]);
+ char Channel[4];
+
+ for(k = 0; k <= 3; k ++) {
+ Channel[k] = Packet[k+8];
+ }
+ // Console->Print("Channel no %#x %#x %#x %#x", Channel[0], Channel[1], Channel[2], Channel[3]);
+
+ // First, check if packet is a direct-chat-packet
+ if(*(uint8_t*)&Packet[8] == 0x04) {
+ //Console->Print("Direct Chat: %s", ChatText);
+ sendPlayerDirect(Client, ChatText, *(uint32_t*)&Packet[9], false);
+ //sendDirect(Client, ChatText, false);
+ // "DIRECT> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_BUDDY) {
+ //Console->Print("Buddy Chat: %s", ChatText);
+ sendBuddy(Client, ChatText, false);
+ // "BUDDY> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CLAN) {
+ //Console->Print("Clan Chat: %s", ChatText);
+ sendClan(Client, ChatText, false);
+ // "CLAN> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_TEAM) {
+ //Console->Print("Team Chat: %s", ChatText);
+ sendTeam(Client, ChatText, false);
+ // "TEAM> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_ZONE) {
+ //Console->Print("Custom - Zone Chat: %s", ChatText);
+ sendZone(Client, ChatText, false);
+ // "ZONE> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_FRAKTION) {
+ //Console->Print("Custom - Fraktion Chat: %s", ChatText);
+ sendFrak(Client, ChatText, false);
+ // "FRACTION> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_CANYON) {
+ //Console->Print("Custom - Trade_Canyon Chat: %s", ChatText);
+ sendTradeCS(Client, ChatText, false);
+ // "TRADE - CS> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_MB) {
+ //Console->Print("Custom - Trade_MB Chat: %s", ChatText);
+ sendTradeMB(Client, ChatText, false);
+ // "TRADE - MB> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_NC) {
+ //Console->Print("Custom - Trade_NC Chat: %s", ChatText);
+ sendTradeNC(Client, ChatText, false);
+ // "TRADE - NC> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_TH) {
+ //Console->Print("Custom - Trade_TH Chat: %s", ChatText);
+ sendTradeTH(Client, ChatText, false);
+ // "TRADE - TH> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_WASTE) {
+ //Console->Print("Custom - Trade_Waste Chat: %s", ChatText);
+ sendTradeWL(Client, ChatText, false);
+ // "TRADE - WL> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_OOC) {
+ //Console->Print("Custom - OOC Chat: %s", ChatText);
+ sendOOC(Client, ChatText, false);
+ // "OOC> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_PLAYERHELP) {
+ //Console->Print("Custom - PlayerToPlayerhelp Chat: %s", ChatText);
+ sendHelp(Client, ChatText, false);
+ // "HELP> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_CLANSEARCH) {
+ //Console->Print("Custom - Clansearch Chat: %s", ChatText);
+ sendClanSearch(Client, ChatText, false);
+ // "CLANSEARCH> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_CANYON) {
+ //Console->Print("Custom - Services_Canyon Chat: %s", ChatText);
+ sendServicesCS(Client, ChatText, false);
+ // "SKILL - CS> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_MB) {
+ //Console->Print("Custom - Services_MB Chat: %s", ChatText);
+ sendServicesMB(Client, ChatText, false);
+ // "SKILL - MB> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_NC) {
+ //Console->Print("Custom - Services_NC Chat: %s", ChatText);
+ sendServicesNC(Client, ChatText, false);
+ // "SKILL - NC> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_TH) {
+ //Console->Print("Custom - Services_TH Chat: %s", ChatText);
+ sendServicesTH(Client, ChatText, false);
+ // "SKILL - TH> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_WASTE) {
+ //Console->Print("Custom - Services_Waste Chat: %s", ChatText);
+ sendServicesWL(Client, ChatText, false);
+ // "SKILL - WL> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_10) {
+ //Console->Print("Custom - Team10 Chat: %s", ChatText);
+ sendTeam10(Client, ChatText, false);
+ // "TEAMSEARCH 10> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_30) {
+ //Console->Print("Custom - Team30 Chat: %s", ChatText);
+ sendTeam30(Client, ChatText, false);
+ // "EAMSEARCH 30> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_50) {
+ //Console->Print("Custom - Team50 Chat: %s", ChatText);
+ sendTeam50(Client, ChatText, false);
+ // "EAMSEARCH 50> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_70) {
+ //Console->Print("Custom - Team70 Chat: %s", ChatText);
+ sendTeam70(Client, ChatText, false);
+ // "EAMSEARCH 70> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_ADMIN) {
+ //Console->Print("Admin Chat: %s", ChatText);
+ sendAdmin(Client, ChatText, false);
+ // "ADMIN> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_GMADMIN) {
+ //Console->Print("Admin Chat: %s", ChatText);
+ sendGMAdmin(Client, ChatText, false);
+ // "ADMIN> %s: %s", PlayerName, ChatText
+ }
+ else if(*(uint32_t*)Channel == CHANNEL_GMCHAT) {
+ //Console->Print("GameMaster Chat: %s", ChatText);
+ sendGM(Client, ChatText, false);
+ // "GM> %s: %s", PlayerName, ChatText
+ }
+ else {
+ Console->Print("Unknown Chat-Channel: %#x", *(uint32_t*)Channel);
+ };
+ }
+}
+return (true);
+}
+
+bool PChat::cmpr(const uint8_t *Array1, const uint8_t *Array2) {
+ if(Array1[0] == Array2[0] && Array1[1] == Array2[1]) {
+ return true;
+ } else {
+ return false;
+ }
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-\r
-#define LOCALCHAT_MAXDISTANCE 1433\r
-\r
-class PClient;\r
-\r
-class PChat {\r
-public:\r
- PChat();\r
- ~PChat();\r
-\r
- // INCOMING CHAT\r
- bool HandleGameChat(PClient *Client, const uint8_t *Packet);\r
- bool cmpr(const uint8_t *Array1, const uint8_t *Array2);\r
-\r
- // this function is called by the other more specific functions and simply sends the data to the receiver-client\r
- bool send(PClient* receiver, const uint8_t* Channel, const char* AuthorNickName, const char* text, bool debugOut=false);\r
-\r
- // this is for debugging and sends the current connected playerlist to the receiver-client\r
- void sendConnectedList(PClient* receiver, bool debugOut=false);\r
-\r
- // specific channel functions:\r
- void sendBuddy(PClient* author, const char* text, bool debugOut=false);\r
- void sendLocal(PClient* author, const char* text, bool debugOut=false);\r
- void sendClan(PClient* author, const char* text, bool debugOut=false);\r
- void sendTeam(PClient* author, const char* text, bool debugOut=false);\r
- void sendDirect(PClient* author, PClient* receiver, const char* text, bool debugOut=false);\r
- void sendZone(PClient* author, const char* text, bool debugOut=false);\r
- void sendFrak(PClient* author, const char* text, bool debugOut=false);\r
- void sendTradeCS(PClient* author, const char* text, bool debugOut=false);\r
- void sendTradeMB(PClient* author, const char* text, bool debugOut=false);\r
- void sendTradeNC(PClient* author, const char* text, bool debugOut=false);\r
- void sendTradeTH(PClient* author, const char* text, bool debugOut=false);\r
- void sendTradeWL(PClient* author, const char* text, bool debugOut=false);\r
- void sendOOC(PClient* author, const char* text, bool debugOut=false);\r
- void sendHelp(PClient* author, const char* text, bool debugOut=false);\r
- void sendClanSearch(PClient* author, const char* text, bool debugOut=false);\r
- void sendServicesCS(PClient* author, const char* text, bool debugOut=false);\r
- void sendServicesMB(PClient* author, const char* text, bool debugOut=false);\r
- void sendServicesNC(PClient* author, const char* text, bool debugOut=false);\r
- void sendServicesTH(PClient* author, const char* text, bool debugOut=false);\r
- void sendServicesWL(PClient* author, const char* text, bool debugOut=false);\r
- void sendTeam10(PClient* author, const char* text, bool debugOut=false);\r
- void sendTeam30(PClient* author, const char* text, bool debugOut=false);\r
- void sendTeam50(PClient* author, const char* text, bool debugOut=false);\r
- void sendTeam70(PClient* author, const char* text, bool debugOut=false);\r
- void sendAdmin(PClient* author, const char* text, bool debugOut=false);\r
- void sendGM(PClient* author, const char* text, bool debugOut=false);\r
- void sendGMAdmin(PClient* author, const char* text, bool debugOut=false);\r
-\r
- void sendBroadcast(const char* text, bool debugOut=false);\r
- void sendOOCBroadcast(const char* text, bool debugOut=false);\r
- void sendPlayerDirect(PClient* author, const char* text, uint32_t destination, bool debugOut=false);\r
- void sendLocalchat(PClient* receiver, PClient* author, const char* text, bool debugOut=false);\r
- bool chanEnabled(PClient* Client, uint32_t channel);\r
-};\r
-\r
-/** A WARNING: DO >N O T< (!!!) CHANGE >ANY< OF THE FOLLOWING VARIABLES UNLESS YOU KNOW EXACT WHAT YOU'RE DOING! **/\r
-/** You can easily mess up the entire chat subsystem. If you're unsure, ask Namikon first! **/\r
-/*\r
-####################\r
- CHANNEL-CODES:\r
- (INCOMING)\r
-####################\r
-*/\r
-static const uint32_t CHANNEL_BUDDY = 0x00000000; // Buddy\r
-static const uint32_t CHANNEL_CLAN = 0x00000002; // Clan\r
-static const uint32_t CHANNEL_TEAM = 0x00000003; // Team\r
-static const uint32_t CHANNEL_DIRECT = 0xFFFFFFFF; // Direct UNKNOWN YET\r
-static const uint32_t CHANNEL_CUS_ZONE = 0x00000105; // Custom -> Zone\r
-static const uint32_t CHANNEL_CUS_FRAKTION = 0x00000205; // Custom -> Fraktion\r
-static const uint32_t CHANNEL_CUS_TRADE_CANYON = 0x00002005; // Custom -> Trade Canyon\r
-static const uint32_t CHANNEL_CUS_TRADE_MB = 0x00000805; // Custom -> Trade MB\r
-static const uint32_t CHANNEL_CUS_TRADE_NC = 0x00000405; // Custom -> Trade NC\r
-static const uint32_t CHANNEL_CUS_TRADE_TH = 0x00001005; // Custom -> Trade TH\r
-static const uint32_t CHANNEL_CUS_TRADE_WASTE = 0x00004005; // Custom -> Trade Wastelands\r
-static const uint32_t CHANNEL_CUS_OOC = 0x04000005; // Custom -> OOC\r
-static const uint32_t CHANNEL_CUS_PLAYERHELP = 0x02000005; // Custom -> Player 2 Player help\r
-static const uint32_t CHANNEL_CUS_CLANSEARCH = 0x01000005; // Custom -> Searching Clan\r
-static const uint32_t CHANNEL_CUS_SERVICES_CANYON = 0x00040005; // Custom -> Runner Services Canyon\r
-static const uint32_t CHANNEL_CUS_SERVICES_MB = 0x00010005; // Custom -> Runner Services MB\r
-static const uint32_t CHANNEL_CUS_SERVICES_NC = 0x00008005; // Custom -> Runner Services NC\r
-static const uint32_t CHANNEL_CUS_SERVICES_TH = 0x00020005; // Custom -> Runner Services TH\r
-static const uint32_t CHANNEL_CUS_SERVICES_WASTE = 0x00080005; // Custom -> Runner Services Wastelands\r
-static const uint32_t CHANNEL_CUS_TEAM_10 = 0x00100005; // Custom -> Searching Team ~10\r
-static const uint32_t CHANNEL_CUS_TEAM_30 = 0x00200005; // Custom -> Searching Team ~30\r
-static const uint32_t CHANNEL_CUS_TEAM_50 = 0x00400005; // Custom -> Searching Team ~50\r
-static const uint32_t CHANNEL_CUS_TEAM_70 = 0x00800005; // Custom -> Searching Team ~70\r
-static const uint32_t CHANNEL_ADMIN = 0x000000FF; // Admin chat\r
-static const uint32_t CHANNEL_GMADMIN = 0x000000FE; // Admin chat\r
-static const uint32_t CHANNEL_GMCHAT = 0x000000FD; // GameMaster chat\r
-/*\r
-####################\r
- CHANNEL-CODES:\r
- (OUTGOING)\r
-####################\r
-*/\r
-static const uint8_t CHAT_BUDDY[] = {0x00, 0x10};\r
-static const uint8_t CHAT_LOCAL[] = {0x01, 0x10};\r
-static const uint8_t CHAT_CLAN[] = {0x02, 0x10};\r
-static const uint8_t CHAT_TEAM[] = {0x03, 0x10};\r
-static const uint8_t CHAT_DIRECT[] = {0x04, 0x10};\r
-static const uint8_t CHAT_ZONE[] = {0x05, 0x00};\r
-static const uint8_t CHAT_FRAK[] = {0x05, 0x01};\r
-static const uint8_t CHAT_TRADECS[] = {0x05, 0x05};\r
-static const uint8_t CHAT_TRADEMB[] = {0x05, 0x03};\r
-static const uint8_t CHAT_TRADENC[] = {0x05, 0x02};\r
-static const uint8_t CHAT_TRADETH[] = {0x05, 0x04};\r
-static const uint8_t CHAT_TRADEWL[] = {0x05, 0x06};\r
-static const uint8_t CHAT_OOC[] = {0x05, 0x12};\r
-static const uint8_t CHAT_HELP[] = {0x05, 0x11};\r
-static const uint8_t CHAT_CLANSEARCH[] = {0x05, 0x10};\r
-static const uint8_t CHAT_SERVICECS[] = {0x05, 0x0A};\r
-static const uint8_t CHAT_SERVICESMB[] = {0x05, 0x08};\r
-static const uint8_t CHAT_SERVICESNC[] = {0x05, 0x07};\r
-static const uint8_t CHAT_SERVICESTH[] = {0x05, 0x09};\r
-static const uint8_t CHAT_SERVICESWL[] = {0x05, 0x0B};\r
-static const uint8_t CHAT_TEAM10[] = {0x05, 0x0C};\r
-static const uint8_t CHAT_TEAM30[] = {0x05, 0x0D};\r
-static const uint8_t CHAT_TEAM50[] = {0x05, 0x0E};\r
-static const uint8_t CHAT_TEAM70[] = {0x05, 0x0F};\r
-static const uint8_t CHAT_ADMIN[] = {0xFF, 0x10};\r
-static const uint8_t CHAT_GMADMIN[] = {0xFE, 0x10};\r
-static const uint8_t CHAT_GM[] = {0xFD, 0x10};\r
-\r
-/*\r
-####################\r
- CHANNEL-CODES:\r
-(EN/DISABLE-ABLE CHANNELS)\r
-####################\r
-*/\r
-static const uint32_t C_ZONE = 1;\r
-static const uint32_t C_FRAK = 2;\r
-static const uint32_t C_TRADENC = 4;\r
-static const uint32_t C_TRADEMB = 8;\r
-static const uint32_t C_TRADETH = 16;\r
-static const uint32_t C_TRADECS = 32;\r
-static const uint32_t C_TRADEWL = 64;\r
-static const uint32_t C_SERVICENC = 128;\r
-static const uint32_t C_SERVICEMB = 256;\r
-static const uint32_t C_SERVICETH = 512;\r
-static const uint32_t C_SERVICECS = 1024;\r
-static const uint32_t C_SERVICEWL = 2048;\r
-static const uint32_t C_TEAM10 = 4096;\r
-static const uint32_t C_TEAM30 = 8192;\r
-static const uint32_t C_TEAM50 = 16384;\r
-static const uint32_t C_TEAM70 = 32768;\r
-static const uint32_t C_CLANSEARCH = 65536;\r
-static const uint32_t C_HELP = 131072;\r
-static const uint32_t C_OOC = 262144;\r
+#pragma once
+
+#include <cstdint>
+
+#define LOCALCHAT_MAXDISTANCE 1433
+
+class PClient;
+
+class PChat {
+public:
+ PChat();
+ ~PChat();
+
+ // INCOMING CHAT
+ bool HandleGameChat(PClient *Client, const uint8_t *Packet);
+ bool cmpr(const uint8_t *Array1, const uint8_t *Array2);
+
+ // this function is called by the other more specific functions and simply sends the data to the receiver-client
+ bool send(PClient* receiver, const uint8_t* Channel, const char* AuthorNickName, const char* text, bool debugOut=false);
+
+ // this is for debugging and sends the current connected playerlist to the receiver-client
+ void sendConnectedList(PClient* receiver, bool debugOut=false);
+
+ // specific channel functions:
+ void sendBuddy(PClient* author, const char* text, bool debugOut=false);
+ void sendLocal(PClient* author, const char* text, bool debugOut=false);
+ void sendClan(PClient* author, const char* text, bool debugOut=false);
+ void sendTeam(PClient* author, const char* text, bool debugOut=false);
+ void sendDirect(PClient* author, PClient* receiver, const char* text, bool debugOut=false);
+ void sendZone(PClient* author, const char* text, bool debugOut=false);
+ void sendFrak(PClient* author, const char* text, bool debugOut=false);
+ void sendTradeCS(PClient* author, const char* text, bool debugOut=false);
+ void sendTradeMB(PClient* author, const char* text, bool debugOut=false);
+ void sendTradeNC(PClient* author, const char* text, bool debugOut=false);
+ void sendTradeTH(PClient* author, const char* text, bool debugOut=false);
+ void sendTradeWL(PClient* author, const char* text, bool debugOut=false);
+ void sendOOC(PClient* author, const char* text, bool debugOut=false);
+ void sendHelp(PClient* author, const char* text, bool debugOut=false);
+ void sendClanSearch(PClient* author, const char* text, bool debugOut=false);
+ void sendServicesCS(PClient* author, const char* text, bool debugOut=false);
+ void sendServicesMB(PClient* author, const char* text, bool debugOut=false);
+ void sendServicesNC(PClient* author, const char* text, bool debugOut=false);
+ void sendServicesTH(PClient* author, const char* text, bool debugOut=false);
+ void sendServicesWL(PClient* author, const char* text, bool debugOut=false);
+ void sendTeam10(PClient* author, const char* text, bool debugOut=false);
+ void sendTeam30(PClient* author, const char* text, bool debugOut=false);
+ void sendTeam50(PClient* author, const char* text, bool debugOut=false);
+ void sendTeam70(PClient* author, const char* text, bool debugOut=false);
+ void sendAdmin(PClient* author, const char* text, bool debugOut=false);
+ void sendGM(PClient* author, const char* text, bool debugOut=false);
+ void sendGMAdmin(PClient* author, const char* text, bool debugOut=false);
+
+ void sendBroadcast(const char* text, bool debugOut=false);
+ void sendOOCBroadcast(const char* text, bool debugOut=false);
+ void sendPlayerDirect(PClient* author, const char* text, uint32_t destination, bool debugOut=false);
+ void sendLocalchat(PClient* receiver, PClient* author, const char* text, bool debugOut=false);
+ bool chanEnabled(PClient* Client, uint32_t channel);
+};
+
+/** A WARNING: DO >N O T< (!!!) CHANGE >ANY< OF THE FOLLOWING VARIABLES UNLESS YOU KNOW EXACT WHAT YOU'RE DOING! **/
+/** You can easily mess up the entire chat subsystem. If you're unsure, ask Namikon first! **/
+/*
+####################
+ CHANNEL-CODES:
+ (INCOMING)
+####################
+*/
+static const uint32_t CHANNEL_BUDDY = 0x00000000; // Buddy
+static const uint32_t CHANNEL_CLAN = 0x00000002; // Clan
+static const uint32_t CHANNEL_TEAM = 0x00000003; // Team
+static const uint32_t CHANNEL_DIRECT = 0xFFFFFFFF; // Direct UNKNOWN YET
+static const uint32_t CHANNEL_CUS_ZONE = 0x00000105; // Custom -> Zone
+static const uint32_t CHANNEL_CUS_FRAKTION = 0x00000205; // Custom -> Fraktion
+static const uint32_t CHANNEL_CUS_TRADE_CANYON = 0x00002005; // Custom -> Trade Canyon
+static const uint32_t CHANNEL_CUS_TRADE_MB = 0x00000805; // Custom -> Trade MB
+static const uint32_t CHANNEL_CUS_TRADE_NC = 0x00000405; // Custom -> Trade NC
+static const uint32_t CHANNEL_CUS_TRADE_TH = 0x00001005; // Custom -> Trade TH
+static const uint32_t CHANNEL_CUS_TRADE_WASTE = 0x00004005; // Custom -> Trade Wastelands
+static const uint32_t CHANNEL_CUS_OOC = 0x04000005; // Custom -> OOC
+static const uint32_t CHANNEL_CUS_PLAYERHELP = 0x02000005; // Custom -> Player 2 Player help
+static const uint32_t CHANNEL_CUS_CLANSEARCH = 0x01000005; // Custom -> Searching Clan
+static const uint32_t CHANNEL_CUS_SERVICES_CANYON = 0x00040005; // Custom -> Runner Services Canyon
+static const uint32_t CHANNEL_CUS_SERVICES_MB = 0x00010005; // Custom -> Runner Services MB
+static const uint32_t CHANNEL_CUS_SERVICES_NC = 0x00008005; // Custom -> Runner Services NC
+static const uint32_t CHANNEL_CUS_SERVICES_TH = 0x00020005; // Custom -> Runner Services TH
+static const uint32_t CHANNEL_CUS_SERVICES_WASTE = 0x00080005; // Custom -> Runner Services Wastelands
+static const uint32_t CHANNEL_CUS_TEAM_10 = 0x00100005; // Custom -> Searching Team ~10
+static const uint32_t CHANNEL_CUS_TEAM_30 = 0x00200005; // Custom -> Searching Team ~30
+static const uint32_t CHANNEL_CUS_TEAM_50 = 0x00400005; // Custom -> Searching Team ~50
+static const uint32_t CHANNEL_CUS_TEAM_70 = 0x00800005; // Custom -> Searching Team ~70
+static const uint32_t CHANNEL_ADMIN = 0x000000FF; // Admin chat
+static const uint32_t CHANNEL_GMADMIN = 0x000000FE; // Admin chat
+static const uint32_t CHANNEL_GMCHAT = 0x000000FD; // GameMaster chat
+/*
+####################
+ CHANNEL-CODES:
+ (OUTGOING)
+####################
+*/
+static const uint8_t CHAT_BUDDY[] = {0x00, 0x10};
+static const uint8_t CHAT_LOCAL[] = {0x01, 0x10};
+static const uint8_t CHAT_CLAN[] = {0x02, 0x10};
+static const uint8_t CHAT_TEAM[] = {0x03, 0x10};
+static const uint8_t CHAT_DIRECT[] = {0x04, 0x10};
+static const uint8_t CHAT_ZONE[] = {0x05, 0x00};
+static const uint8_t CHAT_FRAK[] = {0x05, 0x01};
+static const uint8_t CHAT_TRADECS[] = {0x05, 0x05};
+static const uint8_t CHAT_TRADEMB[] = {0x05, 0x03};
+static const uint8_t CHAT_TRADENC[] = {0x05, 0x02};
+static const uint8_t CHAT_TRADETH[] = {0x05, 0x04};
+static const uint8_t CHAT_TRADEWL[] = {0x05, 0x06};
+static const uint8_t CHAT_OOC[] = {0x05, 0x12};
+static const uint8_t CHAT_HELP[] = {0x05, 0x11};
+static const uint8_t CHAT_CLANSEARCH[] = {0x05, 0x10};
+static const uint8_t CHAT_SERVICECS[] = {0x05, 0x0A};
+static const uint8_t CHAT_SERVICESMB[] = {0x05, 0x08};
+static const uint8_t CHAT_SERVICESNC[] = {0x05, 0x07};
+static const uint8_t CHAT_SERVICESTH[] = {0x05, 0x09};
+static const uint8_t CHAT_SERVICESWL[] = {0x05, 0x0B};
+static const uint8_t CHAT_TEAM10[] = {0x05, 0x0C};
+static const uint8_t CHAT_TEAM30[] = {0x05, 0x0D};
+static const uint8_t CHAT_TEAM50[] = {0x05, 0x0E};
+static const uint8_t CHAT_TEAM70[] = {0x05, 0x0F};
+static const uint8_t CHAT_ADMIN[] = {0xFF, 0x10};
+static const uint8_t CHAT_GMADMIN[] = {0xFE, 0x10};
+static const uint8_t CHAT_GM[] = {0xFD, 0x10};
+
+/*
+####################
+ CHANNEL-CODES:
+(EN/DISABLE-ABLE CHANNELS)
+####################
+*/
+static const uint32_t C_ZONE = 1;
+static const uint32_t C_FRAK = 2;
+static const uint32_t C_TRADENC = 4;
+static const uint32_t C_TRADEMB = 8;
+static const uint32_t C_TRADETH = 16;
+static const uint32_t C_TRADECS = 32;
+static const uint32_t C_TRADEWL = 64;
+static const uint32_t C_SERVICENC = 128;
+static const uint32_t C_SERVICEMB = 256;
+static const uint32_t C_SERVICETH = 512;
+static const uint32_t C_SERVICECS = 1024;
+static const uint32_t C_SERVICEWL = 2048;
+static const uint32_t C_TEAM10 = 4096;
+static const uint32_t C_TEAM30 = 8192;
+static const uint32_t C_TEAM50 = 16384;
+static const uint32_t C_TEAM70 = 32768;
+static const uint32_t C_CLANSEARCH = 65536;
+static const uint32_t C_HELP = 131072;
+static const uint32_t C_OOC = 262144;
-#include "GameServer/Includes.hxx"\r
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-PClient::PClient( int Index )\r
-{\r
- mAccountID = 0;\r
- mAccountLevel = 0;\r
- mIndex = Index;\r
- mCharID = 0;\r
- mConnection = PCC_NONE;\r
- mRemotePort = 0;\r
- m_TCPConnection = NULL;\r
- m_UDPConnection = NULL;\r
-\r
- for ( int i = 0; i < DEBUG_MODES ; i++ )\r
- mDebugMode[i] = false;\r
-\r
- //********\r
- mAwaitingWarpto = false;\r
- mTargetX = 0;\r
- mTargetY = 0;\r
- mTargetZ = 0;\r
- //********\r
- mActorRemoveMode = false;\r
- mAcceptNPCUpdates = false;\r
-\r
- testval8 = 0;\r
-}\r
-\r
-PClient::~PClient()\r
-{\r
- if ( m_TCPConnection )\r
- {\r
- delete m_TCPConnection;\r
- m_TCPConnection = NULL;\r
- }\r
- if ( m_UDPConnection )\r
- {\r
- delete m_UDPConnection;\r
- m_UDPConnection = NULL;\r
- }\r
-}\r
-/// ******************************************************\r
-\r
-bool PClient::GetDebugMode(PDebugMode nDebugID)\r
-{\r
- return mDebugMode[nDebugID];\r
-}\r
-\r
-bool PClient::IsAcceptingNPCUpdates()\r
-{\r
- return mAcceptNPCUpdates;\r
-}\r
-\r
-void PClient::SetAcceptNPCUpdates(bool nVal)\r
-{\r
- mAcceptNPCUpdates = nVal;\r
-}\r
-\r
-bool PClient::IsZoning()\r
-{\r
- return mZoning;\r
-}\r
-\r
-void PClient::SetZoning(bool nVal)\r
-{\r
- mZoning = nVal;\r
- if (!nVal)\r
- mVhcZoning = false;\r
-}\r
-\r
-bool PClient::IsVhcZoning()\r
-{\r
- return mVhcZoning;\r
-}\r
-\r
-void PClient::SetVhcZoning(bool nVal)\r
-{\r
- mVhcZoning = nVal;\r
-}\r
-\r
-uint32_t PClient::GetIndex() const\r
-{\r
- return mIndex;\r
-}\r
-\r
-uint32_t PClient::GetID() const\r
-{\r
- return mIndex;\r
-}\r
-\r
-uint32_t PClient::GetLocalID() const\r
-{\r
- return mIndex + 1;\r
-}\r
-\r
-uint32_t PClient::GetCharID() const\r
-{\r
- return mCharID;\r
-}\r
-\r
-int PClient::GetRemoteUDPPort() const\r
-{\r
- return mRemotePort;\r
-}\r
-\r
-bool PClient::IsInRemoveActorMode()\r
-{\r
- return mActorRemoveMode;\r
-}\r
-\r
-void PClient::SetRemoveActorMode(bool nNewValue)\r
-{\r
- mActorRemoveMode = nNewValue;\r
-}\r
-\r
-void PClient::SetRemoteUDPPort(int port)\r
-{\r
- mRemotePort = port;\r
-}\r
-\r
-void PClient::SetCharID(int id)\r
-{\r
- mCharID = id;\r
-}\r
-\r
-uint16_t PClient::GetUDP_ID()\r
-{\r
- if ( m_UDPConnection )\r
- return m_UDPConnection->GetUDP_ID();\r
- else\r
- Console->Print( "%s Unable to get UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
- return 0;\r
-}\r
-\r
-void PClient::SetUDP_ID( int id )\r
-{\r
- if ( m_UDPConnection )\r
- m_UDPConnection->SetUDP_ID( id );\r
- else\r
- Console->Print( "%s Unable to set UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
-}\r
-\r
-void PClient::IncreaseUDP_ID()\r
-{\r
- if ( m_UDPConnection )\r
- m_UDPConnection->IncreaseUDP_ID();\r
- else\r
- Console->Print( "%s Unable to increase UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
-}\r
-\r
-uint16_t PClient::GetSessionID()\r
-{\r
- if ( m_UDPConnection )\r
- return m_UDPConnection->GetSessionID();\r
- else\r
- Console->Print( "%s Unable to get UDP SessionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
- return 0;\r
-}\r
-\r
-uint16_t PClient::GetTransactionID()\r
-{\r
- if ( m_UDPConnection )\r
- return m_UDPConnection->GetTransactionID();\r
- else\r
- Console->Print( "%s Unable to get UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
- return 0;\r
-}\r
-\r
-void PClient::ResetTransactionID()\r
-{\r
- if ( m_UDPConnection )\r
- m_UDPConnection->ResetTransactionID();\r
- else\r
- Console->Print( "%s Unable to reset UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
-}\r
-\r
-void PClient::IncreaseTransactionID( uint8_t nInc )\r
-{\r
- if ( m_UDPConnection )\r
- m_UDPConnection->IncreaseTransactionID( nInc );\r
- else\r
- Console->Print( "%s Unable to increase UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
-}\r
-\r
-void PClient::FillInUDP_ID( PMessage* nMessage )\r
-{\r
- uint16_t CurrPos;\r
-\r
- if (( nMessage->GetSize() > 9 ) && ( nMessage->U8Data( 0x00 ) == 0x13 ) )\r
- {\r
- CurrPos = 5;\r
- while ( CurrPos < nMessage->GetSize() ) // do UDP_ID mgt for each 0x03 subtype subpacket\r
- {\r
- if ( nMessage->U8Data( CurrPos + 1 ) == 0x03 )\r
- {\r
- IncreaseUDP_ID();\r
- nMessage->U16Data( CurrPos + 2 ) = GetUDP_ID();\r
- }\r
- CurrPos = CurrPos + nMessage->U8Data( CurrPos ) + 1;\r
- }\r
- }\r
- nMessage->U16Data( 0x01 ) = GetUDP_ID();\r
- nMessage->U16Data( 0x03 ) = GetSessionID();\r
-}\r
-\r
-void PClient::setTCPConnection(ConnectionTCP *conn)\r
-{\r
- m_TCPConnection = conn;\r
- m_UDPConnection = nullptr;\r
- mConnection = PCC_GAME;\r
-}\r
-\r
-void PClient::setUDPConnection(ConnectionUDP *conn)\r
-{\r
- m_UDPConnection = conn;\r
-}\r
-\r
-ConnectionTCP *PClient::getTCPConn()\r
-{\r
- return m_TCPConnection;\r
-}\r
-\r
-ConnectionUDP *PClient::getUDPConn()\r
-{\r
- return m_UDPConnection;\r
-}\r
-\r
-void PClient::SendTCPMessage(PMessage *nMessage)\r
-{\r
- if (m_TCPConnection)\r
- m_TCPConnection->SendMessage(nMessage);\r
- else\r
- delete nMessage;\r
-}\r
-\r
-void PClient::FragmentAndSendUDPMessage( PMessage* nMessage, uint8_t nType )\r
-{\r
- PMessage* ChunkBuffer;\r
- PMessage* ChunkMsg;\r
- const uint16_t ChunkSize = 220;\r
- uint16_t StartIncUDPIDOnChunk = 0;\r
- uint16_t IncludedHeaderSize = 0;\r
- bool ReplaceFirstByte = false;\r
- uint8_t ReplaceFirstByteValue = 0;\r
- uint16_t MultiTriggeringSize = 0;\r
-\r
- switch ( nType )\r
- {\r
- case 0x68: // Terminal ReceiveDB\r
- {\r
- ReplaceFirstByte = true;\r
- ReplaceFirstByteValue = 0x21;\r
- MultiTriggeringSize = 220;\r
- IncludedHeaderSize = 9;\r
- StartIncUDPIDOnChunk = 1;\r
- break;\r
- }\r
- case 0x04:\r
- {\r
- Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Message type 0x%02x not managed yet", nType );\r
- break;\r
- }\r
- case 0x05: //CharOpenContainerMsg with header & UDP_ID incremented\r
- {\r
- StartIncUDPIDOnChunk = 1;\r
- IncludedHeaderSize = 9;\r
- ReplaceFirstByte = true;\r
- ReplaceFirstByteValue = 0x15;\r
- MultiTriggeringSize = 230;\r
- break;\r
- }\r
- case 0x06: // For sending Custom LUA Scripts to client\r
- {\r
- break;\r
- }\r
- case 0x19: //BaselineMsg (with no header)\r
- {\r
- break;\r
- }\r
- case 0xac: //BuildTraderItemListMsg with header & UDP_ID incremented\r
- {\r
- StartIncUDPIDOnChunk = 1;\r
- IncludedHeaderSize = 9;\r
- ReplaceFirstByte = true;\r
- ReplaceFirstByteValue = 0x15;\r
- MultiTriggeringSize = 230;\r
- break;\r
- }\r
- default:\r
- {\r
- Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Message type 0x%02x not managed", nType );\r
- break;\r
- }\r
- }\r
-\r
- if ( nMessage->GetSize() >= MultiTriggeringSize )\r
- {\r
- if ( gDevDebug )\r
- Console->Print( YELLOW, BLACK, "[Debug] Fragmenting message type 0x%02x", nType );\r
- if ( ReplaceFirstByte )\r
- {\r
- nMessage->U8Data( IncludedHeaderSize ) = ReplaceFirstByteValue;\r
- }\r
-\r
- uint16_t ChunksNum = ( nMessage->GetSize() - IncludedHeaderSize + ChunkSize - 1 ) / ChunkSize;\r
-\r
- for ( uint16_t ChunkID = 0; ChunkID < ChunksNum; ChunkID++ )\r
- {\r
- ChunkBuffer = nMessage->GetChunk( IncludedHeaderSize, ChunkSize, ChunkID );\r
- if ( ChunkBuffer == NULL )\r
- {\r
- Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Bad chunk number: %d for size %d", ChunksNum, nMessage->GetSize() );\r
- break;\r
- }\r
-\r
- ChunkMsg = new PMessage( ChunkSize + 15 );\r
- if ( ChunkID >= StartIncUDPIDOnChunk )\r
- {\r
- IncreaseUDP_ID();\r
- }\r
-\r
- *ChunkMsg << ( uint8_t )0x13;\r
- *ChunkMsg << ( uint16_t )GetUDP_ID();\r
- *ChunkMsg << ( uint16_t )GetSessionID();\r
- *ChunkMsg << ( uint8_t )( 9 + ChunkBuffer->GetSize() );\r
- *ChunkMsg << ( uint8_t )0x03;\r
- *ChunkMsg << ( uint16_t )GetUDP_ID();\r
- *ChunkMsg << ( uint8_t )0x07; // Fragmented\r
- *ChunkMsg << ( uint16_t )ChunkID;\r
- *ChunkMsg << ( uint16_t )ChunksNum;\r
- *ChunkMsg << ( uint8_t )nType;\r
- *ChunkMsg << *ChunkBuffer;\r
-\r
- delete ChunkBuffer;\r
- //Console->Print(YELLOW, BLACK, "[Debug] Sending Fragment %d/%d", ChunkID+1, ChunksNum);\r
- //ChunkMsg->Dump();\r
- SendUDPMessage( ChunkMsg );\r
- }\r
- delete nMessage;\r
- }\r
- else\r
- {\r
- //Console->Print(YELLOW, BLACK, "[Debug] Sending message WITHOUT Fragmenting");\r
- SendUDPMessage( nMessage );\r
- }\r
-}\r
-\r
-void PClient::SendUDPMessage(PMessage *nMessage, bool nVIP)\r
-{\r
- if (m_UDPConnection)\r
- m_UDPConnection->SendMessage(nMessage, nVIP);\r
- else\r
- delete nMessage;\r
-}\r
-\r
-void PClient::SetDebugMode( PDebugMode nDebugID, bool nVal )\r
-{\r
- if ( nDebugID == DBG_ALL )\r
- {\r
- for ( int i = 0; i < DEBUG_MODES ; i++ )\r
- mDebugMode[i] = nVal;\r
- }\r
- else\r
- mDebugMode[nDebugID] = nVal;\r
-}\r
-\r
-bool PClient::ChangeCharLocation( uint32_t nLocation, bool DoForce )\r
-{\r
- if ( gDevDebug )\r
- Console->Print( "%s PClient::ChangeCharLocation", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- if ( Worlds->IsValidWorld( nLocation ) )\r
- {\r
- mAcceptNPCUpdates = false; // Zone changed, reject NPC updates till initial NPC spawn\r
- PChar* tChar = GetChar();\r
- uint32_t CurrentLocation = tChar->GetLocation();\r
- if (( CurrentLocation == nLocation ) && !DoForce )\r
- return true;\r
-\r
- // DoForce is used in GM teleport and jail/unjail command to free player from jail\r
- if (( tChar->IsJailed() == true ) && !DoForce )\r
- {\r
- if ( CurrentLocation != 550 && CurrentLocation != 551 ) // If player managed to "get out of jail" somehow, replace him there\r
- {\r
- // Do nothing here. This doesnt work as long as we are able to warp the player around just by\r
- // sending some packets out. Enable/modify this if fixed\r
- //tChar->SetLocation(550);\r
- }\r
- // Player still in 550 or 551 and trying to warp out (by death for example) just\r
- // return true and let him respawn at 550 entrypoint 0\r
- //return true;\r
- }\r
-\r
- PWorld* nWorld;\r
- if (( nWorld = Worlds->LeaseWorld( nLocation ) ) )\r
- {\r
- if ( tChar->GetLocationLeased() )\r
- {\r
- // TAke care of sitting chars\r
- uint32_t ChairObjectId;\r
- uint8_t tSeatId;\r
- PSeatType tSeatType;\r
- if (( tSeatType = tChar->GetSeatInUse( &ChairObjectId, &tSeatId ) ) )\r
- {\r
- bool vhcZoning = false;\r
- PSpawnedVehicle* tVhc = 0;\r
- if ( (tSeatType == seat_vhc) && IsVhcZoning() ) // If seat is vhc,\r
- { // Do additionnal check\r
- if (( tVhc = nWorld->GetSpawnedVehicles()->GetVehicle( ChairObjectId ) ) )\r
- {\r
- if ( tVhc->GetSeatUser( tSeatId ) == tChar->GetID() )\r
- {\r
- vhcZoning = true;\r
- }\r
- }\r
- }\r
-\r
- if ( ! vhcZoning )\r
- {\r
- PUdpCharExitChair::DoLeaveChair( tChar, this, tVhc, true );\r
- }\r
- /*{\r
- Worlds->GetWorld( CurrentLocation )->CharLeaveChair( GetLocalID(), ChairObjectId );\r
- tChar->SetSeatInUse( seat_none );\r
- }*/\r
- }\r
- this->InitWarpCircle();\r
- this->InitCharVanish();\r
- Worlds->ReleaseWorld( CurrentLocation );\r
- }\r
- tChar->SetLocation( nLocation );\r
- tChar->SetLocationLeased();\r
-\r
- return true;\r
- }\r
- }\r
- else if ( nLocation != 1 ) // try to fall back if bad location\r
- {\r
- Console->Print( YELLOW, BLACK, "[Warning] Client %d want to zone to invalid world %d. Falling back to world 1", mIndex, nLocation );\r
- return ChangeCharLocation( 1, DoForce );\r
- }\r
-\r
- return false;\r
-}\r
-\r
-int PClient::GetConnection() const\r
-{\r
- return mConnection;\r
-}\r
-\r
-const char *PClient::GetAddress() const\r
-{\r
- return m_TCPConnection->getRemoteAddress();\r
-}\r
-\r
-uint32_t PClient::GetAccountID() const\r
-{\r
- return mAccountID;\r
-}\r
-\r
-int PClient::GetAccountLevel() const\r
-{\r
- return mAccountLevel;\r
-}\r
-\r
-void PClient::GameDisconnect()\r
-{\r
- mAccountID = 0;\r
-\r
- if ( m_TCPConnection )\r
- {\r
- delete m_TCPConnection;\r
- m_TCPConnection = NULL;\r
- }\r
-\r
- if ( m_UDPConnection )\r
- {\r
- delete m_UDPConnection;\r
- m_UDPConnection = NULL;\r
- }\r
-\r
- /**** Will be better to put that char-saving-at-disconnect in Char destructor, when only used Chars will be loaded ****/\r
- PChar *tChar = GetChar();\r
- if ( tChar )\r
- {\r
- SetZoning();\r
- if ( tChar->GetLocationLeased() )\r
- {\r
- if ( tChar->GetSeatInUse() )\r
- {\r
- //if(gDevDebug)\r
- Console->Print( "%s Trying to get leaving char out of her seat", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- PUdpCharExitChair::DoLeaveChair( tChar, this, NULL, true );\r
- }\r
- /* // replaced by the lines above\r
- PSeatType cSeatType;\r
- uint32_t cSeatObjectId;\r
- uint8_t cSeatId;\r
- PWorld* cWorld;\r
-\r
- cWorld = Worlds->GetWorld(tChar->GetLocation());\r
- cSeatType = tChar->GetSeatInUse(&cSeatObjectId, &cSeatId);\r
- if(cSeatType)\r
- {\r
- if(cSeatType == seat_chair)\r
- {\r
- cWorld->CharLeaveChair(GetLocalID(), cSeatObjectId);\r
- tChar->SetSeatInUse(seat_none);\r
- }\r
- else if(cSeatType == seat_subway)\r
- {\r
- Subway->UnsetSeatUser(cSeatObjectId, cSeatId, GetLocalID());\r
- tChar->SetSeatInUse(seat_none);\r
- }\r
- else if(cSeatType == seat_vhc)\r
- {\r
- cWorld->GetSpawnedVehicles()->GetVehicle(cSeatObjectId)->UnsetSeatUser(cSeatId, GetLocalID());\r
- tChar->SetSeatInUse(seat_none);\r
- }\r
- else\r
- {\r
- Console->Print(RED, BLACK, "[Notice] PClient::GameDisconnect : Leaving seat of unkown type %d", cSeatType);\r
- }\r
- }\r
- */\r
- }\r
-\r
- if ( tChar->IsDirty() )\r
- {\r
- bool res = tChar->SQLSave();\r
- if ( res )\r
- Console->Print( "%s GameDisconnect: Char %i (Client %i) saved before disconnect.", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex );\r
- else\r
- Console->Print( RED, BLACK, "[DEBUG] GameDisconnect: Char %i (Client %i) saving before disconnect and FAILED.", tChar->GetID(), mIndex );\r
- }\r
- else\r
- {\r
- Console->Print( "%s GameDisconnect: Char %i (Client %i) no save needed.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex );\r
- if ( !tChar->IsOnline() )\r
- Console->Print( "%s GameDisconnect: Char %i (Client %i) wasn't marked as ingame anyway...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex );\r
- }\r
-\r
- if ( tChar->GetLocationLeased() )\r
- {\r
- if ( gDevDebug )\r
- Console->Print( "%s Sending char leaving effect", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- InitWarpCircle();\r
- InitCharVanish();\r
-\r
- Worlds->ReleaseWorld( tChar->GetLocation() );\r
- tChar->SetLocationLeased( false );\r
- }\r
-\r
- Chars->RemoveChar( mCharID );\r
- delete tChar;\r
- mCharID = 0;\r
- }\r
- else\r
- {\r
- //Console->Print(YELLOW, BLACK, "GameDisconnect: Client %i had no char online.", mIndex);\r
- }\r
- /**********************************/\r
-\r
- //mConnection &= ~PCC_GAME;\r
- mConnection = PCC_NONE;\r
-}\r
-\r
-void PClient::RefreshAccountInfo( PAccount *Account )\r
-{\r
- mAccountID = Account->GetID();\r
- mAccountLevel = Account->GetLevel();\r
-}\r
-\r
-void PClient::LoggedIn(PAccount *Account)\r
-{\r
- RefreshAccountInfo(Account);\r
-}\r
-\r
-void PClient::Update()\r
-{\r
- if ( m_TCPConnection )\r
- {\r
- if ( m_TCPConnection->timeOut() )\r
- {\r
- Console->Print( "%s GameSocket: Client %i: timeout", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), mIndex );\r
- GameServer->ClientDisconnected( this );\r
- }\r
- else\r
- {\r
- if ( !m_TCPConnection->update() )\r
- {\r
- GameServer->ClientDisconnected( this );\r
- }\r
- }\r
- }\r
-\r
- if ( m_UDPConnection )\r
- {\r
- if ( m_UDPConnection->timeOut() )\r
- {\r
- Console->Print( "%s Game UDP: Client %i: timeout", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), mIndex );\r
- GameServer->UDPStreamClosed( this );\r
- }\r
- else\r
- {\r
- if ( !m_UDPConnection->update() )\r
- {\r
- GameServer->UDPStreamClosed( this );\r
- }\r
- }\r
- }\r
-}\r
-\r
-PChar* PClient::GetChar() const\r
-{\r
- if ( mCharID )\r
- {\r
- return Chars->GetChar( mCharID );\r
- }\r
- else\r
- {\r
- return NULL;\r
- }\r
-}\r
-\r
-int PClient::getZoneID() const\r
-{\r
- return m_ZoneID;\r
-}\r
-\r
-void PClient::SetAwaitingWarpto(bool yesno, uint16_t NewX, uint16_t NewY, uint16_t NewZ)\r
-{\r
- mAwaitingWarpto = yesno;\r
- mTargetX = NewX;\r
- mTargetY = NewY;\r
- mTargetZ = NewZ;\r
-}\r
-\r
-bool PClient::GetCharAwaitingWarpto( uint16_t* PosX, uint16_t* PosY, uint16_t* PosZ )\r
-{\r
- if ( PosX )\r
- *PosX = mTargetX;\r
- if ( PosY )\r
- *PosY = mTargetY;\r
- if ( PosZ )\r
- *PosZ = mTargetZ;\r
-\r
- return mAwaitingWarpto;\r
- /*\r
- if(mAwaitingWarpto == true)\r
- {\r
-\r
- // Position update doesnt work. Uncomment&Change function if ever required again\r
- mAwaitingWarpto = false;\r
- (GetChar()->Coords).mX = mTargetX;\r
- (GetChar()->Coords).mY = mTargetY;\r
- (GetChar()->Coords).mZ = mTargetZ;\r
- return true;\r
- // PMessage* tmpMsg_posupdate;\r
- //\r
- // tmpMsg_posupdate = MsgBuilder->BuildCharPosMoveMsg(this, mTargetX, mTargetY, mTargetZ);\r
- // ClientManager->UDPBroadcast(tmpMsg_posupdate, this);\r
- // tmpMsg_posupdate = NULL;\r
- }\r
- return false;\r
- */\r
-}\r
-\r
-void PClient::InitWarpCircle()\r
-{\r
- PMessage* tmpMsg_circle = MsgBuilder->BuildCharShowGlowCircleMsg( this );\r
- ClientManager->UDPBroadcast( tmpMsg_circle, this, 1000, true ); // send only in a 1000 radius\r
-}\r
-\r
-void PClient::InitCharVanish()\r
-{\r
- PMessage* tmpMsg_vanish = MsgBuilder->BuildRemoveWorldObjectMsg( GetLocalID() );\r
- ClientManager->UDPBroadcast( tmpMsg_vanish, this, 0, true );\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "GameServer/Decoder/Includes.hxx"
+#include "Common/Includes.hxx"
+
+PClient::PClient( int Index )
+{
+ mAccountID = 0;
+ mAccountLevel = 0;
+ mIndex = Index;
+ mCharID = 0;
+ mConnection = PCC_NONE;
+ mRemotePort = 0;
+ m_TCPConnection = NULL;
+ m_UDPConnection = NULL;
+
+ for ( int i = 0; i < DEBUG_MODES ; i++ )
+ mDebugMode[i] = false;
+
+ //********
+ mAwaitingWarpto = false;
+ mTargetX = 0;
+ mTargetY = 0;
+ mTargetZ = 0;
+ //********
+ mActorRemoveMode = false;
+ mAcceptNPCUpdates = false;
+
+ testval8 = 0;
+}
+
+PClient::~PClient()
+{
+ if ( m_TCPConnection )
+ {
+ delete m_TCPConnection;
+ m_TCPConnection = NULL;
+ }
+ if ( m_UDPConnection )
+ {
+ delete m_UDPConnection;
+ m_UDPConnection = NULL;
+ }
+}
+/// ******************************************************
+
+bool PClient::GetDebugMode(PDebugMode nDebugID)
+{
+ return mDebugMode[nDebugID];
+}
+
+bool PClient::IsAcceptingNPCUpdates()
+{
+ return mAcceptNPCUpdates;
+}
+
+void PClient::SetAcceptNPCUpdates(bool nVal)
+{
+ mAcceptNPCUpdates = nVal;
+}
+
+bool PClient::IsZoning()
+{
+ return mZoning;
+}
+
+void PClient::SetZoning(bool nVal)
+{
+ mZoning = nVal;
+ if (!nVal)
+ mVhcZoning = false;
+}
+
+bool PClient::IsVhcZoning()
+{
+ return mVhcZoning;
+}
+
+void PClient::SetVhcZoning(bool nVal)
+{
+ mVhcZoning = nVal;
+}
+
+uint32_t PClient::GetIndex() const
+{
+ return mIndex;
+}
+
+uint32_t PClient::GetID() const
+{
+ return mIndex;
+}
+
+uint32_t PClient::GetLocalID() const
+{
+ return mIndex + 1;
+}
+
+uint32_t PClient::GetCharID() const
+{
+ return mCharID;
+}
+
+int PClient::GetRemoteUDPPort() const
+{
+ return mRemotePort;
+}
+
+bool PClient::IsInRemoveActorMode()
+{
+ return mActorRemoveMode;
+}
+
+void PClient::SetRemoveActorMode(bool nNewValue)
+{
+ mActorRemoveMode = nNewValue;
+}
+
+void PClient::SetRemoteUDPPort(int port)
+{
+ mRemotePort = port;
+}
+
+void PClient::SetCharID(int id)
+{
+ mCharID = id;
+}
+
+uint16_t PClient::GetUDP_ID()
+{
+ if ( m_UDPConnection )
+ return m_UDPConnection->GetUDP_ID();
+ else
+ Console->Print( "%s Unable to get UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );
+ return 0;
+}
+
+void PClient::SetUDP_ID( int id )
+{
+ if ( m_UDPConnection )
+ m_UDPConnection->SetUDP_ID( id );
+ else
+ Console->Print( "%s Unable to set UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );
+}
+
+void PClient::IncreaseUDP_ID()
+{
+ if ( m_UDPConnection )
+ m_UDPConnection->IncreaseUDP_ID();
+ else
+ Console->Print( "%s Unable to increase UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );
+}
+
+uint16_t PClient::GetSessionID()
+{
+ if ( m_UDPConnection )
+ return m_UDPConnection->GetSessionID();
+ else
+ Console->Print( "%s Unable to get UDP SessionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );
+ return 0;
+}
+
+uint16_t PClient::GetTransactionID()
+{
+ if ( m_UDPConnection )
+ return m_UDPConnection->GetTransactionID();
+ else
+ Console->Print( "%s Unable to get UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );
+ return 0;
+}
+
+void PClient::ResetTransactionID()
+{
+ if ( m_UDPConnection )
+ m_UDPConnection->ResetTransactionID();
+ else
+ Console->Print( "%s Unable to reset UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );
+}
+
+void PClient::IncreaseTransactionID( uint8_t nInc )
+{
+ if ( m_UDPConnection )
+ m_UDPConnection->IncreaseTransactionID( nInc );
+ else
+ Console->Print( "%s Unable to increase UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) );
+}
+
+void PClient::FillInUDP_ID( PMessage* nMessage )
+{
+ uint16_t CurrPos;
+
+ if (( nMessage->GetSize() > 9 ) && ( nMessage->U8Data( 0x00 ) == 0x13 ) )
+ {
+ CurrPos = 5;
+ while ( CurrPos < nMessage->GetSize() ) // do UDP_ID mgt for each 0x03 subtype subpacket
+ {
+ if ( nMessage->U8Data( CurrPos + 1 ) == 0x03 )
+ {
+ IncreaseUDP_ID();
+ nMessage->U16Data( CurrPos + 2 ) = GetUDP_ID();
+ }
+ CurrPos = CurrPos + nMessage->U8Data( CurrPos ) + 1;
+ }
+ }
+ nMessage->U16Data( 0x01 ) = GetUDP_ID();
+ nMessage->U16Data( 0x03 ) = GetSessionID();
+}
+
+void PClient::setTCPConnection(ConnectionTCP *conn)
+{
+ m_TCPConnection = conn;
+ m_UDPConnection = nullptr;
+ mConnection = PCC_GAME;
+}
+
+void PClient::setUDPConnection(ConnectionUDP *conn)
+{
+ m_UDPConnection = conn;
+}
+
+ConnectionTCP *PClient::getTCPConn()
+{
+ return m_TCPConnection;
+}
+
+ConnectionUDP *PClient::getUDPConn()
+{
+ return m_UDPConnection;
+}
+
+void PClient::SendTCPMessage(PMessage *nMessage)
+{
+ if (m_TCPConnection)
+ m_TCPConnection->SendMessage(nMessage);
+ else
+ delete nMessage;
+}
+
+void PClient::FragmentAndSendUDPMessage( PMessage* nMessage, uint8_t nType )
+{
+ PMessage* ChunkBuffer;
+ PMessage* ChunkMsg;
+ const uint16_t ChunkSize = 220;
+ uint16_t StartIncUDPIDOnChunk = 0;
+ uint16_t IncludedHeaderSize = 0;
+ bool ReplaceFirstByte = false;
+ uint8_t ReplaceFirstByteValue = 0;
+ uint16_t MultiTriggeringSize = 0;
+
+ switch ( nType )
+ {
+ case 0x68: // Terminal ReceiveDB
+ {
+ ReplaceFirstByte = true;
+ ReplaceFirstByteValue = 0x21;
+ MultiTriggeringSize = 220;
+ IncludedHeaderSize = 9;
+ StartIncUDPIDOnChunk = 1;
+ break;
+ }
+ case 0x04:
+ {
+ Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Message type 0x%02x not managed yet", nType );
+ break;
+ }
+ case 0x05: //CharOpenContainerMsg with header & UDP_ID incremented
+ {
+ StartIncUDPIDOnChunk = 1;
+ IncludedHeaderSize = 9;
+ ReplaceFirstByte = true;
+ ReplaceFirstByteValue = 0x15;
+ MultiTriggeringSize = 230;
+ break;
+ }
+ case 0x06: // For sending Custom LUA Scripts to client
+ {
+ break;
+ }
+ case 0x19: //BaselineMsg (with no header)
+ {
+ break;
+ }
+ case 0xac: //BuildTraderItemListMsg with header & UDP_ID incremented
+ {
+ StartIncUDPIDOnChunk = 1;
+ IncludedHeaderSize = 9;
+ ReplaceFirstByte = true;
+ ReplaceFirstByteValue = 0x15;
+ MultiTriggeringSize = 230;
+ break;
+ }
+ default:
+ {
+ Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Message type 0x%02x not managed", nType );
+ break;
+ }
+ }
+
+ if ( nMessage->GetSize() >= MultiTriggeringSize )
+ {
+ if ( gDevDebug )
+ Console->Print( YELLOW, BLACK, "[Debug] Fragmenting message type 0x%02x", nType );
+ if ( ReplaceFirstByte )
+ {
+ nMessage->U8Data( IncludedHeaderSize ) = ReplaceFirstByteValue;
+ }
+
+ uint16_t ChunksNum = ( nMessage->GetSize() - IncludedHeaderSize + ChunkSize - 1 ) / ChunkSize;
+
+ for ( uint16_t ChunkID = 0; ChunkID < ChunksNum; ChunkID++ )
+ {
+ ChunkBuffer = nMessage->GetChunk( IncludedHeaderSize, ChunkSize, ChunkID );
+ if ( ChunkBuffer == NULL )
+ {
+ Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Bad chunk number: %d for size %d", ChunksNum, nMessage->GetSize() );
+ break;
+ }
+
+ ChunkMsg = new PMessage( ChunkSize + 15 );
+ if ( ChunkID >= StartIncUDPIDOnChunk )
+ {
+ IncreaseUDP_ID();
+ }
+
+ *ChunkMsg << ( uint8_t )0x13;
+ *ChunkMsg << ( uint16_t )GetUDP_ID();
+ *ChunkMsg << ( uint16_t )GetSessionID();
+ *ChunkMsg << ( uint8_t )( 9 + ChunkBuffer->GetSize() );
+ *ChunkMsg << ( uint8_t )0x03;
+ *ChunkMsg << ( uint16_t )GetUDP_ID();
+ *ChunkMsg << ( uint8_t )0x07; // Fragmented
+ *ChunkMsg << ( uint16_t )ChunkID;
+ *ChunkMsg << ( uint16_t )ChunksNum;
+ *ChunkMsg << ( uint8_t )nType;
+ *ChunkMsg << *ChunkBuffer;
+
+ delete ChunkBuffer;
+ //Console->Print(YELLOW, BLACK, "[Debug] Sending Fragment %d/%d", ChunkID+1, ChunksNum);
+ //ChunkMsg->Dump();
+ SendUDPMessage( ChunkMsg );
+ }
+ delete nMessage;
+ }
+ else
+ {
+ //Console->Print(YELLOW, BLACK, "[Debug] Sending message WITHOUT Fragmenting");
+ SendUDPMessage( nMessage );
+ }
+}
+
+void PClient::SendUDPMessage(PMessage *nMessage, bool nVIP)
+{
+ if (m_UDPConnection)
+ m_UDPConnection->SendMessage(nMessage, nVIP);
+ else
+ delete nMessage;
+}
+
+void PClient::SetDebugMode( PDebugMode nDebugID, bool nVal )
+{
+ if ( nDebugID == DBG_ALL )
+ {
+ for ( int i = 0; i < DEBUG_MODES ; i++ )
+ mDebugMode[i] = nVal;
+ }
+ else
+ mDebugMode[nDebugID] = nVal;
+}
+
+bool PClient::ChangeCharLocation( uint32_t nLocation, bool DoForce )
+{
+ if ( gDevDebug )
+ Console->Print( "%s PClient::ChangeCharLocation", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ if ( Worlds->IsValidWorld( nLocation ) )
+ {
+ mAcceptNPCUpdates = false; // Zone changed, reject NPC updates till initial NPC spawn
+ PChar* tChar = GetChar();
+ uint32_t CurrentLocation = tChar->GetLocation();
+ if (( CurrentLocation == nLocation ) && !DoForce )
+ return true;
+
+ // DoForce is used in GM teleport and jail/unjail command to free player from jail
+ if (( tChar->IsJailed() == true ) && !DoForce )
+ {
+ if ( CurrentLocation != 550 && CurrentLocation != 551 ) // If player managed to "get out of jail" somehow, replace him there
+ {
+ // Do nothing here. This doesnt work as long as we are able to warp the player around just by
+ // sending some packets out. Enable/modify this if fixed
+ //tChar->SetLocation(550);
+ }
+ // Player still in 550 or 551 and trying to warp out (by death for example) just
+ // return true and let him respawn at 550 entrypoint 0
+ //return true;
+ }
+
+ PWorld* nWorld;
+ if (( nWorld = Worlds->LeaseWorld( nLocation ) ) )
+ {
+ if ( tChar->GetLocationLeased() )
+ {
+ // TAke care of sitting chars
+ uint32_t ChairObjectId;
+ uint8_t tSeatId;
+ PSeatType tSeatType;
+ if (( tSeatType = tChar->GetSeatInUse( &ChairObjectId, &tSeatId ) ) )
+ {
+ bool vhcZoning = false;
+ PSpawnedVehicle* tVhc = 0;
+ if ( (tSeatType == seat_vhc) && IsVhcZoning() ) // If seat is vhc,
+ { // Do additionnal check
+ if (( tVhc = nWorld->GetSpawnedVehicles()->GetVehicle( ChairObjectId ) ) )
+ {
+ if ( tVhc->GetSeatUser( tSeatId ) == tChar->GetID() )
+ {
+ vhcZoning = true;
+ }
+ }
+ }
+
+ if ( ! vhcZoning )
+ {
+ PUdpCharExitChair::DoLeaveChair( tChar, this, tVhc, true );
+ }
+ /*{
+ Worlds->GetWorld( CurrentLocation )->CharLeaveChair( GetLocalID(), ChairObjectId );
+ tChar->SetSeatInUse( seat_none );
+ }*/
+ }
+ this->InitWarpCircle();
+ this->InitCharVanish();
+ Worlds->ReleaseWorld( CurrentLocation );
+ }
+ tChar->SetLocation( nLocation );
+ tChar->SetLocationLeased();
+
+ return true;
+ }
+ }
+ else if ( nLocation != 1 ) // try to fall back if bad location
+ {
+ Console->Print( YELLOW, BLACK, "[Warning] Client %d want to zone to invalid world %d. Falling back to world 1", mIndex, nLocation );
+ return ChangeCharLocation( 1, DoForce );
+ }
+
+ return false;
+}
+
+int PClient::GetConnection() const
+{
+ return mConnection;
+}
+
+const char *PClient::GetAddress() const
+{
+ return m_TCPConnection->getRemoteAddress();
+}
+
+uint32_t PClient::GetAccountID() const
+{
+ return mAccountID;
+}
+
+int PClient::GetAccountLevel() const
+{
+ return mAccountLevel;
+}
+
+void PClient::GameDisconnect()
+{
+ mAccountID = 0;
+
+ if ( m_TCPConnection )
+ {
+ delete m_TCPConnection;
+ m_TCPConnection = NULL;
+ }
+
+ if ( m_UDPConnection )
+ {
+ delete m_UDPConnection;
+ m_UDPConnection = NULL;
+ }
+
+ /**** Will be better to put that char-saving-at-disconnect in Char destructor, when only used Chars will be loaded ****/
+ PChar *tChar = GetChar();
+ if ( tChar )
+ {
+ SetZoning();
+ if ( tChar->GetLocationLeased() )
+ {
+ if ( tChar->GetSeatInUse() )
+ {
+ //if(gDevDebug)
+ Console->Print( "%s Trying to get leaving char out of her seat", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ PUdpCharExitChair::DoLeaveChair( tChar, this, NULL, true );
+ }
+ /* // replaced by the lines above
+ PSeatType cSeatType;
+ uint32_t cSeatObjectId;
+ uint8_t cSeatId;
+ PWorld* cWorld;
+
+ cWorld = Worlds->GetWorld(tChar->GetLocation());
+ cSeatType = tChar->GetSeatInUse(&cSeatObjectId, &cSeatId);
+ if(cSeatType)
+ {
+ if(cSeatType == seat_chair)
+ {
+ cWorld->CharLeaveChair(GetLocalID(), cSeatObjectId);
+ tChar->SetSeatInUse(seat_none);
+ }
+ else if(cSeatType == seat_subway)
+ {
+ Subway->UnsetSeatUser(cSeatObjectId, cSeatId, GetLocalID());
+ tChar->SetSeatInUse(seat_none);
+ }
+ else if(cSeatType == seat_vhc)
+ {
+ cWorld->GetSpawnedVehicles()->GetVehicle(cSeatObjectId)->UnsetSeatUser(cSeatId, GetLocalID());
+ tChar->SetSeatInUse(seat_none);
+ }
+ else
+ {
+ Console->Print(RED, BLACK, "[Notice] PClient::GameDisconnect : Leaving seat of unkown type %d", cSeatType);
+ }
+ }
+ */
+ }
+
+ if ( tChar->IsDirty() )
+ {
+ bool res = tChar->SQLSave();
+ if ( res )
+ Console->Print( "%s GameDisconnect: Char %i (Client %i) saved before disconnect.", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex );
+ else
+ Console->Print( RED, BLACK, "[DEBUG] GameDisconnect: Char %i (Client %i) saving before disconnect and FAILED.", tChar->GetID(), mIndex );
+ }
+ else
+ {
+ Console->Print( "%s GameDisconnect: Char %i (Client %i) no save needed.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex );
+ if ( !tChar->IsOnline() )
+ Console->Print( "%s GameDisconnect: Char %i (Client %i) wasn't marked as ingame anyway...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex );
+ }
+
+ if ( tChar->GetLocationLeased() )
+ {
+ if ( gDevDebug )
+ Console->Print( "%s Sending char leaving effect", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ InitWarpCircle();
+ InitCharVanish();
+
+ Worlds->ReleaseWorld( tChar->GetLocation() );
+ tChar->SetLocationLeased( false );
+ }
+
+ Chars->RemoveChar( mCharID );
+ delete tChar;
+ mCharID = 0;
+ }
+ else
+ {
+ //Console->Print(YELLOW, BLACK, "GameDisconnect: Client %i had no char online.", mIndex);
+ }
+ /**********************************/
+
+ //mConnection &= ~PCC_GAME;
+ mConnection = PCC_NONE;
+}
+
+void PClient::RefreshAccountInfo( PAccount *Account )
+{
+ mAccountID = Account->GetID();
+ mAccountLevel = Account->GetLevel();
+}
+
+void PClient::LoggedIn(PAccount *Account)
+{
+ RefreshAccountInfo(Account);
+}
+
+void PClient::Update()
+{
+ if ( m_TCPConnection )
+ {
+ if ( m_TCPConnection->timeOut() )
+ {
+ Console->Print( "%s GameSocket: Client %i: timeout", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), mIndex );
+ GameServer->ClientDisconnected( this );
+ }
+ else
+ {
+ if ( !m_TCPConnection->update() )
+ {
+ GameServer->ClientDisconnected( this );
+ }
+ }
+ }
+
+ if ( m_UDPConnection )
+ {
+ if ( m_UDPConnection->timeOut() )
+ {
+ Console->Print( "%s Game UDP: Client %i: timeout", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), mIndex );
+ GameServer->UDPStreamClosed( this );
+ }
+ else
+ {
+ if ( !m_UDPConnection->update() )
+ {
+ GameServer->UDPStreamClosed( this );
+ }
+ }
+ }
+}
+
+PChar* PClient::GetChar() const
+{
+ if ( mCharID )
+ {
+ return Chars->GetChar( mCharID );
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+int PClient::getZoneID() const
+{
+ return m_ZoneID;
+}
+
+void PClient::SetAwaitingWarpto(bool yesno, uint16_t NewX, uint16_t NewY, uint16_t NewZ)
+{
+ mAwaitingWarpto = yesno;
+ mTargetX = NewX;
+ mTargetY = NewY;
+ mTargetZ = NewZ;
+}
+
+bool PClient::GetCharAwaitingWarpto( uint16_t* PosX, uint16_t* PosY, uint16_t* PosZ )
+{
+ if ( PosX )
+ *PosX = mTargetX;
+ if ( PosY )
+ *PosY = mTargetY;
+ if ( PosZ )
+ *PosZ = mTargetZ;
+
+ return mAwaitingWarpto;
+ /*
+ if(mAwaitingWarpto == true)
+ {
+
+ // Position update doesnt work. Uncomment&Change function if ever required again
+ mAwaitingWarpto = false;
+ (GetChar()->Coords).mX = mTargetX;
+ (GetChar()->Coords).mY = mTargetY;
+ (GetChar()->Coords).mZ = mTargetZ;
+ return true;
+ // PMessage* tmpMsg_posupdate;
+ //
+ // tmpMsg_posupdate = MsgBuilder->BuildCharPosMoveMsg(this, mTargetX, mTargetY, mTargetZ);
+ // ClientManager->UDPBroadcast(tmpMsg_posupdate, this);
+ // tmpMsg_posupdate = NULL;
+ }
+ return false;
+ */
+}
+
+void PClient::InitWarpCircle()
+{
+ PMessage* tmpMsg_circle = MsgBuilder->BuildCharShowGlowCircleMsg( this );
+ ClientManager->UDPBroadcast( tmpMsg_circle, this, 1000, true ); // send only in a 1000 radius
+}
+
+void PClient::InitCharVanish()
+{
+ PMessage* tmpMsg_vanish = MsgBuilder->BuildRemoveWorldObjectMsg( GetLocalID() );
+ ClientManager->UDPBroadcast( tmpMsg_vanish, this, 0, true );
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-\r
-class ConnectionTCP;\r
-class ConnectionUDP;\r
-class PMessage;\r
-\r
-// TODO: - check that SetUDP_ID, and the mSessionID(UDP_ID_HIGH) real use,\r
-// and if UDP_ID and mSessionID must be synced (like in NeoX) or not\r
-\r
-enum PClientConnection\r
-{\r
- PCC_NONE = 0,\r
- PCC_GAME = 1\r
-};\r
-\r
-// AccountLevel handling is part of accounts.cpp\r
-/*\r
-enum PClientLevel\r
-{\r
- PCL_BANNED = -1,\r
- PCL_UNREGPLAYER = 0,\r
- PCL_REGPLAYER = 1,\r
- PCL_VOLUNTEER = 30,\r
- PCL_GM = 50,\r
- PCL_ADMIN = 100\r
-};\r
-*/\r
-#define DEBUG_MODES 3\r
-enum PDebugMode\r
-{\r
- DBG_LOCATION = 0,\r
- DBG_ITEMID = 1,\r
- DBG_SUBWAY = 2,\r
- DBG_ALL = DEBUG_MODES // must always be last, with DEBUG_MODES updated as needed\r
-};\r
-\r
-\r
-class PClient\r
-{\r
- private :\r
- ConnectionTCP* m_TCPConnection;\r
- ConnectionUDP* m_UDPConnection;\r
-\r
- uint32_t mAccountID;\r
- int mAccountLevel;\r
- uint32_t mIndex;\r
- uint32_t mCharID;\r
-\r
-// uint16_t mUDP_ID;\r
-// uint16_t mSessionID;\r
-// uint16_t mTransactionID;\r
-\r
- // AccountLevel handling is part of accounts.cpp\r
- //PClientLevel mLevel;\r
- int mConnection;\r
- int mRemotePort;\r
-\r
- bool mDebugMode[DEBUG_MODES];\r
- // new multiuser-chat implementation //\r
- int m_ZoneID;\r
- //int[4] m_IP;\r
-\r
- //*******\r
- bool mActorRemoveMode;\r
- //*******\r
- bool mAwaitingWarpto;\r
- uint16_t mTargetX;\r
- uint16_t mTargetY;\r
- uint16_t mTargetZ;\r
- //*******\r
- bool mAcceptNPCUpdates;\r
- bool mZoning;\r
- bool mVhcZoning;\r
-\r
- public :\r
- PClient( int Index );\r
- ~PClient();\r
-\r
- bool GetDebugMode(PDebugMode nDebugID);\r
- void SetDebugMode(PDebugMode nDebugID, bool nVal = true);\r
-\r
- bool IsAcceptingNPCUpdates();\r
- void SetAcceptNPCUpdates(bool nVal);\r
- bool IsZoning();\r
- void SetZoning(bool nVal = true);\r
- bool IsVhcZoning();\r
- void SetVhcZoning(bool nVal = true);\r
-\r
- uint32_t GetIndex() const; // better use GetID()\r
- uint32_t GetID() const; // for better coherency with other classes\r
- uint32_t GetLocalID() const;\r
- uint32_t GetCharID() const;\r
- PChar* GetChar() const;\r
- bool ChangeCharLocation(uint32_t nLocation, bool DoForce = false);\r
-\r
- int GetRemoteUDPPort() const; // Temp solution\r
-\r
- bool IsInRemoveActorMode();\r
- void SetRemoveActorMode(bool nNewValue);\r
-\r
- void SetRemoteUDPPort(int port); // Temp solution\r
- void SetCharID(int id);//NEW added\r
-\r
- /*\r
- inline uint16_t GetUDP_ID() const { return mUDP_ID; }\r
- inline uint16_t GetSessionID() const { return SESSION_UDP_OFFSET + mUDP_ID ; }\r
- inline uint16_t GetTransactionID() {return mTransactionID; }\r
- void SetUDP_ID(int id);\r
- inline void IncreaseUDP_ID() { SetUDP_ID(mUDP_ID + 1); }\r
- inline void ResetTransactionID() { mTransactionID = 10170; }\r
-\r
- inline void IncreaseTransactionID(uint8_t nInc = 1) { mTransactionID += nInc; }\r
- */\r
-\r
- // All outgoing ID's and stuff is now part of the ConnectionUDP class itself!\r
- // (which is not so good.... comment from Hammag)\r
- // However, we still have full access to it through these functions\r
- uint16_t GetUDP_ID();\r
- void SetUDP_ID( int id );\r
- void IncreaseUDP_ID();\r
-\r
- uint16_t GetSessionID();\r
-\r
- uint16_t GetTransactionID();\r
- void ResetTransactionID();\r
- void IncreaseTransactionID( uint8_t nInc = 1 );\r
-\r
- void FillInUDP_ID( PMessage* nMessage );\r
-\r
-// ************************************************************************ //\r
- // AccountLevel handling is part of accounts.cpp\r
- //inline PClientLevel GetLevel() const { return mLevel; }\r
-\r
- void setTCPConnection(ConnectionTCP *conn);\r
- void setUDPConnection(ConnectionUDP *conn);\r
-\r
- ConnectionTCP* getTCPConn();\r
- ConnectionUDP* getUDPConn();\r
-\r
- void SendTCPMessage(PMessage *nMessage);\r
- void FragmentAndSendUDPMessage( PMessage* nMessage, uint8_t nType );\r
- void SendUDPMessage(PMessage *nMessage, bool nVIP = false);\r
-\r
- int GetConnection() const;\r
- const char *GetAddress() const;\r
- uint32_t GetAccountID() const;\r
- int GetAccountLevel() const;\r
-\r
- void GameDisconnect();\r
-\r
- void RefreshAccountInfo(PAccount *Account);\r
- void LoggedIn(PAccount *Account);\r
- void Update();\r
-\r
- // new multiuser-chat implementation //\r
- int getZoneID() const;\r
- //inline int* getIP() const { return (int*) m_IP; }\r
-\r
- void SetAwaitingWarpto(bool yesno, uint16_t NewX, uint16_t NewY, uint16_t NewZ);\r
- bool GetCharAwaitingWarpto(uint16_t* PosX = NULL, uint16_t* PosY = NULL, uint16_t* PosZ = NULL);\r
-\r
- // Char broadcasted effects\r
- void InitWarpCircle();\r
- void InitCharVanish();\r
-\r
- // used for dynamic ingame testing\r
- uint8_t testval8;\r
- uint16_t testval16;\r
- uint32_t testval32;\r
-};\r
+#pragma once
+
+#include <cstdint>
+
+class ConnectionTCP;
+class ConnectionUDP;
+class PMessage;
+
+// TODO: - check that SetUDP_ID, and the mSessionID(UDP_ID_HIGH) real use,
+// and if UDP_ID and mSessionID must be synced (like in NeoX) or not
+
+enum PClientConnection
+{
+ PCC_NONE = 0,
+ PCC_GAME = 1
+};
+
+// AccountLevel handling is part of accounts.cpp
+/*
+enum PClientLevel
+{
+ PCL_BANNED = -1,
+ PCL_UNREGPLAYER = 0,
+ PCL_REGPLAYER = 1,
+ PCL_VOLUNTEER = 30,
+ PCL_GM = 50,
+ PCL_ADMIN = 100
+};
+*/
+#define DEBUG_MODES 3
+enum PDebugMode
+{
+ DBG_LOCATION = 0,
+ DBG_ITEMID = 1,
+ DBG_SUBWAY = 2,
+ DBG_ALL = DEBUG_MODES // must always be last, with DEBUG_MODES updated as needed
+};
+
+
+class PClient
+{
+ private :
+ ConnectionTCP* m_TCPConnection;
+ ConnectionUDP* m_UDPConnection;
+
+ uint32_t mAccountID;
+ int mAccountLevel;
+ uint32_t mIndex;
+ uint32_t mCharID;
+
+// uint16_t mUDP_ID;
+// uint16_t mSessionID;
+// uint16_t mTransactionID;
+
+ // AccountLevel handling is part of accounts.cpp
+ //PClientLevel mLevel;
+ int mConnection;
+ int mRemotePort;
+
+ bool mDebugMode[DEBUG_MODES];
+ // new multiuser-chat implementation //
+ int m_ZoneID;
+ //int[4] m_IP;
+
+ //*******
+ bool mActorRemoveMode;
+ //*******
+ bool mAwaitingWarpto;
+ uint16_t mTargetX;
+ uint16_t mTargetY;
+ uint16_t mTargetZ;
+ //*******
+ bool mAcceptNPCUpdates;
+ bool mZoning;
+ bool mVhcZoning;
+
+ public :
+ PClient( int Index );
+ ~PClient();
+
+ bool GetDebugMode(PDebugMode nDebugID);
+ void SetDebugMode(PDebugMode nDebugID, bool nVal = true);
+
+ bool IsAcceptingNPCUpdates();
+ void SetAcceptNPCUpdates(bool nVal);
+ bool IsZoning();
+ void SetZoning(bool nVal = true);
+ bool IsVhcZoning();
+ void SetVhcZoning(bool nVal = true);
+
+ uint32_t GetIndex() const; // better use GetID()
+ uint32_t GetID() const; // for better coherency with other classes
+ uint32_t GetLocalID() const;
+ uint32_t GetCharID() const;
+ PChar* GetChar() const;
+ bool ChangeCharLocation(uint32_t nLocation, bool DoForce = false);
+
+ int GetRemoteUDPPort() const; // Temp solution
+
+ bool IsInRemoveActorMode();
+ void SetRemoveActorMode(bool nNewValue);
+
+ void SetRemoteUDPPort(int port); // Temp solution
+ void SetCharID(int id);//NEW added
+
+ /*
+ inline uint16_t GetUDP_ID() const { return mUDP_ID; }
+ inline uint16_t GetSessionID() const { return SESSION_UDP_OFFSET + mUDP_ID ; }
+ inline uint16_t GetTransactionID() {return mTransactionID; }
+ void SetUDP_ID(int id);
+ inline void IncreaseUDP_ID() { SetUDP_ID(mUDP_ID + 1); }
+ inline void ResetTransactionID() { mTransactionID = 10170; }
+
+ inline void IncreaseTransactionID(uint8_t nInc = 1) { mTransactionID += nInc; }
+ */
+
+ // All outgoing ID's and stuff is now part of the ConnectionUDP class itself!
+ // (which is not so good.... comment from Hammag)
+ // However, we still have full access to it through these functions
+ uint16_t GetUDP_ID();
+ void SetUDP_ID( int id );
+ void IncreaseUDP_ID();
+
+ uint16_t GetSessionID();
+
+ uint16_t GetTransactionID();
+ void ResetTransactionID();
+ void IncreaseTransactionID( uint8_t nInc = 1 );
+
+ void FillInUDP_ID( PMessage* nMessage );
+
+// ************************************************************************ //
+ // AccountLevel handling is part of accounts.cpp
+ //inline PClientLevel GetLevel() const { return mLevel; }
+
+ void setTCPConnection(ConnectionTCP *conn);
+ void setUDPConnection(ConnectionUDP *conn);
+
+ ConnectionTCP* getTCPConn();
+ ConnectionUDP* getUDPConn();
+
+ void SendTCPMessage(PMessage *nMessage);
+ void FragmentAndSendUDPMessage( PMessage* nMessage, uint8_t nType );
+ void SendUDPMessage(PMessage *nMessage, bool nVIP = false);
+
+ int GetConnection() const;
+ const char *GetAddress() const;
+ uint32_t GetAccountID() const;
+ int GetAccountLevel() const;
+
+ void GameDisconnect();
+
+ void RefreshAccountInfo(PAccount *Account);
+ void LoggedIn(PAccount *Account);
+ void Update();
+
+ // new multiuser-chat implementation //
+ int getZoneID() const;
+ //inline int* getIP() const { return (int*) m_IP; }
+
+ void SetAwaitingWarpto(bool yesno, uint16_t NewX, uint16_t NewY, uint16_t NewZ);
+ bool GetCharAwaitingWarpto(uint16_t* PosX = NULL, uint16_t* PosY = NULL, uint16_t* PosZ = NULL);
+
+ // Char broadcasted effects
+ void InitWarpCircle();
+ void InitCharVanish();
+
+ // used for dynamic ingame testing
+ uint8_t testval8;
+ uint16_t testval16;
+ uint32_t testval32;
+};
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-// TODO: - these are just begining of modif, as the Client Manager is bound to be a major component for multiplayer management\r
-\r
-PClientManager::PClientManager()\r
-{\r
- //mLastID = 0;\r
-}\r
-\r
-\r
-PClientManager::~PClientManager()\r
-{\r
- /*\r
- for(PClientMap::iterator it=mClientList.begin(); it!=mClientList.end(); it++)\r
- {\r
- delete it->second;\r
- }\r
- */\r
-}\r
-\r
-bool PClientManager::addClientToList( PClient* newClient )\r
-{\r
- if ( !newClient )\r
- return false;\r
-\r
- PClientMap::const_iterator it = mClientList.find( newClient->GetLocalID() );\r
- if ( it == mClientList.end() ) // only if client not found in list\r
- {\r
- /* mClientList.insert(std::make_pair(m_LastID, newClient));\r
- ++m_LastID; */\r
-\r
- mClientList.insert( std::make_pair( newClient->GetLocalID(), newClient ) );\r
- //Console->Print(GREEN, BLACK, "Client %d added to clientmanager", newClient->GetIndex());\r
- /* if(newClient)\r
- {\r
- return true;\r
- } */\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-// Check if a zone is in use\r
-bool PClientManager::IsWorldInUse( uint32_t nWorldID ) const\r
-{\r
- for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ )\r
- {\r
- if ( it->second && it->second->GetChar() )\r
- {\r
- if ( it->second->GetChar()->GetLocation() == nWorldID )\r
- return true;\r
- }\r
- }\r
- return false;\r
-}\r
-\r
-// Check if a rawObjectId belongs to a char is in use\r
-PClient* PClientManager::GetClientByCharLocalId( uint32_t rawObjectId, uint32_t nWorldID ) const\r
-{\r
- PClient* nClient;\r
- for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ )\r
- {\r
- // note: atm, charid = clientid+1 in any zone (client.h)\r
- if ( (nClient = it->second) && ( nClient->GetLocalID() == rawObjectId ) )\r
- {\r
- if ( nClient->GetChar() && ( nClient->GetChar()->GetLocation() == nWorldID ) )\r
- return nClient;\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-void PClientManager::deleteClientFromList( uint32_t id )\r
-{\r
- PClientMap::iterator it = mClientList.find( id );\r
- if ( it != mClientList.end() )\r
- {\r
- mClientList.erase( it );\r
- //Console->Print(YELLOW, BLACK, "Client %d removed from clientmanager", ((PClient*)(it->second))->GetIndex());\r
- }\r
-}\r
-\r
-/* bool PClientManager::deleteClientFromList(PClient* delClient)\r
-{\r
- for(PClientMap::iterator it=mClientList.begin(); it!=mClientList.end(); it++)\r
- {\r
- if(delClient == it->second)\r
- {\r
- // if(it->second)\r
- // {\r
- // delete delClient;\r
- mClientList.erase( it );\r
- return true;\r
- // }\r
- }\r
- }\r
- return false;\r
-} */\r
-\r
-PClient* PClientManager::getClientByID( uint32_t id ) const\r
-{\r
- PClientMap::const_iterator it = mClientList.find( id );\r
- return (( it != mClientList.end() ) ? ( PClient* )( it->second ) : NULL );\r
-}\r
-\r
-PClient* PClientManager::getClientByChar( uint32_t CharID ) const\r
-{\r
- for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ )\r
- {\r
- if ( it->second )\r
- {\r
- if ( it->second->GetCharID() == CharID )\r
- return it->second;\r
- }\r
- }\r
- return NULL;\r
-}\r
-\r
-PClient* PClientManager::getClientByChar( const std::string &Name ) const\r
-{\r
- for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ )\r
- {\r
- if ( it->second )\r
- {\r
- if ( it->second->GetChar()->GetName() == Name )\r
- return it->second;\r
- }\r
- }\r
- return NULL;\r
-}\r
-\r
-/* uint32_t PClientManager::getClientID(PClient* _client)\r
-{\r
- for(PClientMap::iterator it=mClientList.begin(); it!=mClientList<p align="center"></p>.end(); it++)\r
- {\r
- if(_client == it->second)\r
- {\r
- return it->first;\r
- }\r
- }\r
-\r
- return -1;\r
-} */\r
-\r
-// Distance checking doesn't care for Z axis ATM\r
-int PClientManager::UDPBroadcast( PMessage* nMessage, uint32_t nZoneID, uint16_t nX, uint16_t nY, uint16_t nZ, uint16_t nMaxDist, uint32_t nSkipCharId, bool nNPCPing )\r
-{\r
- int msgCount = 0;\r
- PChar* nChar;\r
- PMessage* tmpMsg;\r
- PClient* itClient;\r
- uint16_t Dapprox;\r
-\r
- for ( PClientMap::iterator it = mClientList.begin(); it != mClientList.end(); it++ )\r
- {\r
- itClient = ( PClient* )( it->second );\r
-\r
- // Dont send NPC alive messages when client is not ready for them\r
- if ( !itClient->IsAcceptingNPCUpdates() && nNPCPing )\r
- continue;\r
-\r
- if ( itClient->getUDPConn() )\r
- {\r
- nChar = itClient->GetChar();\r
- if ( nChar && ( nChar->GetLocation() != nZoneID ) )// if limited to zone, do check\r
- continue;\r
-\r
- if (itClient->GetCharID() == nSkipCharId ) // if source of broadcast should be skipped\r
- continue;\r
-\r
- if ( nMaxDist ) // if limited to distance, do check\r
- {\r
- Dapprox = DistanceApprox(( nChar->Coords ).mX, ( nChar->Coords ).mY, ( nChar->Coords ).mZ, nX, nY, nZ );\r
- if ( Dapprox > nMaxDist )\r
- continue;\r
- }\r
-\r
- /*tmpMsg = new PMessage(nMessage->GetMaxSize());\r
- (*tmpMsg) = (*nMessage);*/\r
- tmpMsg = new PMessage( *nMessage );\r
-\r
- itClient->FillInUDP_ID( tmpMsg );\r
- itClient->SendUDPMessage( tmpMsg );\r
- ++msgCount;\r
- }\r
- }\r
-\r
- //Console->Print("Broadcast in zone %d to %d chars", nZoneID, msgCount);\r
- delete nMessage;\r
- return msgCount;\r
-}\r
-\r
-int PClientManager::UDPBroadcast( PMessage* nMessage, PClient* nClient, uint16_t nMaxDist, bool nSkipSource, bool nNPCPing )\r
-{\r
- PChar* nChar;\r
- uint32_t skipCharId = nSkipSource ? nClient->GetCharID() : 0 ;\r
-\r
- if ( nClient && ( nChar = nClient->GetChar() ) )\r
- {\r
- return UDPBroadcast( nMessage, nChar->GetLocation(), ( nChar->Coords ).mX, ( nChar->Coords ).mY, ( nChar->Coords ).mZ, nMaxDist, skipCharId, nNPCPing );\r
- }\r
- else\r
- {\r
- delete nMessage;\r
- return 0;\r
- }\r
-}\r
-\r
-int PClientManager::SendUDPZoneWelcomeToClient( PClient* nClient )\r
-{\r
- int msgCount = 0;\r
- PChar* nChar;\r
- PChar* itChar;\r
- PMessage* tmpMsg;\r
- uint32_t nZoneID;\r
- PClient* itClient;\r
-\r
- if ( nClient && ( nChar = nClient->GetChar() ) ) // if nClient is set, always use its zone\r
- {\r
- nZoneID = nChar->GetLocation();\r
- }\r
- else\r
- return 0;\r
-\r
- for ( PClientMap::iterator it = mClientList.begin(); it != mClientList.end(); it++ )\r
- {\r
- if ( nClient->GetLocalID() == it->first )\r
- continue;\r
-\r
- itClient = ( PClient* )( it->second );\r
- if ( itClient->getUDPConn() )\r
- {\r
- itChar = itClient->GetChar();\r
- if ( itChar->GetLocation() != nZoneID ) // limit to zone\r
- continue;\r
-\r
- tmpMsg = MsgBuilder->BuildCharHelloMsg( itClient );\r
-\r
- nClient->FillInUDP_ID( tmpMsg );\r
- nClient->SendUDPMessage( tmpMsg );\r
- //Console->Print("Welcome data sent from client %d to client %d", itClient->GetIndex(), nClient->GetIndex());\r
- //tmpMsg->Dump();\r
-\r
- if ( itChar->GetSeatInUse() != seat_none )\r
- {\r
- tmpMsg = MsgBuilder->BuildCharPosUpdateMsg( itClient );\r
- nClient->FillInUDP_ID( tmpMsg );\r
- nClient->SendUDPMessage( tmpMsg );\r
-\r
- //Console->Print("Sit on chair %d sent from client %d to client %d", (itChar->GetChairInUse()+1)*1024, itClient->GetIndex(), nClient->GetIndex());\r
- /*tmpMsg = MsgBuilder->BuildCharUseSeatMsg(itClient, (itChar->GetChairInUse()+1)*1024);\r
- nClient->FillInUDP_ID(tmpMsg);\r
- nClient->SendUDPMessage(tmpMsg);*/\r
- }\r
- ++msgCount;\r
- }\r
- }\r
-\r
- return msgCount;\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+// TODO: - these are just begining of modif, as the Client Manager is bound to be a major component for multiplayer management
+
+PClientManager::PClientManager()
+{
+ //mLastID = 0;
+}
+
+
+PClientManager::~PClientManager()
+{
+ /*
+ for(PClientMap::iterator it=mClientList.begin(); it!=mClientList.end(); it++)
+ {
+ delete it->second;
+ }
+ */
+}
+
+bool PClientManager::addClientToList( PClient* newClient )
+{
+ if ( !newClient )
+ return false;
+
+ PClientMap::const_iterator it = mClientList.find( newClient->GetLocalID() );
+ if ( it == mClientList.end() ) // only if client not found in list
+ {
+ /* mClientList.insert(std::make_pair(m_LastID, newClient));
+ ++m_LastID; */
+
+ mClientList.insert( std::make_pair( newClient->GetLocalID(), newClient ) );
+ //Console->Print(GREEN, BLACK, "Client %d added to clientmanager", newClient->GetIndex());
+ /* if(newClient)
+ {
+ return true;
+ } */
+ return true;
+ }
+ else
+ return false;
+}
+
+// Check if a zone is in use
+bool PClientManager::IsWorldInUse( uint32_t nWorldID ) const
+{
+ for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ )
+ {
+ if ( it->second && it->second->GetChar() )
+ {
+ if ( it->second->GetChar()->GetLocation() == nWorldID )
+ return true;
+ }
+ }
+ return false;
+}
+
+// Check if a rawObjectId belongs to a char is in use
+PClient* PClientManager::GetClientByCharLocalId( uint32_t rawObjectId, uint32_t nWorldID ) const
+{
+ PClient* nClient;
+ for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ )
+ {
+ // note: atm, charid = clientid+1 in any zone (client.h)
+ if ( (nClient = it->second) && ( nClient->GetLocalID() == rawObjectId ) )
+ {
+ if ( nClient->GetChar() && ( nClient->GetChar()->GetLocation() == nWorldID ) )
+ return nClient;
+ }
+ }
+ return 0;
+}
+
+void PClientManager::deleteClientFromList( uint32_t id )
+{
+ PClientMap::iterator it = mClientList.find( id );
+ if ( it != mClientList.end() )
+ {
+ mClientList.erase( it );
+ //Console->Print(YELLOW, BLACK, "Client %d removed from clientmanager", ((PClient*)(it->second))->GetIndex());
+ }
+}
+
+/* bool PClientManager::deleteClientFromList(PClient* delClient)
+{
+ for(PClientMap::iterator it=mClientList.begin(); it!=mClientList.end(); it++)
+ {
+ if(delClient == it->second)
+ {
+ // if(it->second)
+ // {
+ // delete delClient;
+ mClientList.erase( it );
+ return true;
+ // }
+ }
+ }
+ return false;
+} */
+
+PClient* PClientManager::getClientByID( uint32_t id ) const
+{
+ PClientMap::const_iterator it = mClientList.find( id );
+ return (( it != mClientList.end() ) ? ( PClient* )( it->second ) : NULL );
+}
+
+PClient* PClientManager::getClientByChar( uint32_t CharID ) const
+{
+ for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ )
+ {
+ if ( it->second )
+ {
+ if ( it->second->GetCharID() == CharID )
+ return it->second;
+ }
+ }
+ return NULL;
+}
+
+PClient* PClientManager::getClientByChar( const std::string &Name ) const
+{
+ for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ )
+ {
+ if ( it->second )
+ {
+ if ( it->second->GetChar()->GetName() == Name )
+ return it->second;
+ }
+ }
+ return NULL;
+}
+
+/* uint32_t PClientManager::getClientID(PClient* _client)
+{
+ for(PClientMap::iterator it=mClientList.begin(); it!=mClientList<p align="center"></p>.end(); it++)
+ {
+ if(_client == it->second)
+ {
+ return it->first;
+ }
+ }
+
+ return -1;
+} */
+
+// Distance checking doesn't care for Z axis ATM
+int PClientManager::UDPBroadcast( PMessage* nMessage, uint32_t nZoneID, uint16_t nX, uint16_t nY, uint16_t nZ, uint16_t nMaxDist, uint32_t nSkipCharId, bool nNPCPing )
+{
+ int msgCount = 0;
+ PChar* nChar;
+ PMessage* tmpMsg;
+ PClient* itClient;
+ uint16_t Dapprox;
+
+ for ( PClientMap::iterator it = mClientList.begin(); it != mClientList.end(); it++ )
+ {
+ itClient = ( PClient* )( it->second );
+
+ // Dont send NPC alive messages when client is not ready for them
+ if ( !itClient->IsAcceptingNPCUpdates() && nNPCPing )
+ continue;
+
+ if ( itClient->getUDPConn() )
+ {
+ nChar = itClient->GetChar();
+ if ( nChar && ( nChar->GetLocation() != nZoneID ) )// if limited to zone, do check
+ continue;
+
+ if (itClient->GetCharID() == nSkipCharId ) // if source of broadcast should be skipped
+ continue;
+
+ if ( nMaxDist ) // if limited to distance, do check
+ {
+ Dapprox = DistanceApprox(( nChar->Coords ).mX, ( nChar->Coords ).mY, ( nChar->Coords ).mZ, nX, nY, nZ );
+ if ( Dapprox > nMaxDist )
+ continue;
+ }
+
+ /*tmpMsg = new PMessage(nMessage->GetMaxSize());
+ (*tmpMsg) = (*nMessage);*/
+ tmpMsg = new PMessage( *nMessage );
+
+ itClient->FillInUDP_ID( tmpMsg );
+ itClient->SendUDPMessage( tmpMsg );
+ ++msgCount;
+ }
+ }
+
+ //Console->Print("Broadcast in zone %d to %d chars", nZoneID, msgCount);
+ delete nMessage;
+ return msgCount;
+}
+
+int PClientManager::UDPBroadcast( PMessage* nMessage, PClient* nClient, uint16_t nMaxDist, bool nSkipSource, bool nNPCPing )
+{
+ PChar* nChar;
+ uint32_t skipCharId = nSkipSource ? nClient->GetCharID() : 0 ;
+
+ if ( nClient && ( nChar = nClient->GetChar() ) )
+ {
+ return UDPBroadcast( nMessage, nChar->GetLocation(), ( nChar->Coords ).mX, ( nChar->Coords ).mY, ( nChar->Coords ).mZ, nMaxDist, skipCharId, nNPCPing );
+ }
+ else
+ {
+ delete nMessage;
+ return 0;
+ }
+}
+
+int PClientManager::SendUDPZoneWelcomeToClient( PClient* nClient )
+{
+ int msgCount = 0;
+ PChar* nChar;
+ PChar* itChar;
+ PMessage* tmpMsg;
+ uint32_t nZoneID;
+ PClient* itClient;
+
+ if ( nClient && ( nChar = nClient->GetChar() ) ) // if nClient is set, always use its zone
+ {
+ nZoneID = nChar->GetLocation();
+ }
+ else
+ return 0;
+
+ for ( PClientMap::iterator it = mClientList.begin(); it != mClientList.end(); it++ )
+ {
+ if ( nClient->GetLocalID() == it->first )
+ continue;
+
+ itClient = ( PClient* )( it->second );
+ if ( itClient->getUDPConn() )
+ {
+ itChar = itClient->GetChar();
+ if ( itChar->GetLocation() != nZoneID ) // limit to zone
+ continue;
+
+ tmpMsg = MsgBuilder->BuildCharHelloMsg( itClient );
+
+ nClient->FillInUDP_ID( tmpMsg );
+ nClient->SendUDPMessage( tmpMsg );
+ //Console->Print("Welcome data sent from client %d to client %d", itClient->GetIndex(), nClient->GetIndex());
+ //tmpMsg->Dump();
+
+ if ( itChar->GetSeatInUse() != seat_none )
+ {
+ tmpMsg = MsgBuilder->BuildCharPosUpdateMsg( itClient );
+ nClient->FillInUDP_ID( tmpMsg );
+ nClient->SendUDPMessage( tmpMsg );
+
+ //Console->Print("Sit on chair %d sent from client %d to client %d", (itChar->GetChairInUse()+1)*1024, itClient->GetIndex(), nClient->GetIndex());
+ /*tmpMsg = MsgBuilder->BuildCharUseSeatMsg(itClient, (itChar->GetChairInUse()+1)*1024);
+ nClient->FillInUDP_ID(tmpMsg);
+ nClient->SendUDPMessage(tmpMsg);*/
+ }
+ ++msgCount;
+ }
+ }
+
+ return msgCount;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <map>\r
-\r
-typedef std::map<uint32_t, PClient*> PClientMap;\r
-\r
-class PClientManager {\r
-private:\r
- //int mLastID;\r
- PClientMap mClientList;\r
-\r
-public:\r
- PClientManager();\r
- ~PClientManager();\r
-\r
- PClientMap::iterator getClientListBegin() { return mClientList.begin(); }\r
- PClientMap::iterator getClientListEnd() { return mClientList.end(); }\r
-\r
- bool addClientToList( PClient* newClient );\r
- //void deleteClientFromListByID(int id);\r
- void deleteClientFromList( uint32_t id );\r
- //bool deleteClientFromList(PClient* delClient); // maybe no use for this...\r
- PClient* getClientByID( uint32_t uint32_t ) const; // returns pointer to a client for further use\r
- PClient* getClientByChar( uint32_t CharID ) const;\r
- PClient* getClientByChar( const std::string &Name ) const;\r
- // int getClientID(PClient* _client); do _client->GetLocalID()\r
- bool IsWorldInUse( uint32_t nWorldID ) const; // Temp until world content fully managed by world\r
- PClient* GetClientByCharLocalId( uint32_t rawObjectId, uint32_t nWorldID ) const; // Temp (called by world) until world content fuly managed by world\r
-\r
- // each function return the number of messages sent.\r
- int UDPBroadcast( PMessage* nMessage, uint32_t nZoneID, uint16_t nX = 0, uint16_t nY = 0, uint16_t nZ = 0, uint16_t nMaxDist = 0, uint32_t nSkipCharId = 0, bool nNPCPing = false );\r
- int UDPBroadcast( PMessage* nMessage, PClient* nClient, uint16_t nMaxDist = 0, bool nSkipSource = false, bool nNPCPing = false );\r
- int SendUDPZoneWelcomeToClient( PClient* nClient );\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <map>
+
+typedef std::map<uint32_t, PClient*> PClientMap;
+
+class PClientManager {
+private:
+ //int mLastID;
+ PClientMap mClientList;
+
+public:
+ PClientManager();
+ ~PClientManager();
+
+ PClientMap::iterator getClientListBegin() { return mClientList.begin(); }
+ PClientMap::iterator getClientListEnd() { return mClientList.end(); }
+
+ bool addClientToList( PClient* newClient );
+ //void deleteClientFromListByID(int id);
+ void deleteClientFromList( uint32_t id );
+ //bool deleteClientFromList(PClient* delClient); // maybe no use for this...
+ PClient* getClientByID( uint32_t uint32_t ) const; // returns pointer to a client for further use
+ PClient* getClientByChar( uint32_t CharID ) const;
+ PClient* getClientByChar( const std::string &Name ) const;
+ // int getClientID(PClient* _client); do _client->GetLocalID()
+ bool IsWorldInUse( uint32_t nWorldID ) const; // Temp until world content fully managed by world
+ PClient* GetClientByCharLocalId( uint32_t rawObjectId, uint32_t nWorldID ) const; // Temp (called by world) until world content fuly managed by world
+
+ // each function return the number of messages sent.
+ int UDPBroadcast( PMessage* nMessage, uint32_t nZoneID, uint16_t nX = 0, uint16_t nY = 0, uint16_t nZ = 0, uint16_t nMaxDist = 0, uint32_t nSkipCharId = 0, bool nNPCPing = false );
+ int UDPBroadcast( PMessage* nMessage, PClient* nClient, uint16_t nMaxDist = 0, bool nSkipSource = false, bool nNPCPing = false );
+ int SendUDPZoneWelcomeToClient( PClient* nClient );
+};
-#pragma once\r
-\r
-/*\r
- TODO: put a single data_directory entry as the root directory for all NC data\r
-*/\r
-\r
-static const char *GameConfigTemplate[][2] = {\r
- // {option_name, default_value} if default_value is empty string, it means option is mandatory\r
- // List ends with empty string for option_name\r
- {"info_sql_host", "127.0.0.1"},\r
- {"info_sql_port", "3306"},\r
- {"info_sql_username", ""},\r
- {"info_sql_password", ""},\r
- {"info_sql_database", "infoserver"},\r
- {"game_sql_host", "127.0.0.1"},\r
- {"game_sql_port", "3306"},\r
- {"gameserver_udpport_min", "5000"},\r
- {"gameserver_udpport_max", "5099"},\r
- {"game_sql_username", ""},\r
- {"game_sql_password", ""},\r
- {"game_sql_database", "gameserver"},\r
- {"mysql_wait_timeout", "28800"}, // value of the wait_timout system variable from the MySQL server (same for game & info DB atm). 0 to disable keepalive.\r
- {"server_name", "TinNS"},\r
- {"server_ip", "127.0.0.1"}, //IP address used with clients reached without NAT (see localnet)\r
- {"no_nat_net", "0"}, // 0 is for "don't bother with NAT", else format is like 192.168.1. (with trailing dot)\r
- {"server_nat_ip", "127.0.0.1"}, //IP address used with clients reached through NAT\r
- {"gameserver_port", "12000"},\r
- {"server_version", ""},\r
- {"maxclients", "128"},\r
- {"gm_slots", "10"},\r
- //{"defs_path", "./defs"},\r
- //{"worlds_path", "./worlds"},\r
- {"nc_data_path", "."},\r
- {"isc_method", "1"},\r
- {"isc_server_id", ""},\r
- {"isc_update_intervall", "60"},\r
- {"isc_delayed_update_intervall", "6"}, // the purpose of this option is to avoid multiple infoDB update when client just disconnects/reconnects during login phases\r
- {"isc_infoserverip", "127.0.0.1"},\r
- {"isc_infoserverport", "9991"},\r
- {"isc_connect_pw", "change_me"}, // make default value empty when isc ready\r
- {"dev_debug", "0"}, // set to non-zero to activate development outputs\r
- {"auto_save_period", "300"},\r
- {"new_char_location", "1085"},\r
- {"broadcast_new", "0"},\r
- {"broadcast_new_hidestaff", "0"},\r
- {"max_cash", "20000000"},\r
- {"item_price", "70"},\r
- {"require_validation", "0"},\r
- {"minlevel", "0"},\r
- {"username_filter", "^[a-z][\\w\\-]{2,14}$"},\r
- {"password_filter", "^[[:graph:]]{3,15}$"},\r
- {"charname_filter", "^[a-z]+([\\-\\ ]?[a-z]+){0,2}$"},\r
- {"clanname_filter", "^[a-z][\\w\\-\\ ]{2,14}$"},\r
-\r
-// For futur use:\r
-// {"max_chars_per_account", "4"},\r
-// {"multiple_logins_per_account", "0"}, // 0=nobody, 1=gm+ only, 2=everybody\r
-// {"multiple_ingames_per_account", "0"}, // 0=nobody, 1=gm+ only, 2=everybody (needs multiple logins ...)\r
-\r
-// {"local_chat_range", "500"},\r
-\r
- {"", ""} // do not change this line (end mark)\r
-};\r
-\r
-static const char *CommandsTemplate[][2] = {\r
- {"debug", "100"},\r
- {"settime", "100"},\r
- {"warp", "0"},\r
-// {"delworlditem", "100"},\r
-// {"addworlditem", "100"},\r
-// {"adddoor", "100"},\r
- {"online", "0"},\r
- {"sendchat", "50"},\r
- {"skin", "50"},\r
- {"effect", "0"},\r
- {"speed", "0"},\r
- {"color", "0"},\r
- {"brightness", "0"},\r
- {"remove", "50"},\r
- {"rehash", "100"},\r
- {"uptime", "0"},\r
- {"version", "0"},\r
- {"broadcast", "100"},\r
- {"kick", "50"},\r
- {"info", "50"},\r
- {"setlevel", "100"},\r
- {"warpto", "50"},\r
- {"recall", "50"},\r
-\r
- {"ban", "50"}, // Set ban\r
- {"unban", "50"}, // Remove ban\r
- {"listbans", "50"}, // Show list of all banned accounts\r
- {"shun", "50"}, // Quiet all chat\r
- {"unshun", "50"}, // UnQuiet all chat\r
- {"jail", "50"}, // "Jail" someone (Regants ^^)\r
- {"unjail", "50"}, // Move him out\r
- {"teleport", "50"}, // Warp targetplayer XX to zone YY\r
- {"givemoney", "50"}, // Warp targetplayer XX to zone YY\r
- {"takemoney", "50"}, // Warp targetplayer XX to zone YY\r
- {"spawnactor", "50"}, // Spawn given actor next to player\r
-\r
- {"weather", "50"}, // Set weather in a zone\r
- {"setmainskill", "50"}, // Set mainskill (INT,PSI,DEX,CON,STR) of own char or someone else\r
- {"setsubskill", "50"}, // Set subskill (BRT,HCK,PPU,...) of own char or someone else\r
- {"npc", "50"}, // do actions with NPCs\r
-\r
- {"", ""} // do not change this line (end mark)\r
-};\r
+#pragma once
+
+/*
+ TODO: put a single data_directory entry as the root directory for all NC data
+*/
+
+static const char *GameConfigTemplate[][2] = {
+ // {option_name, default_value} if default_value is empty string, it means option is mandatory
+ // List ends with empty string for option_name
+ {"info_sql_host", "127.0.0.1"},
+ {"info_sql_port", "3306"},
+ {"info_sql_username", ""},
+ {"info_sql_password", ""},
+ {"info_sql_database", "infoserver"},
+ {"game_sql_host", "127.0.0.1"},
+ {"game_sql_port", "3306"},
+ {"gameserver_udpport_min", "5000"},
+ {"gameserver_udpport_max", "5099"},
+ {"game_sql_username", ""},
+ {"game_sql_password", ""},
+ {"game_sql_database", "gameserver"},
+ {"mysql_wait_timeout", "28800"}, // value of the wait_timout system variable from the MySQL server (same for game & info DB atm). 0 to disable keepalive.
+ {"server_name", "TinNS"},
+ {"server_ip", "127.0.0.1"}, //IP address used with clients reached without NAT (see localnet)
+ {"no_nat_net", "0"}, // 0 is for "don't bother with NAT", else format is like 192.168.1. (with trailing dot)
+ {"server_nat_ip", "127.0.0.1"}, //IP address used with clients reached through NAT
+ {"gameserver_port", "12000"},
+ {"server_version", ""},
+ {"maxclients", "128"},
+ {"gm_slots", "10"},
+ //{"defs_path", "./defs"},
+ //{"worlds_path", "./worlds"},
+ {"nc_data_path", "."},
+ {"isc_method", "1"},
+ {"isc_server_id", ""},
+ {"isc_update_intervall", "60"},
+ {"isc_delayed_update_intervall", "6"}, // the purpose of this option is to avoid multiple infoDB update when client just disconnects/reconnects during login phases
+ {"isc_infoserverip", "127.0.0.1"},
+ {"isc_infoserverport", "9991"},
+ {"isc_connect_pw", "change_me"}, // make default value empty when isc ready
+ {"dev_debug", "0"}, // set to non-zero to activate development outputs
+ {"auto_save_period", "300"},
+ {"new_char_location", "1085"},
+ {"broadcast_new", "0"},
+ {"broadcast_new_hidestaff", "0"},
+ {"max_cash", "20000000"},
+ {"item_price", "70"},
+ {"require_validation", "0"},
+ {"minlevel", "0"},
+ {"username_filter", "^[a-z][\\w\\-]{2,14}$"},
+ {"password_filter", "^[[:graph:]]{3,15}$"},
+ {"charname_filter", "^[a-z]+([\\-\\ ]?[a-z]+){0,2}$"},
+ {"clanname_filter", "^[a-z][\\w\\-\\ ]{2,14}$"},
+
+// For futur use:
+// {"max_chars_per_account", "4"},
+// {"multiple_logins_per_account", "0"}, // 0=nobody, 1=gm+ only, 2=everybody
+// {"multiple_ingames_per_account", "0"}, // 0=nobody, 1=gm+ only, 2=everybody (needs multiple logins ...)
+
+// {"local_chat_range", "500"},
+
+ {"", ""} // do not change this line (end mark)
+};
+
+static const char *CommandsTemplate[][2] = {
+ {"debug", "100"},
+ {"settime", "100"},
+ {"warp", "0"},
+// {"delworlditem", "100"},
+// {"addworlditem", "100"},
+// {"adddoor", "100"},
+ {"online", "0"},
+ {"sendchat", "50"},
+ {"skin", "50"},
+ {"effect", "0"},
+ {"speed", "0"},
+ {"color", "0"},
+ {"brightness", "0"},
+ {"remove", "50"},
+ {"rehash", "100"},
+ {"uptime", "0"},
+ {"version", "0"},
+ {"broadcast", "100"},
+ {"kick", "50"},
+ {"info", "50"},
+ {"setlevel", "100"},
+ {"warpto", "50"},
+ {"recall", "50"},
+
+ {"ban", "50"}, // Set ban
+ {"unban", "50"}, // Remove ban
+ {"listbans", "50"}, // Show list of all banned accounts
+ {"shun", "50"}, // Quiet all chat
+ {"unshun", "50"}, // UnQuiet all chat
+ {"jail", "50"}, // "Jail" someone (Regants ^^)
+ {"unjail", "50"}, // Move him out
+ {"teleport", "50"}, // Warp targetplayer XX to zone YY
+ {"givemoney", "50"}, // Warp targetplayer XX to zone YY
+ {"takemoney", "50"}, // Warp targetplayer XX to zone YY
+ {"spawnactor", "50"}, // Spawn given actor next to player
+
+ {"weather", "50"}, // Set weather in a zone
+ {"setmainskill", "50"}, // Set mainskill (INT,PSI,DEX,CON,STR) of own char or someone else
+ {"setsubskill", "50"}, // Set subskill (BRT,HCK,PPU,...) of own char or someone else
+ {"npc", "50"}, // do actions with NPCs
+
+ {"", ""} // do not change this line (end mark)
+};
-#include "GameServer/Includes.hxx"\r
-#include "GameServer/Definitions/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-/* --- PContainerEntry class --- */\r
-\r
-PContainerEntry::PContainerEntry( PItem* nItem, uint8_t X, uint8_t Y, uint32_t nInvID, bool SetDirty )\r
-{\r
- mItem = nItem;\r
- mPosX = X;\r
- mPosY = Y;\r
- mInvID = nInvID;\r
- mDirtyFlag = SetDirty;\r
-}\r
-\r
-PContainerEntry::PContainerEntry( MYSQL_ROW row )\r
-{\r
- mItem = NULL;\r
- mInvID = atoi( row[i_invid] );\r
- mPosX = atoi( row[i_x] );\r
- mPosY = atoi( row[i_y] );\r
- mDirtyFlag = false;\r
-\r
- uint32_t nItemID = atoi( row[i_itemid] );\r
- uint8_t nStackSize = atoi( row[i_qty] );\r
- // = std::atoi(row[i_type]);\r
- uint8_t CurDur = atoi( row[i_curdur] );\r
- uint8_t Dmg = atoi( row[i_dmg] );\r
- uint8_t Freq = atoi( row[i_freq] );\r
- uint8_t Hand = atoi( row[i_hand] );\r
- uint8_t Rng = atoi( row[i_rng] );\r
- uint8_t Dur = atoi( row[i_maxdur] );\r
-\r
- mItem = new PItem( nItemID, nStackSize, CurDur, Dur, Dmg, Freq, Hand, Rng );\r
-}\r
-\r
-PContainerEntry::~PContainerEntry()\r
-{\r
- delete mItem;\r
-}\r
-\r
-bool PContainerEntry::SQLSave( uint32_t CharID, uint32_t InvLoc )\r
-{\r
- std::string query, queryv;\r
-\r
- queryv += Ssprintf( " inv_charid='%u',inv_loc='%u',inv_x='%u',inv_y='%u'", CharID, InvLoc, mPosX, mPosY );\r
- queryv += Ssprintf( ",inv_itemid='%u',inv_qty='%u'", mItem->mItemID, mItem->mStackSize );\r
- //queryv += Ssprintf( ",inv_type='%u'", 0 );\r
- queryv += Ssprintf( ",inv_cdur='%u'", mItem->mCurDuration );\r
- queryv += Ssprintf( ",inv_dmg='%u'", mItem->mDamages );\r
- queryv += Ssprintf( ",inv_frq='%u'", mItem->mFrequency );\r
- queryv += Ssprintf( ",inv_hnd='%u'", mItem->mHandling );\r
- queryv += Ssprintf( ",inv_rng='%u'", mItem->mRange );\r
- queryv += Ssprintf( ",inv_mdur='%u'", mItem->mMaxDuration );\r
-\r
- if ( mInvID )\r
- {\r
- query = "UPDATE inventory SET " + queryv;\r
- query += Ssprintf( " WHERE inv_id='%u' LIMIT 1;", mInvID );\r
- }\r
- else\r
- {\r
- query = "INSERT INTO inventory SET " + queryv + ";";\r
- }\r
-\r
- if ( MySQL->GameQuery( query.c_str() ) )\r
- {\r
- Console->Print( RED, BLACK, "PContainerEntry::SQLSave could not add/update some inventory item in the database" );\r
- Console->Print( "Query was:" );\r
- Console->Print( "%s", query.c_str() );\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
- else\r
- {\r
- if ( !mInvID )\r
- {\r
- mInvID = MySQL->GetLastGameInsertId();\r
- if ( gDevDebug )\r
- Console->Print( GREEN, BLACK, "New item %d added to inventory DB", mInvID );\r
- }\r
-//Console->Print(YELLOW, BLACK, "PContainerEntry::SQLSave - Query was:");\r
-//Console->Print(YELLOW, BLACK, "%s", query.c_str());\r
- mDirtyFlag = false;\r
- return true;\r
- }\r
-}\r
-\r
-bool PContainerEntry::SQLDelete()\r
-{\r
- std::string query;\r
-\r
- if ( mInvID )\r
- {\r
- query = Ssprintf( "DELETE FROM inventory WHERE inv_id='%u' LIMIT 1;", mInvID );\r
-\r
- if ( MySQL->GameQuery( query.c_str() ) )\r
- {\r
- Console->Print( RED, BLACK, "PContainerEntry::SQLDelete could not delete some container item from the database" );\r
- Console->Print( "Query was:" );\r
- Console->Print( "%s", query.c_str() );\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
- else\r
- {\r
- if ( gDevDebug )\r
- Console->Print( GREEN, BLACK, "Item %d deleted from container DB", mInvID );\r
- mInvID = 0;\r
- delete mItem;\r
- mItem = NULL;\r
-\r
- mDirtyFlag = false;\r
- return true;\r
- }\r
- }\r
- else\r
- {\r
- Console->Print( YELLOW, BLACK, "PContainerEntry::SQLDelete: Item was not in inventory DB" );\r
- return true;\r
- }\r
-}\r
-\r
-/* --- PContainer class --- */\r
-\r
-PContainer::PContainer( uint8_t nMaxSlots )\r
-{\r
- mMaxSlots = ( nMaxSlots > CONTAINER_MAX_SIZE ? CONTAINER_MAX_SIZE : nMaxSlots ) ;\r
- if ( mMaxSlots )\r
- mContContent = new std::vector< PContainerEntry* >( mMaxSlots, NULL );\r
- else\r
- mContContent = new std::vector< PContainerEntry* >;\r
- mCharID = 0;\r
- mInvLoc = 0;\r
- mExclusiveUseCharID = 0;\r
- mDirtyFlag = false;\r
-}\r
-\r
-PContainer::~PContainer()\r
-{\r
- for ( uint8_t i = 0; i < mContContent->size(); ++i )\r
- delete mContContent->at( i );\r
-\r
- if ( mExclusiveUseCharID )\r
- Console->Print( RED, BLACK, "[ERROR] PContainer::~PContainer: Char %d still has exclusive access to container !!! Bad Pointer error will happen.", mExclusiveUseCharID );\r
-}\r
-\r
-bool PContainer::AddEntry( PContainerEntry* NewEntry, uint8_t nSlotId )\r
-{\r
- if ( IsSlotAllowed( nSlotId ) )\r
- {\r
- for ( uint8_t i = mContContent->size(); i <= nSlotId; ++i ) // Extend as needed\r
- mContContent->push_back( static_cast<PContainerEntry*>(NULL) );\r
- if ( mContContent->at( nSlotId ) )\r
- {\r
- Console->Print( RED, BLACK, "[Warning] PContainer::AddEntry: Target entry already %d in use !!!", nSlotId );\r
- return false;\r
- }\r
- mContContent->at( nSlotId ) = NewEntry;\r
- mDirtyFlag = true;\r
- this->SetEntryPosXY( NewEntry, nSlotId, NewEntry->mPosX, NewEntry->mPosY );\r
- return true;\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[Warning] PContainer::AddEntry: Target entry %d not allowed (max = %d) !!!", nSlotId, mMaxSlots );\r
- return false;\r
- }\r
- /* --- degug only ---\r
- Console->Print(GREEN, BLACK, "PContainer::AddEntry: added item %d at pos (%d,%d)", NewEntry->mItem->GetItemID(), NewEntry->mPosX, NewEntry->mPosY);\r
-\r
- Dump();\r
- --- --- */\r
-}\r
-\r
-void PContainer::SetEntryPosXY( PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX, uint8_t nPosY )\r
-{\r
- nPosX = nPosY;\r
- nEntry->Set2DPos( nSlotId, 0 );\r
- mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag;\r
-}\r
-\r
-PContainerEntry* PContainer::RemoveEntry( uint8_t nSlotId )\r
-{\r
- PContainerEntry* tEntry = NULL;\r
-\r
- if ( nSlotId < mContContent->size() )\r
- {\r
- tEntry = mContContent->at( nSlotId );\r
- mContContent->at( nSlotId ) = NULL;\r
- }\r
- return tEntry;\r
-}\r
-\r
-bool PContainer::GetFreeSlot( uint8_t* nSlotId )\r
-{\r
- return IsSlotFree( *nSlotId );\r
-}\r
-\r
-void PContainer::Compact( uint8_t startSlotId )\r
-{\r
- uint8_t i, j;\r
- PContainerEntry* tEntry;\r
-\r
- for ( i = j = startSlotId; i < mContContent->size(); ++i )\r
- {\r
- if ( mContContent->at( i ) )\r
- {\r
- if ( j < i )\r
- {\r
- mContContent->at( j ) = tEntry = mContContent->at( i );\r
- this->SetEntryPosXY( tEntry, j, tEntry->mPosX, tEntry->mPosX );\r
- mContContent->at( i ) = NULL;\r
- mDirtyFlag = true;\r
- }\r
- ++j;\r
- }\r
- }\r
-\r
- if ( !mMaxSlots ) // reduce size only if not fixed-size\r
- {\r
- for ( ; j < i; ++j )\r
- mContContent->pop_back();\r
- }\r
-}\r
-\r
-bool PContainer::StartUse( uint32_t nExclusiveUseCharID )\r
-{\r
- if ( mExclusiveUseCharID )\r
- return false;\r
- else\r
- {\r
- mExclusiveUseCharID = nExclusiveUseCharID;\r
- return true;\r
- }\r
-}\r
-\r
-bool PContainer::EndUse( uint32_t nExclusiveUseCharID )\r
-{\r
- if ( nExclusiveUseCharID == mExclusiveUseCharID )\r
- {\r
- mExclusiveUseCharID = 0;\r
- return true;\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[Warning] PContainer::EndUse called with CharID %d when CharID %d had exclusive use", nExclusiveUseCharID, mExclusiveUseCharID );\r
- return false;\r
- }\r
-}\r
-\r
-bool PContainer::SQLLoad()\r
-{\r
- if ( !mCharID )\r
- {\r
- return false;\r
- }\r
-\r
- MYSQL_RES *result;\r
- MYSQL_ROW row;\r
- char query[1024];\r
- PContainerEntry* NewEntry;\r
- bool SaveDirtyFlag;\r
- uint8_t nSlotId;\r
- //uint8_t nPosX, nPosY, nSizeX, nSizeY;\r
-\r
- /*if (!mContContent.empty())\r
- {\r
- Console->Print(RED, BLACK, "PContainer::SQLLoad: We don't want to load inventory on non-empty inventory for char %d", mCharID);\r
- return false;\r
- }*/\r
-\r
- snprintf( query, 1024, "SELECT * FROM inventory WHERE inv_charid='%d' AND inv_loc='%d' ORDER BY inv_x ASC", mCharID, mInvLoc );\r
- result = MySQL->GameResQuery( query );\r
- if ( result == NULL )\r
- {\r
- Console->Print( RED, BLACK, "[Warning] PContainer::SQLLoad could not load inventory from the database" );\r
- Console->Print( "Query was:" );\r
- Console->Print( "%s", query );\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
- while (( row = mysql_fetch_row( result ) ) )\r
- {\r
- NewEntry = new PContainerEntry( row );\r
- if ( NewEntry->mItem->GetItemID() )\r
- {\r
- nSlotId = NewEntry->mPosX;\r
- SaveDirtyFlag = mDirtyFlag;\r
-\r
- if ( ! this->GetFreeSlot( &nSlotId ) || ! this->AddEntry( NewEntry, nSlotId ) )\r
- {\r
- Console->Print( YELLOW, BLACK, "[Warning] PContainer::SQLLoad: Can't add item %d in slot %d of char %d inventory", NewEntry->mItem->GetItemID(), nSlotId, mCharID );\r
- delete NewEntry;\r
- mDirtyFlag = SaveDirtyFlag;\r
- }\r
- else\r
- {\r
- mDirtyFlag = SaveDirtyFlag || ( nSlotId != NewEntry->mPosX );\r
- }\r
- }\r
- else\r
- {\r
- Console->Print( YELLOW, BLACK, "[Notice] Invalid item in DB (inv_id = %d) - Ignored", NewEntry->mInvID );\r
- delete NewEntry;\r
- }\r
- }\r
- MySQL->FreeGameSQLResult( result );\r
- return true;\r
-}\r
-\r
-bool PContainer::SQLSave()\r
-{\r
- if ( !mCharID )\r
- return false;\r
-\r
- PContainerEntry* ContEntry;\r
- bool SavedOK = true;\r
-\r
- for ( uint8_t i = 0; i < mContContent->size(); ++i )\r
- {\r
- if (( ContEntry = mContContent->at( i ) ) )\r
- {\r
- if (( ContEntry->mDirtyFlag ) )\r
- {\r
- SavedOK = SavedOK && ContEntry->SQLSave( mCharID, mInvLoc );\r
- }\r
- }\r
- }\r
-\r
- if ( SavedOK )\r
- {\r
- mDirtyFlag = false;\r
- }\r
- return SavedOK;\r
-}\r
-\r
-bool PContainer::IsSlotFree( uint8_t nSlotId )\r
-{\r
- if ( !IsSlotAllowed( nSlotId ) )\r
- return false;\r
-\r
- if ( nSlotId >= mContContent->size() )\r
- return true;\r
- else\r
- return !( mContContent->at( nSlotId ) );\r
-}\r
-\r
-bool PContainer::AddItem( PItem* NewItem, uint32_t nInvID, uint8_t nPosX, uint8_t nPosY, bool SetDirty )\r
-{\r
- /* --- auto stacking not implemented yet\r
- 1 - if stackable, check if same item(S) exists\r
- 2 - - if exist\r
- 3 - - - add to stack\r
- 4 - - - if no new stack remains, update LastPutXY & return true\r
- 5 - find an empty space\r
- 6 -\r
- x - put in new space, update LastPutXY & return true\r
-\r
- */\r
-\r
- if ( NewItem->GetItemID() == 0 )\r
- {\r
- Console->Print( RED, BLACK, "[Warning] PContainer::AddItem: invalid item : ID 0" );\r
- return false;\r
- }\r
-\r
- PContainerEntry* NewEntry = new PContainerEntry( NewItem, nPosX, nPosY, nInvID, SetDirty );\r
-\r
- if ( this->GetFreeSlot( &nPosX ) && this->AddEntry( NewEntry, nPosX ) ) // !!!! nPosX not good\r
- return true;\r
- else\r
- {\r
- delete NewEntry;\r
- return false;\r
- }\r
-}\r
-\r
-bool PContainer::MoveItem( uint8_t srcSlotId, uint8_t nCount, PContainer* dstContainer, uint8_t dstSlotId, uint8_t nPosX, uint8_t nPosY )\r
-{\r
- if ( dstContainer == this )\r
- return this->MoveItem( srcSlotId, nCount, dstSlotId );\r
- else if ( dstContainer->GetFreeSlot( &dstSlotId ) )\r
- {\r
- uint8_t savePosX, savePosY;\r
- PContainerEntry* tEntry = this->GetEntry( srcSlotId );\r
- if ( tEntry )\r
- {\r
- tEntry->Get2DPos( &savePosX, &savePosY );\r
- tEntry->Set2DPos( nPosX, nPosY );\r
- if ( !dstContainer->AddEntry( tEntry, dstSlotId ) )\r
- {\r
- tEntry->Set2DPos( savePosX, savePosY );\r
- Console->Print( RED, BLACK, "[Warning] PContainer::MoveItem - Couldn't add entry !" );\r
- return false;\r
- }\r
- tEntry->Get2DPos( &nPosX, &nPosY );\r
- tEntry->Set2DPos( savePosX, savePosY );\r
- RemoveEntry( srcSlotId );\r
- tEntry->Set2DPos( nPosX, nPosY );\r
-\r
- if ( dstContainer->mCharID != this->mCharID ) // save at once if owner changes\r
- {\r
- if ( !tEntry->SQLSave( dstContainer->mCharID, dstContainer->mInvLoc ) ) // TODO: improve to manage non-persistent containers\r
- {\r
- Console->Print( RED, BLACK, "[Warning] PContainer::MoveItem - Moved entry not saved" );\r
- }\r
- //else\r
- //{\r
- // Console->Print(GREEN, BLACK, "[Succes] PContainer::MoveItem - Moved entry saved");\r
- //}\r
- }\r
- return true;\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[Warning] trying to move invalid entry %d", srcSlotId );\r
- return false;\r
- }\r
- }\r
- return false;\r
-}\r
-\r
-// !!! Not partial move yet !!!\r
-bool PContainer::MoveItem( uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId )\r
-{\r
- if ( !( IsSlotAllowed( srcSlotId ) && IsSlotAllowed( dstSlotId ) ) )\r
- return false;\r
-\r
- if ( srcSlotId == dstSlotId )\r
- return true;\r
-\r
- if (( mContContent->at( srcSlotId ) )\r
- && ( mContContent->at( srcSlotId )->mItem->GetStackSize() >= nCount )\r
- && IsSlotFree( dstSlotId ) )\r
- {\r
- PContainerEntry* tEntry = mContContent->at( dstSlotId ) = mContContent->at( srcSlotId );\r
- tEntry->mPosX = dstSlotId;\r
- tEntry->mPosY = 0;\r
- tEntry->mDirtyFlag = true;\r
- mContContent->at( srcSlotId ) = NULL;\r
- mDirtyFlag = true;\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-std::vector< PContainerEntry* >* PContainer::GetEntries()\r
-{\r
- std::vector< PContainerEntry* >* Entries = new std::vector< PContainerEntry* >;\r
-\r
- for ( uint8_t i = 0; i < mContContent->size(); ++i )\r
- {\r
- if ( mContContent->at( i ) )\r
- Entries->push_back( mContContent->at( i ) );\r
- }\r
-\r
- return Entries;\r
-}\r
-\r
-PContainerEntry* PContainer::GetEntry( uint8_t nSlotId )\r
-{\r
- if ( nSlotId >= mContContent->size() )\r
- return NULL;\r
-\r
- return mContContent->at( nSlotId );\r
-}\r
-\r
-PItem* PContainer::GetItem( uint8_t nSlotId )\r
-{\r
- PContainerEntry* tEntry = this->GetEntry( nSlotId );\r
- return ( tEntry ? tEntry->mItem : NULL );\r
-}\r
-\r
-uint8_t PContainer::RandomFill( uint8_t nItemCount, int nItemContainerDefIndex )\r
-{\r
- PItem* nItem = NULL;\r
- const PDefItems* nItemDef;\r
- uint32_t nItemSeqId;\r
- uint8_t CreatedCount = 0;\r
-\r
- if ( !nItemCount )\r
- nItemCount = mMaxSlots;\r
- if ( !nItemCount )\r
- nItemCount = CONTAINER_MAX_SIZE;\r
-\r
- if ( nItemContainerDefIndex >= 0 )\r
- {\r
- int newItemIdx, newItemIndex;\r
- uint8_t newItemQuality;\r
-\r
- const PDefItemContainer* containerDef = GameDefs->ItemContainers()->GetDef( nItemContainerDefIndex );\r
- if ( containerDef )\r
- {\r
- for ( uint8_t i = 0; i < nItemCount; ++i )\r
- {\r
- newItemIdx = containerDef->GetRandomItemIdx();\r
- if ( newItemIdx >= 0 )\r
- {\r
- newItemIndex = containerDef->GetItemId( newItemIdx );\r
- newItemQuality = ( uint8_t )( 255 & int( 255.0 * containerDef->GetQuality( newItemIdx ) ) );\r
- if ( newItemIndex <= 0 ) // Item group\r
- {\r
- newItemIndex = GameDefs->Items()->GetRandomItemIdFromGroup( -newItemIndex );\r
- }\r
- nItem = new PItem( newItemIndex, 1, 255, newItemQuality, newItemQuality, newItemQuality, newItemQuality, 255 );\r
- if ( nItem->GetItemID() )\r
- {\r
- if ( this->AddItem( nItem ) )\r
- {\r
- ++CreatedCount;\r
- }\r
- else\r
- {\r
- Console->Print( YELLOW, BLACK, "[Warning] Couldn't add item %d at pos %d", nItem->GetItemID(), i );\r
- delete nItem;\r
- }\r
- }\r
- }\r
- }\r
- }\r
- else\r
- Console->Print( YELLOW, BLACK, "[Warning] Container def not found: %d", nItemContainerDefIndex );\r
- }\r
- else\r
- {\r
- int NumItemsDefs = GameDefs->Items()->GetNumDefs();\r
-\r
- for ( uint8_t i = 0; i < nItemCount; ++i )\r
- {\r
- nItemSeqId = GetRandom( NumItemsDefs, 1 );\r
-\r
- if (( nItemDef = GameDefs->Items()->GetDefBySeqIndex( nItemSeqId ) ) )\r
- {\r
- nItem = new PItem( nItemDef->GetIndex(), 1, 255, 255, 255, 255, 255, 255 );\r
- if ( nItem->GetItemID() )\r
- {\r
- if ( this->AddItem( nItem ) )\r
- {\r
- ++CreatedCount;\r
- }\r
- else\r
- {\r
- //Console->Print(GREEN, BLACK, "Couldn't add item % d at pos % d", nItem->GetItemID(), i);\r
- delete nItem;\r
- }\r
- }\r
- }\r
- else\r
- Console->Print( RED, BLACK, "[Warning] PContainer::RandomFill Couldn't find item for SEQ %d", nItemSeqId );\r
- }\r
- }\r
- return CreatedCount;\r
-}\r
-\r
-void PContainer::Dump()\r
-{\r
- PContainerEntry* tmpEntry;\r
- PItem* tmpItem;\r
- uint8_t i;\r
- //uint8_t y, x;\r
-\r
- for ( i = 0; i < mContContent->size(); ++i )\r
- {\r
- if (( tmpEntry = mContContent->at( i ) ) )\r
- {\r
- tmpItem = tmpEntry->mItem;\r
- Console->Print( GREEN, BLACK, "%d: (%d,%d) (%d x %d) Item %d (InvID %d) %s %s", i, tmpEntry->mPosX, tmpEntry->mPosY, tmpItem->GetSizeX(), tmpItem->GetSizeY(), tmpItem->GetItemID(), tmpEntry->mInvID, tmpItem->GetName().c_str(), tmpEntry->mDirtyFlag ? "[*]" : "" );\r
- }\r
- }\r
-\r
- if ( mDirtyFlag )\r
- Console->Print( GREEN, BLACK, "Dirty" );\r
- Console->Print( GREEN, BLACK, "------------------------------------" );\r
-}\r
-\r
-/* --- PContainerWithHoles class --- */\r
-\r
-\r
-/* --- PContainerAutoCompact --- */\r
-PContainerEntry* PContainerAutoCompact::RemoveEntry( uint8_t nSlotId )\r
-{\r
- PContainerEntry* tEntry = NULL;\r
-\r
- if ( nSlotId < mContContent->size() )\r
- {\r
- tEntry = mContContent->at( nSlotId );\r
- mContContent->at( nSlotId ) = NULL;\r
- if ( nSlotId == ( mContContent->size() - 1 ) )\r
- mContContent->pop_back();\r
- else\r
- Compact( nSlotId );\r
- }\r
- return tEntry;\r
-}\r
-\r
-bool PContainerAutoCompact::GetFreeSlot( uint8_t* nSlotId ) // not optimal. A "first free from end" would be better at PContainer level\r
-{\r
- bool Found = false;\r
-\r
- for ( *nSlotId = 0; *nSlotId < mContContent->size(); ++*nSlotId )\r
- if ( ! mContContent->at( *nSlotId ) )\r
- {\r
- Found = true;\r
- break;\r
- }\r
- return ( Found || IsSlotAllowed( *nSlotId ) );\r
-}\r
-\r
-bool PContainerAutoCompact::MoveItem( uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId )\r
-{\r
- srcSlotId = nCount = dstSlotId;\r
- return false;\r
-}\r
-\r
-/* --- PContainer2D class --- */\r
-\r
-void PContainer2D::SetEntryPosXY( PContainerEntry* nEntry, uint8_t /*nSlotId*/, uint8_t nPosX, uint8_t nPosY )\r
-{\r
- //nSlotId = nSlotId;\r
- if (( nPosX >= INV_BACKPACK_COLS ) || ( nPosY == 255 ) )\r
- {\r
- nPosX = nPosY = 0;\r
- }\r
- nEntry->Set2DPos( nPosX, nPosY );\r
- mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag;\r
-}\r
-\r
-/* --- PContainer2DWorkaround --- */\r
-/////\r
-PContainer2DWorkaround::PContainer2DWorkaround( uint8_t nMaxSlots ) : PContainerWithHoles( nMaxSlots )\r
-{\r
- mNextFreeSlot = 0;\r
- mMaxCols = 254;\r
- mMaxRows = 254;\r
- mRows = 0;\r
- AddRow();\r
-}\r
-\r
-PContainer2DWorkaround::~PContainer2DWorkaround()\r
-{\r
- for ( int i = 0; i < mRows; i++ )\r
- delete mContSpace[i];\r
-}\r
-\r
-bool PContainer2DWorkaround::AddEntry( PContainerEntry* tEntry, uint8_t nSlotId )\r
-{\r
- if ( IsSlotAllowed( nSlotId ) )\r
- {\r
- if ( FindValid2DPos( tEntry ) )\r
- {\r
- for ( uint8_t i = mContContent->size(); i <= nSlotId; ++i ) // Extend as needed\r
- mContContent->push_back( static_cast<PContainerEntry *>(NULL) );\r
- if ( mContContent->at( nSlotId ) )\r
- {\r
- Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: Target entry already %d in use !!!", nSlotId );\r
- return false;\r
- }\r
- mContContent->at( nSlotId ) = tEntry;\r
- mDirtyFlag = true;\r
- //this->SetEntryPosXY(tEntry, nSlotId, tEntry->mPosX, tEntry->mPosY);\r
- mDirtyFlag = mDirtyFlag || tEntry->mDirtyFlag;\r
- SetUsed( tEntry );\r
- return true;\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: No 2D space left !!!", nSlotId, mMaxSlots );\r
- return false;\r
- }\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: Target entry %d not allowed (max = %d) !!!", nSlotId, mMaxSlots );\r
- return false;\r
- }\r
-\r
-}\r
-\r
-PContainerEntry* PContainer2DWorkaround::RemoveEntry( uint8_t nSlotId )\r
-{\r
- PContainerEntry* tEntry = NULL;\r
-\r
- if ( nSlotId < mContContent->size() )\r
- {\r
- tEntry = mContContent->at( nSlotId );\r
- mContContent->at( nSlotId ) = NULL;\r
- //Console->Print(YELLOW, BLACK, "Cleaning (%d,%d) (%d x %d)", tEntry->mPosX, tEntry->mPosY, tEntry->mItem->GetSizeX(), tEntry->mItem->GetSizeY());\r
- SetUsed( tEntry, false );\r
- }\r
- return tEntry;\r
-}\r
-\r
-bool PContainer2DWorkaround::GetFreeSlot( uint8_t* nSlotId )\r
-{\r
- if ( IsSlotAllowed( mNextFreeSlot ) )\r
- {\r
- *nSlotId = mNextFreeSlot++;\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-void PContainer2DWorkaround::SetEntryPosXY( PContainerEntry* nEntry, uint8_t /*nSlotId*/, uint8_t nPosX, uint8_t nPosY )\r
-{\r
- //nSlotId = nSlotId;\r
- if (( nPosX == 255 ) && ( nPosY == 255 ) )\r
- {\r
- nEntry->Set2DPos( 255, 255 );\r
- }\r
- else\r
- {\r
- if (( nPosX >= mMaxCols ) || ( nPosY >= mMaxRows ) )\r
- {\r
- nPosX = nPosY = 0;\r
- }\r
- nEntry->Set2DPos( nPosX, nPosY );\r
-\r
- if ( !FindValid2DPos( nEntry ) )\r
- {\r
- nEntry->Set2DPos( 255, 255 );\r
- Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::SetEntryPosXY - Space position already used" );\r
- }\r
- }\r
- mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag;\r
-}\r
-\r
-bool PContainer2DWorkaround::MoveItem( uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId )\r
-{\r
- srcSlotId = nCount = dstSlotId;\r
- return false;\r
-}\r
-\r
-void PContainer2DWorkaround::AddRow()\r
-{\r
- if ( mRows + 1 < mMaxRows )\r
- {\r
- std::vector<bool>* NewRow = new std::vector<bool>( mMaxCols, 0 );\r
- mContSpace.push_back( NewRow );\r
- ++mRows;\r
- }\r
-}\r
-\r
-bool PContainer2DWorkaround::Is2DFree( uint8_t PosX, uint8_t PosY, uint8_t SizeX, uint8_t SizeY )\r
-{\r
- if (( PosX == 255 ) && ( PosY == 255 ) )\r
- {\r
- return true;\r
- }\r
- if ( !Is2DPosAllowed( PosX, PosY, SizeX, SizeY ) )\r
- return false;\r
-\r
- uint8_t h, v;\r
- for ( v = 0; ( v < SizeY ) && ( PosY + v < mRows ) ; v++ ) // what is over existing rows is free\r
- {\r
- for ( h = 0; h < SizeX; h++ )\r
- {\r
- if ( PosX + h >= mMaxCols ) // what is over max col is not free\r
- return false;\r
-\r
- if (( *mContSpace[PosY+v] )[PosX+h] )\r
- return false;\r
- }\r
- }\r
- return ( PosY + SizeY <= mMaxRows );\r
-}\r
-\r
-void PContainer2DWorkaround::SetUsed( PContainerEntry* nEntry, bool Value )\r
-{\r
- uint8_t PosX = nEntry->mPosX;;\r
- uint8_t PosY = nEntry->mPosY;\r
- uint8_t SizeX = nEntry->mItem->GetSizeX();\r
- uint8_t SizeY = nEntry->mItem->GetSizeY();\r
-\r
- if ( !Is2DPosAllowed( PosX, PosY, SizeX, SizeY ) )\r
- return;\r
-\r
- while ( PosY + SizeY > mRows ) // add new rows when needed\r
- AddRow();\r
-\r
- uint8_t h, v;\r
- for ( v = 0; ( v < SizeY ) && ( PosY + v < mRows ) ; v++ )\r
- {\r
- for ( h = 0; ( h < SizeX ) && ( PosX + h < mMaxCols ); h++ )\r
- ( *mContSpace[PosY+v] )[PosX+h] = Value;\r
- }\r
-}\r
-\r
-bool PContainer2DWorkaround::FindValid2DPos( PContainerEntry* nEntry )\r
-{\r
- bool Found = false;\r
- uint8_t SizeX = nEntry->mItem->GetSizeX();\r
- uint8_t SizeY = nEntry->mItem->GetSizeY();\r
- uint8_t dPosX, dPosY;\r
-\r
- if ( Is2DFree( nEntry->mPosX, nEntry->mPosY, SizeX, SizeY ) )\r
- Found = true;\r
- else\r
- {\r
- dPosX = nEntry->mPosX;\r
- dPosY = nEntry->mPosY;\r
- if ( !Is2DPosAllowed( dPosX, dPosY, SizeX, SizeY ) )\r
- {\r
- dPosX = dPosY = 0;\r
- //Console->Print(YELLOW, BLACK, "Init pos RESET");\r
- }\r
-\r
- while ( !Found && Is2DPosAllowed( dPosX, dPosY, SizeX, SizeY ) )\r
- {\r
- //Console->Print(YELLOW, BLACK, "Searching line %d", dPosY);\r
- for ( ; dPosX <= ( mMaxCols - SizeX ); ++dPosX )\r
- {\r
- if (( Found = Is2DFree( dPosX, dPosY, SizeX, SizeY ) ) )\r
- break;\r
- }\r
- if ( Found )\r
- {\r
- nEntry->mPosX = dPosX;\r
- nEntry->mPosY = dPosY;\r
- nEntry->mDirtyFlag = true;\r
- //Console->Print(YELLOW, BLACK, "Success: Found new space position : (%d,%d)", dPosX, dPosY);\r
- break;\r
- }\r
- ++dPosY;\r
- dPosX = 0;\r
- }\r
- }\r
- return Found;\r
-}\r
-\r
-void PContainer2DWorkaround::Dump()\r
-{\r
- PContainer::Dump();\r
-\r
- std::string tmpS;\r
- uint8_t y, x;\r
- for ( y = 0 ; y < mRows; y++ )\r
- {\r
- tmpS = "";\r
- for ( x = 0 ; x < mMaxCols; x++ )\r
- {\r
- tmpS += (( *mContSpace[y] )[x] ) ? "X" : ".";\r
- }\r
- Console->Print( "%s", tmpS.c_str() );\r
- }\r
- Console->Print( GREEN, BLACK, "------------------------------------" );\r
-}\r
-\r
-/* --- PContainerAutoFindFree --- */\r
-bool PContainerAutoFindFree::GetFreeSlot( uint8_t* nSlotId )\r
-{\r
- bool Found = false;\r
-\r
- for ( *nSlotId = 0; *nSlotId < mContContent->size(); ++*nSlotId )\r
- if ( ! mContContent->at( *nSlotId ) )\r
- {\r
- Found = true;\r
- break;\r
- }\r
-\r
- return ( Found || IsSlotAllowed( *nSlotId ) );\r
-}\r
-\r
-/* --- PContainerAutoCompactOnClose --- */\r
-bool PContainerAutoCompactOnClose::EndUse( uint32_t nExclusiveUseCharID )\r
-{\r
- if ( nExclusiveUseCharID == mExclusiveUseCharID )\r
- {\r
- mExclusiveUseCharID = 0;\r
- Compact();\r
- return true;\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] PContainerAutoCompactOnClose::EndUse called with CharID %d when CharID %d had exclusive use", nExclusiveUseCharID, mExclusiveUseCharID );\r
- return false;\r
- }\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "GameServer/Definitions/Includes.hxx"
+#include "Common/Includes.hxx"
+
+/* --- PContainerEntry class --- */
+
+PContainerEntry::PContainerEntry( PItem* nItem, uint8_t X, uint8_t Y, uint32_t nInvID, bool SetDirty )
+{
+ mItem = nItem;
+ mPosX = X;
+ mPosY = Y;
+ mInvID = nInvID;
+ mDirtyFlag = SetDirty;
+}
+
+PContainerEntry::PContainerEntry( MYSQL_ROW row )
+{
+ mItem = NULL;
+ mInvID = atoi( row[i_invid] );
+ mPosX = atoi( row[i_x] );
+ mPosY = atoi( row[i_y] );
+ mDirtyFlag = false;
+
+ uint32_t nItemID = atoi( row[i_itemid] );
+ uint8_t nStackSize = atoi( row[i_qty] );
+ // = std::atoi(row[i_type]);
+ uint8_t CurDur = atoi( row[i_curdur] );
+ uint8_t Dmg = atoi( row[i_dmg] );
+ uint8_t Freq = atoi( row[i_freq] );
+ uint8_t Hand = atoi( row[i_hand] );
+ uint8_t Rng = atoi( row[i_rng] );
+ uint8_t Dur = atoi( row[i_maxdur] );
+
+ mItem = new PItem( nItemID, nStackSize, CurDur, Dur, Dmg, Freq, Hand, Rng );
+}
+
+PContainerEntry::~PContainerEntry()
+{
+ delete mItem;
+}
+
+bool PContainerEntry::SQLSave( uint32_t CharID, uint32_t InvLoc )
+{
+ std::string query, queryv;
+
+ queryv += Ssprintf( " inv_charid='%u',inv_loc='%u',inv_x='%u',inv_y='%u'", CharID, InvLoc, mPosX, mPosY );
+ queryv += Ssprintf( ",inv_itemid='%u',inv_qty='%u'", mItem->mItemID, mItem->mStackSize );
+ //queryv += Ssprintf( ",inv_type='%u'", 0 );
+ queryv += Ssprintf( ",inv_cdur='%u'", mItem->mCurDuration );
+ queryv += Ssprintf( ",inv_dmg='%u'", mItem->mDamages );
+ queryv += Ssprintf( ",inv_frq='%u'", mItem->mFrequency );
+ queryv += Ssprintf( ",inv_hnd='%u'", mItem->mHandling );
+ queryv += Ssprintf( ",inv_rng='%u'", mItem->mRange );
+ queryv += Ssprintf( ",inv_mdur='%u'", mItem->mMaxDuration );
+
+ if ( mInvID )
+ {
+ query = "UPDATE inventory SET " + queryv;
+ query += Ssprintf( " WHERE inv_id='%u' LIMIT 1;", mInvID );
+ }
+ else
+ {
+ query = "INSERT INTO inventory SET " + queryv + ";";
+ }
+
+ if ( MySQL->GameQuery( query.c_str() ) )
+ {
+ Console->Print( RED, BLACK, "PContainerEntry::SQLSave could not add/update some inventory item in the database" );
+ Console->Print( "Query was:" );
+ Console->Print( "%s", query.c_str() );
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+ else
+ {
+ if ( !mInvID )
+ {
+ mInvID = MySQL->GetLastGameInsertId();
+ if ( gDevDebug )
+ Console->Print( GREEN, BLACK, "New item %d added to inventory DB", mInvID );
+ }
+//Console->Print(YELLOW, BLACK, "PContainerEntry::SQLSave - Query was:");
+//Console->Print(YELLOW, BLACK, "%s", query.c_str());
+ mDirtyFlag = false;
+ return true;
+ }
+}
+
+bool PContainerEntry::SQLDelete()
+{
+ std::string query;
+
+ if ( mInvID )
+ {
+ query = Ssprintf( "DELETE FROM inventory WHERE inv_id='%u' LIMIT 1;", mInvID );
+
+ if ( MySQL->GameQuery( query.c_str() ) )
+ {
+ Console->Print( RED, BLACK, "PContainerEntry::SQLDelete could not delete some container item from the database" );
+ Console->Print( "Query was:" );
+ Console->Print( "%s", query.c_str() );
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+ else
+ {
+ if ( gDevDebug )
+ Console->Print( GREEN, BLACK, "Item %d deleted from container DB", mInvID );
+ mInvID = 0;
+ delete mItem;
+ mItem = NULL;
+
+ mDirtyFlag = false;
+ return true;
+ }
+ }
+ else
+ {
+ Console->Print( YELLOW, BLACK, "PContainerEntry::SQLDelete: Item was not in inventory DB" );
+ return true;
+ }
+}
+
+/* --- PContainer class --- */
+
+PContainer::PContainer( uint8_t nMaxSlots )
+{
+ mMaxSlots = ( nMaxSlots > CONTAINER_MAX_SIZE ? CONTAINER_MAX_SIZE : nMaxSlots ) ;
+ if ( mMaxSlots )
+ mContContent = new std::vector< PContainerEntry* >( mMaxSlots, NULL );
+ else
+ mContContent = new std::vector< PContainerEntry* >;
+ mCharID = 0;
+ mInvLoc = 0;
+ mExclusiveUseCharID = 0;
+ mDirtyFlag = false;
+}
+
+PContainer::~PContainer()
+{
+ for ( uint8_t i = 0; i < mContContent->size(); ++i )
+ delete mContContent->at( i );
+
+ if ( mExclusiveUseCharID )
+ Console->Print( RED, BLACK, "[ERROR] PContainer::~PContainer: Char %d still has exclusive access to container !!! Bad Pointer error will happen.", mExclusiveUseCharID );
+}
+
+bool PContainer::AddEntry( PContainerEntry* NewEntry, uint8_t nSlotId )
+{
+ if ( IsSlotAllowed( nSlotId ) )
+ {
+ for ( uint8_t i = mContContent->size(); i <= nSlotId; ++i ) // Extend as needed
+ mContContent->push_back( static_cast<PContainerEntry*>(NULL) );
+ if ( mContContent->at( nSlotId ) )
+ {
+ Console->Print( RED, BLACK, "[Warning] PContainer::AddEntry: Target entry already %d in use !!!", nSlotId );
+ return false;
+ }
+ mContContent->at( nSlotId ) = NewEntry;
+ mDirtyFlag = true;
+ this->SetEntryPosXY( NewEntry, nSlotId, NewEntry->mPosX, NewEntry->mPosY );
+ return true;
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[Warning] PContainer::AddEntry: Target entry %d not allowed (max = %d) !!!", nSlotId, mMaxSlots );
+ return false;
+ }
+ /* --- degug only ---
+ Console->Print(GREEN, BLACK, "PContainer::AddEntry: added item %d at pos (%d,%d)", NewEntry->mItem->GetItemID(), NewEntry->mPosX, NewEntry->mPosY);
+
+ Dump();
+ --- --- */
+}
+
+void PContainer::SetEntryPosXY( PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX, uint8_t nPosY )
+{
+ nPosX = nPosY;
+ nEntry->Set2DPos( nSlotId, 0 );
+ mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag;
+}
+
+PContainerEntry* PContainer::RemoveEntry( uint8_t nSlotId )
+{
+ PContainerEntry* tEntry = NULL;
+
+ if ( nSlotId < mContContent->size() )
+ {
+ tEntry = mContContent->at( nSlotId );
+ mContContent->at( nSlotId ) = NULL;
+ }
+ return tEntry;
+}
+
+bool PContainer::GetFreeSlot( uint8_t* nSlotId )
+{
+ return IsSlotFree( *nSlotId );
+}
+
+void PContainer::Compact( uint8_t startSlotId )
+{
+ uint8_t i, j;
+ PContainerEntry* tEntry;
+
+ for ( i = j = startSlotId; i < mContContent->size(); ++i )
+ {
+ if ( mContContent->at( i ) )
+ {
+ if ( j < i )
+ {
+ mContContent->at( j ) = tEntry = mContContent->at( i );
+ this->SetEntryPosXY( tEntry, j, tEntry->mPosX, tEntry->mPosX );
+ mContContent->at( i ) = NULL;
+ mDirtyFlag = true;
+ }
+ ++j;
+ }
+ }
+
+ if ( !mMaxSlots ) // reduce size only if not fixed-size
+ {
+ for ( ; j < i; ++j )
+ mContContent->pop_back();
+ }
+}
+
+bool PContainer::StartUse( uint32_t nExclusiveUseCharID )
+{
+ if ( mExclusiveUseCharID )
+ return false;
+ else
+ {
+ mExclusiveUseCharID = nExclusiveUseCharID;
+ return true;
+ }
+}
+
+bool PContainer::EndUse( uint32_t nExclusiveUseCharID )
+{
+ if ( nExclusiveUseCharID == mExclusiveUseCharID )
+ {
+ mExclusiveUseCharID = 0;
+ return true;
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[Warning] PContainer::EndUse called with CharID %d when CharID %d had exclusive use", nExclusiveUseCharID, mExclusiveUseCharID );
+ return false;
+ }
+}
+
+bool PContainer::SQLLoad()
+{
+ if ( !mCharID )
+ {
+ return false;
+ }
+
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ char query[1024];
+ PContainerEntry* NewEntry;
+ bool SaveDirtyFlag;
+ uint8_t nSlotId;
+ //uint8_t nPosX, nPosY, nSizeX, nSizeY;
+
+ /*if (!mContContent.empty())
+ {
+ Console->Print(RED, BLACK, "PContainer::SQLLoad: We don't want to load inventory on non-empty inventory for char %d", mCharID);
+ return false;
+ }*/
+
+ snprintf( query, 1024, "SELECT * FROM inventory WHERE inv_charid='%d' AND inv_loc='%d' ORDER BY inv_x ASC", mCharID, mInvLoc );
+ result = MySQL->GameResQuery( query );
+ if ( result == NULL )
+ {
+ Console->Print( RED, BLACK, "[Warning] PContainer::SQLLoad could not load inventory from the database" );
+ Console->Print( "Query was:" );
+ Console->Print( "%s", query );
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+ while (( row = mysql_fetch_row( result ) ) )
+ {
+ NewEntry = new PContainerEntry( row );
+ if ( NewEntry->mItem->GetItemID() )
+ {
+ nSlotId = NewEntry->mPosX;
+ SaveDirtyFlag = mDirtyFlag;
+
+ if ( ! this->GetFreeSlot( &nSlotId ) || ! this->AddEntry( NewEntry, nSlotId ) )
+ {
+ Console->Print( YELLOW, BLACK, "[Warning] PContainer::SQLLoad: Can't add item %d in slot %d of char %d inventory", NewEntry->mItem->GetItemID(), nSlotId, mCharID );
+ delete NewEntry;
+ mDirtyFlag = SaveDirtyFlag;
+ }
+ else
+ {
+ mDirtyFlag = SaveDirtyFlag || ( nSlotId != NewEntry->mPosX );
+ }
+ }
+ else
+ {
+ Console->Print( YELLOW, BLACK, "[Notice] Invalid item in DB (inv_id = %d) - Ignored", NewEntry->mInvID );
+ delete NewEntry;
+ }
+ }
+ MySQL->FreeGameSQLResult( result );
+ return true;
+}
+
+bool PContainer::SQLSave()
+{
+ if ( !mCharID )
+ return false;
+
+ PContainerEntry* ContEntry;
+ bool SavedOK = true;
+
+ for ( uint8_t i = 0; i < mContContent->size(); ++i )
+ {
+ if (( ContEntry = mContContent->at( i ) ) )
+ {
+ if (( ContEntry->mDirtyFlag ) )
+ {
+ SavedOK = SavedOK && ContEntry->SQLSave( mCharID, mInvLoc );
+ }
+ }
+ }
+
+ if ( SavedOK )
+ {
+ mDirtyFlag = false;
+ }
+ return SavedOK;
+}
+
+bool PContainer::IsSlotFree( uint8_t nSlotId )
+{
+ if ( !IsSlotAllowed( nSlotId ) )
+ return false;
+
+ if ( nSlotId >= mContContent->size() )
+ return true;
+ else
+ return !( mContContent->at( nSlotId ) );
+}
+
+bool PContainer::AddItem( PItem* NewItem, uint32_t nInvID, uint8_t nPosX, uint8_t nPosY, bool SetDirty )
+{
+ /* --- auto stacking not implemented yet
+ 1 - if stackable, check if same item(S) exists
+ 2 - - if exist
+ 3 - - - add to stack
+ 4 - - - if no new stack remains, update LastPutXY & return true
+ 5 - find an empty space
+ 6 -
+ x - put in new space, update LastPutXY & return true
+
+ */
+
+ if ( NewItem->GetItemID() == 0 )
+ {
+ Console->Print( RED, BLACK, "[Warning] PContainer::AddItem: invalid item : ID 0" );
+ return false;
+ }
+
+ PContainerEntry* NewEntry = new PContainerEntry( NewItem, nPosX, nPosY, nInvID, SetDirty );
+
+ if ( this->GetFreeSlot( &nPosX ) && this->AddEntry( NewEntry, nPosX ) ) // !!!! nPosX not good
+ return true;
+ else
+ {
+ delete NewEntry;
+ return false;
+ }
+}
+
+bool PContainer::MoveItem( uint8_t srcSlotId, uint8_t nCount, PContainer* dstContainer, uint8_t dstSlotId, uint8_t nPosX, uint8_t nPosY )
+{
+ if ( dstContainer == this )
+ return this->MoveItem( srcSlotId, nCount, dstSlotId );
+ else if ( dstContainer->GetFreeSlot( &dstSlotId ) )
+ {
+ uint8_t savePosX, savePosY;
+ PContainerEntry* tEntry = this->GetEntry( srcSlotId );
+ if ( tEntry )
+ {
+ tEntry->Get2DPos( &savePosX, &savePosY );
+ tEntry->Set2DPos( nPosX, nPosY );
+ if ( !dstContainer->AddEntry( tEntry, dstSlotId ) )
+ {
+ tEntry->Set2DPos( savePosX, savePosY );
+ Console->Print( RED, BLACK, "[Warning] PContainer::MoveItem - Couldn't add entry !" );
+ return false;
+ }
+ tEntry->Get2DPos( &nPosX, &nPosY );
+ tEntry->Set2DPos( savePosX, savePosY );
+ RemoveEntry( srcSlotId );
+ tEntry->Set2DPos( nPosX, nPosY );
+
+ if ( dstContainer->mCharID != this->mCharID ) // save at once if owner changes
+ {
+ if ( !tEntry->SQLSave( dstContainer->mCharID, dstContainer->mInvLoc ) ) // TODO: improve to manage non-persistent containers
+ {
+ Console->Print( RED, BLACK, "[Warning] PContainer::MoveItem - Moved entry not saved" );
+ }
+ //else
+ //{
+ // Console->Print(GREEN, BLACK, "[Succes] PContainer::MoveItem - Moved entry saved");
+ //}
+ }
+ return true;
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[Warning] trying to move invalid entry %d", srcSlotId );
+ return false;
+ }
+ }
+ return false;
+}
+
+// !!! Not partial move yet !!!
+bool PContainer::MoveItem( uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId )
+{
+ if ( !( IsSlotAllowed( srcSlotId ) && IsSlotAllowed( dstSlotId ) ) )
+ return false;
+
+ if ( srcSlotId == dstSlotId )
+ return true;
+
+ if (( mContContent->at( srcSlotId ) )
+ && ( mContContent->at( srcSlotId )->mItem->GetStackSize() >= nCount )
+ && IsSlotFree( dstSlotId ) )
+ {
+ PContainerEntry* tEntry = mContContent->at( dstSlotId ) = mContContent->at( srcSlotId );
+ tEntry->mPosX = dstSlotId;
+ tEntry->mPosY = 0;
+ tEntry->mDirtyFlag = true;
+ mContContent->at( srcSlotId ) = NULL;
+ mDirtyFlag = true;
+ return true;
+ }
+ else
+ return false;
+}
+
+std::vector< PContainerEntry* >* PContainer::GetEntries()
+{
+ std::vector< PContainerEntry* >* Entries = new std::vector< PContainerEntry* >;
+
+ for ( uint8_t i = 0; i < mContContent->size(); ++i )
+ {
+ if ( mContContent->at( i ) )
+ Entries->push_back( mContContent->at( i ) );
+ }
+
+ return Entries;
+}
+
+PContainerEntry* PContainer::GetEntry( uint8_t nSlotId )
+{
+ if ( nSlotId >= mContContent->size() )
+ return NULL;
+
+ return mContContent->at( nSlotId );
+}
+
+PItem* PContainer::GetItem( uint8_t nSlotId )
+{
+ PContainerEntry* tEntry = this->GetEntry( nSlotId );
+ return ( tEntry ? tEntry->mItem : NULL );
+}
+
+uint8_t PContainer::RandomFill( uint8_t nItemCount, int nItemContainerDefIndex )
+{
+ PItem* nItem = NULL;
+ const PDefItems* nItemDef;
+ uint32_t nItemSeqId;
+ uint8_t CreatedCount = 0;
+
+ if ( !nItemCount )
+ nItemCount = mMaxSlots;
+ if ( !nItemCount )
+ nItemCount = CONTAINER_MAX_SIZE;
+
+ if ( nItemContainerDefIndex >= 0 )
+ {
+ int newItemIdx, newItemIndex;
+ uint8_t newItemQuality;
+
+ const PDefItemContainer* containerDef = GameDefs->ItemContainers()->GetDef( nItemContainerDefIndex );
+ if ( containerDef )
+ {
+ for ( uint8_t i = 0; i < nItemCount; ++i )
+ {
+ newItemIdx = containerDef->GetRandomItemIdx();
+ if ( newItemIdx >= 0 )
+ {
+ newItemIndex = containerDef->GetItemId( newItemIdx );
+ newItemQuality = ( uint8_t )( 255 & int( 255.0 * containerDef->GetQuality( newItemIdx ) ) );
+ if ( newItemIndex <= 0 ) // Item group
+ {
+ newItemIndex = GameDefs->Items()->GetRandomItemIdFromGroup( -newItemIndex );
+ }
+ nItem = new PItem( newItemIndex, 1, 255, newItemQuality, newItemQuality, newItemQuality, newItemQuality, 255 );
+ if ( nItem->GetItemID() )
+ {
+ if ( this->AddItem( nItem ) )
+ {
+ ++CreatedCount;
+ }
+ else
+ {
+ Console->Print( YELLOW, BLACK, "[Warning] Couldn't add item %d at pos %d", nItem->GetItemID(), i );
+ delete nItem;
+ }
+ }
+ }
+ }
+ }
+ else
+ Console->Print( YELLOW, BLACK, "[Warning] Container def not found: %d", nItemContainerDefIndex );
+ }
+ else
+ {
+ int NumItemsDefs = GameDefs->Items()->GetNumDefs();
+
+ for ( uint8_t i = 0; i < nItemCount; ++i )
+ {
+ nItemSeqId = GetRandom( NumItemsDefs, 1 );
+
+ if (( nItemDef = GameDefs->Items()->GetDefBySeqIndex( nItemSeqId ) ) )
+ {
+ nItem = new PItem( nItemDef->GetIndex(), 1, 255, 255, 255, 255, 255, 255 );
+ if ( nItem->GetItemID() )
+ {
+ if ( this->AddItem( nItem ) )
+ {
+ ++CreatedCount;
+ }
+ else
+ {
+ //Console->Print(GREEN, BLACK, "Couldn't add item % d at pos % d", nItem->GetItemID(), i);
+ delete nItem;
+ }
+ }
+ }
+ else
+ Console->Print( RED, BLACK, "[Warning] PContainer::RandomFill Couldn't find item for SEQ %d", nItemSeqId );
+ }
+ }
+ return CreatedCount;
+}
+
+void PContainer::Dump()
+{
+ PContainerEntry* tmpEntry;
+ PItem* tmpItem;
+ uint8_t i;
+ //uint8_t y, x;
+
+ for ( i = 0; i < mContContent->size(); ++i )
+ {
+ if (( tmpEntry = mContContent->at( i ) ) )
+ {
+ tmpItem = tmpEntry->mItem;
+ Console->Print( GREEN, BLACK, "%d: (%d,%d) (%d x %d) Item %d (InvID %d) %s %s", i, tmpEntry->mPosX, tmpEntry->mPosY, tmpItem->GetSizeX(), tmpItem->GetSizeY(), tmpItem->GetItemID(), tmpEntry->mInvID, tmpItem->GetName().c_str(), tmpEntry->mDirtyFlag ? "[*]" : "" );
+ }
+ }
+
+ if ( mDirtyFlag )
+ Console->Print( GREEN, BLACK, "Dirty" );
+ Console->Print( GREEN, BLACK, "------------------------------------" );
+}
+
+/* --- PContainerWithHoles class --- */
+
+
+/* --- PContainerAutoCompact --- */
+PContainerEntry* PContainerAutoCompact::RemoveEntry( uint8_t nSlotId )
+{
+ PContainerEntry* tEntry = NULL;
+
+ if ( nSlotId < mContContent->size() )
+ {
+ tEntry = mContContent->at( nSlotId );
+ mContContent->at( nSlotId ) = NULL;
+ if ( nSlotId == ( mContContent->size() - 1 ) )
+ mContContent->pop_back();
+ else
+ Compact( nSlotId );
+ }
+ return tEntry;
+}
+
+bool PContainerAutoCompact::GetFreeSlot( uint8_t* nSlotId ) // not optimal. A "first free from end" would be better at PContainer level
+{
+ bool Found = false;
+
+ for ( *nSlotId = 0; *nSlotId < mContContent->size(); ++*nSlotId )
+ if ( ! mContContent->at( *nSlotId ) )
+ {
+ Found = true;
+ break;
+ }
+ return ( Found || IsSlotAllowed( *nSlotId ) );
+}
+
+bool PContainerAutoCompact::MoveItem( uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId )
+{
+ srcSlotId = nCount = dstSlotId;
+ return false;
+}
+
+/* --- PContainer2D class --- */
+
+void PContainer2D::SetEntryPosXY( PContainerEntry* nEntry, uint8_t /*nSlotId*/, uint8_t nPosX, uint8_t nPosY )
+{
+ //nSlotId = nSlotId;
+ if (( nPosX >= INV_BACKPACK_COLS ) || ( nPosY == 255 ) )
+ {
+ nPosX = nPosY = 0;
+ }
+ nEntry->Set2DPos( nPosX, nPosY );
+ mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag;
+}
+
+/* --- PContainer2DWorkaround --- */
+/////
+PContainer2DWorkaround::PContainer2DWorkaround( uint8_t nMaxSlots ) : PContainerWithHoles( nMaxSlots )
+{
+ mNextFreeSlot = 0;
+ mMaxCols = 254;
+ mMaxRows = 254;
+ mRows = 0;
+ AddRow();
+}
+
+PContainer2DWorkaround::~PContainer2DWorkaround()
+{
+ for ( int i = 0; i < mRows; i++ )
+ delete mContSpace[i];
+}
+
+bool PContainer2DWorkaround::AddEntry( PContainerEntry* tEntry, uint8_t nSlotId )
+{
+ if ( IsSlotAllowed( nSlotId ) )
+ {
+ if ( FindValid2DPos( tEntry ) )
+ {
+ for ( uint8_t i = mContContent->size(); i <= nSlotId; ++i ) // Extend as needed
+ mContContent->push_back( static_cast<PContainerEntry *>(NULL) );
+ if ( mContContent->at( nSlotId ) )
+ {
+ Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: Target entry already %d in use !!!", nSlotId );
+ return false;
+ }
+ mContContent->at( nSlotId ) = tEntry;
+ mDirtyFlag = true;
+ //this->SetEntryPosXY(tEntry, nSlotId, tEntry->mPosX, tEntry->mPosY);
+ mDirtyFlag = mDirtyFlag || tEntry->mDirtyFlag;
+ SetUsed( tEntry );
+ return true;
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: No 2D space left !!!", nSlotId, mMaxSlots );
+ return false;
+ }
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: Target entry %d not allowed (max = %d) !!!", nSlotId, mMaxSlots );
+ return false;
+ }
+
+}
+
+PContainerEntry* PContainer2DWorkaround::RemoveEntry( uint8_t nSlotId )
+{
+ PContainerEntry* tEntry = NULL;
+
+ if ( nSlotId < mContContent->size() )
+ {
+ tEntry = mContContent->at( nSlotId );
+ mContContent->at( nSlotId ) = NULL;
+ //Console->Print(YELLOW, BLACK, "Cleaning (%d,%d) (%d x %d)", tEntry->mPosX, tEntry->mPosY, tEntry->mItem->GetSizeX(), tEntry->mItem->GetSizeY());
+ SetUsed( tEntry, false );
+ }
+ return tEntry;
+}
+
+bool PContainer2DWorkaround::GetFreeSlot( uint8_t* nSlotId )
+{
+ if ( IsSlotAllowed( mNextFreeSlot ) )
+ {
+ *nSlotId = mNextFreeSlot++;
+ return true;
+ }
+ else
+ return false;
+}
+
+void PContainer2DWorkaround::SetEntryPosXY( PContainerEntry* nEntry, uint8_t /*nSlotId*/, uint8_t nPosX, uint8_t nPosY )
+{
+ //nSlotId = nSlotId;
+ if (( nPosX == 255 ) && ( nPosY == 255 ) )
+ {
+ nEntry->Set2DPos( 255, 255 );
+ }
+ else
+ {
+ if (( nPosX >= mMaxCols ) || ( nPosY >= mMaxRows ) )
+ {
+ nPosX = nPosY = 0;
+ }
+ nEntry->Set2DPos( nPosX, nPosY );
+
+ if ( !FindValid2DPos( nEntry ) )
+ {
+ nEntry->Set2DPos( 255, 255 );
+ Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::SetEntryPosXY - Space position already used" );
+ }
+ }
+ mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag;
+}
+
+bool PContainer2DWorkaround::MoveItem( uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId )
+{
+ srcSlotId = nCount = dstSlotId;
+ return false;
+}
+
+void PContainer2DWorkaround::AddRow()
+{
+ if ( mRows + 1 < mMaxRows )
+ {
+ std::vector<bool>* NewRow = new std::vector<bool>( mMaxCols, 0 );
+ mContSpace.push_back( NewRow );
+ ++mRows;
+ }
+}
+
+bool PContainer2DWorkaround::Is2DFree( uint8_t PosX, uint8_t PosY, uint8_t SizeX, uint8_t SizeY )
+{
+ if (( PosX == 255 ) && ( PosY == 255 ) )
+ {
+ return true;
+ }
+ if ( !Is2DPosAllowed( PosX, PosY, SizeX, SizeY ) )
+ return false;
+
+ uint8_t h, v;
+ for ( v = 0; ( v < SizeY ) && ( PosY + v < mRows ) ; v++ ) // what is over existing rows is free
+ {
+ for ( h = 0; h < SizeX; h++ )
+ {
+ if ( PosX + h >= mMaxCols ) // what is over max col is not free
+ return false;
+
+ if (( *mContSpace[PosY+v] )[PosX+h] )
+ return false;
+ }
+ }
+ return ( PosY + SizeY <= mMaxRows );
+}
+
+void PContainer2DWorkaround::SetUsed( PContainerEntry* nEntry, bool Value )
+{
+ uint8_t PosX = nEntry->mPosX;;
+ uint8_t PosY = nEntry->mPosY;
+ uint8_t SizeX = nEntry->mItem->GetSizeX();
+ uint8_t SizeY = nEntry->mItem->GetSizeY();
+
+ if ( !Is2DPosAllowed( PosX, PosY, SizeX, SizeY ) )
+ return;
+
+ while ( PosY + SizeY > mRows ) // add new rows when needed
+ AddRow();
+
+ uint8_t h, v;
+ for ( v = 0; ( v < SizeY ) && ( PosY + v < mRows ) ; v++ )
+ {
+ for ( h = 0; ( h < SizeX ) && ( PosX + h < mMaxCols ); h++ )
+ ( *mContSpace[PosY+v] )[PosX+h] = Value;
+ }
+}
+
+bool PContainer2DWorkaround::FindValid2DPos( PContainerEntry* nEntry )
+{
+ bool Found = false;
+ uint8_t SizeX = nEntry->mItem->GetSizeX();
+ uint8_t SizeY = nEntry->mItem->GetSizeY();
+ uint8_t dPosX, dPosY;
+
+ if ( Is2DFree( nEntry->mPosX, nEntry->mPosY, SizeX, SizeY ) )
+ Found = true;
+ else
+ {
+ dPosX = nEntry->mPosX;
+ dPosY = nEntry->mPosY;
+ if ( !Is2DPosAllowed( dPosX, dPosY, SizeX, SizeY ) )
+ {
+ dPosX = dPosY = 0;
+ //Console->Print(YELLOW, BLACK, "Init pos RESET");
+ }
+
+ while ( !Found && Is2DPosAllowed( dPosX, dPosY, SizeX, SizeY ) )
+ {
+ //Console->Print(YELLOW, BLACK, "Searching line %d", dPosY);
+ for ( ; dPosX <= ( mMaxCols - SizeX ); ++dPosX )
+ {
+ if (( Found = Is2DFree( dPosX, dPosY, SizeX, SizeY ) ) )
+ break;
+ }
+ if ( Found )
+ {
+ nEntry->mPosX = dPosX;
+ nEntry->mPosY = dPosY;
+ nEntry->mDirtyFlag = true;
+ //Console->Print(YELLOW, BLACK, "Success: Found new space position : (%d,%d)", dPosX, dPosY);
+ break;
+ }
+ ++dPosY;
+ dPosX = 0;
+ }
+ }
+ return Found;
+}
+
+void PContainer2DWorkaround::Dump()
+{
+ PContainer::Dump();
+
+ std::string tmpS;
+ uint8_t y, x;
+ for ( y = 0 ; y < mRows; y++ )
+ {
+ tmpS = "";
+ for ( x = 0 ; x < mMaxCols; x++ )
+ {
+ tmpS += (( *mContSpace[y] )[x] ) ? "X" : ".";
+ }
+ Console->Print( "%s", tmpS.c_str() );
+ }
+ Console->Print( GREEN, BLACK, "------------------------------------" );
+}
+
+/* --- PContainerAutoFindFree --- */
+bool PContainerAutoFindFree::GetFreeSlot( uint8_t* nSlotId )
+{
+ bool Found = false;
+
+ for ( *nSlotId = 0; *nSlotId < mContContent->size(); ++*nSlotId )
+ if ( ! mContContent->at( *nSlotId ) )
+ {
+ Found = true;
+ break;
+ }
+
+ return ( Found || IsSlotAllowed( *nSlotId ) );
+}
+
+/* --- PContainerAutoCompactOnClose --- */
+bool PContainerAutoCompactOnClose::EndUse( uint32_t nExclusiveUseCharID )
+{
+ if ( nExclusiveUseCharID == mExclusiveUseCharID )
+ {
+ mExclusiveUseCharID = 0;
+ Compact();
+ return true;
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[ERROR] PContainerAutoCompactOnClose::EndUse called with CharID %d when CharID %d had exclusive use", nExclusiveUseCharID, mExclusiveUseCharID );
+ return false;
+ }
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <vector>\r
-#ifdef MYSQL_INC_DIR\r
-#include <mysql/mysql.h>\r
-#else\r
-#include <mysql.h>\r
-#endif\r
-\r
-#define CONTAINER_MAX_SIZE 254\r
-\r
-class PItem;\r
-\r
-class PContainerEntry {\r
- friend class PContainer;\r
- friend class PContainer2D;\r
- friend class PMsgBuilder;\r
- friend class PContainer2DWorkaround;\r
-\r
-private:\r
- enum {\r
- i_invid = 0,\r
- i_charid,\r
- i_invloc,\r
- i_x,\r
- i_y,\r
- i_itemid,\r
- //i_type,\r
- i_flag,\r
- i_qty,\r
- i_sqty,\r
- i_curdur,\r
- i_dmg,\r
- i_freq,\r
- i_hand,\r
- i_rng,\r
- i_maxdur,\r
- i_slots,\r
- i_slt1,\r
- i_slt2,\r
- i_slt3,\r
- i_slt4,\r
- i_slt5,\r
- i_atype,\r
- i_conatin\r
- };\r
-\r
- PItem* mItem;\r
- uint8_t mPosX;\r
- uint8_t mPosY;\r
- uint32_t mInvID;\r
- bool mDirtyFlag;\r
-\r
- PContainerEntry(PItem* nItem, uint8_t X, uint8_t Y, uint32_t nInvID = 0, bool SetDirty = true);\r
- PContainerEntry(MYSQL_ROW row);\r
-\r
- bool SQLSave(uint32_t CharID, uint32_t InvLoc);\r
- bool SQLDelete();\r
-\r
- inline void Set2DPos(uint8_t nPosX, uint8_t nPosY) { mDirtyFlag = mDirtyFlag || (mPosX != nPosX) || (mPosY != nPosY) ; mPosX = nPosX; mPosY = nPosY; }\r
-\r
-public:\r
- ~PContainerEntry();\r
-\r
- inline void Get2DPos(uint8_t* oPosX, uint8_t* oPosY) { *oPosX = mPosX; *oPosY = mPosY; }\r
-};\r
-\r
-\r
-\r
-class PContainer // Holes allowed, no autofind free slots\r
-{\r
- protected:\r
- uint8_t mMaxSlots;\r
- std::vector< PContainerEntry* >* mContContent;\r
- uint32_t mCharID;\r
- uint32_t mInvLoc;\r
- uint32_t mExclusiveUseCharID;\r
- bool mDirtyFlag;\r
-\r
- inline bool IsSlotAllowed(uint8_t nSlotId) { return ((nSlotId < CONTAINER_MAX_SIZE) && (!mMaxSlots || (nSlotId < mMaxSlots))); }\r
- virtual bool AddEntry(PContainerEntry* NewEntry, uint8_t nSlotId = 0);\r
- virtual PContainerEntry* RemoveEntry(uint8_t nSlotId);\r
- virtual bool GetFreeSlot(uint8_t* nSlotId);\r
- void Compact(uint8_t startSlotId = 0);\r
-\r
- public:\r
- PContainer(uint8_t nMaxSlots = 0);\r
- virtual ~PContainer();\r
-\r
- inline void SetInfo(uint32_t CharID, uint32_t InvLoc) { mCharID = CharID; mInvLoc = InvLoc; }\r
- inline uint32_t GetOwnerId() { return mCharID; }\r
- inline bool IsDirty() { return mDirtyFlag; }\r
- inline void SetDirty() { mDirtyFlag = true; }\r
- bool StartUse(uint32_t nExclusiveUseCharID = 0);\r
- virtual bool EndUse(uint32_t nExclusiveUseCharID = 0);\r
- bool SQLLoad();\r
- bool SQLSave();\r
- bool IsSlotFree(uint8_t nSlotId);\r
- virtual bool AddItem(PItem* NewItem, uint32_t nInvID = 0, uint8_t nPosX = 0, uint8_t nPosY = 0, bool SetDirty = true);\r
- virtual bool MoveItem(uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId);\r
- bool MoveItem(uint8_t srcSlotId, uint8_t nCount, PContainer* dstContainer, uint8_t dstSlotId = 0, uint8_t nPosX = 0, uint8_t nPosY = 0);\r
- virtual void SetEntryPosXY(PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX = 0, uint8_t nPosY = 0);\r
-\r
- virtual uint8_t RandomFill(uint8_t nItemCount = 0, int nItemContainerDefIndex = -1);\r
- PContainerEntry* GetEntry(uint8_t nSlotId);\r
- std::vector< PContainerEntry* >* GetEntries();\r
- PItem* GetItem(uint8_t nSlotId);\r
- virtual void Dump();\r
-};\r
-\r
-\r
-class PContainerWithHoles : public PContainer // Holes allowed, no autofind free slots\r
-{\r
- public:\r
- PContainerWithHoles(uint8_t nMaxSlots = 0) : PContainer(nMaxSlots) {}\r
- virtual ~PContainerWithHoles() {}\r
-};\r
-\r
-\r
-class PContainerAutoCompact : public PContainer // No holes allowed, automatic add to end slot (no control on insertion slot)\r
-{\r
-protected:\r
- virtual PContainerEntry* RemoveEntry(uint8_t nSlotId);\r
- virtual bool GetFreeSlot(uint8_t* nSlotId);\r
-\r
-public:\r
- PContainerAutoCompact(uint8_t nMaxSlots = 0) : PContainer(nMaxSlots) {}\r
- virtual ~PContainerAutoCompact() {}\r
- virtual bool MoveItem(uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId);\r
-};\r
-\r
-\r
-class PContainer2D : public PContainerAutoCompact // + slotId not used, non-significant XY used (no XY check yet)\r
-{\r
- public:\r
- PContainer2D(uint8_t nMaxSlots = 0) : PContainerAutoCompact(nMaxSlots) {}\r
- virtual ~PContainer2D() {}\r
-\r
- virtual void SetEntryPosXY(PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX = 0, uint8_t nPosY = 0);\r
-};\r
-\r
-class PContainer2DWorkaround : public PContainerWithHoles // Holes allowed, autofind free slot (always increasing id)\r
-{\r
-private:\r
- uint8_t mNextFreeSlot;\r
- std::vector< std::vector<bool>* > mContSpace;\r
- uint8_t mMaxCols;\r
- uint8_t mMaxRows;\r
- uint8_t mRows;\r
-\r
- void AddRow();\r
- inline bool Is2DPosAllowed(uint8_t PosX, uint8_t PosY, uint8_t SizeX, uint8_t SizeY)\r
- {\r
- return ((PosX < mMaxCols-SizeX+1) && (PosY < mMaxRows-SizeY+1));\r
- }\r
- bool Is2DFree(uint8_t PosX, uint8_t PosY, uint8_t SizeX, uint8_t SizeY);\r
- bool FindValid2DPos(PContainerEntry* nEntry);\r
-\r
-protected:\r
- bool AddEntry(PContainerEntry* NewEntry, uint8_t nSlotId = 0);\r
- PContainerEntry* RemoveEntry(uint8_t nSlotId);\r
- bool GetFreeSlot(uint8_t* nSlotId);\r
-\r
- public:\r
- PContainer2DWorkaround(uint8_t nMaxSlots = 0);\r
- ~PContainer2DWorkaround();\r
-\r
- bool MoveItem(uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId);\r
-\r
- void Set2DPosMax(uint8_t MaxPosX, uint8_t MaxPosY = 254) { mMaxCols = MaxPosX; mMaxRows = MaxPosY; }\r
- void SetEntryPosXY(PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX = 0, uint8_t nPosY = 0);\r
- void SetUsed(PContainerEntry* nEntry, bool Value = true);\r
- void Dump();\r
-};\r
-\r
-class PContainerAutoFindFree : public PContainerWithHoles // No holes kept after EndUse, automatic find first free slots (no control on insertion slot)\r
-{\r
- protected:\r
- virtual bool GetFreeSlot(uint8_t* nSlotId);\r
-\r
- public:\r
- PContainerAutoFindFree(uint8_t nMaxSlots = 0) : PContainerWithHoles(nMaxSlots) {}\r
- virtual ~PContainerAutoFindFree() {}\r
-};\r
-\r
-class PContainerAutoCompactOnClose : public PContainerAutoFindFree // No holes kept after EndUse, automatic find first free slots (no control on insertion slot)\r
-{\r
- public:\r
- PContainerAutoCompactOnClose(uint8_t nMaxSlots = 0) : PContainerAutoFindFree(nMaxSlots) {}\r
- virtual ~PContainerAutoCompactOnClose() {}\r
-\r
- virtual bool EndUse(uint32_t nExclusiveUseCharID = 0);\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <vector>
+#ifdef MYSQL_INC_DIR
+#include <mysql/mysql.h>
+#else
+#include <mysql.h>
+#endif
+
+#define CONTAINER_MAX_SIZE 254
+
+class PItem;
+
+class PContainerEntry {
+ friend class PContainer;
+ friend class PContainer2D;
+ friend class PMsgBuilder;
+ friend class PContainer2DWorkaround;
+
+private:
+ enum {
+ i_invid = 0,
+ i_charid,
+ i_invloc,
+ i_x,
+ i_y,
+ i_itemid,
+ //i_type,
+ i_flag,
+ i_qty,
+ i_sqty,
+ i_curdur,
+ i_dmg,
+ i_freq,
+ i_hand,
+ i_rng,
+ i_maxdur,
+ i_slots,
+ i_slt1,
+ i_slt2,
+ i_slt3,
+ i_slt4,
+ i_slt5,
+ i_atype,
+ i_conatin
+ };
+
+ PItem* mItem;
+ uint8_t mPosX;
+ uint8_t mPosY;
+ uint32_t mInvID;
+ bool mDirtyFlag;
+
+ PContainerEntry(PItem* nItem, uint8_t X, uint8_t Y, uint32_t nInvID = 0, bool SetDirty = true);
+ PContainerEntry(MYSQL_ROW row);
+
+ bool SQLSave(uint32_t CharID, uint32_t InvLoc);
+ bool SQLDelete();
+
+ inline void Set2DPos(uint8_t nPosX, uint8_t nPosY) { mDirtyFlag = mDirtyFlag || (mPosX != nPosX) || (mPosY != nPosY) ; mPosX = nPosX; mPosY = nPosY; }
+
+public:
+ ~PContainerEntry();
+
+ inline void Get2DPos(uint8_t* oPosX, uint8_t* oPosY) { *oPosX = mPosX; *oPosY = mPosY; }
+};
+
+
+
+class PContainer // Holes allowed, no autofind free slots
+{
+ protected:
+ uint8_t mMaxSlots;
+ std::vector< PContainerEntry* >* mContContent;
+ uint32_t mCharID;
+ uint32_t mInvLoc;
+ uint32_t mExclusiveUseCharID;
+ bool mDirtyFlag;
+
+ inline bool IsSlotAllowed(uint8_t nSlotId) { return ((nSlotId < CONTAINER_MAX_SIZE) && (!mMaxSlots || (nSlotId < mMaxSlots))); }
+ virtual bool AddEntry(PContainerEntry* NewEntry, uint8_t nSlotId = 0);
+ virtual PContainerEntry* RemoveEntry(uint8_t nSlotId);
+ virtual bool GetFreeSlot(uint8_t* nSlotId);
+ void Compact(uint8_t startSlotId = 0);
+
+ public:
+ PContainer(uint8_t nMaxSlots = 0);
+ virtual ~PContainer();
+
+ inline void SetInfo(uint32_t CharID, uint32_t InvLoc) { mCharID = CharID; mInvLoc = InvLoc; }
+ inline uint32_t GetOwnerId() { return mCharID; }
+ inline bool IsDirty() { return mDirtyFlag; }
+ inline void SetDirty() { mDirtyFlag = true; }
+ bool StartUse(uint32_t nExclusiveUseCharID = 0);
+ virtual bool EndUse(uint32_t nExclusiveUseCharID = 0);
+ bool SQLLoad();
+ bool SQLSave();
+ bool IsSlotFree(uint8_t nSlotId);
+ virtual bool AddItem(PItem* NewItem, uint32_t nInvID = 0, uint8_t nPosX = 0, uint8_t nPosY = 0, bool SetDirty = true);
+ virtual bool MoveItem(uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId);
+ bool MoveItem(uint8_t srcSlotId, uint8_t nCount, PContainer* dstContainer, uint8_t dstSlotId = 0, uint8_t nPosX = 0, uint8_t nPosY = 0);
+ virtual void SetEntryPosXY(PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX = 0, uint8_t nPosY = 0);
+
+ virtual uint8_t RandomFill(uint8_t nItemCount = 0, int nItemContainerDefIndex = -1);
+ PContainerEntry* GetEntry(uint8_t nSlotId);
+ std::vector< PContainerEntry* >* GetEntries();
+ PItem* GetItem(uint8_t nSlotId);
+ virtual void Dump();
+};
+
+
+class PContainerWithHoles : public PContainer // Holes allowed, no autofind free slots
+{
+ public:
+ PContainerWithHoles(uint8_t nMaxSlots = 0) : PContainer(nMaxSlots) {}
+ virtual ~PContainerWithHoles() {}
+};
+
+
+class PContainerAutoCompact : public PContainer // No holes allowed, automatic add to end slot (no control on insertion slot)
+{
+protected:
+ virtual PContainerEntry* RemoveEntry(uint8_t nSlotId);
+ virtual bool GetFreeSlot(uint8_t* nSlotId);
+
+public:
+ PContainerAutoCompact(uint8_t nMaxSlots = 0) : PContainer(nMaxSlots) {}
+ virtual ~PContainerAutoCompact() {}
+ virtual bool MoveItem(uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId);
+};
+
+
+class PContainer2D : public PContainerAutoCompact // + slotId not used, non-significant XY used (no XY check yet)
+{
+ public:
+ PContainer2D(uint8_t nMaxSlots = 0) : PContainerAutoCompact(nMaxSlots) {}
+ virtual ~PContainer2D() {}
+
+ virtual void SetEntryPosXY(PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX = 0, uint8_t nPosY = 0);
+};
+
+class PContainer2DWorkaround : public PContainerWithHoles // Holes allowed, autofind free slot (always increasing id)
+{
+private:
+ uint8_t mNextFreeSlot;
+ std::vector< std::vector<bool>* > mContSpace;
+ uint8_t mMaxCols;
+ uint8_t mMaxRows;
+ uint8_t mRows;
+
+ void AddRow();
+ inline bool Is2DPosAllowed(uint8_t PosX, uint8_t PosY, uint8_t SizeX, uint8_t SizeY)
+ {
+ return ((PosX < mMaxCols-SizeX+1) && (PosY < mMaxRows-SizeY+1));
+ }
+ bool Is2DFree(uint8_t PosX, uint8_t PosY, uint8_t SizeX, uint8_t SizeY);
+ bool FindValid2DPos(PContainerEntry* nEntry);
+
+protected:
+ bool AddEntry(PContainerEntry* NewEntry, uint8_t nSlotId = 0);
+ PContainerEntry* RemoveEntry(uint8_t nSlotId);
+ bool GetFreeSlot(uint8_t* nSlotId);
+
+ public:
+ PContainer2DWorkaround(uint8_t nMaxSlots = 0);
+ ~PContainer2DWorkaround();
+
+ bool MoveItem(uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId);
+
+ void Set2DPosMax(uint8_t MaxPosX, uint8_t MaxPosY = 254) { mMaxCols = MaxPosX; mMaxRows = MaxPosY; }
+ void SetEntryPosXY(PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX = 0, uint8_t nPosY = 0);
+ void SetUsed(PContainerEntry* nEntry, bool Value = true);
+ void Dump();
+};
+
+class PContainerAutoFindFree : public PContainerWithHoles // No holes kept after EndUse, automatic find first free slots (no control on insertion slot)
+{
+ protected:
+ virtual bool GetFreeSlot(uint8_t* nSlotId);
+
+ public:
+ PContainerAutoFindFree(uint8_t nMaxSlots = 0) : PContainerWithHoles(nMaxSlots) {}
+ virtual ~PContainerAutoFindFree() {}
+};
+
+class PContainerAutoCompactOnClose : public PContainerAutoFindFree // No holes kept after EndUse, automatic find first free slots (no control on insertion slot)
+{
+ public:
+ PContainerAutoCompactOnClose(uint8_t nMaxSlots = 0) : PContainerAutoFindFree(nMaxSlots) {}
+ virtual ~PContainerAutoCompactOnClose() {}
+
+ virtual bool EndUse(uint32_t nExclusiveUseCharID = 0);
+};
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-void PUdpMsgDecoder::Init(PMessage *nMessage, PClient *nClient)\r
-{\r
- mDecodeData.mMessage = nMessage;\r
- mDecodeData.mClient = nClient;\r
- mDecodeData.mState = (nMessage && nClient) ? DECODE_MORE : DECODE_UNDEF;\r
- mDecodeData.mUnknownType = 0;\r
- mDecodeData.mHandling0x13Sub = false;\r
- mDecodeData.Sub0x13Start = mDecodeData.Sub0x13StartNext = 0;\r
- mPacketName.erase();\r
- mDecodeData.mName.str(mPacketName);\r
- mDecodeData.mErrorDetail.erase();\r
- mDecodeData.mTraceKnownMsg = false;\r
- mDecodeData.mTraceUnknownMsg = false;\r
- mDecodeData.mTraceDump = false;\r
- if (mCurrentAnalyser)\r
- {\r
- delete mCurrentAnalyser;\r
- mCurrentAnalyser = nullptr;\r
- }\r
-}\r
-\r
-PUdpMsgDecoder::PUdpMsgDecoder()\r
-{\r
- mCurrentAnalyser = nullptr;\r
- Reset();\r
-}\r
-\r
-PUdpMsgDecoder::PUdpMsgDecoder(PMessage *nMessage, PClient *nClient)\r
-{\r
- mCurrentAnalyser = nullptr;\r
- Init(nMessage, nClient);\r
-}\r
-\r
-PUdpMsgDecoder::~PUdpMsgDecoder()\r
-{\r
- if (mCurrentAnalyser)\r
- {\r
- delete mCurrentAnalyser;\r
- }\r
-}\r
-\r
-bool PUdpMsgDecoder::Analyse()\r
-{\r
- PUdpMsgAnalyser* nextAnalyser;\r
-\r
- if ((mDecodeData.mState & DECODE_MORE) || mDecodeData.mHandling0x13Sub)\r
- {\r
- if (mCurrentAnalyser)\r
- {\r
- delete mCurrentAnalyser;\r
- mCurrentAnalyser = nullptr;\r
- }\r
- if (mDecodeData.mHandling0x13Sub)\r
- {\r
- mPacketName.erase();\r
- mDecodeData.mName.str(mPacketName);\r
- mCurrentAnalyser = new PUdp0x13(&mDecodeData);\r
- mDecodeData.mState = DECODE_MORE;\r
- }\r
- else\r
- {\r
- mCurrentAnalyser = new PUdpMsgAnalyser(&mDecodeData);\r
- }\r
-\r
- while (mDecodeData.mState & DECODE_MORE)\r
- {\r
- nextAnalyser = mCurrentAnalyser->Analyse();\r
- if (mCurrentAnalyser != nextAnalyser)\r
- {\r
- delete mCurrentAnalyser;\r
- mCurrentAnalyser = nextAnalyser;\r
- }\r
- }\r
- }\r
- return (!(mDecodeData.mState & (DECODE_MORE | DECODE_ERROR | DECODE_UNKNOWN)));\r
-}\r
-\r
-bool PUdpMsgDecoder::Analyse(PMessage *nMessage, PClient *nClient)\r
-{\r
- Init(nMessage, nClient);\r
- return Analyse();\r
-}\r
-\r
-void PUdpMsgDecoder::Init(PMessage *nMessage, PClient *nClient, PGameState *nClientState)\r
-{\r
- mDecodeData.mClientState = nClientState;\r
- Init(nMessage, nClient);\r
-}\r
-\r
-uint8_t PUdpMsgDecoder::GetState()\r
-{\r
- return mDecodeData.mState;\r
-}\r
-\r
-bool PUdpMsgDecoder::IsError()\r
-{\r
- return (mDecodeData.mState & DECODE_ERROR);\r
-}\r
-\r
-bool PUdpMsgDecoder::IsKnown()\r
-{\r
- return (!(mDecodeData.mState & DECODE_UNKNOWN));\r
-}\r
-\r
-bool PUdpMsgDecoder::MoreSubMsg()\r
-{\r
- return mDecodeData.mHandling0x13Sub;\r
-}\r
-\r
-bool PUdpMsgDecoder::IsActionReady()\r
-{\r
- return (mDecodeData.mState & DECODE_ACTION_READY);\r
-}\r
-\r
-bool PUdpMsgDecoder::IsActionDone()\r
-{\r
- return (mDecodeData.mState & DECODE_ACTION_DONE);\r
-}\r
-\r
-bool PUdpMsgDecoder::IsTraceKnownMsg()\r
-{\r
- return mDecodeData.mTraceKnownMsg;\r
-}\r
-\r
-bool PUdpMsgDecoder::IsTraceUnknownMsg()\r
-{\r
- return mDecodeData.mTraceUnknownMsg;\r
-}\r
-\r
-bool PUdpMsgDecoder::IsTraceDump()\r
-{\r
- return mDecodeData.mTraceDump;\r
-}\r
-\r
-void PUdpMsgDecoder::DumpMsg()\r
-{\r
- if (mDecodeData.mMessage)\r
- mDecodeData.mMessage->Dump();\r
-}\r
-\r
-std::string const &PUdpMsgDecoder::GetName()\r
-{\r
- return (mTmpName = mDecodeData.mName.str());\r
-}\r
-\r
-std::string const &PUdpMsgDecoder::GetError()\r
-{\r
- return mDecodeData.mErrorDetail;\r
-}\r
-\r
-bool PUdpMsgDecoder::DoAction()\r
-{\r
- if (mDecodeData.mState & DECODE_ACTION_READY)\r
- {\r
- return mCurrentAnalyser->DoAction();\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-}\r
-\r
-void PUdpMsgDecoder::Reset()\r
-{\r
- Init(nullptr, nullptr);\r
-}\r
+#include "GameServer/Decoder/Includes.hxx"
+#include "Common/Includes.hxx"
+
+void PUdpMsgDecoder::Init(PMessage *nMessage, PClient *nClient)
+{
+ mDecodeData.mMessage = nMessage;
+ mDecodeData.mClient = nClient;
+ mDecodeData.mState = (nMessage && nClient) ? DECODE_MORE : DECODE_UNDEF;
+ mDecodeData.mUnknownType = 0;
+ mDecodeData.mHandling0x13Sub = false;
+ mDecodeData.Sub0x13Start = mDecodeData.Sub0x13StartNext = 0;
+ mPacketName.erase();
+ mDecodeData.mName.str(mPacketName);
+ mDecodeData.mErrorDetail.erase();
+ mDecodeData.mTraceKnownMsg = false;
+ mDecodeData.mTraceUnknownMsg = false;
+ mDecodeData.mTraceDump = false;
+ if (mCurrentAnalyser)
+ {
+ delete mCurrentAnalyser;
+ mCurrentAnalyser = nullptr;
+ }
+}
+
+PUdpMsgDecoder::PUdpMsgDecoder()
+{
+ mCurrentAnalyser = nullptr;
+ Reset();
+}
+
+PUdpMsgDecoder::PUdpMsgDecoder(PMessage *nMessage, PClient *nClient)
+{
+ mCurrentAnalyser = nullptr;
+ Init(nMessage, nClient);
+}
+
+PUdpMsgDecoder::~PUdpMsgDecoder()
+{
+ if (mCurrentAnalyser)
+ {
+ delete mCurrentAnalyser;
+ }
+}
+
+bool PUdpMsgDecoder::Analyse()
+{
+ PUdpMsgAnalyser* nextAnalyser;
+
+ if ((mDecodeData.mState & DECODE_MORE) || mDecodeData.mHandling0x13Sub)
+ {
+ if (mCurrentAnalyser)
+ {
+ delete mCurrentAnalyser;
+ mCurrentAnalyser = nullptr;
+ }
+ if (mDecodeData.mHandling0x13Sub)
+ {
+ mPacketName.erase();
+ mDecodeData.mName.str(mPacketName);
+ mCurrentAnalyser = new PUdp0x13(&mDecodeData);
+ mDecodeData.mState = DECODE_MORE;
+ }
+ else
+ {
+ mCurrentAnalyser = new PUdpMsgAnalyser(&mDecodeData);
+ }
+
+ while (mDecodeData.mState & DECODE_MORE)
+ {
+ nextAnalyser = mCurrentAnalyser->Analyse();
+ if (mCurrentAnalyser != nextAnalyser)
+ {
+ delete mCurrentAnalyser;
+ mCurrentAnalyser = nextAnalyser;
+ }
+ }
+ }
+ return (!(mDecodeData.mState & (DECODE_MORE | DECODE_ERROR | DECODE_UNKNOWN)));
+}
+
+bool PUdpMsgDecoder::Analyse(PMessage *nMessage, PClient *nClient)
+{
+ Init(nMessage, nClient);
+ return Analyse();
+}
+
+void PUdpMsgDecoder::Init(PMessage *nMessage, PClient *nClient, PGameState *nClientState)
+{
+ mDecodeData.mClientState = nClientState;
+ Init(nMessage, nClient);
+}
+
+uint8_t PUdpMsgDecoder::GetState()
+{
+ return mDecodeData.mState;
+}
+
+bool PUdpMsgDecoder::IsError()
+{
+ return (mDecodeData.mState & DECODE_ERROR);
+}
+
+bool PUdpMsgDecoder::IsKnown()
+{
+ return (!(mDecodeData.mState & DECODE_UNKNOWN));
+}
+
+bool PUdpMsgDecoder::MoreSubMsg()
+{
+ return mDecodeData.mHandling0x13Sub;
+}
+
+bool PUdpMsgDecoder::IsActionReady()
+{
+ return (mDecodeData.mState & DECODE_ACTION_READY);
+}
+
+bool PUdpMsgDecoder::IsActionDone()
+{
+ return (mDecodeData.mState & DECODE_ACTION_DONE);
+}
+
+bool PUdpMsgDecoder::IsTraceKnownMsg()
+{
+ return mDecodeData.mTraceKnownMsg;
+}
+
+bool PUdpMsgDecoder::IsTraceUnknownMsg()
+{
+ return mDecodeData.mTraceUnknownMsg;
+}
+
+bool PUdpMsgDecoder::IsTraceDump()
+{
+ return mDecodeData.mTraceDump;
+}
+
+void PUdpMsgDecoder::DumpMsg()
+{
+ if (mDecodeData.mMessage)
+ mDecodeData.mMessage->Dump();
+}
+
+std::string const &PUdpMsgDecoder::GetName()
+{
+ return (mTmpName = mDecodeData.mName.str());
+}
+
+std::string const &PUdpMsgDecoder::GetError()
+{
+ return mDecodeData.mErrorDetail;
+}
+
+bool PUdpMsgDecoder::DoAction()
+{
+ if (mDecodeData.mState & DECODE_ACTION_READY)
+ {
+ return mCurrentAnalyser->DoAction();
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void PUdpMsgDecoder::Reset()
+{
+ Init(nullptr, nullptr);
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <sstream>\r
-#include <string>\r
-\r
-struct PGameState;\r
-class PClient;\r
-class PMessage;\r
-class PUdpMsgAnalyser;\r
-\r
-#define DECODE_UNDEF 0\r
-#define DECODE_ERROR 1 // one error occured on the current decoding step\r
-#define DECODE_UNKNOWN 2 // the current decoded (sub)message is unkown\r
-#define DECODE_MORE 4 // more decoding needed for the (sub)message\r
-#define DECODE_FINISHED 8 // decoding if finished for the whole message\r
-#define DECODE_ACTION_READY 16 // an action is ready to be done\r
-#define DECODE_ACTION_DONE 32 // the action triggered hasn't to be triggered again\r
-#define DECODE_ACTION_IGNORED 64 // the action wasn't performed for some (good) reason (to combine or not with DONE)\r
-#define DECODE_ACTION_FAILED 128 // the action failed totally or partially (to combine or not with DONE)\r
-\r
-struct PMsgDecodeData {\r
- PMessage *mMessage;\r
- PClient *mClient;\r
- uint8_t mState;\r
- uint8_t mUnknownType;\r
- bool mHandling0x13Sub;\r
- uint16_t Sub0x13Start;\r
- uint16_t Sub0x13StartNext;\r
- std::stringstream mName;\r
- std::string mErrorDetail;\r
- bool mTraceKnownMsg;\r
- bool mTraceUnknownMsg;\r
- bool mTraceDump;\r
- PGameState *mClientState; // Temporary until State is put back in Client object\r
-};\r
-\r
-// UDP Message decoder\r
-// boolean methods return true if successful\r
-\r
-class PUdpMsgDecoder {\r
-private:\r
- PMsgDecodeData mDecodeData;\r
- PUdpMsgAnalyser *mCurrentAnalyser;\r
- std::string mPacketName;\r
- std::string mTmpName;\r
-\r
- void Init(PMessage *nMessage, PClient *nClient);\r
-\r
-public:\r
- PUdpMsgDecoder();\r
- PUdpMsgDecoder(PMessage *nMessage, PClient *nClient);\r
- ~PUdpMsgDecoder();\r
-\r
- bool Analyse();\r
- bool Analyse(PMessage *nMessage, PClient *nClient); // Can be used on non initialized or already used object\r
- // Temporary form until State is put back in Client object\r
- void Init(PMessage *nMessage, PClient *nClient, PGameState *nClientState);\r
- uint8_t GetState();\r
- bool IsError();\r
- bool IsKnown();\r
- bool MoreSubMsg();\r
- bool IsActionReady();\r
- bool IsActionDone();\r
- bool IsTraceKnownMsg();\r
- bool IsTraceUnknownMsg();\r
- bool IsTraceDump();\r
- void DumpMsg();\r
- std::string const &GetName();\r
- std::string const &GetError();\r
- bool DoAction();\r
- void Reset();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <sstream>
+#include <string>
+
+struct PGameState;
+class PClient;
+class PMessage;
+class PUdpMsgAnalyser;
+
+#define DECODE_UNDEF 0
+#define DECODE_ERROR 1 // one error occured on the current decoding step
+#define DECODE_UNKNOWN 2 // the current decoded (sub)message is unkown
+#define DECODE_MORE 4 // more decoding needed for the (sub)message
+#define DECODE_FINISHED 8 // decoding if finished for the whole message
+#define DECODE_ACTION_READY 16 // an action is ready to be done
+#define DECODE_ACTION_DONE 32 // the action triggered hasn't to be triggered again
+#define DECODE_ACTION_IGNORED 64 // the action wasn't performed for some (good) reason (to combine or not with DONE)
+#define DECODE_ACTION_FAILED 128 // the action failed totally or partially (to combine or not with DONE)
+
+struct PMsgDecodeData {
+ PMessage *mMessage;
+ PClient *mClient;
+ uint8_t mState;
+ uint8_t mUnknownType;
+ bool mHandling0x13Sub;
+ uint16_t Sub0x13Start;
+ uint16_t Sub0x13StartNext;
+ std::stringstream mName;
+ std::string mErrorDetail;
+ bool mTraceKnownMsg;
+ bool mTraceUnknownMsg;
+ bool mTraceDump;
+ PGameState *mClientState; // Temporary until State is put back in Client object
+};
+
+// UDP Message decoder
+// boolean methods return true if successful
+
+class PUdpMsgDecoder {
+private:
+ PMsgDecodeData mDecodeData;
+ PUdpMsgAnalyser *mCurrentAnalyser;
+ std::string mPacketName;
+ std::string mTmpName;
+
+ void Init(PMessage *nMessage, PClient *nClient);
+
+public:
+ PUdpMsgDecoder();
+ PUdpMsgDecoder(PMessage *nMessage, PClient *nClient);
+ ~PUdpMsgDecoder();
+
+ bool Analyse();
+ bool Analyse(PMessage *nMessage, PClient *nClient); // Can be used on non initialized or already used object
+ // Temporary form until State is put back in Client object
+ void Init(PMessage *nMessage, PClient *nClient, PGameState *nClientState);
+ uint8_t GetState();
+ bool IsError();
+ bool IsKnown();
+ bool MoreSubMsg();
+ bool IsActionReady();
+ bool IsActionDone();
+ bool IsTraceKnownMsg();
+ bool IsTraceUnknownMsg();
+ bool IsTraceDump();
+ void DumpMsg();
+ std::string const &GetName();
+ std::string const &GetError();
+ bool DoAction();
+ void Reset();
+};
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "GameServer/Includes.hxx"\r
-\r
-PUdp0x08::PUdp0x08(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
-{\r
- nDecodeData->mName << "/0x08";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdp0x08::Analyse()\r
-{\r
- mDecodeData->mName << "=Client crash";\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
-\r
- return this;\r
-}\r
-\r
-bool PUdp0x08::DoAction()\r
-{\r
- // Client crashed, close connection from our side\r
- GameServer->ClientDisconnected(mDecodeData->mClient);\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
-\r
- return true;\r
-}\r
+#include "GameServer/Decoder/Includes.hxx"
+#include "GameServer/Includes.hxx"
+
+PUdp0x08::PUdp0x08(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+ nDecodeData->mName << "/0x08";
+}
+
+PUdpMsgAnalyser* PUdp0x08::Analyse()
+{
+ mDecodeData->mName << "=Client crash";
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+ return this;
+}
+
+bool PUdp0x08::DoAction()
+{
+ // Client crashed, close connection from our side
+ GameServer->ClientDisconnected(mDecodeData->mClient);
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+
+ return true;
+}
-#pragma once\r
-\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdp0x08 : public PUdpMsgAnalyser {\r
-public:\r
- PUdp0x08(PMsgDecodeData *nDecodeData);\r
- //~PUdp0x08();\r
- PUdpMsgAnalyser* Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdp0x08 : public PUdpMsgAnalyser {
+public:
+ PUdp0x08(PMsgDecodeData *nDecodeData);
+ //~PUdp0x08();
+ PUdpMsgAnalyser* Analyse();
+ bool DoAction();
+};
-#pragma once\r
-\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdp0x13 : public PUdpMsgAnalyser {\r
-public:\r
- PUdp0x13(PMsgDecodeData *nDecodeData);\r
- //~PUdp0x13();\r
- PUdpMsgAnalyser* Analyse();\r
- //bool DoAction();\r
-};\r
+#pragma once
+
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdp0x13 : public PUdpMsgAnalyser {
+public:
+ PUdp0x13(PMsgDecodeData *nDecodeData);
+ //~PUdp0x13();
+ PUdpMsgAnalyser* Analyse();
+ //bool DoAction();
+};
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-/**** PUdp0x1f ****/\r
-\r
-PUdp0x1f::PUdp0x1f( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x1f";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdp0x1f::Analyse()\r
-{\r
- PUdpMsgAnalyser* nextAnalyser = NULL;\r
- mDecodeData->mState = DECODE_MORE;\r
- uint8_t MsgType = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 7 );\r
- uint8_t MsgSubType = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 8 );\r
-\r
- switch ( MsgType )\r
- {\r
- case 0x00:\r
- {\r
- nextAnalyser = new PUdpHeldItemBasicAction( mDecodeData );\r
- break;\r
- }\r
- case 0x01:\r
- {\r
- nextAnalyser = new PUdpHeldItemAimedAction( mDecodeData );\r
- break;\r
- }\r
- case 0x02:\r
- {\r
- nextAnalyser = new PUdpCharJump( mDecodeData );\r
- break;\r
- }\r
- case 0x17:\r
- {\r
- nextAnalyser = new PUdpUseObject( mDecodeData );\r
- break;\r
- }\r
- case 0x19: // NPC Dialog closed\r
- {\r
- nextAnalyser = new PUdpNPCDialogClose( mDecodeData );\r
- break;\r
- }\r
- case 0x1a: // NPC Dialog action/reply\r
- {\r
- nextAnalyser = new PUdpNPCDialogAction( mDecodeData );\r
- break;\r
- }\r
- case 0x1b:\r
- {\r
- nextAnalyser = new PUdpChatLocal( mDecodeData );\r
- break;\r
- }\r
- case 0x1e: // item move QB<>INV<>GND\r
- {\r
- nextAnalyser = new PUdpItemMove( mDecodeData );\r
- break;\r
- }\r
- case 0x1f: // Slot use\r
- {\r
- nextAnalyser = new PUdpItemSlotUse( mDecodeData );\r
- break;\r
- }\r
- case 0x20: // Use item for hacking, launcher, "launcher" spell\r
- {\r
- nextAnalyser = new PUdpHeldItemLaunchingAction( mDecodeData );\r
- break;\r
- }\r
- case 0x22:\r
- {\r
- nextAnalyser = new PUdpCharExitChair( mDecodeData );\r
- break;\r
- }\r
- case 0x25:\r
- {\r
- mDecodeData->mName << "/0x25";\r
- switch ( MsgSubType )\r
- {\r
- case 0x04: // Hack announcement?\r
- {\r
- nextAnalyser = new PUdpSubskillInc( mDecodeData );\r
- break;\r
- }\r
- case 0x0c: // addons activation\r
- {\r
- nextAnalyser = new PUdpItemAddonActivation( mDecodeData );\r
- break;\r
- }\r
- case 0x14: // Hack announcement?\r
- {\r
- nextAnalyser = new PUdpItemMoveBP( mDecodeData );\r
- break;\r
- }\r
- case 0x16: // ???? confirm reload anim start ???\r
- {\r
- mDecodeData->mUnknownType = MsgSubType;\r
- mDecodeData->mTraceUnknownMsg = true;\r
- break;\r
- }\r
- case 0x17: // Item drop on item\r
- {\r
- nextAnalyser = new PUdpItemDropOnItem( mDecodeData );\r
- break;\r
- }\r
- case 0x18:\r
- {\r
- mDecodeData->mName << "/0x18";\r
- switch ( mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 9 ) )\r
- {\r
- case 0x01: // Use inventory item\r
- {\r
- nextAnalyser = new PUdpItemUse( mDecodeData );\r
- break;\r
- }\r
- case 0x0e: // Request manual reload\r
- {\r
- nextAnalyser = new PUdpItemManualReload( mDecodeData );\r
- break;\r
- }\r
- default:\r
- {\r
- mDecodeData->mUnknownType = MsgSubType;\r
- mDecodeData->mTraceUnknownMsg = true;\r
- break;\r
- }\r
- }\r
- break;\r
- }\r
-\r
- case 0x1d: // ? before Packet0: 0b 03 01 00 1f 00 00 25 1d 00 00 01\r
- case 0x1e: // ? before Packet0: 0d 03 02 00 1f 00 00 25 1e ff ff ff ff 00\r
- default:\r
- {\r
- mDecodeData->mUnknownType = MsgSubType;\r
- mDecodeData->mTraceUnknownMsg = true;\r
- break;\r
- }\r
- }\r
- break;\r
- }\r
- case 0x27:\r
- {\r
- nextAnalyser = new PUdpCloseItemContainer( mDecodeData );\r
- break;\r
- }\r
- case 0x29:\r
- {\r
- nextAnalyser = new PUdpHackSuccess( mDecodeData );\r
- break;\r
- }\r
- case 0x2c:\r
- {\r
- nextAnalyser = new PUdpHackFail( mDecodeData );\r
- break;\r
- }\r
- case 0x2e:\r
- {\r
- nextAnalyser = new PUdpOutfitter( mDecodeData );\r
- break;\r
- }\r
- case 0x2f:\r
- {\r
- nextAnalyser = new PUdpDeathRespawn( mDecodeData );\r
- break;\r
- }\r
- case 0x33:\r
- {\r
- nextAnalyser = new PUdpChatListAdd( mDecodeData );\r
- break;\r
- }\r
- case 0x38:\r
- {\r
- nextAnalyser = new PUdpAppartmentAccess( mDecodeData );\r
- break;\r
- }\r
- case 0x39:\r
- {\r
- nextAnalyser = new PUdpChatListRemove( mDecodeData );\r
- break;\r
- }\r
- case 0x3b:\r
- {\r
- nextAnalyser = new PUdpChatGlobal( mDecodeData );\r
- break;\r
- }\r
- case 0x3d:\r
- {\r
- mDecodeData->mName << "/0x3d";\r
- switch ( MsgSubType ) // In fact MsgSubType is U32, but only lower byte is used\r
- {\r
- case 0x02:\r
- {\r
- nextAnalyser = new PUdpAddGenrepToList( mDecodeData );\r
- break;\r
- }\r
- case 0x03:\r
- {\r
- nextAnalyser = new PUdpAptGRZoning( mDecodeData );\r
- break;\r
- }\r
- case 0x04:\r
- {\r
- nextAnalyser = new PUdpGenrepZoning( mDecodeData );\r
- break;\r
- }\r
- case 0x09:\r
- {\r
- nextAnalyser = new PUdpPopupResponse( mDecodeData );\r
- break;\r
- }\r
- case 0x0a:\r
- {\r
- nextAnalyser = new PUdpAptLocInfo( mDecodeData );\r
- break;\r
- }\r
- case 0x0f:\r
- {\r
- nextAnalyser = new PUdpVhcUse( mDecodeData );\r
- break;\r
- }\r
- case 0x10:\r
- {\r
- nextAnalyser = new PUdpKillSelf( mDecodeData );\r
- break;\r
- }\r
- default:\r
- {\r
- mDecodeData->mUnknownType = MsgSubType;\r
- break;\r
- }\r
- }\r
- break;\r
- }\r
- case 0x3e:\r
- {\r
- nextAnalyser = new PUdpPvPTrade( mDecodeData );\r
- break;\r
- }\r
- case 0x4c:\r
- {\r
- nextAnalyser = new PUdpChatChannels( mDecodeData );\r
- break;\r
- }\r
- default:\r
- {\r
- mDecodeData->mUnknownType = MsgType;\r
- mDecodeData->mTraceUnknownMsg = true;\r
- break;\r
- }\r
- }\r
-\r
- if ( ! nextAnalyser )\r
- {\r
- nextAnalyser = new PUdpMsgUnknown( mDecodeData );\r
- }\r
-\r
- return nextAnalyser;\r
-}\r
+#include "GameServer/Decoder/Includes.hxx"
+#include "Common/Includes.hxx"
+
+/**** PUdp0x1f ****/
+
+PUdp0x1f::PUdp0x1f( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x1f";
+}
+
+PUdpMsgAnalyser* PUdp0x1f::Analyse()
+{
+ PUdpMsgAnalyser* nextAnalyser = NULL;
+ mDecodeData->mState = DECODE_MORE;
+ uint8_t MsgType = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 7 );
+ uint8_t MsgSubType = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 8 );
+
+ switch ( MsgType )
+ {
+ case 0x00:
+ {
+ nextAnalyser = new PUdpHeldItemBasicAction( mDecodeData );
+ break;
+ }
+ case 0x01:
+ {
+ nextAnalyser = new PUdpHeldItemAimedAction( mDecodeData );
+ break;
+ }
+ case 0x02:
+ {
+ nextAnalyser = new PUdpCharJump( mDecodeData );
+ break;
+ }
+ case 0x17:
+ {
+ nextAnalyser = new PUdpUseObject( mDecodeData );
+ break;
+ }
+ case 0x19: // NPC Dialog closed
+ {
+ nextAnalyser = new PUdpNPCDialogClose( mDecodeData );
+ break;
+ }
+ case 0x1a: // NPC Dialog action/reply
+ {
+ nextAnalyser = new PUdpNPCDialogAction( mDecodeData );
+ break;
+ }
+ case 0x1b:
+ {
+ nextAnalyser = new PUdpChatLocal( mDecodeData );
+ break;
+ }
+ case 0x1e: // item move QB<>INV<>GND
+ {
+ nextAnalyser = new PUdpItemMove( mDecodeData );
+ break;
+ }
+ case 0x1f: // Slot use
+ {
+ nextAnalyser = new PUdpItemSlotUse( mDecodeData );
+ break;
+ }
+ case 0x20: // Use item for hacking, launcher, "launcher" spell
+ {
+ nextAnalyser = new PUdpHeldItemLaunchingAction( mDecodeData );
+ break;
+ }
+ case 0x22:
+ {
+ nextAnalyser = new PUdpCharExitChair( mDecodeData );
+ break;
+ }
+ case 0x25:
+ {
+ mDecodeData->mName << "/0x25";
+ switch ( MsgSubType )
+ {
+ case 0x04: // Hack announcement?
+ {
+ nextAnalyser = new PUdpSubskillInc( mDecodeData );
+ break;
+ }
+ case 0x0c: // addons activation
+ {
+ nextAnalyser = new PUdpItemAddonActivation( mDecodeData );
+ break;
+ }
+ case 0x14: // Hack announcement?
+ {
+ nextAnalyser = new PUdpItemMoveBP( mDecodeData );
+ break;
+ }
+ case 0x16: // ???? confirm reload anim start ???
+ {
+ mDecodeData->mUnknownType = MsgSubType;
+ mDecodeData->mTraceUnknownMsg = true;
+ break;
+ }
+ case 0x17: // Item drop on item
+ {
+ nextAnalyser = new PUdpItemDropOnItem( mDecodeData );
+ break;
+ }
+ case 0x18:
+ {
+ mDecodeData->mName << "/0x18";
+ switch ( mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 9 ) )
+ {
+ case 0x01: // Use inventory item
+ {
+ nextAnalyser = new PUdpItemUse( mDecodeData );
+ break;
+ }
+ case 0x0e: // Request manual reload
+ {
+ nextAnalyser = new PUdpItemManualReload( mDecodeData );
+ break;
+ }
+ default:
+ {
+ mDecodeData->mUnknownType = MsgSubType;
+ mDecodeData->mTraceUnknownMsg = true;
+ break;
+ }
+ }
+ break;
+ }
+
+ case 0x1d: // ? before Packet0: 0b 03 01 00 1f 00 00 25 1d 00 00 01
+ case 0x1e: // ? before Packet0: 0d 03 02 00 1f 00 00 25 1e ff ff ff ff 00
+ default:
+ {
+ mDecodeData->mUnknownType = MsgSubType;
+ mDecodeData->mTraceUnknownMsg = true;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x27:
+ {
+ nextAnalyser = new PUdpCloseItemContainer( mDecodeData );
+ break;
+ }
+ case 0x29:
+ {
+ nextAnalyser = new PUdpHackSuccess( mDecodeData );
+ break;
+ }
+ case 0x2c:
+ {
+ nextAnalyser = new PUdpHackFail( mDecodeData );
+ break;
+ }
+ case 0x2e:
+ {
+ nextAnalyser = new PUdpOutfitter( mDecodeData );
+ break;
+ }
+ case 0x2f:
+ {
+ nextAnalyser = new PUdpDeathRespawn( mDecodeData );
+ break;
+ }
+ case 0x33:
+ {
+ nextAnalyser = new PUdpChatListAdd( mDecodeData );
+ break;
+ }
+ case 0x38:
+ {
+ nextAnalyser = new PUdpAppartmentAccess( mDecodeData );
+ break;
+ }
+ case 0x39:
+ {
+ nextAnalyser = new PUdpChatListRemove( mDecodeData );
+ break;
+ }
+ case 0x3b:
+ {
+ nextAnalyser = new PUdpChatGlobal( mDecodeData );
+ break;
+ }
+ case 0x3d:
+ {
+ mDecodeData->mName << "/0x3d";
+ switch ( MsgSubType ) // In fact MsgSubType is U32, but only lower byte is used
+ {
+ case 0x02:
+ {
+ nextAnalyser = new PUdpAddGenrepToList( mDecodeData );
+ break;
+ }
+ case 0x03:
+ {
+ nextAnalyser = new PUdpAptGRZoning( mDecodeData );
+ break;
+ }
+ case 0x04:
+ {
+ nextAnalyser = new PUdpGenrepZoning( mDecodeData );
+ break;
+ }
+ case 0x09:
+ {
+ nextAnalyser = new PUdpPopupResponse( mDecodeData );
+ break;
+ }
+ case 0x0a:
+ {
+ nextAnalyser = new PUdpAptLocInfo( mDecodeData );
+ break;
+ }
+ case 0x0f:
+ {
+ nextAnalyser = new PUdpVhcUse( mDecodeData );
+ break;
+ }
+ case 0x10:
+ {
+ nextAnalyser = new PUdpKillSelf( mDecodeData );
+ break;
+ }
+ default:
+ {
+ mDecodeData->mUnknownType = MsgSubType;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x3e:
+ {
+ nextAnalyser = new PUdpPvPTrade( mDecodeData );
+ break;
+ }
+ case 0x4c:
+ {
+ nextAnalyser = new PUdpChatChannels( mDecodeData );
+ break;
+ }
+ default:
+ {
+ mDecodeData->mUnknownType = MsgType;
+ mDecodeData->mTraceUnknownMsg = true;
+ break;
+ }
+ }
+
+ if ( ! nextAnalyser )
+ {
+ nextAnalyser = new PUdpMsgUnknown( mDecodeData );
+ }
+
+ return nextAnalyser;
+}
-#pragma once\r
-\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdp0x1f : public PUdpMsgAnalyser {\r
-public:\r
- PUdp0x1f(PMsgDecodeData *nDecodeData);\r
- //~PUdp0x1f();\r
- PUdpMsgAnalyser *Analyse();\r
- //bool DoAction();\r
-};\r
+#pragma once
+
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdp0x1f : public PUdpMsgAnalyser {
+public:
+ PUdp0x1f(PMsgDecodeData *nDecodeData);
+ //~PUdp0x1f();
+ PUdpMsgAnalyser *Analyse();
+ //bool DoAction();
+};
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-/**** PUdp0x22 ****/\r
-\r
-PUdp0x22::PUdp0x22(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
-{\r
- nDecodeData->mName << "/0x22";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdp0x22::Analyse()\r
-{\r
- PUdpMsgAnalyser* nextAnalyser = NULL;\r
- mDecodeData->mState = DECODE_MORE;\r
- uint8_t MsgType = mDecodeData->mMessage->U8Data(mDecodeData->Sub0x13Start + 5);\r
- switch(MsgType) // MsgType is probably uint16_t rather than uint8_t\r
- {\r
- case 0x03: // Zoning phase 2\r
- {\r
- nextAnalyser = new PUdpZoning2(mDecodeData);\r
- break;\r
- }\r
- case 0x06: // Char/Clan/Rank/Map Info request\r
- {\r
- nextAnalyser = new PUdpReqInfo(mDecodeData);\r
- break;\r
- }\r
- case 0x0b: // Entity position request\r
- {\r
- nextAnalyser = new PUdpEntityPosRequest(mDecodeData);\r
- break;\r
- }\r
- case 0x0d: // Zoning phase 1\r
- {\r
- nextAnalyser = new PUdpZoning1(mDecodeData);\r
- break;\r
- }\r
- default:\r
- {\r
- mDecodeData->mUnknownType = MsgType;\r
- break;\r
- }\r
- }\r
-\r
- if (! nextAnalyser)\r
- {\r
- nextAnalyser = new PUdpMsgUnknown(mDecodeData);\r
- }\r
-\r
- return nextAnalyser;\r
-}\r
+#include "GameServer/Decoder/Includes.hxx"
+#include "Common/Includes.hxx"
+
+/**** PUdp0x22 ****/
+
+PUdp0x22::PUdp0x22(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+ nDecodeData->mName << "/0x22";
+}
+
+PUdpMsgAnalyser* PUdp0x22::Analyse()
+{
+ PUdpMsgAnalyser* nextAnalyser = NULL;
+ mDecodeData->mState = DECODE_MORE;
+ uint8_t MsgType = mDecodeData->mMessage->U8Data(mDecodeData->Sub0x13Start + 5);
+ switch(MsgType) // MsgType is probably uint16_t rather than uint8_t
+ {
+ case 0x03: // Zoning phase 2
+ {
+ nextAnalyser = new PUdpZoning2(mDecodeData);
+ break;
+ }
+ case 0x06: // Char/Clan/Rank/Map Info request
+ {
+ nextAnalyser = new PUdpReqInfo(mDecodeData);
+ break;
+ }
+ case 0x0b: // Entity position request
+ {
+ nextAnalyser = new PUdpEntityPosRequest(mDecodeData);
+ break;
+ }
+ case 0x0d: // Zoning phase 1
+ {
+ nextAnalyser = new PUdpZoning1(mDecodeData);
+ break;
+ }
+ default:
+ {
+ mDecodeData->mUnknownType = MsgType;
+ break;
+ }
+ }
+
+ if (! nextAnalyser)
+ {
+ nextAnalyser = new PUdpMsgUnknown(mDecodeData);
+ }
+
+ return nextAnalyser;
+}
-#pragma once\r
-\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdp0x22 : public PUdpMsgAnalyser {\r
-public:\r
- PUdp0x22(PMsgDecodeData *nDecodeData);\r
- //~PUdp0x22();\r
- PUdpMsgAnalyser *Analyse();\r
- //bool DoAction();\r
-};\r
+#pragma once
+
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdp0x22 : public PUdpMsgAnalyser {
+public:
+ PUdp0x22(PMsgDecodeData *nDecodeData);
+ //~PUdp0x22();
+ PUdpMsgAnalyser *Analyse();
+ //bool DoAction();
+};
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-/**** PUdp0x2b ****/\r
-\r
-PUdp0x2b::PUdp0x2b(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
-{\r
- nDecodeData->mName << "/0x2b";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdp0x2b::Analyse()\r
-{\r
- PUdpMsgAnalyser* nextAnalyser = nullptr;\r
- mDecodeData->mState = DECODE_MORE;\r
- uint8_t MsgType = mDecodeData->mMessage->U8Data(mDecodeData->Sub0x13Start + 5);\r
- switch(MsgType)\r
- {\r
- case 0x17: // ReceiveDB Terminal Command\r
- {\r
- nextAnalyser = new PUdpReceiveDB(mDecodeData);\r
- break;\r
- }\r
- case 0x18: // UpdateDB Terminal Command\r
- {\r
- nextAnalyser = new PUdpUpdateDB(mDecodeData);\r
- break;\r
- }\r
- case 0x19: // TryAccess Terminal Command\r
- {\r
- nextAnalyser = new PUdpTryAccessDB(mDecodeData);\r
- break;\r
- }\r
- case 0x1b: // DB Query and Command\r
- {\r
- nextAnalyser = new PUdpQueryDB(mDecodeData);\r
- break;\r
- }\r
- case 0x1f: // Citycom?\r
- {\r
- nextAnalyser = new PUdpTeminal0x1f(mDecodeData);\r
- break;\r
- }\r
-\r
- default:\r
- {\r
- mDecodeData->mUnknownType = MsgType;\r
- break;\r
- }\r
- }\r
-\r
- if (! nextAnalyser)\r
- {\r
- nextAnalyser = new PUdpMsgUnknown(mDecodeData);\r
- }\r
-\r
- return nextAnalyser;\r
-}\r
+#include "GameServer/Decoder/Includes.hxx"
+#include "Common/Includes.hxx"
+
+/**** PUdp0x2b ****/
+
+PUdp0x2b::PUdp0x2b(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+ nDecodeData->mName << "/0x2b";
+}
+
+PUdpMsgAnalyser* PUdp0x2b::Analyse()
+{
+ PUdpMsgAnalyser* nextAnalyser = nullptr;
+ mDecodeData->mState = DECODE_MORE;
+ uint8_t MsgType = mDecodeData->mMessage->U8Data(mDecodeData->Sub0x13Start + 5);
+ switch(MsgType)
+ {
+ case 0x17: // ReceiveDB Terminal Command
+ {
+ nextAnalyser = new PUdpReceiveDB(mDecodeData);
+ break;
+ }
+ case 0x18: // UpdateDB Terminal Command
+ {
+ nextAnalyser = new PUdpUpdateDB(mDecodeData);
+ break;
+ }
+ case 0x19: // TryAccess Terminal Command
+ {
+ nextAnalyser = new PUdpTryAccessDB(mDecodeData);
+ break;
+ }
+ case 0x1b: // DB Query and Command
+ {
+ nextAnalyser = new PUdpQueryDB(mDecodeData);
+ break;
+ }
+ case 0x1f: // Citycom?
+ {
+ nextAnalyser = new PUdpTeminal0x1f(mDecodeData);
+ break;
+ }
+
+ default:
+ {
+ mDecodeData->mUnknownType = MsgType;
+ break;
+ }
+ }
+
+ if (! nextAnalyser)
+ {
+ nextAnalyser = new PUdpMsgUnknown(mDecodeData);
+ }
+
+ return nextAnalyser;
+}
-#pragma once\r
-\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdp0x2b : public PUdpMsgAnalyser {\r
-public:\r
- PUdp0x2b(PMsgDecodeData *nDecodeData);\r
- //~PUdp0x2b();\r
- PUdpMsgAnalyser *Analyse();\r
- //bool DoAction();\r
-};\r
+#pragma once
+
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdp0x2b : public PUdpMsgAnalyser {
+public:
+ PUdp0x2b(PMsgDecodeData *nDecodeData);
+ //~PUdp0x2b();
+ PUdpMsgAnalyser *Analyse();
+ //bool DoAction();
+};
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-/**** PUdpMsgAnalyser ****/\r
-\r
-int PUdpMsgAnalyser::smAnaCount = 0; // temp for check\r
-\r
-PUdpMsgAnalyser::PUdpMsgAnalyser(PMsgDecodeData* nDecodeData)\r
-{\r
- mDecodeData = nDecodeData;\r
- if (++smAnaCount > 2) // temp for check\r
- Console->Print(RED, BLACK, "Analyser instances count: %d", smAnaCount); // temp for check\r
-}\r
-\r
-PUdpMsgAnalyser::~PUdpMsgAnalyser()\r
-{\r
- --smAnaCount;\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpMsgAnalyser::Analyse()\r
-{\r
- PUdpMsgAnalyser* nextAnalyser;\r
- uint8_t MsgType;\r
-\r
- mDecodeData->mState = DECODE_MORE;\r
-//mDecodeData->mTraceKnownMsg = true; // Don't want to trace all known messages\r
-mDecodeData->mTraceUnknownMsg = true; // Want to show all unknown messages\r
-\r
- *(mDecodeData->mMessage) >> MsgType;\r
- switch(MsgType)\r
- {\r
- case 0x01:\r
- {\r
- nextAnalyser = new PUdpSync0(mDecodeData);\r
- break;\r
- }\r
- case 0x03:\r
- {\r
- nextAnalyser = new PUdpSync1(mDecodeData);\r
- break;\r
- }\r
- case 0x08:\r
- {\r
- nextAnalyser = new PUdp0x08(mDecodeData);\r
- break;\r
- }\r
- case 0x13:\r
- {\r
- nextAnalyser = new PUdp0x13(mDecodeData);\r
- break;\r
- }\r
- default:\r
- {\r
- mDecodeData->mUnknownType = MsgType;\r
- nextAnalyser = new PUdpMsgUnknown(mDecodeData);\r
- break;\r
- }\r
- }\r
- return nextAnalyser;\r
-}\r
-\r
-bool PUdpMsgAnalyser::DoAction()\r
-{\r
- return false; // no action at this level\r
-}\r
-\r
-\r
-/**** Unkown UDP message ****/\r
-\r
-PUdpMsgUnknown::PUdpMsgUnknown(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
-{\r
- char hexstr[16];\r
-\r
- nDecodeData->mState = DECODE_UNKNOWN;\r
- snprintf(hexstr, 16, "/0x%02x", mDecodeData->mUnknownType);\r
- mDecodeData->mName << hexstr;\r
- nDecodeData->mName << "=Unknown";\r
-}\r
-\r
-/*PUdpMsgUnknown::~PUdpMsgUnknown()\r
-{\r
-}*/\r
-\r
-/*bool PUdpMsgUnknown::DoAction()\r
-{\r
- return false;\r
-}*/\r
-\r
-/**** Ignore UDP message ****/\r
-\r
-PUdpMsgIgnore::PUdpMsgIgnore(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
-{\r
- char hexstr[16];\r
-\r
- nDecodeData->mState = DECODE_FINISHED;\r
- snprintf(hexstr, 16, "/0x%02x", mDecodeData->mUnknownType);\r
- mDecodeData->mName << hexstr;\r
- nDecodeData->mName << "=Ignore";\r
-}\r
-\r
-/*PUdpMsgUnknown::~PUdpMsgUnknown()\r
-{\r
-}*/\r
-\r
-/*bool PUdpMsgUnknown::DoAction()\r
-{\r
- return false;\r
-}*/\r
+#include "GameServer/Decoder/Includes.hxx"
+#include "Common/Includes.hxx"
+
+/**** PUdpMsgAnalyser ****/
+
+int PUdpMsgAnalyser::smAnaCount = 0; // temp for check
+
+PUdpMsgAnalyser::PUdpMsgAnalyser(PMsgDecodeData* nDecodeData)
+{
+ mDecodeData = nDecodeData;
+ if (++smAnaCount > 2) // temp for check
+ Console->Print(RED, BLACK, "Analyser instances count: %d", smAnaCount); // temp for check
+}
+
+PUdpMsgAnalyser::~PUdpMsgAnalyser()
+{
+ --smAnaCount;
+}
+
+PUdpMsgAnalyser* PUdpMsgAnalyser::Analyse()
+{
+ PUdpMsgAnalyser* nextAnalyser;
+ uint8_t MsgType;
+
+ mDecodeData->mState = DECODE_MORE;
+//mDecodeData->mTraceKnownMsg = true; // Don't want to trace all known messages
+mDecodeData->mTraceUnknownMsg = true; // Want to show all unknown messages
+
+ *(mDecodeData->mMessage) >> MsgType;
+ switch(MsgType)
+ {
+ case 0x01:
+ {
+ nextAnalyser = new PUdpSync0(mDecodeData);
+ break;
+ }
+ case 0x03:
+ {
+ nextAnalyser = new PUdpSync1(mDecodeData);
+ break;
+ }
+ case 0x08:
+ {
+ nextAnalyser = new PUdp0x08(mDecodeData);
+ break;
+ }
+ case 0x13:
+ {
+ nextAnalyser = new PUdp0x13(mDecodeData);
+ break;
+ }
+ default:
+ {
+ mDecodeData->mUnknownType = MsgType;
+ nextAnalyser = new PUdpMsgUnknown(mDecodeData);
+ break;
+ }
+ }
+ return nextAnalyser;
+}
+
+bool PUdpMsgAnalyser::DoAction()
+{
+ return false; // no action at this level
+}
+
+
+/**** Unkown UDP message ****/
+
+PUdpMsgUnknown::PUdpMsgUnknown(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+ char hexstr[16];
+
+ nDecodeData->mState = DECODE_UNKNOWN;
+ snprintf(hexstr, 16, "/0x%02x", mDecodeData->mUnknownType);
+ mDecodeData->mName << hexstr;
+ nDecodeData->mName << "=Unknown";
+}
+
+/*PUdpMsgUnknown::~PUdpMsgUnknown()
+{
+}*/
+
+/*bool PUdpMsgUnknown::DoAction()
+{
+ return false;
+}*/
+
+/**** Ignore UDP message ****/
+
+PUdpMsgIgnore::PUdpMsgIgnore(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+ char hexstr[16];
+
+ nDecodeData->mState = DECODE_FINISHED;
+ snprintf(hexstr, 16, "/0x%02x", mDecodeData->mUnknownType);
+ mDecodeData->mName << hexstr;
+ nDecodeData->mName << "=Ignore";
+}
+
+/*PUdpMsgUnknown::~PUdpMsgUnknown()
+{
+}*/
+
+/*bool PUdpMsgUnknown::DoAction()
+{
+ return false;
+}*/
-#pragma once\r
-\r
-#include <cstdint>\r
-\r
-struct PMsgDecodeData;\r
-\r
-class PUdpMsgAnalyser {\r
- friend class PUdpMsgDecoder;\r
-\r
-protected:\r
- PMsgDecodeData* mDecodeData;\r
-\r
-public:\r
- PUdpMsgAnalyser(PMsgDecodeData *nDecodeData);\r
- virtual ~PUdpMsgAnalyser();\r
-\r
- virtual PUdpMsgAnalyser *Analyse();\r
- virtual bool DoAction();\r
-\r
- static int32_t smAnaCount; // temp for check\r
-\r
-};\r
-\r
-class PUdpMsgUnknown : public PUdpMsgAnalyser {\r
-public:\r
- PUdpMsgUnknown(PMsgDecodeData *nDecodeData);\r
- //~PUdpMsgUnknown();\r
-\r
- //bool DoAction();\r
-};\r
-\r
-class PUdpMsgIgnore : public PUdpMsgAnalyser {\r
-public:\r
- PUdpMsgIgnore(PMsgDecodeData *nDecodeData);\r
- //~PUdpMsgUnknown();\r
-\r
- //bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+
+struct PMsgDecodeData;
+
+class PUdpMsgAnalyser {
+ friend class PUdpMsgDecoder;
+
+protected:
+ PMsgDecodeData* mDecodeData;
+
+public:
+ PUdpMsgAnalyser(PMsgDecodeData *nDecodeData);
+ virtual ~PUdpMsgAnalyser();
+
+ virtual PUdpMsgAnalyser *Analyse();
+ virtual bool DoAction();
+
+ static int32_t smAnaCount; // temp for check
+
+};
+
+class PUdpMsgUnknown : public PUdpMsgAnalyser {
+public:
+ PUdpMsgUnknown(PMsgDecodeData *nDecodeData);
+ //~PUdpMsgUnknown();
+
+ //bool DoAction();
+};
+
+class PUdpMsgIgnore : public PUdpMsgAnalyser {
+public:
+ PUdpMsgIgnore(PMsgDecodeData *nDecodeData);
+ //~PUdpMsgUnknown();
+
+ //bool DoAction();
+};
-#pragma once\r
-\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpAptLocInfo : public PUdpMsgAnalyser {\r
-public:\r
- PUdpAptLocInfo(PMsgDecodeData *nDecodeData);\r
- //~PUdpAptLocInfo();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpAptLocInfo : public PUdpMsgAnalyser {
+public:
+ PUdpAptLocInfo(PMsgDecodeData *nDecodeData);
+ //~PUdpAptLocInfo();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#include <string>\r
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-#define JUMPHEIGHT 160\r
-\r
-/**** PUdpCharPosUpdate ****/\r
-\r
-PUdpCharPosUpdate::PUdpCharPosUpdate( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x20";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpCharPosUpdate::Analyse()\r
-{\r
- mDecodeData->mName << "=Char position update";\r
-\r
-//mDecodeData->mTraceUnknownMsg = true; // temp stop being bugged with unknown move msg\r
-//mDecodeData->mTraceKnownMsg = true;\r
-\r
- PMessage* nMsg = mDecodeData->mMessage;\r
- nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 4 );\r
-\r
- *nMsg >> mInfoBitfield;\r
-//bitfield [C?AL UXZY] packet read from LSB\r
-// 8.21 8421\r
-//Console->Print(YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Bitfield value %02x", mInfoBitfield);\r
- if ( mInfoBitfield & 0x80 ) // Sitting on chair\r
- {\r
- if ( mInfoBitfield & 0x7f )\r
- {\r
- mDecodeData->mName << " + mixed bitfield (" << mInfoBitfield << ")";\r
- mDecodeData->mState = DECODE_UNKNOWN | DECODE_FINISHED;\r
- Console->Print( YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Client %d sent Mixed field value %x", mDecodeData->mClient->GetID(), mInfoBitfield );\r
- }\r
- else\r
- {\r
- mDecodeData->mName << " (Char sitting)";\r
-\r
- *nMsg >> mChairItemID;\r
- *nMsg >> mChairItemSeat;\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
-//mDecodeData->mTraceKnownMsg = true;\r
-//mDecodeData->mTraceDump = true;\r
- if ( gDevDebug ) Console->Print( "%s Localid %d sitting on object %d (0x%08x) seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetLocalID(), mChairItemID, mChairItemID, mChairItemSeat );\r
- }\r
- }\r
- else\r
- {\r
- if ( mInfoBitfield & 0x01 )\r
- {\r
- *nMsg >> mNewY;\r
- }\r
- if ( mInfoBitfield & 0x02 )\r
- {\r
- *nMsg >> mNewZ;\r
- }\r
- if ( mInfoBitfield & 0x04 )\r
- {\r
- *nMsg >> mNewX;\r
- }\r
- if ( mInfoBitfield & 0x08 )\r
- {\r
- *nMsg >> mNewUD;\r
- }\r
- if ( mInfoBitfield & 0x10 )\r
- {\r
- *nMsg >> mNewLR;\r
- }\r
- if ( mInfoBitfield & 0x20 )\r
- {\r
- *nMsg >> mNewAct;\r
- }\r
- if ( mInfoBitfield & 0x40 ) // purpose unknown\r
- {\r
- *nMsg >> mNewUnknown;\r
- if ( gDevDebug && mNewUnknown )\r
- {\r
- Console->Print( YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Client %d sent field 0x40 (in %x) value %x", mDecodeData->mClient->GetID(), mInfoBitfield, mNewUnknown );\r
- }\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- }\r
-\r
- return this;\r
-}\r
-\r
-bool PUdpCharPosUpdate::DoAction()\r
-{\r
- PClient* nClient = mDecodeData->mClient;\r
- PChar* nChar = nClient->GetChar();\r
- PMessage* tmpMsg;\r
-\r
- if ( ! (mInfoBitfield & 0x80) )\r
- {\r
- uint32_t nSeatableObjectId;\r
- uint8_t nSeatId;\r
- if( nChar->GetSeatInUse(&nSeatableObjectId, &nSeatId) == seat_vhc )\r
- {\r
- tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, nSeatableObjectId, nSeatId );\r
- nClient->FillInUDP_ID(tmpMsg);\r
- nClient->SendUDPMessage( tmpMsg );\r
- mChairItemID = nSeatableObjectId;\r
- mChairItemSeat = nSeatId;\r
- mInfoBitfield = 0x80;\r
- }\r
- }\r
-\r
- if ( mInfoBitfield & 0x80 ) // Sitting on chair\r
- {\r
- //tmpMsg = MsgBuilder->BuildCharSittingMsg(nClient, mChairItemID);\r
- //tmpMsg = MsgBuilder->BuildCharSittingMsg(nClient);\r
- //ClientManager->UDPBroadcast(tmpMsg, nClient, 5000); // TODO: Get the range from config\r
- tmpMsg = MsgBuilder->BuildCharPosUpdateMsg( nClient );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient, 5000 ); // TODO: Get the range from config\r
- }\r
- else\r
- {\r
- bool IsRealMove = false;\r
-\r
- if (( mInfoBitfield & 0x01 ) && ( nChar->Coords.mY != mNewY ) )\r
- {\r
- nChar->Coords.mY = mNewY;\r
- IsRealMove = true;\r
- }\r
- if (( mInfoBitfield & 0x02 ) && ( nChar->Coords.mZ != mNewZ ) )\r
- {\r
- nChar->Coords.mZ = mNewZ;\r
- IsRealMove = true;\r
- }\r
- if (( mInfoBitfield & 0x04 ) && ( nChar->Coords.mX != mNewX ) )\r
- {\r
- nChar->Coords.mX = mNewX;\r
- IsRealMove = true;\r
- }\r
- if ( mInfoBitfield & 0x08 )\r
- {\r
- nChar->Coords.mUD = mNewUD;\r
- //IsRealMove = true;\r
- }\r
- if (( mInfoBitfield & 0x10 ) && ( nChar->Coords.mLR != mNewLR ) )\r
- {\r
- nChar->Coords.mLR = mNewLR;\r
- IsRealMove = true;\r
- }\r
- if ( mInfoBitfield & 0x20 )\r
- {\r
- nChar->Coords.mAct = mNewAct;\r
- }\r
- if ( mInfoBitfield & 0x20 )\r
- {\r
- nChar->Coords.mUnknown = mNewUnknown;\r
- }\r
- // movement action byte mask:\r
- // 0x00 NC has no focus (player alt+tab'ed out)\r
- // 0x02 kneeing\r
- // 0x20 Walk mode (= not run mode)\r
- // 0x08 left step\r
- // 0x10 right step\r
- // 0x40 forward\r
- // 0x80 backward\r
- // bits: 00000000\r
- // BFWRL.K.\r
-\r
- if ( IsRealMove )\r
- {\r
- nChar->SetDirtyFlag();\r
- }\r
- /*if(IsRealMove)\r
- if(mInfoBitfield == 0x7f)\r
- {\r
- tmpMsg = MsgBuilder->BuildCharPosUpdateMsg(nClient);\r
- ClientManager->UDPBroadcast(tmpMsg, nClient, 5000); // TODO: Get the range from config\r
- }*/\r
-\r
- uint16_t nSaveZ = nChar->Coords.mZ;\r
- if(nChar->Coords.mJumpingState)\r
- {\r
- mInfoBitfield |= 0x02; // Update Z and Act only\r
- if(nChar->Coords.mJumpingState == 1)\r
- {\r
- if ( gDevDebug ) Console->Print( "%s Send moving jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- (nChar->Coords.mZ) += JUMPHEIGHT;\r
- nChar->Coords.mJumpingState = 2; // Jump done\r
- }\r
- else\r
- nChar->Coords.mJumpingState = 0; // No pending jump\r
- }\r
-\r
- tmpMsg = MsgBuilder->BuildCharPosUpdate2Msg( nClient, mInfoBitfield );\r
-\r
- if(nChar->Coords.mJumpingState)\r
- nChar->Coords.mZ = nSaveZ;\r
-\r
- ClientManager->UDPBroadcast( tmpMsg, nClient, 5000, true );\r
-\r
- if ( IsRealMove && nClient->GetDebugMode( DBG_LOCATION ) )\r
- {\r
- char DbgMessage[128];\r
- float f[3];\r
-// uint32_t h[3];\r
- f[0] = nChar->Coords.mY - 32000;\r
- f[1] = nChar->Coords.mZ - 32000;\r
- f[2] = nChar->Coords.mX - 32000;\r
- snprintf( DbgMessage, 128, "position y:%0.1f z:%0.1f x:%0.1f lr:%d (Act=%x BF=%x)", f[0], f[1], f[2], nChar->Coords.mLR, nChar->Coords.mAct , mInfoBitfield );\r
- Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
- }\r
- /*{\r
- uint16_t p[3];\r
- p[0] = nChar->Coords.mY;\r
- p[1] = nChar->Coords.mZ;\r
- p[2] = nChar->Coords.mX;\r
- for(int i = 0; i<3; i++)\r
- {\r
- if(p[i]< nChar->Coords.minPos[i])\r
- nChar->Coords.minPos[i] = p[i];\r
- if(p[i]> nChar->Coords.maxPos[i])\r
- nChar->Coords.maxPos[i] = p[i];\r
- }\r
- }*/\r
-\r
- if(gDevDebug && IsRealMove)\r
- Console->Print("%s Char %d position : X(%d) Y(%d) Z(%d) U/D(%d) L/R(%d) Action(%02x)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetID(), nChar->Coords.mX, nChar->Coords.mY, nChar->Coords.mZ, nChar->Coords.mUD, nChar->Coords.mLR, nChar->Coords.mAct);\r
- }\r
- if ( mInfoBitfield >= 0x7f )\r
- {\r
- tmpMsg = MsgBuilder->BuildCharHealthUpdateMsg( nClient );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
-\r
-\r
-/**** PUdpCharExitChair ****/\r
-\r
-PUdpCharExitChair::PUdpCharExitChair( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x22";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpCharExitChair::Analyse()\r
-{\r
- mDecodeData->mName << "=Char exiting chair";\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
-\r
- return this;\r
-}\r
-\r
-bool PUdpCharExitChair::DoAction()\r
-{\r
- DoLeaveChair( mDecodeData->mClient->GetChar(), mDecodeData->mClient );\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
-\r
-bool PUdpCharExitChair::DoLeaveChair( PChar* nChar, PClient* nClient, PSpawnedVehicle* nVhc, bool nForce )\r
-{\r
- if ( ! nClient )\r
- nClient = ClientManager->getClientByChar( nChar->GetID() );\r
- if ( ! nClient )\r
- {\r
- Console->Print("%s PUdpCharExitChair::DoLeaveChair called without PClient* and client not available when searching by char.", Console->ColorText( RED, BLACK, "[ERROR]" ) );\r
- return false;\r
- }\r
-\r
- PMessage* tmpMsg;\r
- uint32_t cSeatObjectId;\r
- uint8_t cSeatId;\r
- PSeatType cSeatType = nChar->GetSeatInUse( &cSeatObjectId, &cSeatId );\r
- uint32_t tNowTime = GameServer->GetGameTime();\r
- bool ReadyToExit = false;\r
-\r
- // This is only for investigation on subway timing\r
- if ( nClient->GetDebugMode( DBG_SUBWAY ) && ( cSeatType == seat_subway ) )\r
- {\r
- char DbgMessage[80];\r
- uint8_t tCabId;\r
- Subway->GetInfoIndex( cSeatObjectId, &tCabId );\r
- uint8_t tStationId = Subway->GetStation( cSeatObjectId, tNowTime );\r
- std::string* StationName = Subway->GetStationName( tStationId );\r
- std::string OpenState = ( Subway->IsDoorOpen( cSeatObjectId, tNowTime ) ? "open" : "closed" );\r
-\r
- snprintf( DbgMessage, 80, "Cab %d (%d) is in station %s (%d). Door is %s (time: %d)", tCabId, cSeatObjectId, StationName->c_str(), tStationId, OpenState.c_str(), tNowTime );\r
- DbgMessage[79] = 0;\r
- Chat->send( nClient, CHAT_DIRECT, "System", DbgMessage );\r
- delete StationName;\r
- }\r
- // end investigation\r
-\r
- if ( cSeatType )\r
- {\r
- PWorld* tWorld = Worlds->GetWorld( nChar->GetLocation() );\r
-\r
- if ( cSeatType == seat_chair )\r
- {\r
- tWorld->CharLeaveChair( nClient->GetLocalID(), cSeatObjectId );\r
- nChar->SetSeatInUse( seat_none );\r
- ReadyToExit = true;\r
- }\r
- else if ( cSeatType == seat_subway )\r
- {\r
- if ( Subway->IsDoorOpen( cSeatObjectId, tNowTime ) || nForce )\r
- {\r
- Subway->GetStationExitPosition( &( nChar->Coords ), Subway->GetStation( cSeatObjectId, tNowTime ), GetRandomFloat() );\r
- Subway->UnsetSeatUser( cSeatObjectId, cSeatId, nChar->GetID() );\r
- nChar->SetSeatInUse( seat_none );\r
- ReadyToExit = true;\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, cSeatObjectId ); // "Damn, locked"\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- else if ( cSeatType == seat_vhc )\r
- {\r
- PSpawnedVehicle* tVhc = tWorld->GetSpawnedVehicles()->GetVehicle( cSeatObjectId );\r
- if ( tVhc && (!nVhc || (tVhc == nVhc) || nForce) )\r
- {\r
- PVhcCoordinates tCoords = tVhc->GetPosition();\r
- tVhc->UnsetSeatUser( cSeatId, nChar->GetID() );\r
- nChar->SetSeatInUse( seat_none );\r
- nChar->Coords.SetPosition( tCoords.GetY(), tCoords.GetZ(), tCoords.GetX() ); // to complete with LR\r
- ReadyToExit = true;\r
- }\r
- }\r
- else\r
- {\r
- Console->Print( "%s PUdpCharExitChair::DoLeaveChair : Invalid seat type %d", Console->ColorText( RED, BLACK, "[ERROR]" ), cSeatType );\r
- }\r
-\r
- if ( ReadyToExit )\r
- {\r
- nChar->SetSeatInUse( seat_none );\r
-\r
- tmpMsg = MsgBuilder->BuildCharExitSeatMsg( nClient );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
-\r
- if ( gDevDebug ) Console->Print( "%s Localchar %d get up from chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nClient->GetLocalID(), cSeatObjectId );\r
- return true;\r
- }\r
- }\r
-\r
- return false;\r
-}\r
-\r
-/**** PUdpCharJump ****/\r
-\r
-PUdpCharJump::PUdpCharJump( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x02";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpCharJump::Analyse()\r
-{\r
- mDecodeData->mName << "=Char jumping";\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
-\r
- return this;\r
-}\r
-\r
-bool PUdpCharJump::DoAction()\r
-{\r
- PClient* nClient = mDecodeData->mClient;\r
- PChar* nChar = nClient->GetChar();\r
-\r
- if( nChar->Coords.mAct & 0xd8 ) // if moving, don't jump now and wait next update\r
- {\r
- nChar->Coords.mJumpingState = 1; // Jump pending. Do at next pos update\r
- if ( gDevDebug ) Console->Print( "%s Prepare moving jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- }\r
- else // If not moving, jump now\r
- {\r
- if ( gDevDebug ) Console->Print( "%s Send static jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- uint8_t mInfoBitfield = 0x22; // Update Z and Act only\r
- uint16_t nSaveZ = nChar->Coords.mZ;\r
- (nChar->Coords.mZ) += JUMPHEIGHT;\r
- PMessage* tmpMsg = MsgBuilder->BuildCharPosUpdate2Msg( nClient, mInfoBitfield );\r
- nChar->Coords.mZ = nSaveZ;\r
- nChar->Coords.mJumpingState = 2; // Jump done\r
- ClientManager->UDPBroadcast( tmpMsg, nClient, 5000, true );\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
-\r
- return true;\r
-}\r
-\r
-\r
-/**** PUdpCharTargeting ****/\r
-\r
-PUdpCharTargeting::PUdpCharTargeting( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x2d";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpCharTargeting::Analyse()\r
-{\r
- mDecodeData->mName << "=Targeting char";\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
-\r
- return this;\r
-}\r
-\r
-bool PUdpCharTargeting::DoAction()\r
-{\r
- PClient* nClient = mDecodeData->mClient;\r
- PChar* tChar = nClient->GetChar();\r
- uint16_t CharID = mDecodeData->mMessage->U16Data( mDecodeData->Sub0x13Start + 2 );\r
- uint8_t strangeval1 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 4 );\r
- uint8_t strangeval2 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 5 );\r
- uint8_t strangeval3 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 6 );\r
-\r
- tChar->SetLookingAt( CharID );\r
-\r
- if ( gDevDebug )\r
- Console->Print( "%s Char %d targeting char %d. // %d %d %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetID(), CharID, strangeval1, strangeval2, strangeval3 );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
+#include <string>
+#include "GameServer/Decoder/Includes.hxx"
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+#define JUMPHEIGHT 160
+
+/**** PUdpCharPosUpdate ****/
+
+PUdpCharPosUpdate::PUdpCharPosUpdate( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x20";
+}
+
+PUdpMsgAnalyser* PUdpCharPosUpdate::Analyse()
+{
+ mDecodeData->mName << "=Char position update";
+
+//mDecodeData->mTraceUnknownMsg = true; // temp stop being bugged with unknown move msg
+//mDecodeData->mTraceKnownMsg = true;
+
+ PMessage* nMsg = mDecodeData->mMessage;
+ nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 4 );
+
+ *nMsg >> mInfoBitfield;
+//bitfield [C?AL UXZY] packet read from LSB
+// 8.21 8421
+//Console->Print(YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Bitfield value %02x", mInfoBitfield);
+ if ( mInfoBitfield & 0x80 ) // Sitting on chair
+ {
+ if ( mInfoBitfield & 0x7f )
+ {
+ mDecodeData->mName << " + mixed bitfield (" << mInfoBitfield << ")";
+ mDecodeData->mState = DECODE_UNKNOWN | DECODE_FINISHED;
+ Console->Print( YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Client %d sent Mixed field value %x", mDecodeData->mClient->GetID(), mInfoBitfield );
+ }
+ else
+ {
+ mDecodeData->mName << " (Char sitting)";
+
+ *nMsg >> mChairItemID;
+ *nMsg >> mChairItemSeat;
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+//mDecodeData->mTraceKnownMsg = true;
+//mDecodeData->mTraceDump = true;
+ if ( gDevDebug ) Console->Print( "%s Localid %d sitting on object %d (0x%08x) seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetLocalID(), mChairItemID, mChairItemID, mChairItemSeat );
+ }
+ }
+ else
+ {
+ if ( mInfoBitfield & 0x01 )
+ {
+ *nMsg >> mNewY;
+ }
+ if ( mInfoBitfield & 0x02 )
+ {
+ *nMsg >> mNewZ;
+ }
+ if ( mInfoBitfield & 0x04 )
+ {
+ *nMsg >> mNewX;
+ }
+ if ( mInfoBitfield & 0x08 )
+ {
+ *nMsg >> mNewUD;
+ }
+ if ( mInfoBitfield & 0x10 )
+ {
+ *nMsg >> mNewLR;
+ }
+ if ( mInfoBitfield & 0x20 )
+ {
+ *nMsg >> mNewAct;
+ }
+ if ( mInfoBitfield & 0x40 ) // purpose unknown
+ {
+ *nMsg >> mNewUnknown;
+ if ( gDevDebug && mNewUnknown )
+ {
+ Console->Print( YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Client %d sent field 0x40 (in %x) value %x", mDecodeData->mClient->GetID(), mInfoBitfield, mNewUnknown );
+ }
+ }
+
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ }
+
+ return this;
+}
+
+bool PUdpCharPosUpdate::DoAction()
+{
+ PClient* nClient = mDecodeData->mClient;
+ PChar* nChar = nClient->GetChar();
+ PMessage* tmpMsg;
+
+ if ( ! (mInfoBitfield & 0x80) )
+ {
+ uint32_t nSeatableObjectId;
+ uint8_t nSeatId;
+ if( nChar->GetSeatInUse(&nSeatableObjectId, &nSeatId) == seat_vhc )
+ {
+ tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, nSeatableObjectId, nSeatId );
+ nClient->FillInUDP_ID(tmpMsg);
+ nClient->SendUDPMessage( tmpMsg );
+ mChairItemID = nSeatableObjectId;
+ mChairItemSeat = nSeatId;
+ mInfoBitfield = 0x80;
+ }
+ }
+
+ if ( mInfoBitfield & 0x80 ) // Sitting on chair
+ {
+ //tmpMsg = MsgBuilder->BuildCharSittingMsg(nClient, mChairItemID);
+ //tmpMsg = MsgBuilder->BuildCharSittingMsg(nClient);
+ //ClientManager->UDPBroadcast(tmpMsg, nClient, 5000); // TODO: Get the range from config
+ tmpMsg = MsgBuilder->BuildCharPosUpdateMsg( nClient );
+ ClientManager->UDPBroadcast( tmpMsg, nClient, 5000 ); // TODO: Get the range from config
+ }
+ else
+ {
+ bool IsRealMove = false;
+
+ if (( mInfoBitfield & 0x01 ) && ( nChar->Coords.mY != mNewY ) )
+ {
+ nChar->Coords.mY = mNewY;
+ IsRealMove = true;
+ }
+ if (( mInfoBitfield & 0x02 ) && ( nChar->Coords.mZ != mNewZ ) )
+ {
+ nChar->Coords.mZ = mNewZ;
+ IsRealMove = true;
+ }
+ if (( mInfoBitfield & 0x04 ) && ( nChar->Coords.mX != mNewX ) )
+ {
+ nChar->Coords.mX = mNewX;
+ IsRealMove = true;
+ }
+ if ( mInfoBitfield & 0x08 )
+ {
+ nChar->Coords.mUD = mNewUD;
+ //IsRealMove = true;
+ }
+ if (( mInfoBitfield & 0x10 ) && ( nChar->Coords.mLR != mNewLR ) )
+ {
+ nChar->Coords.mLR = mNewLR;
+ IsRealMove = true;
+ }
+ if ( mInfoBitfield & 0x20 )
+ {
+ nChar->Coords.mAct = mNewAct;
+ }
+ if ( mInfoBitfield & 0x20 )
+ {
+ nChar->Coords.mUnknown = mNewUnknown;
+ }
+ // movement action byte mask:
+ // 0x00 NC has no focus (player alt+tab'ed out)
+ // 0x02 kneeing
+ // 0x20 Walk mode (= not run mode)
+ // 0x08 left step
+ // 0x10 right step
+ // 0x40 forward
+ // 0x80 backward
+ // bits: 00000000
+ // BFWRL.K.
+
+ if ( IsRealMove )
+ {
+ nChar->SetDirtyFlag();
+ }
+ /*if(IsRealMove)
+ if(mInfoBitfield == 0x7f)
+ {
+ tmpMsg = MsgBuilder->BuildCharPosUpdateMsg(nClient);
+ ClientManager->UDPBroadcast(tmpMsg, nClient, 5000); // TODO: Get the range from config
+ }*/
+
+ uint16_t nSaveZ = nChar->Coords.mZ;
+ if(nChar->Coords.mJumpingState)
+ {
+ mInfoBitfield |= 0x02; // Update Z and Act only
+ if(nChar->Coords.mJumpingState == 1)
+ {
+ if ( gDevDebug ) Console->Print( "%s Send moving jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ (nChar->Coords.mZ) += JUMPHEIGHT;
+ nChar->Coords.mJumpingState = 2; // Jump done
+ }
+ else
+ nChar->Coords.mJumpingState = 0; // No pending jump
+ }
+
+ tmpMsg = MsgBuilder->BuildCharPosUpdate2Msg( nClient, mInfoBitfield );
+
+ if(nChar->Coords.mJumpingState)
+ nChar->Coords.mZ = nSaveZ;
+
+ ClientManager->UDPBroadcast( tmpMsg, nClient, 5000, true );
+
+ if ( IsRealMove && nClient->GetDebugMode( DBG_LOCATION ) )
+ {
+ char DbgMessage[128];
+ float f[3];
+// uint32_t h[3];
+ f[0] = nChar->Coords.mY - 32000;
+ f[1] = nChar->Coords.mZ - 32000;
+ f[2] = nChar->Coords.mX - 32000;
+ snprintf( DbgMessage, 128, "position y:%0.1f z:%0.1f x:%0.1f lr:%d (Act=%x BF=%x)", f[0], f[1], f[2], nChar->Coords.mLR, nChar->Coords.mAct , mInfoBitfield );
+ Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );
+ }
+ /*{
+ uint16_t p[3];
+ p[0] = nChar->Coords.mY;
+ p[1] = nChar->Coords.mZ;
+ p[2] = nChar->Coords.mX;
+ for(int i = 0; i<3; i++)
+ {
+ if(p[i]< nChar->Coords.minPos[i])
+ nChar->Coords.minPos[i] = p[i];
+ if(p[i]> nChar->Coords.maxPos[i])
+ nChar->Coords.maxPos[i] = p[i];
+ }
+ }*/
+
+ if(gDevDebug && IsRealMove)
+ Console->Print("%s Char %d position : X(%d) Y(%d) Z(%d) U/D(%d) L/R(%d) Action(%02x)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetID(), nChar->Coords.mX, nChar->Coords.mY, nChar->Coords.mZ, nChar->Coords.mUD, nChar->Coords.mLR, nChar->Coords.mAct);
+ }
+ if ( mInfoBitfield >= 0x7f )
+ {
+ tmpMsg = MsgBuilder->BuildCharHealthUpdateMsg( nClient );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
+
+
+/**** PUdpCharExitChair ****/
+
+PUdpCharExitChair::PUdpCharExitChair( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x22";
+}
+
+PUdpMsgAnalyser* PUdpCharExitChair::Analyse()
+{
+ mDecodeData->mName << "=Char exiting chair";
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+ return this;
+}
+
+bool PUdpCharExitChair::DoAction()
+{
+ DoLeaveChair( mDecodeData->mClient->GetChar(), mDecodeData->mClient );
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
+
+bool PUdpCharExitChair::DoLeaveChair( PChar* nChar, PClient* nClient, PSpawnedVehicle* nVhc, bool nForce )
+{
+ if ( ! nClient )
+ nClient = ClientManager->getClientByChar( nChar->GetID() );
+ if ( ! nClient )
+ {
+ Console->Print("%s PUdpCharExitChair::DoLeaveChair called without PClient* and client not available when searching by char.", Console->ColorText( RED, BLACK, "[ERROR]" ) );
+ return false;
+ }
+
+ PMessage* tmpMsg;
+ uint32_t cSeatObjectId;
+ uint8_t cSeatId;
+ PSeatType cSeatType = nChar->GetSeatInUse( &cSeatObjectId, &cSeatId );
+ uint32_t tNowTime = GameServer->GetGameTime();
+ bool ReadyToExit = false;
+
+ // This is only for investigation on subway timing
+ if ( nClient->GetDebugMode( DBG_SUBWAY ) && ( cSeatType == seat_subway ) )
+ {
+ char DbgMessage[80];
+ uint8_t tCabId;
+ Subway->GetInfoIndex( cSeatObjectId, &tCabId );
+ uint8_t tStationId = Subway->GetStation( cSeatObjectId, tNowTime );
+ std::string* StationName = Subway->GetStationName( tStationId );
+ std::string OpenState = ( Subway->IsDoorOpen( cSeatObjectId, tNowTime ) ? "open" : "closed" );
+
+ snprintf( DbgMessage, 80, "Cab %d (%d) is in station %s (%d). Door is %s (time: %d)", tCabId, cSeatObjectId, StationName->c_str(), tStationId, OpenState.c_str(), tNowTime );
+ DbgMessage[79] = 0;
+ Chat->send( nClient, CHAT_DIRECT, "System", DbgMessage );
+ delete StationName;
+ }
+ // end investigation
+
+ if ( cSeatType )
+ {
+ PWorld* tWorld = Worlds->GetWorld( nChar->GetLocation() );
+
+ if ( cSeatType == seat_chair )
+ {
+ tWorld->CharLeaveChair( nClient->GetLocalID(), cSeatObjectId );
+ nChar->SetSeatInUse( seat_none );
+ ReadyToExit = true;
+ }
+ else if ( cSeatType == seat_subway )
+ {
+ if ( Subway->IsDoorOpen( cSeatObjectId, tNowTime ) || nForce )
+ {
+ Subway->GetStationExitPosition( &( nChar->Coords ), Subway->GetStation( cSeatObjectId, tNowTime ), GetRandomFloat() );
+ Subway->UnsetSeatUser( cSeatObjectId, cSeatId, nChar->GetID() );
+ nChar->SetSeatInUse( seat_none );
+ ReadyToExit = true;
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, cSeatObjectId ); // "Damn, locked"
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ else if ( cSeatType == seat_vhc )
+ {
+ PSpawnedVehicle* tVhc = tWorld->GetSpawnedVehicles()->GetVehicle( cSeatObjectId );
+ if ( tVhc && (!nVhc || (tVhc == nVhc) || nForce) )
+ {
+ PVhcCoordinates tCoords = tVhc->GetPosition();
+ tVhc->UnsetSeatUser( cSeatId, nChar->GetID() );
+ nChar->SetSeatInUse( seat_none );
+ nChar->Coords.SetPosition( tCoords.GetY(), tCoords.GetZ(), tCoords.GetX() ); // to complete with LR
+ ReadyToExit = true;
+ }
+ }
+ else
+ {
+ Console->Print( "%s PUdpCharExitChair::DoLeaveChair : Invalid seat type %d", Console->ColorText( RED, BLACK, "[ERROR]" ), cSeatType );
+ }
+
+ if ( ReadyToExit )
+ {
+ nChar->SetSeatInUse( seat_none );
+
+ tmpMsg = MsgBuilder->BuildCharExitSeatMsg( nClient );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+
+ if ( gDevDebug ) Console->Print( "%s Localchar %d get up from chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nClient->GetLocalID(), cSeatObjectId );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**** PUdpCharJump ****/
+
+PUdpCharJump::PUdpCharJump( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x02";
+}
+
+PUdpMsgAnalyser* PUdpCharJump::Analyse()
+{
+ mDecodeData->mName << "=Char jumping";
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+ return this;
+}
+
+bool PUdpCharJump::DoAction()
+{
+ PClient* nClient = mDecodeData->mClient;
+ PChar* nChar = nClient->GetChar();
+
+ if( nChar->Coords.mAct & 0xd8 ) // if moving, don't jump now and wait next update
+ {
+ nChar->Coords.mJumpingState = 1; // Jump pending. Do at next pos update
+ if ( gDevDebug ) Console->Print( "%s Prepare moving jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ }
+ else // If not moving, jump now
+ {
+ if ( gDevDebug ) Console->Print( "%s Send static jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ uint8_t mInfoBitfield = 0x22; // Update Z and Act only
+ uint16_t nSaveZ = nChar->Coords.mZ;
+ (nChar->Coords.mZ) += JUMPHEIGHT;
+ PMessage* tmpMsg = MsgBuilder->BuildCharPosUpdate2Msg( nClient, mInfoBitfield );
+ nChar->Coords.mZ = nSaveZ;
+ nChar->Coords.mJumpingState = 2; // Jump done
+ ClientManager->UDPBroadcast( tmpMsg, nClient, 5000, true );
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+
+ return true;
+}
+
+
+/**** PUdpCharTargeting ****/
+
+PUdpCharTargeting::PUdpCharTargeting( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x2d";
+}
+
+PUdpMsgAnalyser* PUdpCharTargeting::Analyse()
+{
+ mDecodeData->mName << "=Targeting char";
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+ return this;
+}
+
+bool PUdpCharTargeting::DoAction()
+{
+ PClient* nClient = mDecodeData->mClient;
+ PChar* tChar = nClient->GetChar();
+ uint16_t CharID = mDecodeData->mMessage->U16Data( mDecodeData->Sub0x13Start + 2 );
+ uint8_t strangeval1 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 4 );
+ uint8_t strangeval2 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 5 );
+ uint8_t strangeval3 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 6 );
+
+ tChar->SetLookingAt( CharID );
+
+ if ( gDevDebug )
+ Console->Print( "%s Char %d targeting char %d. // %d %d %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetID(), CharID, strangeval1, strangeval2, strangeval3 );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PChar;\r
-class PClient;\r
-class PSpawnedVehicle;\r
-\r
-class PUdpCharPosUpdate : public PUdpMsgAnalyser {\r
-private:\r
- uint8_t mInfoBitfield;\r
- uint16_t mNewY;\r
- uint16_t mNewZ;\r
- uint16_t mNewX;\r
- uint8_t mNewUD;\r
- uint8_t mNewLR;\r
- uint8_t mNewAct;\r
- uint8_t mNewUnknown;\r
- uint32_t mChairItemID; // uint16_t or uint32_t ???\r
- uint8_t mChairItemSeat;\r
-\r
-public:\r
- PUdpCharPosUpdate(PMsgDecodeData *nDecodeData);\r
- //~PUdpCharMoves();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpCharExitChair : public PUdpMsgAnalyser {\r
-public:\r
- PUdpCharExitChair(PMsgDecodeData *nDecodeData);\r
- //~PUdpCharExitChair();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-\r
- //nClient is optionnal, nVhc is to limit to that vhc, nForce to force exit event when cab door closed\r
- static bool DoLeaveChair(PChar *nChar, PClient *nClient = nullptr, PSpawnedVehicle *nVhc = nullptr,\r
- bool nForce = false);\r
-};\r
-\r
-class PUdpCharJump : public PUdpMsgAnalyser {\r
-public:\r
- PUdpCharJump(PMsgDecodeData *nDecodeData);\r
- //~PUdpCharJump();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpCharTargeting : public PUdpMsgAnalyser {\r
-public:\r
- PUdpCharTargeting(PMsgDecodeData *nDecodeData);\r
- //~PUdpCharTargeting();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PChar;
+class PClient;
+class PSpawnedVehicle;
+
+class PUdpCharPosUpdate : public PUdpMsgAnalyser {
+private:
+ uint8_t mInfoBitfield;
+ uint16_t mNewY;
+ uint16_t mNewZ;
+ uint16_t mNewX;
+ uint8_t mNewUD;
+ uint8_t mNewLR;
+ uint8_t mNewAct;
+ uint8_t mNewUnknown;
+ uint32_t mChairItemID; // uint16_t or uint32_t ???
+ uint8_t mChairItemSeat;
+
+public:
+ PUdpCharPosUpdate(PMsgDecodeData *nDecodeData);
+ //~PUdpCharMoves();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpCharExitChair : public PUdpMsgAnalyser {
+public:
+ PUdpCharExitChair(PMsgDecodeData *nDecodeData);
+ //~PUdpCharExitChair();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+
+ //nClient is optionnal, nVhc is to limit to that vhc, nForce to force exit event when cab door closed
+ static bool DoLeaveChair(PChar *nChar, PClient *nClient = nullptr, PSpawnedVehicle *nVhc = nullptr,
+ bool nForce = false);
+};
+
+class PUdpCharJump : public PUdpMsgAnalyser {
+public:
+ PUdpCharJump(PMsgDecodeData *nDecodeData);
+ //~PUdpCharJump();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpCharTargeting : public PUdpMsgAnalyser {
+public:
+ PUdpCharTargeting(PMsgDecodeData *nDecodeData);
+ //~PUdpCharTargeting();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#pragma once\r
-\r
-#include <cstdint>\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpChatLocal : public PUdpMsgAnalyser {\r
-public:\r
- PUdpChatLocal(PMsgDecodeData *nDecodeData);\r
- //~PUdpChatLocal();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpChatGlobal : public PUdpMsgAnalyser {\r
-public:\r
- PUdpChatGlobal(PMsgDecodeData *nDecodeData);\r
- //~PUdpChatGlobal();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpChatListAdd : public PUdpMsgAnalyser {\r
-private:\r
- uint8_t mChatList; // 1 = Direct, 2 = Buddy List\r
- char *mAddedCharname;\r
-\r
-public:\r
- PUdpChatListAdd(PMsgDecodeData *nDecodeData);\r
- //~PUdpChatListAdd();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpChatListRemove : public PUdpMsgAnalyser {\r
-private:\r
- uint8_t mChatList;\r
- uint32_t mRemovedCharID;\r
-\r
-public:\r
- PUdpChatListRemove(PMsgDecodeData *nDecodeData);\r
- //~PUdpChatListRemove();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpChatChannels : public PUdpMsgAnalyser {\r
-private:\r
- uint32_t mChannelFlags; // 1 bit per custom channel, starting from LSB, in same order as in chat i/f\r
-\r
-public:\r
- PUdpChatChannels(PMsgDecodeData *nDecodeData);\r
- //~PUdpChatChannels();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpChatLocal : public PUdpMsgAnalyser {
+public:
+ PUdpChatLocal(PMsgDecodeData *nDecodeData);
+ //~PUdpChatLocal();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpChatGlobal : public PUdpMsgAnalyser {
+public:
+ PUdpChatGlobal(PMsgDecodeData *nDecodeData);
+ //~PUdpChatGlobal();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpChatListAdd : public PUdpMsgAnalyser {
+private:
+ uint8_t mChatList; // 1 = Direct, 2 = Buddy List
+ char *mAddedCharname;
+
+public:
+ PUdpChatListAdd(PMsgDecodeData *nDecodeData);
+ //~PUdpChatListAdd();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpChatListRemove : public PUdpMsgAnalyser {
+private:
+ uint8_t mChatList;
+ uint32_t mRemovedCharID;
+
+public:
+ PUdpChatListRemove(PMsgDecodeData *nDecodeData);
+ //~PUdpChatListRemove();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpChatChannels : public PUdpMsgAnalyser {
+private:
+ uint32_t mChannelFlags; // 1 bit per custom channel, starting from LSB, in same order as in chat i/f
+
+public:
+ PUdpChatChannels(PMsgDecodeData *nDecodeData);
+ //~PUdpChatChannels();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-PUdpEntityPosRequest::PUdpEntityPosRequest(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
-{\r
- nDecodeData->mName << "/0x0b";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpEntityPosRequest::Analyse()\r
-{\r
- mDecodeData->mName << "=Entity position request";\r
-\r
-//mDecodeData->mTraceUnknownMsg = true; // temp stop being bugged with unknown move msg\r
-//mDecodeData->mTraceKnownMsg = true;\r
-\r
- PMessage* nMsg = mDecodeData->mMessage;\r
- nMsg->SetNextByteOffset(mDecodeData->Sub0x13Start + 7);\r
-\r
- *nMsg >> mEntityID; //(uint16_t ... or uint32_t ???)\r
-\r
- if(mEntityID >= WORLDDATATEMPLATE_MAXPOSITEMS)\r
- {\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- mDecodeData->mErrorDetail = Ssprintf("Invalid position entity ID (%d)", mEntityID);\r
- Console->Print("%s Client[%d] sent invalid position entity Id[%d]", Console->ColorText(YELLOW, BLACK, "[Notice]"), mDecodeData->mClient->GetID(), mEntityID);\r
- mDecodeData->mTraceDump = true;\r
- }\r
- else\r
- {\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- }\r
-\r
- return this;\r
-}\r
-\r
-bool PUdpEntityPosRequest::DoAction()\r
-{\r
- PClient* nClient = mDecodeData->mClient;\r
- PChar* nChar = nClient->GetChar();\r
- PWorld* currentWorld = Worlds->GetWorld(nChar->GetLocation());\r
- float fpX, fpY, fpZ;\r
- uint16_t pX, pY, pZ;\r
-\r
- if(currentWorld)\r
- {\r
- if((mEntityID < WORLDDATATEMPLATE_MAXPOSITEMS) && currentWorld->getPositionItemPosition(mEntityID, &fpX, &fpY, &fpZ))\r
- {\r
- pX = (uint16_t) (fpX + 32000);\r
- pY = (uint16_t) (fpY + 32000);\r
- pZ = (uint16_t) (fpZ + 32000);\r
-\r
-if(gDevDebug) Console->Print(GREEN, BLACK, "Client %d - Sending pos for entity %d : X=%d Y=%d Z=%d", mDecodeData->mClient->GetID(), mEntityID, pX, pY, pZ);\r
- }\r
- else if(!nClient->GetCharAwaitingWarpto(&pX, &pY, &pZ))\r
- {\r
- pX = pY = pZ = 0;\r
- Console->Print("%s Client[%d] requested invalid position entity %d. Position reset.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mDecodeData->mClient->GetID(), mEntityID);\r
- }\r
-\r
- PMessage* tmpMsg;\r
- tmpMsg = MsgBuilder->BuildEntityPositionMsg(nClient, pX, pY, pZ);\r
- nClient->SendUDPMessage(tmpMsg);\r
- (nChar->Coords).mY=pY;\r
- (nChar->Coords).mZ=pZ;\r
- (nChar->Coords).mX=pX;\r
- }\r
- else\r
- {\r
- Console->Print(RED, BLACK, "[Warning] PUdpEntityPosRequest - Invalid world (%d)", nChar->GetLocation());\r
- }\r
-// if(IsRealMove && nClient->GetDebugMode(DBG_LOCATION))\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
+#include "GameServer/Decoder/Includes.hxx"
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+PUdpEntityPosRequest::PUdpEntityPosRequest(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+ nDecodeData->mName << "/0x0b";
+}
+
+PUdpMsgAnalyser* PUdpEntityPosRequest::Analyse()
+{
+ mDecodeData->mName << "=Entity position request";
+
+//mDecodeData->mTraceUnknownMsg = true; // temp stop being bugged with unknown move msg
+//mDecodeData->mTraceKnownMsg = true;
+
+ PMessage* nMsg = mDecodeData->mMessage;
+ nMsg->SetNextByteOffset(mDecodeData->Sub0x13Start + 7);
+
+ *nMsg >> mEntityID; //(uint16_t ... or uint32_t ???)
+
+ if(mEntityID >= WORLDDATATEMPLATE_MAXPOSITEMS)
+ {
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ mDecodeData->mErrorDetail = Ssprintf("Invalid position entity ID (%d)", mEntityID);
+ Console->Print("%s Client[%d] sent invalid position entity Id[%d]", Console->ColorText(YELLOW, BLACK, "[Notice]"), mDecodeData->mClient->GetID(), mEntityID);
+ mDecodeData->mTraceDump = true;
+ }
+ else
+ {
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ }
+
+ return this;
+}
+
+bool PUdpEntityPosRequest::DoAction()
+{
+ PClient* nClient = mDecodeData->mClient;
+ PChar* nChar = nClient->GetChar();
+ PWorld* currentWorld = Worlds->GetWorld(nChar->GetLocation());
+ float fpX, fpY, fpZ;
+ uint16_t pX, pY, pZ;
+
+ if(currentWorld)
+ {
+ if((mEntityID < WORLDDATATEMPLATE_MAXPOSITEMS) && currentWorld->getPositionItemPosition(mEntityID, &fpX, &fpY, &fpZ))
+ {
+ pX = (uint16_t) (fpX + 32000);
+ pY = (uint16_t) (fpY + 32000);
+ pZ = (uint16_t) (fpZ + 32000);
+
+if(gDevDebug) Console->Print(GREEN, BLACK, "Client %d - Sending pos for entity %d : X=%d Y=%d Z=%d", mDecodeData->mClient->GetID(), mEntityID, pX, pY, pZ);
+ }
+ else if(!nClient->GetCharAwaitingWarpto(&pX, &pY, &pZ))
+ {
+ pX = pY = pZ = 0;
+ Console->Print("%s Client[%d] requested invalid position entity %d. Position reset.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mDecodeData->mClient->GetID(), mEntityID);
+ }
+
+ PMessage* tmpMsg;
+ tmpMsg = MsgBuilder->BuildEntityPositionMsg(nClient, pX, pY, pZ);
+ nClient->SendUDPMessage(tmpMsg);
+ (nChar->Coords).mY=pY;
+ (nChar->Coords).mZ=pZ;
+ (nChar->Coords).mX=pX;
+ }
+ else
+ {
+ Console->Print(RED, BLACK, "[Warning] PUdpEntityPosRequest - Invalid world (%d)", nChar->GetLocation());
+ }
+// if(IsRealMove && nClient->GetDebugMode(DBG_LOCATION))
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpEntityPosRequest : public PUdpMsgAnalyser {\r
-private:\r
- uint16_t mEntityID; // u16 or u32 ???\r
-\r
-public:\r
- PUdpEntityPosRequest(PMsgDecodeData *nDecodeData);\r
- //~PUdpEntityPosRequest();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpEntityPosRequest : public PUdpMsgAnalyser {
+private:
+ uint16_t mEntityID; // u16 or u32 ???
+
+public:
+ PUdpEntityPosRequest(PMsgDecodeData *nDecodeData);
+ //~PUdpEntityPosRequest();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#pragma once\r
-\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpHackFail : public PUdpMsgAnalyser {\r
-public:\r
- PUdpHackFail(PMsgDecodeData *nDecodeData);\r
- //~PUdpHackFail();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpHackSuccess : public PUdpMsgAnalyser {\r
-public:\r
- PUdpHackSuccess(PMsgDecodeData *nDecodeData);\r
- //~PUdpHackSuccess();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpHackFail : public PUdpMsgAnalyser {
+public:
+ PUdpHackFail(PMsgDecodeData *nDecodeData);
+ //~PUdpHackFail();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpHackSuccess : public PUdpMsgAnalyser {
+public:
+ PUdpHackSuccess(PMsgDecodeData *nDecodeData);
+ //~PUdpHackSuccess();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-/**** PUdpItemMove ****/\r
-\r
-#define PUdpItemMove_NO_BOX_TAKE_ALL\r
-\r
-PUdpItemMove::PUdpItemMove( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x1e";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpItemMove::Analyse()\r
-{\r
- mDecodeData->mName << "=Moving item";\r
-\r
- PMessage* nMsg = mDecodeData->mMessage;\r
- nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 8 );\r
-\r
- *nMsg >> mSrcLoc;\r
- *nMsg >> mSrcX;\r
- *nMsg >> mSrcY;\r
- *nMsg >> mDstLoc;\r
- *nMsg >> mDstX;\r
- *nMsg >> mDstY;\r
- *nMsg >> mItemCnt;\r
-\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpItemMove::DoAction()\r
-{\r
-//mDecodeData->mTraceDump = true;\r
- PMessage* tmpMsg;\r
- bool MoveSucceded = false;\r
- PClient* nClient = mDecodeData->mClient;\r
- PChar* tChar = nClient->GetChar();\r
- uint8_t origDstX = mDstX;\r
- uint8_t origDstY = mDstY;\r
- PContainerEntry* tEntry;\r
-\r
- PItem* tItem = NULL;\r
-\r
- PContainer* SrcContainer = GetContainerByLoc( tChar, mSrcLoc );\r
- if ( SrcContainer )\r
- {\r
- tEntry = SrcContainer->GetEntry( mSrcX );\r
- tItem = SrcContainer->GetItem( mSrcX );\r
- if ( mSrcLoc != mDstLoc )\r
- {\r
- PContainer* DstContainer = GetContainerByLoc( tChar, mDstLoc );\r
- if ( mSrcY )\r
- Console->Print( "%s PUdpItemMove: intramove: src Y != 0", Console->ColorText( YELLOW, BLACK, "[WARNING]" ) );\r
-#ifdef PUdpItemMove_NO_BOX_TAKE_ALL\r
- if (( mSrcLoc != INV_LOC_BOX ) || ( mDstX != 255 ) || ( mDstY != 255 ) )\r
- {\r
-#endif\r
- if ( DstContainer )\r
- {\r
- //PContainerEntry* tEntry = SrcContainer->GetEntry(mSrcX);\r
- MoveSucceded = SrcContainer->MoveItem( mSrcX, mItemCnt, DstContainer, mDstX, mDstX, mDstY );\r
- /*if(tEntry)\r
- tEntry->Get2DPos(&mDstX, &mDstY);*/\r
- }\r
-#ifdef PUdpItemMove_NO_BOX_TAKE_ALL\r
- }\r
-#endif\r
- }\r
- else\r
- {\r
- if ( mSrcY || mDstY )\r
- Console->Print( "%s PUdpItemMove: intramove: src Y or dst Y != 0", Console->ColorText( YELLOW, BLACK, "[WARNING]" ) );\r
- MoveSucceded = SrcContainer->MoveItem( mSrcX, mItemCnt, mDstX );\r
- }\r
- }\r
-\r
- if ( MoveSucceded )\r
- {\r
- if (( mDstX == 255 ) && ( mDstY == 255 ) && ( mSrcLoc == INV_LOC_BOX ) )\r
- {\r
- tmpMsg = MsgBuilder->BuildUndefineduseMsg( nClient, 0x2c );\r
- nClient->SendUDPMessage( tmpMsg );\r
- tmpMsg = MsgBuilder->BuildBoxItemMoveMsg( nClient, tEntry, mSrcX, mSrcY, mDstLoc, mDstX, mDstY, mItemCnt );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildItemMoveMsg( nClient, mSrcLoc, mSrcX, mSrcY, mDstLoc, mDstX, mDstY, mItemCnt );\r
- }\r
- nClient->SendUDPMessage( tmpMsg );\r
-\r
- if ( gDevDebug )\r
- Console->Print( "%s Success : Item move %u:%u-%u => %u:%u-%u : %u %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, origDstX, origDstY, mItemCnt, tItem ? tItem->GetName().c_str() : "" );\r
- /*Console->Print(YELLOW, BLACK, "--- Worn Inventory ---");\r
- tChar->GetInventory()->GetContainer(INV_LOC_WORN)->Dump();\r
- Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---");\r
- tChar->GetInventory()->GetContainer(INV_LOC_BACKPACK)->Dump();\r
- Console->Print(YELLOW, BLACK, "--- Gogo Inventory ---");\r
- tChar->GetInventory()->GetContainer(INV_LOC_GOGO)->Dump();\r
- if (tChar->GetInventory()->IsDirty())\r
- Console->Print(YELLOW, BLACK, "Inventory DIRTY"); */\r
-\r
-// => TO CHECK: deactivate item in-hand if active slot now emtpy ???\r
- }\r
- else\r
- {\r
-#ifdef PUdpItemMove_NO_BOX_TAKE_ALL\r
- if (( mSrcLoc != INV_LOC_BOX ) || ( mDstX != 255 ) || ( mDstY != 255 ) )\r
- {\r
-#endif\r
- if ( mDstLoc == INV_LOC_GROUND )\r
- Chat->send( nClient, CHAT_DIRECT, "System", "Can't throw items to the ground yet." );\r
- else\r
- Console->Print( "%s Item move failed %u:%u-%u => %u:%u-%u : %u %s", Console->ColorText( YELLOW, BLACK, "[WARNING]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, origDstX, origDstY, mItemCnt, tItem ? tItem->GetName().c_str() : "" );\r
- // Send 'null move'\r
- //tmpMsg = MsgBuilder->BuildItemMoveMsg(nClient, mSrcLoc, mSrcX, mSrcY, mSrcLoc, mSrcX, mSrcY, mItemCnt);\r
- //nClient->SendUDPMessage(tmpMsg);\r
-#ifdef PUdpItemMove_NO_BOX_TAKE_ALL\r
- }\r
- else\r
- {\r
- Chat->send( nClient, CHAT_DIRECT, "System", "'TAKE ALL' can't be used yet." );\r
- }\r
-#endif\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
-\r
-PContainer* PUdpItemMove::GetContainerByLoc( PChar* nChar, uint8_t nLoc )\r
-{\r
- PContainer* tContainer = NULL;\r
-\r
- switch ( nLoc )\r
- {\r
- case INV_LOC_WORN:\r
- case INV_LOC_BACKPACK:\r
- case INV_LOC_GOGO:\r
- {\r
- tContainer = nChar->GetInventory()->GetContainer( nLoc );\r
- break;\r
- }\r
-\r
- case INV_LOC_BOX:\r
- {\r
- tContainer = nChar->GetContainerInExclusiveUse();\r
- break;\r
- }\r
- case INV_LOC_GROUND:\r
- case INV_LOC_NPCTRADE:\r
- default:\r
- break;\r
- }\r
-\r
- return tContainer;\r
-}\r
-\r
-\r
-/**** PUdpItemMoveBP ****/\r
-\r
-PUdpItemMoveBP::PUdpItemMoveBP( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x14";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpItemMoveBP::Analyse()\r
-{\r
- mDecodeData->mName << "=Moving item";\r
-\r
- PMessage* nMsg = mDecodeData->mMessage;\r
- nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 9 );\r
-\r
- *nMsg >> mSrcSlotId;\r
- *nMsg >> mDumb;\r
- *nMsg >> mDstX;\r
- *nMsg >> mDstY;\r
-\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpItemMoveBP::DoAction()\r
-{\r
-//mDecodeData->mTraceDump = true;\r
-// PMessage* tmpMsg;\r
- bool MoveSucceded = false;\r
- PClient* nClient = mDecodeData->mClient;\r
- PChar* tChar = nClient->GetChar();\r
-\r
- PContainer2DWorkaround* SrcContainer = tChar->GetInventory()->GetBackpackContainer();\r
- if ( SrcContainer )\r
- {\r
- if ( mDumb )\r
- Console->Print( "%s PUdpItemMoveBP: Dumb != 0 (%d)", Console->ColorText( YELLOW, BLACK, "[WARNING]" ), mDumb );\r
- if ( gDevDebug )\r
- Console->Print( "%s PUdpItemMoveBP: Tyring Item move: slot %u => %u-%u", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcSlotId, mDstX, mDstY );\r
- PContainerEntry* tEntry = SrcContainer->GetEntry( mSrcSlotId );\r
- if ( tEntry )\r
- {\r
- SrcContainer->SetUsed( tEntry, false );\r
- SrcContainer->SetEntryPosXY( tEntry, mSrcSlotId, mDstX, mDstY );\r
- SrcContainer->SetUsed( tEntry );\r
- SrcContainer->SetDirty();\r
- MoveSucceded = true;\r
- }\r
- else\r
- Console->Print( "%s PUdpItemMoveBP: trying to use invalid slot %d", Console->ColorText( RED, BLACK, "[WARNING]" ), mSrcSlotId );\r
- }\r
- else\r
- {\r
- Console->Print( "%s trying to use invalid Backpack container", Console->ColorText( RED, BLACK, "[WARNING]" ) );\r
- }\r
-//Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---");\r
-//SrcContainer->Dump();\r
-\r
-// No answer to confirm ?\r
-//tmpMsg = NULL;\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
-\r
-/**** PUdpItemDropOnItem ****/\r
-\r
-PUdpItemDropOnItem::PUdpItemDropOnItem( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x17";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpItemDropOnItem::Analyse()\r
-{\r
- mDecodeData->mName << "=Dropping item on item";\r
-\r
- PMessage* nMsg = mDecodeData->mMessage;\r
- nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 9 );\r
-\r
- *nMsg >> mSrcLoc;\r
- *nMsg >> mSrcX; // Linear Idx\r
- *nMsg >> mSrcY; // 0\r
- *nMsg >> mDstLoc;\r
- *nMsg >> mDstX; // Linear Idx\r
- *nMsg >> mDstY; // 0\r
-\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpItemDropOnItem::DoAction()\r
-{\r
- PClient* nClient = mDecodeData->mClient;\r
- PChar* tChar = nClient->GetChar();\r
- if ( gDevDebug )\r
- Console->Print( "%s PUdpItemDropOnItem: %u:%u-%u => %u:%u-%u", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, mDstX, mDstY );\r
- PContainer* SrcContainer = PUdpItemMove::GetContainerByLoc( tChar, mSrcLoc );\r
- PContainer* DstContainer = PUdpItemMove::GetContainerByLoc( tChar, mDstLoc );\r
- if ( SrcContainer && DstContainer )\r
- {\r
- PItem* sItem = SrcContainer->GetItem( mSrcX );\r
- PItem* dItem = DstContainer->GetItem( mDstX );\r
-\r
- if ( gDevDebug )\r
- Console->Print( "%s Drop item %s on %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), sItem ? sItem->GetName().c_str() : "???", dItem ? dItem->GetName().c_str() : "???" );\r
- }\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
+#include "GameServer/Decoder/Includes.hxx"
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+/**** PUdpItemMove ****/
+
+#define PUdpItemMove_NO_BOX_TAKE_ALL
+
+PUdpItemMove::PUdpItemMove( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x1e";
+}
+
+PUdpMsgAnalyser* PUdpItemMove::Analyse()
+{
+ mDecodeData->mName << "=Moving item";
+
+ PMessage* nMsg = mDecodeData->mMessage;
+ nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 8 );
+
+ *nMsg >> mSrcLoc;
+ *nMsg >> mSrcX;
+ *nMsg >> mSrcY;
+ *nMsg >> mDstLoc;
+ *nMsg >> mDstX;
+ *nMsg >> mDstY;
+ *nMsg >> mItemCnt;
+
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpItemMove::DoAction()
+{
+//mDecodeData->mTraceDump = true;
+ PMessage* tmpMsg;
+ bool MoveSucceded = false;
+ PClient* nClient = mDecodeData->mClient;
+ PChar* tChar = nClient->GetChar();
+ uint8_t origDstX = mDstX;
+ uint8_t origDstY = mDstY;
+ PContainerEntry* tEntry;
+
+ PItem* tItem = NULL;
+
+ PContainer* SrcContainer = GetContainerByLoc( tChar, mSrcLoc );
+ if ( SrcContainer )
+ {
+ tEntry = SrcContainer->GetEntry( mSrcX );
+ tItem = SrcContainer->GetItem( mSrcX );
+ if ( mSrcLoc != mDstLoc )
+ {
+ PContainer* DstContainer = GetContainerByLoc( tChar, mDstLoc );
+ if ( mSrcY )
+ Console->Print( "%s PUdpItemMove: intramove: src Y != 0", Console->ColorText( YELLOW, BLACK, "[WARNING]" ) );
+#ifdef PUdpItemMove_NO_BOX_TAKE_ALL
+ if (( mSrcLoc != INV_LOC_BOX ) || ( mDstX != 255 ) || ( mDstY != 255 ) )
+ {
+#endif
+ if ( DstContainer )
+ {
+ //PContainerEntry* tEntry = SrcContainer->GetEntry(mSrcX);
+ MoveSucceded = SrcContainer->MoveItem( mSrcX, mItemCnt, DstContainer, mDstX, mDstX, mDstY );
+ /*if(tEntry)
+ tEntry->Get2DPos(&mDstX, &mDstY);*/
+ }
+#ifdef PUdpItemMove_NO_BOX_TAKE_ALL
+ }
+#endif
+ }
+ else
+ {
+ if ( mSrcY || mDstY )
+ Console->Print( "%s PUdpItemMove: intramove: src Y or dst Y != 0", Console->ColorText( YELLOW, BLACK, "[WARNING]" ) );
+ MoveSucceded = SrcContainer->MoveItem( mSrcX, mItemCnt, mDstX );
+ }
+ }
+
+ if ( MoveSucceded )
+ {
+ if (( mDstX == 255 ) && ( mDstY == 255 ) && ( mSrcLoc == INV_LOC_BOX ) )
+ {
+ tmpMsg = MsgBuilder->BuildUndefineduseMsg( nClient, 0x2c );
+ nClient->SendUDPMessage( tmpMsg );
+ tmpMsg = MsgBuilder->BuildBoxItemMoveMsg( nClient, tEntry, mSrcX, mSrcY, mDstLoc, mDstX, mDstY, mItemCnt );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildItemMoveMsg( nClient, mSrcLoc, mSrcX, mSrcY, mDstLoc, mDstX, mDstY, mItemCnt );
+ }
+ nClient->SendUDPMessage( tmpMsg );
+
+ if ( gDevDebug )
+ Console->Print( "%s Success : Item move %u:%u-%u => %u:%u-%u : %u %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, origDstX, origDstY, mItemCnt, tItem ? tItem->GetName().c_str() : "" );
+ /*Console->Print(YELLOW, BLACK, "--- Worn Inventory ---");
+ tChar->GetInventory()->GetContainer(INV_LOC_WORN)->Dump();
+ Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---");
+ tChar->GetInventory()->GetContainer(INV_LOC_BACKPACK)->Dump();
+ Console->Print(YELLOW, BLACK, "--- Gogo Inventory ---");
+ tChar->GetInventory()->GetContainer(INV_LOC_GOGO)->Dump();
+ if (tChar->GetInventory()->IsDirty())
+ Console->Print(YELLOW, BLACK, "Inventory DIRTY"); */
+
+// => TO CHECK: deactivate item in-hand if active slot now emtpy ???
+ }
+ else
+ {
+#ifdef PUdpItemMove_NO_BOX_TAKE_ALL
+ if (( mSrcLoc != INV_LOC_BOX ) || ( mDstX != 255 ) || ( mDstY != 255 ) )
+ {
+#endif
+ if ( mDstLoc == INV_LOC_GROUND )
+ Chat->send( nClient, CHAT_DIRECT, "System", "Can't throw items to the ground yet." );
+ else
+ Console->Print( "%s Item move failed %u:%u-%u => %u:%u-%u : %u %s", Console->ColorText( YELLOW, BLACK, "[WARNING]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, origDstX, origDstY, mItemCnt, tItem ? tItem->GetName().c_str() : "" );
+ // Send 'null move'
+ //tmpMsg = MsgBuilder->BuildItemMoveMsg(nClient, mSrcLoc, mSrcX, mSrcY, mSrcLoc, mSrcX, mSrcY, mItemCnt);
+ //nClient->SendUDPMessage(tmpMsg);
+#ifdef PUdpItemMove_NO_BOX_TAKE_ALL
+ }
+ else
+ {
+ Chat->send( nClient, CHAT_DIRECT, "System", "'TAKE ALL' can't be used yet." );
+ }
+#endif
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
+
+PContainer* PUdpItemMove::GetContainerByLoc( PChar* nChar, uint8_t nLoc )
+{
+ PContainer* tContainer = NULL;
+
+ switch ( nLoc )
+ {
+ case INV_LOC_WORN:
+ case INV_LOC_BACKPACK:
+ case INV_LOC_GOGO:
+ {
+ tContainer = nChar->GetInventory()->GetContainer( nLoc );
+ break;
+ }
+
+ case INV_LOC_BOX:
+ {
+ tContainer = nChar->GetContainerInExclusiveUse();
+ break;
+ }
+ case INV_LOC_GROUND:
+ case INV_LOC_NPCTRADE:
+ default:
+ break;
+ }
+
+ return tContainer;
+}
+
+
+/**** PUdpItemMoveBP ****/
+
+PUdpItemMoveBP::PUdpItemMoveBP( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x14";
+}
+
+PUdpMsgAnalyser* PUdpItemMoveBP::Analyse()
+{
+ mDecodeData->mName << "=Moving item";
+
+ PMessage* nMsg = mDecodeData->mMessage;
+ nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 9 );
+
+ *nMsg >> mSrcSlotId;
+ *nMsg >> mDumb;
+ *nMsg >> mDstX;
+ *nMsg >> mDstY;
+
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpItemMoveBP::DoAction()
+{
+//mDecodeData->mTraceDump = true;
+// PMessage* tmpMsg;
+ bool MoveSucceded = false;
+ PClient* nClient = mDecodeData->mClient;
+ PChar* tChar = nClient->GetChar();
+
+ PContainer2DWorkaround* SrcContainer = tChar->GetInventory()->GetBackpackContainer();
+ if ( SrcContainer )
+ {
+ if ( mDumb )
+ Console->Print( "%s PUdpItemMoveBP: Dumb != 0 (%d)", Console->ColorText( YELLOW, BLACK, "[WARNING]" ), mDumb );
+ if ( gDevDebug )
+ Console->Print( "%s PUdpItemMoveBP: Tyring Item move: slot %u => %u-%u", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcSlotId, mDstX, mDstY );
+ PContainerEntry* tEntry = SrcContainer->GetEntry( mSrcSlotId );
+ if ( tEntry )
+ {
+ SrcContainer->SetUsed( tEntry, false );
+ SrcContainer->SetEntryPosXY( tEntry, mSrcSlotId, mDstX, mDstY );
+ SrcContainer->SetUsed( tEntry );
+ SrcContainer->SetDirty();
+ MoveSucceded = true;
+ }
+ else
+ Console->Print( "%s PUdpItemMoveBP: trying to use invalid slot %d", Console->ColorText( RED, BLACK, "[WARNING]" ), mSrcSlotId );
+ }
+ else
+ {
+ Console->Print( "%s trying to use invalid Backpack container", Console->ColorText( RED, BLACK, "[WARNING]" ) );
+ }
+//Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---");
+//SrcContainer->Dump();
+
+// No answer to confirm ?
+//tmpMsg = NULL;
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
+
+/**** PUdpItemDropOnItem ****/
+
+PUdpItemDropOnItem::PUdpItemDropOnItem( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x17";
+}
+
+PUdpMsgAnalyser* PUdpItemDropOnItem::Analyse()
+{
+ mDecodeData->mName << "=Dropping item on item";
+
+ PMessage* nMsg = mDecodeData->mMessage;
+ nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 9 );
+
+ *nMsg >> mSrcLoc;
+ *nMsg >> mSrcX; // Linear Idx
+ *nMsg >> mSrcY; // 0
+ *nMsg >> mDstLoc;
+ *nMsg >> mDstX; // Linear Idx
+ *nMsg >> mDstY; // 0
+
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpItemDropOnItem::DoAction()
+{
+ PClient* nClient = mDecodeData->mClient;
+ PChar* tChar = nClient->GetChar();
+ if ( gDevDebug )
+ Console->Print( "%s PUdpItemDropOnItem: %u:%u-%u => %u:%u-%u", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, mDstX, mDstY );
+ PContainer* SrcContainer = PUdpItemMove::GetContainerByLoc( tChar, mSrcLoc );
+ PContainer* DstContainer = PUdpItemMove::GetContainerByLoc( tChar, mDstLoc );
+ if ( SrcContainer && DstContainer )
+ {
+ PItem* sItem = SrcContainer->GetItem( mSrcX );
+ PItem* dItem = DstContainer->GetItem( mDstX );
+
+ if ( gDevDebug )
+ Console->Print( "%s Drop item %s on %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), sItem ? sItem->GetName().c_str() : "???", dItem ? dItem->GetName().c_str() : "???" );
+ }
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PContainer;\r
-\r
-class PUdpItemMove : public PUdpMsgAnalyser {\r
-private:\r
- uint8_t mSrcLoc;\r
- uint8_t mSrcX;\r
- uint8_t mSrcY;\r
- uint8_t mDstLoc;\r
- uint8_t mDstX;\r
- uint8_t mDstY;\r
- uint8_t mItemCnt;\r
-\r
-public:\r
- PUdpItemMove(PMsgDecodeData *nDecodeData);\r
- //~PUdpItemMove();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-\r
- static PContainer *GetContainerByLoc(PChar *nChar, uint8_t nLoc);\r
-};\r
-\r
-class PUdpItemMoveBP : public PUdpMsgAnalyser {\r
-private:\r
- uint8_t mSrcSlotId;\r
- uint8_t mDumb;\r
- uint8_t mDstX;\r
- uint8_t mDstY;\r
-\r
-public:\r
- PUdpItemMoveBP(PMsgDecodeData *nDecodeData);\r
- //~PUdpItemMove();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpItemDropOnItem : public PUdpMsgAnalyser {\r
-private:\r
- uint8_t mSrcLoc;\r
- uint8_t mSrcX;\r
- uint8_t mSrcY;\r
- uint8_t mDstLoc;\r
- uint8_t mDstX;\r
- uint8_t mDstY;\r
-\r
-public:\r
- PUdpItemDropOnItem(PMsgDecodeData *nDecodeData);\r
- //~PUdpItemDropOnItem();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PContainer;
+
+class PUdpItemMove : public PUdpMsgAnalyser {
+private:
+ uint8_t mSrcLoc;
+ uint8_t mSrcX;
+ uint8_t mSrcY;
+ uint8_t mDstLoc;
+ uint8_t mDstX;
+ uint8_t mDstY;
+ uint8_t mItemCnt;
+
+public:
+ PUdpItemMove(PMsgDecodeData *nDecodeData);
+ //~PUdpItemMove();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+
+ static PContainer *GetContainerByLoc(PChar *nChar, uint8_t nLoc);
+};
+
+class PUdpItemMoveBP : public PUdpMsgAnalyser {
+private:
+ uint8_t mSrcSlotId;
+ uint8_t mDumb;
+ uint8_t mDstX;
+ uint8_t mDstY;
+
+public:
+ PUdpItemMoveBP(PMsgDecodeData *nDecodeData);
+ //~PUdpItemMove();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpItemDropOnItem : public PUdpMsgAnalyser {
+private:
+ uint8_t mSrcLoc;
+ uint8_t mSrcX;
+ uint8_t mSrcY;
+ uint8_t mDstLoc;
+ uint8_t mDstX;
+ uint8_t mDstY;
+
+public:
+ PUdpItemDropOnItem(PMsgDecodeData *nDecodeData);
+ //~PUdpItemDropOnItem();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-/**** PUdpOOO ****/\r
-\r
-PUdpOOO::PUdpOOO(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)\r
-{\r
- nDecodeData->mName << "/0x01";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpOOO::Analyse()\r
-{\r
- mDecodeData->mName << "=Out Of Order";\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
-\r
- return this;\r
-}\r
-\r
-bool PUdpOOO::DoAction()\r
-{\r
- uint16_t MissingUDP_ID = mDecodeData->mMessage->U16Data(mDecodeData->Sub0x13Start+5);\r
-\r
- mDecodeData->mClient->getUDPConn()->ReSendUDPMessage(MissingUDP_ID);\r
- //Console->Print("%s Out of Order packet received ! (Client is missing UDPID %d) ***not managed yet***", Console->ColorText(YELLOW, BLACK, "[Notice]"), MissingUDP_ID);\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
+#include "GameServer/Decoder/Includes.hxx"
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+/**** PUdpOOO ****/
+
+PUdpOOO::PUdpOOO(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData)
+{
+ nDecodeData->mName << "/0x01";
+}
+
+PUdpMsgAnalyser* PUdpOOO::Analyse()
+{
+ mDecodeData->mName << "=Out Of Order";
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+
+ return this;
+}
+
+bool PUdpOOO::DoAction()
+{
+ uint16_t MissingUDP_ID = mDecodeData->mMessage->U16Data(mDecodeData->Sub0x13Start+5);
+
+ mDecodeData->mClient->getUDPConn()->ReSendUDPMessage(MissingUDP_ID);
+ //Console->Print("%s Out of Order packet received ! (Client is missing UDPID %d) ***not managed yet***", Console->ColorText(YELLOW, BLACK, "[Notice]"), MissingUDP_ID);
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
-#pragma once\r
-\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpOOO : public PUdpMsgAnalyser {\r
-public:\r
- PUdpOOO(PMsgDecodeData *nDecodeData);\r
- //~PUdpPing();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpOOO : public PUdpMsgAnalyser {
+public:
+ PUdpOOO(PMsgDecodeData *nDecodeData);
+ //~PUdpPing();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#pragma once\r
-\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpPacket0 : public PUdpMsgAnalyser {\r
-public:\r
- PUdpPacket0(PMsgDecodeData *nDecodeData);\r
- //~PUdpPacket0();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpPacket0 : public PUdpMsgAnalyser {
+public:
+ PUdpPacket0(PMsgDecodeData *nDecodeData);
+ //~PUdpPacket0();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#pragma once\r
-\r
-#include <cstdint>\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpPing : public PUdpMsgAnalyser {\r
-private:\r
- uint32_t mClientTime;\r
-\r
-public:\r
- PUdpPing(PMsgDecodeData *nDecodeData);\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpPing : public PUdpMsgAnalyser {
+private:
+ uint32_t mClientTime;
+
+public:
+ PUdpPing(PMsgDecodeData *nDecodeData);
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#pragma once\r
-\r
-#include <cstdint>\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpItemSlotUse : public PUdpMsgAnalyser {\r
-private:\r
- uint8_t mTargetSlot;\r
-\r
-public:\r
- PUdpItemSlotUse(PMsgDecodeData *nDecodeData);\r
- //~PUdpItemSlotUse();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpItemSlotUse : public PUdpMsgAnalyser {
+private:
+ uint8_t mTargetSlot;
+
+public:
+ PUdpItemSlotUse(PMsgDecodeData *nDecodeData);
+ //~PUdpItemSlotUse();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#pragma once\r
-\r
-#include <cstdint>\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpReqInfo : public PUdpMsgAnalyser {\r
-private:\r
- uint16_t mRequestType;\r
- uint32_t mInfoId;\r
-\r
-public:\r
- PUdpReqInfo(PMsgDecodeData *nDecodeData);\r
- //~PUdpCharInfo();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpReqInfo : public PUdpMsgAnalyser {
+private:
+ uint16_t mRequestType;
+ uint32_t mInfoId;
+
+public:
+ PUdpReqInfo(PMsgDecodeData *nDecodeData);
+ //~PUdpCharInfo();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#pragma once\r
-\r
-#include <cstdint>\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpSubskillInc : public PUdpMsgAnalyser {\r
-private:\r
- uint16_t SubskillID;\r
-\r
-public:\r
- PUdpSubskillInc(PMsgDecodeData *nDecodeData);\r
- //~PUdpSubskillInc();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpSubskillInc : public PUdpMsgAnalyser {
+private:
+ uint16_t SubskillID;
+
+public:
+ PUdpSubskillInc(PMsgDecodeData *nDecodeData);
+ //~PUdpSubskillInc();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#pragma once\r
-\r
-#include <cstdint>\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpSync0 : public PUdpMsgAnalyser {\r
-public:\r
- PUdpSync0(PMsgDecodeData *nDecodeData);\r
- //~PUdpSync0();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-\r
- static void GetToSync1(PMsgDecodeData *nDecodeData);\r
-};\r
-\r
-class PUdpSync1 : public PUdpMsgAnalyser {\r
-public:\r
- PUdpSync1(PMsgDecodeData *nDecodeData);\r
- //~PUdpSync1();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpSync2 : public PUdpMsgAnalyser {\r
-private:\r
- uint32_t mClientTime;\r
-\r
-public:\r
- PUdpSync2(PMsgDecodeData *nDecodeData);\r
- //~PUdpSync2();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpSync0 : public PUdpMsgAnalyser {
+public:
+ PUdpSync0(PMsgDecodeData *nDecodeData);
+ //~PUdpSync0();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+
+ static void GetToSync1(PMsgDecodeData *nDecodeData);
+};
+
+class PUdpSync1 : public PUdpMsgAnalyser {
+public:
+ PUdpSync1(PMsgDecodeData *nDecodeData);
+ //~PUdpSync1();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpSync2 : public PUdpMsgAnalyser {
+private:
+ uint32_t mClientTime;
+
+public:
+ PUdpSync2(PMsgDecodeData *nDecodeData);
+ //~PUdpSync2();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#include <cmath>\r
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-/*******************************************************************************************/\r
-/**** PUdpReceiveDB ****/\r
-/*******************************************************************************************/\r
-PUdpReceiveDB::PUdpReceiveDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x17";\r
- mOptionsCount = 0;\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpReceiveDB::Analyse()\r
-{\r
- PMessage* TmpMsg = mDecodeData->mMessage;\r
- uint16_t Unknown3, OptionSize;\r
-\r
- mDecodeData->mName << "=ReceiveDB request from client";\r
-\r
- mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 );\r
- TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 );\r
- ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is\r
- ( *TmpMsg ) >> mUnknown1; // command name size\r
- ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is!\r
- ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options!\r
- ( *TmpMsg ) >> mCommandName; // null terminated string\r
-\r
-\r
- while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) )\r
- {\r
- ( *TmpMsg ) >> OptionSize;\r
- if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )\r
- {\r
- ( *TmpMsg ) >> mOptions[mOptionsCount++];\r
- //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)!\r
- }\r
- else\r
- {\r
- break;\r
- }\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpReceiveDB::DoAction()\r
-{\r
- //PMessage* tmpMsg;\r
- //PClient* tClient = mDecodeData->mClient;\r
- //PChar* tChar = tClient->GetChar();\r
- bool Result = false;\r
-\r
- if ( gDevDebug )\r
- {\r
- Console->Print( "%s ReceiveDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- Console->Print( "%s Open Terminal - Terminal session %04x (?) - Unknown1 %04x - DBId %04x - Unknown2 %02x", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId, mUnknown1, mDBId, mUnknown2 );\r
- Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() );\r
- for ( uint8_t i = 0; i < mOptionsCount; ++i )\r
- Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() );\r
- }\r
-\r
- if ( mCommandName == "VehicleListing" )\r
- {\r
- Result = ActionVehicleListing();\r
- }\r
- else if ( mCommandName == "VehicleControl" )\r
- {\r
- Result = ActionVehicleControl();\r
- }\r
- else\r
- {\r
- // Let Terminal try before error\r
- Result = Terminal->HandleReceiveDB(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2);\r
- }\r
-\r
- if ( !Result )\r
- {\r
- Console->Print( "%s PUdpReceiveDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mCommandName.c_str() );\r
- for ( uint8_t i = 0; i < mOptionsCount; ++i )\r
- Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() );\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return Result;\r
-}\r
-\r
-bool PUdpReceiveDB::ActionVehicleListing()\r
-{\r
- PMessage* tmpMsg;\r
- PClient* tClient = mDecodeData->mClient;\r
- PChar* tChar = tClient->GetChar();\r
-\r
- if ( mOptionsCount == 3 ) // CharId, StartVhcEntry, MaxVhcEntries\r
- {\r
- if ((( uint32_t )atol( mOptions[0].c_str() ) ) != tChar->GetID() )\r
- {\r
- // Err: invalid CharId. Can alert, But we don't care :-) (except if used for other terminal function)\r
- }\r
- // !!! some more check/regex on values to do before using !!!\r
- uint16_t StartIndex = atoi( mOptions[1].c_str() );\r
- uint16_t MaxEntries = atoi( mOptions[2].c_str() );\r
-\r
- uint8_t nStatus = 1;\r
- uint16_t nErrcode = 0;\r
-\r
- tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );\r
- tClient->SendUDPMessage( tmpMsg );\r
-\r
- PVhcInfoList* VhcList = Vehicles->GetCharVehicles( tChar->GetID(), MaxEntries, StartIndex );\r
- if ( ! VhcList->empty() )\r
- {\r
- uint16_t NumEntries = VhcList->size();\r
- std::string* Answer = new std::string[4 * NumEntries];\r
- uint16_t Index = 0;\r
- PVehicleInformation* EntryInfo;\r
-//Console->Print("VHc entries : %d", NumEntries);\r
-\r
- while ( ! VhcList->empty() )\r
- {\r
- EntryInfo = VhcList->front();\r
- VhcList->pop();\r
- Answer[Index++] = Ssprintf( "%u", EntryInfo->GetVehicleId() ); //vhcId\r
- Answer[Index++] = Ssprintf( "%u", EntryInfo->GetVehicleType() ); //vhcType\r
- Answer[Index++] = Ssprintf( "%u", EntryInfo->GetStatus() ); //vhcStatus 0:parking, 1:in_service, 2:destroyed\r
- Answer[Index++] = Ssprintf( "%u", EntryInfo->GetHealth() ); //vhcHealth%\r
-//Console->Print("Entry: %s/%s/%s/%s", Answer[Index-4].c_str(), Answer[Index-3].c_str(), Answer[Index-2].c_str(), Answer[Index-1].c_str());\r
- delete EntryInfo;\r
- }\r
-\r
- tmpMsg = MsgBuilder->BuildDBAnswerMsg( tClient, &mCommandName, Answer, NumEntries, 4 );\r
- tClient->SendUDPMessage( tmpMsg );\r
- delete [] Answer;\r
- }\r
- delete VhcList;\r
-\r
- return true;\r
- }\r
- else\r
- return false;\r
- /*\r
- // Option1=CharId, Option2=resultEntryStart, Option3=maxResultEntries\r
- S=> 03/2b/1a <uint16_t size incl 0><uint8_t bool succes ?><uint16_t err code ?>VehicleListing+0\r
- 13 2a 00 7c be 19\r
- 03 2a 00 2b 1a 0f 00 01 00 00 56 65 68 69 63 6c .*.+......Vehicl\r
- 65 4c 69 73 74 69 6e 67 00 eListing.\r
- S=> 03/2b/17 0f 00 08 00 04 00 <0f 00><uint16_t entries nb><04 00>\r
- VehicleListing+0\r
- <id_size incl 0><id_string +0>\r
- <type_size><type_id_string? +0>\r
- <status_size><status_string +0> (val: 0=stored)\r
- <health_size><health_string +0> (val: 0-255)\r
- ==\r
- 03/2b/17 0f 00 01 00 04 00 <0f 00><uint16_t entries nb><04 00>\r
- 31\r
- 03 54 00 2b 17 0f 00 01 00 04 00 56 65 68 69 63 6c 65 4c 69 73 74 .....VehicleList\r
- 69 6e 67 00 06 00 32 35 32 37 37 00 03 00 36 30 ing...25277...60\r
- 00 02 00 30 00 04 00 32 35 35 00 ...0...255.\r
- */\r
-}\r
-\r
-bool PUdpReceiveDB::ActionVehicleControl()\r
-{\r
- PMessage* tmpMsg;\r
- PClient* tClient = mDecodeData->mClient;\r
-\r
- if ( mOptionsCount == 2 ) // VhcId, CharId\r
- {\r
- // !!! validate values !!!\r
- uint8_t nStatus = 1;\r
- uint16_t nErrcode = 0;\r
-\r
- tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );\r
- tClient->SendUDPMessage( tmpMsg );\r
-\r
- uint32_t VhcId = ( uint32_t )atol( mOptions[0].c_str() );\r
- PVehicleInformation EntryInfo;\r
- if ( Vehicles->GetVehicleInfo( VhcId, &EntryInfo ) )\r
- {\r
- std::string* Answer = new std::string[4];\r
- Answer[0] = Ssprintf( "%u", EntryInfo.GetVehicleType() ); //vhcType\r
- Answer[1] = Ssprintf( "%u", EntryInfo.GetStatus() ); //vhcStatus\r
- Answer[2] = Ssprintf( "%u", EntryInfo.GetHealth() ); //vhcHealth%\r
- Answer[3] = Ssprintf( "%u", ( 255 - EntryInfo.GetHealth() ) * 1000 * EntryInfo.GetVehicleType() / 255 ); //Repair cost\r
- if ( gDevDebug )\r
- Console->Print( "%s Entry: %s/%s/%s/%s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), Answer[0].c_str(), Answer[1].c_str(), Answer[2].c_str(), Answer[3].c_str() );\r
- tmpMsg = MsgBuilder->BuildDBAnswerMsg( tClient, &mCommandName, Answer, 1, 4 );\r
- tClient->SendUDPMessage( tmpMsg );\r
- delete [] Answer;\r
- }\r
- return true;\r
- }\r
- else\r
- return false;\r
- /*\r
- // Option1=VhcId, Option2=CharId\r
- S=> 03/2b/1a VehicleControl\r
- 13 77 00 c9 be 19\r
- 03 76 00 2b 1a 0f 00 01 00 00 56 65 68 69 63 6c .v.+......Vehicl\r
- 65 43 6f 6e 74 72 6f 6c 00 eControl.\r
- S=> 03/2b/17 0f 00 01 00 04 00 VehicleControl 4 0 255 4255(\r
- 2f\r
- 03 77 00 2b 17 0f 00 01 00 04 00 56 65 68 69 63 6c 65 43 6f 6e 74 .....VehicleCont\r
- 72 6f 6c 00 02 00 34 00 02 00 30 00 04 00 32 35 rol...4...0...25\r
- 35 00 05 00 34 32 35 35 00 5...4255.\r
- */\r
-}\r
-\r
-/*******************************************************************************************/\r
-/**** PUdpUpdateDB ****/\r
-/*******************************************************************************************/\r
-PUdpUpdateDB::PUdpUpdateDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x18";\r
- mOptionsCount = 0;\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpUpdateDB::Analyse()\r
-{\r
- PMessage* TmpMsg = mDecodeData->mMessage;\r
- uint16_t Unknown3, OptionSize;\r
-\r
- mDecodeData->mName << "=UpdateDB request from client";\r
-\r
- mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 );\r
- TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 );\r
- ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is\r
- ( *TmpMsg ) >> mUnknown1; // command name size\r
- ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is!\r
- ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options!\r
- ( *TmpMsg ) >> mCommandName; // null terminated string\r
-\r
-\r
- while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) )\r
- {\r
- ( *TmpMsg ) >> OptionSize;\r
- if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )\r
- {\r
- ( *TmpMsg ) >> mOptions[mOptionsCount++];\r
- //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)!\r
- }\r
- else\r
- {\r
- break;\r
- }\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpUpdateDB::DoAction()\r
-{\r
- if ( gDevDebug )\r
- {\r
- Console->Print( "%s UpdateDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId );\r
- Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() );\r
- for ( uint8_t i = 0; i < mOptionsCount; ++i )\r
- Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() );\r
- }\r
- bool Result = false;\r
- Result = Terminal->HandleUpdateDB(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2);\r
-\r
- if ( !Result )\r
- {\r
- Console->Print( "%s PUdpUpdateDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mCommandName.c_str() );\r
- for ( uint8_t i = 0; i < mOptionsCount; ++i )\r
- Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() );\r
- }\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
-/*******************************************************************************************/\r
-/**** PUdpTryAccessDB ****/\r
-/*******************************************************************************************/\r
-PUdpTryAccessDB::PUdpTryAccessDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x19";\r
- mOptionsCount = 0;\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpTryAccessDB::Analyse()\r
-{\r
- PMessage* TmpMsg = mDecodeData->mMessage;\r
- uint16_t Unknown3, OptionSize;\r
-\r
- mDecodeData->mName << "=TryAccess request from client";\r
-\r
- mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 );\r
- TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 );\r
- ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is\r
- ( *TmpMsg ) >> mUnknown1; // command name size\r
- ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is!\r
- ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options!\r
- ( *TmpMsg ) >> mCommandName; // null terminated string\r
-\r
- while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) )\r
- {\r
- ( *TmpMsg ) >> OptionSize;\r
- if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )\r
- {\r
- ( *TmpMsg ) >> mOptions[mOptionsCount++];\r
- //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)!\r
- }\r
- else\r
- {\r
- break;\r
- }\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpTryAccessDB::DoAction()\r
-{\r
- // Let the terminal class handle the request\r
- Terminal->HandleTryAccess(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2);\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
-/*******************************************************************************************/\r
-/**** PUdpQueryDB ****/\r
-/*******************************************************************************************/\r
-PUdpQueryDB::PUdpQueryDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x1b";\r
- mOptionsCount = 0;\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpQueryDB::Analyse()\r
-{\r
- PMessage* TmpMsg = mDecodeData->mMessage;\r
- uint16_t OptionSize;\r
-\r
- mDecodeData->mName << "=QueryDB request from client";\r
-\r
- mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 );\r
- TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 18 );\r
- ( *TmpMsg ) >> OptionSize; // Size of data\r
- ( *TmpMsg ) >> OptionSize; // Size of DB Command Name\r
- if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )\r
- {\r
- ( *TmpMsg ) >> mDBCommandName;\r
- }\r
- ( *TmpMsg ) >> OptionSize; // Size of Command Name\r
- if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )\r
- {\r
- ( *TmpMsg ) >> mCommandName; // null terminated string\r
- }\r
-\r
- while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) )\r
- {\r
- ( *TmpMsg ) >> OptionSize;\r
- if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )\r
- {\r
- ( *TmpMsg ) >> mOptions[mOptionsCount++];\r
- //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)!\r
- }\r
- else\r
- {\r
- break;\r
- }\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpQueryDB::DoAction()\r
-{\r
- //PMessage* tmpMsg;\r
- //PClient* tClient = mDecodeData->mClient;\r
- bool Result = false;\r
-\r
- if ( gDevDebug )\r
- {\r
- Console->Print( "%s QueryDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId );\r
- Console->Print( "%s DBCommand: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDBCommandName.c_str() );\r
- Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() );\r
- for ( uint8_t i = 0; i < mOptionsCount; ++i )\r
- Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() );\r
- }\r
-\r
- if ( mDBCommandName == "SPAWNVEHICLE" )\r
- {\r
- Result = ActionSpawnVehicle();\r
- }\r
- else if ( mDBCommandName == "REPAIRVEHICLE" )\r
- {\r
- Result = ActionRepairVehicle();\r
- }\r
- else if ( mDBCommandName == "DISMISSVEHICLE" )\r
- {\r
- Result = ActionDismissVehicle();\r
- }\r
- else\r
- {\r
- // Let Terminal try before error\r
- Result = Terminal->HandleQueryDB(mDecodeData->mClient, &mDBCommandName, &mCommandName, mOptions, mOptionsCount);\r
- }\r
-\r
- if ( !Result )\r
- {\r
- Console->Print( "%s PUdpQueryDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mDBCommandName.c_str() );\r
- for ( uint8_t i = 0; i < mOptionsCount; ++i )\r
- Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() );\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return Result;\r
-}\r
-\r
-bool PUdpQueryDB::ActionSpawnVehicle()\r
-{\r
- PMessage* tmpMsg;\r
- PClient* tClient = mDecodeData->mClient;\r
- PChar* tChar = tClient->GetChar();\r
-\r
- if ( mOptionsCount == 3 ) // 0, VhcId, CharId\r
- {\r
- uint32_t VhcId = ( uint32_t )atol( mOptions[1].c_str() );\r
- //uint32_t CharId = (uint32_t)atol(mOptions[2].c_str());\r
- // !!! validate values !!!\r
- // !!! + check CharId = current char && CharId is owner of VhcId\r
- uint8_t nStatus = 1; // 1=OK, 0=Err\r
- uint16_t nErrcode = 16; // 0=n/a 16=Already Spawned // MsdId = 2500+nErrcode [MISC]\r
-\r
- tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );\r
- tClient->SendUDPMessage( tmpMsg );\r
-\r
- PVhcCoordinates NewPosition;\r
- PWorld* CurrentWorld = Worlds->GetWorld( tChar->GetLocation() );\r
- bool relativePos = false;\r
- if ( tChar->GetLastUsedObject() && !WorldActors->IsDynamicActor( tChar->GetLastUsedObject() ) && CurrentWorld )\r
- {\r
- const PFurnitureItemTemplate* tFurnitureTemplate = CurrentWorld->GetFurnitureItemTemplate( tChar->GetLastUsedObject() / 1024 - 1 );\r
- if ( tFurnitureTemplate && ( tFurnitureTemplate->GetFunctionType() == 28 ) ) // vhc term\r
- {\r
- float decal = 1000; // distance at which to spawn the vhc\r
- float nPosX, nPosY, nPosZ;\r
- tFurnitureTemplate->GetPos( &nPosX, &nPosY, &nPosZ );\r
- nPosX += 32000;\r
- nPosY += 32000;\r
- float dX = ( tChar->Coords.mX - nPosX );\r
- float dY = ( tChar->Coords.mY - nPosY );\r
- float d = decal / sqrt( dX * dX + dY * dY );\r
- NewPosition.SetPosition( static_cast<uint16_t>( nPosY + d * dY ), ( tChar->Coords ).mZ + 100, static_cast<uint16_t>( nPosX + d * dX ), ( tChar->Coords ).mUD, 34683, 32403 );\r
- relativePos = true;\r
- }\r
- }\r
-\r
- if( ! relativePos )\r
- NewPosition.SetPosition(( tChar->Coords ).mY, ( tChar->Coords ).mZ + 150, ( tChar->Coords ).mX, ( tChar->Coords ).mUD, 34683, 32403 );\r
-\r
- PSpawnedVehicle* NewVhc = Vehicles->SpawnVehicle( VhcId, tChar->GetLocation(), &NewPosition );\r
- if ( NewVhc )\r
- {\r
- tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( NewVhc );\r
- ClientManager->UDPBroadcast( tmpMsg, tChar->GetLocation() );\r
- }\r
-\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-bool PUdpQueryDB::ActionRepairVehicle()\r
-{\r
- PMessage* tmpMsg;\r
- PClient* tClient = mDecodeData->mClient;\r
-\r
- if ( mOptionsCount == 3 ) // 0, VhcId, CharId\r
- {\r
- //uint32_t VhcId = (uint32_t)atol(mOptions[1].c_str());\r
- //uint32_t CharId = (uint32_t)atol(mOptions[2].c_str());\r
- // !!! validate values !!!\r
-\r
- uint8_t nStatus = 1; // 1=OK, 0=Err\r
- uint16_t nErrcode = 18; // 0=n/a 18=Still Spawned, 19=Not enough money\r
-\r
- tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );\r
- tClient->SendUDPMessage( tmpMsg );\r
-\r
- // Action here\r
-\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-bool PUdpQueryDB::ActionDismissVehicle()\r
-{\r
- PMessage* tmpMsg;\r
- PClient* tClient = mDecodeData->mClient;\r
- //PChar* tChar = tClient->GetChar();\r
- bool Result = false;\r
-\r
- if ( mOptionsCount == 3 ) // 0, VhcId, CharId\r
- {\r
- uint32_t VhcId = ( uint32_t )atol( mOptions[1].c_str() );\r
- //uint32_t CharId = (uint32_t)atol(mOptions[2].c_str());\r
- // !!! validate values !!!\r
- // !!! + check CharId = current char && CharId is owner of VjhcId\r
- // !!! Check vhc empty\r
- uint8_t nStatus = 0; // 1=OK, 0=Err\r
- uint16_t nErrcode = 17; // 0=n/a 17=Not Spawned\r
- PVehicleInformation nInfo;\r
- uint32_t tLocalId = 0;\r
- uint32_t tLocation = 0;\r
-\r
- PSpawnedVehicle* tVhc = Vehicles->GetSpawnedVehicle( VhcId );\r
- if ( tVhc )\r
- {\r
- tLocalId = tVhc->GetLocalId();\r
- tLocation = tVhc->GetLocation();\r
- uint32_t tCharId;\r
- PChar* tChar;\r
- for ( uint8_t i = 0; i < tVhc->GetNumSeats(); ++i )\r
- {\r
- if (( tCharId = tVhc->GetSeatUser( i ) ) )\r
- {\r
- if (( tChar = Chars->GetChar( tCharId ) ) )\r
- {\r
- PUdpCharExitChair::DoLeaveChair( tChar, NULL, tVhc );\r
- }\r
- }\r
- }\r
- Result = Vehicles->UnspawnVehicle( VhcId );\r
- }\r
-\r
- if ( Result )\r
- {\r
- nStatus = 1;\r
- nErrcode = 0;\r
- }\r
- tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );\r
- tClient->SendUDPMessage( tmpMsg );\r
-\r
- if ( Result )\r
- {\r
- tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg( tLocalId );\r
- ClientManager->UDPBroadcast( tmpMsg, tLocation );\r
- }\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-/*******************************************************************************************/\r
-/**** PUdpTeminal0x1f ****/\r
-/*******************************************************************************************/\r
-PUdpTeminal0x1f::PUdpTeminal0x1f( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x1f";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpTeminal0x1f::Analyse()\r
-{\r
- mDecodeData->mName << "=Open Terminal";\r
- mTerminalSessionId = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 6 );\r
-\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpTeminal0x1f::DoAction()\r
-{\r
- if ( gDevDebug )\r
- Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
+#include <cmath>
+#include "GameServer/Decoder/Includes.hxx"
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+/*******************************************************************************************/
+/**** PUdpReceiveDB ****/
+/*******************************************************************************************/
+PUdpReceiveDB::PUdpReceiveDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x17";
+ mOptionsCount = 0;
+}
+
+PUdpMsgAnalyser* PUdpReceiveDB::Analyse()
+{
+ PMessage* TmpMsg = mDecodeData->mMessage;
+ uint16_t Unknown3, OptionSize;
+
+ mDecodeData->mName << "=ReceiveDB request from client";
+
+ mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 );
+ TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 );
+ ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is
+ ( *TmpMsg ) >> mUnknown1; // command name size
+ ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is!
+ ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options!
+ ( *TmpMsg ) >> mCommandName; // null terminated string
+
+
+ while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) )
+ {
+ ( *TmpMsg ) >> OptionSize;
+ if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )
+ {
+ ( *TmpMsg ) >> mOptions[mOptionsCount++];
+ //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)!
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpReceiveDB::DoAction()
+{
+ //PMessage* tmpMsg;
+ //PClient* tClient = mDecodeData->mClient;
+ //PChar* tChar = tClient->GetChar();
+ bool Result = false;
+
+ if ( gDevDebug )
+ {
+ Console->Print( "%s ReceiveDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ Console->Print( "%s Open Terminal - Terminal session %04x (?) - Unknown1 %04x - DBId %04x - Unknown2 %02x", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId, mUnknown1, mDBId, mUnknown2 );
+ Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() );
+ for ( uint8_t i = 0; i < mOptionsCount; ++i )
+ Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() );
+ }
+
+ if ( mCommandName == "VehicleListing" )
+ {
+ Result = ActionVehicleListing();
+ }
+ else if ( mCommandName == "VehicleControl" )
+ {
+ Result = ActionVehicleControl();
+ }
+ else
+ {
+ // Let Terminal try before error
+ Result = Terminal->HandleReceiveDB(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2);
+ }
+
+ if ( !Result )
+ {
+ Console->Print( "%s PUdpReceiveDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mCommandName.c_str() );
+ for ( uint8_t i = 0; i < mOptionsCount; ++i )
+ Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() );
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return Result;
+}
+
+bool PUdpReceiveDB::ActionVehicleListing()
+{
+ PMessage* tmpMsg;
+ PClient* tClient = mDecodeData->mClient;
+ PChar* tChar = tClient->GetChar();
+
+ if ( mOptionsCount == 3 ) // CharId, StartVhcEntry, MaxVhcEntries
+ {
+ if ((( uint32_t )atol( mOptions[0].c_str() ) ) != tChar->GetID() )
+ {
+ // Err: invalid CharId. Can alert, But we don't care :-) (except if used for other terminal function)
+ }
+ // !!! some more check/regex on values to do before using !!!
+ uint16_t StartIndex = atoi( mOptions[1].c_str() );
+ uint16_t MaxEntries = atoi( mOptions[2].c_str() );
+
+ uint8_t nStatus = 1;
+ uint16_t nErrcode = 0;
+
+ tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );
+ tClient->SendUDPMessage( tmpMsg );
+
+ PVhcInfoList* VhcList = Vehicles->GetCharVehicles( tChar->GetID(), MaxEntries, StartIndex );
+ if ( ! VhcList->empty() )
+ {
+ uint16_t NumEntries = VhcList->size();
+ std::string* Answer = new std::string[4 * NumEntries];
+ uint16_t Index = 0;
+ PVehicleInformation* EntryInfo;
+//Console->Print("VHc entries : %d", NumEntries);
+
+ while ( ! VhcList->empty() )
+ {
+ EntryInfo = VhcList->front();
+ VhcList->pop();
+ Answer[Index++] = Ssprintf( "%u", EntryInfo->GetVehicleId() ); //vhcId
+ Answer[Index++] = Ssprintf( "%u", EntryInfo->GetVehicleType() ); //vhcType
+ Answer[Index++] = Ssprintf( "%u", EntryInfo->GetStatus() ); //vhcStatus 0:parking, 1:in_service, 2:destroyed
+ Answer[Index++] = Ssprintf( "%u", EntryInfo->GetHealth() ); //vhcHealth%
+//Console->Print("Entry: %s/%s/%s/%s", Answer[Index-4].c_str(), Answer[Index-3].c_str(), Answer[Index-2].c_str(), Answer[Index-1].c_str());
+ delete EntryInfo;
+ }
+
+ tmpMsg = MsgBuilder->BuildDBAnswerMsg( tClient, &mCommandName, Answer, NumEntries, 4 );
+ tClient->SendUDPMessage( tmpMsg );
+ delete [] Answer;
+ }
+ delete VhcList;
+
+ return true;
+ }
+ else
+ return false;
+ /*
+ // Option1=CharId, Option2=resultEntryStart, Option3=maxResultEntries
+ S=> 03/2b/1a <uint16_t size incl 0><uint8_t bool succes ?><uint16_t err code ?>VehicleListing+0
+ 13 2a 00 7c be 19
+ 03 2a 00 2b 1a 0f 00 01 00 00 56 65 68 69 63 6c .*.+......Vehicl
+ 65 4c 69 73 74 69 6e 67 00 eListing.
+ S=> 03/2b/17 0f 00 08 00 04 00 <0f 00><uint16_t entries nb><04 00>
+ VehicleListing+0
+ <id_size incl 0><id_string +0>
+ <type_size><type_id_string? +0>
+ <status_size><status_string +0> (val: 0=stored)
+ <health_size><health_string +0> (val: 0-255)
+ ==
+ 03/2b/17 0f 00 01 00 04 00 <0f 00><uint16_t entries nb><04 00>
+ 31
+ 03 54 00 2b 17 0f 00 01 00 04 00 56 65 68 69 63 6c 65 4c 69 73 74 .....VehicleList
+ 69 6e 67 00 06 00 32 35 32 37 37 00 03 00 36 30 ing...25277...60
+ 00 02 00 30 00 04 00 32 35 35 00 ...0...255.
+ */
+}
+
+bool PUdpReceiveDB::ActionVehicleControl()
+{
+ PMessage* tmpMsg;
+ PClient* tClient = mDecodeData->mClient;
+
+ if ( mOptionsCount == 2 ) // VhcId, CharId
+ {
+ // !!! validate values !!!
+ uint8_t nStatus = 1;
+ uint16_t nErrcode = 0;
+
+ tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );
+ tClient->SendUDPMessage( tmpMsg );
+
+ uint32_t VhcId = ( uint32_t )atol( mOptions[0].c_str() );
+ PVehicleInformation EntryInfo;
+ if ( Vehicles->GetVehicleInfo( VhcId, &EntryInfo ) )
+ {
+ std::string* Answer = new std::string[4];
+ Answer[0] = Ssprintf( "%u", EntryInfo.GetVehicleType() ); //vhcType
+ Answer[1] = Ssprintf( "%u", EntryInfo.GetStatus() ); //vhcStatus
+ Answer[2] = Ssprintf( "%u", EntryInfo.GetHealth() ); //vhcHealth%
+ Answer[3] = Ssprintf( "%u", ( 255 - EntryInfo.GetHealth() ) * 1000 * EntryInfo.GetVehicleType() / 255 ); //Repair cost
+ if ( gDevDebug )
+ Console->Print( "%s Entry: %s/%s/%s/%s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), Answer[0].c_str(), Answer[1].c_str(), Answer[2].c_str(), Answer[3].c_str() );
+ tmpMsg = MsgBuilder->BuildDBAnswerMsg( tClient, &mCommandName, Answer, 1, 4 );
+ tClient->SendUDPMessage( tmpMsg );
+ delete [] Answer;
+ }
+ return true;
+ }
+ else
+ return false;
+ /*
+ // Option1=VhcId, Option2=CharId
+ S=> 03/2b/1a VehicleControl
+ 13 77 00 c9 be 19
+ 03 76 00 2b 1a 0f 00 01 00 00 56 65 68 69 63 6c .v.+......Vehicl
+ 65 43 6f 6e 74 72 6f 6c 00 eControl.
+ S=> 03/2b/17 0f 00 01 00 04 00 VehicleControl 4 0 255 4255(
+ 2f
+ 03 77 00 2b 17 0f 00 01 00 04 00 56 65 68 69 63 6c 65 43 6f 6e 74 .....VehicleCont
+ 72 6f 6c 00 02 00 34 00 02 00 30 00 04 00 32 35 rol...4...0...25
+ 35 00 05 00 34 32 35 35 00 5...4255.
+ */
+}
+
+/*******************************************************************************************/
+/**** PUdpUpdateDB ****/
+/*******************************************************************************************/
+PUdpUpdateDB::PUdpUpdateDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x18";
+ mOptionsCount = 0;
+}
+
+PUdpMsgAnalyser* PUdpUpdateDB::Analyse()
+{
+ PMessage* TmpMsg = mDecodeData->mMessage;
+ uint16_t Unknown3, OptionSize;
+
+ mDecodeData->mName << "=UpdateDB request from client";
+
+ mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 );
+ TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 );
+ ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is
+ ( *TmpMsg ) >> mUnknown1; // command name size
+ ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is!
+ ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options!
+ ( *TmpMsg ) >> mCommandName; // null terminated string
+
+
+ while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) )
+ {
+ ( *TmpMsg ) >> OptionSize;
+ if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )
+ {
+ ( *TmpMsg ) >> mOptions[mOptionsCount++];
+ //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)!
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpUpdateDB::DoAction()
+{
+ if ( gDevDebug )
+ {
+ Console->Print( "%s UpdateDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId );
+ Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() );
+ for ( uint8_t i = 0; i < mOptionsCount; ++i )
+ Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() );
+ }
+ bool Result = false;
+ Result = Terminal->HandleUpdateDB(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2);
+
+ if ( !Result )
+ {
+ Console->Print( "%s PUdpUpdateDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mCommandName.c_str() );
+ for ( uint8_t i = 0; i < mOptionsCount; ++i )
+ Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() );
+ }
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
+/*******************************************************************************************/
+/**** PUdpTryAccessDB ****/
+/*******************************************************************************************/
+PUdpTryAccessDB::PUdpTryAccessDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x19";
+ mOptionsCount = 0;
+}
+
+PUdpMsgAnalyser* PUdpTryAccessDB::Analyse()
+{
+ PMessage* TmpMsg = mDecodeData->mMessage;
+ uint16_t Unknown3, OptionSize;
+
+ mDecodeData->mName << "=TryAccess request from client";
+
+ mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 );
+ TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 );
+ ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is
+ ( *TmpMsg ) >> mUnknown1; // command name size
+ ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is!
+ ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options!
+ ( *TmpMsg ) >> mCommandName; // null terminated string
+
+ while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) )
+ {
+ ( *TmpMsg ) >> OptionSize;
+ if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )
+ {
+ ( *TmpMsg ) >> mOptions[mOptionsCount++];
+ //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)!
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpTryAccessDB::DoAction()
+{
+ // Let the terminal class handle the request
+ Terminal->HandleTryAccess(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2);
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
+/*******************************************************************************************/
+/**** PUdpQueryDB ****/
+/*******************************************************************************************/
+PUdpQueryDB::PUdpQueryDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x1b";
+ mOptionsCount = 0;
+}
+
+PUdpMsgAnalyser* PUdpQueryDB::Analyse()
+{
+ PMessage* TmpMsg = mDecodeData->mMessage;
+ uint16_t OptionSize;
+
+ mDecodeData->mName << "=QueryDB request from client";
+
+ mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 );
+ TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 18 );
+ ( *TmpMsg ) >> OptionSize; // Size of data
+ ( *TmpMsg ) >> OptionSize; // Size of DB Command Name
+ if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )
+ {
+ ( *TmpMsg ) >> mDBCommandName;
+ }
+ ( *TmpMsg ) >> OptionSize; // Size of Command Name
+ if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )
+ {
+ ( *TmpMsg ) >> mCommandName; // null terminated string
+ }
+
+ while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) )
+ {
+ ( *TmpMsg ) >> OptionSize;
+ if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize )
+ {
+ ( *TmpMsg ) >> mOptions[mOptionsCount++];
+ //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)!
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpQueryDB::DoAction()
+{
+ //PMessage* tmpMsg;
+ //PClient* tClient = mDecodeData->mClient;
+ bool Result = false;
+
+ if ( gDevDebug )
+ {
+ Console->Print( "%s QueryDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId );
+ Console->Print( "%s DBCommand: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDBCommandName.c_str() );
+ Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() );
+ for ( uint8_t i = 0; i < mOptionsCount; ++i )
+ Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() );
+ }
+
+ if ( mDBCommandName == "SPAWNVEHICLE" )
+ {
+ Result = ActionSpawnVehicle();
+ }
+ else if ( mDBCommandName == "REPAIRVEHICLE" )
+ {
+ Result = ActionRepairVehicle();
+ }
+ else if ( mDBCommandName == "DISMISSVEHICLE" )
+ {
+ Result = ActionDismissVehicle();
+ }
+ else
+ {
+ // Let Terminal try before error
+ Result = Terminal->HandleQueryDB(mDecodeData->mClient, &mDBCommandName, &mCommandName, mOptions, mOptionsCount);
+ }
+
+ if ( !Result )
+ {
+ Console->Print( "%s PUdpQueryDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mDBCommandName.c_str() );
+ for ( uint8_t i = 0; i < mOptionsCount; ++i )
+ Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() );
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return Result;
+}
+
+bool PUdpQueryDB::ActionSpawnVehicle()
+{
+ PMessage* tmpMsg;
+ PClient* tClient = mDecodeData->mClient;
+ PChar* tChar = tClient->GetChar();
+
+ if ( mOptionsCount == 3 ) // 0, VhcId, CharId
+ {
+ uint32_t VhcId = ( uint32_t )atol( mOptions[1].c_str() );
+ //uint32_t CharId = (uint32_t)atol(mOptions[2].c_str());
+ // !!! validate values !!!
+ // !!! + check CharId = current char && CharId is owner of VhcId
+ uint8_t nStatus = 1; // 1=OK, 0=Err
+ uint16_t nErrcode = 16; // 0=n/a 16=Already Spawned // MsdId = 2500+nErrcode [MISC]
+
+ tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );
+ tClient->SendUDPMessage( tmpMsg );
+
+ PVhcCoordinates NewPosition;
+ PWorld* CurrentWorld = Worlds->GetWorld( tChar->GetLocation() );
+ bool relativePos = false;
+ if ( tChar->GetLastUsedObject() && !WorldActors->IsDynamicActor( tChar->GetLastUsedObject() ) && CurrentWorld )
+ {
+ const PFurnitureItemTemplate* tFurnitureTemplate = CurrentWorld->GetFurnitureItemTemplate( tChar->GetLastUsedObject() / 1024 - 1 );
+ if ( tFurnitureTemplate && ( tFurnitureTemplate->GetFunctionType() == 28 ) ) // vhc term
+ {
+ float decal = 1000; // distance at which to spawn the vhc
+ float nPosX, nPosY, nPosZ;
+ tFurnitureTemplate->GetPos( &nPosX, &nPosY, &nPosZ );
+ nPosX += 32000;
+ nPosY += 32000;
+ float dX = ( tChar->Coords.mX - nPosX );
+ float dY = ( tChar->Coords.mY - nPosY );
+ float d = decal / sqrt( dX * dX + dY * dY );
+ NewPosition.SetPosition( static_cast<uint16_t>( nPosY + d * dY ), ( tChar->Coords ).mZ + 100, static_cast<uint16_t>( nPosX + d * dX ), ( tChar->Coords ).mUD, 34683, 32403 );
+ relativePos = true;
+ }
+ }
+
+ if( ! relativePos )
+ NewPosition.SetPosition(( tChar->Coords ).mY, ( tChar->Coords ).mZ + 150, ( tChar->Coords ).mX, ( tChar->Coords ).mUD, 34683, 32403 );
+
+ PSpawnedVehicle* NewVhc = Vehicles->SpawnVehicle( VhcId, tChar->GetLocation(), &NewPosition );
+ if ( NewVhc )
+ {
+ tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( NewVhc );
+ ClientManager->UDPBroadcast( tmpMsg, tChar->GetLocation() );
+ }
+
+ return true;
+ }
+ else
+ return false;
+}
+
+bool PUdpQueryDB::ActionRepairVehicle()
+{
+ PMessage* tmpMsg;
+ PClient* tClient = mDecodeData->mClient;
+
+ if ( mOptionsCount == 3 ) // 0, VhcId, CharId
+ {
+ //uint32_t VhcId = (uint32_t)atol(mOptions[1].c_str());
+ //uint32_t CharId = (uint32_t)atol(mOptions[2].c_str());
+ // !!! validate values !!!
+
+ uint8_t nStatus = 1; // 1=OK, 0=Err
+ uint16_t nErrcode = 18; // 0=n/a 18=Still Spawned, 19=Not enough money
+
+ tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );
+ tClient->SendUDPMessage( tmpMsg );
+
+ // Action here
+
+ return true;
+ }
+ else
+ return false;
+}
+
+bool PUdpQueryDB::ActionDismissVehicle()
+{
+ PMessage* tmpMsg;
+ PClient* tClient = mDecodeData->mClient;
+ //PChar* tChar = tClient->GetChar();
+ bool Result = false;
+
+ if ( mOptionsCount == 3 ) // 0, VhcId, CharId
+ {
+ uint32_t VhcId = ( uint32_t )atol( mOptions[1].c_str() );
+ //uint32_t CharId = (uint32_t)atol(mOptions[2].c_str());
+ // !!! validate values !!!
+ // !!! + check CharId = current char && CharId is owner of VjhcId
+ // !!! Check vhc empty
+ uint8_t nStatus = 0; // 1=OK, 0=Err
+ uint16_t nErrcode = 17; // 0=n/a 17=Not Spawned
+ PVehicleInformation nInfo;
+ uint32_t tLocalId = 0;
+ uint32_t tLocation = 0;
+
+ PSpawnedVehicle* tVhc = Vehicles->GetSpawnedVehicle( VhcId );
+ if ( tVhc )
+ {
+ tLocalId = tVhc->GetLocalId();
+ tLocation = tVhc->GetLocation();
+ uint32_t tCharId;
+ PChar* tChar;
+ for ( uint8_t i = 0; i < tVhc->GetNumSeats(); ++i )
+ {
+ if (( tCharId = tVhc->GetSeatUser( i ) ) )
+ {
+ if (( tChar = Chars->GetChar( tCharId ) ) )
+ {
+ PUdpCharExitChair::DoLeaveChair( tChar, NULL, tVhc );
+ }
+ }
+ }
+ Result = Vehicles->UnspawnVehicle( VhcId );
+ }
+
+ if ( Result )
+ {
+ nStatus = 1;
+ nErrcode = 0;
+ }
+ tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode );
+ tClient->SendUDPMessage( tmpMsg );
+
+ if ( Result )
+ {
+ tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg( tLocalId );
+ ClientManager->UDPBroadcast( tmpMsg, tLocation );
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+/*******************************************************************************************/
+/**** PUdpTeminal0x1f ****/
+/*******************************************************************************************/
+PUdpTeminal0x1f::PUdpTeminal0x1f( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x1f";
+}
+
+PUdpMsgAnalyser* PUdpTeminal0x1f::Analyse()
+{
+ mDecodeData->mName << "=Open Terminal";
+ mTerminalSessionId = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 6 );
+
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpTeminal0x1f::DoAction()
+{
+ if ( gDevDebug )
+ Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpReceiveDB : public PUdpMsgAnalyser {\r
-private:\r
- static const uint8_t mMaxOptions = 9; // Largest: forum\forenlist.tsc(21, 114,...)\r
- uint16_t mTerminalSessionId;\r
- std::string mCommandName;\r
- std::string mOptions[mMaxOptions];\r
- uint8_t mOptionsCount;\r
-\r
- uint16_t mUnknown1;\r
- uint8_t mUnknown2;\r
- uint16_t mDBId;\r
-\r
- bool ActionVehicleListing();\r
- bool ActionVehicleControl();\r
-\r
-public:\r
- PUdpReceiveDB(PMsgDecodeData *nDecodeData);\r
- //~PUdpReceiveDB();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpUpdateDB : public PUdpMsgAnalyser {\r
-private:\r
- static const uint8_t mMaxOptions = 7; // Largest: forum\bbcnewthread.tsc(66):\r
- uint16_t mTerminalSessionId;\r
- std::string mCommandName;\r
- std::string mOptions[mMaxOptions];\r
- uint8_t mOptionsCount;\r
-\r
- uint16_t mUnknown1;\r
- uint8_t mUnknown2;\r
- uint16_t mDBId;\r
-\r
-public:\r
- PUdpUpdateDB(PMsgDecodeData *nDecodeData);\r
- //~PUdpUpdateDB();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpTryAccessDB : public PUdpMsgAnalyser {\r
-private:\r
- static const uint8_t mMaxOptions = 9; // Largest: stockx\depot.tsc(227):\r
- uint16_t mTerminalSessionId;\r
- std::string mCommandName;\r
- std::string mOptions[mMaxOptions];\r
- uint8_t mOptionsCount;\r
-\r
- uint16_t mUnknown1;\r
- uint8_t mUnknown2;\r
- uint16_t mDBId;\r
-\r
-public:\r
- PUdpTryAccessDB(PMsgDecodeData *nDecodeData);\r
- //~PUdpTryAccessDB();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpQueryDB : public PUdpMsgAnalyser { // Also called "ServerMessage" in .tsc scripts!\r
-private:\r
- static const uint8_t mMaxOptions = 5; // Largest: politics\transcomment.tsc(36):\r
- uint16_t mTerminalSessionId;\r
- uint16_t mDBId;\r
- std::string mDBCommandName;\r
- std::string mCommandName;\r
- std::string mOptions[mMaxOptions];\r
- uint8_t mOptionsCount;\r
-\r
- bool ActionSpawnVehicle();\r
- bool ActionRepairVehicle();\r
- bool ActionDismissVehicle();\r
-\r
-public:\r
- PUdpQueryDB(PMsgDecodeData *nDecodeData);\r
- //~PUdpQueryDB();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpTeminal0x1f : public PUdpMsgAnalyser {\r
-private:\r
- uint16_t mTerminalSessionId;\r
-\r
-public:\r
- PUdpTeminal0x1f(PMsgDecodeData *nDecodeData);\r
- //~PUdpTeminal0x1f();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpReceiveDB : public PUdpMsgAnalyser {
+private:
+ static const uint8_t mMaxOptions = 9; // Largest: forum\forenlist.tsc(21, 114,...)
+ uint16_t mTerminalSessionId;
+ std::string mCommandName;
+ std::string mOptions[mMaxOptions];
+ uint8_t mOptionsCount;
+
+ uint16_t mUnknown1;
+ uint8_t mUnknown2;
+ uint16_t mDBId;
+
+ bool ActionVehicleListing();
+ bool ActionVehicleControl();
+
+public:
+ PUdpReceiveDB(PMsgDecodeData *nDecodeData);
+ //~PUdpReceiveDB();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpUpdateDB : public PUdpMsgAnalyser {
+private:
+ static const uint8_t mMaxOptions = 7; // Largest: forum\bbcnewthread.tsc(66):
+ uint16_t mTerminalSessionId;
+ std::string mCommandName;
+ std::string mOptions[mMaxOptions];
+ uint8_t mOptionsCount;
+
+ uint16_t mUnknown1;
+ uint8_t mUnknown2;
+ uint16_t mDBId;
+
+public:
+ PUdpUpdateDB(PMsgDecodeData *nDecodeData);
+ //~PUdpUpdateDB();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpTryAccessDB : public PUdpMsgAnalyser {
+private:
+ static const uint8_t mMaxOptions = 9; // Largest: stockx\depot.tsc(227):
+ uint16_t mTerminalSessionId;
+ std::string mCommandName;
+ std::string mOptions[mMaxOptions];
+ uint8_t mOptionsCount;
+
+ uint16_t mUnknown1;
+ uint8_t mUnknown2;
+ uint16_t mDBId;
+
+public:
+ PUdpTryAccessDB(PMsgDecodeData *nDecodeData);
+ //~PUdpTryAccessDB();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpQueryDB : public PUdpMsgAnalyser { // Also called "ServerMessage" in .tsc scripts!
+private:
+ static const uint8_t mMaxOptions = 5; // Largest: politics\transcomment.tsc(36):
+ uint16_t mTerminalSessionId;
+ uint16_t mDBId;
+ std::string mDBCommandName;
+ std::string mCommandName;
+ std::string mOptions[mMaxOptions];
+ uint8_t mOptionsCount;
+
+ bool ActionSpawnVehicle();
+ bool ActionRepairVehicle();
+ bool ActionDismissVehicle();
+
+public:
+ PUdpQueryDB(PMsgDecodeData *nDecodeData);
+ //~PUdpQueryDB();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpTeminal0x1f : public PUdpMsgAnalyser {
+private:
+ uint16_t mTerminalSessionId;
+
+public:
+ PUdpTeminal0x1f(PMsgDecodeData *nDecodeData);
+ //~PUdpTeminal0x1f();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "GameServer/Definitions/Includes.hxx"\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-uint32_t gVhcId = 0x3ff;\r
-\r
-/**** PUdpVhcMove ****/\r
-\r
-PUdpUseObject::PUdpUseObject( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x17";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpUseObject::Analyse()\r
-{\r
- mDecodeData->mName << "=Object use";\r
-\r
- mRawItemID = mDecodeData->mMessage->U32Data( mDecodeData->Sub0x13Start + 8 );\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpUseObject::DoAction()\r
-{\r
- PClient* nClient = mDecodeData->mClient;\r
- PChar* nChar = nClient->GetChar();\r
- uint32_t ItemID;\r
- char DbgMessage[128];\r
- PMessage* tmpMsg;\r
-\r
- bool tHandleDynamicActor = false;\r
-\r
- /*PMessage* cMsg = mDecodeData->mMessage;\r
- uint32_t ClientTime = cMsg->U32Data(mDecodeData->Sub0x13Start+2);\r
-\r
- tmpMsg = MsgBuilder->BuildPingMsg(mDecodeData->mClient, ClientTime);\r
- mDecodeData->mClient->SendUDPMessage(tmpMsg);*/\r
-\r
- nChar->SetLastUsedObject( mRawItemID );\r
-\r
- if ( nClient->IsInRemoveActorMode() == true )\r
- {\r
- if ( WorldActors->IsDynamicActor( mRawItemID ) == true )\r
- {\r
- WorldActors->DelWorldActor( nClient, mRawItemID );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
- }\r
- else\r
- Chat->send( nClient, CHAT_DIRECT, "System", "This is not an dynamic worldactor. To remove it please type @remove <rawID>" );\r
- }\r
-\r
- if ( gDevDebug )\r
- {\r
- Console->Print( "Char at y=%f (0x%04x) z=%f (0x%04x) x=%f (0x%04x)", ( float )( nChar->Coords.mY - 32000 ), nChar->Coords.mY, ( float )( nChar->Coords.mZ - 32000 ), nChar->Coords.mZ, ( float )( nChar->Coords.mX - 32000 ), nChar->Coords.mX );\r
- if ( mRawItemID & 1023 )\r
- Console->Print( "using item %d (0x%08x)", mRawItemID, mRawItemID );\r
- else\r
- Console->Print( "using item %d (0x%08x) [dat entry %d (0x%08x)]", mRawItemID, mRawItemID, mRawItemID / 1024 - 1, mRawItemID / 1024 - 1 );\r
- }\r
-\r
- if ( nClient->GetDebugMode( DBG_ITEMID ) )\r
- {\r
- if ( mRawItemID & 1023 )\r
- snprintf( DbgMessage, 128, "using item [raw: %d (0x%08x)]", mRawItemID, mRawItemID );\r
- else\r
- snprintf( DbgMessage, 128, "using item %d (0x%08x) [raw: %d (0x%08x)]", mRawItemID / 1024 - 1, mRawItemID / 1024 - 1, mRawItemID, mRawItemID );\r
- Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
- }\r
-\r
- PWorld* CurrentWorld = Worlds->GetWorld( nChar->GetLocation() );\r
- if ( CurrentWorld )\r
- {\r
- if ( WorldActors->IsDynamicActor( mRawItemID ) == true )\r
- {\r
- tHandleDynamicActor = true;\r
- if ( gDevDebug )\r
- Console->Print( "%s Dynamic actor found, processing...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- }\r
-\r
- if ( mRawItemID & 1023 && tHandleDynamicActor == false ) // non-furniture objects\r
- {\r
- if ( mRawItemID > 0x80 ) // maybe door\r
- {\r
- if ( nClient->GetDebugMode( DBG_ITEMID ) )\r
- {\r
- snprintf( DbgMessage, 128, "Door : %d", mRawItemID - 0x80 );\r
- Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
- }\r
- const PDoorTemplate* tDoor = CurrentWorld->GetDoor( mRawItemID - 0x80 );\r
- if ( tDoor )\r
- {\r
- if ( tDoor->IsTriggeredDoor() )\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- else\r
- {\r
- if ( gDevDebug )\r
- Console->Print( "%s Opening %s door %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), ( tDoor->IsDoubleDoor() ? "double" : "simple" ), mRawItemID - 0x80 );\r
- tmpMsg = MsgBuilder->BuildDoorOpenMsg( mRawItemID, tDoor->IsDoubleDoor() );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- }\r
- }\r
- if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // else might be PC, NPC, VHC\r
- {\r
- if ( gDevDebug )\r
- Console->Print( "%s Clicking on char, npc or vhc %d (%x) - time = %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, mRawItemID, GameServer->GetGameTime() );\r
-\r
- if ( PSpawnedVehicles::IsPotentialSpawnedVehicle( mRawItemID ) )\r
- {\r
- bool vhcFound = false;\r
-\r
- if ( nChar->GetSeatInUse() == seat_none ) // Refuse if Char is already sitting somewhere\r
- {\r
- PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mRawItemID );\r
- if ( tVhc )\r
- {\r
- if ( gDevDebug )\r
- Console->Print( "%s Using vhc %d (0x%04x)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, mRawItemID );\r
- vhcFound = true;\r
-\r
- if ( tVhc->GetInformation().GetOwnerCharId() == nChar->GetID() ) // Requester is the owner\r
- {\r
- PUdpVhcUse::DoFreeSitting( nClient, tVhc, mRawItemID );\r
- }\r
- else // Requester is not the owner\r
- {\r
- if ( tVhc->GetNumSeats() == 1 ) // single seat vhc\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 17, mRawItemID ); // "Not your vhc" msg\r
- nClient->SendUDPMessage( tmpMsg );\r
- } // multi seats vhc\r
- else if ( ! tVhc->IsCharInside( tVhc->GetInformation().GetOwnerCharId() ) )\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 18, mRawItemID ); // "Owner not on board" msg\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- else if ( tVhc->GetNbFreeSeats() == 0 )\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 5, mRawItemID ); // "No free seat" msg\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- else\r
- {\r
- // Send request to owner\r
- PClient* ownerClient = ClientManager->getClientByChar( tVhc->GetInformation().GetOwnerCharId() );\r
- if ( ownerClient )\r
- {\r
- PChar* ownerChar = ownerClient->GetChar();\r
- // We could check for valid allowed access before adding a new one\r
- uint32_t newReqId = ownerChar->GetVhcAccessRequestList()->Add( nChar->GetID(), tVhc->GetInformation().GetVehicleId() );\r
- if ( newReqId )\r
- {\r
- tmpMsg = MsgBuilder->BuildVhcAccessRequestMsg( ownerClient, newReqId, nChar->GetID(), nClient->GetID(), tVhc->GetInformation().GetVehicleId() );\r
- ownerClient->SendUDPMessage( tmpMsg );\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 19, mRawItemID ); // "req transmitted" msg\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); // Undefined failure / Owner not available\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- }\r
- //////// Msg100 id\r
- //22 can't use that seat\r
- }\r
- else if (( nChar->GetLocation() == PWorlds::mNcSubwayWorldId ) && Subway->IsValidSubwayCab( mRawItemID ) && ( nChar->GetSeatInUse() == seat_none ) ) // Entering subway\r
- {\r
- vhcFound = true;\r
- if ( Subway->IsDoorOpen( mRawItemID, GameServer->GetGameTime() ) )\r
- {\r
- uint8_t freeSeat = Subway->GetFreeSeat( mRawItemID );\r
- if ( freeSeat && Subway->SetSeatUser( mRawItemID, freeSeat, nChar->GetID() ) )\r
- {\r
- nChar->SetSeatInUse( seat_subway, mRawItemID, freeSeat );\r
- tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mRawItemID, freeSeat );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- // else error: invalid vhc\r
- } // else char alreay sitting\r
- if ( vhcFound )\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- }\r
-\r
- if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // not a vhc\r
- {\r
- // Is it a PC ?\r
- PClient* tClient;\r
- if (( tClient = CurrentWorld->GetClientByCharLocalId( mRawItemID ) ) )\r
- {\r
- /*if(gDevDebug)*/\r
- Console->Print( "%s clicking on PC %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID );\r
- tmpMsg = MsgBuilder->BuildCharInteractionMenuMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- }\r
- }\r
-\r
- if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // not a vhc nor a pc\r
- {\r
- //Console->Print(">>> Searching world");\r
- // Is it a NPC ?\r
- PNPC* targetNPC = 0;\r
- PNPCWorld* currentNPCWorld = NPCManager->GetWorld( nChar->GetLocation() );\r
- if ( currentNPCWorld )\r
- {\r
- //Console->Print(">>> Searching NPC (SQL Version)");\r
- targetNPC = currentNPCWorld->GetNPC( mRawItemID );\r
- if(!targetNPC)\r
- {\r
- //Console->Print(">>> Searching NPC (DEF Version)");\r
- // Note to myself: This is UGLY!!!! and BAD!!! but it works for now. CHANGE THIS!\r
- targetNPC = currentNPCWorld->GetNPC( mRawItemID - 255 );\r
- }\r
- }\r
- if ( targetNPC )\r
- {\r
- /*if(gDevDebug)*/\r
- Console->Print( "%s Player talks to NPC %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID );\r
- //if(gDevDebug) tContainer->Dump();\r
-\r
- // Well its not "start a conversation" its more "User clicked NPC, do anything with it (Trade, script,...)\r
- targetNPC->StartConversation(nClient);\r
-\r
- //tmpMsg = MsgBuilder->BuildTraderItemListMsg( nClient, mRawItemID );\r
- //tmpMsg->Dump();\r
- //nClient->FragmentAndSendUDPMessage( tmpMsg, 0xac );\r
- }\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- }\r
- }\r
- else // furniture objects\r
- {\r
- const PFurnitureItemTemplate* tFurnitureTemplate = NULL;\r
- const PDefWorldModel* tFurnitureModel = NULL;\r
- if ( tHandleDynamicActor == false )\r
- {\r
- // We have an STATIC ACTOR, which means we DONT KNOW the FUNCTION VALUE from pak_worldmodel.def yet\r
- // (the setentry one). So we need to get it over the .dat file:\r
-\r
- // Dat files have smaller IDs\r
- ItemID = mRawItemID / 1024 - 1;\r
-\r
- // Now grab the template from .dat file\r
- tFurnitureTemplate = CurrentWorld->GetFurnitureItemTemplate( ItemID );\r
-\r
- // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc\r
- tFurnitureModel = CurrentWorld->GetFurnitureItemModel( ItemID );\r
- }\r
- else\r
- {\r
- // We have an DYNAMIC ACTOR, which means we DO KNOW the FUNCTION VALUE (stored in SQL).\r
-\r
- // First, assign the RawID to the "real" itemID, which is used for several objects to identify them clientside\r
- ItemID = mRawItemID;\r
-\r
- // Now get the get the function value:\r
- int tFunctionVal = WorldActors->GetWorldActorFunctionID( mRawItemID );\r
-\r
- // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc\r
- tFurnitureModel = GameDefs->WorldModels()->GetDef( tFunctionVal );\r
-\r
- if ( gDevDebug )\r
- Console->Print( "%s Processing dynmic actor %d with Functionvalue %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, tFunctionVal );\r
- }\r
-\r
- if ( tFurnitureModel ) // valid active furniture (else invalid or passive furniture)\r
- {\r
- if ( nClient->GetDebugMode( DBG_ITEMID ) )\r
- {\r
- snprintf( DbgMessage, 128, "Item : %s", tFurnitureModel->GetName().c_str() );\r
- Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
- }\r
-\r
- if ( tFurnitureModel->GetUseFlags() & ufChair )\r
- {\r
- uint32_t cSeatObjectId;\r
- PSeatType cSeatType = nChar->GetSeatInUse( &cSeatObjectId );\r
- if (( cSeatType == seat_none ) || ( cSeatType == seat_chair ) )\r
- {\r
- if ( CurrentWorld->CharUseChair( nClient->GetLocalID(), ItemID ) )\r
- {\r
- if ( gDevDebug )\r
- Console->Print( "%s Localchar %d was previously using chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nClient->GetLocalID(), cSeatObjectId );\r
- if (( cSeatType ) && ( cSeatObjectId != ItemID ) )\r
- {\r
- CurrentWorld->CharLeaveChair( nClient->GetLocalID(), cSeatObjectId );\r
- }\r
- nChar->SetSeatInUse( seat_chair, ItemID );\r
- if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )\r
- {\r
- tFurnitureTemplate->GetFrontPos( &( nChar->Coords.mX ), &( nChar->Coords.mY ), &( nChar->Coords.mZ ) );\r
- //(nChar->Coords).mLR = tFurnitureTemplate->GetFrontLR();\r
- }\r
- else\r
- {\r
- WorldActors->GetFrontPos( mRawItemID, &( nChar->Coords.mX ), &( nChar->Coords.mY ), &( nChar->Coords.mZ ) );\r
- //(nChar->Coords).mLR = WorldActors->GetFrontLR();\r
- }\r
-\r
- tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mRawItemID );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mRawItemID ); // "Already in use" msg\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- }\r
- else\r
- {\r
- if ( gDevDebug )\r
- Console->Print( "%s Item function type: %d value: %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tFurnitureModel->GetFunctionType(), tFurnitureModel->GetFunctionValue() );\r
-\r
- DbgMessage[0] = 0;\r
- switch ( tFurnitureModel->GetFunctionType() )\r
- {\r
- case 6: //Respawn Station (GenRep)\r
- {\r
- uint32_t nLocation = nChar->GetLocation();\r
- uint16_t nEntity;\r
- if ( Worlds->IsPotentialAppartement( nLocation ) )\r
- {\r
- nLocation = 0xffffffff; // (uint32_t)-1;\r
- nEntity = 0xffff; //(uint16_t)-1;\r
- }\r
- else\r
- {\r
- //nEntity = MySQL->GetWorldItemOption(mRawItemID/256, nLocation, 1);\r
- // This is a kind of nearly-not-hardcoded-hack ...\r
- int nEntityInt = 0;\r
- if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )\r
- {\r
- nEntityInt = GameDefs->Respawns()->GetRespawnEntity( nChar->GetLocation(), tFurnitureTemplate->GetLinkedObjectID() );\r
- }\r
- else\r
- {\r
- nEntityInt = GameDefs->Respawns()->GetRespawnEntity( nChar->GetLocation(), WorldActors->GetLinkedObjectID( mRawItemID ) );\r
- }\r
-\r
- nEntity = ( nEntityInt < 0 ? 0xffff : ( uint16_t )nEntityInt );\r
- }\r
-\r
- tmpMsg = MsgBuilder->BuildCharUseGenrepMsg( nClient, mRawItemID, nLocation, nEntity );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
-\r
- case 7: //GoGuardian\r
- {\r
- tmpMsg = MsgBuilder->BuildCharUseGogoMsg( nClient );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
-\r
- case 9: //Appartement Eingang\r
- {\r
- tmpMsg = MsgBuilder->BuildCharUseLiftMsg( nClient, mRawItemID, tFurnitureModel->GetFunctionValue() );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
-\r
- case 10: //Appartement Ein/Ausgang\r
- {\r
- tmpMsg = MsgBuilder->BuildCharUseLiftMsg( nClient, mRawItemID, 0 );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
-\r
- case 15: //HOLOMATCH EXIT\r
- {\r
- // temp hack + wrong entity... guess it works same as function 20\r
- uint32_t HoloNum = nChar->GetLocation() - 90000; // value 1 to 16, to transalte to 540..547 550..557 for worldmodel.def\r
-\r
- const PDefWorldModel* tHoloExitModel = GameDefs->WorldModels()->GetDef( 539 + HoloNum + ( HoloNum > 8 ? 2 : 0 ) );\r
- if ( tHoloExitModel && ( tHoloExitModel->GetFunctionType() == 14 ) ) // we use the Holomatch entry. Takes care of bad zone id\r
- {\r
- const PDefAppPlace* nAppPlace = GameDefs->AppPlaces()->GetDef( tHoloExitModel->GetFunctionValue() );\r
- if ( nAppPlace )\r
- {\r
- uint32_t Location = nAppPlace->GetExitWorldID();\r
- uint16_t Entity = nAppPlace->GetExitWorldEntity();\r
- uint8_t SewerLevel = 0;\r
-\r
- tmpMsg = MsgBuilder->BuildChangeLocationMsg( nClient, Location, Entity, SewerLevel, 0 ); //mRawItemID\r
- nClient->SendUDPMessage( tmpMsg );\r
- if ( gDevDebug )\r
- Console->Print( "%s Holoexit: Client[%d] Char[%s] moving to zone %d (%s)", Console->ColorText( GREEN, BLACK, "[Debug]" ), nClient->GetID(), nChar->GetName().c_str(), Location, nAppPlace->GetName().c_str() );\r
- if ( gDevDebug )\r
- Console->Print( "%s Location=%d Entity=%d Level=%d", Console->ColorText( CYAN, BLACK, "[Debug]" ), Location, Entity, SewerLevel );\r
- }\r
- else\r
- {\r
- Console->Print( "%s Client[%d] Char[%s] invalid destination %d (appplaces.def)", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() );\r
- }\r
- }\r
- else\r
- {\r
- Console->Print( "%s Client[%d] Char[%s] invalid holoentry used %d", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() );\r
- }\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
- case 18: // "WORLDCHANGEACTOR"\r
- case 20: // "DATFILE WORLDCHANGE ACTOR"\r
- case 29: //Underground Exit\r
- {\r
- const PDefAppPlace* nAppPlace;\r
- if ( tFurnitureModel->GetFunctionType() == 29 )\r
- {\r
- nAppPlace = GameDefs->AppPlaces()->GetDef( nChar->GetLocation() ); // special for UG exit\r
- }\r
- else\r
- {\r
- nAppPlace = GameDefs->AppPlaces()->GetDef( tFurnitureModel->GetFunctionValue() );\r
- }\r
- if ( nAppPlace )\r
- {\r
- uint32_t Location = nAppPlace->GetExitWorldID();\r
- uint16_t Entity = nAppPlace->GetExitWorldEntity();\r
- uint8_t SewerLevel = 0;\r
- //if(((tFurnitureModel->GetFunctionType() == 20) && nAppPlace->GetSewerLevel()) || (tFurnitureModel->GetFunctionType() == 29))\r
- if (( tFurnitureModel->GetFunctionType() == 20 ) || ( tFurnitureModel->GetFunctionType() == 29 ) )\r
- {\r
- SewerLevel = 1;\r
- }\r
-\r
- tmpMsg = MsgBuilder->BuildChangeLocationMsg( nClient, Location, Entity, SewerLevel, mRawItemID ); //mRawItemID\r
- nClient->SendUDPMessage( tmpMsg );\r
- if ( gDevDebug )\r
- {\r
- Console->Print( "%s Dungeon in/out: Client[%d] Char[%s] moving to zone %d, %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), nClient->GetID(), nChar->GetName().c_str(), Location, nAppPlace->GetName().c_str() );\r
- Console->Print( "%s Location=%d Entity=%d Level=%d", Console->ColorText( CYAN, BLACK, "[Debug]" ), Location, Entity, SewerLevel );\r
- Console->Print( "%s Function: %d, Value: %d - Sewer level in appplaces.def for this point: %d", Console->ColorText( CYAN, BLACK, "[Debug]" ), tFurnitureModel->GetFunctionType(), tFurnitureModel->GetFunctionValue(), nAppPlace->GetSewerLevel() );\r
- Console->Print( "%s Worldmodel id: %d", Console->ColorText( CYAN, BLACK, "[Debug]" ), tFurnitureModel->GetID() );\r
- }\r
- }\r
- else\r
- {\r
- Console->Print( "%s Client[%d] Char[%s] invalid destination %d (appplaces.def)", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() );\r
- // send a "refused" msg ?\r
- }\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- //nextAnalyser = new PUdpCharJump(mDecodeData);\r
- break;\r
- }\r
-\r
- case 2: //Terminal\r
- case 3: //Outfitter\r
- case 16: //HOLOMATCH REFRESH\r
- case 17: //HOLOMATCH HEAL & Recreation units\r
- case 26: //Outpost Switch\r
- {\r
- tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
-\r
- case 31: //Venture Warp Station\r
- {\r
- tmpMsg = MsgBuilder->BuildCharUseVentureWarpMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
-\r
- case 28: //Fahrzeug Depot Interface\r
- {\r
- tmpMsg = MsgBuilder->BuildCharUseVhcTerminalMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
-\r
- case 11: //Appartement Klingel/�ffner\r
- {\r
- if ( Appartements->CanFreelyEnter( nChar, nChar->GetLocation() ) )\r
- {\r
- if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )\r
- {\r
- if ( tFurnitureTemplate->GetLinkedObjectID() )\r
- {\r
- tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- else\r
- {\r
- if ( WorldActors->GetLinkedObjectID( mRawItemID ) )\r
- {\r
- tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + WorldActors->GetLinkedObjectID( mRawItemID ), CurrentWorld->GetDoor( WorldActors->GetLinkedObjectID( mRawItemID ) )->IsDoubleDoor() );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildFurnitureActivateMsg( nClient, mRawItemID, 5 ); // Ring\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
-\r
- case 12: //Standard Button\r
- {\r
- if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )\r
- {\r
- if ( tFurnitureTemplate->GetLinkedObjectID() )\r
- {\r
- tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- else\r
- {\r
- if ( WorldActors->GetLinkedObjectID( mRawItemID ) )\r
- {\r
- tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + WorldActors->GetLinkedObjectID( mRawItemID ), CurrentWorld->GetDoor( WorldActors->GetLinkedObjectID( mRawItemID ) )->IsDoubleDoor() );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
- case 13: //Hack Button\r
- {\r
- if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )\r
- {\r
- if ( tFurnitureTemplate->GetLinkedObjectID() )\r
- {\r
- if ( nClient->GetAccountLevel() >= PAL_GM ) // Allow GameMasters and higher to just bypass HackButtons\r
- {\r
- tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 106 ); // Damn, locked!\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
-\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- else\r
- {\r
- uint32_t linkobjID = WorldActors->GetLinkedObjectID( mRawItemID );\r
- if ( linkobjID )\r
- {\r
- if ( nClient->GetAccountLevel() >= PAL_GM ) // Allow GameMasters and higher to just bypass HackButtons\r
- {\r
- tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + linkobjID, CurrentWorld->GetDoor( linkobjID )->IsDoubleDoor() );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 106 ); // Damn, locked!\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
-\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
-\r
- case 23: //EINTRITTSGELD BUTTON\r
- {\r
- if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )\r
- {\r
- if ( tFurnitureTemplate->GetLinkedObjectID() )\r
- {\r
- uint32_t OldCash = nChar->GetCash();\r
- uint32_t DoorFee = ( uint32_t )tFurnitureModel->GetFunctionValue();\r
- if ( OldCash >= DoorFee )\r
- {\r
- uint32_t NewCash = nChar->SetCash( OldCash - DoorFee );\r
- PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg( nClient, NewCash );\r
- nClient->SendUDPMessage( tmpMsg_cash );\r
- tmpMsg_cash = NULL;\r
- tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 12 ); // You dont have enough money!\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- else\r
- {\r
- uint32_t linkobjID = WorldActors->GetLinkedObjectID( mRawItemID );\r
- if ( linkobjID )\r
- {\r
- uint32_t OldCash = nChar->GetCash();\r
- uint32_t DoorFee = ( uint32_t )tFurnitureModel->GetFunctionValue();\r
- if ( OldCash >= DoorFee )\r
- {\r
- uint32_t NewCash = nChar->SetCash( OldCash - DoorFee );\r
- PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg( nClient, NewCash );\r
- nClient->SendUDPMessage( tmpMsg_cash );\r
- tmpMsg_cash = NULL;\r
- tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + linkobjID, CurrentWorld->GetDoor( linkobjID )->IsDoubleDoor() );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 12 ); // You dont have enough money!\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
- case 1: //Itemcontainer\r
- {\r
- // TODO: Add check if container is already open / Make containers persistent\r
- // PContainer* tContainer = World->GetContainer(mRawItemID);\r
- PContainer* tContainer = new PContainerAutoCompactOnClose( INV_CABINET_MAXSLOTS );\r
- int functionVal = tFurnitureModel->GetFunctionValue();\r
- if ( functionVal <= 5 ) // force full random for cabinets for item testing\r
- functionVal = -1;\r
- tContainer->RandomFill( INV_CABINET_MAXSLOTS, functionVal );\r
-\r
- /*nItem = new PItem(19, 1, 250, 250, 250, 250, 250, 250);\r
- if(nItem->GetItemID());\r
- tContainer->AddItem(nItem);*/\r
- if ( gDevDebug ) Console->Print( "%s Temporary container created", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- //if(gDevDebug) tContainer->Dump();\r
- if ( tContainer->StartUse( nChar->GetID() ) )\r
- {\r
- nChar->SetContainerInExclusiveUse( tContainer );\r
- tmpMsg = MsgBuilder->BuildCharOpenContainerMsg( nClient, mRawItemID, tContainer );\r
- //tmpMsg->Dump();\r
- nClient->FragmentAndSendUDPMessage( tmpMsg, 0x05 );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildFurnitureActivateMsg( nClient, mRawItemID, 10 );\r
- nClient->SendUDPMessage( tmpMsg );\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
- case 32: // Text message\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, ( uint8_t )( 255 & tFurnitureModel->GetFunctionValue() ), mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
- // Temp placeholder implementations ============================\r
- case 4: //Trader\r
- {\r
- snprintf( DbgMessage, 128, "That's a trader" );\r
- Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
- tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
- case 5: //Mineral\r
- {\r
- snprintf( DbgMessage, 128, "That's some minerals" );\r
- Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
- tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
- case 8: //Hackterminal\r
- {\r
- snprintf( DbgMessage, 128, "That's a hacking terminal" );\r
- Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
- tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
- case 14: //HOLOMATCH ENTRANCE\r
- {\r
- snprintf( DbgMessage, 128, "That's an holomatch entrance" );\r
- Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
- tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
- case 19: //CLANTERMINAL\r
- {\r
- snprintf( DbgMessage, 128, "That's a clan terminal" );\r
- Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
- tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
- case 25: //EXPLOSIVE\r
- {\r
- snprintf( DbgMessage, 128, "That's explosive !" );\r
- Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
- tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
- case 0: //May be roadsign if touchable\r
- {\r
- if ( ( tFurnitureModel->GetUseFlags() & ufTouchable ) ) // Touchable ?\r
- {\r
- snprintf( DbgMessage, 128, "You're at %s", tFurnitureModel->GetName().c_str() );\r
- Chat->send( nClient, CHAT_GM, "Information", DbgMessage );\r
- tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
- // else we continue to undefined\r
- }\r
- case 27: //Old goguardian\r
- //case 21: //LOCATION FOR 20\r
- //case 22: //\r
- case 24: //TUTORIALEXIT\r
- //case 30: //Static FX (Value=Type. 1=Fire 2=Smoke 3=Steam 4=Sparkle)\r
- {\r
- tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );\r
- nClient->SendUDPMessage( tmpMsg );\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- break;\r
- }\r
-\r
- default:\r
- break;\r
- }\r
- }\r
- }\r
- else\r
- {\r
- if ( gDevDebug )\r
- Console->Print( "%s Item not known from world template (maybe seen as PASSIVE ?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- }\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] PUdpUseObject::DoAction : No World defined for client %d (char %d)", nClient->GetID(), nChar->GetID() );\r
- mDecodeData->mState = DECODE_ACTION_FAILED | DECODE_ACTION_DONE | DECODE_FINISHED;\r
- }\r
-\r
- return true;\r
-}\r
-\r
-/**** PUdpCloseItemContainer ****/\r
-\r
-PUdpCloseItemContainer::PUdpCloseItemContainer( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x27";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpCloseItemContainer::Analyse()\r
-{\r
- mDecodeData->mName << "=Closing item container";\r
-\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpCloseItemContainer::DoAction()\r
-{\r
-// PClient* nClient = mDecodeData->mClient;\r
-// PChar* nChar = nClient->GetChar();\r
-\r
- PChar* nChar = mDecodeData->mClient->GetChar();\r
- PContainer* tContainer = nChar->GetContainerInExclusiveUse();\r
- if ( tContainer )\r
- {\r
- nChar->SetContainerInExclusiveUse( NULL );\r
- tContainer->EndUse( nChar->GetID() );\r
- if ( ! tContainer->GetOwnerId() )\r
- {\r
- delete tContainer;\r
- if ( gDevDebug ) Console->Print( "%s Temporary container deleted", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );\r
- }\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
+#include "GameServer/Decoder/Includes.hxx"
+#include "GameServer/Definitions/Includes.hxx"
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+uint32_t gVhcId = 0x3ff;
+
+/**** PUdpVhcMove ****/
+
+PUdpUseObject::PUdpUseObject( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x17";
+}
+
+PUdpMsgAnalyser* PUdpUseObject::Analyse()
+{
+ mDecodeData->mName << "=Object use";
+
+ mRawItemID = mDecodeData->mMessage->U32Data( mDecodeData->Sub0x13Start + 8 );
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpUseObject::DoAction()
+{
+ PClient* nClient = mDecodeData->mClient;
+ PChar* nChar = nClient->GetChar();
+ uint32_t ItemID;
+ char DbgMessage[128];
+ PMessage* tmpMsg;
+
+ bool tHandleDynamicActor = false;
+
+ /*PMessage* cMsg = mDecodeData->mMessage;
+ uint32_t ClientTime = cMsg->U32Data(mDecodeData->Sub0x13Start+2);
+
+ tmpMsg = MsgBuilder->BuildPingMsg(mDecodeData->mClient, ClientTime);
+ mDecodeData->mClient->SendUDPMessage(tmpMsg);*/
+
+ nChar->SetLastUsedObject( mRawItemID );
+
+ if ( nClient->IsInRemoveActorMode() == true )
+ {
+ if ( WorldActors->IsDynamicActor( mRawItemID ) == true )
+ {
+ WorldActors->DelWorldActor( nClient, mRawItemID );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+ }
+ else
+ Chat->send( nClient, CHAT_DIRECT, "System", "This is not an dynamic worldactor. To remove it please type @remove <rawID>" );
+ }
+
+ if ( gDevDebug )
+ {
+ Console->Print( "Char at y=%f (0x%04x) z=%f (0x%04x) x=%f (0x%04x)", ( float )( nChar->Coords.mY - 32000 ), nChar->Coords.mY, ( float )( nChar->Coords.mZ - 32000 ), nChar->Coords.mZ, ( float )( nChar->Coords.mX - 32000 ), nChar->Coords.mX );
+ if ( mRawItemID & 1023 )
+ Console->Print( "using item %d (0x%08x)", mRawItemID, mRawItemID );
+ else
+ Console->Print( "using item %d (0x%08x) [dat entry %d (0x%08x)]", mRawItemID, mRawItemID, mRawItemID / 1024 - 1, mRawItemID / 1024 - 1 );
+ }
+
+ if ( nClient->GetDebugMode( DBG_ITEMID ) )
+ {
+ if ( mRawItemID & 1023 )
+ snprintf( DbgMessage, 128, "using item [raw: %d (0x%08x)]", mRawItemID, mRawItemID );
+ else
+ snprintf( DbgMessage, 128, "using item %d (0x%08x) [raw: %d (0x%08x)]", mRawItemID / 1024 - 1, mRawItemID / 1024 - 1, mRawItemID, mRawItemID );
+ Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );
+ }
+
+ PWorld* CurrentWorld = Worlds->GetWorld( nChar->GetLocation() );
+ if ( CurrentWorld )
+ {
+ if ( WorldActors->IsDynamicActor( mRawItemID ) == true )
+ {
+ tHandleDynamicActor = true;
+ if ( gDevDebug )
+ Console->Print( "%s Dynamic actor found, processing...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ }
+
+ if ( mRawItemID & 1023 && tHandleDynamicActor == false ) // non-furniture objects
+ {
+ if ( mRawItemID > 0x80 ) // maybe door
+ {
+ if ( nClient->GetDebugMode( DBG_ITEMID ) )
+ {
+ snprintf( DbgMessage, 128, "Door : %d", mRawItemID - 0x80 );
+ Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );
+ }
+ const PDoorTemplate* tDoor = CurrentWorld->GetDoor( mRawItemID - 0x80 );
+ if ( tDoor )
+ {
+ if ( tDoor->IsTriggeredDoor() )
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ else
+ {
+ if ( gDevDebug )
+ Console->Print( "%s Opening %s door %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), ( tDoor->IsDoubleDoor() ? "double" : "simple" ), mRawItemID - 0x80 );
+ tmpMsg = MsgBuilder->BuildDoorOpenMsg( mRawItemID, tDoor->IsDoubleDoor() );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ }
+ }
+ if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // else might be PC, NPC, VHC
+ {
+ if ( gDevDebug )
+ Console->Print( "%s Clicking on char, npc or vhc %d (%x) - time = %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, mRawItemID, GameServer->GetGameTime() );
+
+ if ( PSpawnedVehicles::IsPotentialSpawnedVehicle( mRawItemID ) )
+ {
+ bool vhcFound = false;
+
+ if ( nChar->GetSeatInUse() == seat_none ) // Refuse if Char is already sitting somewhere
+ {
+ PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mRawItemID );
+ if ( tVhc )
+ {
+ if ( gDevDebug )
+ Console->Print( "%s Using vhc %d (0x%04x)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, mRawItemID );
+ vhcFound = true;
+
+ if ( tVhc->GetInformation().GetOwnerCharId() == nChar->GetID() ) // Requester is the owner
+ {
+ PUdpVhcUse::DoFreeSitting( nClient, tVhc, mRawItemID );
+ }
+ else // Requester is not the owner
+ {
+ if ( tVhc->GetNumSeats() == 1 ) // single seat vhc
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 17, mRawItemID ); // "Not your vhc" msg
+ nClient->SendUDPMessage( tmpMsg );
+ } // multi seats vhc
+ else if ( ! tVhc->IsCharInside( tVhc->GetInformation().GetOwnerCharId() ) )
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 18, mRawItemID ); // "Owner not on board" msg
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ else if ( tVhc->GetNbFreeSeats() == 0 )
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 5, mRawItemID ); // "No free seat" msg
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ else
+ {
+ // Send request to owner
+ PClient* ownerClient = ClientManager->getClientByChar( tVhc->GetInformation().GetOwnerCharId() );
+ if ( ownerClient )
+ {
+ PChar* ownerChar = ownerClient->GetChar();
+ // We could check for valid allowed access before adding a new one
+ uint32_t newReqId = ownerChar->GetVhcAccessRequestList()->Add( nChar->GetID(), tVhc->GetInformation().GetVehicleId() );
+ if ( newReqId )
+ {
+ tmpMsg = MsgBuilder->BuildVhcAccessRequestMsg( ownerClient, newReqId, nChar->GetID(), nClient->GetID(), tVhc->GetInformation().GetVehicleId() );
+ ownerClient->SendUDPMessage( tmpMsg );
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 19, mRawItemID ); // "req transmitted" msg
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); // Undefined failure / Owner not available
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ }
+ //////// Msg100 id
+ //22 can't use that seat
+ }
+ else if (( nChar->GetLocation() == PWorlds::mNcSubwayWorldId ) && Subway->IsValidSubwayCab( mRawItemID ) && ( nChar->GetSeatInUse() == seat_none ) ) // Entering subway
+ {
+ vhcFound = true;
+ if ( Subway->IsDoorOpen( mRawItemID, GameServer->GetGameTime() ) )
+ {
+ uint8_t freeSeat = Subway->GetFreeSeat( mRawItemID );
+ if ( freeSeat && Subway->SetSeatUser( mRawItemID, freeSeat, nChar->GetID() ) )
+ {
+ nChar->SetSeatInUse( seat_subway, mRawItemID, freeSeat );
+ tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mRawItemID, freeSeat );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ // else error: invalid vhc
+ } // else char alreay sitting
+ if ( vhcFound )
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ }
+
+ if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // not a vhc
+ {
+ // Is it a PC ?
+ PClient* tClient;
+ if (( tClient = CurrentWorld->GetClientByCharLocalId( mRawItemID ) ) )
+ {
+ /*if(gDevDebug)*/
+ Console->Print( "%s clicking on PC %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID );
+ tmpMsg = MsgBuilder->BuildCharInteractionMenuMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ }
+ }
+
+ if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // not a vhc nor a pc
+ {
+ //Console->Print(">>> Searching world");
+ // Is it a NPC ?
+ PNPC* targetNPC = 0;
+ PNPCWorld* currentNPCWorld = NPCManager->GetWorld( nChar->GetLocation() );
+ if ( currentNPCWorld )
+ {
+ //Console->Print(">>> Searching NPC (SQL Version)");
+ targetNPC = currentNPCWorld->GetNPC( mRawItemID );
+ if(!targetNPC)
+ {
+ //Console->Print(">>> Searching NPC (DEF Version)");
+ // Note to myself: This is UGLY!!!! and BAD!!! but it works for now. CHANGE THIS!
+ targetNPC = currentNPCWorld->GetNPC( mRawItemID - 255 );
+ }
+ }
+ if ( targetNPC )
+ {
+ /*if(gDevDebug)*/
+ Console->Print( "%s Player talks to NPC %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID );
+ //if(gDevDebug) tContainer->Dump();
+
+ // Well its not "start a conversation" its more "User clicked NPC, do anything with it (Trade, script,...)
+ targetNPC->StartConversation(nClient);
+
+ //tmpMsg = MsgBuilder->BuildTraderItemListMsg( nClient, mRawItemID );
+ //tmpMsg->Dump();
+ //nClient->FragmentAndSendUDPMessage( tmpMsg, 0xac );
+ }
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ }
+ }
+ else // furniture objects
+ {
+ const PFurnitureItemTemplate* tFurnitureTemplate = NULL;
+ const PDefWorldModel* tFurnitureModel = NULL;
+ if ( tHandleDynamicActor == false )
+ {
+ // We have an STATIC ACTOR, which means we DONT KNOW the FUNCTION VALUE from pak_worldmodel.def yet
+ // (the setentry one). So we need to get it over the .dat file:
+
+ // Dat files have smaller IDs
+ ItemID = mRawItemID / 1024 - 1;
+
+ // Now grab the template from .dat file
+ tFurnitureTemplate = CurrentWorld->GetFurnitureItemTemplate( ItemID );
+
+ // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc
+ tFurnitureModel = CurrentWorld->GetFurnitureItemModel( ItemID );
+ }
+ else
+ {
+ // We have an DYNAMIC ACTOR, which means we DO KNOW the FUNCTION VALUE (stored in SQL).
+
+ // First, assign the RawID to the "real" itemID, which is used for several objects to identify them clientside
+ ItemID = mRawItemID;
+
+ // Now get the get the function value:
+ int tFunctionVal = WorldActors->GetWorldActorFunctionID( mRawItemID );
+
+ // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc
+ tFurnitureModel = GameDefs->WorldModels()->GetDef( tFunctionVal );
+
+ if ( gDevDebug )
+ Console->Print( "%s Processing dynmic actor %d with Functionvalue %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, tFunctionVal );
+ }
+
+ if ( tFurnitureModel ) // valid active furniture (else invalid or passive furniture)
+ {
+ if ( nClient->GetDebugMode( DBG_ITEMID ) )
+ {
+ snprintf( DbgMessage, 128, "Item : %s", tFurnitureModel->GetName().c_str() );
+ Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );
+ }
+
+ if ( tFurnitureModel->GetUseFlags() & ufChair )
+ {
+ uint32_t cSeatObjectId;
+ PSeatType cSeatType = nChar->GetSeatInUse( &cSeatObjectId );
+ if (( cSeatType == seat_none ) || ( cSeatType == seat_chair ) )
+ {
+ if ( CurrentWorld->CharUseChair( nClient->GetLocalID(), ItemID ) )
+ {
+ if ( gDevDebug )
+ Console->Print( "%s Localchar %d was previously using chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nClient->GetLocalID(), cSeatObjectId );
+ if (( cSeatType ) && ( cSeatObjectId != ItemID ) )
+ {
+ CurrentWorld->CharLeaveChair( nClient->GetLocalID(), cSeatObjectId );
+ }
+ nChar->SetSeatInUse( seat_chair, ItemID );
+ if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )
+ {
+ tFurnitureTemplate->GetFrontPos( &( nChar->Coords.mX ), &( nChar->Coords.mY ), &( nChar->Coords.mZ ) );
+ //(nChar->Coords).mLR = tFurnitureTemplate->GetFrontLR();
+ }
+ else
+ {
+ WorldActors->GetFrontPos( mRawItemID, &( nChar->Coords.mX ), &( nChar->Coords.mY ), &( nChar->Coords.mZ ) );
+ //(nChar->Coords).mLR = WorldActors->GetFrontLR();
+ }
+
+ tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mRawItemID );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mRawItemID ); // "Already in use" msg
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ }
+ else
+ {
+ if ( gDevDebug )
+ Console->Print( "%s Item function type: %d value: %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tFurnitureModel->GetFunctionType(), tFurnitureModel->GetFunctionValue() );
+
+ DbgMessage[0] = 0;
+ switch ( tFurnitureModel->GetFunctionType() )
+ {
+ case 6: //Respawn Station (GenRep)
+ {
+ uint32_t nLocation = nChar->GetLocation();
+ uint16_t nEntity;
+ if ( Worlds->IsPotentialAppartement( nLocation ) )
+ {
+ nLocation = 0xffffffff; // (uint32_t)-1;
+ nEntity = 0xffff; //(uint16_t)-1;
+ }
+ else
+ {
+ //nEntity = MySQL->GetWorldItemOption(mRawItemID/256, nLocation, 1);
+ // This is a kind of nearly-not-hardcoded-hack ...
+ int nEntityInt = 0;
+ if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )
+ {
+ nEntityInt = GameDefs->Respawns()->GetRespawnEntity( nChar->GetLocation(), tFurnitureTemplate->GetLinkedObjectID() );
+ }
+ else
+ {
+ nEntityInt = GameDefs->Respawns()->GetRespawnEntity( nChar->GetLocation(), WorldActors->GetLinkedObjectID( mRawItemID ) );
+ }
+
+ nEntity = ( nEntityInt < 0 ? 0xffff : ( uint16_t )nEntityInt );
+ }
+
+ tmpMsg = MsgBuilder->BuildCharUseGenrepMsg( nClient, mRawItemID, nLocation, nEntity );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+
+ case 7: //GoGuardian
+ {
+ tmpMsg = MsgBuilder->BuildCharUseGogoMsg( nClient );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+
+ case 9: //Appartement Eingang
+ {
+ tmpMsg = MsgBuilder->BuildCharUseLiftMsg( nClient, mRawItemID, tFurnitureModel->GetFunctionValue() );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+
+ case 10: //Appartement Ein/Ausgang
+ {
+ tmpMsg = MsgBuilder->BuildCharUseLiftMsg( nClient, mRawItemID, 0 );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+
+ case 15: //HOLOMATCH EXIT
+ {
+ // temp hack + wrong entity... guess it works same as function 20
+ uint32_t HoloNum = nChar->GetLocation() - 90000; // value 1 to 16, to transalte to 540..547 550..557 for worldmodel.def
+
+ const PDefWorldModel* tHoloExitModel = GameDefs->WorldModels()->GetDef( 539 + HoloNum + ( HoloNum > 8 ? 2 : 0 ) );
+ if ( tHoloExitModel && ( tHoloExitModel->GetFunctionType() == 14 ) ) // we use the Holomatch entry. Takes care of bad zone id
+ {
+ const PDefAppPlace* nAppPlace = GameDefs->AppPlaces()->GetDef( tHoloExitModel->GetFunctionValue() );
+ if ( nAppPlace )
+ {
+ uint32_t Location = nAppPlace->GetExitWorldID();
+ uint16_t Entity = nAppPlace->GetExitWorldEntity();
+ uint8_t SewerLevel = 0;
+
+ tmpMsg = MsgBuilder->BuildChangeLocationMsg( nClient, Location, Entity, SewerLevel, 0 ); //mRawItemID
+ nClient->SendUDPMessage( tmpMsg );
+ if ( gDevDebug )
+ Console->Print( "%s Holoexit: Client[%d] Char[%s] moving to zone %d (%s)", Console->ColorText( GREEN, BLACK, "[Debug]" ), nClient->GetID(), nChar->GetName().c_str(), Location, nAppPlace->GetName().c_str() );
+ if ( gDevDebug )
+ Console->Print( "%s Location=%d Entity=%d Level=%d", Console->ColorText( CYAN, BLACK, "[Debug]" ), Location, Entity, SewerLevel );
+ }
+ else
+ {
+ Console->Print( "%s Client[%d] Char[%s] invalid destination %d (appplaces.def)", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() );
+ }
+ }
+ else
+ {
+ Console->Print( "%s Client[%d] Char[%s] invalid holoentry used %d", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() );
+ }
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+ case 18: // "WORLDCHANGEACTOR"
+ case 20: // "DATFILE WORLDCHANGE ACTOR"
+ case 29: //Underground Exit
+ {
+ const PDefAppPlace* nAppPlace;
+ if ( tFurnitureModel->GetFunctionType() == 29 )
+ {
+ nAppPlace = GameDefs->AppPlaces()->GetDef( nChar->GetLocation() ); // special for UG exit
+ }
+ else
+ {
+ nAppPlace = GameDefs->AppPlaces()->GetDef( tFurnitureModel->GetFunctionValue() );
+ }
+ if ( nAppPlace )
+ {
+ uint32_t Location = nAppPlace->GetExitWorldID();
+ uint16_t Entity = nAppPlace->GetExitWorldEntity();
+ uint8_t SewerLevel = 0;
+ //if(((tFurnitureModel->GetFunctionType() == 20) && nAppPlace->GetSewerLevel()) || (tFurnitureModel->GetFunctionType() == 29))
+ if (( tFurnitureModel->GetFunctionType() == 20 ) || ( tFurnitureModel->GetFunctionType() == 29 ) )
+ {
+ SewerLevel = 1;
+ }
+
+ tmpMsg = MsgBuilder->BuildChangeLocationMsg( nClient, Location, Entity, SewerLevel, mRawItemID ); //mRawItemID
+ nClient->SendUDPMessage( tmpMsg );
+ if ( gDevDebug )
+ {
+ Console->Print( "%s Dungeon in/out: Client[%d] Char[%s] moving to zone %d, %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), nClient->GetID(), nChar->GetName().c_str(), Location, nAppPlace->GetName().c_str() );
+ Console->Print( "%s Location=%d Entity=%d Level=%d", Console->ColorText( CYAN, BLACK, "[Debug]" ), Location, Entity, SewerLevel );
+ Console->Print( "%s Function: %d, Value: %d - Sewer level in appplaces.def for this point: %d", Console->ColorText( CYAN, BLACK, "[Debug]" ), tFurnitureModel->GetFunctionType(), tFurnitureModel->GetFunctionValue(), nAppPlace->GetSewerLevel() );
+ Console->Print( "%s Worldmodel id: %d", Console->ColorText( CYAN, BLACK, "[Debug]" ), tFurnitureModel->GetID() );
+ }
+ }
+ else
+ {
+ Console->Print( "%s Client[%d] Char[%s] invalid destination %d (appplaces.def)", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() );
+ // send a "refused" msg ?
+ }
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ //nextAnalyser = new PUdpCharJump(mDecodeData);
+ break;
+ }
+
+ case 2: //Terminal
+ case 3: //Outfitter
+ case 16: //HOLOMATCH REFRESH
+ case 17: //HOLOMATCH HEAL & Recreation units
+ case 26: //Outpost Switch
+ {
+ tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+
+ case 31: //Venture Warp Station
+ {
+ tmpMsg = MsgBuilder->BuildCharUseVentureWarpMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+
+ case 28: //Fahrzeug Depot Interface
+ {
+ tmpMsg = MsgBuilder->BuildCharUseVhcTerminalMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+
+ case 11: //Appartement Klingel/�ffner
+ {
+ if ( Appartements->CanFreelyEnter( nChar, nChar->GetLocation() ) )
+ {
+ if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )
+ {
+ if ( tFurnitureTemplate->GetLinkedObjectID() )
+ {
+ tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ else
+ {
+ if ( WorldActors->GetLinkedObjectID( mRawItemID ) )
+ {
+ tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + WorldActors->GetLinkedObjectID( mRawItemID ), CurrentWorld->GetDoor( WorldActors->GetLinkedObjectID( mRawItemID ) )->IsDoubleDoor() );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildFurnitureActivateMsg( nClient, mRawItemID, 5 ); // Ring
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+
+ case 12: //Standard Button
+ {
+ if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )
+ {
+ if ( tFurnitureTemplate->GetLinkedObjectID() )
+ {
+ tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ else
+ {
+ if ( WorldActors->GetLinkedObjectID( mRawItemID ) )
+ {
+ tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + WorldActors->GetLinkedObjectID( mRawItemID ), CurrentWorld->GetDoor( WorldActors->GetLinkedObjectID( mRawItemID ) )->IsDoubleDoor() );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+ case 13: //Hack Button
+ {
+ if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )
+ {
+ if ( tFurnitureTemplate->GetLinkedObjectID() )
+ {
+ if ( nClient->GetAccountLevel() >= PAL_GM ) // Allow GameMasters and higher to just bypass HackButtons
+ {
+ tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 106 ); // Damn, locked!
+ nClient->SendUDPMessage( tmpMsg );
+ }
+
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ else
+ {
+ uint32_t linkobjID = WorldActors->GetLinkedObjectID( mRawItemID );
+ if ( linkobjID )
+ {
+ if ( nClient->GetAccountLevel() >= PAL_GM ) // Allow GameMasters and higher to just bypass HackButtons
+ {
+ tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + linkobjID, CurrentWorld->GetDoor( linkobjID )->IsDoubleDoor() );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 106 ); // Damn, locked!
+ nClient->SendUDPMessage( tmpMsg );
+ }
+
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+
+ case 23: //EINTRITTSGELD BUTTON
+ {
+ if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL )
+ {
+ if ( tFurnitureTemplate->GetLinkedObjectID() )
+ {
+ uint32_t OldCash = nChar->GetCash();
+ uint32_t DoorFee = ( uint32_t )tFurnitureModel->GetFunctionValue();
+ if ( OldCash >= DoorFee )
+ {
+ uint32_t NewCash = nChar->SetCash( OldCash - DoorFee );
+ PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg( nClient, NewCash );
+ nClient->SendUDPMessage( tmpMsg_cash );
+ tmpMsg_cash = NULL;
+ tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 12 ); // You dont have enough money!
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ else
+ {
+ uint32_t linkobjID = WorldActors->GetLinkedObjectID( mRawItemID );
+ if ( linkobjID )
+ {
+ uint32_t OldCash = nChar->GetCash();
+ uint32_t DoorFee = ( uint32_t )tFurnitureModel->GetFunctionValue();
+ if ( OldCash >= DoorFee )
+ {
+ uint32_t NewCash = nChar->SetCash( OldCash - DoorFee );
+ PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg( nClient, NewCash );
+ nClient->SendUDPMessage( tmpMsg_cash );
+ tmpMsg_cash = NULL;
+ tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + linkobjID, CurrentWorld->GetDoor( linkobjID )->IsDoubleDoor() );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 12 ); // You dont have enough money!
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+ case 1: //Itemcontainer
+ {
+ // TODO: Add check if container is already open / Make containers persistent
+ // PContainer* tContainer = World->GetContainer(mRawItemID);
+ PContainer* tContainer = new PContainerAutoCompactOnClose( INV_CABINET_MAXSLOTS );
+ int functionVal = tFurnitureModel->GetFunctionValue();
+ if ( functionVal <= 5 ) // force full random for cabinets for item testing
+ functionVal = -1;
+ tContainer->RandomFill( INV_CABINET_MAXSLOTS, functionVal );
+
+ /*nItem = new PItem(19, 1, 250, 250, 250, 250, 250, 250);
+ if(nItem->GetItemID());
+ tContainer->AddItem(nItem);*/
+ if ( gDevDebug ) Console->Print( "%s Temporary container created", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ //if(gDevDebug) tContainer->Dump();
+ if ( tContainer->StartUse( nChar->GetID() ) )
+ {
+ nChar->SetContainerInExclusiveUse( tContainer );
+ tmpMsg = MsgBuilder->BuildCharOpenContainerMsg( nClient, mRawItemID, tContainer );
+ //tmpMsg->Dump();
+ nClient->FragmentAndSendUDPMessage( tmpMsg, 0x05 );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildFurnitureActivateMsg( nClient, mRawItemID, 10 );
+ nClient->SendUDPMessage( tmpMsg );
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+ case 32: // Text message
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, ( uint8_t )( 255 & tFurnitureModel->GetFunctionValue() ), mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+ // Temp placeholder implementations ============================
+ case 4: //Trader
+ {
+ snprintf( DbgMessage, 128, "That's a trader" );
+ Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );
+ tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+ case 5: //Mineral
+ {
+ snprintf( DbgMessage, 128, "That's some minerals" );
+ Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );
+ tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+ case 8: //Hackterminal
+ {
+ snprintf( DbgMessage, 128, "That's a hacking terminal" );
+ Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );
+ tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+ case 14: //HOLOMATCH ENTRANCE
+ {
+ snprintf( DbgMessage, 128, "That's an holomatch entrance" );
+ Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );
+ tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+ case 19: //CLANTERMINAL
+ {
+ snprintf( DbgMessage, 128, "That's a clan terminal" );
+ Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );
+ tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+ case 25: //EXPLOSIVE
+ {
+ snprintf( DbgMessage, 128, "That's explosive !" );
+ Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );
+ tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+ case 0: //May be roadsign if touchable
+ {
+ if ( ( tFurnitureModel->GetUseFlags() & ufTouchable ) ) // Touchable ?
+ {
+ snprintf( DbgMessage, 128, "You're at %s", tFurnitureModel->GetName().c_str() );
+ Chat->send( nClient, CHAT_GM, "Information", DbgMessage );
+ tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+ // else we continue to undefined
+ }
+ case 27: //Old goguardian
+ //case 21: //LOCATION FOR 20
+ //case 22: //
+ case 24: //TUTORIALEXIT
+ //case 30: //Static FX (Value=Type. 1=Fire 2=Smoke 3=Steam 4=Sparkle)
+ {
+ tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID );
+ nClient->SendUDPMessage( tmpMsg );
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ if ( gDevDebug )
+ Console->Print( "%s Item not known from world template (maybe seen as PASSIVE ?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ }
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[ERROR] PUdpUseObject::DoAction : No World defined for client %d (char %d)", nClient->GetID(), nChar->GetID() );
+ mDecodeData->mState = DECODE_ACTION_FAILED | DECODE_ACTION_DONE | DECODE_FINISHED;
+ }
+
+ return true;
+}
+
+/**** PUdpCloseItemContainer ****/
+
+PUdpCloseItemContainer::PUdpCloseItemContainer( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x27";
+}
+
+PUdpMsgAnalyser* PUdpCloseItemContainer::Analyse()
+{
+ mDecodeData->mName << "=Closing item container";
+
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpCloseItemContainer::DoAction()
+{
+// PClient* nClient = mDecodeData->mClient;
+// PChar* nChar = nClient->GetChar();
+
+ PChar* nChar = mDecodeData->mClient->GetChar();
+ PContainer* tContainer = nChar->GetContainerInExclusiveUse();
+ if ( tContainer )
+ {
+ nChar->SetContainerInExclusiveUse( NULL );
+ tContainer->EndUse( nChar->GetID() );
+ if ( ! tContainer->GetOwnerId() )
+ {
+ delete tContainer;
+ if ( gDevDebug ) Console->Print( "%s Temporary container deleted", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) );
+ }
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpUseObject : public PUdpMsgAnalyser {\r
-private:\r
- uint32_t mRawItemID;\r
-\r
- void OldHandler(); // Temp during migration only\r
-\r
-public:\r
- PUdpUseObject(PMsgDecodeData *nDecodeData);\r
- //~PUdpUseObject();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpCloseItemContainer : public PUdpMsgAnalyser {\r
-public:\r
- PUdpCloseItemContainer(PMsgDecodeData *nDecodeData);\r
- //~PUdpCloseItemContainer();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpUseObject : public PUdpMsgAnalyser {
+private:
+ uint32_t mRawItemID;
+
+ void OldHandler(); // Temp during migration only
+
+public:
+ PUdpUseObject(PMsgDecodeData *nDecodeData);
+ //~PUdpUseObject();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpCloseItemContainer : public PUdpMsgAnalyser {
+public:
+ PUdpCloseItemContainer(PMsgDecodeData *nDecodeData);
+ //~PUdpCloseItemContainer();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-/**** PUdpVhcMove ****/\r
-\r
-PUdpVhcMove::PUdpVhcMove( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x32";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpVhcMove::Analyse()\r
-{\r
- mDecodeData->mName << "=Vhc move";\r
-\r
- PMessage* nMsg = mDecodeData->mMessage;\r
- nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 );\r
-\r
- *nMsg >> mVhcLocalId;\r
- *nMsg >> mMoveType; // 0 for subway/chair, 3 for vhc, 7 in nc2.2\r
- *nMsg >> mNewY;\r
- *nMsg >> mNewZ;\r
- *nMsg >> mNewX;\r
- *nMsg >> mNewUD; // neutral :=0x7f, > := upward, < := downward\r
- *nMsg >> mNewLR;\r
- *nMsg >> mNewRoll; // neutral := 0x7fff > := bank left, < := bank right\r
- *nMsg >> mUnk1;\r
- *nMsg >> mFF;\r
- *nMsg >> mAction;\r
-//0 = not moving\r
-//&01 = Left\r
-//&02 = Right\r
-//&04 = Forward\r
-//&08 = Back\r
-//&10 = Shoot button\r
-//&20 = Pushing down\r
-//&40 = Pulling up\r
-//\r
- /*\r
- --- rolling front+left\r
- 13 b0 00 02 bf\r
- 15\r
- 32\r
- c9 03 =short VhcId\r
- 07\r
- c3 66 37 8b 47 6e 80 2a 88 70 27 22\r
- 81\r
- 01 00\r
- ff = speed% ?\r
- 05 = forward+left ?\r
- => srv resp\r
- 13 6b 01 bd bf\r
- 18\r
- 03 6a 01 32 c9 03 07 8b 66 37 8b d9 6d 80 e0 8f\r
- ea 27 22 81 01 00 ff 05\r
- 0c\r
- 03 6b 01 1f 01 00 30 5e 79 36 87 87\r
- 13\r
- 32 c9 03 03 8b 66 38 8b d9 6d 7f 2a 88 92 7f 01 00 00 05\r
- 0b\r
- 20 ed 03 5d 5a c8 8d 9b 7b c2 00\r
-\r
- --- stopped\r
- 13 88 01 da bf\r
- 13\r
- 32\r
- c9 03 =short VhcId\r
- 03\r
- 05\r
- 66 36 8b 90 6d 7f 5b 9d 00\r
- 80\r
- 01 00\r
- 00 = speed% ?\r
- 00 = no move\r
-\r
- */\r
- if ( gDevDebug )\r
- {\r
- Console->Print( YELLOW, BLACK, "[DEBUG] VHC move type %d - objid %d", mMoveType, mVhcLocalId );\r
- //nMsg->Dump();\r
- Console->Print( "X=%d Y=%d Z=%d Act=%d", mNewX - 768, mNewY - 768, mNewZ - 768, mAction );\r
- Console->Print( "LR=%d UD=%d Ro=%d Unk=%d Act=%02x ff=%x", mNewLR, mNewUD, mNewRoll, mUnk1, mAction, mFF );\r
- Console->Print( "Msg len: %d", nMsg->U8Data( mDecodeData->Sub0x13Start ) );\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpVhcMove::DoAction()\r
-{\r
- PClient* nClient = mDecodeData->mClient;\r
- //PCharCoordinates* nCoords = &(nClient->GetChar()->Coords);\r
- PWorld* CurrentWorld = Worlds->GetWorld( nClient->GetChar()->GetLocation() );\r
-\r
- if ( CurrentWorld )\r
- {\r
- PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mVhcLocalId );\r
- if ( tVhc )\r
- {\r
- //Todo: calc & mem Speed & Accel vectors\r
- PVhcCoordinates nPos;\r
- nPos.SetPosition( mNewY - 768, mNewZ - 768, mNewX - 768, mNewUD, mNewLR, mNewRoll, mAction, mUnk1, mFF );\r
- tVhc->SetPosition( &nPos );\r
- PMessage* tmpMsg = MsgBuilder->BuildVhcPosUpdate2Msg( tVhc );\r
- ClientManager->UDPBroadcast( tmpMsg, mDecodeData->mClient );\r
-\r
- tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( tVhc );\r
- ClientManager->UDPBroadcast( tmpMsg, mDecodeData->mClient );\r
-\r
- if( CurrentWorld->CheckVhcNeedZoning( &nPos ) )\r
- {\r
- uint32_t destWorldId;\r
- PVhcCoordinates destPos;\r
-\r
- if (( destWorldId = CurrentWorld->GetVhcZoningDestination( tVhc, &destPos ) ) )\r
- {\r
- if ( nClient->GetDebugMode( DBG_LOCATION ) )\r
- {\r
- uint8_t pH = 0;\r
- uint8_t pV = 0;\r
- Worlds->GetWorldmapFromWorldId( destWorldId, pH, pV );\r
- char DbgMessage[128];\r
- snprintf( DbgMessage, 128, "Vhc zoning to zone %c%02d (id %d)", ( 'a' + pV ), pH, destWorldId );\r
- Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );\r
- }\r
-\r
- DoVhcZoning( tVhc, nClient->GetChar()->GetLocation(), destWorldId, &destPos );\r
- }\r
- }\r
- }\r
- else\r
- Console->Print( RED, BLACK, "[Error] PUdpVhcMove: Inexistant vhc Id %d", mVhcLocalId );\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
-\r
-// Failures are not managed yet\r
-bool PUdpVhcMove::DoVhcZoning( PSpawnedVehicle* currVhc, uint32_t currWorldId, uint32_t destWorldId, PVhcCoordinates* destPos )\r
-{\r
- uint32_t seatedCharsId[8];\r
- uint32_t vhcGlobalId = currVhc->GetVehicleId();\r
- uint32_t vhcLocalId = currVhc->GetLocalId();\r
- PVhcCoordinates currCoords = currVhc->GetPosition();\r
- uint8_t numSeats = currVhc->GetNumSeats();\r
- uint32_t sittingCharId;\r
- PClient* sittingClient;\r
- PClient* sittingClients[8];\r
- PMessage* tmpMsg;\r
-\r
- for ( uint8_t i = 0; i < numSeats; ++i )\r
- {\r
- // Save seated chars list\r
- seatedCharsId[i] = sittingCharId = currVhc->GetSeatUser( i );\r
-\r
- if ( sittingCharId )\r
- {\r
- sittingClients[i] = sittingClient = ClientManager->getClientByChar( sittingCharId );\r
- // Tag each client as zoning to avoid transient side effects\r
- sittingClient->SetZoning();\r
- sittingClient->SetVhcZoning();\r
- // Trigger zoning\r
- //tmpMsg = MsgBuilder->BuildGenrepZoningMsg( sittingClient, destWorldId, 0 ); // unknown value // 0x62bc or 0x2d4e\r
- //sittingClient->SendUDPMessage( tmpMsg );\r
- // We send the unseat msg to the corresponding client only.\r
- sittingClient->GetChar()->Coords.SetPosition( currCoords.GetY(), currCoords.GetZ(), currCoords.GetX() );\r
- tmpMsg = MsgBuilder->BuildCharExitSeatMsg( sittingClient );\r
- sittingClient->FillInUDP_ID( tmpMsg );\r
- sittingClient->SendUDPMessage( tmpMsg );\r
- }\r
- else\r
- sittingClients[i] = 0;\r
- }\r
-\r
- // Unspawn vhc instance from local world\r
- Vehicles->UnspawnVehicle( vhcGlobalId );\r
- tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg( vhcLocalId );\r
- ClientManager->UDPBroadcast( tmpMsg, currWorldId );\r
-\r
- // Spawn vhc instance in destWorld\r
- PSpawnedVehicle* destVhc = Vehicles->SpawnVehicle( vhcGlobalId, destWorldId, destPos );\r
- if ( destVhc )\r
- {\r
- tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( destVhc );\r
- ClientManager->UDPBroadcast( tmpMsg, destWorldId );\r
-\r
- vhcLocalId = destVhc->GetLocalId();\r
-\r
- // Update chars seat in use and restore vhc used seats\r
- PChar* sittingChar;\r
- for ( uint8_t i = 0; i < numSeats; ++i )\r
- {\r
- if (( sittingClient = sittingClients[i] ) )\r
- {\r
- //if ( gDevDebug )\r
- Console->Print( "%s PUdpVhcMove::DoVhcZoning : Char %d sitting on vhc %d, seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), seatedCharsId[i], vhcLocalId, i );\r
- sittingChar = sittingClient->GetChar();\r
- sittingChar->SetSeatInUse( seat_vhc, vhcLocalId, i );\r
- sittingChar->Coords.SetPosition( destPos->GetY(), destPos->GetZ(), destPos->GetX() );\r
- destVhc->SetSeatUser( i, seatedCharsId[i] );\r
- }\r
- }\r
- }\r
- else\r
- {\r
- for ( uint8_t i = 0; i < numSeats; ++i )\r
- {\r
- if ( sittingClients[i] )\r
- {\r
- sittingClients[i]->GetChar()->SetSeatInUse( seat_none );\r
- }\r
- }\r
-\r
- return false;\r
- }\r
-\r
- return true;\r
-\r
-}\r
-\r
-/**** PUdpVhcUse ****/\r
-\r
-PUdpVhcUse::PUdpVhcUse( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x0f";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpVhcUse::Analyse()\r
-{\r
- mDecodeData->mName << "=Try enter vhc";\r
-\r
- PMessage* nMsg = mDecodeData->mMessage;\r
- nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 12 );\r
- *nMsg >> mVehicleID; // uint32_t\r
- *nMsg >> mVehicleSeat;\r
-\r
- if ( gDevDebug )\r
- Console->Print( "%s Localid %d trying to enter vhc %d on seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetLocalID(), mVehicleID, mVehicleSeat );\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpVhcUse::DoAction()\r
-{\r
- PClient* nClient = mDecodeData->mClient;\r
- PChar* nChar = nClient->GetChar();\r
- PMessage* tmpMsg;\r
-\r
- if ( nChar->GetSeatInUse() == seat_none ) // Refuse if Char is already sitting somewhere\r
- {\r
- PWorld* CurrentWorld = Worlds->GetWorld( nChar->GetLocation() );\r
- if ( CurrentWorld )\r
- {\r
- PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mVehicleID );\r
- if ( tVhc )\r
- {\r
- if ( tVhc->SetSeatUser( mVehicleSeat, nChar->GetID() ) ) // Char was able to sit\r
- {\r
- nChar->SetSeatInUse( seat_vhc, mVehicleID, mVehicleSeat );\r
- tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mVehicleID, mVehicleSeat );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mVehicleID ); // Already in use\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- }\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
-\r
-void PUdpVhcUse::DoFreeSitting( PClient* nClient, PSpawnedVehicle* nVhc, uint32_t nRawVhcLocalId, uint8_t nSeatId )\r
-{\r
- PMessage* tmpMsg;\r
-\r
- if (( nVhc->GetNbFreeSeats() > 1 ) && ( nSeatId > nVhc->GetNumSeats() ) )\r
- {\r
- uint8_t freeSeats = nVhc->GetFreeSeatsFlags();\r
- tmpMsg = MsgBuilder->BuildCharUseVhcMsg( nClient, nRawVhcLocalId, nVhc->GetInformation().GetVehicleType(), freeSeats );\r
- nClient->SendUDPMessage( tmpMsg ); // Open seat selection window\r
- }\r
- else\r
- {\r
- if ( nSeatId <= nVhc->GetNumSeats() )\r
- {\r
- if ( nVhc->GetSeatUser( nSeatId ) )\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, nRawVhcLocalId ); // Already in use\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- else\r
- {\r
- nSeatId = nVhc->GetFirstFreeSeat();\r
-\r
- if ( nSeatId != 255 )\r
- {\r
- if ( nVhc->SetSeatUser( nSeatId, nClient->GetChar()->GetID() ) ) // Char was able to sit\r
- {\r
- nClient->GetChar()->SetSeatInUse( seat_vhc, nRawVhcLocalId, nSeatId );\r
- tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, nRawVhcLocalId, nSeatId );\r
- ClientManager->UDPBroadcast( tmpMsg, nClient );\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, nRawVhcLocalId ); // Undefined failure\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- else\r
- {\r
- tmpMsg = MsgBuilder->BuildText100Msg( nClient, 5, nRawVhcLocalId ); // "No free seat" msg\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- }\r
- }\r
-}\r
-\r
-/**** PUdpSubwayUpdate ****/\r
-\r
-PUdpSubwayUpdate::PUdpSubwayUpdate( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x00";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpSubwayUpdate::Analyse()\r
-{\r
- uint8_t Dumb;\r
-\r
- mDecodeData->mName << "=Subway update";\r
-\r
- PMessage* nMsg = mDecodeData->mMessage;\r
- nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 );\r
-\r
- *nMsg >> mVehicleID;\r
- *nMsg >> Dumb;\r
- *nMsg >> mPosition;\r
- *nMsg >> mDoorOpened;\r
-\r
- if ( gDevDebug )\r
- Console->Print( "%s Subway update 0x%4x : pos 0x%4x, status 0x%2x", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID, mPosition, mDoorOpened );\r
-\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpSubwayUpdate::DoAction()\r
-{\r
- /* No real use for that ?\r
- Subway->UpdateInfo(mVehicleID, mPosition, mDoorOpened);\r
-\r
- PMessage* tmpMsg = MsgBuilder->BuildSubwaySingleUpdateMsg(mVehicleID, mPosition, mDoorOpened);\r
- ClientManager->UDPBroadcast(tmpMsg, mDecodeData->mClient);\r
- */\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
-\r
-/**** PUdpRequestVhcInfo ****/\r
-\r
-PUdpRequestVhcInfo::PUdpRequestVhcInfo( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )\r
-{\r
- nDecodeData->mName << "/0x27";\r
-}\r
-\r
-PUdpMsgAnalyser* PUdpRequestVhcInfo::Analyse()\r
-{\r
- mDecodeData->mName << "=Request seatable object info";\r
-\r
- PMessage* nMsg = mDecodeData->mMessage;\r
- nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 );\r
-\r
- *nMsg >> mVehicleID;\r
-\r
- if ( gDevDebug )\r
- Console->Print( "%s Request Seatable Info for 0x%04x :", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID );\r
-\r
- mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;\r
- return this;\r
-}\r
-\r
-bool PUdpRequestVhcInfo::DoAction()\r
-{\r
- PClient* nClient = mDecodeData->mClient;\r
- //PCharCoordinates* nCoords = &(nClient->GetChar()->Coords);\r
- PWorld* CurrentWorld = Worlds->GetWorld( nClient->GetChar()->GetLocation() );\r
-\r
- if ( CurrentWorld )\r
- {\r
- PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mVehicleID );\r
- if ( tVhc )\r
- {\r
- if ( gDevDebug )\r
- Console->Print("%s Sending Info for vhcId 0x%04x : type %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID, tVhc->GetInformation().GetVehicleType() );\r
- PMessage* tmpMsg = MsgBuilder->BuildVhcInfoMsg( nClient, tVhc );\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
- else\r
- Console->Print( RED, BLACK, "[Error] PUdpRequestVhcInfo: Inexistant vhc Id %d", mVehicleID );\r
- }\r
-\r
- mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;\r
- return true;\r
-}\r
+#include "GameServer/Decoder/Includes.hxx"
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+/**** PUdpVhcMove ****/
+
+PUdpVhcMove::PUdpVhcMove( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x32";
+}
+
+PUdpMsgAnalyser* PUdpVhcMove::Analyse()
+{
+ mDecodeData->mName << "=Vhc move";
+
+ PMessage* nMsg = mDecodeData->mMessage;
+ nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 );
+
+ *nMsg >> mVhcLocalId;
+ *nMsg >> mMoveType; // 0 for subway/chair, 3 for vhc, 7 in nc2.2
+ *nMsg >> mNewY;
+ *nMsg >> mNewZ;
+ *nMsg >> mNewX;
+ *nMsg >> mNewUD; // neutral :=0x7f, > := upward, < := downward
+ *nMsg >> mNewLR;
+ *nMsg >> mNewRoll; // neutral := 0x7fff > := bank left, < := bank right
+ *nMsg >> mUnk1;
+ *nMsg >> mFF;
+ *nMsg >> mAction;
+//0 = not moving
+//&01 = Left
+//&02 = Right
+//&04 = Forward
+//&08 = Back
+//&10 = Shoot button
+//&20 = Pushing down
+//&40 = Pulling up
+//
+ /*
+ --- rolling front+left
+ 13 b0 00 02 bf
+ 15
+ 32
+ c9 03 =short VhcId
+ 07
+ c3 66 37 8b 47 6e 80 2a 88 70 27 22
+ 81
+ 01 00
+ ff = speed% ?
+ 05 = forward+left ?
+ => srv resp
+ 13 6b 01 bd bf
+ 18
+ 03 6a 01 32 c9 03 07 8b 66 37 8b d9 6d 80 e0 8f
+ ea 27 22 81 01 00 ff 05
+ 0c
+ 03 6b 01 1f 01 00 30 5e 79 36 87 87
+ 13
+ 32 c9 03 03 8b 66 38 8b d9 6d 7f 2a 88 92 7f 01 00 00 05
+ 0b
+ 20 ed 03 5d 5a c8 8d 9b 7b c2 00
+
+ --- stopped
+ 13 88 01 da bf
+ 13
+ 32
+ c9 03 =short VhcId
+ 03
+ 05
+ 66 36 8b 90 6d 7f 5b 9d 00
+ 80
+ 01 00
+ 00 = speed% ?
+ 00 = no move
+
+ */
+ if ( gDevDebug )
+ {
+ Console->Print( YELLOW, BLACK, "[DEBUG] VHC move type %d - objid %d", mMoveType, mVhcLocalId );
+ //nMsg->Dump();
+ Console->Print( "X=%d Y=%d Z=%d Act=%d", mNewX - 768, mNewY - 768, mNewZ - 768, mAction );
+ Console->Print( "LR=%d UD=%d Ro=%d Unk=%d Act=%02x ff=%x", mNewLR, mNewUD, mNewRoll, mUnk1, mAction, mFF );
+ Console->Print( "Msg len: %d", nMsg->U8Data( mDecodeData->Sub0x13Start ) );
+ }
+
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpVhcMove::DoAction()
+{
+ PClient* nClient = mDecodeData->mClient;
+ //PCharCoordinates* nCoords = &(nClient->GetChar()->Coords);
+ PWorld* CurrentWorld = Worlds->GetWorld( nClient->GetChar()->GetLocation() );
+
+ if ( CurrentWorld )
+ {
+ PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mVhcLocalId );
+ if ( tVhc )
+ {
+ //Todo: calc & mem Speed & Accel vectors
+ PVhcCoordinates nPos;
+ nPos.SetPosition( mNewY - 768, mNewZ - 768, mNewX - 768, mNewUD, mNewLR, mNewRoll, mAction, mUnk1, mFF );
+ tVhc->SetPosition( &nPos );
+ PMessage* tmpMsg = MsgBuilder->BuildVhcPosUpdate2Msg( tVhc );
+ ClientManager->UDPBroadcast( tmpMsg, mDecodeData->mClient );
+
+ tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( tVhc );
+ ClientManager->UDPBroadcast( tmpMsg, mDecodeData->mClient );
+
+ if( CurrentWorld->CheckVhcNeedZoning( &nPos ) )
+ {
+ uint32_t destWorldId;
+ PVhcCoordinates destPos;
+
+ if (( destWorldId = CurrentWorld->GetVhcZoningDestination( tVhc, &destPos ) ) )
+ {
+ if ( nClient->GetDebugMode( DBG_LOCATION ) )
+ {
+ uint8_t pH = 0;
+ uint8_t pV = 0;
+ Worlds->GetWorldmapFromWorldId( destWorldId, pH, pV );
+ char DbgMessage[128];
+ snprintf( DbgMessage, 128, "Vhc zoning to zone %c%02d (id %d)", ( 'a' + pV ), pH, destWorldId );
+ Chat->send( nClient, CHAT_GM, "Debug", DbgMessage );
+ }
+
+ DoVhcZoning( tVhc, nClient->GetChar()->GetLocation(), destWorldId, &destPos );
+ }
+ }
+ }
+ else
+ Console->Print( RED, BLACK, "[Error] PUdpVhcMove: Inexistant vhc Id %d", mVhcLocalId );
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
+
+// Failures are not managed yet
+bool PUdpVhcMove::DoVhcZoning( PSpawnedVehicle* currVhc, uint32_t currWorldId, uint32_t destWorldId, PVhcCoordinates* destPos )
+{
+ uint32_t seatedCharsId[8];
+ uint32_t vhcGlobalId = currVhc->GetVehicleId();
+ uint32_t vhcLocalId = currVhc->GetLocalId();
+ PVhcCoordinates currCoords = currVhc->GetPosition();
+ uint8_t numSeats = currVhc->GetNumSeats();
+ uint32_t sittingCharId;
+ PClient* sittingClient;
+ PClient* sittingClients[8];
+ PMessage* tmpMsg;
+
+ for ( uint8_t i = 0; i < numSeats; ++i )
+ {
+ // Save seated chars list
+ seatedCharsId[i] = sittingCharId = currVhc->GetSeatUser( i );
+
+ if ( sittingCharId )
+ {
+ sittingClients[i] = sittingClient = ClientManager->getClientByChar( sittingCharId );
+ // Tag each client as zoning to avoid transient side effects
+ sittingClient->SetZoning();
+ sittingClient->SetVhcZoning();
+ // Trigger zoning
+ //tmpMsg = MsgBuilder->BuildGenrepZoningMsg( sittingClient, destWorldId, 0 ); // unknown value // 0x62bc or 0x2d4e
+ //sittingClient->SendUDPMessage( tmpMsg );
+ // We send the unseat msg to the corresponding client only.
+ sittingClient->GetChar()->Coords.SetPosition( currCoords.GetY(), currCoords.GetZ(), currCoords.GetX() );
+ tmpMsg = MsgBuilder->BuildCharExitSeatMsg( sittingClient );
+ sittingClient->FillInUDP_ID( tmpMsg );
+ sittingClient->SendUDPMessage( tmpMsg );
+ }
+ else
+ sittingClients[i] = 0;
+ }
+
+ // Unspawn vhc instance from local world
+ Vehicles->UnspawnVehicle( vhcGlobalId );
+ tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg( vhcLocalId );
+ ClientManager->UDPBroadcast( tmpMsg, currWorldId );
+
+ // Spawn vhc instance in destWorld
+ PSpawnedVehicle* destVhc = Vehicles->SpawnVehicle( vhcGlobalId, destWorldId, destPos );
+ if ( destVhc )
+ {
+ tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( destVhc );
+ ClientManager->UDPBroadcast( tmpMsg, destWorldId );
+
+ vhcLocalId = destVhc->GetLocalId();
+
+ // Update chars seat in use and restore vhc used seats
+ PChar* sittingChar;
+ for ( uint8_t i = 0; i < numSeats; ++i )
+ {
+ if (( sittingClient = sittingClients[i] ) )
+ {
+ //if ( gDevDebug )
+ Console->Print( "%s PUdpVhcMove::DoVhcZoning : Char %d sitting on vhc %d, seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), seatedCharsId[i], vhcLocalId, i );
+ sittingChar = sittingClient->GetChar();
+ sittingChar->SetSeatInUse( seat_vhc, vhcLocalId, i );
+ sittingChar->Coords.SetPosition( destPos->GetY(), destPos->GetZ(), destPos->GetX() );
+ destVhc->SetSeatUser( i, seatedCharsId[i] );
+ }
+ }
+ }
+ else
+ {
+ for ( uint8_t i = 0; i < numSeats; ++i )
+ {
+ if ( sittingClients[i] )
+ {
+ sittingClients[i]->GetChar()->SetSeatInUse( seat_none );
+ }
+ }
+
+ return false;
+ }
+
+ return true;
+
+}
+
+/**** PUdpVhcUse ****/
+
+PUdpVhcUse::PUdpVhcUse( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x0f";
+}
+
+PUdpMsgAnalyser* PUdpVhcUse::Analyse()
+{
+ mDecodeData->mName << "=Try enter vhc";
+
+ PMessage* nMsg = mDecodeData->mMessage;
+ nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 12 );
+ *nMsg >> mVehicleID; // uint32_t
+ *nMsg >> mVehicleSeat;
+
+ if ( gDevDebug )
+ Console->Print( "%s Localid %d trying to enter vhc %d on seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetLocalID(), mVehicleID, mVehicleSeat );
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpVhcUse::DoAction()
+{
+ PClient* nClient = mDecodeData->mClient;
+ PChar* nChar = nClient->GetChar();
+ PMessage* tmpMsg;
+
+ if ( nChar->GetSeatInUse() == seat_none ) // Refuse if Char is already sitting somewhere
+ {
+ PWorld* CurrentWorld = Worlds->GetWorld( nChar->GetLocation() );
+ if ( CurrentWorld )
+ {
+ PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mVehicleID );
+ if ( tVhc )
+ {
+ if ( tVhc->SetSeatUser( mVehicleSeat, nChar->GetID() ) ) // Char was able to sit
+ {
+ nChar->SetSeatInUse( seat_vhc, mVehicleID, mVehicleSeat );
+ tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mVehicleID, mVehicleSeat );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mVehicleID ); // Already in use
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ }
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
+
+void PUdpVhcUse::DoFreeSitting( PClient* nClient, PSpawnedVehicle* nVhc, uint32_t nRawVhcLocalId, uint8_t nSeatId )
+{
+ PMessage* tmpMsg;
+
+ if (( nVhc->GetNbFreeSeats() > 1 ) && ( nSeatId > nVhc->GetNumSeats() ) )
+ {
+ uint8_t freeSeats = nVhc->GetFreeSeatsFlags();
+ tmpMsg = MsgBuilder->BuildCharUseVhcMsg( nClient, nRawVhcLocalId, nVhc->GetInformation().GetVehicleType(), freeSeats );
+ nClient->SendUDPMessage( tmpMsg ); // Open seat selection window
+ }
+ else
+ {
+ if ( nSeatId <= nVhc->GetNumSeats() )
+ {
+ if ( nVhc->GetSeatUser( nSeatId ) )
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, nRawVhcLocalId ); // Already in use
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ else
+ {
+ nSeatId = nVhc->GetFirstFreeSeat();
+
+ if ( nSeatId != 255 )
+ {
+ if ( nVhc->SetSeatUser( nSeatId, nClient->GetChar()->GetID() ) ) // Char was able to sit
+ {
+ nClient->GetChar()->SetSeatInUse( seat_vhc, nRawVhcLocalId, nSeatId );
+ tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, nRawVhcLocalId, nSeatId );
+ ClientManager->UDPBroadcast( tmpMsg, nClient );
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, nRawVhcLocalId ); // Undefined failure
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ else
+ {
+ tmpMsg = MsgBuilder->BuildText100Msg( nClient, 5, nRawVhcLocalId ); // "No free seat" msg
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ }
+ }
+}
+
+/**** PUdpSubwayUpdate ****/
+
+PUdpSubwayUpdate::PUdpSubwayUpdate( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x00";
+}
+
+PUdpMsgAnalyser* PUdpSubwayUpdate::Analyse()
+{
+ uint8_t Dumb;
+
+ mDecodeData->mName << "=Subway update";
+
+ PMessage* nMsg = mDecodeData->mMessage;
+ nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 );
+
+ *nMsg >> mVehicleID;
+ *nMsg >> Dumb;
+ *nMsg >> mPosition;
+ *nMsg >> mDoorOpened;
+
+ if ( gDevDebug )
+ Console->Print( "%s Subway update 0x%4x : pos 0x%4x, status 0x%2x", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID, mPosition, mDoorOpened );
+
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpSubwayUpdate::DoAction()
+{
+ /* No real use for that ?
+ Subway->UpdateInfo(mVehicleID, mPosition, mDoorOpened);
+
+ PMessage* tmpMsg = MsgBuilder->BuildSubwaySingleUpdateMsg(mVehicleID, mPosition, mDoorOpened);
+ ClientManager->UDPBroadcast(tmpMsg, mDecodeData->mClient);
+ */
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
+
+/**** PUdpRequestVhcInfo ****/
+
+PUdpRequestVhcInfo::PUdpRequestVhcInfo( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData )
+{
+ nDecodeData->mName << "/0x27";
+}
+
+PUdpMsgAnalyser* PUdpRequestVhcInfo::Analyse()
+{
+ mDecodeData->mName << "=Request seatable object info";
+
+ PMessage* nMsg = mDecodeData->mMessage;
+ nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 );
+
+ *nMsg >> mVehicleID;
+
+ if ( gDevDebug )
+ Console->Print( "%s Request Seatable Info for 0x%04x :", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID );
+
+ mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED;
+ return this;
+}
+
+bool PUdpRequestVhcInfo::DoAction()
+{
+ PClient* nClient = mDecodeData->mClient;
+ //PCharCoordinates* nCoords = &(nClient->GetChar()->Coords);
+ PWorld* CurrentWorld = Worlds->GetWorld( nClient->GetChar()->GetLocation() );
+
+ if ( CurrentWorld )
+ {
+ PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mVehicleID );
+ if ( tVhc )
+ {
+ if ( gDevDebug )
+ Console->Print("%s Sending Info for vhcId 0x%04x : type %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID, tVhc->GetInformation().GetVehicleType() );
+ PMessage* tmpMsg = MsgBuilder->BuildVhcInfoMsg( nClient, tVhc );
+ nClient->SendUDPMessage( tmpMsg );
+ }
+ else
+ Console->Print( RED, BLACK, "[Error] PUdpRequestVhcInfo: Inexistant vhc Id %d", mVehicleID );
+ }
+
+ mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED;
+ return true;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PSpawnedVehicle;\r
-class PVhcCoordinates;\r
-\r
-class PUdpVhcMove : public PUdpMsgAnalyser {\r
-private:\r
- uint16_t mVhcLocalId;\r
- uint16_t mNewY;\r
- uint16_t mNewZ;\r
- uint16_t mNewX;\r
- uint16_t mNewLR;\r
- uint16_t mNewRoll;\r
- uint16_t mUnk1; // always 0x0001 ?\r
- uint8_t mMoveType;\r
- uint8_t mNewUD;\r
- uint8_t mFF; // always 0xff ?\r
- uint8_t mAction; // &1 = Left, &2 = Right, &4 = Forward, &8 = Backward\r
-\r
-public:\r
- PUdpVhcMove(PMsgDecodeData *nDecodeData);\r
- //~PUdpVhcMove();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
- bool DoVhcZoning(PSpawnedVehicle *currVhc, uint32_t currWorldId, uint32_t destWorldId, PVhcCoordinates *destPos);\r
-};\r
-\r
-class PUdpVhcUse : public PUdpMsgAnalyser {\r
-private:\r
- uint32_t mVehicleID;\r
- uint8_t mVehicleSeat;\r
-\r
-public:\r
- PUdpVhcUse(PMsgDecodeData *nDecodeData);\r
- //~PUdpVhcUse();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
- static void DoFreeSitting(PClient *nClient, PSpawnedVehicle *nVhc, uint32_t nRawVhcLocalId, uint8_t nSeatId = 254);\r
-};\r
-\r
-class PUdpSubwayUpdate : public PUdpMsgAnalyser {\r
-private:\r
- uint32_t mVehicleID;\r
- uint16_t mPosition;\r
- uint8_t mDoorOpened;\r
-\r
-public:\r
- PUdpSubwayUpdate(PMsgDecodeData *nDecodeData);\r
- //~PUdpSubwayUpdate();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpRequestVhcInfo : public PUdpMsgAnalyser {\r
-private:\r
- uint32_t mVehicleID;\r
-\r
-public:\r
- PUdpRequestVhcInfo(PMsgDecodeData *nDecodeData);\r
- //~PUdpRequestVhcInfo();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PSpawnedVehicle;
+class PVhcCoordinates;
+
+class PUdpVhcMove : public PUdpMsgAnalyser {
+private:
+ uint16_t mVhcLocalId;
+ uint16_t mNewY;
+ uint16_t mNewZ;
+ uint16_t mNewX;
+ uint16_t mNewLR;
+ uint16_t mNewRoll;
+ uint16_t mUnk1; // always 0x0001 ?
+ uint8_t mMoveType;
+ uint8_t mNewUD;
+ uint8_t mFF; // always 0xff ?
+ uint8_t mAction; // &1 = Left, &2 = Right, &4 = Forward, &8 = Backward
+
+public:
+ PUdpVhcMove(PMsgDecodeData *nDecodeData);
+ //~PUdpVhcMove();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+ bool DoVhcZoning(PSpawnedVehicle *currVhc, uint32_t currWorldId, uint32_t destWorldId, PVhcCoordinates *destPos);
+};
+
+class PUdpVhcUse : public PUdpMsgAnalyser {
+private:
+ uint32_t mVehicleID;
+ uint8_t mVehicleSeat;
+
+public:
+ PUdpVhcUse(PMsgDecodeData *nDecodeData);
+ //~PUdpVhcUse();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+ static void DoFreeSitting(PClient *nClient, PSpawnedVehicle *nVhc, uint32_t nRawVhcLocalId, uint8_t nSeatId = 254);
+};
+
+class PUdpSubwayUpdate : public PUdpMsgAnalyser {
+private:
+ uint32_t mVehicleID;
+ uint16_t mPosition;
+ uint8_t mDoorOpened;
+
+public:
+ PUdpSubwayUpdate(PMsgDecodeData *nDecodeData);
+ //~PUdpSubwayUpdate();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpRequestVhcInfo : public PUdpMsgAnalyser {
+private:
+ uint32_t mVehicleID;
+
+public:
+ PUdpRequestVhcInfo(PMsgDecodeData *nDecodeData);
+ //~PUdpRequestVhcInfo();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#pragma once\r
-\r
-#include <cstdint>\r
-#include "GameServer/Decoder/UdpAnalyser.hxx"\r
-\r
-class PUdpZoning1 : public PUdpMsgAnalyser {\r
-private:\r
- uint32_t mNewLocation;\r
- uint16_t mNewEntity;\r
- uint8_t mUnknown;\r
-\r
-public:\r
- PUdpZoning1(PMsgDecodeData *nDecodeData);\r
- //~PUdpZoning1();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpZoning2 : public PUdpMsgAnalyser {\r
-public:\r
- PUdpZoning2(PMsgDecodeData *nDecodeData);\r
- //~PUdpZoning2();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpGenrepZoning : public PUdpMsgAnalyser {\r
-private:\r
- uint32_t mNewLocation;\r
- uint16_t mNewEntity;\r
-\r
-public:\r
- PUdpGenrepZoning(PMsgDecodeData *nDecodeData);\r
- //~PUdpGenrepZoning();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
- static bool DoEffectiveZoning(PClient *nClient, uint32_t nNewLocation, uint16_t nNewEntity);\r
-};\r
-\r
-class PUdpAptGRZoning : public PUdpMsgAnalyser {\r
-public:\r
- PUdpAptGRZoning(PMsgDecodeData *nDecodeData);\r
- //~PUdpAptGRZoning();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
- static bool DoEffectiveZoning(PClient *nClient);\r
-};\r
-\r
-class PUdpAddGenrepToList : public PUdpMsgAnalyser {\r
-private:\r
- uint32_t mLocation;\r
- uint16_t mEntity;\r
-\r
-public:\r
- PUdpAddGenrepToList(PMsgDecodeData *nDecodeData);\r
- //~PUdpAddGenrepToList();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-class PUdpAppartmentAccess : public PUdpMsgAnalyser {\r
-private:\r
- uint16_t mAppartmentPlace;\r
- char *mPassword;\r
-\r
-public:\r
- PUdpAppartmentAccess(PMsgDecodeData *nDecodeData);\r
- //~PUdpAppartmentAccess();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
-\r
-\r
-class PUdpEndOfZoning : public PUdpMsgAnalyser {\r
-public:\r
- PUdpEndOfZoning(PMsgDecodeData *nDecodeData);\r
- //~PUdpEndOfZoning();\r
- PUdpMsgAnalyser *Analyse();\r
- bool DoAction();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include "GameServer/Decoder/UdpAnalyser.hxx"
+
+class PUdpZoning1 : public PUdpMsgAnalyser {
+private:
+ uint32_t mNewLocation;
+ uint16_t mNewEntity;
+ uint8_t mUnknown;
+
+public:
+ PUdpZoning1(PMsgDecodeData *nDecodeData);
+ //~PUdpZoning1();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpZoning2 : public PUdpMsgAnalyser {
+public:
+ PUdpZoning2(PMsgDecodeData *nDecodeData);
+ //~PUdpZoning2();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpGenrepZoning : public PUdpMsgAnalyser {
+private:
+ uint32_t mNewLocation;
+ uint16_t mNewEntity;
+
+public:
+ PUdpGenrepZoning(PMsgDecodeData *nDecodeData);
+ //~PUdpGenrepZoning();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+ static bool DoEffectiveZoning(PClient *nClient, uint32_t nNewLocation, uint16_t nNewEntity);
+};
+
+class PUdpAptGRZoning : public PUdpMsgAnalyser {
+public:
+ PUdpAptGRZoning(PMsgDecodeData *nDecodeData);
+ //~PUdpAptGRZoning();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+ static bool DoEffectiveZoning(PClient *nClient);
+};
+
+class PUdpAddGenrepToList : public PUdpMsgAnalyser {
+private:
+ uint32_t mLocation;
+ uint16_t mEntity;
+
+public:
+ PUdpAddGenrepToList(PMsgDecodeData *nDecodeData);
+ //~PUdpAddGenrepToList();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+class PUdpAppartmentAccess : public PUdpMsgAnalyser {
+private:
+ uint16_t mAppartmentPlace;
+ char *mPassword;
+
+public:
+ PUdpAppartmentAccess(PMsgDecodeData *nDecodeData);
+ //~PUdpAppartmentAccess();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
+
+
+class PUdpEndOfZoning : public PUdpMsgAnalyser {
+public:
+ PUdpEndOfZoning(PMsgDecodeData *nDecodeData);
+ //~PUdpEndOfZoning();
+ PUdpMsgAnalyser *Analyse();
+ bool DoAction();
+};
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-PDefAppPlace::PDefAppPlace()\r
-{\r
-}\r
-\r
-bool PDefAppPlace::LoadFromDef(PTokenList *Tokens)\r
-{\r
- int Idx=0;\r
- for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
- {\r
- switch(Idx)\r
- {\r
- case 0: // setentry\r
- continue;\r
-\r
- case 1: // index\r
- mIndex = atoi(i->c_str()); break;\r
-\r
- case 2: // name\r
- mName = *i; break;\r
-\r
- case 3: // Exit World\r
- mExitWorldID = atoi(i->c_str()); break;\r
-\r
- case 4: // Exit World entity\r
- mExitWorldEntity = atoi(i->c_str()); break;\r
-\r
- case 5: // Sewer level\r
- mSewerLevel = atoi(i->c_str()); break;\r
- }\r
- }\r
-\r
- return true;\r
-}\r
+#include "GameServer/Definitions/Includes.hxx"
+
+PDefAppPlace::PDefAppPlace()
+{
+}
+
+bool PDefAppPlace::LoadFromDef(PTokenList *Tokens)
+{
+ int Idx=0;
+ for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)
+ {
+ switch(Idx)
+ {
+ case 0: // setentry
+ continue;
+
+ case 1: // index
+ mIndex = atoi(i->c_str()); break;
+
+ case 2: // name
+ mName = *i; break;
+
+ case 3: // Exit World
+ mExitWorldID = atoi(i->c_str()); break;
+
+ case 4: // Exit World entity
+ mExitWorldEntity = atoi(i->c_str()); break;
+
+ case 5: // Sewer level
+ mSewerLevel = atoi(i->c_str()); break;
+ }
+ }
+
+ return true;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-#include "GameServer/Definitions/Definition.hxx"\r
-\r
-class PDefAppPlace : public PDef {\r
-private :\r
- //int32_t mIndex;\r
- std::string mName;\r
- int32_t mExitWorldID;\r
- int32_t mExitWorldEntity;\r
- int32_t mSewerLevel;\r
-\r
-public :\r
- PDefAppPlace();\r
- //~PDefAppPlace();\r
-\r
- bool LoadFromDef(PTokenList *Tokens);\r
-\r
- inline const std::string &GetName() const { return mName; }\r
- inline int32_t GetExitWorldID() const { return mExitWorldID; }\r
- inline int32_t GetExitWorldEntity() const { return mExitWorldEntity; }\r
- inline int32_t GetSewerLevel() const { return mSewerLevel; }\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include "GameServer/Definitions/Definition.hxx"
+
+class PDefAppPlace : public PDef {
+private :
+ //int32_t mIndex;
+ std::string mName;
+ int32_t mExitWorldID;
+ int32_t mExitWorldEntity;
+ int32_t mSewerLevel;
+
+public :
+ PDefAppPlace();
+ //~PDefAppPlace();
+
+ bool LoadFromDef(PTokenList *Tokens);
+
+ inline const std::string &GetName() const { return mName; }
+ inline int32_t GetExitWorldID() const { return mExitWorldID; }
+ inline int32_t GetExitWorldEntity() const { return mExitWorldEntity; }
+ inline int32_t GetSewerLevel() const { return mSewerLevel; }
+};
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-PDefAppartement::PDefAppartement()\r
-{\r
-}\r
-\r
-bool PDefAppartement::LoadFromDef(PTokenList *Tokens)\r
-{\r
- mFaction = 0;\r
- int Idx=0;\r
- for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
- {\r
- switch(Idx)\r
- {\r
- case 0: // setentry\r
- continue;\r
-\r
- case 1: // index\r
- mIndex = atoi(i->c_str()); break;\r
-\r
- case 2: // name\r
- mName = *i; break;\r
-\r
- case 3: // world name\r
- mWorldName = *i; break;\r
-\r
- case 4: // value\r
- mValue = atoi(i->c_str()); break;\r
-\r
- case 5: // number of places\r
- mPlaceCount = atoi(i->c_str()); break;\r
-\r
- case 6:\r
- case 7:\r
- case 8:\r
- case 9:\r
- case 10:\r
- case 11:\r
- case 12:\r
- case 13:\r
- mPlace[Idx-6] = atoi(i->c_str()); break;\r
-\r
- case 14: // faction if base appartement\r
- mFaction = atoi(i->c_str()); break;\r
- }\r
- }\r
-//Console->Print("%04d:%s file:%s val:%d places:%d pl1:%d pl2:%d pl8:%d faction:%d",\r
-// mIndex, mName.c_str(), mWorldName.c_str(), mValue, mPlaceCount, mPlace[0], mPlace[1], mPlace[7], mFaction);\r
- return true;\r
-}\r
+#include "GameServer/Definitions/Includes.hxx"
+
+PDefAppartement::PDefAppartement()
+{
+}
+
+bool PDefAppartement::LoadFromDef(PTokenList *Tokens)
+{
+ mFaction = 0;
+ int Idx=0;
+ for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)
+ {
+ switch(Idx)
+ {
+ case 0: // setentry
+ continue;
+
+ case 1: // index
+ mIndex = atoi(i->c_str()); break;
+
+ case 2: // name
+ mName = *i; break;
+
+ case 3: // world name
+ mWorldName = *i; break;
+
+ case 4: // value
+ mValue = atoi(i->c_str()); break;
+
+ case 5: // number of places
+ mPlaceCount = atoi(i->c_str()); break;
+
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ mPlace[Idx-6] = atoi(i->c_str()); break;
+
+ case 14: // faction if base appartement
+ mFaction = atoi(i->c_str()); break;
+ }
+ }
+//Console->Print("%04d:%s file:%s val:%d places:%d pl1:%d pl2:%d pl8:%d faction:%d",
+// mIndex, mName.c_str(), mWorldName.c_str(), mValue, mPlaceCount, mPlace[0], mPlace[1], mPlace[7], mFaction);
+ return true;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-#include "GameServer/Definitions/Definition.hxx"\r
-#include "GameServer/Definitions/Map.hxx"\r
-\r
-class PDefAppartement : public PDef {\r
-private:\r
- //int32_t mIndex;\r
- std::string mName;\r
- std::string mWorldName;\r
- int32_t mValue;\r
- int32_t mPlaceCount;\r
- int32_t mPlace[8];\r
- int32_t mFaction;\r
-\r
-public:\r
- PDefAppartement();\r
- //~PDefAppartement();\r
-\r
- bool LoadFromDef(PTokenList *Tokens);\r
-\r
- inline int32_t GetID() const { return mIndex; }\r
- inline const std::string &GetName() const { return mName; }\r
- inline const std::string &GetWorldName() const { return mWorldName; }\r
- inline int32_t GetValue() const { return mValue; }\r
- inline int32_t GetPlaceCount() const { return mPlaceCount; }\r
- inline int32_t GetPlace(int32_t nIdx) const { return ( (nIdx < mPlaceCount) ? mPlace[nIdx] : 0 ); }\r
- inline int32_t GetFaction() const { return mFaction; }\r
-};\r
-\r
-class PDefAppartementsMap : public PDefMap<PDefAppartement> {\r
-public:\r
- inline std::map<int32_t, PDefAppartement*>::const_iterator ConstIteratorBegin() const { return mDefs.begin(); }\r
- inline std::map<int32_t, PDefAppartement*>::const_iterator ConstIteratorEnd() const { return mDefs.end(); }\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include "GameServer/Definitions/Definition.hxx"
+#include "GameServer/Definitions/Map.hxx"
+
+class PDefAppartement : public PDef {
+private:
+ //int32_t mIndex;
+ std::string mName;
+ std::string mWorldName;
+ int32_t mValue;
+ int32_t mPlaceCount;
+ int32_t mPlace[8];
+ int32_t mFaction;
+
+public:
+ PDefAppartement();
+ //~PDefAppartement();
+
+ bool LoadFromDef(PTokenList *Tokens);
+
+ inline int32_t GetID() const { return mIndex; }
+ inline const std::string &GetName() const { return mName; }
+ inline const std::string &GetWorldName() const { return mWorldName; }
+ inline int32_t GetValue() const { return mValue; }
+ inline int32_t GetPlaceCount() const { return mPlaceCount; }
+ inline int32_t GetPlace(int32_t nIdx) const { return ( (nIdx < mPlaceCount) ? mPlace[nIdx] : 0 ); }
+ inline int32_t GetFaction() const { return mFaction; }
+};
+
+class PDefAppartementsMap : public PDefMap<PDefAppartement> {
+public:
+ inline std::map<int32_t, PDefAppartement*>::const_iterator ConstIteratorBegin() const { return mDefs.begin(); }
+ inline std::map<int32_t, PDefAppartement*>::const_iterator ConstIteratorEnd() const { return mDefs.end(); }
+};
-#include <cstring>\r
-#include "GameServer/Definitions/Includes.hxx"\r
-#include "GameServer/Includes.hxx"\r
-\r
-// charkinds are character templates used for player char creation\r
-\r
-PDefCharKind::PDefCharKind()\r
-{\r
- mSkillInfo = 0;\r
- memset(mInventory, 0, sizeof(mInventory));\r
-}\r
-\r
-PDefCharKind::~PDefCharKind()\r
-{\r
- delete [] mSkillInfo;\r
- for(PSkillPtsMap::const_iterator i=mSkillPts.begin(); i!=mSkillPts.end(); i++)\r
- delete i->second;\r
- for(PSubSkillPtsMap::const_iterator i=mSubSkillPts.begin(); i!=mSubSkillPts.end(); i++)\r
- delete i->second;\r
- for(PStartLevelMap::const_iterator i=mStartLevels.begin(); i!=mStartLevels.end(); i++)\r
- delete i->second;\r
-}\r
-\r
-bool PDefCharKind::LoadFromDef(PTokenList *Tokens)\r
-{\r
- int NumSkills = GameDefs->Skills()->GetNumDefs();\r
- //int NumSubSkills = GameDefs->SubSkills()->GetNumDefs();\r
-\r
- int SkillInfoStart = 4;\r
- int TrainPtsStart = SkillInfoStart+NumSkills*3;\r
- int LevelsStart = TrainPtsStart + 32*2;\r
- int MoneyStart = LevelsStart + 16*2;\r
- int InventoryStart = MoneyStart+1;\r
-\r
- mSkillInfo = new PSkillInfo[NumSkills];\r
-\r
- int Idx=0;\r
- for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
- {\r
- switch(Idx)\r
- {\r
- case 0 : // setentry\r
- continue;\r
-\r
- case 1 :\r
- mIndex = atoi(i->c_str()); break;\r
-\r
- case 2 :\r
- mName = *i; break;\r
-\r
- case 3 :\r
- mType = atoi(i->c_str()); break;\r
-\r
- }\r
-\r
- if((Idx >= SkillInfoStart) && (Idx < TrainPtsStart)) // skill info\r
- {\r
- int SkillIdx = (Idx-SkillInfoStart)/3;\r
- int Value = atoi(i->c_str());\r
-\r
- // start, max, grow per skill\r
- switch((Idx-SkillInfoStart)%3)\r
- {\r
- case 0 : mSkillInfo[SkillIdx].mStart = Value; break;\r
- case 1 : mSkillInfo[SkillIdx].mMax = Value; break;\r
- case 2 : mSkillInfo[SkillIdx].mGrow = Value; break;\r
- }\r
- } else\r
- // 32 skill/subskill train pts\r
- if((Idx >= TrainPtsStart) && (Idx < LevelsStart))\r
- {\r
- static int SkillIndex = 0;\r
- int Index = Idx-TrainPtsStart;\r
- if((Index&1)==0)\r
- {\r
- SkillIndex = atoi(i->c_str());\r
- } else\r
- {\r
- if(SkillIndex >= 1000) // skill\r
- {\r
- const PDefSkill *Skill = GameDefs->Skills()->GetDef(SkillIndex-1000);\r
- if(Skill)\r
- {\r
- int Index = Skill->GetIndex()-1;\r
- PSkillPtsInfo *CurrentSkillPts = new PSkillPtsInfo();\r
- CurrentSkillPts->mSkill = Index;\r
- CurrentSkillPts->mPoints = atoi(i->c_str());\r
- mSkillPts.insert(std::make_pair(Index, CurrentSkillPts));\r
- } else\r
- {\r
- if(SkillIndex-1000 != 0)\r
- Console->Print("Charkind def: invalid skill index %i", SkillIndex-1000);\r
- }\r
- } else // subskill\r
- {\r
- const PDefSubSkill *SubSkill = GameDefs->SubSkills()->GetDef(SkillIndex);\r
- if(SubSkill)\r
- {\r
- int Index = SubSkill->GetIndex()-1;\r
- PSubSkillPtsInfo *CurrentSubSkillPts = new PSubSkillPtsInfo();\r
- CurrentSubSkillPts->mSubSkill = Index;\r
- CurrentSubSkillPts->mPoints = atoi(i->c_str());\r
- mSubSkillPts.insert(std::make_pair(Index, CurrentSubSkillPts));\r
- } else\r
- {\r
- if(SkillIndex != 0)\r
- Console->Print("Charkind def: invalid subskill index %i", SkillIndex);\r
- }\r
- }\r
- }\r
- } else\r
- // 16 subskill start levels\r
- if((Idx >= LevelsStart) && (Idx < MoneyStart))\r
- {\r
- static int LevelIndex = 0;\r
- int Index = Idx-NumSkills*3+4+(32*2);\r
- if((Index&1)==0)\r
- {\r
- LevelIndex = atoi(i->c_str());\r
- } else\r
- {\r
- if(LevelIndex > 0)\r
- {\r
- const PDefSubSkill *SubSkill = GameDefs->SubSkills()->GetDef(LevelIndex);\r
- if(SubSkill)\r
- {\r
- PStartLevelInfo *Level = new PStartLevelInfo();\r
- Level->mSubSkill = SubSkill->GetIndex();\r
- Level->mLevel = atoi(i->c_str());\r
- mStartLevels.insert(std::make_pair(Level->mSubSkill, Level));\r
- } else\r
- {\r
- Console->Print("Charkind def: invalid subskill index %i", LevelIndex);\r
- }\r
- }\r
- }\r
- } else\r
- // money\r
- if((Idx >= MoneyStart) && (Idx < InventoryStart))\r
- {\r
- mMoney = atoi(i->c_str());\r
- } else\r
- // inventory\r
- if((Idx >= InventoryStart) && (Idx < InventoryStart+8))\r
- {\r
- mInventory[Idx-InventoryStart] = atoi(i->c_str());\r
- }\r
- }\r
- \r
- return true;\r
-}\r
-\r
+#include <cstring>
+#include "GameServer/Definitions/Includes.hxx"
+#include "GameServer/Includes.hxx"
+
+// charkinds are character templates used for player char creation
+
+PDefCharKind::PDefCharKind()
+{
+ mSkillInfo = 0;
+ memset(mInventory, 0, sizeof(mInventory));
+}
+
+PDefCharKind::~PDefCharKind()
+{
+ delete [] mSkillInfo;
+ for(PSkillPtsMap::const_iterator i=mSkillPts.begin(); i!=mSkillPts.end(); i++)
+ delete i->second;
+ for(PSubSkillPtsMap::const_iterator i=mSubSkillPts.begin(); i!=mSubSkillPts.end(); i++)
+ delete i->second;
+ for(PStartLevelMap::const_iterator i=mStartLevels.begin(); i!=mStartLevels.end(); i++)
+ delete i->second;
+}
+
+bool PDefCharKind::LoadFromDef(PTokenList *Tokens)
+{
+ int NumSkills = GameDefs->Skills()->GetNumDefs();
+ //int NumSubSkills = GameDefs->SubSkills()->GetNumDefs();
+
+ int SkillInfoStart = 4;
+ int TrainPtsStart = SkillInfoStart+NumSkills*3;
+ int LevelsStart = TrainPtsStart + 32*2;
+ int MoneyStart = LevelsStart + 16*2;
+ int InventoryStart = MoneyStart+1;
+
+ mSkillInfo = new PSkillInfo[NumSkills];
+
+ int Idx=0;
+ for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)
+ {
+ switch(Idx)
+ {
+ case 0 : // setentry
+ continue;
+
+ case 1 :
+ mIndex = atoi(i->c_str()); break;
+
+ case 2 :
+ mName = *i; break;
+
+ case 3 :
+ mType = atoi(i->c_str()); break;
+
+ }
+
+ if((Idx >= SkillInfoStart) && (Idx < TrainPtsStart)) // skill info
+ {
+ int SkillIdx = (Idx-SkillInfoStart)/3;
+ int Value = atoi(i->c_str());
+
+ // start, max, grow per skill
+ switch((Idx-SkillInfoStart)%3)
+ {
+ case 0 : mSkillInfo[SkillIdx].mStart = Value; break;
+ case 1 : mSkillInfo[SkillIdx].mMax = Value; break;
+ case 2 : mSkillInfo[SkillIdx].mGrow = Value; break;
+ }
+ } else
+ // 32 skill/subskill train pts
+ if((Idx >= TrainPtsStart) && (Idx < LevelsStart))
+ {
+ static int SkillIndex = 0;
+ int Index = Idx-TrainPtsStart;
+ if((Index&1)==0)
+ {
+ SkillIndex = atoi(i->c_str());
+ } else
+ {
+ if(SkillIndex >= 1000) // skill
+ {
+ const PDefSkill *Skill = GameDefs->Skills()->GetDef(SkillIndex-1000);
+ if(Skill)
+ {
+ int Index = Skill->GetIndex()-1;
+ PSkillPtsInfo *CurrentSkillPts = new PSkillPtsInfo();
+ CurrentSkillPts->mSkill = Index;
+ CurrentSkillPts->mPoints = atoi(i->c_str());
+ mSkillPts.insert(std::make_pair(Index, CurrentSkillPts));
+ } else
+ {
+ if(SkillIndex-1000 != 0)
+ Console->Print("Charkind def: invalid skill index %i", SkillIndex-1000);
+ }
+ } else // subskill
+ {
+ const PDefSubSkill *SubSkill = GameDefs->SubSkills()->GetDef(SkillIndex);
+ if(SubSkill)
+ {
+ int Index = SubSkill->GetIndex()-1;
+ PSubSkillPtsInfo *CurrentSubSkillPts = new PSubSkillPtsInfo();
+ CurrentSubSkillPts->mSubSkill = Index;
+ CurrentSubSkillPts->mPoints = atoi(i->c_str());
+ mSubSkillPts.insert(std::make_pair(Index, CurrentSubSkillPts));
+ } else
+ {
+ if(SkillIndex != 0)
+ Console->Print("Charkind def: invalid subskill index %i", SkillIndex);
+ }
+ }
+ }
+ } else
+ // 16 subskill start levels
+ if((Idx >= LevelsStart) && (Idx < MoneyStart))
+ {
+ static int LevelIndex = 0;
+ int Index = Idx-NumSkills*3+4+(32*2);
+ if((Index&1)==0)
+ {
+ LevelIndex = atoi(i->c_str());
+ } else
+ {
+ if(LevelIndex > 0)
+ {
+ const PDefSubSkill *SubSkill = GameDefs->SubSkills()->GetDef(LevelIndex);
+ if(SubSkill)
+ {
+ PStartLevelInfo *Level = new PStartLevelInfo();
+ Level->mSubSkill = SubSkill->GetIndex();
+ Level->mLevel = atoi(i->c_str());
+ mStartLevels.insert(std::make_pair(Level->mSubSkill, Level));
+ } else
+ {
+ Console->Print("Charkind def: invalid subskill index %i", LevelIndex);
+ }
+ }
+ }
+ } else
+ // money
+ if((Idx >= MoneyStart) && (Idx < InventoryStart))
+ {
+ mMoney = atoi(i->c_str());
+ } else
+ // inventory
+ if((Idx >= InventoryStart) && (Idx < InventoryStart+8))
+ {
+ mInventory[Idx-InventoryStart] = atoi(i->c_str());
+ }
+ }
+
+ return true;
+}
+
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <map>\r
-#include <string>\r
-#include "GameServer/Definitions/Definition.hxx"\r
-\r
-struct PSkillInfo {\r
- int32_t mStart;\r
- int32_t mMax;\r
- int32_t mGrow;\r
-\r
- inline PSkillInfo()\r
- {\r
- mStart = mMax = mGrow = 0;\r
- }\r
-};\r
-\r
-struct PSkillPtsInfo {\r
- int32_t mSkill;\r
- int32_t mPoints;\r
-\r
- inline PSkillPtsInfo()\r
- {\r
- mSkill = mPoints = 0;\r
- }\r
-};\r
-\r
-struct PSubSkillPtsInfo {\r
- int32_t mSubSkill;\r
- int32_t mPoints;\r
-\r
- inline PSubSkillPtsInfo()\r
- {\r
- mSubSkill = mPoints = 0;\r
- }\r
-};\r
-\r
-struct PStartLevelInfo {\r
- int32_t mSubSkill;\r
- int32_t mLevel;\r
-\r
- inline PStartLevelInfo()\r
- {\r
- mSubSkill = mLevel = 0;\r
- }\r
-\r
-};\r
-\r
-class PDefCharKind : public PDef {\r
-private:\r
- typedef std::map<int32_t, PSkillPtsInfo*> PSkillPtsMap;\r
- typedef std::map<int32_t, PSubSkillPtsInfo*> PSubSkillPtsMap;\r
- typedef std::map<int32_t, PStartLevelInfo*> PStartLevelMap;\r
-\r
- //int32_t mIndex;\r
- std::string mName;\r
- int32_t mType;\r
-\r
- // TODO: shouldnt this be a map?\r
- PSkillInfo *mSkillInfo;\r
-\r
- PSkillPtsMap mSkillPts;\r
- PSubSkillPtsMap mSubSkillPts;\r
- PStartLevelMap mStartLevels;\r
- int32_t mMoney;\r
- uint32_t mInventory[8];\r
-\r
-public:\r
- PDefCharKind();\r
- ~PDefCharKind();\r
-\r
- bool LoadFromDef(PTokenList *Tokens);\r
-\r
- inline const std::string &GetName() const { return mName; }\r
- inline int32_t GetType() const { return mType; }\r
- inline const PSkillInfo &GetSkillInfo(int32_t Skill) const { return mSkillInfo[Skill-1]; }\r
-\r
- inline int32_t GetStartMoney() const { return mMoney; }\r
- inline uint32_t GetStartInventory(uint8_t Index) const { return ((Index < 7) ? mInventory[Index] : 0); }\r
- // TODO: mission get() functions\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include "GameServer/Definitions/Definition.hxx"
+
+struct PSkillInfo {
+ int32_t mStart;
+ int32_t mMax;
+ int32_t mGrow;
+
+ inline PSkillInfo()
+ {
+ mStart = mMax = mGrow = 0;
+ }
+};
+
+struct PSkillPtsInfo {
+ int32_t mSkill;
+ int32_t mPoints;
+
+ inline PSkillPtsInfo()
+ {
+ mSkill = mPoints = 0;
+ }
+};
+
+struct PSubSkillPtsInfo {
+ int32_t mSubSkill;
+ int32_t mPoints;
+
+ inline PSubSkillPtsInfo()
+ {
+ mSubSkill = mPoints = 0;
+ }
+};
+
+struct PStartLevelInfo {
+ int32_t mSubSkill;
+ int32_t mLevel;
+
+ inline PStartLevelInfo()
+ {
+ mSubSkill = mLevel = 0;
+ }
+
+};
+
+class PDefCharKind : public PDef {
+private:
+ typedef std::map<int32_t, PSkillPtsInfo*> PSkillPtsMap;
+ typedef std::map<int32_t, PSubSkillPtsInfo*> PSubSkillPtsMap;
+ typedef std::map<int32_t, PStartLevelInfo*> PStartLevelMap;
+
+ //int32_t mIndex;
+ std::string mName;
+ int32_t mType;
+
+ // TODO: shouldnt this be a map?
+ PSkillInfo *mSkillInfo;
+
+ PSkillPtsMap mSkillPts;
+ PSubSkillPtsMap mSubSkillPts;
+ PStartLevelMap mStartLevels;
+ int32_t mMoney;
+ uint32_t mInventory[8];
+
+public:
+ PDefCharKind();
+ ~PDefCharKind();
+
+ bool LoadFromDef(PTokenList *Tokens);
+
+ inline const std::string &GetName() const { return mName; }
+ inline int32_t GetType() const { return mType; }
+ inline const PSkillInfo &GetSkillInfo(int32_t Skill) const { return mSkillInfo[Skill-1]; }
+
+ inline int32_t GetStartMoney() const { return mMoney; }
+ inline uint32_t GetStartInventory(uint8_t Index) const { return ((Index < 7) ? mInventory[Index] : 0); }
+ // TODO: mission get() functions
+};
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-// characters.def contains all ingame characters (player types, npc's, monsters)\r
-\r
-PDefCharacter::PDefCharacter()\r
-{\r
- mIndex = -1;\r
- mName = "unknown";\r
- mModel = -1;\r
-}\r
-\r
-bool PDefCharacter::LoadFromDef(PTokenList *Tokens)\r
-{\r
- int Idx=0;\r
- for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
- {\r
- switch(Idx)\r
- {\r
- case 0 : // setentry\r
- continue;\r
-\r
- case 1 :\r
- mIndex = atoi(i->c_str()); break;\r
-\r
- case 2 :\r
- mName = *i; break;\r
-\r
- case 3 :\r
- mModel = atoi(i->c_str()); break;\r
-\r
- case 4 : // 0\r
- continue;\r
-\r
- case 5 :\r
- mHead = atoi(i->c_str()); break;\r
-\r
- case 6 :\r
- mTorso = atoi(i->c_str()); break;\r
-\r
- case 7 :\r
- mLegs = atoi(i->c_str()); break;\r
-\r
- case 8 :\r
- mColor = atoi(i->c_str()); break;\r
-\r
- case 9 :\r
- mBrightness = atoi(i->c_str()); break;\r
- }\r
-\r
- if(Idx==9)\r
- return true;\r
- }\r
-\r
- return false;\r
-}\r
+#include "GameServer/Definitions/Includes.hxx"
+
+// characters.def contains all ingame characters (player types, npc's, monsters)
+
+PDefCharacter::PDefCharacter()
+{
+ mIndex = -1;
+ mName = "unknown";
+ mModel = -1;
+}
+
+bool PDefCharacter::LoadFromDef(PTokenList *Tokens)
+{
+ int Idx=0;
+ for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)
+ {
+ switch(Idx)
+ {
+ case 0 : // setentry
+ continue;
+
+ case 1 :
+ mIndex = atoi(i->c_str()); break;
+
+ case 2 :
+ mName = *i; break;
+
+ case 3 :
+ mModel = atoi(i->c_str()); break;
+
+ case 4 : // 0
+ continue;
+
+ case 5 :
+ mHead = atoi(i->c_str()); break;
+
+ case 6 :
+ mTorso = atoi(i->c_str()); break;
+
+ case 7 :
+ mLegs = atoi(i->c_str()); break;
+
+ case 8 :
+ mColor = atoi(i->c_str()); break;
+
+ case 9 :
+ mBrightness = atoi(i->c_str()); break;
+ }
+
+ if(Idx==9)
+ return true;
+ }
+
+ return false;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-#include "GameServer/Definitions/Definition.hxx"\r
-\r
-class PDefCharacter : public PDef {\r
-private:\r
- //int32_t mIndex;\r
- std::string mName;\r
- int32_t mModel;\r
- int32_t mHead;\r
- int32_t mTorso;\r
- int32_t mLegs;\r
- int32_t mColor;\r
- int32_t mBrightness;\r
-\r
-public:\r
- PDefCharacter();\r
- //~PDefCharacter();\r
-\r
- bool LoadFromDef(PTokenList *Tokens);\r
-\r
- inline const std::string &GetName() const { return mName; }\r
- inline int32_t GetModel() const { return mModel; }\r
- inline int32_t GetHead() const { return mHead; }\r
- inline int32_t GetTorso() const { return mTorso; }\r
- inline int32_t GetLegs() const { return mLegs; }\r
- inline int32_t GetColor() const { return mColor; }\r
- inline int32_t GetBrightness() const { return mBrightness; }\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include "GameServer/Definitions/Definition.hxx"
+
+class PDefCharacter : public PDef {
+private:
+ //int32_t mIndex;
+ std::string mName;
+ int32_t mModel;
+ int32_t mHead;
+ int32_t mTorso;
+ int32_t mLegs;
+ int32_t mColor;
+ int32_t mBrightness;
+
+public:
+ PDefCharacter();
+ //~PDefCharacter();
+
+ bool LoadFromDef(PTokenList *Tokens);
+
+ inline const std::string &GetName() const { return mName; }
+ inline int32_t GetModel() const { return mModel; }
+ inline int32_t GetHead() const { return mHead; }
+ inline int32_t GetTorso() const { return mTorso; }
+ inline int32_t GetLegs() const { return mLegs; }
+ inline int32_t GetColor() const { return mColor; }
+ inline int32_t GetBrightness() const { return mBrightness; }
+};
-#include <cstring>\r
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-PDefFaction::PDefFaction()\r
-{\r
- memset(mRelations, 0, sizeof(mRelations)); // ... array members supposed to by auto-initialized by C++\r
-}\r
-\r
-bool PDefFaction::LoadFromDef(PTokenList *Tokens)\r
-{\r
- int Idx=0;\r
- for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
- {\r
- // setfracc 19 "Monster" -1024 0 0 -1024 -1024 -1024 -1\r
- switch(Idx)\r
- {\r
- case 0 : // setfrac\r
- continue;\r
-\r
- case 1 :\r
- mIndex = atol(i->c_str()); break;\r
-\r
- case 2 :\r
- mName = *i;\r
- CleanUpString(&mName);\r
- break;\r
-\r
- case 3 :\r
- mStartValue = atol(i->c_str()); break;\r
-\r
- case 4:\r
- mAffected = atol(i->c_str())!=0; break;\r
-\r
- case 5:\r
- mSL = atol(i->c_str()); break;\r
-\r
- default :\r
- {\r
- if(Idx-6 < NUMFACTIONS)\r
- mRelations[Idx-6] = atol(i->c_str()); break;\r
- }\r
- }\r
- }\r
-\r
- return true;\r
-}\r
-\r
-int PDefFaction::GetRelation(int Faction) const\r
-{\r
- // faction 0 has no relations\r
- if(Faction <= 0 || Faction > NUMFACTIONS)\r
- return 0;\r
-\r
- return mRelations[Faction-1];\r
-}\r
-\r
+#include <cstring>
+#include "GameServer/Definitions/Includes.hxx"
+
+PDefFaction::PDefFaction()
+{
+ memset(mRelations, 0, sizeof(mRelations)); // ... array members supposed to by auto-initialized by C++
+}
+
+bool PDefFaction::LoadFromDef(PTokenList *Tokens)
+{
+ int Idx=0;
+ for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)
+ {
+ // setfracc 19 "Monster" -1024 0 0 -1024 -1024 -1024 -1
+ switch(Idx)
+ {
+ case 0 : // setfrac
+ continue;
+
+ case 1 :
+ mIndex = atol(i->c_str()); break;
+
+ case 2 :
+ mName = *i;
+ CleanUpString(&mName);
+ break;
+
+ case 3 :
+ mStartValue = atol(i->c_str()); break;
+
+ case 4:
+ mAffected = atol(i->c_str())!=0; break;
+
+ case 5:
+ mSL = atol(i->c_str()); break;
+
+ default :
+ {
+ if(Idx-6 < NUMFACTIONS)
+ mRelations[Idx-6] = atol(i->c_str()); break;
+ }
+ }
+ }
+
+ return true;
+}
+
+int PDefFaction::GetRelation(int Faction) const
+{
+ // faction 0 has no relations
+ if(Faction <= 0 || Faction > NUMFACTIONS)
+ return 0;
+
+ return mRelations[Faction-1];
+}
+
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-#include "GameServer/Definitions/Definition.hxx"\r
-\r
-static const int32_t NUMFACTIONS = 20; // for faction relations only\r
-\r
-class PDefFaction : public PDef {\r
-private :\r
- //int32_t mIndex;\r
- std::string mName;\r
- int32_t mStartValue;\r
- bool mAffected;\r
- int32_t mSL;\r
- int32_t mRelations[NUMFACTIONS];\r
-public :\r
- PDefFaction();\r
- //~PDefFaction();\r
-\r
- bool LoadFromDef(PTokenList *Tokens);\r
-\r
- inline const std::string &GetName() const { return mName; }\r
- inline int32_t GetStartValue() const { return mStartValue; }\r
- inline bool GetAffected() const { return mAffected; }\r
- inline int32_t GetSL() const { return mSL; };\r
- int32_t GetRelation(int32_t Faction) const;\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include "GameServer/Definitions/Definition.hxx"
+
+static const int32_t NUMFACTIONS = 20; // for faction relations only
+
+class PDefFaction : public PDef {
+private :
+ //int32_t mIndex;
+ std::string mName;
+ int32_t mStartValue;
+ bool mAffected;
+ int32_t mSL;
+ int32_t mRelations[NUMFACTIONS];
+public :
+ PDefFaction();
+ //~PDefFaction();
+
+ bool LoadFromDef(PTokenList *Tokens);
+
+ inline const std::string &GetName() const { return mName; }
+ inline int32_t GetStartValue() const { return mStartValue; }
+ inline bool GetAffected() const { return mAffected; }
+ inline int32_t GetSL() const { return mSL; };
+ int32_t GetRelation(int32_t Faction) const;
+};
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-/*\r
- --------------------------------------------------------------------\r
- WARNING:\r
- When adding new .def support, don't forget to add required stuff in PGameDefs::Init()\r
- (compiler won't complain if you don't add that)\r
- --------------------------------------------------------------------\r
-\r
- NOTA: as PGameDefs uses the PDefParser class, which uses the PFileSystem and PFile classes,\r
- files are searched in the same way as the NC client does:\r
- - first try to load the file in unpacked form from the given directory,\r
- - else tries to load the file in packed form from the given directory,\r
- appending pak_ to its name,\r
- - else tries to load the packed file from the .pak archive which name is\r
- derived from the last part of the path.\r
-*/\r
-\r
-PGameDefs::PGameDefs() {}\r
-PGameDefs::~PGameDefs() {}\r
-\r
-bool PGameDefs::Init()\r
-{\r
- Console->Print( "Initializing game defs..." );\r
- bool Res = true;\r
-\r
- Res |= mActionModsDefs.Load ("Action mods", "defs/actionmod.def");\r
- Res |= mAmmosDefs.Load ("Ammos", "defs/ammo.def");\r
- Res |= mAppartementsDefs.Load ("Apartments", "defs/appartements.def");\r
- Res |= mAppPlacesDefs.Load ("App Places", "defs/appplaces.def");\r
- Res |= mBlueprintPiecesDefs.Load ("Blueprint pieces", "defs/blueprintpieces.def");\r
- Res |= mCharsDefs.Load ("Chars", "defs/characters.def");\r
- Res |= mCharActionsDefs.Load ("Char actions", "defs/charaction.def");\r
- Res |= mDamagesDefs.Load ("Damage", "defs/damage.def");\r
- Res |= mDrugsDefs.Load ("Drugs", "defs/drugs.def");\r
- Res |= mFactionsDefs.Load ("Factions", "defs/fractions.def");\r
- //Res |= mHacksDefs.Load ("Hack", "defs/hack.def");\r
- Res |= mImplantsDefs.Load ("Implants", "defs/implants.def");\r
- Res |= mItemContainersDefs.Load ("Item containers", "defs/itemcontainer.def");\r
- Res |= mItemModsDefs.Load ("Item mods", "defs/itemmod.def");\r
- Res |= mItemRestrictionsDefs.Load ("Item restrictions", "defs/itemres.def");\r
- Res |= mItemsDefs.Load ("Items", "defs/items.def");\r
- Res |= mMissionsDefs.Load ("Missions", "defs/missionbase.def");\r
- Res |= mNpcArmorsDefs.Load ("NPC Armors", "defs/npcarmor.def");\r
- Res |= mNpcGroupSpawnsDefs.Load ("NPC group spawns", "defs/npcgroupspawn.def");\r
- Res |= mNpcsDefs.Load ("NPC", "defs/npc.def");\r
- Res |= mOutpostsDefs.Load ("Outposts", "defs/outposts.def");\r
- Res |= mRecyclesDefs.Load ("Recycles", "defs/recycles.def");\r
- Res |= mRespawnsDefs.Load ("Respawns", "defs/respawn.def");\r
- Res |= mShotsDefs.Load ("Shots", "defs/shots.def");\r
- Res |= mSubSkillsDefs.Load ("Subskills", "defs/subskill.def"); // Loading before skills is required\r
- Res |= mSkillsDefs.Load ("Skills", "defs/skills.def");\r
- Res |= mCharKindsDefs.Load ("Char kinds", "defs/charkinds.def"); // Loading after skills is required\r
- Res |= mTradersDefs.Load ("Traders", "defs/trader.def");\r
- Res |= mVhcsDefs.Load ("Vehicles", "defs/vehicles.def");\r
- Res |= mVhcSeatsDefs.Load ("Vehicle seats", "defs/vehiclesits.def");\r
- Res |= mWeaponsDefs.Load ("Weapons", "defs/weapons.def");\r
- Res |= mWeathersDefs.Load ("Weathers", "defs/weather.def");\r
- Res |= mWorldsDefs.Load ("Worldinfo", "defs/worldinfo.def");\r
- Res |= mWorldFilesDefs.Load ("World files", "worlds/worlds.ini");\r
- Res |= mWorldModelsDefs.Load ("World models", "defs/worldmodel.def");\r
- Res |= mScriptDefs.Load ("Script defs", "defs/scripts.def");\r
-\r
- return ( Res );\r
-}\r
+#include "GameServer/Definitions/Includes.hxx"
+
+/*
+ --------------------------------------------------------------------
+ WARNING:
+ When adding new .def support, don't forget to add required stuff in PGameDefs::Init()
+ (compiler won't complain if you don't add that)
+ --------------------------------------------------------------------
+
+ NOTA: as PGameDefs uses the PDefParser class, which uses the PFileSystem and PFile classes,
+ files are searched in the same way as the NC client does:
+ - first try to load the file in unpacked form from the given directory,
+ - else tries to load the file in packed form from the given directory,
+ appending pak_ to its name,
+ - else tries to load the packed file from the .pak archive which name is
+ derived from the last part of the path.
+*/
+
+PGameDefs::PGameDefs() {}
+PGameDefs::~PGameDefs() {}
+
+bool PGameDefs::Init()
+{
+ Console->Print( "Initializing game defs..." );
+ bool Res = true;
+
+ Res |= mActionModsDefs.Load ("Action mods", "defs/actionmod.def");
+ Res |= mAmmosDefs.Load ("Ammos", "defs/ammo.def");
+ Res |= mAppartementsDefs.Load ("Apartments", "defs/appartements.def");
+ Res |= mAppPlacesDefs.Load ("App Places", "defs/appplaces.def");
+ Res |= mBlueprintPiecesDefs.Load ("Blueprint pieces", "defs/blueprintpieces.def");
+ Res |= mCharsDefs.Load ("Chars", "defs/characters.def");
+ Res |= mCharActionsDefs.Load ("Char actions", "defs/charaction.def");
+ Res |= mDamagesDefs.Load ("Damage", "defs/damage.def");
+ Res |= mDrugsDefs.Load ("Drugs", "defs/drugs.def");
+ Res |= mFactionsDefs.Load ("Factions", "defs/fractions.def");
+ //Res |= mHacksDefs.Load ("Hack", "defs/hack.def");
+ Res |= mImplantsDefs.Load ("Implants", "defs/implants.def");
+ Res |= mItemContainersDefs.Load ("Item containers", "defs/itemcontainer.def");
+ Res |= mItemModsDefs.Load ("Item mods", "defs/itemmod.def");
+ Res |= mItemRestrictionsDefs.Load ("Item restrictions", "defs/itemres.def");
+ Res |= mItemsDefs.Load ("Items", "defs/items.def");
+ Res |= mMissionsDefs.Load ("Missions", "defs/missionbase.def");
+ Res |= mNpcArmorsDefs.Load ("NPC Armors", "defs/npcarmor.def");
+ Res |= mNpcGroupSpawnsDefs.Load ("NPC group spawns", "defs/npcgroupspawn.def");
+ Res |= mNpcsDefs.Load ("NPC", "defs/npc.def");
+ Res |= mOutpostsDefs.Load ("Outposts", "defs/outposts.def");
+ Res |= mRecyclesDefs.Load ("Recycles", "defs/recycles.def");
+ Res |= mRespawnsDefs.Load ("Respawns", "defs/respawn.def");
+ Res |= mShotsDefs.Load ("Shots", "defs/shots.def");
+ Res |= mSubSkillsDefs.Load ("Subskills", "defs/subskill.def"); // Loading before skills is required
+ Res |= mSkillsDefs.Load ("Skills", "defs/skills.def");
+ Res |= mCharKindsDefs.Load ("Char kinds", "defs/charkinds.def"); // Loading after skills is required
+ Res |= mTradersDefs.Load ("Traders", "defs/trader.def");
+ Res |= mVhcsDefs.Load ("Vehicles", "defs/vehicles.def");
+ Res |= mVhcSeatsDefs.Load ("Vehicle seats", "defs/vehiclesits.def");
+ Res |= mWeaponsDefs.Load ("Weapons", "defs/weapons.def");
+ Res |= mWeathersDefs.Load ("Weathers", "defs/weather.def");
+ Res |= mWorldsDefs.Load ("Worldinfo", "defs/worldinfo.def");
+ Res |= mWorldFilesDefs.Load ("World files", "worlds/worlds.ini");
+ Res |= mWorldModelsDefs.Load ("World models", "defs/worldmodel.def");
+ Res |= mScriptDefs.Load ("Script defs", "defs/scripts.def");
+
+ return ( Res );
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include "GameServer/Definitions/Definition.hxx"\r
-#include "GameServer/Definitions/Implants.hxx"\r
-#include "GameServer/Definitions/ItemContainer.hxx"\r
-#include "GameServer/Definitions/ItemMod.hxx"\r
-#include "GameServer/Definitions/ItemRes.hxx"\r
-#include "GameServer/Definitions/Items.hxx"\r
-#include "GameServer/Definitions/Mission.hxx"\r
-#include "GameServer/Definitions/NpcArmor.hxx"\r
-#include "GameServer/Definitions/NpcGroupSpawn.hxx"\r
-#include "GameServer/Definitions/Npc.hxx"\r
-#include "GameServer/Definitions/Outposts.hxx"\r
-#include "GameServer/Definitions/Recycles.hxx"\r
-#include "GameServer/Definitions/Respawn.hxx"\r
-#include "GameServer/Definitions/Scripts.hxx"\r
-#include "GameServer/Definitions/Shots.hxx"\r
-#include "GameServer/Definitions/Skills.hxx"\r
-#include "GameServer/Definitions/SubSkills.hxx"\r
-#include "GameServer/Definitions/Trader.hxx"\r
-#include "GameServer/Definitions/Vehicles.hxx"\r
-#include "GameServer/Definitions/VehicleSits.hxx"\r
-#include "GameServer/Definitions/Weapons.hxx"\r
-#include "GameServer/Definitions/Weather.hxx"\r
-#include "GameServer/Definitions/WorldFile.hxx"\r
-#include "GameServer/Definitions/WorldModels.hxx"\r
-#include "GameServer/Definitions/Worlds.hxx"\r
-\r
-typedef PDefMap<PDefActionMod> PDefActionModsMap;\r
-typedef PDefMap<PDefAmmo> PDefAmmosMap;\r
-class PDefAppartementsMap; // Derived classe for addition of specific members\r
-typedef PDefMap<PDefAppPlace> PDefAppPlacesMap; // No derived class needed here\r
-typedef PDefMap<PDefBlueprintPieces> PDefBlueprintPiecesMap;\r
-typedef PDefMap<PDefCharacter> PDefCharactersMap;\r
-typedef PDefMap<PDefCharAction> PDefCharActionsMap;\r
-typedef PDefMap<PDefCharKind> PDefCharKindsMap;\r
-typedef PDefMap<PDefDamage> PDefDamagesMap;\r
-typedef PDefMap<PDefDrug> PDefDrugsMap;\r
-typedef PDefMap<PDefFaction> PDefFactionsMap;\r
-//typedef PDefMap<PDefHack> PDefHacksMap; // File not used by KK\r
-typedef PDefMap<PDefImplant> PDefImplantsMap;\r
-typedef PDefMap<PDefItemContainer> PDefItemContainersMap;\r
-typedef PDefMap<PDefItemMod> PDefItemModsMap;\r
-typedef PDefMap<PDefItemRestriction> PDefItemRestrictionsMap;\r
-class PDefItemsMap;\r
-typedef PDefMap<PDefMission> PDefMissionsMap;\r
-typedef PDefMap<PDefNpcArmor> PDefNpcArmorsMap;\r
-typedef PDefMap<PDefNpcGroupSpawn> PDefNpcGroupSpawnsMap;\r
-typedef PDefMap<PDefNpc> PDefNpcsMap;\r
-typedef PDefMap<PDefOutpost> PDefOutpostsMap;\r
-typedef PDefMap<PDefRecycle> PDefRecyclesMap;\r
-class PDefRespawnsMap;\r
-typedef PDefMap<PDefShot> PDefShotsMap;\r
-typedef PDefMap<PDefSkill> PDefSkillsMap;\r
-typedef PDefMap<PDefSubSkill> PDefSubSkillsMap;\r
-typedef PDefMap<PDefTrader> PDefTradersMap;\r
-typedef PDefMap<PDefVhc> PDefVhcsMap;\r
-typedef PDefMap<PDefVhcSeat> PDefVhcSeatsMap;\r
-typedef PDefMap<PDefWeapon> PDefWeaponsMap;\r
-typedef PDefMap<PDefWeather> PDefWeathersMap;\r
-typedef PDefMap<PDefWorld> PDefWorldsMap;\r
-class PDefWorldFilesMap;\r
-typedef PDefMap<PDefWorldModel> PDefWorldModelsMap;\r
-\r
-class PDefScriptsMap;\r
-//typedef PDefMap<PDefScripts> PDefScriptsMap;\r
-// ___Add new entries here in alpĥabetical order___\r
-\r
-\r
-class PGameDefs {\r
-private:\r
- PDefActionModsMap mActionModsDefs;\r
- PDefAmmosMap mAmmosDefs;\r
- PDefAppartementsMap mAppartementsDefs;\r
- PDefAppPlacesMap mAppPlacesDefs;\r
- PDefBlueprintPiecesMap mBlueprintPiecesDefs;\r
- PDefCharactersMap mCharsDefs;\r
- PDefCharActionsMap mCharActionsDefs;\r
- PDefCharKindsMap mCharKindsDefs;\r
- PDefDamagesMap mDamagesDefs;\r
- PDefDrugsMap mDrugsDefs;\r
- PDefFactionsMap mFactionsDefs;\r
- //PDefHacksMap mHacksDefs;\r
- PDefImplantsMap mImplantsDefs;\r
- PDefItemContainersMap mItemContainersDefs;\r
- PDefItemModsMap mItemModsDefs;\r
- PDefItemRestrictionsMap mItemRestrictionsDefs;\r
- PDefItemsMap mItemsDefs;\r
- PDefMissionsMap mMissionsDefs;\r
- PDefNpcArmorsMap mNpcArmorsDefs;\r
- PDefNpcGroupSpawnsMap mNpcGroupSpawnsDefs;\r
- PDefNpcsMap mNpcsDefs;\r
- PDefOutpostsMap mOutpostsDefs;\r
- PDefRecyclesMap mRecyclesDefs;\r
- PDefRespawnsMap mRespawnsDefs;\r
- PDefShotsMap mShotsDefs;\r
- PDefSkillsMap mSkillsDefs;\r
- PDefSubSkillsMap mSubSkillsDefs;\r
- PDefTradersMap mTradersDefs;\r
- PDefVhcsMap mVhcsDefs;\r
- PDefVhcSeatsMap mVhcSeatsDefs;\r
- PDefWeaponsMap mWeaponsDefs;\r
- PDefWeathersMap mWeathersDefs;\r
- PDefWorldsMap mWorldsDefs;\r
- PDefWorldFilesMap mWorldFilesDefs;\r
- PDefWorldModelsMap mWorldModelsDefs;\r
- PDefScriptsMap mScriptDefs;\r
- // ___Add new entries here___\r
-\r
-public:\r
- PGameDefs();\r
- ~PGameDefs();\r
-\r
- bool Init();\r
-\r
- inline const PDefActionModsMap* ActionMods() const { return &mActionModsDefs; }\r
- inline const PDefAmmosMap* Ammos() const { return &mAmmosDefs; }\r
- inline const PDefAppartementsMap* Appartements() const { return &mAppartementsDefs; }\r
- inline const PDefAppPlacesMap* AppPlaces() const { return &mAppPlacesDefs; }\r
- inline const PDefBlueprintPiecesMap* BlueprintPieces() const { return &mBlueprintPiecesDefs; }\r
- inline const PDefCharactersMap* Chars() const { return &mCharsDefs; }\r
- inline const PDefCharActionsMap* CharActions() const { return &mCharActionsDefs; }\r
- inline const PDefCharKindsMap* CharKinds() const { return &mCharKindsDefs; }\r
- inline const PDefDamagesMap* Damages() const { return &mDamagesDefs; }\r
- inline const PDefDrugsMap* Drugs() const { return &mDrugsDefs; }\r
- inline const PDefFactionsMap* Factions() const { return &mFactionsDefs; }\r
- //inline const PDefHacksMap* Hacks() const { return &mHacksDefs; }\r
- inline const PDefImplantsMap* Implants() const { return &mImplantsDefs;}\r
- inline const PDefItemContainersMap* ItemContainers() const { return &mItemContainersDefs; }\r
- inline const PDefItemModsMap* ItemMods() const { return &mItemModsDefs; }\r
- inline const PDefItemRestrictionsMap* ItemRestrictions() const { return & mItemRestrictionsDefs; }\r
- inline const PDefItemsMap* Items() const { return &mItemsDefs; }\r
- inline const PDefMissionsMap* Missions() const { return &mMissionsDefs; }\r
- inline const PDefNpcArmorsMap* NpcArmors() const { return & mNpcArmorsDefs; }\r
- inline const PDefNpcGroupSpawnsMap* GroupSpawns() const { return &mNpcGroupSpawnsDefs; }\r
- inline const PDefNpcsMap* Npcs() const { return &mNpcsDefs; }\r
- inline const PDefOutpostsMap* Outposts() const { return &mOutpostsDefs; }\r
- inline const PDefRecyclesMap* Recycles() const { return &mRecyclesDefs; }\r
- inline const PDefRespawnsMap* Respawns() const { return &mRespawnsDefs; }\r
- inline const PDefShotsMap* Shots() const { return &mShotsDefs; }\r
- inline const PDefSkillsMap* Skills() const { return &mSkillsDefs; }\r
- inline const PDefSubSkillsMap* SubSkills() const { return &mSubSkillsDefs; }\r
- inline const PDefTradersMap* Traders() const { return &mTradersDefs; }\r
- inline const PDefVhcsMap* Vhcs() const { return &mVhcsDefs; }\r
- inline const PDefVhcSeatsMap* VhcSeats() const { return &mVhcSeatsDefs; }\r
- inline const PDefWeaponsMap* Weapons() const { return &mWeaponsDefs; }\r
- inline const PDefWeathersMap* Weathers() const { return &mWeathersDefs; }\r
- inline const PDefWorldsMap* Worlds() const { return &mWorldsDefs; }\r
- inline const PDefWorldFilesMap* WorldFiles() const { return &mWorldFilesDefs; }\r
- inline const PDefWorldModelsMap* WorldModels() const { return &mWorldModelsDefs; }\r
- inline const PDefScriptsMap* Scripts() const { return &mScriptDefs; }\r
- // ___Add new entries here___\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include "GameServer/Definitions/Definition.hxx"
+#include "GameServer/Definitions/Implants.hxx"
+#include "GameServer/Definitions/ItemContainer.hxx"
+#include "GameServer/Definitions/ItemMod.hxx"
+#include "GameServer/Definitions/ItemRes.hxx"
+#include "GameServer/Definitions/Items.hxx"
+#include "GameServer/Definitions/Mission.hxx"
+#include "GameServer/Definitions/NpcArmor.hxx"
+#include "GameServer/Definitions/NpcGroupSpawn.hxx"
+#include "GameServer/Definitions/Npc.hxx"
+#include "GameServer/Definitions/Outposts.hxx"
+#include "GameServer/Definitions/Recycles.hxx"
+#include "GameServer/Definitions/Respawn.hxx"
+#include "GameServer/Definitions/Scripts.hxx"
+#include "GameServer/Definitions/Shots.hxx"
+#include "GameServer/Definitions/Skills.hxx"
+#include "GameServer/Definitions/SubSkills.hxx"
+#include "GameServer/Definitions/Trader.hxx"
+#include "GameServer/Definitions/Vehicles.hxx"
+#include "GameServer/Definitions/VehicleSits.hxx"
+#include "GameServer/Definitions/Weapons.hxx"
+#include "GameServer/Definitions/Weather.hxx"
+#include "GameServer/Definitions/WorldFile.hxx"
+#include "GameServer/Definitions/WorldModels.hxx"
+#include "GameServer/Definitions/Worlds.hxx"
+
+typedef PDefMap<PDefActionMod> PDefActionModsMap;
+typedef PDefMap<PDefAmmo> PDefAmmosMap;
+class PDefAppartementsMap; // Derived classe for addition of specific members
+typedef PDefMap<PDefAppPlace> PDefAppPlacesMap; // No derived class needed here
+typedef PDefMap<PDefBlueprintPieces> PDefBlueprintPiecesMap;
+typedef PDefMap<PDefCharacter> PDefCharactersMap;
+typedef PDefMap<PDefCharAction> PDefCharActionsMap;
+typedef PDefMap<PDefCharKind> PDefCharKindsMap;
+typedef PDefMap<PDefDamage> PDefDamagesMap;
+typedef PDefMap<PDefDrug> PDefDrugsMap;
+typedef PDefMap<PDefFaction> PDefFactionsMap;
+//typedef PDefMap<PDefHack> PDefHacksMap; // File not used by KK
+typedef PDefMap<PDefImplant> PDefImplantsMap;
+typedef PDefMap<PDefItemContainer> PDefItemContainersMap;
+typedef PDefMap<PDefItemMod> PDefItemModsMap;
+typedef PDefMap<PDefItemRestriction> PDefItemRestrictionsMap;
+class PDefItemsMap;
+typedef PDefMap<PDefMission> PDefMissionsMap;
+typedef PDefMap<PDefNpcArmor> PDefNpcArmorsMap;
+typedef PDefMap<PDefNpcGroupSpawn> PDefNpcGroupSpawnsMap;
+typedef PDefMap<PDefNpc> PDefNpcsMap;
+typedef PDefMap<PDefOutpost> PDefOutpostsMap;
+typedef PDefMap<PDefRecycle> PDefRecyclesMap;
+class PDefRespawnsMap;
+typedef PDefMap<PDefShot> PDefShotsMap;
+typedef PDefMap<PDefSkill> PDefSkillsMap;
+typedef PDefMap<PDefSubSkill> PDefSubSkillsMap;
+typedef PDefMap<PDefTrader> PDefTradersMap;
+typedef PDefMap<PDefVhc> PDefVhcsMap;
+typedef PDefMap<PDefVhcSeat> PDefVhcSeatsMap;
+typedef PDefMap<PDefWeapon> PDefWeaponsMap;
+typedef PDefMap<PDefWeather> PDefWeathersMap;
+typedef PDefMap<PDefWorld> PDefWorldsMap;
+class PDefWorldFilesMap;
+typedef PDefMap<PDefWorldModel> PDefWorldModelsMap;
+
+class PDefScriptsMap;
+//typedef PDefMap<PDefScripts> PDefScriptsMap;
+// ___Add new entries here in alpĥabetical order___
+
+
+class PGameDefs {
+private:
+ PDefActionModsMap mActionModsDefs;
+ PDefAmmosMap mAmmosDefs;
+ PDefAppartementsMap mAppartementsDefs;
+ PDefAppPlacesMap mAppPlacesDefs;
+ PDefBlueprintPiecesMap mBlueprintPiecesDefs;
+ PDefCharactersMap mCharsDefs;
+ PDefCharActionsMap mCharActionsDefs;
+ PDefCharKindsMap mCharKindsDefs;
+ PDefDamagesMap mDamagesDefs;
+ PDefDrugsMap mDrugsDefs;
+ PDefFactionsMap mFactionsDefs;
+ //PDefHacksMap mHacksDefs;
+ PDefImplantsMap mImplantsDefs;
+ PDefItemContainersMap mItemContainersDefs;
+ PDefItemModsMap mItemModsDefs;
+ PDefItemRestrictionsMap mItemRestrictionsDefs;
+ PDefItemsMap mItemsDefs;
+ PDefMissionsMap mMissionsDefs;
+ PDefNpcArmorsMap mNpcArmorsDefs;
+ PDefNpcGroupSpawnsMap mNpcGroupSpawnsDefs;
+ PDefNpcsMap mNpcsDefs;
+ PDefOutpostsMap mOutpostsDefs;
+ PDefRecyclesMap mRecyclesDefs;
+ PDefRespawnsMap mRespawnsDefs;
+ PDefShotsMap mShotsDefs;
+ PDefSkillsMap mSkillsDefs;
+ PDefSubSkillsMap mSubSkillsDefs;
+ PDefTradersMap mTradersDefs;
+ PDefVhcsMap mVhcsDefs;
+ PDefVhcSeatsMap mVhcSeatsDefs;
+ PDefWeaponsMap mWeaponsDefs;
+ PDefWeathersMap mWeathersDefs;
+ PDefWorldsMap mWorldsDefs;
+ PDefWorldFilesMap mWorldFilesDefs;
+ PDefWorldModelsMap mWorldModelsDefs;
+ PDefScriptsMap mScriptDefs;
+ // ___Add new entries here___
+
+public:
+ PGameDefs();
+ ~PGameDefs();
+
+ bool Init();
+
+ inline const PDefActionModsMap* ActionMods() const { return &mActionModsDefs; }
+ inline const PDefAmmosMap* Ammos() const { return &mAmmosDefs; }
+ inline const PDefAppartementsMap* Appartements() const { return &mAppartementsDefs; }
+ inline const PDefAppPlacesMap* AppPlaces() const { return &mAppPlacesDefs; }
+ inline const PDefBlueprintPiecesMap* BlueprintPieces() const { return &mBlueprintPiecesDefs; }
+ inline const PDefCharactersMap* Chars() const { return &mCharsDefs; }
+ inline const PDefCharActionsMap* CharActions() const { return &mCharActionsDefs; }
+ inline const PDefCharKindsMap* CharKinds() const { return &mCharKindsDefs; }
+ inline const PDefDamagesMap* Damages() const { return &mDamagesDefs; }
+ inline const PDefDrugsMap* Drugs() const { return &mDrugsDefs; }
+ inline const PDefFactionsMap* Factions() const { return &mFactionsDefs; }
+ //inline const PDefHacksMap* Hacks() const { return &mHacksDefs; }
+ inline const PDefImplantsMap* Implants() const { return &mImplantsDefs;}
+ inline const PDefItemContainersMap* ItemContainers() const { return &mItemContainersDefs; }
+ inline const PDefItemModsMap* ItemMods() const { return &mItemModsDefs; }
+ inline const PDefItemRestrictionsMap* ItemRestrictions() const { return & mItemRestrictionsDefs; }
+ inline const PDefItemsMap* Items() const { return &mItemsDefs; }
+ inline const PDefMissionsMap* Missions() const { return &mMissionsDefs; }
+ inline const PDefNpcArmorsMap* NpcArmors() const { return & mNpcArmorsDefs; }
+ inline const PDefNpcGroupSpawnsMap* GroupSpawns() const { return &mNpcGroupSpawnsDefs; }
+ inline const PDefNpcsMap* Npcs() const { return &mNpcsDefs; }
+ inline const PDefOutpostsMap* Outposts() const { return &mOutpostsDefs; }
+ inline const PDefRecyclesMap* Recycles() const { return &mRecyclesDefs; }
+ inline const PDefRespawnsMap* Respawns() const { return &mRespawnsDefs; }
+ inline const PDefShotsMap* Shots() const { return &mShotsDefs; }
+ inline const PDefSkillsMap* Skills() const { return &mSkillsDefs; }
+ inline const PDefSubSkillsMap* SubSkills() const { return &mSubSkillsDefs; }
+ inline const PDefTradersMap* Traders() const { return &mTradersDefs; }
+ inline const PDefVhcsMap* Vhcs() const { return &mVhcsDefs; }
+ inline const PDefVhcSeatsMap* VhcSeats() const { return &mVhcSeatsDefs; }
+ inline const PDefWeaponsMap* Weapons() const { return &mWeaponsDefs; }
+ inline const PDefWeathersMap* Weathers() const { return &mWeathersDefs; }
+ inline const PDefWorldsMap* Worlds() const { return &mWorldsDefs; }
+ inline const PDefWorldFilesMap* WorldFiles() const { return &mWorldFilesDefs; }
+ inline const PDefWorldModelsMap* WorldModels() const { return &mWorldModelsDefs; }
+ inline const PDefScriptsMap* Scripts() const { return &mScriptDefs; }
+ // ___Add new entries here___
+};
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-PDefHack::PDefHack()\r
-{\r
-}\r
-\r
-bool PDefHack::LoadFromDef(PTokenList *Tokens)\r
-{\r
- int Idx=0;\r
- for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
- {\r
- switch(Idx)\r
- {\r
- case 0: // setentry\r
- continue ;\r
-\r
-\r
- case 1: // index\r
- mIndex = atoi(i->c_str()); break;\r
-\r
-\r
- }\r
- }\r
-\r
- return true;\r
-}\r
-\r
+#include "GameServer/Definitions/Includes.hxx"
+
+PDefHack::PDefHack()
+{
+}
+
+bool PDefHack::LoadFromDef(PTokenList *Tokens)
+{
+ int Idx=0;
+ for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)
+ {
+ switch(Idx)
+ {
+ case 0: // setentry
+ continue ;
+
+
+ case 1: // index
+ mIndex = atoi(i->c_str()); break;
+
+
+ }
+ }
+
+ return true;
+}
+
-#pragma once\r
-\r
-#include "GameServer/Definitions/Definition.hxx"\r
-\r
-class PDefHack : public PDef {\r
-private:\r
- //int mIndex;\r
- //qui aggiungere valori\r
-public:\r
- PDefHack();\r
- //~PDefHack();\r
-\r
- bool LoadFromDef(PTokenList *Tokens);\r
-\r
- //qui aggiungere funzioni per i gets\r
-};\r
+#pragma once
+
+#include "GameServer/Definitions/Definition.hxx"
+
+class PDefHack : public PDef {
+private:
+ //int mIndex;
+ //qui aggiungere valori
+public:
+ PDefHack();
+ //~PDefHack();
+
+ bool LoadFromDef(PTokenList *Tokens);
+
+ //qui aggiungere funzioni per i gets
+};
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-#define GAMEDEFS_DEFITEMSMAXSEQ 100\r
-\r
-PDefItems::PDefItems()\r
-{\r
- //mIndex = 0;\r
- mModel = 0;\r
- mType = 0;\r
- mValue1 = 0;\r
- mValue2 = 0;\r
- mValue3 = 0;\r
- //mBmNum = 0;\r
- //mmBmNumIndex = 0;\r
- mSizeX = 1;\r
- mSizeY = 1;\r
- //mSmallbmnum = 0;\r
- mWeight = 0;\r
- mStackable = 0;\r
- mFillWeight = 0;\r
- mQualifier = 0;\r
- mGfxMods = 0;\r
- mItemGroupID = 0;\r
- mTextDescID = 0;\r
- mBasePrice = 0;\r
- mTechlevel = 0;\r
- mItemflags = 0;\r
- // std::mShortname = "";\r
-}\r
-\r
-bool PDefItems::LoadFromDef( PTokenList *Tokens )\r
-{\r
- int Idx = 0;\r
- for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )\r
- {\r
- switch ( Idx )\r
- {\r
- case 0: // setentry\r
- continue;\r
- case 1: // index\r
- mIndex = atoi( i->c_str() ); break;\r
- case 2: // name\r
- mName = *i; break;\r
- case 3:\r
- mModel = atoi(i->c_str()); // used for IG display\r
- break;\r
- case 4:\r
- mType = atoi( i->c_str() ); break;\r
- case 5:\r
- mValue1 = atoi( i->c_str() ); break;\r
- case 6:\r
- mValue2 = atoi( i->c_str() ); break;\r
- case 7:\r
- mValue3 = atoi( i->c_str() ); break;\r
- case 8:\r
- // mBmNum = atoi(i->c_str()); // used IG for inventory display\r
- break;\r
- case 9:\r
- // mmBmNumIndex = atoi(i->c_str()); // used IG for inventory display\r
- break;\r
- case 10:\r
- mSizeX = atoi( i->c_str() ); break;\r
- case 11:\r
- mSizeY = atoi( i->c_str() ); break;\r
- case 12:\r
- // mSmallbmnum = atoi(i->c_str()); // used IG for inventory display\r
- break;\r
- case 13:\r
- mWeight = atof( i->c_str() ); break;\r
- case 14:\r
- mStackable = atoi( i->c_str() ); break;\r
- case 15:\r
- mFillWeight = atof( i->c_str() ); break;\r
- case 16:\r
- mQualifier = atoi( i->c_str() ); break;\r
- case 17:\r
- mGfxMods = atoi( i->c_str() ); break;\r
- case 18:\r
- mItemGroupID = atoi( i->c_str() ); break;\r
- case 19:\r
- mTextDescID = atoi( i->c_str() ); break;\r
- case 20:\r
- mBasePrice = atoi( i->c_str() ); break;\r
- case 21:\r
- mTechlevel = atoi( i->c_str() ); break;\r
- case 22:\r
- mItemflags = atoi( i->c_str() ); break;\r
- case 23:\r
- // mShortname = *i; // used IG for display on inventories Icons\r
- break;\r
- }\r
- }\r
-\r
- return true;\r
-}\r
-\r
-\r
-PDefItemsMap::PDefItemsMap()\r
-{\r
- mMapItCache = NULL;\r
- mMapItCacheCount = 0;\r
- mMaxItemGroupId = -1;\r
-}\r
-\r
-PDefItemsMap::~PDefItemsMap()\r
-{\r
- delete [] mMapItCache;\r
-}\r
-\r
-void PDefItemsMap::BuildMapItCache()\r
-{\r
- int CacheEntryIdx = 0;\r
- int EntrySeqIdx = 1;\r
-\r
- mMapItCacheCount = 1 + ( mDefs.size() / GAMEDEFS_DEFITEMSMAXSEQ );\r
-\r
- if ( mMapItCacheCount )\r
- {\r
- if( mMapItCache )\r
- {\r
- delete [] mMapItCache;\r
- }\r
- mMapItCache = new std::map<int, PDefItems*>::const_iterator[mMapItCacheCount];\r
- mMapItCache[CacheEntryIdx++] = mDefs.begin();\r
-\r
- std::map<int, PDefItems*>::const_iterator It = mDefs.begin();\r
- while ( It != mDefs.end() )\r
- {\r
- if ( EntrySeqIdx++ == GAMEDEFS_DEFITEMSMAXSEQ )\r
- {\r
- mMapItCache[CacheEntryIdx++] = It;\r
- EntrySeqIdx = 1;\r
- }\r
- It++;\r
- }\r
- }\r
-}\r
-\r
-void PDefItemsMap::BuildItemGroups()\r
-{\r
- //std::map<int, std::vector<int> > mItemGroups;\r
- // Implementation more complicated than needed but avoid too many realloc\r
- \r
- // Group size conting\r
- std::map<int, int> groupSize;\r
- for ( std::map<int, PDefItems*>::const_iterator i = mDefs.begin(); i != mDefs.end(); i++ )\r
- groupSize[ i->second->GetItemGroupID() ]++;\r
-\r
- // Item group vectors size reservation\r
- mItemGroups.clear();\r
- for ( std::map<int, int>::const_iterator i = groupSize.begin(); i != groupSize.end(); i++ )\r
- {\r
- mItemGroups[i->first].reserve(i->second);\r
- if(i->first > mMaxItemGroupId)\r
- mMaxItemGroupId = i->first;\r
- //Console->Print("Item group %d : %d items", i->first, i->second);\r
- }\r
- \r
- // Effective groups building\r
- for ( std::map<int, PDefItems*>::const_iterator i = mDefs.begin(); i != mDefs.end(); i++ )\r
- mItemGroups[ i->second->GetItemGroupID() ].push_back(i->first); // i->first is ItemIndex\r
-}\r
-\r
-bool PDefItemsMap::Load(const char* nName, const char* nFilename)\r
-{\r
- if( PDefMap<PDefItems>::Load( nName, nFilename) )\r
- {\r
- BuildMapItCache();\r
- BuildItemGroups();\r
- return ( true );\r
- }\r
- else\r
- return ( false );\r
-}\r
-\r
-const PDefItems* PDefItemsMap::GetDefBySeqIndex( int nSeqIndex ) const\r
-{\r
- int CacheEntryIdx = nSeqIndex / GAMEDEFS_DEFITEMSMAXSEQ;\r
- if ( CacheEntryIdx >= mMapItCacheCount )\r
- return NULL;\r
-\r
- std::map<int, PDefItems*>::const_iterator It = mMapItCache[CacheEntryIdx];\r
- int EntrySeqIdx = CacheEntryIdx * GAMEDEFS_DEFITEMSMAXSEQ;\r
-\r
- while (( EntrySeqIdx < nSeqIndex ) && ( It != mDefs.end() ) )\r
- {\r
- EntrySeqIdx++;\r
- It++;\r
- }\r
-\r
- if (( EntrySeqIdx == nSeqIndex ) && ( It != mDefs.end() ) )\r
- {\r
- return It->second;\r
- }\r
- else\r
- return NULL;\r
-}\r
-\r
-int PDefItemsMap::GetRandomItemIdFromGroup( int nGroupId ) const\r
-{\r
- if( (nGroupId >= 0) && (nGroupId <= mMaxItemGroupId) )\r
- {\r
- std::map<int, std::vector<int> >::const_iterator selectedEntry = mItemGroups.find(nGroupId);\r
- if(selectedEntry != mItemGroups.end())\r
- {\r
- int groupSize = selectedEntry->second.size();\r
- if( groupSize )\r
- {\r
- return selectedEntry->second[GetRandom(groupSize - 1, 0)];\r
- }\r
- }\r
- }\r
-\r
- return 0;\r
-}\r
+#include "GameServer/Definitions/Includes.hxx"
+
+#define GAMEDEFS_DEFITEMSMAXSEQ 100
+
+PDefItems::PDefItems()
+{
+ //mIndex = 0;
+ mModel = 0;
+ mType = 0;
+ mValue1 = 0;
+ mValue2 = 0;
+ mValue3 = 0;
+ //mBmNum = 0;
+ //mmBmNumIndex = 0;
+ mSizeX = 1;
+ mSizeY = 1;
+ //mSmallbmnum = 0;
+ mWeight = 0;
+ mStackable = 0;
+ mFillWeight = 0;
+ mQualifier = 0;
+ mGfxMods = 0;
+ mItemGroupID = 0;
+ mTextDescID = 0;
+ mBasePrice = 0;
+ mTechlevel = 0;
+ mItemflags = 0;
+ // std::mShortname = "";
+}
+
+bool PDefItems::LoadFromDef( PTokenList *Tokens )
+{
+ int Idx = 0;
+ for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+ {
+ switch ( Idx )
+ {
+ case 0: // setentry
+ continue;
+ case 1: // index
+ mIndex = atoi( i->c_str() ); break;
+ case 2: // name
+ mName = *i; break;
+ case 3:
+ mModel = atoi(i->c_str()); // used for IG display
+ break;
+ case 4:
+ mType = atoi( i->c_str() ); break;
+ case 5:
+ mValue1 = atoi( i->c_str() ); break;
+ case 6:
+ mValue2 = atoi( i->c_str() ); break;
+ case 7:
+ mValue3 = atoi( i->c_str() ); break;
+ case 8:
+ // mBmNum = atoi(i->c_str()); // used IG for inventory display
+ break;
+ case 9:
+ // mmBmNumIndex = atoi(i->c_str()); // used IG for inventory display
+ break;
+ case 10:
+ mSizeX = atoi( i->c_str() ); break;
+ case 11:
+ mSizeY = atoi( i->c_str() ); break;
+ case 12:
+ // mSmallbmnum = atoi(i->c_str()); // used IG for inventory display
+ break;
+ case 13:
+ mWeight = atof( i->c_str() ); break;
+ case 14:
+ mStackable = atoi( i->c_str() ); break;
+ case 15:
+ mFillWeight = atof( i->c_str() ); break;
+ case 16:
+ mQualifier = atoi( i->c_str() ); break;
+ case 17:
+ mGfxMods = atoi( i->c_str() ); break;
+ case 18:
+ mItemGroupID = atoi( i->c_str() ); break;
+ case 19:
+ mTextDescID = atoi( i->c_str() ); break;
+ case 20:
+ mBasePrice = atoi( i->c_str() ); break;
+ case 21:
+ mTechlevel = atoi( i->c_str() ); break;
+ case 22:
+ mItemflags = atoi( i->c_str() ); break;
+ case 23:
+ // mShortname = *i; // used IG for display on inventories Icons
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+PDefItemsMap::PDefItemsMap()
+{
+ mMapItCache = NULL;
+ mMapItCacheCount = 0;
+ mMaxItemGroupId = -1;
+}
+
+PDefItemsMap::~PDefItemsMap()
+{
+ delete [] mMapItCache;
+}
+
+void PDefItemsMap::BuildMapItCache()
+{
+ int CacheEntryIdx = 0;
+ int EntrySeqIdx = 1;
+
+ mMapItCacheCount = 1 + ( mDefs.size() / GAMEDEFS_DEFITEMSMAXSEQ );
+
+ if ( mMapItCacheCount )
+ {
+ if( mMapItCache )
+ {
+ delete [] mMapItCache;
+ }
+ mMapItCache = new std::map<int, PDefItems*>::const_iterator[mMapItCacheCount];
+ mMapItCache[CacheEntryIdx++] = mDefs.begin();
+
+ std::map<int, PDefItems*>::const_iterator It = mDefs.begin();
+ while ( It != mDefs.end() )
+ {
+ if ( EntrySeqIdx++ == GAMEDEFS_DEFITEMSMAXSEQ )
+ {
+ mMapItCache[CacheEntryIdx++] = It;
+ EntrySeqIdx = 1;
+ }
+ It++;
+ }
+ }
+}
+
+void PDefItemsMap::BuildItemGroups()
+{
+ //std::map<int, std::vector<int> > mItemGroups;
+ // Implementation more complicated than needed but avoid too many realloc
+
+ // Group size conting
+ std::map<int, int> groupSize;
+ for ( std::map<int, PDefItems*>::const_iterator i = mDefs.begin(); i != mDefs.end(); i++ )
+ groupSize[ i->second->GetItemGroupID() ]++;
+
+ // Item group vectors size reservation
+ mItemGroups.clear();
+ for ( std::map<int, int>::const_iterator i = groupSize.begin(); i != groupSize.end(); i++ )
+ {
+ mItemGroups[i->first].reserve(i->second);
+ if(i->first > mMaxItemGroupId)
+ mMaxItemGroupId = i->first;
+ //Console->Print("Item group %d : %d items", i->first, i->second);
+ }
+
+ // Effective groups building
+ for ( std::map<int, PDefItems*>::const_iterator i = mDefs.begin(); i != mDefs.end(); i++ )
+ mItemGroups[ i->second->GetItemGroupID() ].push_back(i->first); // i->first is ItemIndex
+}
+
+bool PDefItemsMap::Load(const char* nName, const char* nFilename)
+{
+ if( PDefMap<PDefItems>::Load( nName, nFilename) )
+ {
+ BuildMapItCache();
+ BuildItemGroups();
+ return ( true );
+ }
+ else
+ return ( false );
+}
+
+const PDefItems* PDefItemsMap::GetDefBySeqIndex( int nSeqIndex ) const
+{
+ int CacheEntryIdx = nSeqIndex / GAMEDEFS_DEFITEMSMAXSEQ;
+ if ( CacheEntryIdx >= mMapItCacheCount )
+ return NULL;
+
+ std::map<int, PDefItems*>::const_iterator It = mMapItCache[CacheEntryIdx];
+ int EntrySeqIdx = CacheEntryIdx * GAMEDEFS_DEFITEMSMAXSEQ;
+
+ while (( EntrySeqIdx < nSeqIndex ) && ( It != mDefs.end() ) )
+ {
+ EntrySeqIdx++;
+ It++;
+ }
+
+ if (( EntrySeqIdx == nSeqIndex ) && ( It != mDefs.end() ) )
+ {
+ return It->second;
+ }
+ else
+ return NULL;
+}
+
+int PDefItemsMap::GetRandomItemIdFromGroup( int nGroupId ) const
+{
+ if( (nGroupId >= 0) && (nGroupId <= mMaxItemGroupId) )
+ {
+ std::map<int, std::vector<int> >::const_iterator selectedEntry = mItemGroups.find(nGroupId);
+ if(selectedEntry != mItemGroups.end())
+ {
+ int groupSize = selectedEntry->second.size();
+ if( groupSize )
+ {
+ return selectedEntry->second[GetRandom(groupSize - 1, 0)];
+ }
+ }
+ }
+
+ return 0;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <map>\r
-#include "GameServer/Definitions/Definition.hxx"\r
-\r
-class PDefItems : public PDef {\r
-private:\r
- //int32_t mIndex;//1\r
- std::string mName;//2\r
- int32_t mModel; // used for IG display\r
- int32_t mType;\r
- int32_t mValue1;\r
- int32_t mValue2;\r
- int32_t mValue3;\r
- // int32_t mBmNum; // used IG for inventory display\r
- // int32_t mmBmNumIndex; // used IG for inventory display\r
- int32_t mSizeX;\r
- int32_t mSizeY;\r
- // int32_t mSmallbmnum; // used IG for inventory display\r
- float mWeight;\r
- int32_t mStackable;\r
- float mFillWeight;\r
- int32_t mQualifier;\r
- int32_t mGfxMods;\r
- int32_t mItemGroupID;\r
- int32_t mTextDescID;\r
- int32_t mBasePrice;\r
- int32_t mTechlevel;\r
- int32_t mItemflags;\r
- // std::mShortname; // used IG for display on inventories Icons\r
-\r
-public:\r
- PDefItems();\r
- //~PDefItems();\r
-\r
- bool LoadFromDef(PTokenList *Tokens);\r
-\r
- inline const std::string &GetName() const { return mName; }\r
- inline int32_t GetModel() const { return mModel; }\r
- inline int32_t GetType() const { return mType; }\r
- inline int32_t GetValue1() const { return mValue1; }\r
- inline int32_t GetValue2() const { return mValue2; }\r
- inline int32_t GetValue3() const { return mValue3; }\r
- inline int32_t GetSizeX() const { return mSizeX; }\r
- inline int32_t GetSizeY() const { return mSizeY; }\r
- inline float GetWeight() const { return mWeight; }\r
- inline bool IsStackable() const { return (mStackable == 1); }\r
- inline float GetFillWeight() const { return mFillWeight; }\r
- inline int32_t GetQualifier() const { return mQualifier; }\r
- inline int32_t GetGfxMods() const { return mGfxMods; }\r
- inline int32_t GetItemGroupID() const { return mItemGroupID; }\r
- inline int32_t GetTextDescID() const { return mTextDescID; }\r
- inline int32_t GetBasePrice() const { return mBasePrice; }\r
- inline int32_t GetTechlevel() const { return mTechlevel; }\r
- inline int32_t GetItemflags() const { return mItemflags; }\r
-};\r
-\r
-class PDefItemsMap : public PDefMap<PDefItems> {\r
-private:\r
- std::map<int32_t, PDefItems*>::const_iterator* mMapItCache;\r
- int32_t mMapItCacheCount;\r
- std::map<int32_t, std::vector<int32_t> > mItemGroups;\r
- int32_t mMaxItemGroupId;\r
- void BuildMapItCache();\r
- void BuildItemGroups();\r
-\r
-public:\r
- PDefItemsMap();\r
- ~PDefItemsMap();\r
- bool Load(const char* nName, const char* nFilename);\r
- const PDefItems* GetDefBySeqIndex( int32_t nSeqIndex ) const;\r
- int32_t GetRandomItemIdFromGroup( int32_t nGroupId ) const;\r
-\r
- inline std::map<int32_t, PDefItems*>::const_iterator ConstIteratorBegin() const { return mDefs.begin(); }\r
- inline std::map<int32_t, PDefItems*>::const_iterator ConstIteratorEnd() const { return mDefs.end(); }\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <map>
+#include "GameServer/Definitions/Definition.hxx"
+
+class PDefItems : public PDef {
+private:
+ //int32_t mIndex;//1
+ std::string mName;//2
+ int32_t mModel; // used for IG display
+ int32_t mType;
+ int32_t mValue1;
+ int32_t mValue2;
+ int32_t mValue3;
+ // int32_t mBmNum; // used IG for inventory display
+ // int32_t mmBmNumIndex; // used IG for inventory display
+ int32_t mSizeX;
+ int32_t mSizeY;
+ // int32_t mSmallbmnum; // used IG for inventory display
+ float mWeight;
+ int32_t mStackable;
+ float mFillWeight;
+ int32_t mQualifier;
+ int32_t mGfxMods;
+ int32_t mItemGroupID;
+ int32_t mTextDescID;
+ int32_t mBasePrice;
+ int32_t mTechlevel;
+ int32_t mItemflags;
+ // std::mShortname; // used IG for display on inventories Icons
+
+public:
+ PDefItems();
+ //~PDefItems();
+
+ bool LoadFromDef(PTokenList *Tokens);
+
+ inline const std::string &GetName() const { return mName; }
+ inline int32_t GetModel() const { return mModel; }
+ inline int32_t GetType() const { return mType; }
+ inline int32_t GetValue1() const { return mValue1; }
+ inline int32_t GetValue2() const { return mValue2; }
+ inline int32_t GetValue3() const { return mValue3; }
+ inline int32_t GetSizeX() const { return mSizeX; }
+ inline int32_t GetSizeY() const { return mSizeY; }
+ inline float GetWeight() const { return mWeight; }
+ inline bool IsStackable() const { return (mStackable == 1); }
+ inline float GetFillWeight() const { return mFillWeight; }
+ inline int32_t GetQualifier() const { return mQualifier; }
+ inline int32_t GetGfxMods() const { return mGfxMods; }
+ inline int32_t GetItemGroupID() const { return mItemGroupID; }
+ inline int32_t GetTextDescID() const { return mTextDescID; }
+ inline int32_t GetBasePrice() const { return mBasePrice; }
+ inline int32_t GetTechlevel() const { return mTechlevel; }
+ inline int32_t GetItemflags() const { return mItemflags; }
+};
+
+class PDefItemsMap : public PDefMap<PDefItems> {
+private:
+ std::map<int32_t, PDefItems*>::const_iterator* mMapItCache;
+ int32_t mMapItCacheCount;
+ std::map<int32_t, std::vector<int32_t> > mItemGroups;
+ int32_t mMaxItemGroupId;
+ void BuildMapItCache();
+ void BuildItemGroups();
+
+public:
+ PDefItemsMap();
+ ~PDefItemsMap();
+ bool Load(const char* nName, const char* nFilename);
+ const PDefItems* GetDefBySeqIndex( int32_t nSeqIndex ) const;
+ int32_t GetRandomItemIdFromGroup( int32_t nGroupId ) const;
+
+ inline std::map<int32_t, PDefItems*>::const_iterator ConstIteratorBegin() const { return mDefs.begin(); }
+ inline std::map<int32_t, PDefItems*>::const_iterator ConstIteratorEnd() const { return mDefs.end(); }
+};
-#include "GameServer/Definitions/Includes.hxx"\r
-#include "GameServer/Includes.hxx"\r
-\r
-PDefParser::PDefParser()\r
-{\r
-}\r
-\r
-PDefParser::~PDefParser()\r
-{\r
- for(PDefTokenList::iterator i=mTokens.begin(); i!=mTokens.end(); i++)\r
- delete *i;\r
-}\r
-\r
-bool PDefParser::Parse(const char *File)\r
-{\r
- PFile *f = Filesystem->Open("", File, Config->GetOption("nc_data_path"));\r
- enum { NOPE, MAYBE, LINE, BLOCK, MAYBE_END } Comment = NOPE;\r
-\r
- if(f)\r
- {\r
- while(!f->Eof())\r
- {\r
- std::string Str = f->ReadString();\r
- int Len = Str.length();\r
- if(Len <= 0)\r
- continue;\r
-\r
- if(Str.substr(0, 3)!="set")\r
- continue;\r
-\r
- //Console->Print("%s", Str.c_str());//NEW was commented , just to be sure of what we are reading\r
-\r
- PTokenList *List = new PTokenList();\r
- int Start=0, Tokens=0;\r
- bool Quote=false;\r
- for(int i=0; i<Len; i++)\r
- {\r
- if(Str[i]=='\r' || Str[i]=='\n' || Str[i]=='|' || Str[i]==';')\r
- {\r
- if(Comment < LINE)\r
- {\r
- int End=i-1;\r
- if(End >= Start)\r
- {\r
- List->push_back(std::string(Str.substr(Start, (End-Start)+1)));\r
- Tokens++;\r
- break;\r
- }\r
- Quote=false;\r
- }\r
- if(Comment != BLOCK)\r
- Comment=NOPE;\r
- break;\r
- }\r
-\r
- if(!Quote)\r
- {\r
- if(Comment < LINE && (Str[i]=='\t' || Str[i]==',' || Str[i]==' ' || Str[i]==';' || Str[i]=='|' || i==Len-1))\r
- {\r
- int End=i-1;\r
- if(End >= Start)\r
- {\r
- List->push_back(std::string(Str.substr(Start, (End-Start)+1)));\r
- Tokens++;\r
- }\r
- Start=i+1;\r
- }\r
-\r
- if(Str[i] <= ' ')\r
- continue;\r
-\r
- if(Str[i]=='*')\r
- {\r
- if(Comment==MAYBE)\r
- Comment=BLOCK;\r
- else\r
- if(Comment==BLOCK)\r
- Comment=MAYBE_END;\r
- } else\r
- if(Str[i]=='/')\r
- {\r
- if(Comment==MAYBE)\r
- {\r
- // second slash, skip rest of line\r
- Comment=LINE;\r
- break;\r
- } else\r
- if(Comment==MAYBE_END)\r
- {\r
- Comment=NOPE; // comment block ends\r
- Start=i+1;\r
- } else\r
- if(Comment != BLOCK)\r
- Comment=MAYBE; // first slash\r
- } else\r
- {\r
- if(Comment==MAYBE)\r
- Comment=NOPE; // stand-alone slash\r
- else\r
- if(Comment==MAYBE_END)\r
- Comment=BLOCK; // comment block did not end\r
- }\r
- }\r
-\r
- if(Str[i]=='"')\r
- Quote ^= true;\r
- }\r
-\r
- if(Tokens > 0)\r
- mTokens.push_back(List);\r
- else\r
- delete List;\r
- }\r
- } else\r
- {\r
- Console->Print("%s PDefParser::Parse: could not open file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), File);\r
- return false;\r
- }\r
-\r
- return true;\r
-}\r
+#include "GameServer/Definitions/Includes.hxx"
+#include "GameServer/Includes.hxx"
+
+PDefParser::PDefParser()
+{
+}
+
+PDefParser::~PDefParser()
+{
+ for(PDefTokenList::iterator i=mTokens.begin(); i!=mTokens.end(); i++)
+ delete *i;
+}
+
+bool PDefParser::Parse(const char *File)
+{
+ PFile *f = Filesystem->Open("", File, Config->GetOption("nc_data_path"));
+ enum { NOPE, MAYBE, LINE, BLOCK, MAYBE_END } Comment = NOPE;
+
+ if(f)
+ {
+ while(!f->Eof())
+ {
+ std::string Str = f->ReadString();
+ int Len = Str.length();
+ if(Len <= 0)
+ continue;
+
+ if(Str.substr(0, 3)!="set")
+ continue;
+
+ //Console->Print("%s", Str.c_str());//NEW was commented , just to be sure of what we are reading
+
+ PTokenList *List = new PTokenList();
+ int Start=0, Tokens=0;
+ bool Quote=false;
+ for(int i=0; i<Len; i++)
+ {
+ if(Str[i]=='\r' || Str[i]=='\n' || Str[i]=='|' || Str[i]==';')
+ {
+ if(Comment < LINE)
+ {
+ int End=i-1;
+ if(End >= Start)
+ {
+ List->push_back(std::string(Str.substr(Start, (End-Start)+1)));
+ Tokens++;
+ break;
+ }
+ Quote=false;
+ }
+ if(Comment != BLOCK)
+ Comment=NOPE;
+ break;
+ }
+
+ if(!Quote)
+ {
+ if(Comment < LINE && (Str[i]=='\t' || Str[i]==',' || Str[i]==' ' || Str[i]==';' || Str[i]=='|' || i==Len-1))
+ {
+ int End=i-1;
+ if(End >= Start)
+ {
+ List->push_back(std::string(Str.substr(Start, (End-Start)+1)));
+ Tokens++;
+ }
+ Start=i+1;
+ }
+
+ if(Str[i] <= ' ')
+ continue;
+
+ if(Str[i]=='*')
+ {
+ if(Comment==MAYBE)
+ Comment=BLOCK;
+ else
+ if(Comment==BLOCK)
+ Comment=MAYBE_END;
+ } else
+ if(Str[i]=='/')
+ {
+ if(Comment==MAYBE)
+ {
+ // second slash, skip rest of line
+ Comment=LINE;
+ break;
+ } else
+ if(Comment==MAYBE_END)
+ {
+ Comment=NOPE; // comment block ends
+ Start=i+1;
+ } else
+ if(Comment != BLOCK)
+ Comment=MAYBE; // first slash
+ } else
+ {
+ if(Comment==MAYBE)
+ Comment=NOPE; // stand-alone slash
+ else
+ if(Comment==MAYBE_END)
+ Comment=BLOCK; // comment block did not end
+ }
+ }
+
+ if(Str[i]=='"')
+ Quote ^= true;
+ }
+
+ if(Tokens > 0)
+ mTokens.push_back(List);
+ else
+ delete List;
+ }
+ } else
+ {
+ Console->Print("%s PDefParser::Parse: could not open file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), File);
+ return false;
+ }
+
+ return true;
+}
-#pragma once\r
-\r
-#include <list>\r
-#include <string>\r
-\r
-typedef std::list<std::string> PTokenList;\r
-typedef std::list<PTokenList *> PDefTokenList;\r
-\r
-class PDefParser {\r
-private:\r
- PDefTokenList mTokens;\r
-\r
-public:\r
- PDefParser();\r
- ~PDefParser();\r
- bool Parse(const char *File);\r
- inline const PDefTokenList &GetTokens() const { return mTokens; }\r
-};\r
+#pragma once
+
+#include <list>
+#include <string>
+
+typedef std::list<std::string> PTokenList;
+typedef std::list<PTokenList *> PDefTokenList;
+
+class PDefParser {
+private:
+ PDefTokenList mTokens;
+
+public:
+ PDefParser();
+ ~PDefParser();
+ bool Parse(const char *File);
+ inline const PDefTokenList &GetTokens() const { return mTokens; }
+};
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-PDefRespawn::PDefRespawn()\r
-{\r
-}\r
-\r
-bool PDefRespawn::LoadFromDef( PTokenList *Tokens )\r
-{\r
- int Idx = 0;\r
- for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )\r
- {\r
- switch ( Idx )\r
- {\r
- case 0: // setentry\r
- continue;\r
-\r
- case 1: // index\r
- mIndex = atoi( i->c_str() ); break;\r
-\r
- case 2: // value\r
- mWorldID = atoi( i->c_str() ); break;\r
-\r
- case 3: // value\r
- mEntityID = atoi( i->c_str() ); break;\r
-\r
- case 4: // value\r
- mHazardLevel = atoi( i->c_str() ); break;\r
-\r
- case 5: // name\r
- mName = *i; break;\r
-\r
- case 6: // world name\r
- mFlag = *i; break;\r
- }\r
- }\r
-\r
- return true;\r
-}\r
-\r
-// class PDefRespawnMap defined in gamedefs.h\r
-int PDefRespawnsMap::GetRespawnEntity( uint32_t nWorldID, uint16_t nGROrder ) const\r
-{\r
- uint16_t tOrder = 0;\r
-\r
- for ( std::map<int, PDefRespawn*>::const_iterator it = mDefs.begin(); it != mDefs.end(); it++ )\r
- {\r
- if (( uint32_t )( it->second->GetWorldID() ) == nWorldID )\r
- {\r
- ++tOrder;\r
- if (( nWorldID == 1 ) || ( nWorldID == 2 ) ) // hack for zones 1 & 2\r
- {\r
- if (( 3 - tOrder ) == nGROrder )\r
- {\r
- return ( it->second->GetEntityID() );\r
- }\r
- }\r
- else if ( tOrder == nGROrder )\r
- {\r
- return ( it->second->GetEntityID() );\r
- }\r
- }\r
- }\r
- return 0;\r
-}\r
+#include "GameServer/Definitions/Includes.hxx"
+
+PDefRespawn::PDefRespawn()
+{
+}
+
+bool PDefRespawn::LoadFromDef( PTokenList *Tokens )
+{
+ int Idx = 0;
+ for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+ {
+ switch ( Idx )
+ {
+ case 0: // setentry
+ continue;
+
+ case 1: // index
+ mIndex = atoi( i->c_str() ); break;
+
+ case 2: // value
+ mWorldID = atoi( i->c_str() ); break;
+
+ case 3: // value
+ mEntityID = atoi( i->c_str() ); break;
+
+ case 4: // value
+ mHazardLevel = atoi( i->c_str() ); break;
+
+ case 5: // name
+ mName = *i; break;
+
+ case 6: // world name
+ mFlag = *i; break;
+ }
+ }
+
+ return true;
+}
+
+// class PDefRespawnMap defined in gamedefs.h
+int PDefRespawnsMap::GetRespawnEntity( uint32_t nWorldID, uint16_t nGROrder ) const
+{
+ uint16_t tOrder = 0;
+
+ for ( std::map<int, PDefRespawn*>::const_iterator it = mDefs.begin(); it != mDefs.end(); it++ )
+ {
+ if (( uint32_t )( it->second->GetWorldID() ) == nWorldID )
+ {
+ ++tOrder;
+ if (( nWorldID == 1 ) || ( nWorldID == 2 ) ) // hack for zones 1 & 2
+ {
+ if (( 3 - tOrder ) == nGROrder )
+ {
+ return ( it->second->GetEntityID() );
+ }
+ }
+ else if ( tOrder == nGROrder )
+ {
+ return ( it->second->GetEntityID() );
+ }
+ }
+ }
+ return 0;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-#include "GameServer/Definitions/Definition.hxx"\r
-\r
-class PDefRespawn : public PDef {\r
-private:\r
- //int32_t mIndex;\r
- int32_t mWorldID;\r
- int32_t mEntityID; // Station ID\r
- int32_t mHazardLevel;\r
- std::string mName; // Description\r
- std::string mFlag; // ???\r
-\r
-public:\r
- PDefRespawn();\r
- //~PDefRespawn();\r
-\r
- bool LoadFromDef(PTokenList *Tokens);\r
-\r
- inline int32_t GetWorldID() const { return mWorldID; }\r
- inline int32_t GetEntityID() const { return mEntityID; }\r
- inline int32_t GetHazardLevel() const { return mHazardLevel; }\r
- inline const std::string &GetName() const { return mName; }\r
- inline const std::string &GetFlag() const { return mFlag; }\r
-};\r
-\r
-class PDefRespawnsMap : public PDefMap<PDefRespawn> {\r
-public:\r
- int32_t GetRespawnEntity( uint32_t nWorldID, uint16_t nGROrder ) const;\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include "GameServer/Definitions/Definition.hxx"
+
+class PDefRespawn : public PDef {
+private:
+ //int32_t mIndex;
+ int32_t mWorldID;
+ int32_t mEntityID; // Station ID
+ int32_t mHazardLevel;
+ std::string mName; // Description
+ std::string mFlag; // ???
+
+public:
+ PDefRespawn();
+ //~PDefRespawn();
+
+ bool LoadFromDef(PTokenList *Tokens);
+
+ inline int32_t GetWorldID() const { return mWorldID; }
+ inline int32_t GetEntityID() const { return mEntityID; }
+ inline int32_t GetHazardLevel() const { return mHazardLevel; }
+ inline const std::string &GetName() const { return mName; }
+ inline const std::string &GetFlag() const { return mFlag; }
+};
+
+class PDefRespawnsMap : public PDefMap<PDefRespawn> {
+public:
+ int32_t GetRespawnEntity( uint32_t nWorldID, uint16_t nGROrder ) const;
+};
-#include <cstring>\r
-#include "GameServer/Definitions/Includes.hxx"\r
-#include "GameServer/Includes.hxx"\r
-\r
-// skill.def includes skill names and skill/subskill mapping\r
-\r
-PDefSkill::PDefSkill()\r
-{\r
- mSubSkills = 0;\r
- mNumSubSkills = 0;\r
-}\r
-\r
-PDefSkill::~PDefSkill()\r
-{\r
- delete [] mSubSkills;\r
-}\r
-\r
-bool PDefSkill::LoadFromDef(PTokenList *Tokens)\r
-{\r
- int Idx=0;\r
- for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
- {\r
- switch(Idx)\r
- {\r
- case 0 : // setentry\r
- continue;\r
-\r
- case 1 :\r
- mIndex = atol(i->c_str()); break;\r
-\r
- case 2 :\r
- mName = *i; break;\r
-\r
- case 3 :\r
- mShortName = *i; break;\r
-\r
- case 4 :\r
- {\r
- mNumSubSkills = atol(i->c_str());\r
- mSubSkills = new int[mNumSubSkills];\r
- std::memset(mSubSkills, 0, sizeof(int)*mNumSubSkills);\r
- break;\r
- }\r
- }\r
-\r
- if(Idx >= 5)\r
- {\r
- mSubSkills[Idx-5] = atoi(i->c_str());\r
- if(!GameDefs->SubSkills()->GetDef(mSubSkills[Idx-5]))\r
- {\r
- Console->Print("Skill def error: skill %s refers to nonexistant subskill %i", mShortName.c_str(), mSubSkills[Idx-5]);\r
- return false;\r
- }\r
- }\r
- }\r
-\r
- if(Idx-5 != mNumSubSkills)\r
- {\r
- Console->Print("Warning: skill %s has incorrect number of subskills", mShortName.c_str());\r
- Console->Print(" Expected %i, available %i", mNumSubSkills, Idx-5);\r
- }\r
- return true;\r
-}\r
+#include <cstring>
+#include "GameServer/Definitions/Includes.hxx"
+#include "GameServer/Includes.hxx"
+
+// skill.def includes skill names and skill/subskill mapping
+
+PDefSkill::PDefSkill()
+{
+ mSubSkills = 0;
+ mNumSubSkills = 0;
+}
+
+PDefSkill::~PDefSkill()
+{
+ delete [] mSubSkills;
+}
+
+bool PDefSkill::LoadFromDef(PTokenList *Tokens)
+{
+ int Idx=0;
+ for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)
+ {
+ switch(Idx)
+ {
+ case 0 : // setentry
+ continue;
+
+ case 1 :
+ mIndex = atol(i->c_str()); break;
+
+ case 2 :
+ mName = *i; break;
+
+ case 3 :
+ mShortName = *i; break;
+
+ case 4 :
+ {
+ mNumSubSkills = atol(i->c_str());
+ mSubSkills = new int[mNumSubSkills];
+ std::memset(mSubSkills, 0, sizeof(int)*mNumSubSkills);
+ break;
+ }
+ }
+
+ if(Idx >= 5)
+ {
+ mSubSkills[Idx-5] = atoi(i->c_str());
+ if(!GameDefs->SubSkills()->GetDef(mSubSkills[Idx-5]))
+ {
+ Console->Print("Skill def error: skill %s refers to nonexistant subskill %i", mShortName.c_str(), mSubSkills[Idx-5]);
+ return false;
+ }
+ }
+ }
+
+ if(Idx-5 != mNumSubSkills)
+ {
+ Console->Print("Warning: skill %s has incorrect number of subskills", mShortName.c_str());
+ Console->Print(" Expected %i, available %i", mNumSubSkills, Idx-5);
+ }
+ return true;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-#include "GameServer/Definitions/Definition.hxx"\r
-\r
-class PDefSkill : public PDef {\r
-private:\r
- //int32_t mIndex;\r
- std::string mName;\r
- std::string mShortName;\r
- int32_t mNumSubSkills;\r
- int32_t *mSubSkills;\r
-public:\r
- PDefSkill();\r
- ~PDefSkill();\r
-\r
- bool LoadFromDef(PTokenList *Tokens);\r
-\r
- inline const std::string &GetName() const { return mName; }\r
- inline const std::string &GetShortName() const { return mShortName; }\r
- inline int32_t GetNumSubSkills() const { return mNumSubSkills; }\r
- inline int32_t GetSubSkill(int32_t Index) const { return mSubSkills[Index]; }\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include "GameServer/Definitions/Definition.hxx"
+
+class PDefSkill : public PDef {
+private:
+ //int32_t mIndex;
+ std::string mName;
+ std::string mShortName;
+ int32_t mNumSubSkills;
+ int32_t *mSubSkills;
+public:
+ PDefSkill();
+ ~PDefSkill();
+
+ bool LoadFromDef(PTokenList *Tokens);
+
+ inline const std::string &GetName() const { return mName; }
+ inline const std::string &GetShortName() const { return mShortName; }
+ inline int32_t GetNumSubSkills() const { return mNumSubSkills; }
+ inline int32_t GetSubSkill(int32_t Index) const { return mSubSkills[Index]; }
+};
-#include <cstring>\r
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-// subskill.def, names and parameters of all subskills\r
-\r
-PDefSubSkill::PDefSubSkill()\r
-{\r
- mActionModifiers = 0;\r
- mNumActionModifiers = 0;\r
-}\r
-\r
-PDefSubSkill::~PDefSubSkill()\r
-{\r
- delete [] mActionModifiers;\r
-}\r
-\r
-bool PDefSubSkill::LoadFromDef(PTokenList *Tokens)\r
-{\r
- int Idx=0;\r
- for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
- {\r
- switch(Idx)\r
- {\r
- case 0 : // setentry\r
- continue;\r
-\r
- case 1 :\r
- mIndex = atoi(i->c_str()); break;\r
-\r
- case 2 :\r
- mName = *i; break;\r
-\r
- case 3 :\r
- mShortName = *i; break;\r
-\r
- case 4 :\r
- mStrengthenFactor = static_cast<float>(atof(i->c_str())); break;\r
-\r
- case 5 :\r
- {\r
- mNumActionModifiers = atoi(i->c_str());\r
- mActionModifiers = new int[mNumActionModifiers];\r
- std::memset(mActionModifiers, 0, sizeof(int)*mNumActionModifiers);\r
- break;\r
- }\r
- }\r
-\r
- if(Idx>=6)\r
- mActionModifiers[Idx-6] = atoi(i->c_str());\r
- }\r
-\r
- return true;\r
-}\r
-\r
+#include <cstring>
+#include "GameServer/Definitions/Includes.hxx"
+
+// subskill.def, names and parameters of all subskills
+
+PDefSubSkill::PDefSubSkill()
+{
+ mActionModifiers = 0;
+ mNumActionModifiers = 0;
+}
+
+PDefSubSkill::~PDefSubSkill()
+{
+ delete [] mActionModifiers;
+}
+
+bool PDefSubSkill::LoadFromDef(PTokenList *Tokens)
+{
+ int Idx=0;
+ for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)
+ {
+ switch(Idx)
+ {
+ case 0 : // setentry
+ continue;
+
+ case 1 :
+ mIndex = atoi(i->c_str()); break;
+
+ case 2 :
+ mName = *i; break;
+
+ case 3 :
+ mShortName = *i; break;
+
+ case 4 :
+ mStrengthenFactor = static_cast<float>(atof(i->c_str())); break;
+
+ case 5 :
+ {
+ mNumActionModifiers = atoi(i->c_str());
+ mActionModifiers = new int[mNumActionModifiers];
+ std::memset(mActionModifiers, 0, sizeof(int)*mNumActionModifiers);
+ break;
+ }
+ }
+
+ if(Idx>=6)
+ mActionModifiers[Idx-6] = atoi(i->c_str());
+ }
+
+ return true;
+}
+
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-#include "GameServer/Definitions/Definition.hxx"\r
-\r
-class PDefSubSkill : public PDef {\r
-private:\r
- //int32_t mIndex;\r
- std::string mName;\r
- std::string mShortName;\r
- float mStrengthenFactor;\r
- int32_t mNumActionModifiers;\r
- int32_t *mActionModifiers;\r
-\r
-public:\r
- PDefSubSkill();\r
- ~PDefSubSkill();\r
-\r
- bool LoadFromDef(PTokenList *Tokens);\r
-\r
- inline const std::string &GetName() const { return mName; }\r
- inline const std::string &GetShortName() const { return mShortName; }\r
- inline float GetStrengthenFactor() const { return mStrengthenFactor; }\r
- inline int32_t GetNumActionModifiers() const { return mNumActionModifiers; }\r
- inline int32_t GetActionModifier(int32_t Index) const { return mActionModifiers[Index]; }\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include "GameServer/Definitions/Definition.hxx"
+
+class PDefSubSkill : public PDef {
+private:
+ //int32_t mIndex;
+ std::string mName;
+ std::string mShortName;
+ float mStrengthenFactor;
+ int32_t mNumActionModifiers;
+ int32_t *mActionModifiers;
+
+public:
+ PDefSubSkill();
+ ~PDefSubSkill();
+
+ bool LoadFromDef(PTokenList *Tokens);
+
+ inline const std::string &GetName() const { return mName; }
+ inline const std::string &GetShortName() const { return mShortName; }
+ inline float GetStrengthenFactor() const { return mStrengthenFactor; }
+ inline int32_t GetNumActionModifiers() const { return mNumActionModifiers; }
+ inline int32_t GetActionModifier(int32_t Index) const { return mActionModifiers[Index]; }
+};
-#include <cmath>\r
-#include <cstring>\r
-#include "GameServer/Definitions/Includes.hxx"\r
-#include "GameServer/Includes.hxx"\r
-\r
-const uint16_t nonDiscardUseFlags = ufTouchable | ufUsable | ufChair | ufToolTarget ; // furniture always to keep even if function type = 0\r
-\r
-PWorldDatParser::PWorldDatParser()\r
-{\r
- f = NULL;\r
-}\r
-\r
-PWorldDatParser::~PWorldDatParser()\r
-{\r
-\r
-}\r
-\r
-int PWorldDatParser::LoadDatFile( const std::string& nFilename, PWorldDataTemplate* nWorld, const bool nDiscardPassiveObjects, const bool nTestAccesOnly )\r
-{\r
- PWorldFileHeader FileHeader;\r
- PSectionHeader SectionHeader;\r
- PSec2ElemHeader Sec2ElemHeader;\r
-\r
- uint32_t FileLen;\r
- uint32_t NextSectionOffset = 0;\r
- uint32_t NextElementOffset;\r
- bool ProcessOK;\r
-\r
- mWorld = nWorld;\r
- mDiscardPassiveObjects = nDiscardPassiveObjects;\r
-\r
- if ( mNCDataPath == "" )\r
- {\r
- mNCDataPath = Config->GetOption( "nc_data_path" );\r
- }\r
-\r
- if ( gDevDebug )\r
- Console->Print( "Reading file %s/%s", mNCDataPath.c_str(), nFilename.c_str() );\r
- f = Filesystem->Open( "", nFilename.c_str(), mNCDataPath );\r
-\r
- if ( nTestAccesOnly )\r
- {\r
- ProcessOK = ( bool )f;\r
- Filesystem->Close( f );\r
- return ( ProcessOK ? 0 : -1 );\r
- }\r
-\r
- if ( f )\r
- {\r
- FileLen = f->GetSize();\r
-\r
- // Section 1\r
- if (gDevDebug)\r
- Console->Print( "Reading file header (section 1) ... " );\r
- f->Read( &FileHeader, sizeof( PWorldFileHeader ) );\r
- if (( FileHeader.mHeaderSize != 0x00000008 )\r
- || ( FileHeader.mHeaderSig != 0x000fcfcf )\r
- || ( FileHeader.mSection != 0x00000001 ) )\r
- {\r
- if (gDevDebug)\r
- Console->Print( "Read header: %08x / %08x / %08x", FileHeader.mHeaderSize, FileHeader.mHeaderSig, FileHeader.mSection);\r
- Filesystem->Close( f );\r
- return -2;\r
- }\r
- NextSectionOffset += FileHeader.mHeaderSize + 4;\r
-\r
- // Other Sections\r
- // Header\r
- while ( ! f->Eof() )\r
- {\r
- f->Seek( NextSectionOffset ); // Make sure we are at the computed offset\r
- if (gDevDebug)\r
- Console->Print( "Reading next section header ... " );\r
- if (( uint32_t )( f->Read( &SectionHeader, sizeof( PSectionHeader ) ) ) < sizeof( PSectionHeader ) )\r
- {\r
- Filesystem->Close( f );\r
- return -3;\r
- }\r
-\r
- if (( SectionHeader.mHeaderSize != 0x0000000c ) || ( SectionHeader.mHeaderSig != 0x0000ffcf ) )\r
- {\r
- Filesystem->Close( f );\r
- return -2;\r
- }\r
-\r
- if ( SectionHeader.mSection == 0 )\r
- {\r
- if (gDevDebug)\r
- Console->Print( "Ending section reached" );\r
- break;\r
- }\r
-\r
- NextElementOffset = NextSectionOffset + SectionHeader.mHeaderSize + 4;\r
- NextSectionOffset = NextElementOffset + SectionHeader.mDataSize;\r
- if (gDevDebug)\r
- Console->Print( "Processing section %d (size %d)", SectionHeader.mSection, SectionHeader.mDataSize );\r
-\r
- if ( SectionHeader.mSection == 2 )\r
- {\r
- //int cnt=0;\r
- if ( gDevDebug )\r
- Console->Print( "Element Type 3 size: %d or %d", sizeof( PSec2ElemType3a ), sizeof( PSec2ElemType3a ) + sizeof( PSec2ElemType3b ) );\r
- while ( NextElementOffset < NextSectionOffset )\r
- {\r
- f->Seek( NextElementOffset ); // Make sure we are at the computed offset\r
-\r
- //if ( gDevDebug )\r
- // Console->Print( "Reading next element header ... " );\r
- if (( uint32_t )( f->Read( &Sec2ElemHeader, sizeof( PSec2ElemHeader ) ) ) < sizeof( PSec2ElemHeader ) )\r
- {\r
- Filesystem->Close( f );\r
- return -3;\r
- }\r
- if (( Sec2ElemHeader.mHeaderSize != 0x0000000c ) || ( Sec2ElemHeader.mHeaderSig != 0x0ffefef1 ) )\r
- {\r
- Filesystem->Close( f );\r
- return -2;\r
- }\r
- NextElementOffset += ( Sec2ElemHeader.mHeaderSize + 4 + Sec2ElemHeader.mDataSize );\r
- //if (gDevDebug) Console->Print("Found element %d of type %d, size %d", ++cnt, Sec2ElemHeader.mElementType, Sec2ElemHeader.mDataSize);\r
- switch ( Sec2ElemHeader.mElementType )\r
- {\r
- case 1000003:\r
- {\r
- ProcessOK = ProcessSec2ElemType3( Sec2ElemHeader.mDataSize );\r
- break;\r
- }\r
- case 1000005:\r
- {\r
- ProcessOK = ProcessSec2ElemType5( Sec2ElemHeader.mDataSize );\r
- break;\r
- }\r
- case 1000006:\r
- {\r
- ProcessOK = ProcessSec2NPCEntry( Sec2ElemHeader.mDataSize );\r
- break;\r
- }\r
- default:\r
- {\r
- if (gDevDebug) Console->Print( "Ignoring SectionID %d, not supportet yet", Sec2ElemHeader.mElementType );\r
- ProcessOK = true;\r
- break;\r
- }\r
- }\r
-\r
- if ( !ProcessOK )\r
- return -4;\r
- }\r
- }\r
- else\r
- {\r
- if ( gDevDebug )\r
- Console->Print( "Section %d ignored", SectionHeader.mSection );\r
- continue;\r
- }\r
-\r
- }\r
-\r
- Filesystem->Close( f );\r
- }\r
- else\r
- {\r
- return -1;\r
- }\r
-\r
- return 0;\r
-}\r
-\r
-bool PWorldDatParser::ProcessSec2ElemType3( uint32_t nSize ) // furniture\r
-{\r
- PSec2ElemType3a DataA;\r
- PSec2ElemType3b DataB;\r
- const PDefWorldModel* nWorldModel;\r
- std::string nName;\r
- const uint32_t sza = sizeof( PSec2ElemType3a );\r
- const uint32_t szb = sizeof( PSec2ElemType3a ) + sizeof( PSec2ElemType3b );\r
-\r
- if (( nSize != szb ) && ( nSize != sza ) )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType3 (%d read vs %d or %d needed", nSize, sza, szb );\r
- return false;\r
- }\r
- if (( uint32_t )( f->Read( &DataA, sza ) ) < sza )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType3a" );\r
- return false;\r
- }\r
- if ( nSize == szb )\r
- {\r
- if (( uint32_t )( f->Read( &DataB, sizeof( PSec2ElemType3b ) ) ) < sizeof( PSec2ElemType3b ) )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType3b" );\r
- return false;\r
- }\r
- }\r
- else\r
- {\r
- DataB.mBoxLowerY = DataB.mBoxLowerZ = DataB.mBoxLowerX = 0;\r
- DataB.mBoxUpperY = DataB.mBoxUpperZ = DataB.mBoxUpperX = 0;\r
- }\r
-\r
- if ( DataA.mWorldmodelID )\r
- {\r
- nWorldModel = GameDefs->WorldModels()->GetDef( DataA.mWorldmodelID );\r
- if ( nWorldModel )\r
- nName = nWorldModel->GetName();\r
- else\r
- nName = "UNKNOWN";\r
- }\r
- else\r
- {\r
- nName = "PASSIVE";\r
- nWorldModel = NULL;\r
- }\r
-\r
- /* if (gDevDebug) {\r
- Console->Print("-------------------------------------------------------");\r
- Console->Print("%s (%d) : ID %d", nName.c_str(), DataA.mWorldmodelID, DataA.mObjectID);\r
- if (!nWorldModel) Console->Print("y:%f z:%f x:%f model %d", DataA.mPosY , DataA.mPosZ, DataA.mPosX, DataA.mModelID);\r
- Console->Print("Scale:%f Uk2:0x%08x Uk3:0x%08x", DataA.mScale, DataA.mUnknown2, DataA.mUnknown3);\r
- Console->Print("Uk4:0x%08x Uk5:0x%04x", DataA.mUnknown4, DataA.mUnknown5);\r
- //Console->Print("Ly:%f Lz:%f Lx:%f", DataB.mBoxLowerY, DataB.mBoxLowerZ, DataB.mBoxLowerX);\r
- //Console->Print("Uy:%f Uz:%f Ux:%f", DataB.mBoxUpperY, DataB.mBoxUpperZ, DataB.mBoxUpperX);\r
- }*/\r
-\r
- if (( !nWorldModel || ( !nWorldModel->GetFunctionType() && !( nWorldModel->GetUseFlags() & nonDiscardUseFlags ) ) ) && mDiscardPassiveObjects )\r
- {\r
- //if ( gDevDebug )\r
- // Console->Print( "Discarded" );\r
- return true;\r
- }\r
-\r
- PFurnitureItemTemplate* nItem = new PFurnitureItemTemplate;\r
- nItem->mObjectID = DataA.mObjectID;\r
-\r
- // The commented out values are not loaded from dat file atm because they are not used yet.\r
- nItem->mPosY = DataA.mPosY; // float pos values are kept 0-centered\r
- nItem->mPosZ = DataA.mPosZ;\r
- nItem->mPosX = DataA.mPosX;\r
-// nItem->mRotY = DataA.mRotY;\r
- nItem->mRotZ = DataA.mRotZ;\r
-// nItem->mRotX = DataA.mRotX;\r
-// nItem->mScale = DataA.mScale;\r
-// nItem->mUnknown2 = DataA.mUnknown2;\r
- nItem->mModelID = DataA.mModelID;\r
-// nItem->mUnknown3 = DataA.mUnknown3;\r
-// nItem->mUnknown4 = DataA.mUnknown4;\r
- nItem->mWorldmodelID = DataA.mWorldmodelID;\r
-// nItem->mUnknown5 = DataA.mUnknown5;\r
-\r
-// nItem->mBoxLowerY = DataB.mBoxLowerY;\r
-// nItem->mBoxLowerZ = DataB.mBoxLowerZ;\r
-// nItem->mBoxLowerX = DataB.mBoxLowerX;\r
-// nItem->mBoxUpperY = DataB.mBoxUpperY;\r
-// nItem->mBoxUpperZ = DataB.mBoxUpperZ;\r
-// nItem->mBoxUpperX = DataB.mBoxUpperX;\r
-\r
- nItem->mDefWorldModel = nWorldModel;\r
- /*uint16_t func=nWorldModel->GetFunctionType();\r
- if((func==18) || (func==20) || (func==29))\r
- Console->Print("gate model: %d", DataA.mWorldmodelID);*/\r
-\r
- float Angle = ( 180 + DataA.mRotZ ) * 3.14159 / 180;\r
- float Radius = abs(( int )(( DataB.mBoxUpperX - DataB.mBoxLowerX ) / 2 ) );\r
- if ( Radius == 0 )\r
- {\r
- Radius = 10;\r
- }\r
- Radius *= DataA.mScale;\r
- Radius += 5;\r
-\r
- // int pos values are change to match char pos scale (32000 centered)\r
- nItem->mFrontPosY = ( uint16_t )( 32000 + DataA.mPosY + Radius * sinf( Angle ) );\r
- nItem->mFrontPosZ = ( uint16_t )( 32000 + DataA.mPosZ );\r
- nItem->mFrontPosX = ( uint16_t )( 32000 + DataA.mPosX + Radius * cosf( Angle ) );\r
- nItem->mFrontLR = ( uint8_t )( 0.5 * ( DataA.mRotZ + ( DataA.mRotZ < 0 ? 360 : 0 ) ) );\r
-\r
- mWorld->AddFurnitureItem( nItem );\r
-\r
- return true;\r
-}\r
-\r
-bool PWorldDatParser::ProcessSec2ElemType5( uint32_t nSize ) // doors\r
-{\r
- PSec2ElemType5Start Data;\r
- char StringData[64];\r
-\r
- const PDefWorldModel* nWorldModel;\r
- std::string nName;\r
- char* ActorString;\r
- char* ParamString;\r
-\r
- const uint32_t sza = sizeof( PSec2ElemType5Start );\r
-\r
- if (( nSize < sza ) )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType5 (%d read vs %d needed", nSize, sza );\r
- return false;\r
- }\r
- if (( uint32_t )( f->Read( &Data, sza ) ) < sza )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType5start" );\r
- return false;\r
- }\r
- uint32_t szb = Data.mActorStringSize + Data.mParamStringSize;\r
-\r
- if ( nSize != ( sza + szb ) )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType5 (%d read vs %d needed", nSize, sza + szb );\r
- return false;\r
- }\r
- else\r
- {\r
- if ( szb > 64 )\r
- {\r
- Console->Print( RED, BLACK, "[Warning] String data too long in Sec2ElemType5 End String. End will be ignored" );\r
- szb = 64;\r
- }\r
- if (( uint32_t )( f->Read( StringData, szb ) ) < szb )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType5 End Strings" );\r
- return false;\r
- }\r
- }\r
-\r
- if ( Data.mWorldmodelID )\r
- {\r
- nWorldModel = GameDefs->WorldModels()->GetDef( Data.mWorldmodelID );\r
- if ( nWorldModel )\r
- nName = nWorldModel->GetName();\r
- else\r
- nName = "UNKNOWN";\r
- }\r
- else\r
- {\r
- nName = "PASSIVE";\r
- nWorldModel = NULL;\r
- }\r
-\r
- StringData[Data.mActorStringSize - 1] = 0;\r
- ActorString = StringData;\r
- StringData[szb - 1] = 0;\r
- ParamString = StringData + Data.mActorStringSize;\r
- /*\r
- if ( gDevDebug )\r
- {\r
- Console->Print( "-------------------------------------------------------" );\r
- Console->Print( "Door %s (%d) : ID %d", nName.c_str(), Data.mWorldmodelID, Data.mDoorID );\r
- Console->Print( "y:%f z:%f x:%f", Data.mPosY , Data.mPosZ, Data.mPosX );\r
- Console->Print( "Uk1:0x%04x Uk1bis:0x%04x Uk5:0x%04x", Data.mUnknown1, Data.mUnknown1bis, Data.mUnknown5 );\r
- Console->Print( "Type=%s Param=%s", ActorString, ParamString );\r
- }\r
- */\r
-// Let's keep knowledge of doors even without models !\r
- /* if ((!nWorldModel || (!nWorldModel->GetFunctionType() && !(nWorldModel->GetUseFlags() & nonDiscardUseFlags))) && mDiscardPassiveObjects)\r
- {\r
- if (gDevDebug) Console->Print("Discarded");\r
- if (gDevDebug)\r
- {\r
- Console->Print("Door %s (%d) : ID %d", nName.c_str(), Data.mWorldmodelID, Data.mDoorID);\r
- Console->Print("Type=%s Param=%s", ActorString, ParamString);\r
- }\r
- return true;\r
- }*/\r
-\r
- PDoorTemplate* nDoor = new PDoorTemplate;\r
- nDoor->mDoorID = Data.mDoorID;\r
-\r
- //nDoor->mUnknown1 = Data.mUnknown1; //18 00\r
- //nDoor->mUnknown1bis = Data.mUnknown1bis; //00 00 ? varies\r
- nDoor->mPosY = Data.mPosY;\r
- nDoor->mPosZ = Data.mPosZ;\r
- nDoor->mPosX = Data.mPosX;\r
- //nDoor->mUnknown5 = Data.mUnknown5; //00 00 ? second byte varies\r
- nDoor->mWorldmodelID = Data.mWorldmodelID; //door type from worldmodel.def\r
- nDoor->mDefWorldModel = nWorldModel;\r
-\r
- nDoor->SetDoorTypeName( ActorString );\r
- nDoor->SetDoorParameters( ParamString );\r
-\r
- mWorld->AddDoor( nDoor );\r
-\r
- return true;\r
-}\r
-\r
-bool PWorldDatParser::ProcessSec2NPCEntry( uint32_t nSize )\r
-{\r
- PSec2NPC_EntryPart1 tNPCPartA;\r
- PSec2NPC_EntryPart2 tNPCPartB;\r
- std::string tActorName;\r
- std::string tAngle;\r
- char tStrBuffer[64];\r
-\r
- uint32_t tSizeOfA = sizeof(tNPCPartA);\r
- uint32_t tSizeOfB = sizeof(tNPCPartB);\r
-\r
- // Are we able to read enough bytes from the file? means: CAN we safely read our entire struct from the file?\r
- if ( nSize < tSizeOfA )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Wrong size for PSec2NPC_EntryPart1 (%d read vs %d needed", nSize, tSizeOfA );\r
- return false;\r
- }\r
- // yes we can! So read it now. If we reach EOF, break\r
- if (( uint32_t )( f->Read( &tNPCPartA, tSizeOfA ) ) < tSizeOfA )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry" );\r
- return false;\r
- }\r
- // Now we have the header. lets check if we have some waypoints for this NPC\r
- // Size of entire NPC entry in file\r
- uint32_t tCompleteNPCSize = tSizeOfA + tNPCPartA.mActorStringSize + tNPCPartA.mAngleStringSize;\r
- if ( tNPCPartA.mHasAdditionalCoords > 0 )\r
- {\r
- // It has additional coords, add 'em\r
- tCompleteNPCSize += tSizeOfB*tNPCPartA.mHasAdditionalCoords;\r
- }\r
-\r
- // Do a last check if we're on the correct size\r
- if ( nSize != tCompleteNPCSize )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Wrong size for PSec2NPC_Entry (%d available vs %d expected", nSize, tCompleteNPCSize );\r
- Console->Print( RED, BLACK, "NPC ID was: %d", tNPCPartA.mNpcID);\r
- return false;\r
- }\r
- // We are. Continue reading!\r
- // Assign the 2 strings and watch out for EOF!\r
- memset(tStrBuffer, 0, 64);\r
- if (( uint32_t )( f->Read( tStrBuffer, tNPCPartA.mActorStringSize ) ) < tNPCPartA.mActorStringSize )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry mActorStringSize" );\r
- return false;\r
- }\r
- tActorName = tStrBuffer;\r
-\r
- memset(tStrBuffer, 0, 64);\r
- if (( uint32_t )( f->Read( tStrBuffer, tNPCPartA.mAngleStringSize ) ) < tNPCPartA.mAngleStringSize )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry mAngleStringSize" );\r
- return false;\r
- }\r
- tAngle = tStrBuffer;\r
-\r
- // We're done. Now create new NPC entry\r
- PNPCTemplate* tNPC = new PNPCTemplate;\r
-\r
- // and assing all that stuff\r
- tNPC->SetUnknown1(tNPCPartA.mUnknown1);\r
- tNPC->SetPosX(tNPCPartA.mPosX);\r
- tNPC->SetPosY(tNPCPartA.mPosY);\r
- tNPC->SetPosZ(tNPCPartA.mPosZ);\r
- tNPC->SetNPCTypeID(tNPCPartA.mNPCTypeID);\r
- tNPC->SetActorStrSize(tNPCPartA.mActorStringSize);\r
- tNPC->SetAngleStrSize(tNPCPartA.mAngleStringSize);\r
- tNPC->SetNpcID(tNPCPartA.mNpcID);\r
- tNPC->SetUnknown2a(tNPCPartA.mUnknown2a);\r
- tNPC->SetUnknown2b(tNPCPartA.mUnknown2b);\r
- tNPC->SetUnknown2c(tNPCPartA.mUnknown2c);\r
- tNPC->SetTradeID/*SetUnknown3*/(tNPCPartA.mTradeID/*mUnknown3*/);\r
- tNPC->SetUnknown4(tNPCPartA.mUnknown4);\r
-\r
- tNPC->SetActorName(tActorName);\r
- tNPC->SetAngle(tAngle);\r
-\r
- // Read additional Waypoints if available\r
- uint8_t tCurrWayP = 0;\r
- if ( tNPCPartA.mHasAdditionalCoords > 0 )\r
- {\r
- while ( tCurrWayP < tNPCPartA.mHasAdditionalCoords )\r
- {\r
- memset(&tNPCPartB, 0, tSizeOfB);\r
- if (( uint32_t )( f->Read( &tNPCPartB, tSizeOfB ) ) < tSizeOfB )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry while reading WayPoints" );\r
- return false;\r
- }\r
- tNPC->AddWayPoint(tNPCPartB.mPosX, tNPCPartB.mPosY, tNPCPartB.mPosZ, tCurrWayP);\r
- tCurrWayP++;\r
- }\r
- }\r
-\r
- if (gDevDebug) Console->Print("Added NPC ID %d", tNPCPartA.mNpcID);\r
-\r
- mWorld->AddNPC(tNPC);\r
- return true;\r
-}\r
+#include <cmath>
+#include <cstring>
+#include "GameServer/Definitions/Includes.hxx"
+#include "GameServer/Includes.hxx"
+
+const uint16_t nonDiscardUseFlags = ufTouchable | ufUsable | ufChair | ufToolTarget ; // furniture always to keep even if function type = 0
+
+PWorldDatParser::PWorldDatParser()
+{
+ f = NULL;
+}
+
+PWorldDatParser::~PWorldDatParser()
+{
+
+}
+
+int PWorldDatParser::LoadDatFile( const std::string& nFilename, PWorldDataTemplate* nWorld, const bool nDiscardPassiveObjects, const bool nTestAccesOnly )
+{
+ PWorldFileHeader FileHeader;
+ PSectionHeader SectionHeader;
+ PSec2ElemHeader Sec2ElemHeader;
+
+ uint32_t FileLen;
+ uint32_t NextSectionOffset = 0;
+ uint32_t NextElementOffset;
+ bool ProcessOK;
+
+ mWorld = nWorld;
+ mDiscardPassiveObjects = nDiscardPassiveObjects;
+
+ if ( mNCDataPath == "" )
+ {
+ mNCDataPath = Config->GetOption( "nc_data_path" );
+ }
+
+ if ( gDevDebug )
+ Console->Print( "Reading file %s/%s", mNCDataPath.c_str(), nFilename.c_str() );
+ f = Filesystem->Open( "", nFilename.c_str(), mNCDataPath );
+
+ if ( nTestAccesOnly )
+ {
+ ProcessOK = ( bool )f;
+ Filesystem->Close( f );
+ return ( ProcessOK ? 0 : -1 );
+ }
+
+ if ( f )
+ {
+ FileLen = f->GetSize();
+
+ // Section 1
+ if (gDevDebug)
+ Console->Print( "Reading file header (section 1) ... " );
+ f->Read( &FileHeader, sizeof( PWorldFileHeader ) );
+ if (( FileHeader.mHeaderSize != 0x00000008 )
+ || ( FileHeader.mHeaderSig != 0x000fcfcf )
+ || ( FileHeader.mSection != 0x00000001 ) )
+ {
+ if (gDevDebug)
+ Console->Print( "Read header: %08x / %08x / %08x", FileHeader.mHeaderSize, FileHeader.mHeaderSig, FileHeader.mSection);
+ Filesystem->Close( f );
+ return -2;
+ }
+ NextSectionOffset += FileHeader.mHeaderSize + 4;
+
+ // Other Sections
+ // Header
+ while ( ! f->Eof() )
+ {
+ f->Seek( NextSectionOffset ); // Make sure we are at the computed offset
+ if (gDevDebug)
+ Console->Print( "Reading next section header ... " );
+ if (( uint32_t )( f->Read( &SectionHeader, sizeof( PSectionHeader ) ) ) < sizeof( PSectionHeader ) )
+ {
+ Filesystem->Close( f );
+ return -3;
+ }
+
+ if (( SectionHeader.mHeaderSize != 0x0000000c ) || ( SectionHeader.mHeaderSig != 0x0000ffcf ) )
+ {
+ Filesystem->Close( f );
+ return -2;
+ }
+
+ if ( SectionHeader.mSection == 0 )
+ {
+ if (gDevDebug)
+ Console->Print( "Ending section reached" );
+ break;
+ }
+
+ NextElementOffset = NextSectionOffset + SectionHeader.mHeaderSize + 4;
+ NextSectionOffset = NextElementOffset + SectionHeader.mDataSize;
+ if (gDevDebug)
+ Console->Print( "Processing section %d (size %d)", SectionHeader.mSection, SectionHeader.mDataSize );
+
+ if ( SectionHeader.mSection == 2 )
+ {
+ //int cnt=0;
+ if ( gDevDebug )
+ Console->Print( "Element Type 3 size: %d or %d", sizeof( PSec2ElemType3a ), sizeof( PSec2ElemType3a ) + sizeof( PSec2ElemType3b ) );
+ while ( NextElementOffset < NextSectionOffset )
+ {
+ f->Seek( NextElementOffset ); // Make sure we are at the computed offset
+
+ //if ( gDevDebug )
+ // Console->Print( "Reading next element header ... " );
+ if (( uint32_t )( f->Read( &Sec2ElemHeader, sizeof( PSec2ElemHeader ) ) ) < sizeof( PSec2ElemHeader ) )
+ {
+ Filesystem->Close( f );
+ return -3;
+ }
+ if (( Sec2ElemHeader.mHeaderSize != 0x0000000c ) || ( Sec2ElemHeader.mHeaderSig != 0x0ffefef1 ) )
+ {
+ Filesystem->Close( f );
+ return -2;
+ }
+ NextElementOffset += ( Sec2ElemHeader.mHeaderSize + 4 + Sec2ElemHeader.mDataSize );
+ //if (gDevDebug) Console->Print("Found element %d of type %d, size %d", ++cnt, Sec2ElemHeader.mElementType, Sec2ElemHeader.mDataSize);
+ switch ( Sec2ElemHeader.mElementType )
+ {
+ case 1000003:
+ {
+ ProcessOK = ProcessSec2ElemType3( Sec2ElemHeader.mDataSize );
+ break;
+ }
+ case 1000005:
+ {
+ ProcessOK = ProcessSec2ElemType5( Sec2ElemHeader.mDataSize );
+ break;
+ }
+ case 1000006:
+ {
+ ProcessOK = ProcessSec2NPCEntry( Sec2ElemHeader.mDataSize );
+ break;
+ }
+ default:
+ {
+ if (gDevDebug) Console->Print( "Ignoring SectionID %d, not supportet yet", Sec2ElemHeader.mElementType );
+ ProcessOK = true;
+ break;
+ }
+ }
+
+ if ( !ProcessOK )
+ return -4;
+ }
+ }
+ else
+ {
+ if ( gDevDebug )
+ Console->Print( "Section %d ignored", SectionHeader.mSection );
+ continue;
+ }
+
+ }
+
+ Filesystem->Close( f );
+ }
+ else
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+bool PWorldDatParser::ProcessSec2ElemType3( uint32_t nSize ) // furniture
+{
+ PSec2ElemType3a DataA;
+ PSec2ElemType3b DataB;
+ const PDefWorldModel* nWorldModel;
+ std::string nName;
+ const uint32_t sza = sizeof( PSec2ElemType3a );
+ const uint32_t szb = sizeof( PSec2ElemType3a ) + sizeof( PSec2ElemType3b );
+
+ if (( nSize != szb ) && ( nSize != sza ) )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType3 (%d read vs %d or %d needed", nSize, sza, szb );
+ return false;
+ }
+ if (( uint32_t )( f->Read( &DataA, sza ) ) < sza )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType3a" );
+ return false;
+ }
+ if ( nSize == szb )
+ {
+ if (( uint32_t )( f->Read( &DataB, sizeof( PSec2ElemType3b ) ) ) < sizeof( PSec2ElemType3b ) )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType3b" );
+ return false;
+ }
+ }
+ else
+ {
+ DataB.mBoxLowerY = DataB.mBoxLowerZ = DataB.mBoxLowerX = 0;
+ DataB.mBoxUpperY = DataB.mBoxUpperZ = DataB.mBoxUpperX = 0;
+ }
+
+ if ( DataA.mWorldmodelID )
+ {
+ nWorldModel = GameDefs->WorldModels()->GetDef( DataA.mWorldmodelID );
+ if ( nWorldModel )
+ nName = nWorldModel->GetName();
+ else
+ nName = "UNKNOWN";
+ }
+ else
+ {
+ nName = "PASSIVE";
+ nWorldModel = NULL;
+ }
+
+ /* if (gDevDebug) {
+ Console->Print("-------------------------------------------------------");
+ Console->Print("%s (%d) : ID %d", nName.c_str(), DataA.mWorldmodelID, DataA.mObjectID);
+ if (!nWorldModel) Console->Print("y:%f z:%f x:%f model %d", DataA.mPosY , DataA.mPosZ, DataA.mPosX, DataA.mModelID);
+ Console->Print("Scale:%f Uk2:0x%08x Uk3:0x%08x", DataA.mScale, DataA.mUnknown2, DataA.mUnknown3);
+ Console->Print("Uk4:0x%08x Uk5:0x%04x", DataA.mUnknown4, DataA.mUnknown5);
+ //Console->Print("Ly:%f Lz:%f Lx:%f", DataB.mBoxLowerY, DataB.mBoxLowerZ, DataB.mBoxLowerX);
+ //Console->Print("Uy:%f Uz:%f Ux:%f", DataB.mBoxUpperY, DataB.mBoxUpperZ, DataB.mBoxUpperX);
+ }*/
+
+ if (( !nWorldModel || ( !nWorldModel->GetFunctionType() && !( nWorldModel->GetUseFlags() & nonDiscardUseFlags ) ) ) && mDiscardPassiveObjects )
+ {
+ //if ( gDevDebug )
+ // Console->Print( "Discarded" );
+ return true;
+ }
+
+ PFurnitureItemTemplate* nItem = new PFurnitureItemTemplate;
+ nItem->mObjectID = DataA.mObjectID;
+
+ // The commented out values are not loaded from dat file atm because they are not used yet.
+ nItem->mPosY = DataA.mPosY; // float pos values are kept 0-centered
+ nItem->mPosZ = DataA.mPosZ;
+ nItem->mPosX = DataA.mPosX;
+// nItem->mRotY = DataA.mRotY;
+ nItem->mRotZ = DataA.mRotZ;
+// nItem->mRotX = DataA.mRotX;
+// nItem->mScale = DataA.mScale;
+// nItem->mUnknown2 = DataA.mUnknown2;
+ nItem->mModelID = DataA.mModelID;
+// nItem->mUnknown3 = DataA.mUnknown3;
+// nItem->mUnknown4 = DataA.mUnknown4;
+ nItem->mWorldmodelID = DataA.mWorldmodelID;
+// nItem->mUnknown5 = DataA.mUnknown5;
+
+// nItem->mBoxLowerY = DataB.mBoxLowerY;
+// nItem->mBoxLowerZ = DataB.mBoxLowerZ;
+// nItem->mBoxLowerX = DataB.mBoxLowerX;
+// nItem->mBoxUpperY = DataB.mBoxUpperY;
+// nItem->mBoxUpperZ = DataB.mBoxUpperZ;
+// nItem->mBoxUpperX = DataB.mBoxUpperX;
+
+ nItem->mDefWorldModel = nWorldModel;
+ /*uint16_t func=nWorldModel->GetFunctionType();
+ if((func==18) || (func==20) || (func==29))
+ Console->Print("gate model: %d", DataA.mWorldmodelID);*/
+
+ float Angle = ( 180 + DataA.mRotZ ) * 3.14159 / 180;
+ float Radius = abs(( int )(( DataB.mBoxUpperX - DataB.mBoxLowerX ) / 2 ) );
+ if ( Radius == 0 )
+ {
+ Radius = 10;
+ }
+ Radius *= DataA.mScale;
+ Radius += 5;
+
+ // int pos values are change to match char pos scale (32000 centered)
+ nItem->mFrontPosY = ( uint16_t )( 32000 + DataA.mPosY + Radius * sinf( Angle ) );
+ nItem->mFrontPosZ = ( uint16_t )( 32000 + DataA.mPosZ );
+ nItem->mFrontPosX = ( uint16_t )( 32000 + DataA.mPosX + Radius * cosf( Angle ) );
+ nItem->mFrontLR = ( uint8_t )( 0.5 * ( DataA.mRotZ + ( DataA.mRotZ < 0 ? 360 : 0 ) ) );
+
+ mWorld->AddFurnitureItem( nItem );
+
+ return true;
+}
+
+bool PWorldDatParser::ProcessSec2ElemType5( uint32_t nSize ) // doors
+{
+ PSec2ElemType5Start Data;
+ char StringData[64];
+
+ const PDefWorldModel* nWorldModel;
+ std::string nName;
+ char* ActorString;
+ char* ParamString;
+
+ const uint32_t sza = sizeof( PSec2ElemType5Start );
+
+ if (( nSize < sza ) )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType5 (%d read vs %d needed", nSize, sza );
+ return false;
+ }
+ if (( uint32_t )( f->Read( &Data, sza ) ) < sza )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType5start" );
+ return false;
+ }
+ uint32_t szb = Data.mActorStringSize + Data.mParamStringSize;
+
+ if ( nSize != ( sza + szb ) )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType5 (%d read vs %d needed", nSize, sza + szb );
+ return false;
+ }
+ else
+ {
+ if ( szb > 64 )
+ {
+ Console->Print( RED, BLACK, "[Warning] String data too long in Sec2ElemType5 End String. End will be ignored" );
+ szb = 64;
+ }
+ if (( uint32_t )( f->Read( StringData, szb ) ) < szb )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType5 End Strings" );
+ return false;
+ }
+ }
+
+ if ( Data.mWorldmodelID )
+ {
+ nWorldModel = GameDefs->WorldModels()->GetDef( Data.mWorldmodelID );
+ if ( nWorldModel )
+ nName = nWorldModel->GetName();
+ else
+ nName = "UNKNOWN";
+ }
+ else
+ {
+ nName = "PASSIVE";
+ nWorldModel = NULL;
+ }
+
+ StringData[Data.mActorStringSize - 1] = 0;
+ ActorString = StringData;
+ StringData[szb - 1] = 0;
+ ParamString = StringData + Data.mActorStringSize;
+ /*
+ if ( gDevDebug )
+ {
+ Console->Print( "-------------------------------------------------------" );
+ Console->Print( "Door %s (%d) : ID %d", nName.c_str(), Data.mWorldmodelID, Data.mDoorID );
+ Console->Print( "y:%f z:%f x:%f", Data.mPosY , Data.mPosZ, Data.mPosX );
+ Console->Print( "Uk1:0x%04x Uk1bis:0x%04x Uk5:0x%04x", Data.mUnknown1, Data.mUnknown1bis, Data.mUnknown5 );
+ Console->Print( "Type=%s Param=%s", ActorString, ParamString );
+ }
+ */
+// Let's keep knowledge of doors even without models !
+ /* if ((!nWorldModel || (!nWorldModel->GetFunctionType() && !(nWorldModel->GetUseFlags() & nonDiscardUseFlags))) && mDiscardPassiveObjects)
+ {
+ if (gDevDebug) Console->Print("Discarded");
+ if (gDevDebug)
+ {
+ Console->Print("Door %s (%d) : ID %d", nName.c_str(), Data.mWorldmodelID, Data.mDoorID);
+ Console->Print("Type=%s Param=%s", ActorString, ParamString);
+ }
+ return true;
+ }*/
+
+ PDoorTemplate* nDoor = new PDoorTemplate;
+ nDoor->mDoorID = Data.mDoorID;
+
+ //nDoor->mUnknown1 = Data.mUnknown1; //18 00
+ //nDoor->mUnknown1bis = Data.mUnknown1bis; //00 00 ? varies
+ nDoor->mPosY = Data.mPosY;
+ nDoor->mPosZ = Data.mPosZ;
+ nDoor->mPosX = Data.mPosX;
+ //nDoor->mUnknown5 = Data.mUnknown5; //00 00 ? second byte varies
+ nDoor->mWorldmodelID = Data.mWorldmodelID; //door type from worldmodel.def
+ nDoor->mDefWorldModel = nWorldModel;
+
+ nDoor->SetDoorTypeName( ActorString );
+ nDoor->SetDoorParameters( ParamString );
+
+ mWorld->AddDoor( nDoor );
+
+ return true;
+}
+
+bool PWorldDatParser::ProcessSec2NPCEntry( uint32_t nSize )
+{
+ PSec2NPC_EntryPart1 tNPCPartA;
+ PSec2NPC_EntryPart2 tNPCPartB;
+ std::string tActorName;
+ std::string tAngle;
+ char tStrBuffer[64];
+
+ uint32_t tSizeOfA = sizeof(tNPCPartA);
+ uint32_t tSizeOfB = sizeof(tNPCPartB);
+
+ // Are we able to read enough bytes from the file? means: CAN we safely read our entire struct from the file?
+ if ( nSize < tSizeOfA )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Wrong size for PSec2NPC_EntryPart1 (%d read vs %d needed", nSize, tSizeOfA );
+ return false;
+ }
+ // yes we can! So read it now. If we reach EOF, break
+ if (( uint32_t )( f->Read( &tNPCPartA, tSizeOfA ) ) < tSizeOfA )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry" );
+ return false;
+ }
+ // Now we have the header. lets check if we have some waypoints for this NPC
+ // Size of entire NPC entry in file
+ uint32_t tCompleteNPCSize = tSizeOfA + tNPCPartA.mActorStringSize + tNPCPartA.mAngleStringSize;
+ if ( tNPCPartA.mHasAdditionalCoords > 0 )
+ {
+ // It has additional coords, add 'em
+ tCompleteNPCSize += tSizeOfB*tNPCPartA.mHasAdditionalCoords;
+ }
+
+ // Do a last check if we're on the correct size
+ if ( nSize != tCompleteNPCSize )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Wrong size for PSec2NPC_Entry (%d available vs %d expected", nSize, tCompleteNPCSize );
+ Console->Print( RED, BLACK, "NPC ID was: %d", tNPCPartA.mNpcID);
+ return false;
+ }
+ // We are. Continue reading!
+ // Assign the 2 strings and watch out for EOF!
+ memset(tStrBuffer, 0, 64);
+ if (( uint32_t )( f->Read( tStrBuffer, tNPCPartA.mActorStringSize ) ) < tNPCPartA.mActorStringSize )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry mActorStringSize" );
+ return false;
+ }
+ tActorName = tStrBuffer;
+
+ memset(tStrBuffer, 0, 64);
+ if (( uint32_t )( f->Read( tStrBuffer, tNPCPartA.mAngleStringSize ) ) < tNPCPartA.mAngleStringSize )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry mAngleStringSize" );
+ return false;
+ }
+ tAngle = tStrBuffer;
+
+ // We're done. Now create new NPC entry
+ PNPCTemplate* tNPC = new PNPCTemplate;
+
+ // and assing all that stuff
+ tNPC->SetUnknown1(tNPCPartA.mUnknown1);
+ tNPC->SetPosX(tNPCPartA.mPosX);
+ tNPC->SetPosY(tNPCPartA.mPosY);
+ tNPC->SetPosZ(tNPCPartA.mPosZ);
+ tNPC->SetNPCTypeID(tNPCPartA.mNPCTypeID);
+ tNPC->SetActorStrSize(tNPCPartA.mActorStringSize);
+ tNPC->SetAngleStrSize(tNPCPartA.mAngleStringSize);
+ tNPC->SetNpcID(tNPCPartA.mNpcID);
+ tNPC->SetUnknown2a(tNPCPartA.mUnknown2a);
+ tNPC->SetUnknown2b(tNPCPartA.mUnknown2b);
+ tNPC->SetUnknown2c(tNPCPartA.mUnknown2c);
+ tNPC->SetTradeID/*SetUnknown3*/(tNPCPartA.mTradeID/*mUnknown3*/);
+ tNPC->SetUnknown4(tNPCPartA.mUnknown4);
+
+ tNPC->SetActorName(tActorName);
+ tNPC->SetAngle(tAngle);
+
+ // Read additional Waypoints if available
+ uint8_t tCurrWayP = 0;
+ if ( tNPCPartA.mHasAdditionalCoords > 0 )
+ {
+ while ( tCurrWayP < tNPCPartA.mHasAdditionalCoords )
+ {
+ memset(&tNPCPartB, 0, tSizeOfB);
+ if (( uint32_t )( f->Read( &tNPCPartB, tSizeOfB ) ) < tSizeOfB )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry while reading WayPoints" );
+ return false;
+ }
+ tNPC->AddWayPoint(tNPCPartB.mPosX, tNPCPartB.mPosY, tNPCPartB.mPosZ, tCurrWayP);
+ tCurrWayP++;
+ }
+ }
+
+ if (gDevDebug) Console->Print("Added NPC ID %d", tNPCPartA.mNpcID);
+
+ mWorld->AddNPC(tNPC);
+ return true;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-\r
-class PFile;\r
-class PWorldDataTemplate;\r
-\r
-class PWorldDatParser {\r
-private:\r
- PFile* f;\r
- std::string mNCDataPath;\r
-\r
- PWorldDataTemplate* mWorld;\r
- bool mDiscardPassiveObjects;\r
-\r
- bool ProcessSec2ElemType3(uint32_t nSize);\r
- bool ProcessSec2ElemType5(uint32_t nSize);\r
- bool ProcessSec2NPCEntry(uint32_t nSize);\r
-\r
-public:\r
- PWorldDatParser();\r
- ~PWorldDatParser();\r
-\r
- int32_t LoadDatFile(const std::string& nFilename, PWorldDataTemplate* nWorld, const bool nDiscardPassiveObjects = true, const bool nTestAccesOnly = false);\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+class PFile;
+class PWorldDataTemplate;
+
+class PWorldDatParser {
+private:
+ PFile* f;
+ std::string mNCDataPath;
+
+ PWorldDataTemplate* mWorld;
+ bool mDiscardPassiveObjects;
+
+ bool ProcessSec2ElemType3(uint32_t nSize);
+ bool ProcessSec2ElemType5(uint32_t nSize);
+ bool ProcessSec2NPCEntry(uint32_t nSize);
+
+public:
+ PWorldDatParser();
+ ~PWorldDatParser();
+
+ int32_t LoadDatFile(const std::string& nFilename, PWorldDataTemplate* nWorld, const bool nDiscardPassiveObjects = true, const bool nTestAccesOnly = false);
+};
-#pragma once\r
-\r
-#include <cstdint>\r
-\r
-struct PWorldFileHeader {\r
- uint32_t mHeaderSize; // must be 08 00 00 00, = header size after this field\r
- uint32_t mHeaderSig; // must be CF CF 0F 00\r
- uint32_t mSection; // must be 01 00 00 00\r
-};\r
-\r
-struct PSectionHeader {\r
- uint32_t mHeaderSize; // must be 0C 00 00 00\r
- uint32_t mHeaderSig; // must be CF FF 00 00\r
- uint32_t mSection; // 00 00 00 00 means end\r
- uint32_t mDataSize;\r
-};\r
-\r
-struct PSec2ElemHeader {\r
- uint32_t mHeaderSize; // must be 0C 00 00 00\r
- uint32_t mHeaderSig; // must be F1 FE FE 0F\r
- uint32_t mElementType; // 1000003, 1000005 or 1000014\r
- uint32_t mDataSize;\r
-};\r
-\r
-struct PSec2ElemType3a { //static object ?\r
- float mPosY; //= uint32_t16_t PosY - 32000\r
- float mPosZ;\r
- float mPosX;\r
- float mRotY;\r
- float mRotZ;\r
- float mRotX;\r
- float mScale; //00 00 80 3F ? = float(1.000000) !!! => scale factor ?????\r
- uint32_t mUnknown2; //01 00 00 00 ?\r
- uint16_t mModelID; // point32_ts to models.ini\r
- uint32_t mUnknown3; //00 00 00 00 ?\r
- uint32_t mUnknown4; //00 00 00 00 ?\r
- uint16_t mWorldmodelID; // point32_ts to worldmodel.def\r
- uint16_t mUnknown5; //12 00 ?\r
- uint32_t mObjectID;\r
-};\r
-\r
-struct PSec2ElemType3b { //this part is optional\r
- float mBoxLowerY; //Bounding box, for useflag "64 - selfconstructing colisionbox"\r
- float mBoxLowerZ; // int32_t32_t or uint32_t32_t ?\r
- float mBoxLowerX;\r
- float mBoxUpperY;\r
- float mBoxUpperZ;\r
- float mBoxUpperX;\r
-};\r
-\r
-struct PSec2ElemType5Start { //door\r
- uint16_t mUnknown1; //18 00\r
- uint16_t mUnknown1bis; //00 00 ? varies\r
- float mPosY;\r
- float mPosZ;\r
- float mPosX;\r
- uint8_t mActorStringSize; //string size with ending 0\r
- uint8_t mParamStringSize; //string size with ending 0\r
- uint16_t mUnknown5; //00 00 ? second byte varies\r
- uint16_t mDoorID; // but what is the link with ObjectID sent in Use message (can't find the base offset .. or 0x80 for doors ???)\r
- uint16_t mWorldmodelID; //door type from worldmodel.def\r
-};\r
-//Actor As String //null terminated string\r
-//Params As String //null terminated string - for DDOOR, 2nd param is the ID of the other (half)door (*)\r
-//param1 = 2 => simple lateral move ?, 3 => door frontal+lateral move (as at Typherra memorial) ?\r
-//last param = 0/1 for lateral move direction ? no ...\r
-//(*) here is the bug(?) that makes open only one half of a double door\r
-\r
-/*\r
-struct PSec2ElemType6Start //npc\r
-{\r
- uint16_t mUnknown1; //20 00 ?\r
- uint16_t mUnknown2; //12 00 ?\r
- float mPosY;\r
- float mPosZ;\r
- float mPosX;\r
- uint32_t mNPCTypeID; //npc type in npc.def\r
- uint8_t mActorStringSize; //string size with ending 0\r
- uint8_t mParamStringSize; //string size with ending 0\r
- uint16_t mNpcID; // kind of ?\r
- uint32_t mUnknown3; //01 00 00 00 ?\r
- uint16_t mUnknown4; //00 00 ?\r
- uint16_t mUnknown5; //04 00 ?\r
-};\r
- //Actor As String //null terminated string\r
- //Params As String //null terminated string - Seem to be the facing angle in degres\r
-struct PSec2ElemType6End\r
-{\r
- float mPosY2; //second position for movement ?\r
- float mPosZ2; //\r
- float mPosX2; //\r
-};\r
-*/\r
-struct PSec2NPC_EntryPart1 {\r
- uint32_t mUnknown1; // Is always 0x20001200, in every log. maybe header for NPCs?\r
- float mPosY;\r
- float mPosZ;\r
- float mPosX;\r
- uint32_t mNPCTypeID; //npc type in npc.def\r
- uint8_t mActorStringSize; //string size with ending 0\r
- uint8_t mAngleStringSize; //string size with ending 0\r
- uint16_t mNpcID;\r
- uint8_t mHasAdditionalCoords;\r
- uint8_t mUnknown2a;\r
- uint8_t mUnknown2b;\r
- uint8_t mUnknown2c;\r
- uint16_t mTradeID; //mUnknown3; //00 00 ?\r
- uint16_t mUnknown4; //04 00 ?\r
-};\r
-\r
-// uint32_t8_t mActorName[mActorStringSize];\r
-// uint32_t8_t mAngle[mAngleStringSize];\r
-\r
-struct PSec2NPC_EntryPart2 { // Waypoint32_ts! or something like that...\r
- float mPosY;\r
- float mPosZ;\r
- float mPosX;\r
-};\r
-\r
-// uint32_t16_t mStrSize; //non-zero terminated string size\r
-// Name As String //non-zero terminated string\r
-struct PSec2ElemType15End { //area definition/sound ?\r
- float mUnknown1;\r
- float mUnknown2;\r
- float mUnknown3;\r
- float mUnknown4;\r
- float mUnknown5;\r
-};\r
+#pragma once
+
+#include <cstdint>
+
+struct PWorldFileHeader {
+ uint32_t mHeaderSize; // must be 08 00 00 00, = header size after this field
+ uint32_t mHeaderSig; // must be CF CF 0F 00
+ uint32_t mSection; // must be 01 00 00 00
+};
+
+struct PSectionHeader {
+ uint32_t mHeaderSize; // must be 0C 00 00 00
+ uint32_t mHeaderSig; // must be CF FF 00 00
+ uint32_t mSection; // 00 00 00 00 means end
+ uint32_t mDataSize;
+};
+
+struct PSec2ElemHeader {
+ uint32_t mHeaderSize; // must be 0C 00 00 00
+ uint32_t mHeaderSig; // must be F1 FE FE 0F
+ uint32_t mElementType; // 1000003, 1000005 or 1000014
+ uint32_t mDataSize;
+};
+
+struct PSec2ElemType3a { //static object ?
+ float mPosY; //= uint32_t16_t PosY - 32000
+ float mPosZ;
+ float mPosX;
+ float mRotY;
+ float mRotZ;
+ float mRotX;
+ float mScale; //00 00 80 3F ? = float(1.000000) !!! => scale factor ?????
+ uint32_t mUnknown2; //01 00 00 00 ?
+ uint16_t mModelID; // point32_ts to models.ini
+ uint32_t mUnknown3; //00 00 00 00 ?
+ uint32_t mUnknown4; //00 00 00 00 ?
+ uint16_t mWorldmodelID; // point32_ts to worldmodel.def
+ uint16_t mUnknown5; //12 00 ?
+ uint32_t mObjectID;
+};
+
+struct PSec2ElemType3b { //this part is optional
+ float mBoxLowerY; //Bounding box, for useflag "64 - selfconstructing colisionbox"
+ float mBoxLowerZ; // int32_t32_t or uint32_t32_t ?
+ float mBoxLowerX;
+ float mBoxUpperY;
+ float mBoxUpperZ;
+ float mBoxUpperX;
+};
+
+struct PSec2ElemType5Start { //door
+ uint16_t mUnknown1; //18 00
+ uint16_t mUnknown1bis; //00 00 ? varies
+ float mPosY;
+ float mPosZ;
+ float mPosX;
+ uint8_t mActorStringSize; //string size with ending 0
+ uint8_t mParamStringSize; //string size with ending 0
+ uint16_t mUnknown5; //00 00 ? second byte varies
+ uint16_t mDoorID; // but what is the link with ObjectID sent in Use message (can't find the base offset .. or 0x80 for doors ???)
+ uint16_t mWorldmodelID; //door type from worldmodel.def
+};
+//Actor As String //null terminated string
+//Params As String //null terminated string - for DDOOR, 2nd param is the ID of the other (half)door (*)
+//param1 = 2 => simple lateral move ?, 3 => door frontal+lateral move (as at Typherra memorial) ?
+//last param = 0/1 for lateral move direction ? no ...
+//(*) here is the bug(?) that makes open only one half of a double door
+
+/*
+struct PSec2ElemType6Start //npc
+{
+ uint16_t mUnknown1; //20 00 ?
+ uint16_t mUnknown2; //12 00 ?
+ float mPosY;
+ float mPosZ;
+ float mPosX;
+ uint32_t mNPCTypeID; //npc type in npc.def
+ uint8_t mActorStringSize; //string size with ending 0
+ uint8_t mParamStringSize; //string size with ending 0
+ uint16_t mNpcID; // kind of ?
+ uint32_t mUnknown3; //01 00 00 00 ?
+ uint16_t mUnknown4; //00 00 ?
+ uint16_t mUnknown5; //04 00 ?
+};
+ //Actor As String //null terminated string
+ //Params As String //null terminated string - Seem to be the facing angle in degres
+struct PSec2ElemType6End
+{
+ float mPosY2; //second position for movement ?
+ float mPosZ2; //
+ float mPosX2; //
+};
+*/
+struct PSec2NPC_EntryPart1 {
+ uint32_t mUnknown1; // Is always 0x20001200, in every log. maybe header for NPCs?
+ float mPosY;
+ float mPosZ;
+ float mPosX;
+ uint32_t mNPCTypeID; //npc type in npc.def
+ uint8_t mActorStringSize; //string size with ending 0
+ uint8_t mAngleStringSize; //string size with ending 0
+ uint16_t mNpcID;
+ uint8_t mHasAdditionalCoords;
+ uint8_t mUnknown2a;
+ uint8_t mUnknown2b;
+ uint8_t mUnknown2c;
+ uint16_t mTradeID; //mUnknown3; //00 00 ?
+ uint16_t mUnknown4; //04 00 ?
+};
+
+// uint32_t8_t mActorName[mActorStringSize];
+// uint32_t8_t mAngle[mAngleStringSize];
+
+struct PSec2NPC_EntryPart2 { // Waypoint32_ts! or something like that...
+ float mPosY;
+ float mPosZ;
+ float mPosX;
+};
+
+// uint32_t16_t mStrSize; //non-zero terminated string size
+// Name As String //non-zero terminated string
+struct PSec2ElemType15End { //area definition/sound ?
+ float mUnknown1;
+ float mUnknown2;
+ float mUnknown3;
+ float mUnknown4;
+ float mUnknown5;
+};
-#include "GameServer/Definitions/Includes.hxx"\r
-#include "GameServer/Includes.hxx"\r
-\r
-/*\r
- NOTA: Some entries in worlds.ini share the same Id ...\r
- e.g: 505: techtown_enter 1/1a/1b/2\r
- As we don't know what it means & how it is supposed to be handled,\r
- we keep the first one for the moment. (this is managed in gamedef.cpp)\r
- TODO: Add a config entry to select the Nth entry for each such case,\r
- as well as a config entry to select the default entry to be kept (first/last)\r
-*/\r
-\r
-PDefWorldFile::PDefWorldFile()\r
-{\r
- mFileInWorldsDir = false;\r
-}\r
-\r
-bool PDefWorldFile::LoadFromDef(PTokenList *Tokens)\r
-{\r
- int Idx=0;\r
- int StartPos = 0;\r
- int TailLen = 0;\r
- int Len;\r
-\r
- for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
- {\r
- switch(Idx)\r
- {\r
- case 0: // setentry\r
- continue;\r
-\r
- case 1: // index\r
- mIndex = atoi(i->c_str()); break;\r
-\r
- case 2: // name\r
- {\r
- Len = (*i).length();\r
-\r
- while((StartPos = (*i).find("\\",StartPos))>-1)\r
- (*i)[StartPos]='/';\r
- StartPos = 0;\r
-\r
- if ((*i)[0] == '\"')\r
- StartPos = 1;\r
-\r
- if ( (*i).substr(StartPos,9) == "./worlds/" )\r
- {\r
- mFileInWorldsDir = true;\r
- StartPos += 9;\r
- }\r
- else if ( (*i).substr(StartPos,2) == "./" )\r
- StartPos += 2;\r
-\r
- if ((*i)[Len-1] == '\"')\r
- TailLen = 1;\r
- if ( (Len > (StartPos+TailLen+4)) && ((*i)[Len-TailLen-4] == '.') )\r
- TailLen += 4;\r
-\r
- mName = (*i).substr(StartPos,Len-StartPos-TailLen); // remove prefix, extension and doublequotes\r
-\r
- break;\r
- }\r
- }\r
- }\r
-\r
- return (Idx == 3);\r
-}\r
-\r
-// class PDefWorldFileMap defined in gamedefs.h\r
-bool PDefWorldFilesMap::Load(const char* nName, const char* nFilename)\r
-{\r
- mName = nName;\r
- if(mName.empty())\r
- {\r
- Console->Print( "%s Defs name not defined", Console->ColorText( RED, BLACK, "[ERROR]" ) );\r
- return (false);\r
- }\r
-\r
- if(! *nFilename)\r
- {\r
- Console->Print( "%s Filename not defined for %s defs", Console->ColorText( RED, BLACK, "[ERROR]" ), mName.c_str() );\r
- return (false);\r
- }\r
-\r
- PDefParser parser;\r
- int nDefs = 0, nErrors = 0, nDup = 0;\r
-\r
- if ( parser.Parse( nFilename ) )\r
- {\r
- const PDefTokenList &t = parser.GetTokens();\r
-\r
- for ( PDefTokenList::const_iterator i = t.begin(); i != t.end(); i++ )\r
- {\r
- PDefWorldFile *it = new PDefWorldFile();\r
- bool loadfail = !it->LoadFromDef( *i ), insertfail = false;\r
-\r
- if ( !loadfail )\r
- insertfail = !mDefs.insert( std::make_pair( it->GetIndex(), it ) ).second;\r
- if ( loadfail || insertfail )\r
- {\r
- if ( insertfail )\r
- {\r
- ++nDup;\r
- if ( gDevDebug ) Console->Print( "%s ini error (new duplicate id %i discarded)", mName.c_str(), it->GetIndex(), it->GetName().c_str() );\r
- }\r
- else\r
- {\r
- Console->Print( "%s ini load error @ %i", mName.c_str(), nDefs + nErrors );\r
- ++nErrors;\r
- }\r
- delete it;\r
- }\r
- else\r
- ++nDefs;\r
- }\r
- }\r
- else\r
- {\r
- Console->Print( "%s Error loading %s ini defs", Console->ColorText( RED, BLACK, "[ERROR]" ), mName.c_str() );\r
- return ( false );\r
- }\r
-\r
- if ( nErrors > 0 )\r
- Console->Print( "%s Loaded %i %s ini defs, %i error(s).", Console->ColorText( RED, BLACK, "[ERROR]" ), nDefs, mName.c_str(), nErrors );\r
- else\r
- Console->Print( "%s Loaded %i %s ini defs, %i error(s).", Console->ColorText( GREEN, BLACK, "[Success]" ), nDefs, mName.c_str(), nErrors );\r
-\r
- if ( nDup )\r
- Console->Print( "%s %d duplicate entries ignored in %s ini defs.", Console->ColorText( YELLOW, BLACK, "[Notice]" ), nDup, mName.c_str() );\r
-\r
- return ( true );\r
-}\r
+#include "GameServer/Definitions/Includes.hxx"
+#include "GameServer/Includes.hxx"
+
+/*
+ NOTA: Some entries in worlds.ini share the same Id ...
+ e.g: 505: techtown_enter 1/1a/1b/2
+ As we don't know what it means & how it is supposed to be handled,
+ we keep the first one for the moment. (this is managed in gamedef.cpp)
+ TODO: Add a config entry to select the Nth entry for each such case,
+ as well as a config entry to select the default entry to be kept (first/last)
+*/
+
+PDefWorldFile::PDefWorldFile()
+{
+ mFileInWorldsDir = false;
+}
+
+bool PDefWorldFile::LoadFromDef(PTokenList *Tokens)
+{
+ int Idx=0;
+ int StartPos = 0;
+ int TailLen = 0;
+ int Len;
+
+ for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)
+ {
+ switch(Idx)
+ {
+ case 0: // setentry
+ continue;
+
+ case 1: // index
+ mIndex = atoi(i->c_str()); break;
+
+ case 2: // name
+ {
+ Len = (*i).length();
+
+ while((StartPos = (*i).find("\\",StartPos))>-1)
+ (*i)[StartPos]='/';
+ StartPos = 0;
+
+ if ((*i)[0] == '\"')
+ StartPos = 1;
+
+ if ( (*i).substr(StartPos,9) == "./worlds/" )
+ {
+ mFileInWorldsDir = true;
+ StartPos += 9;
+ }
+ else if ( (*i).substr(StartPos,2) == "./" )
+ StartPos += 2;
+
+ if ((*i)[Len-1] == '\"')
+ TailLen = 1;
+ if ( (Len > (StartPos+TailLen+4)) && ((*i)[Len-TailLen-4] == '.') )
+ TailLen += 4;
+
+ mName = (*i).substr(StartPos,Len-StartPos-TailLen); // remove prefix, extension and doublequotes
+
+ break;
+ }
+ }
+ }
+
+ return (Idx == 3);
+}
+
+// class PDefWorldFileMap defined in gamedefs.h
+bool PDefWorldFilesMap::Load(const char* nName, const char* nFilename)
+{
+ mName = nName;
+ if(mName.empty())
+ {
+ Console->Print( "%s Defs name not defined", Console->ColorText( RED, BLACK, "[ERROR]" ) );
+ return (false);
+ }
+
+ if(! *nFilename)
+ {
+ Console->Print( "%s Filename not defined for %s defs", Console->ColorText( RED, BLACK, "[ERROR]" ), mName.c_str() );
+ return (false);
+ }
+
+ PDefParser parser;
+ int nDefs = 0, nErrors = 0, nDup = 0;
+
+ if ( parser.Parse( nFilename ) )
+ {
+ const PDefTokenList &t = parser.GetTokens();
+
+ for ( PDefTokenList::const_iterator i = t.begin(); i != t.end(); i++ )
+ {
+ PDefWorldFile *it = new PDefWorldFile();
+ bool loadfail = !it->LoadFromDef( *i ), insertfail = false;
+
+ if ( !loadfail )
+ insertfail = !mDefs.insert( std::make_pair( it->GetIndex(), it ) ).second;
+ if ( loadfail || insertfail )
+ {
+ if ( insertfail )
+ {
+ ++nDup;
+ if ( gDevDebug ) Console->Print( "%s ini error (new duplicate id %i discarded)", mName.c_str(), it->GetIndex(), it->GetName().c_str() );
+ }
+ else
+ {
+ Console->Print( "%s ini load error @ %i", mName.c_str(), nDefs + nErrors );
+ ++nErrors;
+ }
+ delete it;
+ }
+ else
+ ++nDefs;
+ }
+ }
+ else
+ {
+ Console->Print( "%s Error loading %s ini defs", Console->ColorText( RED, BLACK, "[ERROR]" ), mName.c_str() );
+ return ( false );
+ }
+
+ if ( nErrors > 0 )
+ Console->Print( "%s Loaded %i %s ini defs, %i error(s).", Console->ColorText( RED, BLACK, "[ERROR]" ), nDefs, mName.c_str(), nErrors );
+ else
+ Console->Print( "%s Loaded %i %s ini defs, %i error(s).", Console->ColorText( GREEN, BLACK, "[Success]" ), nDefs, mName.c_str(), nErrors );
+
+ if ( nDup )
+ Console->Print( "%s %d duplicate entries ignored in %s ini defs.", Console->ColorText( YELLOW, BLACK, "[Notice]" ), nDup, mName.c_str() );
+
+ return ( true );
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <map>\r
-#include <string>\r
-#include "GameServer/Definitions/Definition.hxx"\r
-\r
-class PDefWorldFile : public PDef {\r
-private:\r
- //int32_t mIndex;\r
- std::string mName; // dat filename with ending extension and starting ./ or ./worlds/ REMOVED\r
- bool mFileInWorldsDir; // TRUE if worlds/ must be appendend before mName to get real file name (dat file at least)\r
-\r
-public:\r
- PDefWorldFile();\r
- //~PDefWorldFile();\r
-\r
- bool LoadFromDef(PTokenList *Tokens);\r
-\r
- inline const std::string &GetName() const { return mName; }\r
- inline const std::string GetBasicFileName() const { return (mFileInWorldsDir ? (std::string("worlds/") + mName) : mName); };\r
-};\r
-\r
-\r
-class PDefWorldFilesMap : public PDefMap<PDefWorldFile> {\r
-public:\r
- bool Load(const char* nName, const char* nFilename);\r
- inline std::map<int32_t, PDefWorldFile*>::const_iterator ConstIteratorBegin() const { return mDefs.begin(); }\r
- inline std::map<int32_t, PDefWorldFile*>::const_iterator ConstIteratorEnd() const { return mDefs.end(); }\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <map>
+#include <string>
+#include "GameServer/Definitions/Definition.hxx"
+
+class PDefWorldFile : public PDef {
+private:
+ //int32_t mIndex;
+ std::string mName; // dat filename with ending extension and starting ./ or ./worlds/ REMOVED
+ bool mFileInWorldsDir; // TRUE if worlds/ must be appendend before mName to get real file name (dat file at least)
+
+public:
+ PDefWorldFile();
+ //~PDefWorldFile();
+
+ bool LoadFromDef(PTokenList *Tokens);
+
+ inline const std::string &GetName() const { return mName; }
+ inline const std::string GetBasicFileName() const { return (mFileInWorldsDir ? (std::string("worlds/") + mName) : mName); };
+};
+
+
+class PDefWorldFilesMap : public PDefMap<PDefWorldFile> {
+public:
+ bool Load(const char* nName, const char* nFilename);
+ inline std::map<int32_t, PDefWorldFile*>::const_iterator ConstIteratorBegin() const { return mDefs.begin(); }
+ inline std::map<int32_t, PDefWorldFile*>::const_iterator ConstIteratorEnd() const { return mDefs.end(); }
+};
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-PDefWorldModel::PDefWorldModel()\r
-{\r
-}\r
-\r
-bool PDefWorldModel::LoadFromDef(PTokenList *Tokens)\r
-{\r
- int Idx=0;\r
- for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)\r
- {\r
- switch(Idx)\r
- {\r
- case 0: // setentry\r
- continue;\r
-\r
- case 1: // index\r
- mIndex = atoi(i->c_str()); break;\r
-\r
- case 2: // name\r
- mName = *i; break;\r
-\r
- case 3: // use flag\r
- mUseFlags = atoi(i->c_str()); break;\r
-\r
- case 4: // function type\r
- mFunctionType = atoi(i->c_str()); break;\r
-\r
- case 5: // function value\r
- mFunctionValue = atoi(i->c_str()); break;\r
-\r
- case 6: // hack difficulty\r
- mHackDifficulty = atoi(i->c_str()); break;\r
-\r
- case 7: // hack penalty\r
- mHackPenalty = atoi(i->c_str()); break;\r
- }\r
- }\r
-\r
- return true;\r
-}\r
+#include "GameServer/Definitions/Includes.hxx"
+
+PDefWorldModel::PDefWorldModel()
+{
+}
+
+bool PDefWorldModel::LoadFromDef(PTokenList *Tokens)
+{
+ int Idx=0;
+ for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++)
+ {
+ switch(Idx)
+ {
+ case 0: // setentry
+ continue;
+
+ case 1: // index
+ mIndex = atoi(i->c_str()); break;
+
+ case 2: // name
+ mName = *i; break;
+
+ case 3: // use flag
+ mUseFlags = atoi(i->c_str()); break;
+
+ case 4: // function type
+ mFunctionType = atoi(i->c_str()); break;
+
+ case 5: // function value
+ mFunctionValue = atoi(i->c_str()); break;
+
+ case 6: // hack difficulty
+ mHackDifficulty = atoi(i->c_str()); break;
+
+ case 7: // hack penalty
+ mHackPenalty = atoi(i->c_str()); break;
+ }
+ }
+
+ return true;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-#include "GameServer/Definitions/Definition.hxx"\r
-\r
-class PDefWorldModel : public PDef {\r
-private:\r
- //int32_t mIndex;\r
- std::string mName;\r
- int32_t mUseFlags;\r
- int32_t mFunctionType;\r
- int32_t mFunctionValue;\r
- int32_t mHackDifficulty;\r
- int32_t mHackPenalty;\r
-\r
-public:\r
- PDefWorldModel();\r
- //~PDefWorldModel();\r
-\r
- bool LoadFromDef(PTokenList *Tokens);\r
-\r
- inline int32_t GetID() const { return mIndex; }\r
- inline const std::string &GetName() const { return mName; }\r
- inline int32_t GetUseFlags() const { return mUseFlags; }\r
- inline int32_t GetFunctionType() const { return mFunctionType; }\r
- inline int32_t GetFunctionValue() const { return mFunctionValue; }\r
- inline int32_t GetHackDifficulty() const { return mHackDifficulty; }\r
- inline int32_t GetHackPenalty() const { return mHackPenalty; }\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include "GameServer/Definitions/Definition.hxx"
+
+class PDefWorldModel : public PDef {
+private:
+ //int32_t mIndex;
+ std::string mName;
+ int32_t mUseFlags;
+ int32_t mFunctionType;
+ int32_t mFunctionValue;
+ int32_t mHackDifficulty;
+ int32_t mHackPenalty;
+
+public:
+ PDefWorldModel();
+ //~PDefWorldModel();
+
+ bool LoadFromDef(PTokenList *Tokens);
+
+ inline int32_t GetID() const { return mIndex; }
+ inline const std::string &GetName() const { return mName; }
+ inline int32_t GetUseFlags() const { return mUseFlags; }
+ inline int32_t GetFunctionType() const { return mFunctionType; }
+ inline int32_t GetFunctionValue() const { return mFunctionValue; }
+ inline int32_t GetHackDifficulty() const { return mHackDifficulty; }
+ inline int32_t GetHackPenalty() const { return mHackPenalty; }
+};
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-PDefWorld::PDefWorld()\r
-{\r
-}\r
-\r
-bool PDefWorld::LoadFromDef( PTokenList *Tokens )\r
-{\r
- int Idx = 0;\r
- int StartPos = 0;\r
- int TailLen = 0;\r
- int Len;\r
-\r
- for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )\r
- {\r
- switch ( Idx )\r
- {\r
- case 0: // setentry\r
- continue;\r
- case 3: // music\r
- continue;\r
-\r
- case 1: // index\r
- mIndex = atoi( i->c_str() ); break;\r
-\r
- case 2: // name\r
- {\r
- Len = ( *i ).length();\r
-\r
- if (( *i )[0] == '\"' )\r
- StartPos = 1;\r
-\r
- while (( *i )[StartPos] == ' ' )\r
- ++StartPos;\r
-\r
- if (( *i )[Len-1] == '\"' )\r
- TailLen = 1;\r
-\r
- while (( Len - TailLen > 0 ) && (( *i )[Len-TailLen-1] == ' ' ) )\r
- ++TailLen;\r
-\r
- if ( StartPos >= Len - TailLen )\r
- mName = "";\r
- else\r
- mName = ( *i ).substr( StartPos, Len - StartPos - TailLen );\r
-\r
- break;\r
- }\r
-\r
- case 4: // datfile\r
- {\r
- Len = ( *i ).length();\r
-\r
- while (( StartPos = ( *i ).find( "\\", StartPos ) ) > -1 )\r
- ( *i )[StartPos] = '/';\r
- StartPos = 0;\r
-\r
- if (( *i )[0] == '\"' )\r
- StartPos = 1;\r
-\r
- while (( *i )[StartPos] == ' ' )\r
- ++StartPos;\r
-\r
- if (( StartPos <= Len - 2 ) && (( *i ).substr( StartPos, 2 ) == "./" ) )\r
- StartPos += 2;\r
-\r
- if (( *i )[Len-1] == '\"' )\r
- TailLen = 1;\r
-\r
- while (( Len - TailLen > 0 ) && (( *i )[Len-TailLen-1] == ' ' ) )\r
- ++TailLen;\r
-\r
- if ( StartPos >= Len - TailLen )\r
- mDatFile = "";\r
- else\r
- mDatFile = ( *i ).substr( StartPos, Len - StartPos - TailLen );\r
-\r
- break;\r
- }\r
-\r
- case 5:\r
- mFlags = atoi( i->c_str() ); break;\r
- }\r
- }\r
-\r
- return true;\r
-}\r
-\r
+#include "GameServer/Definitions/Includes.hxx"
+
+PDefWorld::PDefWorld()
+{
+}
+
+bool PDefWorld::LoadFromDef( PTokenList *Tokens )
+{
+ int Idx = 0;
+ int StartPos = 0;
+ int TailLen = 0;
+ int Len;
+
+ for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ )
+ {
+ switch ( Idx )
+ {
+ case 0: // setentry
+ continue;
+ case 3: // music
+ continue;
+
+ case 1: // index
+ mIndex = atoi( i->c_str() ); break;
+
+ case 2: // name
+ {
+ Len = ( *i ).length();
+
+ if (( *i )[0] == '\"' )
+ StartPos = 1;
+
+ while (( *i )[StartPos] == ' ' )
+ ++StartPos;
+
+ if (( *i )[Len-1] == '\"' )
+ TailLen = 1;
+
+ while (( Len - TailLen > 0 ) && (( *i )[Len-TailLen-1] == ' ' ) )
+ ++TailLen;
+
+ if ( StartPos >= Len - TailLen )
+ mName = "";
+ else
+ mName = ( *i ).substr( StartPos, Len - StartPos - TailLen );
+
+ break;
+ }
+
+ case 4: // datfile
+ {
+ Len = ( *i ).length();
+
+ while (( StartPos = ( *i ).find( "\\", StartPos ) ) > -1 )
+ ( *i )[StartPos] = '/';
+ StartPos = 0;
+
+ if (( *i )[0] == '\"' )
+ StartPos = 1;
+
+ while (( *i )[StartPos] == ' ' )
+ ++StartPos;
+
+ if (( StartPos <= Len - 2 ) && (( *i ).substr( StartPos, 2 ) == "./" ) )
+ StartPos += 2;
+
+ if (( *i )[Len-1] == '\"' )
+ TailLen = 1;
+
+ while (( Len - TailLen > 0 ) && (( *i )[Len-TailLen-1] == ' ' ) )
+ ++TailLen;
+
+ if ( StartPos >= Len - TailLen )
+ mDatFile = "";
+ else
+ mDatFile = ( *i ).substr( StartPos, Len - StartPos - TailLen );
+
+ break;
+ }
+
+ case 5:
+ mFlags = atoi( i->c_str() ); break;
+ }
+ }
+
+ return true;
+}
+
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-#include "GameServer/Definitions/Definition.hxx"\r
-\r
-class PDefWorld : public PDef {\r
-private:\r
- //int32_t mIndex;\r
- std::string mName;\r
- std::string mDatFile;\r
- int32_t mFlags;\r
-\r
-public:\r
- PDefWorld();\r
- //~PDefWorld();\r
-\r
- bool LoadFromDef(PTokenList *Tokens);\r
-\r
- inline const std::string &GetName() const { return mName; }\r
- inline const std::string &GetDatFile() const { return mDatFile; }\r
- inline int32_t GetFlags() const { return mFlags; }\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+#include "GameServer/Definitions/Definition.hxx"
+
+class PDefWorld : public PDef {
+private:
+ //int32_t mIndex;
+ std::string mName;
+ std::string mDatFile;
+ int32_t mFlags;
+
+public:
+ PDefWorld();
+ //~PDefWorld();
+
+ bool LoadFromDef(PTokenList *Tokens);
+
+ inline const std::string &GetName() const { return mName; }
+ inline const std::string &GetDatFile() const { return mDatFile; }
+ inline int32_t GetFlags() const { return mFlags; }
+};
-#include <cstring>\r
-#include "GameServer/Includes.hxx"\r
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-// TODO: - mem corruption occurs if mDoorParameters[] is given a size of 6, and that 6 max param can be accepted\r
-// This bug occurs in world 105. Reason not found yet :-x\r
-\r
-const std::string EmptyString;\r
-\r
-PDoorTemplate::PDoorTemplate()\r
-{\r
- mDoorID = 0;\r
- mWorldmodelID = 0;\r
- mDefWorldModel = NULL;\r
- mIsDoubleDoor = false;\r
- mIsTriggeredDoor = false;\r
-}\r
-\r
-PDoorTemplate::~PDoorTemplate()\r
-{\r
-}\r
-\r
-uint16_t PDoorTemplate::GetID()\r
-{\r
- return mDoorID;\r
-}\r
-\r
-uint16_t PDoorTemplate::GetUseFlags()\r
-{\r
- return (mDefWorldModel ? mDefWorldModel->GetUseFlags() : 0);\r
-}\r
-\r
-uint16_t PDoorTemplate::GetFunctionType()\r
-{\r
- return (mDefWorldModel ? mDefWorldModel->GetFunctionType() : 0);\r
-}\r
-\r
-int PDoorTemplate::GetFunctionValue()\r
-{\r
- return (mDefWorldModel ? mDefWorldModel->GetFunctionValue() : 0);\r
-}\r
-\r
-const std::string& PDoorTemplate::GetName() const\r
-{\r
- return (mDefWorldModel ? mDefWorldModel->GetName() : EmptyString );\r
-}\r
-\r
-const PDefWorldModel *PDoorTemplate::GetDefWorldModel() const\r
-{\r
- return mDefWorldModel;\r
-}\r
-\r
-void PDoorTemplate::GetPos(float *nPosX, float *nPosY, float *nPosZ) const\r
-{\r
- *nPosY = mPosY;\r
- *nPosZ = mPosZ;\r
- *nPosX = mPosX;\r
-}\r
-\r
-uint16_t PDoorTemplate::GetOtherDoorID()\r
-{\r
- return (mIsDoubleDoor ? mDoorParameters[1] : 0);\r
-}\r
-\r
-bool PDoorTemplate::IsDoubleDoor() const\r
-{\r
- return mIsDoubleDoor;\r
-}\r
-\r
-bool PDoorTemplate::IsTriggeredDoor() const\r
-{\r
- return mIsTriggeredDoor;\r
-}\r
-\r
-void PDoorTemplate::SetDoorParameters(char* nDoorParametersString)\r
-{\r
- char* SepPos;\r
- int ParamNum = 0;\r
-//Console->Print("door parameter: %s", nDoorParametersString);\r
- while ( *nDoorParametersString && (SepPos = strchr(nDoorParametersString, ',')) && (ParamNum < 4))\r
- {\r
- *SepPos = 0;\r
- mDoorParameters[ParamNum++] = atoi(nDoorParametersString);\r
- nDoorParametersString = SepPos + 1;\r
- }\r
- if (*nDoorParametersString)\r
- {\r
- if (ParamNum < 4)\r
- mDoorParameters[ParamNum] = atoi(nDoorParametersString);\r
- //else\r
- // Console->Print(RED, BLACK, "[ERROR] More than 4 parameters in Sec2ElemType5 ParamString");\r
- }\r
-}\r
-\r
-void PDoorTemplate::SetDoorTypeName(char* nDoorTypeName)\r
-{\r
- mDoorTypeName = nDoorTypeName;\r
-\r
- if (mDoorTypeName == "DDOOR")\r
- {\r
- mIsDoubleDoor = true;\r
- }\r
- else if (mDoorTypeName == "TRIGDD")\r
- {\r
- mIsDoubleDoor = true;\r
- mIsTriggeredDoor = true;\r
- }\r
- else if (mDoorTypeName == "TRIGDOOR")\r
- {\r
- mIsTriggeredDoor = true;\r
- }\r
- else if (mDoorTypeName == "NBUTTON")\r
- {\r
- mIsTriggeredDoor = false;\r
- }\r
-}\r
+#include <cstring>
+#include "GameServer/Includes.hxx"
+#include "GameServer/Definitions/Includes.hxx"
+
+// TODO: - mem corruption occurs if mDoorParameters[] is given a size of 6, and that 6 max param can be accepted
+// This bug occurs in world 105. Reason not found yet :-x
+
+const std::string EmptyString;
+
+PDoorTemplate::PDoorTemplate()
+{
+ mDoorID = 0;
+ mWorldmodelID = 0;
+ mDefWorldModel = NULL;
+ mIsDoubleDoor = false;
+ mIsTriggeredDoor = false;
+}
+
+PDoorTemplate::~PDoorTemplate()
+{
+}
+
+uint16_t PDoorTemplate::GetID()
+{
+ return mDoorID;
+}
+
+uint16_t PDoorTemplate::GetUseFlags()
+{
+ return (mDefWorldModel ? mDefWorldModel->GetUseFlags() : 0);
+}
+
+uint16_t PDoorTemplate::GetFunctionType()
+{
+ return (mDefWorldModel ? mDefWorldModel->GetFunctionType() : 0);
+}
+
+int PDoorTemplate::GetFunctionValue()
+{
+ return (mDefWorldModel ? mDefWorldModel->GetFunctionValue() : 0);
+}
+
+const std::string& PDoorTemplate::GetName() const
+{
+ return (mDefWorldModel ? mDefWorldModel->GetName() : EmptyString );
+}
+
+const PDefWorldModel *PDoorTemplate::GetDefWorldModel() const
+{
+ return mDefWorldModel;
+}
+
+void PDoorTemplate::GetPos(float *nPosX, float *nPosY, float *nPosZ) const
+{
+ *nPosY = mPosY;
+ *nPosZ = mPosZ;
+ *nPosX = mPosX;
+}
+
+uint16_t PDoorTemplate::GetOtherDoorID()
+{
+ return (mIsDoubleDoor ? mDoorParameters[1] : 0);
+}
+
+bool PDoorTemplate::IsDoubleDoor() const
+{
+ return mIsDoubleDoor;
+}
+
+bool PDoorTemplate::IsTriggeredDoor() const
+{
+ return mIsTriggeredDoor;
+}
+
+void PDoorTemplate::SetDoorParameters(char* nDoorParametersString)
+{
+ char* SepPos;
+ int ParamNum = 0;
+//Console->Print("door parameter: %s", nDoorParametersString);
+ while ( *nDoorParametersString && (SepPos = strchr(nDoorParametersString, ',')) && (ParamNum < 4))
+ {
+ *SepPos = 0;
+ mDoorParameters[ParamNum++] = atoi(nDoorParametersString);
+ nDoorParametersString = SepPos + 1;
+ }
+ if (*nDoorParametersString)
+ {
+ if (ParamNum < 4)
+ mDoorParameters[ParamNum] = atoi(nDoorParametersString);
+ //else
+ // Console->Print(RED, BLACK, "[ERROR] More than 4 parameters in Sec2ElemType5 ParamString");
+ }
+}
+
+void PDoorTemplate::SetDoorTypeName(char* nDoorTypeName)
+{
+ mDoorTypeName = nDoorTypeName;
+
+ if (mDoorTypeName == "DDOOR")
+ {
+ mIsDoubleDoor = true;
+ }
+ else if (mDoorTypeName == "TRIGDD")
+ {
+ mIsDoubleDoor = true;
+ mIsTriggeredDoor = true;
+ }
+ else if (mDoorTypeName == "TRIGDOOR")
+ {
+ mIsTriggeredDoor = true;
+ }
+ else if (mDoorTypeName == "NBUTTON")
+ {
+ mIsTriggeredDoor = false;
+ }
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-\r
-class PDefWorldModel;\r
-\r
-class PDoorTemplate {\r
- friend class PWorldDatParser;\r
-\r
-private:\r
- uint16_t mDoorID;\r
-\r
- // The commented out values are not loaded from dat file atm because they are not used yet.\r
- //uint16_t mUnknown1; //18 00\r
- //uint16_t mUnknown1bis; //00 00 ? varies\r
- float mPosY;\r
- float mPosZ;\r
- float mPosX;\r
- //uint16_t mUnknown5; //00 00 ? second byte varies\r
- uint16_t mWorldmodelID; //door type from worldmodel.def\r
-\r
- std::string mDoorTypeName;\r
- int mDoorParameters[4];\r
- bool mIsDoubleDoor;\r
- bool mIsTriggeredDoor;\r
-\r
- const PDefWorldModel* mDefWorldModel;\r
-\r
-public:\r
- PDoorTemplate();\r
- ~PDoorTemplate();\r
-\r
- uint16_t GetID();\r
- uint16_t GetUseFlags();\r
- uint16_t GetFunctionType();\r
- int GetFunctionValue();\r
- const std::string& GetName() const; /// !!!!\r
- const PDefWorldModel *GetDefWorldModel() const;\r
-\r
- void GetPos(float *nPosX, float *nPosY, float *nPosZ) const;\r
- uint16_t GetOtherDoorID();\r
- bool IsDoubleDoor() const;\r
- bool IsTriggeredDoor() const;\r
-\r
- void SetDoorTypeName(char* nDoorTypeName);\r
- void SetDoorParameters(char* nDoorParametersString);\r
-};\r
+#pragma once
+
+#include <cstdint>
+
+class PDefWorldModel;
+
+class PDoorTemplate {
+ friend class PWorldDatParser;
+
+private:
+ uint16_t mDoorID;
+
+ // The commented out values are not loaded from dat file atm because they are not used yet.
+ //uint16_t mUnknown1; //18 00
+ //uint16_t mUnknown1bis; //00 00 ? varies
+ float mPosY;
+ float mPosZ;
+ float mPosX;
+ //uint16_t mUnknown5; //00 00 ? second byte varies
+ uint16_t mWorldmodelID; //door type from worldmodel.def
+
+ std::string mDoorTypeName;
+ int mDoorParameters[4];
+ bool mIsDoubleDoor;
+ bool mIsTriggeredDoor;
+
+ const PDefWorldModel* mDefWorldModel;
+
+public:
+ PDoorTemplate();
+ ~PDoorTemplate();
+
+ uint16_t GetID();
+ uint16_t GetUseFlags();
+ uint16_t GetFunctionType();
+ int GetFunctionValue();
+ const std::string& GetName() const; /// !!!!
+ const PDefWorldModel *GetDefWorldModel() const;
+
+ void GetPos(float *nPosX, float *nPosY, float *nPosZ) const;
+ uint16_t GetOtherDoorID();
+ bool IsDoubleDoor() const;
+ bool IsTriggeredDoor() const;
+
+ void SetDoorTypeName(char* nDoorTypeName);
+ void SetDoorParameters(char* nDoorParametersString);
+};
-#include "GameServer/Includes.hxx"\r
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-const std::string EmptyString;\r
-\r
-PFurnitureItemTemplate::PFurnitureItemTemplate()\r
-{\r
- mObjectID = 0;\r
- mModelID = 0;\r
- mWorldmodelID = 0;\r
- mDefWorldModel = NULL;\r
- mLinkedObjectID = 0;\r
-}\r
-\r
-PFurnitureItemTemplate::~PFurnitureItemTemplate()\r
-{\r
-}\r
-\r
-uint32_t PFurnitureItemTemplate::GetID() const\r
-{\r
- return mObjectID;\r
-}\r
-\r
-uint16_t PFurnitureItemTemplate::GetUseFlags() const\r
-{\r
- return (mDefWorldModel ? mDefWorldModel->GetUseFlags() : 0);\r
-}\r
-\r
-uint16_t PFurnitureItemTemplate::GetFunctionType() const\r
-{\r
- return (mDefWorldModel ? mDefWorldModel->GetFunctionType() : 0);\r
-}\r
-\r
-int PFurnitureItemTemplate::GetFunctionValue() const\r
-{\r
- return (mDefWorldModel ? mDefWorldModel->GetFunctionValue() : 0);\r
-}\r
-\r
-const std::string &PFurnitureItemTemplate::GetName() const\r
-{\r
- return (mDefWorldModel ? mDefWorldModel->GetName() : EmptyString);\r
-}\r
-\r
-const PDefWorldModel *PFurnitureItemTemplate::GetDefWorldModel() const\r
-{\r
- return mDefWorldModel;\r
-}\r
-\r
-uint8_t PFurnitureItemTemplate::GetFrontLR() const\r
-{\r
- return mFrontLR;\r
-}\r
-\r
-void PFurnitureItemTemplate::GetFrontPos(uint16_t *nFrontPosX, uint16_t *nFrontPosY, uint16_t *nFrontPosZ) const\r
-{\r
- *nFrontPosY = mFrontPosY;\r
- *nFrontPosZ = mFrontPosZ;\r
- *nFrontPosX = mFrontPosX;\r
-}\r
-\r
-void PFurnitureItemTemplate::GetPos(float *nPosX, float *nPosY, float *nPosZ) const\r
-{\r
- *nPosY = mPosY;\r
- *nPosZ = mPosZ;\r
- *nPosX = mPosX;\r
-}\r
-\r
-void PFurnitureItemTemplate::SetLinkedObjectID(uint32_t nID)\r
-{\r
- mLinkedObjectID = nID;\r
-}\r
-\r
-uint32_t PFurnitureItemTemplate::GetLinkedObjectID() const\r
-{\r
- return mLinkedObjectID;\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "GameServer/Definitions/Includes.hxx"
+
+const std::string EmptyString;
+
+PFurnitureItemTemplate::PFurnitureItemTemplate()
+{
+ mObjectID = 0;
+ mModelID = 0;
+ mWorldmodelID = 0;
+ mDefWorldModel = NULL;
+ mLinkedObjectID = 0;
+}
+
+PFurnitureItemTemplate::~PFurnitureItemTemplate()
+{
+}
+
+uint32_t PFurnitureItemTemplate::GetID() const
+{
+ return mObjectID;
+}
+
+uint16_t PFurnitureItemTemplate::GetUseFlags() const
+{
+ return (mDefWorldModel ? mDefWorldModel->GetUseFlags() : 0);
+}
+
+uint16_t PFurnitureItemTemplate::GetFunctionType() const
+{
+ return (mDefWorldModel ? mDefWorldModel->GetFunctionType() : 0);
+}
+
+int PFurnitureItemTemplate::GetFunctionValue() const
+{
+ return (mDefWorldModel ? mDefWorldModel->GetFunctionValue() : 0);
+}
+
+const std::string &PFurnitureItemTemplate::GetName() const
+{
+ return (mDefWorldModel ? mDefWorldModel->GetName() : EmptyString);
+}
+
+const PDefWorldModel *PFurnitureItemTemplate::GetDefWorldModel() const
+{
+ return mDefWorldModel;
+}
+
+uint8_t PFurnitureItemTemplate::GetFrontLR() const
+{
+ return mFrontLR;
+}
+
+void PFurnitureItemTemplate::GetFrontPos(uint16_t *nFrontPosX, uint16_t *nFrontPosY, uint16_t *nFrontPosZ) const
+{
+ *nFrontPosY = mFrontPosY;
+ *nFrontPosZ = mFrontPosZ;
+ *nFrontPosX = mFrontPosX;
+}
+
+void PFurnitureItemTemplate::GetPos(float *nPosX, float *nPosY, float *nPosZ) const
+{
+ *nPosY = mPosY;
+ *nPosZ = mPosZ;
+ *nPosX = mPosX;
+}
+
+void PFurnitureItemTemplate::SetLinkedObjectID(uint32_t nID)
+{
+ mLinkedObjectID = nID;
+}
+
+uint32_t PFurnitureItemTemplate::GetLinkedObjectID() const
+{
+ return mLinkedObjectID;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-\r
-class PDefWorldModel;\r
-\r
-enum { // Furniture Use flags (cumlative)\r
- ufTouchable = 1,\r
- ufUsable = 2,\r
- ufNoCollision = 4,\r
- ufChair = 8,\r
- ufToolTarget = 16,\r
- ufSelfCollisionBox = 64,\r
- ufGraphicalEffect = 128,\r
- ufNoSelectionBox = 256\r
-};\r
-\r
-class PFurnitureItemTemplate {\r
- friend class PWorldDatParser;\r
-\r
-private:\r
- uint32_t mObjectID;\r
-\r
- // The commented out values are not loaded from dat file atm because they are not used yet.\r
- float mPosY; //= mPosY from dat file + 32000, to be coherent with char Pos scale\r
- float mPosZ;\r
- float mPosX;\r
- //float mRotY;\r
- float mRotZ;\r
- //float mRotX;\r
- //uint32_t mScale; //00 00 80 3F ? = float(1.0000) scale factor ? // mostly used by holoscreens (passiv object)\r
- //uint32_t mUnknown2; //01 00 00 00 ?\r
- uint16_t mModelID; // points to models.ini\r
- //uint32_t mUnknown3; //00 00 00 00 ?\r
- //uint32_t mUnknown4; //00 00 00 00 ?\r
- uint16_t mWorldmodelID; // points to worldmodel.def\r
- //uint16_t mUnknown5; //12 00 ? // changes sometime (ex: c288 ...)\r
-\r
- //float mBoxLowerY; //Bounding box, for use when ufSelfCollisionBox is set in mUseFlags.\r
- //float mBoxLowerZ;\r
- //float mBoxLowerX;\r
- //float mBoxUpperY;\r
- //float mBoxUpperZ;\r
- //float mBoxUpperX;\r
-\r
- uint16_t mFrontPosY;\r
- uint16_t mFrontPosZ;\r
- uint16_t mFrontPosX;\r
- uint8_t mFrontLR;\r
-\r
- const PDefWorldModel* mDefWorldModel;\r
-\r
- uint32_t mLinkedObjectID; // for buttons, stores the corresponding triggered door\r
- // fo GR, stores order of the GR entity (spawn point) to later choose from respawn.def data\r
-\r
- public:\r
- PFurnitureItemTemplate();\r
- ~PFurnitureItemTemplate();\r
-\r
- uint32_t GetID() const;\r
- uint16_t GetUseFlags() const;\r
- uint16_t GetFunctionType() const;\r
- int GetFunctionValue() const;\r
- const std::string &GetName() const; /// !!!!\r
- const PDefWorldModel *GetDefWorldModel() const;\r
- uint8_t GetFrontLR() const;\r
- void GetFrontPos(uint16_t *nFrontPosX, uint16_t *nFrontPosY, uint16_t *nFrontPosZ) const;\r
- void GetPos(float *nPosX, float *nPosY, float *nPosZ) const;\r
-\r
- void SetLinkedObjectID(uint32_t nID);\r
- uint32_t GetLinkedObjectID() const;\r
-};\r
-\r
-// *** from worldmodel.def ***\r
-\r
-//function Type\r
-// 0 - none\r
-// 1 - Itemcontainer\r
-// 2 - Terminal\r
-// 3 - Outfitter\r
-// 4 - Trader\r
-// 5 - Mineral\r
-// 6 - Respawn Station\r
-// 7 - GoGuardian\r
-// 8 - Hackterminal\r
-// 9 - Appartement Eingang\r
-// 10 - Appartement Ein/Ausgang\r
-// 11 - Appartement Klingel/�ffner\r
-// 12 - Standard Button\r
-// 13 - Hack Button\r
-// 14 - HOLOMATCH ENTRANCE\r
-// 15 - HOLOMATCH EXIT\r
-// 16 - HOLOMATCH REFRESH\r
-// 17 - HOLOMATCH HEAL\r
-// 18 - WORLDCHANGEACTOR\r
-// 19 - CLANTERMINAL\r
-// 20 - DATFILE WORLDCHANGE ACTOR\r
-// 21 - LOCATION FOR 20\r
-// 22 -\r
-// 23 - EINTRITTSGELD BUTTON\r
-// 24- TUTORIALEXIT\r
-// 25 - EXPLOSIVE\r
-// 26 - Outpost Switch\r
-// 27 - Old goguardian\r
-// 28 - Fahrzeug Depot Interface\r
-// 29 - Underground Exit\r
-// 30 - Static FX (Value=Type. 1=Fire 2=Smoke 3=Steam 4=Sparkle)\r
-// 31 - Venture Warp Station\r
-// 32 - functionvalue+100 gibt eine Meldung aus der Text.ini [MISC] an.\r
-//\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+class PDefWorldModel;
+
+enum { // Furniture Use flags (cumlative)
+ ufTouchable = 1,
+ ufUsable = 2,
+ ufNoCollision = 4,
+ ufChair = 8,
+ ufToolTarget = 16,
+ ufSelfCollisionBox = 64,
+ ufGraphicalEffect = 128,
+ ufNoSelectionBox = 256
+};
+
+class PFurnitureItemTemplate {
+ friend class PWorldDatParser;
+
+private:
+ uint32_t mObjectID;
+
+ // The commented out values are not loaded from dat file atm because they are not used yet.
+ float mPosY; //= mPosY from dat file + 32000, to be coherent with char Pos scale
+ float mPosZ;
+ float mPosX;
+ //float mRotY;
+ float mRotZ;
+ //float mRotX;
+ //uint32_t mScale; //00 00 80 3F ? = float(1.0000) scale factor ? // mostly used by holoscreens (passiv object)
+ //uint32_t mUnknown2; //01 00 00 00 ?
+ uint16_t mModelID; // points to models.ini
+ //uint32_t mUnknown3; //00 00 00 00 ?
+ //uint32_t mUnknown4; //00 00 00 00 ?
+ uint16_t mWorldmodelID; // points to worldmodel.def
+ //uint16_t mUnknown5; //12 00 ? // changes sometime (ex: c288 ...)
+
+ //float mBoxLowerY; //Bounding box, for use when ufSelfCollisionBox is set in mUseFlags.
+ //float mBoxLowerZ;
+ //float mBoxLowerX;
+ //float mBoxUpperY;
+ //float mBoxUpperZ;
+ //float mBoxUpperX;
+
+ uint16_t mFrontPosY;
+ uint16_t mFrontPosZ;
+ uint16_t mFrontPosX;
+ uint8_t mFrontLR;
+
+ const PDefWorldModel* mDefWorldModel;
+
+ uint32_t mLinkedObjectID; // for buttons, stores the corresponding triggered door
+ // fo GR, stores order of the GR entity (spawn point) to later choose from respawn.def data
+
+ public:
+ PFurnitureItemTemplate();
+ ~PFurnitureItemTemplate();
+
+ uint32_t GetID() const;
+ uint16_t GetUseFlags() const;
+ uint16_t GetFunctionType() const;
+ int GetFunctionValue() const;
+ const std::string &GetName() const; /// !!!!
+ const PDefWorldModel *GetDefWorldModel() const;
+ uint8_t GetFrontLR() const;
+ void GetFrontPos(uint16_t *nFrontPosX, uint16_t *nFrontPosY, uint16_t *nFrontPosZ) const;
+ void GetPos(float *nPosX, float *nPosY, float *nPosZ) const;
+
+ void SetLinkedObjectID(uint32_t nID);
+ uint32_t GetLinkedObjectID() const;
+};
+
+// *** from worldmodel.def ***
+
+//function Type
+// 0 - none
+// 1 - Itemcontainer
+// 2 - Terminal
+// 3 - Outfitter
+// 4 - Trader
+// 5 - Mineral
+// 6 - Respawn Station
+// 7 - GoGuardian
+// 8 - Hackterminal
+// 9 - Appartement Eingang
+// 10 - Appartement Ein/Ausgang
+// 11 - Appartement Klingel/�ffner
+// 12 - Standard Button
+// 13 - Hack Button
+// 14 - HOLOMATCH ENTRANCE
+// 15 - HOLOMATCH EXIT
+// 16 - HOLOMATCH REFRESH
+// 17 - HOLOMATCH HEAL
+// 18 - WORLDCHANGEACTOR
+// 19 - CLANTERMINAL
+// 20 - DATFILE WORLDCHANGE ACTOR
+// 21 - LOCATION FOR 20
+// 22 -
+// 23 - EINTRITTSGELD BUTTON
+// 24- TUTORIALEXIT
+// 25 - EXPLOSIVE
+// 26 - Outpost Switch
+// 27 - Old goguardian
+// 28 - Fahrzeug Depot Interface
+// 29 - Underground Exit
+// 30 - Static FX (Value=Type. 1=Fire 2=Smoke 3=Steam 4=Sparkle)
+// 31 - Venture Warp Station
+// 32 - functionvalue+100 gibt eine Meldung aus der Text.ini [MISC] an.
+//
-#include <cstring>\r
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdban()\r
-{\r
- bool SyntaxError = false;\r
- if(ArgC < 2)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- if(SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@ban <charID or nickname> <xS(econds)>/<xM(inutes)>/<xH(ours)>/<xD(ays)>");\r
- return;\r
- }\r
-\r
- if(IsArgNumeric(1) == true)\r
- {\r
- target = GetClientByID(GetArgInt(1));\r
- }\r
- else\r
- {\r
- char tmp_destNick[50];\r
- GetArgText(1, tmp_destNick, 50);\r
- target = GetClientByNick(tmp_destNick);\r
- }\r
-\r
- if(target == nullptr) // If victim isnt found, return error\r
- {\r
- Chat->send(source, CHAT_DIRECT, "System", "No such player");\r
- return;\r
- }\r
- if(source->GetAccountLevel() <= target->GetAccountLevel())\r
- {\r
- char tmpMsg[200];\r
- snprintf(tmpMsg, 199, "Cant ban %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());\r
- tmpMsg[199] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", tmpMsg);\r
- return;\r
- }\r
- char tmpTimeVal[10];\r
- GetArgText(2, tmpTimeVal, 10);\r
-\r
- int32_t loop_i = 0;\r
- char tmp_atoi[10];\r
-\r
- while(isdigit(tmpTimeVal[loop_i]) != 0 && loop_i < 10)\r
- {\r
- tmp_atoi[loop_i] = tmpTimeVal[loop_i];\r
- loop_i++;\r
- }\r
- char timefactor[1];\r
- timefactor[0] = tmpTimeVal[loop_i];\r
- int32_t timevalue = atoi(tmp_atoi);\r
- int32_t time_to_ban = 0;\r
-\r
- if(strcasecmp(timefactor, "s") == 0 )\r
- {\r
- time_to_ban = timevalue;\r
- }\r
- else if(strcasecmp(timefactor, "m") == 0 )\r
- {\r
- time_to_ban = timevalue * 60;\r
- }\r
- else if(strcasecmp(timefactor, "h") == 0 )\r
- {\r
- time_to_ban = timevalue * 60 * 60;\r
- }\r
- else if(strcasecmp(timefactor, "d") == 0 )\r
- {\r
- time_to_ban = timevalue * 60 * 60 * 24;\r
- }\r
- else\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@ban <charID or nickname> <xS(econds)>/<xM(inutes)>/<xH(ours)>/<xD(ays)>");\r
- return;\r
- }\r
-\r
- int32_t final_bantime = std::time(nullptr) + time_to_ban;\r
- PAccount Acc(target->GetAccountID());\r
- Acc.SetBannedUntilTime(final_bantime);\r
- Acc.Save();\r
-\r
- target->InitCharVanish();\r
-\r
- GameServer->ClientDisconnected(target); // Now kick the player (Hes banned :) )\r
-\r
- char tmpMsg_success[81];\r
- snprintf(tmpMsg_success, 80, "Successfully banned %s", target->GetChar()->GetName().c_str());\r
- tmpMsg_success[80] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success);\r
- return;\r
-}\r
+#include <cstring>
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdban()
+{
+ bool SyntaxError = false;
+ if(ArgC < 2)
+ {
+ SyntaxError = true;
+ }
+
+ if(SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@ban <charID or nickname> <xS(econds)>/<xM(inutes)>/<xH(ours)>/<xD(ays)>");
+ return;
+ }
+
+ if(IsArgNumeric(1) == true)
+ {
+ target = GetClientByID(GetArgInt(1));
+ }
+ else
+ {
+ char tmp_destNick[50];
+ GetArgText(1, tmp_destNick, 50);
+ target = GetClientByNick(tmp_destNick);
+ }
+
+ if(target == nullptr) // If victim isnt found, return error
+ {
+ Chat->send(source, CHAT_DIRECT, "System", "No such player");
+ return;
+ }
+ if(source->GetAccountLevel() <= target->GetAccountLevel())
+ {
+ char tmpMsg[200];
+ snprintf(tmpMsg, 199, "Cant ban %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());
+ tmpMsg[199] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", tmpMsg);
+ return;
+ }
+ char tmpTimeVal[10];
+ GetArgText(2, tmpTimeVal, 10);
+
+ int32_t loop_i = 0;
+ char tmp_atoi[10];
+
+ while(isdigit(tmpTimeVal[loop_i]) != 0 && loop_i < 10)
+ {
+ tmp_atoi[loop_i] = tmpTimeVal[loop_i];
+ loop_i++;
+ }
+ char timefactor[1];
+ timefactor[0] = tmpTimeVal[loop_i];
+ int32_t timevalue = atoi(tmp_atoi);
+ int32_t time_to_ban = 0;
+
+ if(strcasecmp(timefactor, "s") == 0 )
+ {
+ time_to_ban = timevalue;
+ }
+ else if(strcasecmp(timefactor, "m") == 0 )
+ {
+ time_to_ban = timevalue * 60;
+ }
+ else if(strcasecmp(timefactor, "h") == 0 )
+ {
+ time_to_ban = timevalue * 60 * 60;
+ }
+ else if(strcasecmp(timefactor, "d") == 0 )
+ {
+ time_to_ban = timevalue * 60 * 60 * 24;
+ }
+ else
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@ban <charID or nickname> <xS(econds)>/<xM(inutes)>/<xH(ours)>/<xD(ays)>");
+ return;
+ }
+
+ int32_t final_bantime = std::time(nullptr) + time_to_ban;
+ PAccount Acc(target->GetAccountID());
+ Acc.SetBannedUntilTime(final_bantime);
+ Acc.Save();
+
+ target->InitCharVanish();
+
+ GameServer->ClientDisconnected(target); // Now kick the player (Hes banned :) )
+
+ char tmpMsg_success[81];
+ snprintf(tmpMsg_success, 80, "Successfully banned %s", target->GetChar()->GetName().c_str());
+ tmpMsg_success[80] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success);
+ return;
+}
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdbrightness()\r
-{\r
- bool SyntaxError = false;\r
- if(ArgC < 1)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- if(SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@brightness -|<head brightness: 0..255> [-|<torso brightness>] [-|<legs brightness>]");\r
- return;\r
- }\r
-\r
- char tmp_v1[30];\r
- char tmp_v2[30];\r
- char tmp_v3[30];\r
-\r
- GetArgText(1, tmp_v1, 30);\r
- GetArgText(2, tmp_v2, 30);\r
- GetArgText(3, tmp_v3, 30);\r
-\r
- uint8_t val1, val2, val3, val4, val5, val6;\r
- char effStr[128];\r
- PMessage* tmpMsg;\r
-\r
- source->GetChar()->GetCurrentBodyColor(val1, val2, val3, val4, val5, val6);\r
- if(tmp_v1[0] != '-')\r
- val4 = (uint8_t)(atoi(tmp_v1) & 0xff);\r
- if((tmp_v2[0] != '-') && (tmp_v2[0] != '\0'))\r
- val5 = (uint8_t)(atoi(tmp_v2) & 0xff);\r
- if((tmp_v3[0] != '-') && (tmp_v3[0] != '\0'))\r
- val6 = (uint8_t)(atoi(tmp_v3) & 0xff);\r
- source->GetChar()->SetCurrentBodyColor(val1, val2, val3, val4, val5, val6);\r
-\r
- tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
- ClientManager->UDPBroadcast(tmpMsg, source);\r
- snprintf(effStr, 127, "Body brightness set to values %d %d %d", val4, val5, val6);\r
- effStr[127] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", effStr);\r
-}\r
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdbrightness()
+{
+ bool SyntaxError = false;
+ if(ArgC < 1)
+ {
+ SyntaxError = true;
+ }
+
+ if(SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@brightness -|<head brightness: 0..255> [-|<torso brightness>] [-|<legs brightness>]");
+ return;
+ }
+
+ char tmp_v1[30];
+ char tmp_v2[30];
+ char tmp_v3[30];
+
+ GetArgText(1, tmp_v1, 30);
+ GetArgText(2, tmp_v2, 30);
+ GetArgText(3, tmp_v3, 30);
+
+ uint8_t val1, val2, val3, val4, val5, val6;
+ char effStr[128];
+ PMessage* tmpMsg;
+
+ source->GetChar()->GetCurrentBodyColor(val1, val2, val3, val4, val5, val6);
+ if(tmp_v1[0] != '-')
+ val4 = (uint8_t)(atoi(tmp_v1) & 0xff);
+ if((tmp_v2[0] != '-') && (tmp_v2[0] != '\0'))
+ val5 = (uint8_t)(atoi(tmp_v2) & 0xff);
+ if((tmp_v3[0] != '-') && (tmp_v3[0] != '\0'))
+ val6 = (uint8_t)(atoi(tmp_v3) & 0xff);
+ source->GetChar()->SetCurrentBodyColor(val1, val2, val3, val4, val5, val6);
+
+ tmpMsg = MsgBuilder->BuildCharHelloMsg(source);
+ ClientManager->UDPBroadcast(tmpMsg, source);
+ snprintf(effStr, 127, "Body brightness set to values %d %d %d", val4, val5, val6);
+ effStr[127] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", effStr);
+}
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-void PCommands::doCmdbroadcast()\r
-{\r
- if(DumbMade == false)\r
- {\r
- Console->Print("%s Missing packetdumb in PCommands::doCmdbroadcast for declared broadcast function!", Console->ColorText(RED, BLACK, "[PANIC]"));\r
- return;\r
- }\r
-\r
- Chat->sendBroadcast(OrgPacketDumb+11);\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+void PCommands::doCmdbroadcast()
+{
+ if(DumbMade == false)
+ {
+ Console->Print("%s Missing packetdumb in PCommands::doCmdbroadcast for declared broadcast function!", Console->ColorText(RED, BLACK, "[PANIC]"));
+ return;
+ }
+
+ Chat->sendBroadcast(OrgPacketDumb+11);
+}
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdcolor()\r
-{\r
- bool SyntaxError = false;\r
- if(ArgC < 1)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- if(SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@color -|<head color: 0..255> [-|<torso color>] [-|<legs color>]");\r
- return;\r
- }\r
-\r
- char tmp_v1[30];\r
- char tmp_v2[30];\r
- char tmp_v3[30];\r
-\r
- GetArgText(1, tmp_v1, 30);\r
- GetArgText(2, tmp_v2, 30);\r
- GetArgText(3, tmp_v3, 30);\r
-\r
- uint8_t val1, val2, val3, val4, val5, val6;\r
- char effStr[128];\r
- PMessage* tmpMsg;\r
-\r
- source->GetChar()->GetCurrentBodyColor(val1, val2, val3, val4, val5, val6);\r
- if(tmp_v1[0] != '-')\r
- val1 = (uint8_t)(atoi(tmp_v1) & 0xff);\r
- if((tmp_v2[0] != '-') && (tmp_v2[0] != '\0'))\r
- val2 = (uint8_t)(atoi(tmp_v2) & 0xff);\r
- if((tmp_v3[0] != '-') && (tmp_v3[0] != '\0'))\r
- val3 = (uint8_t)(atoi(tmp_v3) & 0xff);\r
- source->GetChar()->SetCurrentBodyColor(val1, val2, val3, val4, val5, val6);\r
-\r
- tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
- ClientManager->UDPBroadcast(tmpMsg, source);\r
- snprintf(effStr, 127, "Body color set to values %d %d %d", val1, val2, val3);\r
- effStr[127] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", effStr);\r
-}\r
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdcolor()
+{
+ bool SyntaxError = false;
+ if(ArgC < 1)
+ {
+ SyntaxError = true;
+ }
+
+ if(SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@color -|<head color: 0..255> [-|<torso color>] [-|<legs color>]");
+ return;
+ }
+
+ char tmp_v1[30];
+ char tmp_v2[30];
+ char tmp_v3[30];
+
+ GetArgText(1, tmp_v1, 30);
+ GetArgText(2, tmp_v2, 30);
+ GetArgText(3, tmp_v3, 30);
+
+ uint8_t val1, val2, val3, val4, val5, val6;
+ char effStr[128];
+ PMessage* tmpMsg;
+
+ source->GetChar()->GetCurrentBodyColor(val1, val2, val3, val4, val5, val6);
+ if(tmp_v1[0] != '-')
+ val1 = (uint8_t)(atoi(tmp_v1) & 0xff);
+ if((tmp_v2[0] != '-') && (tmp_v2[0] != '\0'))
+ val2 = (uint8_t)(atoi(tmp_v2) & 0xff);
+ if((tmp_v3[0] != '-') && (tmp_v3[0] != '\0'))
+ val3 = (uint8_t)(atoi(tmp_v3) & 0xff);
+ source->GetChar()->SetCurrentBodyColor(val1, val2, val3, val4, val5, val6);
+
+ tmpMsg = MsgBuilder->BuildCharHelloMsg(source);
+ ClientManager->UDPBroadcast(tmpMsg, source);
+ snprintf(effStr, 127, "Body color set to values %d %d %d", val1, val2, val3);
+ effStr[127] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", effStr);
+}
-#include <cstring>\r
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmddebug()\r
-{\r
- PDebugMode nWhat = DBG_ALL;\r
- int nHow = -1;\r
- const char* DbgTarget = "all";\r
- char DbgMessage[80];\r
- const char* Usage = "@debug [loc[ation] | it[emid] | sub[way]] [0|1]";\r
-\r
- if(ArgC > 0)\r
- {\r
- if(IsArgNumeric(1) == true)\r
- {\r
- if(GetArgInt(1) == 0)\r
- {\r
- nHow = 0;\r
- }\r
- else\r
- {\r
- nHow = 1;\r
- }\r
- }\r
- else\r
- {\r
- char tmp[10];\r
- if(GetArgText(1, tmp, 10))\r
- {\r
- if(strncmp(tmp, "loc", 3) == 0)\r
- {\r
- nWhat = DBG_LOCATION;\r
- DbgTarget = "location";\r
- }\r
- else if(strncmp(tmp, "it", 2) == 0)\r
- {\r
- nWhat = DBG_ITEMID;\r
- DbgTarget = "itemid";\r
- }\r
- else if(strncmp(tmp, "sub", 3) == 0)\r
- {\r
- nWhat = DBG_SUBWAY;\r
- DbgTarget = "subway";\r
- }\r
- }\r
- }\r
-\r
- if (nWhat != DBG_ALL)\r
- {\r
- if(ArgC == 1)\r
- {\r
- nHow = (source->GetDebugMode(nWhat) ? 0 : 1); // toggle if no arg\r
- }\r
- else if(ArgC > 1 && GetArgInt(2) == 0)\r
- {\r
- nHow = 0;\r
- }\r
- else if(ArgC > 1 && GetArgInt(2) == 1)\r
- {\r
- nHow = 1;\r
- }\r
- }\r
- }\r
-\r
- if (nHow != -1)\r
- {\r
- source->SetDebugMode(nWhat, nHow);\r
- snprintf(DbgMessage, 80, "Debug %s is now %s", DbgTarget, (nHow ? "ENABLED" : "DISABLED"));\r
- Chat->send(source, CHAT_DIRECT, "System", DbgMessage);\r
- }\r
- else\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", Usage);\r
- }\r
-}\r
+#include <cstring>
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmddebug()
+{
+ PDebugMode nWhat = DBG_ALL;
+ int nHow = -1;
+ const char* DbgTarget = "all";
+ char DbgMessage[80];
+ const char* Usage = "@debug [loc[ation] | it[emid] | sub[way]] [0|1]";
+
+ if(ArgC > 0)
+ {
+ if(IsArgNumeric(1) == true)
+ {
+ if(GetArgInt(1) == 0)
+ {
+ nHow = 0;
+ }
+ else
+ {
+ nHow = 1;
+ }
+ }
+ else
+ {
+ char tmp[10];
+ if(GetArgText(1, tmp, 10))
+ {
+ if(strncmp(tmp, "loc", 3) == 0)
+ {
+ nWhat = DBG_LOCATION;
+ DbgTarget = "location";
+ }
+ else if(strncmp(tmp, "it", 2) == 0)
+ {
+ nWhat = DBG_ITEMID;
+ DbgTarget = "itemid";
+ }
+ else if(strncmp(tmp, "sub", 3) == 0)
+ {
+ nWhat = DBG_SUBWAY;
+ DbgTarget = "subway";
+ }
+ }
+ }
+
+ if (nWhat != DBG_ALL)
+ {
+ if(ArgC == 1)
+ {
+ nHow = (source->GetDebugMode(nWhat) ? 0 : 1); // toggle if no arg
+ }
+ else if(ArgC > 1 && GetArgInt(2) == 0)
+ {
+ nHow = 0;
+ }
+ else if(ArgC > 1 && GetArgInt(2) == 1)
+ {
+ nHow = 1;
+ }
+ }
+ }
+
+ if (nHow != -1)
+ {
+ source->SetDebugMode(nWhat, nHow);
+ snprintf(DbgMessage, 80, "Debug %s is now %s", DbgTarget, (nHow ? "ENABLED" : "DISABLED"));
+ Chat->send(source, CHAT_DIRECT, "System", DbgMessage);
+ }
+ else
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", Usage);
+ }
+}
-#include <cstdint>\r
-#include <cstdio>\r
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdeffect()\r
-{\r
- bool SyntaxError = false;\r
- if(ArgC < 1)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- if(IsArgNumeric(1) == false)\r
- SyntaxError = true;\r
-\r
- if(SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@effect <effect: 0=none, 1 .. 17> [<density: 0=max .. 255=min>]");\r
- return;\r
- }\r
-\r
- uint8_t val1, val2;\r
- char effStr[128];\r
- PMessage* tmpMsg;\r
-\r
- val1 = (uint8_t)(GetArgInt(1) & 0xff);\r
- val2 = (uint8_t)(GetArgInt(2) & 0xff);\r
-\r
- source->GetChar()->SetBodyEffect(val1, val2);\r
-\r
- tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
- ClientManager->UDPBroadcast(tmpMsg, source);\r
- snprintf(effStr, 127, "Body effect set to value %d with density %d (but you can see it yourself)", val1, val2);\r
- effStr[127] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", effStr);\r
-}\r
+#include <cstdint>
+#include <cstdio>
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdeffect()
+{
+ bool SyntaxError = false;
+ if(ArgC < 1)
+ {
+ SyntaxError = true;
+ }
+
+ if(IsArgNumeric(1) == false)
+ SyntaxError = true;
+
+ if(SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@effect <effect: 0=none, 1 .. 17> [<density: 0=max .. 255=min>]");
+ return;
+ }
+
+ uint8_t val1, val2;
+ char effStr[128];
+ PMessage* tmpMsg;
+
+ val1 = (uint8_t)(GetArgInt(1) & 0xff);
+ val2 = (uint8_t)(GetArgInt(2) & 0xff);
+
+ source->GetChar()->SetBodyEffect(val1, val2);
+
+ tmpMsg = MsgBuilder->BuildCharHelloMsg(source);
+ ClientManager->UDPBroadcast(tmpMsg, source);
+ snprintf(effStr, 127, "Body effect set to value %d with density %d (but you can see it yourself)", val1, val2);
+ effStr[127] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", effStr);
+}
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmd_dev_h()\r
-{\r
- if(IsAdmin() == false)\r
- return;\r
-\r
- if(source->GetAccountLevel() < PAL_ADMIN)\r
- return;\r
-\r
-\r
-\r
- PMessage* tmpMsg = MsgBuilder->BuildEntityPositionMsg(source, GetArgInt(1) & 0xffff, GetArgInt(2) & 0xffff, GetArgInt(3) & 0xffff);\r
- source->SendUDPMessage(tmpMsg);\r
-/*\r
- u8 val1, val2, val3, val4;\r
- char tmpStr[128];\r
-\r
- if(ArgC > 0)\r
- {\r
- val1 = (u8)(GetArgInt(1) & 0xff);\r
- val2 = (u8)(GetArgInt(2) & 0xff);\r
- val3 = (u8)(GetArgInt(3) & 0xff);\r
- val4 = (ArgC > 3) ? (u8)(GetArgInt(4) & 0xff) : 0x01;\r
- }\r
- else\r
- {\r
- val1 = 0xff;\r
- val2 = 0xff;\r
- val3 = 0xff;\r
- val4 = 0x01;\r
- }\r
-\r
- PMessage* tmpMsg = new PMessage(14);\r
-\r
- *tmpMsg << (u8)0x13;\r
- *tmpMsg << (u16)0x0000; //source->GetUDP_ID(); // just placeholder, must be set outside\r
- *tmpMsg << (u16)0x0000; // source->GetSessionID(); // just placeholder, must be set outside\r
- *tmpMsg << (u8)0x00; // Message length placeholder;\r
- *tmpMsg << (u8)0x1f;\r
- *tmpMsg << (u16)source->GetLocalID();\r
- *tmpMsg << (u8)0x30;\r
- *tmpMsg << (u8)val1; //Head Heath (% ?) (45%)\r
- *tmpMsg << (u8)val2; //Body Heath (35%)\r
- *tmpMsg << (u8)val3; //Feet Heath (20%)\r
- *tmpMsg << (u8)val4;\r
-\r
- (*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);\r
- ClientManager->UDPBroadcast(tmpMsg, source);\r
-\r
- snprintf(tmpStr, 127, "Data set to values 0x%02x 0x%02x", val1, val2);\r
- tmpStr[127] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", tmpStr);\r
- */\r
-}\r
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmd_dev_h()
+{
+ if(IsAdmin() == false)
+ return;
+
+ if(source->GetAccountLevel() < PAL_ADMIN)
+ return;
+
+
+
+ PMessage* tmpMsg = MsgBuilder->BuildEntityPositionMsg(source, GetArgInt(1) & 0xffff, GetArgInt(2) & 0xffff, GetArgInt(3) & 0xffff);
+ source->SendUDPMessage(tmpMsg);
+/*
+ u8 val1, val2, val3, val4;
+ char tmpStr[128];
+
+ if(ArgC > 0)
+ {
+ val1 = (u8)(GetArgInt(1) & 0xff);
+ val2 = (u8)(GetArgInt(2) & 0xff);
+ val3 = (u8)(GetArgInt(3) & 0xff);
+ val4 = (ArgC > 3) ? (u8)(GetArgInt(4) & 0xff) : 0x01;
+ }
+ else
+ {
+ val1 = 0xff;
+ val2 = 0xff;
+ val3 = 0xff;
+ val4 = 0x01;
+ }
+
+ PMessage* tmpMsg = new PMessage(14);
+
+ *tmpMsg << (u8)0x13;
+ *tmpMsg << (u16)0x0000; //source->GetUDP_ID(); // just placeholder, must be set outside
+ *tmpMsg << (u16)0x0000; // source->GetSessionID(); // just placeholder, must be set outside
+ *tmpMsg << (u8)0x00; // Message length placeholder;
+ *tmpMsg << (u8)0x1f;
+ *tmpMsg << (u16)source->GetLocalID();
+ *tmpMsg << (u8)0x30;
+ *tmpMsg << (u8)val1; //Head Heath (% ?) (45%)
+ *tmpMsg << (u8)val2; //Body Heath (35%)
+ *tmpMsg << (u8)val3; //Feet Heath (20%)
+ *tmpMsg << (u8)val4;
+
+ (*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6);
+ ClientManager->UDPBroadcast(tmpMsg, source);
+
+ snprintf(tmpStr, 127, "Data set to values 0x%02x 0x%02x", val1, val2);
+ tmpStr[127] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", tmpStr);
+ */
+}
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdinfo()\r
-{\r
- bool SyntaxError = false;\r
- if(ArgC < 1)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- if(SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@info <charID or nickname>");\r
- return;\r
- }\r
-\r
- if(IsArgNumeric(1) == true)\r
- {\r
- target = GetClientByID(GetArgInt(1));\r
- }\r
- else\r
- {\r
- char tmp_destNick[50];\r
- GetArgText(1, tmp_destNick, 50);\r
- target = GetClientByNick(tmp_destNick);\r
- }\r
-\r
- if(target == NULL) // If victim isnt found, return error\r
- {\r
- Chat->send(source, CHAT_DIRECT, "System", "No such player");\r
- return;\r
- }\r
- // *************** Checks done, proceed with command\r
- /*\r
- DIRECT> System: PlayerInformation\r
- DIRECT> Info: CharID : %d // victim->GetCharID();\r
- DIRECT> Info: AccountID : %d // victim->GetAccount()->GetID();\r
- DIRECT> Info: LoginName : %s // victim->GetAccount()->GetName();\r
- DIRECT> Info: AccessLevel: %d // victim->GetAccountLevel();\r
- DIRECT> Info: Current Loc: %d // Chars->GetChar(source->GetCharID())->GetLocation();\r
- DIRECT> Info: IP address : %s // victim->GetAddress():\r
-\r
- Maybe for future addons...\r
- DIRECT> System: CharInformation\r
- DIRECT> Info: Faction : %d // Chars->GetChar(source->GetCharID())->GetFaction();\r
- DIRECT> Info: Cash : %d // Chars->GetChar(source->GetCharID())->GetCash();\r
- DIRECT> Info: Soullight : %d // Chars->GetChar(source->GetCharID())->GetSoullight();\r
- */\r
-\r
- PAccount Acc(target->GetAccountID());\r
-\r
- // If source != target\r
- if(source->GetAccountID() != target->GetAccountID())\r
- {\r
- // Check if accesslevel is lower\r
- if(source->GetAccountLevel() <= target->GetAccountLevel())\r
- {\r
- char tmpMsg[200];\r
- snprintf(tmpMsg, 199, "Cant display info about %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());\r
- tmpMsg[199] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", tmpMsg);\r
- return;\r
- }\r
- }\r
-\r
- char tmpInfo_head[151];\r
- char tmpInfo_cID[151];\r
- char tmpInfo_aID[151];\r
- char tmpInfo_Login[151];\r
- char tmpInfo_AxxLv[151];\r
- char tmpInfo_Loc[151];\r
- char tmpInfo_IP[151];\r
-\r
- snprintf(tmpInfo_head, 150, "PlayerInformation");\r
- snprintf(tmpInfo_cID, 150, "CharID : %d", target->GetCharID());\r
- snprintf(tmpInfo_aID, 150, "AccountID : %d", Acc.GetID());\r
- snprintf(tmpInfo_Login, 150, "LoginName : %s", Acc.GetName().c_str());\r
- snprintf(tmpInfo_AxxLv, 150, "AccessLevel: %d", Acc.GetLevel());\r
- snprintf(tmpInfo_Loc, 150, "Current Loc: %d", Chars->GetChar(target->GetCharID())->GetLocation());\r
- snprintf(tmpInfo_IP, 150, "IP address : %s", target->GetAddress());\r
-\r
- tmpInfo_head[150] = '\0';\r
- tmpInfo_cID[150] = '\0';\r
- tmpInfo_aID[150] = '\0';\r
- tmpInfo_Login[150] = '\0';\r
- tmpInfo_AxxLv[150] = '\0';\r
- tmpInfo_Loc[150] = '\0';\r
- tmpInfo_IP[150] = '\0';\r
-\r
- Chat->send(source, CHAT_DIRECT, "System", tmpInfo_head);\r
- Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_cID);\r
- Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_aID);\r
- Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_Login);\r
- Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_AxxLv);\r
- Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_Loc);\r
- Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_IP);\r
-}\r
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdinfo()
+{
+ bool SyntaxError = false;
+ if(ArgC < 1)
+ {
+ SyntaxError = true;
+ }
+
+ if(SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@info <charID or nickname>");
+ return;
+ }
+
+ if(IsArgNumeric(1) == true)
+ {
+ target = GetClientByID(GetArgInt(1));
+ }
+ else
+ {
+ char tmp_destNick[50];
+ GetArgText(1, tmp_destNick, 50);
+ target = GetClientByNick(tmp_destNick);
+ }
+
+ if(target == NULL) // If victim isnt found, return error
+ {
+ Chat->send(source, CHAT_DIRECT, "System", "No such player");
+ return;
+ }
+ // *************** Checks done, proceed with command
+ /*
+ DIRECT> System: PlayerInformation
+ DIRECT> Info: CharID : %d // victim->GetCharID();
+ DIRECT> Info: AccountID : %d // victim->GetAccount()->GetID();
+ DIRECT> Info: LoginName : %s // victim->GetAccount()->GetName();
+ DIRECT> Info: AccessLevel: %d // victim->GetAccountLevel();
+ DIRECT> Info: Current Loc: %d // Chars->GetChar(source->GetCharID())->GetLocation();
+ DIRECT> Info: IP address : %s // victim->GetAddress():
+
+ Maybe for future addons...
+ DIRECT> System: CharInformation
+ DIRECT> Info: Faction : %d // Chars->GetChar(source->GetCharID())->GetFaction();
+ DIRECT> Info: Cash : %d // Chars->GetChar(source->GetCharID())->GetCash();
+ DIRECT> Info: Soullight : %d // Chars->GetChar(source->GetCharID())->GetSoullight();
+ */
+
+ PAccount Acc(target->GetAccountID());
+
+ // If source != target
+ if(source->GetAccountID() != target->GetAccountID())
+ {
+ // Check if accesslevel is lower
+ if(source->GetAccountLevel() <= target->GetAccountLevel())
+ {
+ char tmpMsg[200];
+ snprintf(tmpMsg, 199, "Cant display info about %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());
+ tmpMsg[199] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", tmpMsg);
+ return;
+ }
+ }
+
+ char tmpInfo_head[151];
+ char tmpInfo_cID[151];
+ char tmpInfo_aID[151];
+ char tmpInfo_Login[151];
+ char tmpInfo_AxxLv[151];
+ char tmpInfo_Loc[151];
+ char tmpInfo_IP[151];
+
+ snprintf(tmpInfo_head, 150, "PlayerInformation");
+ snprintf(tmpInfo_cID, 150, "CharID : %d", target->GetCharID());
+ snprintf(tmpInfo_aID, 150, "AccountID : %d", Acc.GetID());
+ snprintf(tmpInfo_Login, 150, "LoginName : %s", Acc.GetName().c_str());
+ snprintf(tmpInfo_AxxLv, 150, "AccessLevel: %d", Acc.GetLevel());
+ snprintf(tmpInfo_Loc, 150, "Current Loc: %d", Chars->GetChar(target->GetCharID())->GetLocation());
+ snprintf(tmpInfo_IP, 150, "IP address : %s", target->GetAddress());
+
+ tmpInfo_head[150] = '\0';
+ tmpInfo_cID[150] = '\0';
+ tmpInfo_aID[150] = '\0';
+ tmpInfo_Login[150] = '\0';
+ tmpInfo_AxxLv[150] = '\0';
+ tmpInfo_Loc[150] = '\0';
+ tmpInfo_IP[150] = '\0';
+
+ Chat->send(source, CHAT_DIRECT, "System", tmpInfo_head);
+ Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_cID);
+ Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_aID);
+ Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_Login);
+ Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_AxxLv);
+ Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_Loc);
+ Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_IP);
+}
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-void PCommands::doCmdkick()\r
-{\r
- bool SyntaxError = false;\r
- if(ArgC < 1)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- if(SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@kick <charID or nickname>");\r
- return;\r
- }\r
-\r
- if(IsArgNumeric(1) == true)\r
- {\r
- target = GetClientByID(GetArgInt(1));\r
- }\r
- else\r
- {\r
- char tmp_destNick[50];\r
- GetArgText(1, tmp_destNick, 50);\r
- target = GetClientByNick(tmp_destNick);\r
- }\r
-\r
- if(target == NULL) // If victim isnt found, return error\r
- {\r
- Chat->send(source, CHAT_DIRECT, "System", "No such player");\r
- return;\r
- }\r
-\r
- // Make sure only people with a higher level than victim can kick victim\r
- if(source->GetAccountLevel() <= target->GetAccountLevel())\r
- {\r
- char tmpMsg[200];\r
- snprintf(tmpMsg, 199, "Cant kick %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());\r
- tmpMsg[199] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", tmpMsg);\r
- return;\r
- }\r
-\r
-// *************** Checks done, proceed with command\r
- int final_bantime = std::time(NULL) + 60; // Ban 60 seconds (Anti-Rejoin)\r
- PAccount Acc(target->GetAccountID());\r
- Acc.SetBannedUntilTime(final_bantime);\r
- Acc.Save();\r
-\r
- target->InitCharVanish();\r
- GameServer->ClientDisconnected(target); // Kick\r
-\r
- Console->Print("%s %s (Lv %d) kicked %s (Lv %d)", Console->ColorText(YELLOW, BLACK, "[GameCommand]"), Chars->GetChar(source->GetCharID())->GetName().c_str(), source->GetAccountLevel(), Chars->GetChar(target->GetCharID())->GetName().c_str(), target->GetAccountLevel());\r
- char successmsg[100];\r
- snprintf(successmsg, 99, "Kicked %s", Chars->GetChar(target->GetCharID())->GetName().c_str());\r
- successmsg[99] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", successmsg);\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+void PCommands::doCmdkick()
+{
+ bool SyntaxError = false;
+ if(ArgC < 1)
+ {
+ SyntaxError = true;
+ }
+
+ if(SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@kick <charID or nickname>");
+ return;
+ }
+
+ if(IsArgNumeric(1) == true)
+ {
+ target = GetClientByID(GetArgInt(1));
+ }
+ else
+ {
+ char tmp_destNick[50];
+ GetArgText(1, tmp_destNick, 50);
+ target = GetClientByNick(tmp_destNick);
+ }
+
+ if(target == NULL) // If victim isnt found, return error
+ {
+ Chat->send(source, CHAT_DIRECT, "System", "No such player");
+ return;
+ }
+
+ // Make sure only people with a higher level than victim can kick victim
+ if(source->GetAccountLevel() <= target->GetAccountLevel())
+ {
+ char tmpMsg[200];
+ snprintf(tmpMsg, 199, "Cant kick %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());
+ tmpMsg[199] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", tmpMsg);
+ return;
+ }
+
+// *************** Checks done, proceed with command
+ int final_bantime = std::time(NULL) + 60; // Ban 60 seconds (Anti-Rejoin)
+ PAccount Acc(target->GetAccountID());
+ Acc.SetBannedUntilTime(final_bantime);
+ Acc.Save();
+
+ target->InitCharVanish();
+ GameServer->ClientDisconnected(target); // Kick
+
+ Console->Print("%s %s (Lv %d) kicked %s (Lv %d)", Console->ColorText(YELLOW, BLACK, "[GameCommand]"), Chars->GetChar(source->GetCharID())->GetName().c_str(), source->GetAccountLevel(), Chars->GetChar(target->GetCharID())->GetName().c_str(), target->GetAccountLevel());
+ char successmsg[100];
+ snprintf(successmsg, 99, "Kicked %s", Chars->GetChar(target->GetCharID())->GetName().c_str());
+ successmsg[99] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", successmsg);
+}
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdlistbans()\r
-{\r
- Chat->send(source, CHAT_DIRECT, "System", "Sorry, namikon was too lazy to code that ^^");\r
- Chat->send(source, CHAT_DIRECT, "System", "Please wait until the ban is removed automaticly or edit your sqlDB");\r
- return;\r
-}\r
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdlistbans()
+{
+ Chat->send(source, CHAT_DIRECT, "System", "Sorry, namikon was too lazy to code that ^^");
+ Chat->send(source, CHAT_DIRECT, "System", "Please wait until the ban is removed automaticly or edit your sqlDB");
+ return;
+}
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-void PCommands::doCmdconlist()\r
-{\r
- if (gDevDebug) Console->Print("IngameCommand: Sending connected-player-list to charID %d", source->GetCharID());\r
- Chat->sendConnectedList(source, false);\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+void PCommands::doCmdconlist()
+{
+ if (gDevDebug) Console->Print("IngameCommand: Sending connected-player-list to charID %d", source->GetCharID());
+ Chat->sendConnectedList(source, false);
+}
-#include <cstring>\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-void PCommands::doCmdrawf()\r
-{\r
- bool SyntaxError = false;\r
- bool DebugMode = false;\r
- int Prot = 0; // 0: Error 1: UDP 2: TCP\r
-\r
- if(ArgC < 2)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- char file_to_send[50], protocol_to_use[10];\r
- GetArgText(1, file_to_send, 50);\r
- GetArgText(2, protocol_to_use, 10);\r
-\r
- if(strcmp(protocol_to_use, "udp") == 0)\r
- {\r
- Prot = 1;\r
- }\r
- else if(strcmp(protocol_to_use, "tcp") == 0)\r
- {\r
- Prot = 2;\r
- }\r
- else if(strcmp(protocol_to_use, "debug") == 0)\r
- {\r
- DebugMode = true;\r
- }\r
- else\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- if(SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@rawf <file> <udp/tcp/debug>");\r
- return;\r
- }\r
-\r
- std::ifstream::pos_type size;\r
- char *buffer;\r
-\r
- std::ifstream hexdump (file_to_send, std::ios::in | std::ios::binary | std::ios::ate);\r
- if (hexdump.is_open())\r
- {\r
- if (gDevDebug) Console->Print("IngameCommand: Sending packet file %s", file_to_send);\r
-\r
- size = hexdump.tellg();\r
- buffer = new char [size];\r
- hexdump.seekg (0, std::ios::beg);\r
-\r
- hexdump.read (buffer, size);\r
- hexdump.close();\r
- if(DebugMode == true)\r
- {\r
- int k;\r
- Console->Print("Byte dump of %s:", file_to_send);\r
- for(k=0;k<size;k++)\r
- {\r
- Console->Print("Byte %d: %#x", k, buffer[k]);\r
- }\r
- }\r
- else\r
- {\r
- if(Prot == 1)\r
- source->getUDPConn()->write(buffer, size);\r
- else if(Prot == 2)\r
- source->getTCPConn()->write(buffer, size);\r
- else // Should never happen...\r
- Console->Print("%s unable to determine protocol in PCommands::doCmdrawf", Console->ColorText(RED, BLACK, "[Error]"));\r
- }\r
-\r
- delete[] buffer;\r
- }\r
- else\r
- {\r
- char output[100];\r
- Console->Print("IngameCommand: Unable to send file %s", file_to_send);\r
- snprintf(output, 100, "File not found: %s", file_to_send);\r
- Chat->send(source, CHAT_DIRECT, "System", output);\r
- }\r
-}\r
+#include <cstring>
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+void PCommands::doCmdrawf()
+{
+ bool SyntaxError = false;
+ bool DebugMode = false;
+ int Prot = 0; // 0: Error 1: UDP 2: TCP
+
+ if(ArgC < 2)
+ {
+ SyntaxError = true;
+ }
+
+ char file_to_send[50], protocol_to_use[10];
+ GetArgText(1, file_to_send, 50);
+ GetArgText(2, protocol_to_use, 10);
+
+ if(strcmp(protocol_to_use, "udp") == 0)
+ {
+ Prot = 1;
+ }
+ else if(strcmp(protocol_to_use, "tcp") == 0)
+ {
+ Prot = 2;
+ }
+ else if(strcmp(protocol_to_use, "debug") == 0)
+ {
+ DebugMode = true;
+ }
+ else
+ {
+ SyntaxError = true;
+ }
+
+ if(SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@rawf <file> <udp/tcp/debug>");
+ return;
+ }
+
+ std::ifstream::pos_type size;
+ char *buffer;
+
+ std::ifstream hexdump (file_to_send, std::ios::in | std::ios::binary | std::ios::ate);
+ if (hexdump.is_open())
+ {
+ if (gDevDebug) Console->Print("IngameCommand: Sending packet file %s", file_to_send);
+
+ size = hexdump.tellg();
+ buffer = new char [size];
+ hexdump.seekg (0, std::ios::beg);
+
+ hexdump.read (buffer, size);
+ hexdump.close();
+ if(DebugMode == true)
+ {
+ int k;
+ Console->Print("Byte dump of %s:", file_to_send);
+ for(k=0;k<size;k++)
+ {
+ Console->Print("Byte %d: %#x", k, buffer[k]);
+ }
+ }
+ else
+ {
+ if(Prot == 1)
+ source->getUDPConn()->write(buffer, size);
+ else if(Prot == 2)
+ source->getTCPConn()->write(buffer, size);
+ else // Should never happen...
+ Console->Print("%s unable to determine protocol in PCommands::doCmdrawf", Console->ColorText(RED, BLACK, "[Error]"));
+ }
+
+ delete[] buffer;
+ }
+ else
+ {
+ char output[100];
+ Console->Print("IngameCommand: Unable to send file %s", file_to_send);
+ snprintf(output, 100, "File not found: %s", file_to_send);
+ Chat->send(source, CHAT_DIRECT, "System", output);
+ }
+}
-#include <cstring>\r
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdremove()\r
-{\r
- bool SyntaxError = false;\r
- if(ArgC < 1)\r
- {\r
- SyntaxError = true;\r
- }\r
- if(SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@remove actor/<raw item id>");\r
- return;\r
- }\r
-\r
- char tmp_v1[30];\r
- GetArgText(1, tmp_v1, 30);\r
-\r
- if(strcmp(tmp_v1, "actor") == 0)\r
- {\r
- if(source->IsInRemoveActorMode() == false)\r
- {\r
- source->SetRemoveActorMode(true);\r
- Chat->send(source, CHAT_DIRECT, "System", "You are now in REMOVE ACTOR mode. Rightclick an actor to remove it, type command again to disable mode");\r
- }\r
- else\r
- {\r
- source->SetRemoveActorMode(false);\r
- Chat->send(source, CHAT_DIRECT, "System", "REMOVE ACTOR mode disabled");\r
- }\r
- return;\r
- }\r
-\r
- if(IsArgNumeric(1) == true)\r
- {\r
- uint32_t tTest = GetArgInt(1);\r
- if(WorldActors->IsDynamicActor(tTest) == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "System", "You cannot remove dynamic actors over their ID!");\r
- return;\r
- }\r
- uint32_t TargetID;\r
- char delStr[128];\r
- PMessage* tmpMsg;\r
-\r
- TargetID = (uint32_t)(atoi(tmp_v1) & 0xffffffff);\r
- tmpMsg = MsgBuilder->BuildFurnitureActivateMsg(source, TargetID, 5);\r
-\r
- ClientManager->UDPBroadcast(tmpMsg, source);\r
- tmpMsg = MsgBuilder->BuildFurnitureActivateMsg(source, TargetID, 9);\r
-\r
- ClientManager->UDPBroadcast(tmpMsg, source);\r
- snprintf(delStr, 127, "Item %d removed.", TargetID);\r
- delStr[127] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", delStr);\r
- }\r
- else\r
- {\r
- Chat->send(source, CHAT_DIRECT, "System", "Invalid argument given");\r
- return;\r
- }\r
-}\r
+#include <cstring>
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdremove()
+{
+ bool SyntaxError = false;
+ if(ArgC < 1)
+ {
+ SyntaxError = true;
+ }
+ if(SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@remove actor/<raw item id>");
+ return;
+ }
+
+ char tmp_v1[30];
+ GetArgText(1, tmp_v1, 30);
+
+ if(strcmp(tmp_v1, "actor") == 0)
+ {
+ if(source->IsInRemoveActorMode() == false)
+ {
+ source->SetRemoveActorMode(true);
+ Chat->send(source, CHAT_DIRECT, "System", "You are now in REMOVE ACTOR mode. Rightclick an actor to remove it, type command again to disable mode");
+ }
+ else
+ {
+ source->SetRemoveActorMode(false);
+ Chat->send(source, CHAT_DIRECT, "System", "REMOVE ACTOR mode disabled");
+ }
+ return;
+ }
+
+ if(IsArgNumeric(1) == true)
+ {
+ uint32_t tTest = GetArgInt(1);
+ if(WorldActors->IsDynamicActor(tTest) == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "System", "You cannot remove dynamic actors over their ID!");
+ return;
+ }
+ uint32_t TargetID;
+ char delStr[128];
+ PMessage* tmpMsg;
+
+ TargetID = (uint32_t)(atoi(tmp_v1) & 0xffffffff);
+ tmpMsg = MsgBuilder->BuildFurnitureActivateMsg(source, TargetID, 5);
+
+ ClientManager->UDPBroadcast(tmpMsg, source);
+ tmpMsg = MsgBuilder->BuildFurnitureActivateMsg(source, TargetID, 9);
+
+ ClientManager->UDPBroadcast(tmpMsg, source);
+ snprintf(delStr, 127, "Item %d removed.", TargetID);
+ delStr[127] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", delStr);
+ }
+ else
+ {
+ Chat->send(source, CHAT_DIRECT, "System", "Invalid argument given");
+ return;
+ }
+}
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdsetlevel()\r
-{\r
- int destLevel = 0;\r
- bool SyntaxError = false;\r
- if (ArgC < 2)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- if (IsArgNumeric(2) == false)\r
- {\r
- SyntaxError = true;\r
- }\r
- else\r
- {\r
- destLevel = GetArgInt(2);\r
- }\r
-\r
- if (SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@setlevel <charID or nickname> <newlevel 1-99>");\r
- return;\r
- }\r
-\r
- if (IsArgNumeric(1) == true)\r
- {\r
- target = GetClientByID(GetArgInt(1));\r
- }\r
- else\r
- {\r
- char tmp_destNick[50];\r
- GetArgText(1, tmp_destNick, 50);\r
- target = GetClientByNick(tmp_destNick);\r
- }\r
-\r
- if (target == NULL) // If victim isnt found, return error\r
- {\r
- Chat->send(source, CHAT_DIRECT, "System", "No such player");\r
- return;\r
- }\r
- if (source->GetAccountLevel() <= target->GetAccountLevel())\r
- {\r
- char tmpMsg[200];\r
- snprintf(tmpMsg, 199, "Cant set new level for %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());\r
- tmpMsg[199] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", tmpMsg);\r
- return;\r
- }\r
-\r
- PAccount Acc(target->GetAccountID());\r
- Acc.SetLevel(destLevel);\r
- Acc.Save();\r
- source->RefreshAccountInfo(&Acc);\r
-\r
- char tmpMsg[60], tmpMsg2[60];\r
- snprintf(tmpMsg, 59, "Set level for player %s to %d", Chars->GetChar(target->GetCharID())->GetName().c_str(), destLevel);\r
- snprintf(tmpMsg2, 59, "**POOF** Your new accesslevel is now %d", destLevel);\r
-\r
- tmpMsg[59] = '\0';\r
- tmpMsg2[59] = '\0';\r
-\r
- Chat->send(source, CHAT_DIRECT, "System", tmpMsg);\r
- Chat->send(target, CHAT_DIRECT, "System", tmpMsg2);\r
-}\r
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdsetlevel()
+{
+ int destLevel = 0;
+ bool SyntaxError = false;
+ if (ArgC < 2)
+ {
+ SyntaxError = true;
+ }
+
+ if (IsArgNumeric(2) == false)
+ {
+ SyntaxError = true;
+ }
+ else
+ {
+ destLevel = GetArgInt(2);
+ }
+
+ if (SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@setlevel <charID or nickname> <newlevel 1-99>");
+ return;
+ }
+
+ if (IsArgNumeric(1) == true)
+ {
+ target = GetClientByID(GetArgInt(1));
+ }
+ else
+ {
+ char tmp_destNick[50];
+ GetArgText(1, tmp_destNick, 50);
+ target = GetClientByNick(tmp_destNick);
+ }
+
+ if (target == NULL) // If victim isnt found, return error
+ {
+ Chat->send(source, CHAT_DIRECT, "System", "No such player");
+ return;
+ }
+ if (source->GetAccountLevel() <= target->GetAccountLevel())
+ {
+ char tmpMsg[200];
+ snprintf(tmpMsg, 199, "Cant set new level for %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());
+ tmpMsg[199] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", tmpMsg);
+ return;
+ }
+
+ PAccount Acc(target->GetAccountID());
+ Acc.SetLevel(destLevel);
+ Acc.Save();
+ source->RefreshAccountInfo(&Acc);
+
+ char tmpMsg[60], tmpMsg2[60];
+ snprintf(tmpMsg, 59, "Set level for player %s to %d", Chars->GetChar(target->GetCharID())->GetName().c_str(), destLevel);
+ snprintf(tmpMsg2, 59, "**POOF** Your new accesslevel is now %d", destLevel);
+
+ tmpMsg[59] = '\0';
+ tmpMsg2[59] = '\0';
+
+ Chat->send(source, CHAT_DIRECT, "System", tmpMsg);
+ Chat->send(target, CHAT_DIRECT, "System", tmpMsg2);
+}
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-void PCommands::doCmdsettime()\r
-{\r
- if(ArgC < 1 && GetArgInt(1) == 0)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@settime <raw timevalue>");\r
- return;\r
- }\r
-\r
- int newtime = 0;\r
- newtime = GetArgInt(1);\r
-\r
- GameServer->SetGameTime(newtime);\r
- Console->Print("IngameCommand: CharID %d set ingametime to %d", source->GetCharID(), newtime);\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+void PCommands::doCmdsettime()
+{
+ if(ArgC < 1 && GetArgInt(1) == 0)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@settime <raw timevalue>");
+ return;
+ }
+
+ int newtime = 0;
+ newtime = GetArgInt(1);
+
+ GameServer->SetGameTime(newtime);
+ Console->Print("IngameCommand: CharID %d set ingametime to %d", source->GetCharID(), newtime);
+}
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdshun()\r
-{\r
- bool SyntaxError = false;\r
- if(ArgC < 1)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- if(SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@shun <charID or nickname>");\r
- return;\r
- }\r
-\r
- if(IsArgNumeric(1) == true)\r
- {\r
- target = GetClientByID(GetArgInt(1));\r
- }\r
- else\r
- {\r
- char tmp_destNick[50];\r
- GetArgText(1, tmp_destNick, 50);\r
- target = GetClientByNick(tmp_destNick);\r
- }\r
-\r
- if(target == NULL) // If victim isnt found, return error\r
- {\r
- Chat->send(source, CHAT_DIRECT, "System", "No such player");\r
- return;\r
- }\r
- if(source->GetAccountLevel() <= target->GetAccountLevel())\r
- {\r
- char tmpMsg[200];\r
- snprintf(tmpMsg, 199, "Cant shun %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());\r
- tmpMsg[199] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", tmpMsg);\r
- return;\r
- }\r
- if(target->GetChar()->IsShunned() == false)\r
- {\r
- target->GetChar()->SetShun(true);\r
-\r
- char tmpMsg_success[81];\r
- snprintf(tmpMsg_success, 80, "Successfully shunned %s", target->GetChar()->GetName().c_str());\r
- tmpMsg_success[80] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success);\r
- return;\r
- }\r
- else\r
- {\r
- Chat->send(source, CHAT_DIRECT, "System", "Player is already shunned");\r
- return;\r
- }\r
-}\r
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdshun()
+{
+ bool SyntaxError = false;
+ if(ArgC < 1)
+ {
+ SyntaxError = true;
+ }
+
+ if(SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@shun <charID or nickname>");
+ return;
+ }
+
+ if(IsArgNumeric(1) == true)
+ {
+ target = GetClientByID(GetArgInt(1));
+ }
+ else
+ {
+ char tmp_destNick[50];
+ GetArgText(1, tmp_destNick, 50);
+ target = GetClientByNick(tmp_destNick);
+ }
+
+ if(target == NULL) // If victim isnt found, return error
+ {
+ Chat->send(source, CHAT_DIRECT, "System", "No such player");
+ return;
+ }
+ if(source->GetAccountLevel() <= target->GetAccountLevel())
+ {
+ char tmpMsg[200];
+ snprintf(tmpMsg, 199, "Cant shun %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());
+ tmpMsg[199] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", tmpMsg);
+ return;
+ }
+ if(target->GetChar()->IsShunned() == false)
+ {
+ target->GetChar()->SetShun(true);
+
+ char tmpMsg_success[81];
+ snprintf(tmpMsg_success, 80, "Successfully shunned %s", target->GetChar()->GetName().c_str());
+ tmpMsg_success[80] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success);
+ return;
+ }
+ else
+ {
+ Chat->send(source, CHAT_DIRECT, "System", "Player is already shunned");
+ return;
+ }
+}
-#include <sstream>\r
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdskin()\r
-{\r
-// -------------------------------------------------------\r
-/*\r
-Usage: @skin #<chardef idx>\r
- for use with the index id from characters.def\r
- or @skin <model>|-|# [<head>[ <torso>[ <legs>]]]\r
- <model> is the model id found after the model name in characters.def\r
- # resets to real char skin (optionnaly modified by following args)\r
- - means current skin\r
- incrementaly optional <head>, <torso> and <legs> are values 0-9\r
-*/\r
- bool SyntaxError = false;\r
- if(ArgC < 1)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- uint32_t Skinval1, Skinval2, Skinval3, Skinval4;\r
- PChar *SkinChar = Chars->GetChar(source->GetCharID());\r
- std::stringstream SkinChat;\r
- char SkinStr[128];\r
-\r
- if(SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@skin ( #<chardef idx> ) | ( <model> | # [<head>[ <torso>[ <legs>]]] )");\r
- return;\r
- }\r
-\r
- char tmpval[30];\r
- GetArgText(1, tmpval, 30);\r
- if((tmpval[0] == '#') && (tmpval[1] != '\0'))\r
- {\r
- Skinval1 = atoi(tmpval+1);\r
- SkinChar->SetCurrentLookFromCharType(atoi(tmpval+1));\r
- SkinChat << "Skin set to the skin of char type ";\r
- SkinChat << (int)Skinval1;\r
- }\r
- else\r
- {\r
- if ((tmpval[0] == '#') && (tmpval[1] == '\0'))\r
- {\r
- SkinChar->GetRealLook(Skinval1, Skinval2, Skinval3, Skinval4);\r
- }\r
- else if ((tmpval[0] == '-') && (tmpval[1] == '\0'))\r
- {\r
- SkinChar->GetCurrentLook(Skinval1, Skinval2, Skinval3, Skinval4);\r
- }\r
- else\r
- {\r
- Skinval1 = GetArgInt(1);\r
- }\r
-\r
- char tmp_arg2[30];\r
- char tmp_arg3[30];\r
- char tmp_arg4[30];\r
-\r
- GetArgText(2, tmp_arg2, 30);\r
- GetArgText(3, tmp_arg3, 30);\r
- GetArgText(4, tmp_arg4, 30);\r
-\r
- if(tmp_arg2[0] != '\0')\r
- {\r
- if(tmp_arg2[0] != '-')\r
- {\r
- tmp_arg2[1] = '\0';\r
- Skinval2 = GetArgInt(2);\r
- }\r
- if(tmp_arg3[0] != '\0')\r
- {\r
- if(tmp_arg3[0] != '-')\r
- {\r
- tmp_arg3[1] = '\0';\r
- Skinval3 = GetArgInt(3);\r
- }\r
- if(tmp_arg4[0] != '\0')\r
- {\r
- if(tmp_arg4[0] != '-')\r
- {\r
- tmp_arg4[1] = '\0';\r
- Skinval4 = GetArgInt(4);\r
- }\r
- }\r
- }\r
- }\r
-\r
- SkinChar->SetCurrentLook(Skinval1, Skinval2, Skinval3, Skinval4);\r
-\r
- SkinChat << "Skin set to model ";\r
- SkinChat << (int)Skinval1 << " with head " << (int)Skinval2 << ", torso " << (int)Skinval3 << ", legs " << (int)Skinval4;\r
- }\r
-\r
- snprintf(SkinStr, 127, "%s", SkinChat.str().c_str());\r
- SkinStr[127] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", SkinStr);\r
-\r
- PMessage* tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
- ClientManager->UDPBroadcast(tmpMsg, source);\r
-}\r
+#include <sstream>
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdskin()
+{
+// -------------------------------------------------------
+/*
+Usage: @skin #<chardef idx>
+ for use with the index id from characters.def
+ or @skin <model>|-|# [<head>[ <torso>[ <legs>]]]
+ <model> is the model id found after the model name in characters.def
+ # resets to real char skin (optionnaly modified by following args)
+ - means current skin
+ incrementaly optional <head>, <torso> and <legs> are values 0-9
+*/
+ bool SyntaxError = false;
+ if(ArgC < 1)
+ {
+ SyntaxError = true;
+ }
+
+ uint32_t Skinval1, Skinval2, Skinval3, Skinval4;
+ PChar *SkinChar = Chars->GetChar(source->GetCharID());
+ std::stringstream SkinChat;
+ char SkinStr[128];
+
+ if(SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@skin ( #<chardef idx> ) | ( <model> | # [<head>[ <torso>[ <legs>]]] )");
+ return;
+ }
+
+ char tmpval[30];
+ GetArgText(1, tmpval, 30);
+ if((tmpval[0] == '#') && (tmpval[1] != '\0'))
+ {
+ Skinval1 = atoi(tmpval+1);
+ SkinChar->SetCurrentLookFromCharType(atoi(tmpval+1));
+ SkinChat << "Skin set to the skin of char type ";
+ SkinChat << (int)Skinval1;
+ }
+ else
+ {
+ if ((tmpval[0] == '#') && (tmpval[1] == '\0'))
+ {
+ SkinChar->GetRealLook(Skinval1, Skinval2, Skinval3, Skinval4);
+ }
+ else if ((tmpval[0] == '-') && (tmpval[1] == '\0'))
+ {
+ SkinChar->GetCurrentLook(Skinval1, Skinval2, Skinval3, Skinval4);
+ }
+ else
+ {
+ Skinval1 = GetArgInt(1);
+ }
+
+ char tmp_arg2[30];
+ char tmp_arg3[30];
+ char tmp_arg4[30];
+
+ GetArgText(2, tmp_arg2, 30);
+ GetArgText(3, tmp_arg3, 30);
+ GetArgText(4, tmp_arg4, 30);
+
+ if(tmp_arg2[0] != '\0')
+ {
+ if(tmp_arg2[0] != '-')
+ {
+ tmp_arg2[1] = '\0';
+ Skinval2 = GetArgInt(2);
+ }
+ if(tmp_arg3[0] != '\0')
+ {
+ if(tmp_arg3[0] != '-')
+ {
+ tmp_arg3[1] = '\0';
+ Skinval3 = GetArgInt(3);
+ }
+ if(tmp_arg4[0] != '\0')
+ {
+ if(tmp_arg4[0] != '-')
+ {
+ tmp_arg4[1] = '\0';
+ Skinval4 = GetArgInt(4);
+ }
+ }
+ }
+ }
+
+ SkinChar->SetCurrentLook(Skinval1, Skinval2, Skinval3, Skinval4);
+
+ SkinChat << "Skin set to model ";
+ SkinChat << (int)Skinval1 << " with head " << (int)Skinval2 << ", torso " << (int)Skinval3 << ", legs " << (int)Skinval4;
+ }
+
+ snprintf(SkinStr, 127, "%s", SkinChat.str().c_str());
+ SkinStr[127] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", SkinStr);
+
+ PMessage* tmpMsg = MsgBuilder->BuildCharHelloMsg(source);
+ ClientManager->UDPBroadcast(tmpMsg, source);
+}
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdspawnactor()\r
-{\r
- bool SyntaxError = false;\r
- if(ArgC < 2)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- if(IsArgNumeric(1) == false || IsArgNumeric(2) == false)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- uint16_t tmpActorID = (uint16_t)GetArgInt(1);\r
- uint16_t tmpFunctionID = (uint16_t)GetArgInt(2);\r
- uint16_t tmpOption1 = 0;\r
- uint16_t tmpOption2 = 0;\r
- uint16_t tmpOption3 = 0;\r
-\r
- if(ArgC > 2)\r
- {\r
- if(IsArgNumeric(3) == false)\r
- {\r
- SyntaxError = true;\r
- }\r
- else\r
- {\r
- tmpOption1 = (uint16_t)GetArgInt(3);\r
- if(ArgC > 3)\r
- {\r
- if(IsArgNumeric(4) == false)\r
- {\r
- SyntaxError = true;\r
- }\r
- else\r
- {\r
- tmpOption1 = (uint16_t)GetArgInt(4);\r
- if(ArgC > 4)\r
- {\r
- if(IsArgNumeric(4) == false)\r
- {\r
- SyntaxError = true;\r
- }\r
- else\r
- {\r
- tmpOption1 = (uint16_t)GetArgInt(5);\r
- }\r
- }\r
- }\r
- }\r
- }\r
- }\r
-\r
- if(tmpActorID == 0)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- if(SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@spawnactor <actorID> <functionID> [<option1> <option2> <option3>]");\r
- return;\r
- }\r
-\r
- if(WorldActors->IsValidWAFunction(tmpFunctionID) == true)\r
- {\r
- if(WorldActors->RequiresLinkedObject(tmpFunctionID == true))\r
- {\r
- if(WorldActors->IsValidLinkedObject(source, tmpOption1, tmpFunctionID) == false)\r
- {\r
- if(tmpOption1 == 0)\r
- Chat->send(source, CHAT_DIRECT, "System", "Error: This functionID requires an linked object");\r
- else if(tmpOption1 == 18)\r
- Chat->send(source, CHAT_DIRECT, "System", "Error: Invalid destination world");\r
- else\r
- Chat->send(source, CHAT_DIRECT, "System", "Error: Invalid worldobjectID to link to");\r
- return;\r
- }\r
- }\r
- WorldActors->AddWorldActor(source, tmpActorID, tmpFunctionID, tmpOption1, tmpOption2, tmpOption3);\r
- }\r
- else\r
- {\r
- Chat->send(source, CHAT_DIRECT, "System", "Error: This is an invalid function ID");\r
- return;\r
- }\r
- //PMessage* tmpMsg = MsgBuilder->BuiltSpawnObjectMsg(source, tmpActorID, tmpFunctionID, mWOID++);\r
- //ClientManager->UDPBroadcast(tmpMsg, source);\r
- //tmpMsg = NULL;\r
-}\r
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdspawnactor()
+{
+ bool SyntaxError = false;
+ if(ArgC < 2)
+ {
+ SyntaxError = true;
+ }
+
+ if(IsArgNumeric(1) == false || IsArgNumeric(2) == false)
+ {
+ SyntaxError = true;
+ }
+
+ uint16_t tmpActorID = (uint16_t)GetArgInt(1);
+ uint16_t tmpFunctionID = (uint16_t)GetArgInt(2);
+ uint16_t tmpOption1 = 0;
+ uint16_t tmpOption2 = 0;
+ uint16_t tmpOption3 = 0;
+
+ if(ArgC > 2)
+ {
+ if(IsArgNumeric(3) == false)
+ {
+ SyntaxError = true;
+ }
+ else
+ {
+ tmpOption1 = (uint16_t)GetArgInt(3);
+ if(ArgC > 3)
+ {
+ if(IsArgNumeric(4) == false)
+ {
+ SyntaxError = true;
+ }
+ else
+ {
+ tmpOption1 = (uint16_t)GetArgInt(4);
+ if(ArgC > 4)
+ {
+ if(IsArgNumeric(4) == false)
+ {
+ SyntaxError = true;
+ }
+ else
+ {
+ tmpOption1 = (uint16_t)GetArgInt(5);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(tmpActorID == 0)
+ {
+ SyntaxError = true;
+ }
+
+ if(SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@spawnactor <actorID> <functionID> [<option1> <option2> <option3>]");
+ return;
+ }
+
+ if(WorldActors->IsValidWAFunction(tmpFunctionID) == true)
+ {
+ if(WorldActors->RequiresLinkedObject(tmpFunctionID == true))
+ {
+ if(WorldActors->IsValidLinkedObject(source, tmpOption1, tmpFunctionID) == false)
+ {
+ if(tmpOption1 == 0)
+ Chat->send(source, CHAT_DIRECT, "System", "Error: This functionID requires an linked object");
+ else if(tmpOption1 == 18)
+ Chat->send(source, CHAT_DIRECT, "System", "Error: Invalid destination world");
+ else
+ Chat->send(source, CHAT_DIRECT, "System", "Error: Invalid worldobjectID to link to");
+ return;
+ }
+ }
+ WorldActors->AddWorldActor(source, tmpActorID, tmpFunctionID, tmpOption1, tmpOption2, tmpOption3);
+ }
+ else
+ {
+ Chat->send(source, CHAT_DIRECT, "System", "Error: This is an invalid function ID");
+ return;
+ }
+ //PMessage* tmpMsg = MsgBuilder->BuiltSpawnObjectMsg(source, tmpActorID, tmpFunctionID, mWOID++);
+ //ClientManager->UDPBroadcast(tmpMsg, source);
+ //tmpMsg = NULL;
+}
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdspeed()\r
-{\r
-// Speed override setting.\r
-// Usage: @speed <newspeed> | #\r
-// with <speed> = 0 (no move).. 254 , 255 or # meaning "no speed override"\r
-\r
- bool SyntaxError = false;\r
- if(ArgC < 1)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- if(SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@speed <newspeed: 0 .. 254 > | 255 | #");\r
- return;\r
- }\r
- char tmpval[30];\r
- GetArgText(1, tmpval, 30);\r
-\r
- uint8_t val1;\r
- char effStr[128];\r
- PMessage* tmpMsg;\r
-\r
- val1 = ((tmpval[0] == '#') ? 255 : (uint8_t)(atoi(tmpval) & 0xff));\r
- source->GetChar()->SetSpeedOverride(val1);\r
-\r
- tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
- ClientManager->UDPBroadcast(tmpMsg, source);\r
- snprintf(effStr, 127, "Speed override set to value %d ", val1);\r
- effStr[127] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", effStr);\r
-}\r
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdspeed()
+{
+// Speed override setting.
+// Usage: @speed <newspeed> | #
+// with <speed> = 0 (no move).. 254 , 255 or # meaning "no speed override"
+
+ bool SyntaxError = false;
+ if(ArgC < 1)
+ {
+ SyntaxError = true;
+ }
+
+ if(SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@speed <newspeed: 0 .. 254 > | 255 | #");
+ return;
+ }
+ char tmpval[30];
+ GetArgText(1, tmpval, 30);
+
+ uint8_t val1;
+ char effStr[128];
+ PMessage* tmpMsg;
+
+ val1 = ((tmpval[0] == '#') ? 255 : (uint8_t)(atoi(tmpval) & 0xff));
+ source->GetChar()->SetSpeedOverride(val1);
+
+ tmpMsg = MsgBuilder->BuildCharHelloMsg(source);
+ ClientManager->UDPBroadcast(tmpMsg, source);
+ snprintf(effStr, 127, "Speed override set to value %d ", val1);
+ effStr[127] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", effStr);
+}
-#include <chrono>\r
-#include <thread>\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-void PCommands::doCmd_dev_t()\r
-{\r
- const char* usage = "Usage: @t r <rawid> (to remove object) | @t d <rawid> [<v1=74> [<v2=29>]] (to send death packet to object with args v1 v2)";\r
- char tmpStr[128];\r
- const char* textMsg = usage;\r
- PMessage* tmpMsg = NULL;\r
- char Arg1[30];\r
-\r
- if ( IsAdmin() == false )\r
- return;\r
-\r
- Arg1[0] = tmpStr[0] = '\0';\r
-\r
- if ( ArgC >= 2 )\r
- {\r
- GetArgText( 1, Arg1, 30 );\r
- uint32_t targetObjectId = GetArgInt( 2 ) & 0xffffffff;\r
- if ( Arg1[0] == 't' )\r
- {\r
- uint8_t val1;\r
- if ( ArgC >= 3 )\r
- {\r
- int val2 = GetArgInt( 3 );\r
- tmpMsg = new PMessage( 32 );\r
- source->IncreaseUDP_ID();\r
- *tmpMsg << ( uint8_t )0x13;\r
- *tmpMsg << ( uint16_t )source->GetUDP_ID();\r
- *tmpMsg << ( uint16_t )source->GetSessionID();\r
- *tmpMsg << ( uint8_t )0x00; // Message length\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )source->GetUDP_ID();\r
- *tmpMsg << ( uint8_t )0x2d;\r
- *tmpMsg << ( uint32_t )targetObjectId;\r
- *tmpMsg << ( uint8_t )0x01;\r
- *tmpMsg << ( uint32_t )val2;\r
-\r
- ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );\r
- source->SendUDPMessage( tmpMsg );\r
- snprintf( tmpStr, 127, "Sent 13/03/2d msg to object id 0x%08x with values 6/%d", targetObjectId, val2 );\r
- textMsg = tmpStr;\r
- }\r
- else for(val1 = 2; val1 < 255; ++val1)\r
- {\r
- if(val1 == 6) continue;\r
- tmpMsg = new PMessage( 15 );\r
- source->IncreaseUDP_ID();\r
- *tmpMsg << ( uint8_t )0x13;\r
- *tmpMsg << ( uint16_t )source->GetUDP_ID();\r
- *tmpMsg << ( uint16_t )source->GetSessionID();\r
- *tmpMsg << ( uint8_t )0x00; // Message length\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )source->GetUDP_ID();\r
- *tmpMsg << ( uint8_t )0x2d;\r
- *tmpMsg << ( uint32_t )targetObjectId;\r
- *tmpMsg << ( uint8_t )val1;\r
-\r
- ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );\r
- source->SendUDPMessage( tmpMsg );\r
- snprintf( tmpStr, 127, "Sent 13/03/2d msg to object id 0x%08x with value %d", targetObjectId, val1 );\r
- textMsg = tmpStr;\r
- tmpStr[127] = '\0';\r
- Chat->send( source, CHAT_DIRECT, "System", textMsg );\r
- source->getUDPConn()->update();\r
- source->getTCPConn()->update();\r
- //sleep(1);\r
- std::this_thread::sleep_for(std::chrono::seconds(1));\r
- }\r
- tmpMsg = NULL;\r
- }\r
- else if ( Arg1[0] == 'd' )\r
- {\r
- uint8_t val1 = 0x4a; // default values\r
- uint8_t val2 = 0x1e;\r
-\r
- if ( ArgC >= 3 )\r
- val1 = GetArgInt( 3 ) & 0xff;\r
- if ( ArgC >= 4 )\r
- val2 = GetArgInt( 4 ) & 0xff;\r
- tmpMsg = MsgBuilder->BuildNpcDeathMsg( source, targetObjectId, val1, val2 );\r
- snprintf( tmpStr, 127, "Sending Death update to object id 0x%08x with values 0x%02x 0x%02x", targetObjectId, val1, val2 );\r
- textMsg = tmpStr;\r
- }\r
- else if ( Arg1[0] == 'm' )\r
- {\r
- uint8_t nTxtGroupID = targetObjectId & 0xff;\r
- uint16_t nTxtID = 10;\r
- //uint32_t nVal = 0;\r
- if ( ArgC >= 3 )\r
- nTxtID = GetArgInt( 3 ) & 0xffff;\r
- //if(ArgC >= 4)\r
- // val2 = GetArgInt(4) & 0xff;\r
-\r
- tmpMsg = new PMessage( 20 );\r
-\r
- source->IncreaseUDP_ID();\r
- *tmpMsg << ( uint8_t )0x13;\r
- *tmpMsg << ( uint16_t )source->GetUDP_ID();\r
- *tmpMsg << ( uint16_t )source->GetSessionID();\r
- *tmpMsg << ( uint8_t )0x0e; // Message length\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )source->GetUDP_ID();\r
- *tmpMsg << ( uint8_t )0x1f;\r
- *tmpMsg << ( uint16_t )source->GetLocalID();\r
- *tmpMsg << ( uint8_t )0x25; // ??\r
- *tmpMsg << ( uint8_t )0x15; // ??\r
- *tmpMsg << nTxtGroupID;\r
- *tmpMsg << nTxtID;\r
- *tmpMsg << ( uint16_t )0x00; // ??\r
- *tmpMsg << ( uint8_t )0x01;\r
- *tmpMsg << ( uint8_t )0x04;\r
- *tmpMsg << ( uint32_t )0x00;\r
- //*tmpMsg << (uint8_t)0x00; // ??\r
- //*tmpMsg << (uint8_t)0x00; // ??\r
- //*tmpMsg << (uint32_t)nVal;\r
-\r
- ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );\r
- snprintf( tmpStr, 127, "Using msg n %d from group %d", nTxtID, nTxtGroupID );\r
- textMsg = tmpStr;\r
-\r
- source->SendUDPMessage( tmpMsg );\r
- tmpMsg = NULL;\r
- }\r
- else if ( Arg1[0] == 'e' )\r
- {\r
- targetObjectId = 1004; //target=int\r
- uint16_t nval = 5;\r
- uint8_t nType = 1; // 1=+ 2=-\r
- uint16_t nDur = 20;\r
- uint8_t nparam = 1;\r
-\r
- nparam = GetArgInt( 2 ) & 0xff;\r
-\r
- tmpMsg = new PMessage( 32 );\r
-\r
- source->IncreaseUDP_ID();\r
- *tmpMsg << ( uint8_t )0x13;\r
- *tmpMsg << ( uint16_t )source->GetUDP_ID();\r
- *tmpMsg << ( uint16_t )source->GetSessionID();\r
- *tmpMsg << ( uint8_t )0x0e; // Message length\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )source->GetUDP_ID();\r
- *tmpMsg << ( uint8_t )0x1f;\r
- *tmpMsg << ( uint16_t )source->GetLocalID();\r
- *tmpMsg << ( uint8_t )0x25; // ??\r
- *tmpMsg << ( uint8_t )0x06; // ??\r
- *tmpMsg << ( uint8_t )0x01; // 1 effect\r
- *tmpMsg << ( uint8_t )0x01; // effect on intox level ????\r
- *tmpMsg << ( uint16_t )nDur;\r
- *tmpMsg << ( uint16_t )(700+(targetObjectId % 100)); //item id Thyronol\r
- *tmpMsg << ( uint8_t )nType;\r
- *tmpMsg << ( uint16_t )(nval*100); //uint32_t in nc2.2\r
- *tmpMsg << ( uint16_t )targetObjectId;\r
-\r
-\r
- ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );\r
- snprintf( tmpStr, 127, "Sendind drug mod to stat %d, %s %d", targetObjectId, (nType == 1 ? "inc" : "dec"), nval );\r
- textMsg = tmpStr;\r
-\r
- source->SendUDPMessage( tmpMsg );\r
- tmpMsg = NULL;\r
- }\r
- else if ( Arg1[0] == 'w' )\r
- {\r
- /*targetObjectId &= 0xffff;\r
- uint16_t val1 = 0;\r
- if ( ArgC >= 3 )\r
- val1 = GetArgInt( 3 ) & 0xffff;\r
-*/\r
- tmpMsg = new PMessage( 15 );\r
-\r
- source->IncreaseUDP_ID();\r
-\r
- *tmpMsg << ( uint8_t )0x13;\r
- *tmpMsg << ( uint16_t )source->GetUDP_ID();\r
- *tmpMsg << ( uint16_t )source->GetSessionID();\r
- *tmpMsg << ( uint8_t )0x0a; // Message length place;\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )source->GetUDP_ID();\r
- *tmpMsg << ( uint8_t )0x23;\r
- *tmpMsg << ( uint16_t )0x0012; // cmd = ?\r
- *tmpMsg << ( uint16_t )0x0007;\r
- *tmpMsg << ( uint32_t )0x00000000;\r
-\r
- ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );\r
-\r
- snprintf( tmpStr, 127, "Sending w msg " );\r
- textMsg = tmpStr;\r
-\r
- source->SendUDPMessage( tmpMsg );\r
- tmpMsg = NULL;\r
- }\r
- else if ( Arg1[0] == 'x' )\r
- {\r
- uint8_t val1 = targetObjectId &= 0xff;\r
-\r
- tmpMsg = MsgBuilder->BuildUndefineduseMsg( source, val1 );\r
-\r
- snprintf( tmpStr, 127, "Sending x msg with param %d (0x%2x)", val1, val1 );\r
- textMsg = tmpStr;\r
-\r
- source->SendUDPMessage( tmpMsg );\r
- tmpMsg = NULL;\r
- }\r
- }\r
-\r
- tmpStr[127] = '\0';\r
- Chat->send( source, CHAT_DIRECT, "System", textMsg );\r
-\r
- if ( tmpMsg )\r
- ClientManager->UDPBroadcast( tmpMsg, source );\r
-}\r
-\r
-/*** Packet fields testing. Please do not delete (Hammag)\r
-void PCommands::doCmd_dev_t()\r
-{\r
- if(IsAdmin() == false)\r
- return;\r
-\r
- char Arg1[30], Arg2[30];\r
-\r
- Arg1[0] = '\0';\r
- Arg2[0] = '\0';\r
-\r
- if(ArgC > 0)\r
- {\r
- GetArgText(1, Arg1, 30);\r
- if(ArgC > 1)\r
- {\r
- GetArgText(2, Arg2, 30);\r
- }\r
- }\r
-\r
- uint32_t val1;\r
- uint8_t val2;\r
- char tmpStr[128];\r
- static PMessage* tmpMsg = NULL;\r
- bool SetUDP_IDNeeded = true;\r
- PChar* nChar = source->GetChar();\r
- (nChar->Coords).mY += 20;\r
- (nChar->Coords).mZ += 20;\r
- (nChar->Coords).mX += 20;\r
-\r
- if (!tmpMsg)\r
- {\r
- tmpMsg = MsgBuilder->BuildPacket0Msg(source);\r
- //tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
- SetUDP_IDNeeded = false;\r
- }\r
-\r
- if(Arg1[0] != '\0' && Arg2[0] != '\0')\r
- {\r
- val1 = atoi(Arg1);\r
- val2 = (uint8_t)(atoi(Arg2) & 0xff);\r
- //tmpMsg->U8Data(16 + val1) = val2;\r
- tmpMsg->U8Data(10 + val1) = val2;\r
- snprintf(tmpStr, 127, "Data #%d set to value 0x%02x", val1, val2);\r
- }\r
- else\r
- {\r
- if (tmpMsg)\r
- delete tmpMsg;\r
- //tmpMsg = MsgBuilder->BuildCharHelloMsg(source);\r
- tmpMsg = MsgBuilder->BuildPacket0Msg(source);\r
- SetUDP_IDNeeded = false;\r
- snprintf(tmpStr, 127, "Data reset to normal values");\r
- }\r
-\r
- tmpStr[127] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", tmpStr);\r
-\r
- PMessage* SendMsg = new PMessage(*tmpMsg);\r
- if(SetUDP_IDNeeded) {\r
- source->FillInUDP_ID(SendMsg);\r
- }\r
- SendMsg->Dump();\r
- //ClientManager->UDPBroadcast(SendMsg, source);\r
- source->SendUDPMessage(SendMsg);\r
-}\r
-***/\r
-\r
-/*** Subwy testing. Please do not delete (Hammag)\r
-void PCommands::doCmd_dev_t()\r
-{\r
- if(IsAdmin() == false)\r
- return;\r
-\r
- char tmpStr[128];\r
- uint8_t SubWay[] = {0x13, 0x71, 0x00, 0x9b, 0xde,\r
- //Subway 1 (fc 03)\r
- 0x11,\r
- 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfc, 0x03, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,\r
- 0x0d,\r
- 0x03, 0x71, 0x00, 0x2d, 0xfc, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
- 0x00, 0x00, 0x00,\r
- //Subway 2 (fb 03)\r
- 0x11,\r
- 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfb, 0x03, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0xf0, 0x41, 0x00, 0x01,\r
- 0x0d,\r
- 0x03, 0x71, 0x00, 0x2d, 0xfb, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
- 0x00, 0x00, 0x00,\r
- //Subway 3 (fa 03)\r
- 0x11,\r
- 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfa, 0x03, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0x70, 0x42, 0x00, 0x01,\r
- 0x0d,\r
- 0x03, 0x71, 0x00, 0x2d, 0xfa, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
- 0x00, 0x00, 0x00,\r
- //Subway 4 (f9 03)\r
- 0x11,\r
- 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf9, 0x03, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0xb4, 0x42, 0x00, 0x01,\r
- 0x0d,\r
- 0x03, 0x71, 0x00, 0x2d, 0xf9, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
- 0x00, 0x00, 0x00,\r
- //Subway 5 (f8 03)\r
- 0x11,\r
- 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf8, 0x03, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0xf0, 0x42, 0x00, 0x01,\r
- 0x0d,\r
- 0x03, 0x71, 0x00, 0x2d, 0xf8, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
- 0x00, 0x00, 0x00,\r
- //Subway 6 (f7 03)\r
- 0x11,\r
- 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf7, 0x03, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0x16, 0x43, 0x00, 0x01,\r
- 0x0d,\r
- 0x03, 0x71, 0x00, 0x2d, 0xf7, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
- 0x00, 0x00, 0x00};\r
-\r
- uint8_t SubWay2[] = {0x13, 0x71, 0x00, 0x9b, 0xde,\r
- //Subway 7 (f6 03)\r
- 0x11,\r
- 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf6, 0x03, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0x34, 0x43, 0x00, 0x01,\r
- 0x0d,\r
- 0x03, 0x71, 0x00, 0x2d, 0xf6, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
- 0x00, 0x00, 0x00,\r
- //Subway 8 (f5 03)\r
- 0x11,\r
- 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf5, 0x03, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0x52, 0x43, 0x00, 0x01,\r
- 0x0d,\r
- 0x03, 0x71, 0x00, 0x2d, 0xf5, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
- 0x00, 0x00, 0x00,\r
- //Subway 9 (f4 03)\r
- 0x11,\r
- 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf4, 0x03, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0x70, 0x43, 0x00, 0x01,\r
- 0x0d,\r
- 0x03, 0x71, 0x00, 0x2d, 0xf4, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
- 0x00, 0x00, 0x00,\r
- //Subway 10 (f3 03)\r
- 0x11,\r
- 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf3, 0x03, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0x87, 0x43, 0x00, 0x01,\r
- 0x0d,\r
- 0x03, 0x71, 0x00, 0x2d, 0xf3, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
- 0x00, 0x00, 0x00,\r
- //Subway 11 (f2 03)\r
- 0x11,\r
- 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf2, 0x03, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0x96, 0x43, 0x00, 0x01,\r
- 0x0d,\r
- 0x03, 0x71, 0x00, 0x2d, 0xf2, 0x03, 0x00, 0x00, 0x0a, 0x00,\r
- 0x00, 0x00, 0x00};\r
-\r
- if (source->GetChar()->GetLocation() != 1000)\r
- return;\r
-\r
- //SubWay List\r
- //Subway 1\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay[7] = source->GetUDP_ID();\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay[25] = source->GetUDP_ID();\r
-\r
- //Subway 2\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay[39] = source->GetUDP_ID();\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay[57] = source->GetUDP_ID();\r
-\r
- //Subway 3\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay[71] = source->GetUDP_ID();\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay[89] = source->GetUDP_ID();\r
-\r
- //Subway 4\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay[103] = source->GetUDP_ID();\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay[121] = source->GetUDP_ID();\r
-\r
- //Subway 5\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay[135] = source->GetUDP_ID();\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay[153] = source->GetUDP_ID();\r
-\r
- //Subway 6\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay[167] = source->GetUDP_ID();\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay[185] = source->GetUDP_ID();\r
-\r
- //Subway 7\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay2[7] = source->GetUDP_ID();\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay2[25] = source->GetUDP_ID();\r
-\r
- //Subway 8\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay2[39] = source->GetUDP_ID();\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay2[57] = source->GetUDP_ID();\r
-\r
- //Subway 9\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay2[71] = source->GetUDP_ID();\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay2[89] = source->GetUDP_ID();\r
-\r
- //Subway 10\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay2[103] = source->GetUDP_ID();\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay2[121] = source->GetUDP_ID();\r
-\r
- //Subway 11\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay2[135] = source->GetUDP_ID();\r
- source->IncreaseUDP_ID();\r
- *(uint16_t*)&SubWay2[153] = source->GetUDP_ID();\r
-\r
- *(uint16_t*)&SubWay[1] = source->GetUDP_ID();\r
- *(uint16_t*)&SubWay[3] = source->GetSessionID();\r
-\r
- PMessage* msg;\r
- msg = new PMessage(197);\r
- msg->Write(SubWay, sizeof(SubWay));\r
-Console->Print("---- Working 1 ----");\r
-msg->Dump();\r
- source->SendUDPMessage(msg);\r
-msg = MsgBuilder->BuildSubwaySpawnMsg(source, false);\r
-Console->Print("---- Not Working 1 ----");\r
-msg->Dump();\r
-source->SendUDPMessage(msg);\r
-\r
- *(uint16_t*)&SubWay2[1] = source->GetUDP_ID();\r
- *(uint16_t*)&SubWay2[3] = source->GetSessionID();\r
-\r
- msg = new PMessage(197);\r
- msg->Write(SubWay2, sizeof(SubWay2));\r
-Console->Print("---- Working 2 ----");\r
-msg->Dump();\r
- source->SendUDPMessage(msg);\r
-msg = MsgBuilder->BuildSubwaySpawnMsg(source, true);\r
-Console->Print("---- Not Working 2 ----");\r
-msg->Dump();\r
-source->SendUDPMessage(msg);\r
-\r
- snprintf(tmpStr, 127, "Initial subway data sent");\r
- tmpStr[127] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", tmpStr);\r
-}\r
-***/\r
+#include <chrono>
+#include <thread>
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+void PCommands::doCmd_dev_t()
+{
+ const char* usage = "Usage: @t r <rawid> (to remove object) | @t d <rawid> [<v1=74> [<v2=29>]] (to send death packet to object with args v1 v2)";
+ char tmpStr[128];
+ const char* textMsg = usage;
+ PMessage* tmpMsg = NULL;
+ char Arg1[30];
+
+ if ( IsAdmin() == false )
+ return;
+
+ Arg1[0] = tmpStr[0] = '\0';
+
+ if ( ArgC >= 2 )
+ {
+ GetArgText( 1, Arg1, 30 );
+ uint32_t targetObjectId = GetArgInt( 2 ) & 0xffffffff;
+ if ( Arg1[0] == 't' )
+ {
+ uint8_t val1;
+ if ( ArgC >= 3 )
+ {
+ int val2 = GetArgInt( 3 );
+ tmpMsg = new PMessage( 32 );
+ source->IncreaseUDP_ID();
+ *tmpMsg << ( uint8_t )0x13;
+ *tmpMsg << ( uint16_t )source->GetUDP_ID();
+ *tmpMsg << ( uint16_t )source->GetSessionID();
+ *tmpMsg << ( uint8_t )0x00; // Message length
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )source->GetUDP_ID();
+ *tmpMsg << ( uint8_t )0x2d;
+ *tmpMsg << ( uint32_t )targetObjectId;
+ *tmpMsg << ( uint8_t )0x01;
+ *tmpMsg << ( uint32_t )val2;
+
+ ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );
+ source->SendUDPMessage( tmpMsg );
+ snprintf( tmpStr, 127, "Sent 13/03/2d msg to object id 0x%08x with values 6/%d", targetObjectId, val2 );
+ textMsg = tmpStr;
+ }
+ else for(val1 = 2; val1 < 255; ++val1)
+ {
+ if(val1 == 6) continue;
+ tmpMsg = new PMessage( 15 );
+ source->IncreaseUDP_ID();
+ *tmpMsg << ( uint8_t )0x13;
+ *tmpMsg << ( uint16_t )source->GetUDP_ID();
+ *tmpMsg << ( uint16_t )source->GetSessionID();
+ *tmpMsg << ( uint8_t )0x00; // Message length
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )source->GetUDP_ID();
+ *tmpMsg << ( uint8_t )0x2d;
+ *tmpMsg << ( uint32_t )targetObjectId;
+ *tmpMsg << ( uint8_t )val1;
+
+ ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );
+ source->SendUDPMessage( tmpMsg );
+ snprintf( tmpStr, 127, "Sent 13/03/2d msg to object id 0x%08x with value %d", targetObjectId, val1 );
+ textMsg = tmpStr;
+ tmpStr[127] = '\0';
+ Chat->send( source, CHAT_DIRECT, "System", textMsg );
+ source->getUDPConn()->update();
+ source->getTCPConn()->update();
+ //sleep(1);
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ }
+ tmpMsg = NULL;
+ }
+ else if ( Arg1[0] == 'd' )
+ {
+ uint8_t val1 = 0x4a; // default values
+ uint8_t val2 = 0x1e;
+
+ if ( ArgC >= 3 )
+ val1 = GetArgInt( 3 ) & 0xff;
+ if ( ArgC >= 4 )
+ val2 = GetArgInt( 4 ) & 0xff;
+ tmpMsg = MsgBuilder->BuildNpcDeathMsg( source, targetObjectId, val1, val2 );
+ snprintf( tmpStr, 127, "Sending Death update to object id 0x%08x with values 0x%02x 0x%02x", targetObjectId, val1, val2 );
+ textMsg = tmpStr;
+ }
+ else if ( Arg1[0] == 'm' )
+ {
+ uint8_t nTxtGroupID = targetObjectId & 0xff;
+ uint16_t nTxtID = 10;
+ //uint32_t nVal = 0;
+ if ( ArgC >= 3 )
+ nTxtID = GetArgInt( 3 ) & 0xffff;
+ //if(ArgC >= 4)
+ // val2 = GetArgInt(4) & 0xff;
+
+ tmpMsg = new PMessage( 20 );
+
+ source->IncreaseUDP_ID();
+ *tmpMsg << ( uint8_t )0x13;
+ *tmpMsg << ( uint16_t )source->GetUDP_ID();
+ *tmpMsg << ( uint16_t )source->GetSessionID();
+ *tmpMsg << ( uint8_t )0x0e; // Message length
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )source->GetUDP_ID();
+ *tmpMsg << ( uint8_t )0x1f;
+ *tmpMsg << ( uint16_t )source->GetLocalID();
+ *tmpMsg << ( uint8_t )0x25; // ??
+ *tmpMsg << ( uint8_t )0x15; // ??
+ *tmpMsg << nTxtGroupID;
+ *tmpMsg << nTxtID;
+ *tmpMsg << ( uint16_t )0x00; // ??
+ *tmpMsg << ( uint8_t )0x01;
+ *tmpMsg << ( uint8_t )0x04;
+ *tmpMsg << ( uint32_t )0x00;
+ //*tmpMsg << (uint8_t)0x00; // ??
+ //*tmpMsg << (uint8_t)0x00; // ??
+ //*tmpMsg << (uint32_t)nVal;
+
+ ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );
+ snprintf( tmpStr, 127, "Using msg n %d from group %d", nTxtID, nTxtGroupID );
+ textMsg = tmpStr;
+
+ source->SendUDPMessage( tmpMsg );
+ tmpMsg = NULL;
+ }
+ else if ( Arg1[0] == 'e' )
+ {
+ targetObjectId = 1004; //target=int
+ uint16_t nval = 5;
+ uint8_t nType = 1; // 1=+ 2=-
+ uint16_t nDur = 20;
+ uint8_t nparam = 1;
+
+ nparam = GetArgInt( 2 ) & 0xff;
+
+ tmpMsg = new PMessage( 32 );
+
+ source->IncreaseUDP_ID();
+ *tmpMsg << ( uint8_t )0x13;
+ *tmpMsg << ( uint16_t )source->GetUDP_ID();
+ *tmpMsg << ( uint16_t )source->GetSessionID();
+ *tmpMsg << ( uint8_t )0x0e; // Message length
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )source->GetUDP_ID();
+ *tmpMsg << ( uint8_t )0x1f;
+ *tmpMsg << ( uint16_t )source->GetLocalID();
+ *tmpMsg << ( uint8_t )0x25; // ??
+ *tmpMsg << ( uint8_t )0x06; // ??
+ *tmpMsg << ( uint8_t )0x01; // 1 effect
+ *tmpMsg << ( uint8_t )0x01; // effect on intox level ????
+ *tmpMsg << ( uint16_t )nDur;
+ *tmpMsg << ( uint16_t )(700+(targetObjectId % 100)); //item id Thyronol
+ *tmpMsg << ( uint8_t )nType;
+ *tmpMsg << ( uint16_t )(nval*100); //uint32_t in nc2.2
+ *tmpMsg << ( uint16_t )targetObjectId;
+
+
+ ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );
+ snprintf( tmpStr, 127, "Sendind drug mod to stat %d, %s %d", targetObjectId, (nType == 1 ? "inc" : "dec"), nval );
+ textMsg = tmpStr;
+
+ source->SendUDPMessage( tmpMsg );
+ tmpMsg = NULL;
+ }
+ else if ( Arg1[0] == 'w' )
+ {
+ /*targetObjectId &= 0xffff;
+ uint16_t val1 = 0;
+ if ( ArgC >= 3 )
+ val1 = GetArgInt( 3 ) & 0xffff;
+*/
+ tmpMsg = new PMessage( 15 );
+
+ source->IncreaseUDP_ID();
+
+ *tmpMsg << ( uint8_t )0x13;
+ *tmpMsg << ( uint16_t )source->GetUDP_ID();
+ *tmpMsg << ( uint16_t )source->GetSessionID();
+ *tmpMsg << ( uint8_t )0x0a; // Message length place;
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )source->GetUDP_ID();
+ *tmpMsg << ( uint8_t )0x23;
+ *tmpMsg << ( uint16_t )0x0012; // cmd = ?
+ *tmpMsg << ( uint16_t )0x0007;
+ *tmpMsg << ( uint32_t )0x00000000;
+
+ ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );
+
+ snprintf( tmpStr, 127, "Sending w msg " );
+ textMsg = tmpStr;
+
+ source->SendUDPMessage( tmpMsg );
+ tmpMsg = NULL;
+ }
+ else if ( Arg1[0] == 'x' )
+ {
+ uint8_t val1 = targetObjectId &= 0xff;
+
+ tmpMsg = MsgBuilder->BuildUndefineduseMsg( source, val1 );
+
+ snprintf( tmpStr, 127, "Sending x msg with param %d (0x%2x)", val1, val1 );
+ textMsg = tmpStr;
+
+ source->SendUDPMessage( tmpMsg );
+ tmpMsg = NULL;
+ }
+ }
+
+ tmpStr[127] = '\0';
+ Chat->send( source, CHAT_DIRECT, "System", textMsg );
+
+ if ( tmpMsg )
+ ClientManager->UDPBroadcast( tmpMsg, source );
+}
+
+/*** Packet fields testing. Please do not delete (Hammag)
+void PCommands::doCmd_dev_t()
+{
+ if(IsAdmin() == false)
+ return;
+
+ char Arg1[30], Arg2[30];
+
+ Arg1[0] = '\0';
+ Arg2[0] = '\0';
+
+ if(ArgC > 0)
+ {
+ GetArgText(1, Arg1, 30);
+ if(ArgC > 1)
+ {
+ GetArgText(2, Arg2, 30);
+ }
+ }
+
+ uint32_t val1;
+ uint8_t val2;
+ char tmpStr[128];
+ static PMessage* tmpMsg = NULL;
+ bool SetUDP_IDNeeded = true;
+ PChar* nChar = source->GetChar();
+ (nChar->Coords).mY += 20;
+ (nChar->Coords).mZ += 20;
+ (nChar->Coords).mX += 20;
+
+ if (!tmpMsg)
+ {
+ tmpMsg = MsgBuilder->BuildPacket0Msg(source);
+ //tmpMsg = MsgBuilder->BuildCharHelloMsg(source);
+ SetUDP_IDNeeded = false;
+ }
+
+ if(Arg1[0] != '\0' && Arg2[0] != '\0')
+ {
+ val1 = atoi(Arg1);
+ val2 = (uint8_t)(atoi(Arg2) & 0xff);
+ //tmpMsg->U8Data(16 + val1) = val2;
+ tmpMsg->U8Data(10 + val1) = val2;
+ snprintf(tmpStr, 127, "Data #%d set to value 0x%02x", val1, val2);
+ }
+ else
+ {
+ if (tmpMsg)
+ delete tmpMsg;
+ //tmpMsg = MsgBuilder->BuildCharHelloMsg(source);
+ tmpMsg = MsgBuilder->BuildPacket0Msg(source);
+ SetUDP_IDNeeded = false;
+ snprintf(tmpStr, 127, "Data reset to normal values");
+ }
+
+ tmpStr[127] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", tmpStr);
+
+ PMessage* SendMsg = new PMessage(*tmpMsg);
+ if(SetUDP_IDNeeded) {
+ source->FillInUDP_ID(SendMsg);
+ }
+ SendMsg->Dump();
+ //ClientManager->UDPBroadcast(SendMsg, source);
+ source->SendUDPMessage(SendMsg);
+}
+***/
+
+/*** Subwy testing. Please do not delete (Hammag)
+void PCommands::doCmd_dev_t()
+{
+ if(IsAdmin() == false)
+ return;
+
+ char tmpStr[128];
+ uint8_t SubWay[] = {0x13, 0x71, 0x00, 0x9b, 0xde,
+ //Subway 1 (fc 03)
+ 0x11,
+ 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfc, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x0d,
+ 0x03, 0x71, 0x00, 0x2d, 0xfc, 0x03, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00,
+ //Subway 2 (fb 03)
+ 0x11,
+ 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfb, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xf0, 0x41, 0x00, 0x01,
+ 0x0d,
+ 0x03, 0x71, 0x00, 0x2d, 0xfb, 0x03, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00,
+ //Subway 3 (fa 03)
+ 0x11,
+ 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfa, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x70, 0x42, 0x00, 0x01,
+ 0x0d,
+ 0x03, 0x71, 0x00, 0x2d, 0xfa, 0x03, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00,
+ //Subway 4 (f9 03)
+ 0x11,
+ 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf9, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xb4, 0x42, 0x00, 0x01,
+ 0x0d,
+ 0x03, 0x71, 0x00, 0x2d, 0xf9, 0x03, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00,
+ //Subway 5 (f8 03)
+ 0x11,
+ 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf8, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xf0, 0x42, 0x00, 0x01,
+ 0x0d,
+ 0x03, 0x71, 0x00, 0x2d, 0xf8, 0x03, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00,
+ //Subway 6 (f7 03)
+ 0x11,
+ 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf7, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x16, 0x43, 0x00, 0x01,
+ 0x0d,
+ 0x03, 0x71, 0x00, 0x2d, 0xf7, 0x03, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00};
+
+ uint8_t SubWay2[] = {0x13, 0x71, 0x00, 0x9b, 0xde,
+ //Subway 7 (f6 03)
+ 0x11,
+ 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf6, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x34, 0x43, 0x00, 0x01,
+ 0x0d,
+ 0x03, 0x71, 0x00, 0x2d, 0xf6, 0x03, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00,
+ //Subway 8 (f5 03)
+ 0x11,
+ 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf5, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x52, 0x43, 0x00, 0x01,
+ 0x0d,
+ 0x03, 0x71, 0x00, 0x2d, 0xf5, 0x03, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00,
+ //Subway 9 (f4 03)
+ 0x11,
+ 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf4, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x70, 0x43, 0x00, 0x01,
+ 0x0d,
+ 0x03, 0x71, 0x00, 0x2d, 0xf4, 0x03, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00,
+ //Subway 10 (f3 03)
+ 0x11,
+ 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf3, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x87, 0x43, 0x00, 0x01,
+ 0x0d,
+ 0x03, 0x71, 0x00, 0x2d, 0xf3, 0x03, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00,
+ //Subway 11 (f2 03)
+ 0x11,
+ 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf2, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x96, 0x43, 0x00, 0x01,
+ 0x0d,
+ 0x03, 0x71, 0x00, 0x2d, 0xf2, 0x03, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0x00};
+
+ if (source->GetChar()->GetLocation() != 1000)
+ return;
+
+ //SubWay List
+ //Subway 1
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay[7] = source->GetUDP_ID();
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay[25] = source->GetUDP_ID();
+
+ //Subway 2
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay[39] = source->GetUDP_ID();
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay[57] = source->GetUDP_ID();
+
+ //Subway 3
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay[71] = source->GetUDP_ID();
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay[89] = source->GetUDP_ID();
+
+ //Subway 4
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay[103] = source->GetUDP_ID();
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay[121] = source->GetUDP_ID();
+
+ //Subway 5
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay[135] = source->GetUDP_ID();
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay[153] = source->GetUDP_ID();
+
+ //Subway 6
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay[167] = source->GetUDP_ID();
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay[185] = source->GetUDP_ID();
+
+ //Subway 7
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay2[7] = source->GetUDP_ID();
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay2[25] = source->GetUDP_ID();
+
+ //Subway 8
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay2[39] = source->GetUDP_ID();
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay2[57] = source->GetUDP_ID();
+
+ //Subway 9
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay2[71] = source->GetUDP_ID();
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay2[89] = source->GetUDP_ID();
+
+ //Subway 10
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay2[103] = source->GetUDP_ID();
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay2[121] = source->GetUDP_ID();
+
+ //Subway 11
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay2[135] = source->GetUDP_ID();
+ source->IncreaseUDP_ID();
+ *(uint16_t*)&SubWay2[153] = source->GetUDP_ID();
+
+ *(uint16_t*)&SubWay[1] = source->GetUDP_ID();
+ *(uint16_t*)&SubWay[3] = source->GetSessionID();
+
+ PMessage* msg;
+ msg = new PMessage(197);
+ msg->Write(SubWay, sizeof(SubWay));
+Console->Print("---- Working 1 ----");
+msg->Dump();
+ source->SendUDPMessage(msg);
+msg = MsgBuilder->BuildSubwaySpawnMsg(source, false);
+Console->Print("---- Not Working 1 ----");
+msg->Dump();
+source->SendUDPMessage(msg);
+
+ *(uint16_t*)&SubWay2[1] = source->GetUDP_ID();
+ *(uint16_t*)&SubWay2[3] = source->GetSessionID();
+
+ msg = new PMessage(197);
+ msg->Write(SubWay2, sizeof(SubWay2));
+Console->Print("---- Working 2 ----");
+msg->Dump();
+ source->SendUDPMessage(msg);
+msg = MsgBuilder->BuildSubwaySpawnMsg(source, true);
+Console->Print("---- Not Working 2 ----");
+msg->Dump();
+source->SendUDPMessage(msg);
+
+ snprintf(tmpStr, 127, "Initial subway data sent");
+ tmpStr[127] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", tmpStr);
+}
+***/
void PCommands::doCmdtest()
{
- if (GetArgInt(1) == 1)\r
- {\r
- if(ArgC < 5)\r
- return;\r
-\r
- PNPC* targetNPC = NULL;\r
- PNPCWorld* currentNPCWorld = NULL;\r
- currentNPCWorld = NPCManager->GetWorld( source->GetChar()->GetLocation() );\r
- if ( currentNPCWorld )\r
- {\r
- targetNPC = currentNPCWorld->GetNPC( GetArgInt(2) );\r
- if(!targetNPC)\r
- return;\r
- // @test 15 <npcID> <target_to_attack> <unknown uint8_t value>\r
- targetNPC->Attack(GetArgInt(3), (uint8_t)GetArgInt(5), (uint8_t)GetArgInt(4));\r
- }\r
- }\r
- else if (GetArgInt(1) == 2)\r
- {\r
- if(ArgC < 3)\r
- return;\r
-\r
- int tF1 = GetArgInt(2);\r
- int tF2 = GetArgInt(3);\r
- const PDefFaction* tFactionA = NULL;\r
- const PDefFaction* tFactionB = NULL;\r
-\r
- if(tF1 > tF2)\r
- {\r
- tFactionA = GameDefs->Factions()->GetDef(tF1);\r
- tFactionB = GameDefs->Factions()->GetDef(tF2);\r
- }\r
- else\r
- {\r
- tFactionA = GameDefs->Factions()->GetDef(tF2);\r
- tFactionB = GameDefs->Factions()->GetDef(tF1);\r
- }\r
-\r
- if(tFactionA && tFactionB)\r
- {\r
- int tRel = -99;\r
- if(tF1 > tF2)\r
- tRel = tFactionA->GetRelation(tF2);\r
- else\r
- tRel = tFactionA->GetRelation(tF1);\r
-\r
- char buff[150];\r
- snprintf(buff, 150, "Relation between <%s> and <%s> is: %d", tFactionA->GetName().c_str(), tFactionB->GetName().c_str(), tRel);\r
- Chat->send(source, CHAT_DIRECT, "Relations", buff);\r
- }\r
- else\r
- Chat->send(source, CHAT_DIRECT, "Relations", "Invalid faction");\r
- }\r
+ if (GetArgInt(1) == 1)
+ {
+ if(ArgC < 5)
+ return;
+
+ PNPC* targetNPC = NULL;
+ PNPCWorld* currentNPCWorld = NULL;
+ currentNPCWorld = NPCManager->GetWorld( source->GetChar()->GetLocation() );
+ if ( currentNPCWorld )
+ {
+ targetNPC = currentNPCWorld->GetNPC( GetArgInt(2) );
+ if(!targetNPC)
+ return;
+ // @test 15 <npcID> <target_to_attack> <unknown uint8_t value>
+ targetNPC->Attack(GetArgInt(3), (uint8_t)GetArgInt(5), (uint8_t)GetArgInt(4));
+ }
+ }
+ else if (GetArgInt(1) == 2)
+ {
+ if(ArgC < 3)
+ return;
+
+ int tF1 = GetArgInt(2);
+ int tF2 = GetArgInt(3);
+ const PDefFaction* tFactionA = NULL;
+ const PDefFaction* tFactionB = NULL;
+
+ if(tF1 > tF2)
+ {
+ tFactionA = GameDefs->Factions()->GetDef(tF1);
+ tFactionB = GameDefs->Factions()->GetDef(tF2);
+ }
+ else
+ {
+ tFactionA = GameDefs->Factions()->GetDef(tF2);
+ tFactionB = GameDefs->Factions()->GetDef(tF1);
+ }
+
+ if(tFactionA && tFactionB)
+ {
+ int tRel = -99;
+ if(tF1 > tF2)
+ tRel = tFactionA->GetRelation(tF2);
+ else
+ tRel = tFactionA->GetRelation(tF1);
+
+ char buff[150];
+ snprintf(buff, 150, "Relation between <%s> and <%s> is: %d", tFactionA->GetName().c_str(), tFactionB->GetName().c_str(), tRel);
+ Chat->send(source, CHAT_DIRECT, "Relations", buff);
+ }
+ else
+ Chat->send(source, CHAT_DIRECT, "Relations", "Invalid faction");
+ }
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdunban()\r
-{\r
- Chat->send(source, CHAT_DIRECT, "System", "Unban is not yet possible, sorry.");\r
-}\r
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdunban()
+{
+ Chat->send(source, CHAT_DIRECT, "System", "Unban is not yet possible, sorry.");
+}
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmdunshun()\r
-{\r
- bool SyntaxError = false;\r
- if(ArgC < 1)\r
- {\r
- SyntaxError = true;\r
- }\r
-\r
- if(SyntaxError == true)\r
- {\r
- Chat->send(source, CHAT_DIRECT, "Usage", "@shun <charID or nickname>");\r
- return;\r
- }\r
-\r
- if(IsArgNumeric(1) == true)\r
- {\r
- target = GetClientByID(GetArgInt(1));\r
- }\r
- else\r
- {\r
- char tmp_destNick[50];\r
- GetArgText(1, tmp_destNick, 50);\r
- target = GetClientByNick(tmp_destNick);\r
- }\r
-\r
- if(target == NULL) // If victim isnt found, return error\r
- {\r
- Chat->send(source, CHAT_DIRECT, "System", "No such player");\r
- return;\r
- }\r
- if(source->GetAccountLevel() <= target->GetAccountLevel())\r
- {\r
- char tmpMsg[200];\r
- snprintf(tmpMsg, 199, "Cant unshun %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());\r
- tmpMsg[199] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", tmpMsg);\r
- return;\r
- }\r
- if(target->GetChar()->IsShunned() == true)\r
- {\r
- target->GetChar()->SetShun(false);\r
-\r
- char tmpMsg_success[81];\r
- snprintf(tmpMsg_success, 80, "Successfully unshunned %s", target->GetChar()->GetName().c_str());\r
- tmpMsg_success[80] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success);\r
- return;\r
- }\r
- else\r
- {\r
- Chat->send(source, CHAT_DIRECT, "System", "Player is not shunned");\r
- return;\r
- }\r
-}\r
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmdunshun()
+{
+ bool SyntaxError = false;
+ if(ArgC < 1)
+ {
+ SyntaxError = true;
+ }
+
+ if(SyntaxError == true)
+ {
+ Chat->send(source, CHAT_DIRECT, "Usage", "@shun <charID or nickname>");
+ return;
+ }
+
+ if(IsArgNumeric(1) == true)
+ {
+ target = GetClientByID(GetArgInt(1));
+ }
+ else
+ {
+ char tmp_destNick[50];
+ GetArgText(1, tmp_destNick, 50);
+ target = GetClientByNick(tmp_destNick);
+ }
+
+ if(target == NULL) // If victim isnt found, return error
+ {
+ Chat->send(source, CHAT_DIRECT, "System", "No such player");
+ return;
+ }
+ if(source->GetAccountLevel() <= target->GetAccountLevel())
+ {
+ char tmpMsg[200];
+ snprintf(tmpMsg, 199, "Cant unshun %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str());
+ tmpMsg[199] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", tmpMsg);
+ return;
+ }
+ if(target->GetChar()->IsShunned() == true)
+ {
+ target->GetChar()->SetShun(false);
+
+ char tmpMsg_success[81];
+ snprintf(tmpMsg_success, 80, "Successfully unshunned %s", target->GetChar()->GetName().c_str());
+ tmpMsg_success[80] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success);
+ return;
+ }
+ else
+ {
+ Chat->send(source, CHAT_DIRECT, "System", "Player is not shunned");
+ return;
+ }
+}
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmduptime()\r
-{\r
- // get difference between var uptime and current time\r
- time_t Uptime = GameServer->GetStartTime();\r
- uint32_t TimeDiff = std::time(NULL) - Uptime;\r
- uint32_t UpYears = 0, UpMonths = 0, UpWeeks = 0, UpDays = 0, UpHours = 0, UpMinutes = 0, UpSeconds = 0;\r
- char tmpY[21], tmpM[21], tmpW[21], tmpD[21], tmpH[21], tmpMi[21], tmpS[21];\r
-\r
- // 1 min = 60 sec = 60\r
- // 1 hour = 60 * 60 sec = 3600\r
- // 1 day = 24 * 60 * 60 sec = 86400\r
- // 1 week = 7 * 24 * 60 * 60 sec = 604800\r
- // 1 month = 30 * 7 * 24 * 60 * 60 sec = 18144000\r
- // 1 year = 12 * 30 * 7 * 24 * 60 * 60 sec = 217728000\r
-\r
- // Split Years\r
- while(TimeDiff >= 217728000)\r
- {\r
- TimeDiff = TimeDiff - 217728000;\r
- UpYears++;\r
- }\r
-\r
- // Split Months\r
- while(TimeDiff >= 18144000)\r
- {\r
- TimeDiff = TimeDiff - 18144000;\r
- UpMonths++;\r
- }\r
-\r
- // Split Weeks\r
- while(TimeDiff >= 604800)\r
- {\r
- TimeDiff = TimeDiff - 604800;\r
- UpWeeks++;\r
- }\r
-\r
- // Split Days\r
- while(TimeDiff >= 86400)\r
- {\r
- TimeDiff = TimeDiff - 86400;\r
- UpDays++;\r
- }\r
-\r
- // Split Hours\r
- while(TimeDiff >= 3600)\r
- {\r
- TimeDiff = TimeDiff - 3600;\r
- UpHours++;\r
- }\r
-\r
- // Split Minutes\r
- while(TimeDiff >= 60)\r
- {\r
- TimeDiff = TimeDiff - 60;\r
- UpMinutes++;\r
- }\r
-\r
- // What's left are seconds\r
- UpSeconds = TimeDiff;\r
-\r
- // Now create output strings. Add 's' if > 1\r
- // Years\r
- if(UpYears > 1)\r
- snprintf(tmpY, 20, "%d years ", UpYears);\r
- else if(UpYears > 0)\r
- snprintf(tmpY, 20, "%d year ", UpYears);\r
- else\r
- tmpY[0] = '\0';\r
-\r
- // Months\r
- if(UpMonths > 1)\r
- snprintf(tmpM, 20, "%d months ", UpMonths);\r
- else if(UpMonths > 0)\r
- snprintf(tmpM, 20, "%d month ", UpMonths);\r
- else\r
- tmpM[0] = '\0';\r
-\r
- // Weeks\r
- if(UpWeeks > 1)\r
- snprintf(tmpW, 20, "%d weeks ", UpWeeks);\r
- else if(UpWeeks > 0)\r
- snprintf(tmpW, 20, "%d week ", UpWeeks);\r
- else\r
- tmpW[0] = '\0';\r
-\r
- // Days\r
- if(UpDays > 1)\r
- snprintf(tmpD, 20, "%d days ", UpDays);\r
- else if(UpDays > 0)\r
- snprintf(tmpD, 20, "%d day ", UpDays);\r
- else\r
- tmpD[0] = '\0';\r
-\r
- // Hours\r
- if(UpHours > 1)\r
- snprintf(tmpH, 20, "%d hours ", UpHours);\r
- else if(UpHours > 0)\r
- snprintf(tmpH, 20, "%d hour ", UpHours);\r
- else\r
- tmpH[0] = '\0';\r
-\r
- // Minutes\r
- if(UpMinutes > 1)\r
- snprintf(tmpMi, 20, "%d minutes and ", UpMinutes);\r
- else if(UpMinutes > 0)\r
- snprintf(tmpMi, 20, "%d minute and ", UpMinutes);\r
- else\r
- tmpMi[0] = '\0';\r
-\r
- // Seconds\r
- if(UpSeconds > 1 || UpSeconds == 0)\r
- snprintf(tmpS, 20, "%d seconds.", UpSeconds);\r
- else\r
- snprintf(tmpS, 20, "%d second.", UpSeconds);\r
-\r
- // Terminate all chars, just to be sure\r
- tmpY[20] = '\0';\r
- tmpM[20] = '\0';\r
- tmpW[20] = '\0';\r
- tmpD[20] = '\0';\r
- tmpH[20] = '\0';\r
- tmpMi[20] = '\0';\r
- tmpS[20] = '\0';\r
-\r
- //Copy the single msg's into one\r
- char tmpChatMsg[300];\r
- snprintf(tmpChatMsg, 299, "The server has been running for %s%s%s%s%s%s%s", tmpY, tmpM, tmpW, tmpD, tmpH, tmpMi, tmpS);\r
- tmpChatMsg[299] = '\0';\r
-\r
- // Send it out\r
- Chat->send(source, CHAT_DIRECT, "System", tmpChatMsg);\r
-}\r
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmduptime()
+{
+ // get difference between var uptime and current time
+ time_t Uptime = GameServer->GetStartTime();
+ uint32_t TimeDiff = std::time(NULL) - Uptime;
+ uint32_t UpYears = 0, UpMonths = 0, UpWeeks = 0, UpDays = 0, UpHours = 0, UpMinutes = 0, UpSeconds = 0;
+ char tmpY[21], tmpM[21], tmpW[21], tmpD[21], tmpH[21], tmpMi[21], tmpS[21];
+
+ // 1 min = 60 sec = 60
+ // 1 hour = 60 * 60 sec = 3600
+ // 1 day = 24 * 60 * 60 sec = 86400
+ // 1 week = 7 * 24 * 60 * 60 sec = 604800
+ // 1 month = 30 * 7 * 24 * 60 * 60 sec = 18144000
+ // 1 year = 12 * 30 * 7 * 24 * 60 * 60 sec = 217728000
+
+ // Split Years
+ while(TimeDiff >= 217728000)
+ {
+ TimeDiff = TimeDiff - 217728000;
+ UpYears++;
+ }
+
+ // Split Months
+ while(TimeDiff >= 18144000)
+ {
+ TimeDiff = TimeDiff - 18144000;
+ UpMonths++;
+ }
+
+ // Split Weeks
+ while(TimeDiff >= 604800)
+ {
+ TimeDiff = TimeDiff - 604800;
+ UpWeeks++;
+ }
+
+ // Split Days
+ while(TimeDiff >= 86400)
+ {
+ TimeDiff = TimeDiff - 86400;
+ UpDays++;
+ }
+
+ // Split Hours
+ while(TimeDiff >= 3600)
+ {
+ TimeDiff = TimeDiff - 3600;
+ UpHours++;
+ }
+
+ // Split Minutes
+ while(TimeDiff >= 60)
+ {
+ TimeDiff = TimeDiff - 60;
+ UpMinutes++;
+ }
+
+ // What's left are seconds
+ UpSeconds = TimeDiff;
+
+ // Now create output strings. Add 's' if > 1
+ // Years
+ if(UpYears > 1)
+ snprintf(tmpY, 20, "%d years ", UpYears);
+ else if(UpYears > 0)
+ snprintf(tmpY, 20, "%d year ", UpYears);
+ else
+ tmpY[0] = '\0';
+
+ // Months
+ if(UpMonths > 1)
+ snprintf(tmpM, 20, "%d months ", UpMonths);
+ else if(UpMonths > 0)
+ snprintf(tmpM, 20, "%d month ", UpMonths);
+ else
+ tmpM[0] = '\0';
+
+ // Weeks
+ if(UpWeeks > 1)
+ snprintf(tmpW, 20, "%d weeks ", UpWeeks);
+ else if(UpWeeks > 0)
+ snprintf(tmpW, 20, "%d week ", UpWeeks);
+ else
+ tmpW[0] = '\0';
+
+ // Days
+ if(UpDays > 1)
+ snprintf(tmpD, 20, "%d days ", UpDays);
+ else if(UpDays > 0)
+ snprintf(tmpD, 20, "%d day ", UpDays);
+ else
+ tmpD[0] = '\0';
+
+ // Hours
+ if(UpHours > 1)
+ snprintf(tmpH, 20, "%d hours ", UpHours);
+ else if(UpHours > 0)
+ snprintf(tmpH, 20, "%d hour ", UpHours);
+ else
+ tmpH[0] = '\0';
+
+ // Minutes
+ if(UpMinutes > 1)
+ snprintf(tmpMi, 20, "%d minutes and ", UpMinutes);
+ else if(UpMinutes > 0)
+ snprintf(tmpMi, 20, "%d minute and ", UpMinutes);
+ else
+ tmpMi[0] = '\0';
+
+ // Seconds
+ if(UpSeconds > 1 || UpSeconds == 0)
+ snprintf(tmpS, 20, "%d seconds.", UpSeconds);
+ else
+ snprintf(tmpS, 20, "%d second.", UpSeconds);
+
+ // Terminate all chars, just to be sure
+ tmpY[20] = '\0';
+ tmpM[20] = '\0';
+ tmpW[20] = '\0';
+ tmpD[20] = '\0';
+ tmpH[20] = '\0';
+ tmpMi[20] = '\0';
+ tmpS[20] = '\0';
+
+ //Copy the single msg's into one
+ char tmpChatMsg[300];
+ snprintf(tmpChatMsg, 299, "The server has been running for %s%s%s%s%s%s%s", tmpY, tmpM, tmpW, tmpD, tmpH, tmpMi, tmpS);
+ tmpChatMsg[299] = '\0';
+
+ // Send it out
+ Chat->send(source, CHAT_DIRECT, "System", tmpChatMsg);
+}
-#include "GameServer/Includes.hxx"\r
-\r
-void PCommands::doCmd_dev_v()\r
-{\r
- if(IsAdmin() == false)\r
- return;\r
-\r
- char Arg1[30];\r
-\r
- Arg1[0] = '\0';\r
-\r
- if(ArgC > 0)\r
- {\r
- GetArgText(1, Arg1, 30);\r
- }\r
-\r
- char tmpStr[128];\r
- int testmode = 1; // change here only for uint8_t/uint16_t/uint32_t testvalue use\r
-\r
- if(Arg1[0] != '\0')\r
- {\r
- switch(testmode)\r
- {\r
- case 0: source->testval8 = (uint8_t)(atoi(Arg1) & 0xff); break;\r
- case 1: source->testval16 = (uint16_t)(atoi(Arg1) & 0xffff); break;\r
- case 2: source->testval32 = (uint32_t)(atoi(Arg1) & 0xffffffff); break;\r
- }\r
- }\r
- else\r
- {\r
- source->testval8 = 0;\r
- source->testval16 = 0;\r
- source->testval32 = 0;\r
- }\r
-\r
- switch(testmode)\r
- {\r
- case 0: snprintf(tmpStr, 127, "Test value uint8_t set to 0x%02x (%d)", source->testval8, source->testval8); break;\r
- case 1: snprintf(tmpStr, 127, "Test value uint16_t set to 0x%04x (%d)", source->testval16, source->testval16); break;\r
- case 2: snprintf(tmpStr, 127, "Test value uint32_t set to 0x%08x (%d)", source->testval32, source->testval32); break;\r
- default: tmpStr[0] = '\0';\r
- }\r
- tmpStr[127] = '\0';\r
- Chat->send(source, CHAT_DIRECT, "System", tmpStr);\r
-\r
-}\r
+#include "GameServer/Includes.hxx"
+
+void PCommands::doCmd_dev_v()
+{
+ if(IsAdmin() == false)
+ return;
+
+ char Arg1[30];
+
+ Arg1[0] = '\0';
+
+ if(ArgC > 0)
+ {
+ GetArgText(1, Arg1, 30);
+ }
+
+ char tmpStr[128];
+ int testmode = 1; // change here only for uint8_t/uint16_t/uint32_t testvalue use
+
+ if(Arg1[0] != '\0')
+ {
+ switch(testmode)
+ {
+ case 0: source->testval8 = (uint8_t)(atoi(Arg1) & 0xff); break;
+ case 1: source->testval16 = (uint16_t)(atoi(Arg1) & 0xffff); break;
+ case 2: source->testval32 = (uint32_t)(atoi(Arg1) & 0xffffffff); break;
+ }
+ }
+ else
+ {
+ source->testval8 = 0;
+ source->testval16 = 0;
+ source->testval32 = 0;
+ }
+
+ switch(testmode)
+ {
+ case 0: snprintf(tmpStr, 127, "Test value uint8_t set to 0x%02x (%d)", source->testval8, source->testval8); break;
+ case 1: snprintf(tmpStr, 127, "Test value uint16_t set to 0x%04x (%d)", source->testval16, source->testval16); break;
+ case 2: snprintf(tmpStr, 127, "Test value uint32_t set to 0x%08x (%d)", source->testval32, source->testval32); break;
+ default: tmpStr[0] = '\0';
+ }
+ tmpStr[127] = '\0';
+ Chat->send(source, CHAT_DIRECT, "System", tmpStr);
+
+}
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-void PCommands::doCmdversion()\r
-{\r
- char tmpChatMsg[300];\r
- snprintf(tmpChatMsg, 299, "You are on TinNS server %s runnig version %s - SVN Rev. %s", Config->GetOption("server_name").c_str(), ServerVersion, SVNRevision);\r
- tmpChatMsg[299] = '\0';\r
-\r
- Chat->send(source, CHAT_DIRECT, "System", tmpChatMsg);\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+void PCommands::doCmdversion()
+{
+ char tmpChatMsg[300];
+ snprintf(tmpChatMsg, 299, "You are on TinNS server %s runnig version %s - SVN Rev. %s", Config->GetOption("server_name").c_str(), ServerVersion, SVNRevision);
+ tmpChatMsg[299] = '\0';
+
+ Chat->send(source, CHAT_DIRECT, "System", tmpChatMsg);
+}
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-#if 0\r
-PGameScript::PGameScript()\r
-{\r
-}\r
-\r
-PGameScript::~PGameScript()\r
-{\r
- for(HookMap::iterator it = mHooks.begin(); it != mHooks.end(); it++)\r
- delete it->second;\r
-}\r
-\r
-bool PGameScript::LoadScripts()\r
-{\r
-}\r
-\r
-bool PGameScript::Rehash()\r
-{\r
- Console->LPrint("Rehashing GameMonkey Scripts...");\r
- for(HookMap::iterator it = mHooks.end(); it != mHooks.begin(); it--)\r
- mHooks.erase(it);\r
-\r
- if(LoadScripts() == true)\r
- {\r
- Console->LPrint(GREEN, BLACK, "Done");\r
- Console->LClose();\r
- return true;\r
- }\r
- else\r
- {\r
- Console->LPrint(RED, BLACK, "Failed");\r
- Console->LClose();\r
- return false;\r
- }\r
-}\r
-\r
-void PGameScript::TriggerHook(PHookTypes hook)\r
-{\r
-}\r
-\r
-\r
-bool PGameScript::ExecuteFile(const char* a_fileName)\r
-{\r
- FILE* scriptFile = NULL;\r
- char* fileString = NULL;\r
- int fileSize = 0;\r
-\r
- GM_ASSERT(m_machine);\r
-\r
- if( !(scriptFile = fopen(a_fileName, "rb")) )\r
- {\r
- return false;\r
- }\r
-\r
- fseek(scriptFile, 0, SEEK_END);\r
- fileSize = ftell(scriptFile);\r
- fseek(scriptFile, 0, SEEK_SET);\r
- fileString = new char [fileSize+1];\r
- fread(fileString, fileSize, 1, scriptFile);\r
- fileString[fileSize] = 0; // Terminating null\r
- fclose(scriptFile);\r
-\r
- int threadId = GM_INVALID_THREAD;\r
- int errors = m_machine->ExecuteString(fileString, &threadId, true, a_fileName);\r
- if(errors)\r
- {\r
- LogAnyMachineErrorMessages();\r
- }\r
-\r
- delete [] fileString;\r
-\r
- return true;\r
-}\r
-\r
-\r
-int GM_CDECL PGameScript::AddHook(gmThread *a_thread)\r
-{\r
- GM_CHECK_NUM_PARAMS(2);\r
- GM_CHECK_STRING_PARAM(tmphooktype, 0);\r
- GM_CHECK_STRING_PARAM(tmpfunction, 1);\r
-\r
- mHooks.insert(std::make_pair(tmphooktype, tmpfunction));\r
-\r
- return GM_OK;\r
-}\r
-\r
-int PGameScript::AddTwoIntegers(int valueA, int valueB)\r
-{\r
- int resultInt = 0;\r
-\r
- gmCall call;\r
-\r
- if(call.BeginGlobalFunction(&machine, "Add"))\r
- {\r
- call.AddParamInt(valueA);\r
- call.AddParamInt(valueB);\r
- call.End();\r
- call.GetReturnedInt(resultInt);\r
- }\r
-\r
- return resultInt;\r
-}\r
-#endif\r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+#if 0
+PGameScript::PGameScript()
+{
+}
+
+PGameScript::~PGameScript()
+{
+ for(HookMap::iterator it = mHooks.begin(); it != mHooks.end(); it++)
+ delete it->second;
+}
+
+bool PGameScript::LoadScripts()
+{
+}
+
+bool PGameScript::Rehash()
+{
+ Console->LPrint("Rehashing GameMonkey Scripts...");
+ for(HookMap::iterator it = mHooks.end(); it != mHooks.begin(); it--)
+ mHooks.erase(it);
+
+ if(LoadScripts() == true)
+ {
+ Console->LPrint(GREEN, BLACK, "Done");
+ Console->LClose();
+ return true;
+ }
+ else
+ {
+ Console->LPrint(RED, BLACK, "Failed");
+ Console->LClose();
+ return false;
+ }
+}
+
+void PGameScript::TriggerHook(PHookTypes hook)
+{
+}
+
+
+bool PGameScript::ExecuteFile(const char* a_fileName)
+{
+ FILE* scriptFile = NULL;
+ char* fileString = NULL;
+ int fileSize = 0;
+
+ GM_ASSERT(m_machine);
+
+ if( !(scriptFile = fopen(a_fileName, "rb")) )
+ {
+ return false;
+ }
+
+ fseek(scriptFile, 0, SEEK_END);
+ fileSize = ftell(scriptFile);
+ fseek(scriptFile, 0, SEEK_SET);
+ fileString = new char [fileSize+1];
+ fread(fileString, fileSize, 1, scriptFile);
+ fileString[fileSize] = 0; // Terminating null
+ fclose(scriptFile);
+
+ int threadId = GM_INVALID_THREAD;
+ int errors = m_machine->ExecuteString(fileString, &threadId, true, a_fileName);
+ if(errors)
+ {
+ LogAnyMachineErrorMessages();
+ }
+
+ delete [] fileString;
+
+ return true;
+}
+
+
+int GM_CDECL PGameScript::AddHook(gmThread *a_thread)
+{
+ GM_CHECK_NUM_PARAMS(2);
+ GM_CHECK_STRING_PARAM(tmphooktype, 0);
+ GM_CHECK_STRING_PARAM(tmpfunction, 1);
+
+ mHooks.insert(std::make_pair(tmphooktype, tmpfunction));
+
+ return GM_OK;
+}
+
+int PGameScript::AddTwoIntegers(int valueA, int valueB)
+{
+ int resultInt = 0;
+
+ gmCall call;
+
+ if(call.BeginGlobalFunction(&machine, "Add"))
+ {
+ call.AddParamInt(valueA);
+ call.AddParamInt(valueB);
+ call.End();
+ call.GetReturnedInt(resultInt);
+ }
+
+ return resultInt;
+}
+#endif
-#pragma once\r
-\r
-#if 0\r
-#include <map>\r
-#include <string>\r
-\r
-enum PHookTypes {\r
- HOOK_CHAT,\r
- HOOK_TRADE,\r
- HOOK_ZONE\r
-};\r
-\r
-class PGameScript {\r
-private:\r
- typedef std::map<PHookTypes, std::string> HookMap;\r
- HookMap mHooks;\r
-\r
-public:\r
- PGameScript();\r
- ~PGameScript();\r
-\r
- bool LoadScripts();\r
- bool Rehash();\r
- void TriggerHook(PHookTypes hook);\r
- bool ExecuteFile(const char* a_fileName);\r
-};\r
-#endif\r
+#pragma once
+
+#if 0
+#include <map>
+#include <string>
+
+enum PHookTypes {
+ HOOK_CHAT,
+ HOOK_TRADE,
+ HOOK_ZONE
+};
+
+class PGameScript {
+private:
+ typedef std::map<PHookTypes, std::string> HookMap;
+ HookMap mHooks;
+
+public:
+ PGameScript();
+ ~PGameScript();
+
+ bool LoadScripts();
+ bool Rehash();
+ void TriggerHook(PHookTypes hook);
+ bool ExecuteFile(const char* a_fileName);
+};
+#endif
-#include <cstring>\r
-#include "GameServer/Includes.hxx"\r
-#include "GameServer/Decoder/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-// TODO:\r
-// - Deny login if char is already online (More information about the login procedure is necessary to do that)\r
-// - Take main loop timeout setting from config file\r
-// - Add Regex control to new char name validation\r
-// - Add Check of Char offline (and unloaded) before deleting (from the char choosing i/f) if multiple login\r
-// allowed for the same account\r
-// - Check if adding to Client to Client manager shouldn't be done only one UDP connection done ?\r
-// => Risk of sending UDP chat on non-socket ????\r
-\r
-PGameServer::PGameServer()\r
-{\r
- mServerStartupTime = std::time( NULL );\r
- mNumClients = 0;\r
- MsgDecoder = new PUdpMsgDecoder();\r
-}\r
-\r
-PGameServer::~PGameServer()\r
-{\r
- ServerSock->closeServer();\r
- delete MsgDecoder;\r
-}\r
-\r
-void PGameServer::Start()\r
-{\r
- uint16_t Port = Config->GetOptionInt( "gameserver_port" );\r
- Console->LPrint( "Starting gameserver on port %i...", Port );\r
-\r
- if ( ServerSock->open( Port ) )\r
- {\r
- Console->LPrint( GREEN, BLACK, "Success" );\r
- }\r
- else\r
- {\r
- Console->LPrint( RED, BLACK, "Failed" );\r
- }\r
- Console->LClose();\r
- ServerSock->settimeout( 0, 10000 );\r
-\r
- SetGameTime(( 1000 / 10 )*3600*12 ); //Set initial time to 12:00 on 7 Jul 2789\r
-\r
- // Init random generator\r
- struct timespec tmpTime;\r
- if ( !clock_gettime( CLOCK_REALTIME, &tmpTime ) )\r
- {\r
- srandom(( uint32_t )tmpTime.tv_sec );\r
- InitRandom( tmpTime.tv_sec );\r
-//Console->Print("Initializing random generator. First value is %d", random());\r
- }\r
-\r
- if ( Config->GetOptionInt( "gameserver_udpport_max" ) - Config->GetOptionInt( "gameserver_udpport_min" ) + 1 < Config->GetOptionInt( "maxclients" ) )\r
- {\r
- Console->Print( "%s UDP port range setting doesn't allow for the simultaneous max clients set in config", Console->ColorText( YELLOW, BLACK, "[Warning]" ) );\r
- }\r
-\r
-}\r
-\r
-void PGameServer::SetGameTime( uint32_t newtime )\r
-{\r
- if ( clock_gettime( CLOCK_REALTIME, &mStartTime ) )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Clock unavailable !!!" );\r
- perror( "clock_gettime CLOCK_REALTIME" );\r
- mStartTime.tv_sec = 0;\r
- mStartTime.tv_nsec = 0;\r
- }\r
- mBaseGameTime = newtime;\r
-}\r
-\r
-uint32_t PGameServer::GetGameTime()\r
-{\r
- //const uint32_t TimeFactor = 375;\r
- const uint32_t TimeFactor = 1000;\r
- const uint32_t nsTimeFactor = 1000000000 / TimeFactor;\r
-\r
- struct timespec tmpTime;\r
-\r
- if ( mStartTime.tv_sec )\r
- {\r
- clock_gettime( CLOCK_REALTIME, &tmpTime );\r
- return ( mBaseGameTime + (( tmpTime.tv_sec - mStartTime.tv_sec ) * TimeFactor ) + ( tmpTime.tv_nsec / nsTimeFactor ) - ( mStartTime.tv_nsec / nsTimeFactor ) );\r
- }\r
- else\r
- return 0;\r
-}\r
-\r
-void PGameServer::Update()\r
-{\r
- if ( ServerSock->newConnection() )\r
- {\r
- int clid = Server->NewClient();\r
- if ( clid != -1 )\r
- {\r
- Console->Print( GREEN, BLACK, "[Info] Gameserver: client [%i] connected", clid );\r
- PClient *Client = Server->GetClient( clid );\r
- if ( Client->getTCPConn() ) Console->Print( RED, BLACK, "WARNING: Client %d : TCP Socket NOT NULL before allocation.", Client->GetID() );\r
- ConnectionTCP* tcpConn = ServerSock->getTCPConnection();\r
- Client->setTCPConnection( tcpConn );\r
-\r
- //ConnectionUDP* udpConn = ServerSock->getUDPConnection();\r
- //Client->setUDPConnection(udpConn);\r
-\r
- Console->Print( "Client address: %s", Client->GetAddress() );\r
- ++mNumClients;\r
-\r
- PGameState *state = new PGameState();\r
- ClientStates.insert( std::make_pair( Client, state ) );\r
- state->TCP.mState = PGameState::TCP::GS_CONNECTED;\r
-\r
- // add the new connected client to the global clientmanager for further use in chat, etc...\r
- ClientManager->addClientToList( Client );\r
- }\r
- else\r
- {\r
- Console->Print( YELLOW, BLACK, "[Notice] Gameserver: Client connection refused (server full?)" );\r
- }\r
- }\r
-\r
- /*** temp check ***/\r
- for ( PClientMap::iterator it = ClientManager->getClientListBegin(); it != ClientManager->getClientListEnd(); it++ )\r
- {\r
- if ( !it->second )\r
- {\r
- Console->Print( RED, BLACK, "PANIC: NULL Client found in ClientManager Clients Map." );\r
- }\r
- }\r
- /*** end temp check ***/\r
-\r
- for ( GameStateMap::iterator i = ClientStates.begin(); i != ClientStates.end(); )\r
- {\r
- PClient *Client = i->first;\r
- PGameState *State = i->second;\r
- // node gets erased in FinalizeClient, increment iterator now\r
- ++i;\r
- if ( !ProcessClient( Client, State ) )\r
- FinalizeClient( Client, State );\r
- }\r
-}\r
-\r
-bool PGameServer::HandleHandshake( PGameState *State, const uint8_t *Packet, int PacketSize )\r
-{\r
- //static const uint8_t HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x68};\r
- //PGameSocket *Socket = Client->GetGameSocket();\r
-\r
- switch ( State->TCP.mState )\r
- {\r
- case PGameState::TCP::GS_HANDSHAKE0 :\r
- {\r
- if ( PacketSize == 6 && *( uint16_t* )&Packet[3] == 0x0080 && Packet[5] == 0x78 )\r
- {\r
- //FIXME: this packet seems to be unnecessary,\r
- // although it appears in traffic dumps\r
- // (causes clientside "Wrong protocol" errors)\r
-\r
- //Socket->Write(HANDSHAKE1A, 6);\r
- State->TCP.mState = PGameState::TCP::GS_AUTHENTICATE;\r
- }\r
- else\r
- {\r
- Console->Print( YELLOW, BLACK, "[Notice] Gameserver protocol error (GS_HANDSHAKE0): invalid packet [%04x]", *( uint16_t* )&Packet[3] );\r
- return ( false );\r
- }\r
-\r
- break;\r
- }\r
- default:\r
- {\r
- break;\r
- }\r
- }\r
-\r
- return true;\r
-}\r
-\r
-bool PGameServer::HandleAuthenticate( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize )\r
-{\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
-\r
- if ( PacketSize > 20 && *( uint16_t* )&Packet[3] == 0x8084 )\r
- {\r
- // authentication method #1\r
- const uint8_t *Key = &Packet[5]; // password key\r
- uint16_t ULen = *( uint16_t* ) & Packet[16]; // username length\r
- uint16_t PLen = *( uint16_t* ) & Packet[18]; // password length\r
- char *UserName = ( char* ) & Packet[20]; // account name\r
- const uint8_t *PW = &Packet[20+ULen]; // encoded password\r
-\r
- // Safety controls\r
- if ( 15 + ULen + PLen > PacketSize )\r
- {\r
- Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" );\r
- return false;\r
- }\r
- if ( strnlen( UserName, ULen ) == ULen )\r
- {\r
- Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" );\r
- return false;\r
- }\r
-\r
- bool Failed = false;\r
-\r
- PAccount Account( UserName );\r
- if ( Account.GetID() == 0 )\r
- {\r
- Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName );\r
- Failed = true;\r
- }\r
- else if ( !Account.Authenticate( PW, PLen, Key ) )\r
- {\r
- Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName );\r
- Failed = true;\r
- }\r
-\r
- if ( !Failed )\r
- {\r
- Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' authentication successful", UserName );\r
- if ( Account.GetLevel() == PAL_BANNED )\r
- {\r
- Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName );\r
- // TODO: ban ip for an adjustable time span?\r
- Failed = true; // player is banned\r
- }\r
-\r
- if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER )\r
- {\r
- if ( Server->GetNumClients() > Server->GetMaxClients() )\r
- {\r
- Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from user '%s'", UserName );\r
- Failed = true; // server full\r
- }\r
- }\r
- }\r
-\r
- if ( Failed )\r
- {\r
- // TODO: is this packet correct here?\r
- uint8_t AUTHFAILED[15] = {0xfe, 0x0c, 0x00, 0x83, 0x86, 0x05, 0x00, 0x06, 0x00, 'E', 'R',\r
- 'R', 'O', 'R', 0\r
- };\r
- // TODO: send actual reason instead of ERROR\r
- Socket->write( AUTHFAILED, 15 );\r
- FinalizeClientDelayed( Client, State );\r
- State->TCP.mState = PGameState::TCP::GS_UNKNOWN;\r
- Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s' login refused", UserName );\r
- }\r
- else\r
- {\r
- Client->LoggedIn( &Account );\r
- uint8_t AUTHOK[28] = {0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,\r
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r
- };\r
- *( uint32_t* )&AUTHOK[5] = Account.GetID();\r
- Socket->write( AUTHOK, 28 );\r
- State->TCP.mState = PGameState::TCP::GS_GAMEDATA;\r
- Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' logged in", UserName );\r
- }\r
- }\r
- else if ( PacketSize > 29 && *( uint16_t* )&Packet[3] == 0x0183 )\r
- {\r
- // authentication method #2, sent when game starts\r
- const uint8_t *Key = &Packet[13]; // password key\r
- uint16_t PLen = *( uint16_t* ) & Packet[25]; // password length\r
- uint16_t ULen = *( uint16_t* ) & Packet[27]; // username length\r
- char *UserName = ( char* ) & Packet[29]; // account name\r
- const uint8_t *PW = &Packet[29+ULen]; // encoded password\r
-\r
- // Safety controls\r
- if ( 24 + ULen + PLen > PacketSize )\r
- {\r
- Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" );\r
- return false;\r
- }\r
- if ( strnlen( UserName, ULen ) == ULen )\r
- {\r
- Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" );\r
- return false;\r
- }\r
-\r
- bool Failed = false;\r
-\r
- PAccount Account( UserName );\r
- if ( Account.GetID() == 0 )\r
- {\r
- Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName );\r
- Failed = true;\r
- }\r
- else if ( !Account.Authenticate( PW, PLen, Key ) )\r
- {\r
- Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName );\r
- Failed = true;\r
- }\r
-\r
- if ( !Failed )\r
- {\r
- if ( Account.GetLevel() == PAL_BANNED )\r
- {\r
- Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName );\r
- // TODO: ban ip for an adjustable time span?\r
- Failed = true; // player is banned\r
- }\r
-\r
- if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER )\r
- {\r
- if ( Server->GetNumClients() > ( Server->GetMaxClients() - Server->GetGMSlots() ) )\r
- {\r
- Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from regular user '%s'", UserName );\r
- Failed = true; // server full for non-GM users\r
- }\r
- }\r
- else if ( Config->GetOptionInt( "require_validation" ) == 1 && Account.GetLevel() == PAL_UNREGPLAYER )\r
- {\r
- Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', account not activated yet", UserName );\r
- Failed = true;\r
- }\r
- else if ( Config->GetOptionInt( "minlevel" ) > Account.GetLevel() )\r
- {\r
- Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', insufficient level %d vs %d required", UserName, Account.GetLevel(), Config->GetOptionInt( "minlevel" ) );\r
- Failed = true;\r
- }\r
- else if ( Server->GetNumClients() > Server->GetMaxClients() )\r
- {\r
- Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from privileged user '%s'", UserName );\r
- Failed = true; // server full even for GM users\r
- }\r
- }\r
-\r
-\r
- if ( !Failed )\r
- {\r
- int value = *( uint32_t* ) & Packet[21];//i think here we must read uint32_t instead of uint8_t\r
- uint32_t CharID = Account.GetCharIdBySlot( value );\r
-\r
- if ( Chars->LoadChar( CharID ) )\r
- {\r
- Client->SetCharID( CharID );\r
- }\r
- else\r
- {\r
- Failed = true;\r
- }\r
- }\r
-\r
- if ( Failed ) // something strange happened\r
- FinalizeClientDelayed( Client, State );\r
- else\r
- {\r
- Client->LoggedIn( &Account );\r
- /*uint8_t AUTHOK[28]={0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,\r
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\r
- *(uint32_t*)&AUTHOK[5]=Account->GetID();\r
- Socket->Write(AUTHOK, 28);*/\r
- //Client->SetRemoteUDPAddr(*(uint32_t*)&Packet[5], *(uint16_t*)&Packet[9]);\r
- State->TCP.mState = PGameState::TCP::GS_GETSTATUS;\r
- Console->Print( "Gameserver: User '%s' entered game (%08x:%04x)", UserName, *( uint32_t* )&Packet[5], *( uint16_t* )&Packet[9] );\r
- Client->SetRemoteUDPPort( *( int* )&Packet[9] );\r
- }\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): invalid packet [%04x]", *( uint16_t* )&Packet[3] );\r
- return ( false );\r
- }\r
-\r
- return ( true );\r
-}\r
-\r
-bool PGameServer::HandleGameData( PClient *Client, PGameState *State, const uint8_t *Packet )\r
-{\r
- static const uint8_t GAMEDATA[5] = {0xfe, 0x02, 0x00, 0x87, 0x3a};\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
-\r
- if ( *( uint16_t* )&Packet[3] == 0x3787 )\r
- {\r
- Socket->write( GAMEDATA, 5 );\r
- State->TCP.mState = PGameState::TCP::GS_REQUESTCHARS;\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEDATA): invalid packet [%04x]", *( uint16_t* )&Packet[3] );\r
- return ( false );\r
- }\r
-\r
- return ( true );\r
-}\r
-\r
-bool PGameServer::HandleRequestChars( PClient *Client, PGameState *State, const uint8_t *Packet )\r
-{\r
- PAccount Account( Client->GetAccountID() );\r
-\r
- if ( !Account.GetID() )\r
- return false;\r
-\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
-\r
- struct PCharList\r
- {\r
- uint16_t Unknown1;\r
- uint16_t NumSlots;\r
- uint16_t Unknown2;\r
- } CharList;\r
-\r
- PCharProfile CharEntry[MAX_CHARS_PER_ACCOUNT];\r
-\r
- const int CHARBASESIZE = 28;\r
-\r
- if ( *( uint16_t* )&Packet[3] == 0x8284 )\r
- {\r
- CharList.NumSlots = MAX_CHARS_PER_ACCOUNT;\r
- int NameLengths = 0;\r
-\r
- for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ )\r
- {\r
- CharEntry[i].CharID = 0;\r
- CharEntry[i].Type = 0;\r
- CharEntry[i].Color0 = 0;\r
- CharEntry[i].Location = 1;\r
- CharEntry[i].Unknown1 = 0;\r
- CharEntry[i].Head = 0;\r
- CharEntry[i].Torso = 0;\r
- CharEntry[i].Legs = 0;\r
- CharEntry[i].Unknown3 = 1;\r
- CharEntry[i].Unknown4 = 1;\r
- CharEntry[i].Unknown5 = 1;\r
- CharEntry[i].Unknown6 = 1;\r
- CharEntry[i].Unknown7 = 1;\r
- CharEntry[i].Unknown8 = 0;\r
- CharEntry[i].Unknown9 = 0;\r
- CharEntry[i].Unknown10 = 0;\r
- CharEntry[i].Unknown11 = 0;\r
- CharEntry[i].Unknown12 = 0;\r
-\r
- CharEntry[i].in_use = false;\r
- }\r
-\r
- Chars->GetCharProfiles( Account.GetID(), CharEntry, MAX_CHARS_PER_ACCOUNT );\r
-\r
- for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ )\r
- {\r
- if ( CharEntry[i].in_use )\r
- {\r
- NameLengths += CharEntry[i].NameLen;\r
- }\r
- else\r
- {\r
- CharEntry[i].CharID = 0xffffffff;\r
- CharEntry[i].NameLen = 0;\r
- }\r
- }\r
-\r
- uint8_t PacketHeader[5] = {0xfe, 0x00, 0x00, 0x83, 0x85};\r
- *( uint16_t* )&PacketHeader[1] = sizeof( uint16_t ) * 3 + ( MAX_CHARS_PER_ACCOUNT * CHARBASESIZE ) + NameLengths + 2;\r
- Socket->write( PacketHeader, 5 );\r
-\r
- CharList.Unknown1 = 0x0000;\r
- CharList.Unknown2 = CHARBASESIZE;\r
- Socket->write( CharList.Unknown1 );\r
- Socket->write( CharList.NumSlots );\r
- Socket->write( CharList.Unknown2 );\r
-\r
- for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ )\r
- {\r
- Socket->write( CharEntry[i].CharID );\r
- Socket->write( CharEntry[i].Type );\r
- Socket->write( CharEntry[i].Color0 );\r
- Socket->write( CharEntry[i].Unknown1 );\r
- Socket->write( CharEntry[i].Head );\r
- Socket->write( CharEntry[i].Torso );\r
- Socket->write( CharEntry[i].Legs );\r
- Socket->write( CharEntry[i].Location );\r
- Socket->write( CharEntry[i].NameLen );\r
- Socket->write( CharEntry[i].Unknown3 );\r
- Socket->write( CharEntry[i].Unknown4 );\r
- Socket->write( CharEntry[i].Unknown5 );\r
- Socket->write( CharEntry[i].Unknown6 );\r
- Socket->write( CharEntry[i].Unknown7 );\r
- Socket->write( CharEntry[i].Unknown8 );\r
- Socket->write( CharEntry[i].Unknown9 );\r
- Socket->write( CharEntry[i].Unknown10 );\r
- Socket->write( CharEntry[i].Unknown11 );\r
- Socket->write( CharEntry[i].Unknown12 );\r
-\r
- if ( CharEntry[i].Name.length() > 0 )\r
- {\r
- Socket->write( CharEntry[i].Name.c_str() );\r
- Socket->write(( uint8_t )0 );\r
- }\r
- }\r
-\r
- State->TCP.mState = PGameState::TCP::GS_CHARLIST;\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "Gameserver protocol error (GS_REQUESTCHARS): invalid packet [%04x]", *( uint16_t* )&Packet[3] );\r
- return ( false );\r
- }\r
-\r
- return ( true );\r
-}\r
-\r
-bool PGameServer::HandleCharList( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize )\r
-{\r
- static uint8_t Answer[10] = {0xfe, 0x07, 0x00, 0x83, 0x86, 0, 0, 0, 0, 0};\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
-\r
- if ( PacketSize > 9 && *( uint16_t* )&Packet[3] == 0x8284 )\r
- {\r
- uint8_t Mode = Packet[9];\r
-\r
- switch ( Mode )\r
- {\r
- case 6: // request list\r
- return ( HandleRequestChars( Client, State, Packet ) );\r
-\r
- case 5: // validate name\r
- {\r
- if ( PacketSize < 31 )\r
- return ( false );\r
-\r
- // check for valid name string\r
- bool ValidString = false;\r
-\r
- for ( int i = 30; i < PacketSize; i++ )\r
- if ( Packet[i] == 0 )\r
- {\r
- ValidString = true;\r
- break;\r
- }\r
-\r
- const char *Name = ( char* ) & Packet[30];\r
- if ( ValidString )\r
- {\r
- ValidString = PChar::IsCharnameWellFormed( Name );\r
- }\r
-\r
- if ( ValidString )\r
- {\r
- if ( Chars->CharExist( std::string( Name ) ) )\r
- {\r
- ValidString = false;\r
- }\r
- }\r
-\r
- if ( ValidString )\r
- Answer[5] = 1; // ok\r
- else\r
- Answer[5] = 2; // 2..6 => 'char name already in use!'\r
-\r
- // Answer[5] = 0; // => 'unknown error'\r
- Socket->write( Answer, 10 );\r
- return ( true );\r
- }\r
-\r
- case 3: // delete char\r
- {\r
- PAccount Acc( Client->GetAccountID() );\r
- uint8_t Num = Packet[PacketSize-1];\r
-\r
- if ( Acc.GetID() )\r
- {\r
- uint32_t CharID = Acc.GetCharIdBySlot( Num );\r
-\r
- // Also check that char is out of game\r
- if (( CharID != 0 ) && ( Chars->GetChar( CharID ) == NULL ) )\r
- {\r
- char query[100];\r
- snprintf( query, 100, "DELETE FROM characters WHERE c_id = %d LIMIT 1", CharID );\r
- if ( MySQL->GameQuery( query ) )\r
- Console->Print( RED, BLACK, "[Notice] Char %d not deleted!", CharID );\r
- else\r
- {\r
- Console->Print( GREEN, BLACK, "[Info] Char %d deleted!", CharID );\r
-\r
- snprintf( query, 100, "DELETE FROM buddy_list WHERE bud_charid = %d", CharID );\r
- if ( MySQL->GameQuery( query ) )\r
- Console->Print( YELLOW, BLACK, "[Notice] Char %d's buddy list not removed!", CharID );\r
-\r
- snprintf( query, 100, "DELETE FROM genrep WHERE g_charid = %d", CharID );\r
- if ( MySQL->GameQuery( query ) )\r
- Console->Print( YELLOW, BLACK, "[Notice] Char %d's genrep list not removed!", CharID );\r
-\r
- snprintf( query, 100, "DELETE FROM inventory WHERE inv_charid = %d", CharID );\r
- if ( MySQL->GameQuery( query ) )\r
- Console->Print( YELLOW, BLACK, "[Notice] Char %d's inventory not removed!", CharID );\r
-\r
- Appartements->DeleteCharAppartements( CharID );\r
- }\r
- }\r
- else\r
- return false;\r
- }\r
- return ( true );\r
- }\r
-\r
- case 7: // create char\r
- {\r
- if ( PacketSize < 64 )\r
- return ( false );\r
-\r
- uint32_t Slot = * ( uint32_t* ) & Packet[30];\r
- //uint32_t nClass =* (uint32_t*)&Packet[34]; // Not used - indirectly redundant with Profession\r
- uint32_t Profession = * ( uint32_t* ) & Packet[38];\r
- uint32_t Gender = * ( uint32_t* ) & Packet[42];\r
- uint32_t Head = * ( uint32_t* ) & Packet[46];\r
- uint32_t Torso = * ( uint32_t* ) & Packet[50];\r
- uint32_t Legs = * ( uint32_t* ) & Packet[54];\r
- uint32_t Faction = * ( uint32_t* ) & Packet[58];\r
- uint8_t NameLen = Packet[62];\r
- uint8_t NZSNb = Packet[63];\r
-\r
- char TempName[256];\r
- std::strncpy( TempName, ( const char* )&Packet[64], NameLen );\r
- TempName[NameLen] = 0;\r
-\r
- Answer[5] = 2; // return error if char creation fails\r
-\r
- if ( PChar::IsCharnameWellFormed( TempName ) )\r
- {\r
- // check for already used char name - should not happen though\r
- if ( ! Chars->CharExist( std::string( TempName ) ) )\r
- {\r
- PAccount Acc( Client->GetAccountID() );\r
- PChar* nChar = new PChar();\r
-\r
- if ( nChar->CreateNewChar( Acc.GetID(), TempName, Gender, Profession, Faction,\r
- Head, Torso, Legs, NZSNb, ( const char* )&Packet[64+NameLen], Slot ) )\r
- {\r
- Answer[5] = 1; // return success\r
- }\r
- delete nChar;\r
- }\r
- }\r
-\r
- Socket->write( Answer, 10 );\r
- return ( true );\r
- }\r
- }\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_CHARLIST): invalid packet [%04x]", *( uint16_t* )&Packet[3] );\r
-\r
- return ( false );\r
- }\r
-\r
- return true;\r
-}\r
-\r
-bool PGameServer::HandleGetStatus( PClient *Client, PGameState *State, const uint8_t *Packet )\r
-{\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
-\r
- if ( *( uint16_t* )&Packet[3] == 0x3787 )\r
- {\r
- static const uint8_t STATUS[9] = {0xfe, 0x06, 0x00, 0x87, 0x3a, 0x11, 0x00, 0x00, 0x00};\r
-\r
- Socket->write( STATUS, 9 );\r
- State->TCP.mState = PGameState::TCP::GS_GAMEINFO;\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GETSTATUS): invalid packet [%04x]", *( uint16_t* )&Packet[3] );\r
-\r
- return ( false );\r
- }\r
-\r
- return ( true );\r
-}\r
-\r
-bool PGameServer::HandleGameInfo( PClient *Client, PGameState *State, const uint8_t *Packet )\r
-{\r
-// Console->Print("Inside HandleGameInfo");//NEW added\r
-\r
- static uint8_t GameInfo[31] = {0xfe, 0x1c, 0x00, 0x83, 0x05, // header\r
- 0x00, 0x00, 0x00, 0x00, // account id\r
- 0x00, 0x00, 0x00, 0x00, // char id\r
- 0x00, 0x00, 0x00, 0x00, // udp ip\r
- 0x00, 0x00, // udp port\r
- 0x00, 0x00, 0x00, 0x00, // unknown\r
- 0x00, 0x00, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0x00, // session key\r
- };\r
-\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
-\r
- if ( *( uint16_t* )&Packet[3] == 0x3c87 )\r
- {\r
- //int PortFix = Config->GetOptionInt("debug_mode");\r
-\r
- ConnectionUDP* udpConn = ServerSock->getUDPConnection( IPStringToDWord( Client->GetAddress() ), Client->GetRemoteUDPPort() );\r
- Client->setUDPConnection( udpConn );\r
- if ( !udpConn )\r
- {\r
- Console->Print( RED, BLACK, "Client %d: UDP port setup failed", Client->GetID() );\r
- ClientDisconnected( Client );\r
- }\r
-\r
- uint16_t Port = Client->getUDPConn()->getPort();\r
-\r
- if ( Port == 0 )\r
- Console->Print( RED, BLACK, "Client->OpenUDP() failed" );\r
-\r
-\r
- /* if(PortFix == 1) // removed, no more use\r
- {\r
- Port = Config->GetOptionInt("useudpport");\r
- Console->Print(YELLOW, BLACK, "UDP Port set to non-standard for debugging!");\r
- }; */\r
-\r
- uint32_t IP;\r
- std::string IPServerString;\r
-// use [server_nat_ip] for server if client is NOT on [no_nat_net] (and [no_nat_net]!=0)\r
- if ( strcmp( Config->GetOption( "no_nat_net" ).c_str(), "0" ) && strncmp( Client->GetAddress(), Config->GetOption( "no_nat_net" ).c_str(), strlen( Config->GetOption( "no_nat_net" ).c_str() ) ) )\r
- {\r
- IPServerString = Config->GetOption( "server_nat_ip" );\r
- }\r
- else // else client is "local" so use [server_ip]\r
- {\r
- IPServerString = Config->GetOption( "server_ip" );\r
- }\r
- IP = IPStringToDWord( IPServerString.c_str() );\r
-//Console->Print("IP-1 %d", IP);\r
- if ( IP == 0 )\r
- IP = 0x0100007f;\r
-//Console->Print("IP-2 %d", IP);\r
- *( uint32_t* )&GameInfo[13] = IP;\r
- *( uint16_t* )&GameInfo[17] = Port;\r
- Console->Print( GREEN, BLACK, "[Info] Using UDP %s:%d on server", IPServerString.c_str(), Port );\r
-\r
- *( uint32_t* )&GameInfo[5] = Client->GetAccountID();\r
- *( uint32_t* )&GameInfo[9] = Client->GetCharID();\r
- Console->Print( GREEN, BLACK, "[Info] Serving char id :%d", Client->GetCharID() );\r
-\r
- Socket->write( GameInfo, 31 );\r
- Socket->flushSendBuffer();\r
-\r
- static const uint8_t READY[7] = {0xfe, 0x04, 0x00, 0x83, 0x0d, 0x00, 0x00};\r
- Socket->write( READY, 7 );\r
-\r
- State->TCP.mState = PGameState::TCP::GS_INGAME;\r
- State->UDP.mState = PGameState::UDP::GUS_SYNC0;\r
-//Console->Print("Sync Reset");\r
- Client->ResetTransactionID();\r
-\r
- // Mark char as Online\r
- PChar *Char = Client->GetChar();\r
- Char->SetOnlineStatus( true ); //Also using this info to check if Char may have to be saved at client disconnect\r
- Client->ChangeCharLocation( Char->GetLocation(), true );\r
-\r
- // hello-message from server..\r
- /*\r
- std::string serverName = Config->GetOption("server_name");\r
- std::string helloMessage = "Welcome to " + serverName + " - A TinNS Neocron Server.";\r
- char* message = (char*) helloMessage.c_str();\r
- Chat->send(Client, CHAT_DIRECT, "System", message, false);\r
- */\r
-\r
- bool SendBC = false;\r
- if ( Config->GetOptionInt( "broadcast_new" ) == 1 )\r
- {\r
- if ( Config->GetOptionInt( "broadcast_new_hidestaff" ) == 1 )\r
- {\r
- if ( Client->GetAccountLevel() > PAL_REGPLAYER )\r
- SendBC = false;\r
- else\r
- SendBC = true;\r
- }\r
- else\r
- {\r
- SendBC = true;\r
- }\r
- }\r
- if ( SendBC == true )\r
- {\r
- std::string playerName = Chars->GetChar( Client->GetCharID() )->GetName();\r
- std::string serverName = Config->GetOption( "server_name" );\r
- std::string helloMessage = "Hello " + playerName + "! Welcome to " + serverName + " - A TinNS Neocron Server.";\r
- char* message = ( char* ) helloMessage.c_str();\r
-\r
- Chat->sendOOCBroadcast( message );\r
- }\r
- //Console->Print("UDP Setup: %s", nlGetErrorStr(nlGetError()));\r
- }\r
- else\r
- {\r
- Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEINFO): invalid packet [%04x]", *( uint16_t* )&Packet[3] );\r
- return ( false );\r
- }\r
-\r
- return ( true );\r
-}\r
-\r
-bool PGameServer::HandleGame( PClient *Client, PGameState *State )\r
-{\r
- //PGameSocket *Socket = Client->GetGameSocket();\r
- ConnectionUDP *UDPSocket = Client->getUDPConn();\r
- //Console->Print("Clientadress %s", Client->GetAddress());\r
-\r
- //int Size = 0;\r
- PMessage* NewMsg = UDPSocket->GetMessage();\r
- if ( NewMsg && NewMsg->GetSize() )\r
- {\r
-\r
- MsgDecoder->Init( NewMsg, Client, State ); // State used temporarily\r
- do\r
- {\r
- if ( MsgDecoder->Analyse() )\r
- {\r
- if ( gDevDebug && MsgDecoder->IsTraceKnownMsg() )\r
- Console->Print( "%s Client[%d] msg: %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), Client->GetID(), MsgDecoder->GetName().c_str() );\r
-\r
- if ( MsgDecoder->IsActionReady() )\r
- {\r
- MsgDecoder->DoAction();\r
- }\r
- }\r
- else if ( MsgDecoder->IsError() )\r
- {\r
- Console->Print( YELLOW, BLACK, "[Info] Client[%d] Decoding error: %s", Client->GetID(), MsgDecoder->GetError().c_str() );\r
- }\r
-// else if (MsgDecoder->GetState() == DECODE_UNKNOWN)\r
- else if ( gDevDebug && ( MsgDecoder->GetState() == DECODE_UNKNOWN ) && MsgDecoder->IsTraceUnknownMsg() )\r
- {\r
- Console->Print( "%s Client[%d] Unknown msg: %s", Console->ColorText( YELLOW, BLACK, "[Info]" ), Client->GetID(), MsgDecoder->GetName().c_str() );\r
- }\r
-\r
-// if (MsgDecoder->IsTraceDump())\r
- if ( gDevDebug && MsgDecoder->IsTraceDump() )\r
- {\r
- MsgDecoder->DumpMsg();\r
- }\r
-\r
- }\r
- while ( MsgDecoder->MoreSubMsg() );\r
- }\r
-\r
- if ( NewMsg )\r
- {\r
- delete NewMsg;\r
- }\r
-\r
- return ( true );\r
-}\r
-\r
-bool PGameServer::ProcessClient( PClient *Client, PGameState *State )\r
-{\r
- static const uint8_t HANDSHAKE0A[6] = {0xfe, 0x03, 0x00, 0x80, 0x01, 0x66};\r
-\r
- if ( !State )\r
- {\r
- GameStateMap::iterator node = ClientStates.find( Client );\r
- if ( node == ClientStates.end() )\r
- return ( false );\r
-\r
- State = node->second;\r
- }\r
-\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
- if ( !Socket ) Console->Print( RED, BLACK, "PANIC: Client %d : TCP Socket is NULL !!!", Client->GetID() );\r
- if ( State->TCP.mWaitSend && Socket->getSendBufferSize() == 0 )\r
- return ( false );\r
-\r
- if ( State->TCP.mState == PGameState::TCP::GS_CONNECTED )\r
- {\r
- Socket->write( HANDSHAKE0A, 6 );\r
- State->TCP.mState = PGameState::TCP::GS_HANDSHAKE0;\r
- }\r
-\r
- if ( State->TCP.mState == PGameState::TCP::GS_INGAME )\r
- {\r
- return ( HandleGame( Client, State ) );\r
- }\r
- else\r
- {\r
- int PacketSize = 0;\r
- const uint8_t *Packet = Socket->read( &PacketSize );\r
-\r
- if ( PacketSize > 0 )\r
- {\r
- switch ( State->TCP.mState )\r
- {\r
- case PGameState::TCP::GS_HANDSHAKE0:\r
- return ( HandleHandshake( State, Packet, PacketSize ) );\r
-\r
- case PGameState::TCP::GS_AUTHENTICATE:\r
- return ( HandleAuthenticate( Client, State, Packet, PacketSize ) );\r
-\r
- case PGameState::TCP::GS_GAMEDATA:\r
- return ( HandleGameData( Client, State, Packet ) );\r
-\r
- case PGameState::TCP::GS_REQUESTCHARS:\r
- return ( HandleRequestChars( Client, State, Packet ) );\r
-\r
- case PGameState::TCP::GS_CHARLIST:\r
- return ( HandleCharList( Client, State, Packet, PacketSize ) );\r
-\r
- case PGameState::TCP::GS_GETSTATUS:\r
- return ( HandleGetStatus( Client, State, Packet ) );\r
-\r
- case PGameState::TCP::GS_GAMEINFO:\r
- return ( HandleGameInfo( Client, State, Packet ) );\r
- default:\r
- break;\r
- }\r
- }\r
- }\r
-\r
- return ( true );\r
-}\r
-\r
-void PGameServer::ClientDisconnected( PClient *Client )\r
-{\r
- GameStateMap::iterator node = ClientStates.find( Client );\r
-\r
- if ( node == ClientStates.end() )\r
- return;\r
-\r
- PGameState *State = node->second;\r
- FinalizeClient( Client, State );\r
-}\r
-\r
-void PGameServer::UDPStreamClosed( PClient *Client )\r
-{\r
- GameStateMap::iterator node = ClientStates.find( Client );\r
-\r
- if ( node == ClientStates.end() )\r
- return;\r
-\r
- PGameState *State = node->second;\r
- FinalizeClient( Client, State );\r
-}\r
-\r
-void PGameServer::FinalizeClient( PClient *Client, PGameState *State )\r
-{\r
- Console->Print( GREEN, BLACK, "[Info] Gameserver: client %s disconnected", Client->GetAddress() );\r
-\r
- // Isnt working somehow. I assume that mID and mAccount is deleted already.\r
- // Mark char as Offline\r
- //PChar *Char = Chars->GetChar(Client->GetCharID());\r
- //Char->SetOnlineStatus(false);\r
-\r
- // delete client from clientmanager list => Do it before we remove network access\r
- ClientManager->deleteClientFromList( Client->GetLocalID() );\r
-\r
- Client->GameDisconnect();\r
- ClientStates.erase( Client );\r
- delete State;\r
- --mNumClients;\r
-\r
-}\r
-\r
-void PGameServer::FinalizeClientDelayed( PClient *Client, PGameState *State )\r
-{\r
- Console->Print( GREEN, BLACK, "[Info] Gameserver: client %s is about to be disconnected", Client->GetAddress() );\r
- State->TCP.mWaitSend = true;\r
-}\r
-\r
-PGameState* PGameServer::GetClientState( PClient* nClient )\r
-{\r
- GameStateMap::iterator node = ClientStates.find( nClient );\r
-\r
- if ( node == ClientStates.end() )\r
- return NULL;\r
- else\r
- return node->second;\r
-}\r
+#include <cstring>
+#include "GameServer/Includes.hxx"
+#include "GameServer/Decoder/Includes.hxx"
+#include "Common/Includes.hxx"
+
+// TODO:
+// - Deny login if char is already online (More information about the login procedure is necessary to do that)
+// - Take main loop timeout setting from config file
+// - Add Regex control to new char name validation
+// - Add Check of Char offline (and unloaded) before deleting (from the char choosing i/f) if multiple login
+// allowed for the same account
+// - Check if adding to Client to Client manager shouldn't be done only one UDP connection done ?
+// => Risk of sending UDP chat on non-socket ????
+
+PGameServer::PGameServer()
+{
+ mServerStartupTime = std::time( NULL );
+ mNumClients = 0;
+ MsgDecoder = new PUdpMsgDecoder();
+}
+
+PGameServer::~PGameServer()
+{
+ ServerSock->closeServer();
+ delete MsgDecoder;
+}
+
+void PGameServer::Start()
+{
+ uint16_t Port = Config->GetOptionInt( "gameserver_port" );
+ Console->LPrint( "Starting gameserver on port %i...", Port );
+
+ if ( ServerSock->open( Port ) )
+ {
+ Console->LPrint( GREEN, BLACK, "Success" );
+ }
+ else
+ {
+ Console->LPrint( RED, BLACK, "Failed" );
+ }
+ Console->LClose();
+ ServerSock->settimeout( 0, 10000 );
+
+ SetGameTime(( 1000 / 10 )*3600*12 ); //Set initial time to 12:00 on 7 Jul 2789
+
+ // Init random generator
+ struct timespec tmpTime;
+ if ( !clock_gettime( CLOCK_REALTIME, &tmpTime ) )
+ {
+ srandom(( uint32_t )tmpTime.tv_sec );
+ InitRandom( tmpTime.tv_sec );
+//Console->Print("Initializing random generator. First value is %d", random());
+ }
+
+ if ( Config->GetOptionInt( "gameserver_udpport_max" ) - Config->GetOptionInt( "gameserver_udpport_min" ) + 1 < Config->GetOptionInt( "maxclients" ) )
+ {
+ Console->Print( "%s UDP port range setting doesn't allow for the simultaneous max clients set in config", Console->ColorText( YELLOW, BLACK, "[Warning]" ) );
+ }
+
+}
+
+void PGameServer::SetGameTime( uint32_t newtime )
+{
+ if ( clock_gettime( CLOCK_REALTIME, &mStartTime ) )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Clock unavailable !!!" );
+ perror( "clock_gettime CLOCK_REALTIME" );
+ mStartTime.tv_sec = 0;
+ mStartTime.tv_nsec = 0;
+ }
+ mBaseGameTime = newtime;
+}
+
+uint32_t PGameServer::GetGameTime()
+{
+ //const uint32_t TimeFactor = 375;
+ const uint32_t TimeFactor = 1000;
+ const uint32_t nsTimeFactor = 1000000000 / TimeFactor;
+
+ struct timespec tmpTime;
+
+ if ( mStartTime.tv_sec )
+ {
+ clock_gettime( CLOCK_REALTIME, &tmpTime );
+ return ( mBaseGameTime + (( tmpTime.tv_sec - mStartTime.tv_sec ) * TimeFactor ) + ( tmpTime.tv_nsec / nsTimeFactor ) - ( mStartTime.tv_nsec / nsTimeFactor ) );
+ }
+ else
+ return 0;
+}
+
+void PGameServer::Update()
+{
+ if ( ServerSock->newConnection() )
+ {
+ int clid = Server->NewClient();
+ if ( clid != -1 )
+ {
+ Console->Print( GREEN, BLACK, "[Info] Gameserver: client [%i] connected", clid );
+ PClient *Client = Server->GetClient( clid );
+ if ( Client->getTCPConn() ) Console->Print( RED, BLACK, "WARNING: Client %d : TCP Socket NOT NULL before allocation.", Client->GetID() );
+ ConnectionTCP* tcpConn = ServerSock->getTCPConnection();
+ Client->setTCPConnection( tcpConn );
+
+ //ConnectionUDP* udpConn = ServerSock->getUDPConnection();
+ //Client->setUDPConnection(udpConn);
+
+ Console->Print( "Client address: %s", Client->GetAddress() );
+ ++mNumClients;
+
+ PGameState *state = new PGameState();
+ ClientStates.insert( std::make_pair( Client, state ) );
+ state->TCP.mState = PGameState::TCP::GS_CONNECTED;
+
+ // add the new connected client to the global clientmanager for further use in chat, etc...
+ ClientManager->addClientToList( Client );
+ }
+ else
+ {
+ Console->Print( YELLOW, BLACK, "[Notice] Gameserver: Client connection refused (server full?)" );
+ }
+ }
+
+ /*** temp check ***/
+ for ( PClientMap::iterator it = ClientManager->getClientListBegin(); it != ClientManager->getClientListEnd(); it++ )
+ {
+ if ( !it->second )
+ {
+ Console->Print( RED, BLACK, "PANIC: NULL Client found in ClientManager Clients Map." );
+ }
+ }
+ /*** end temp check ***/
+
+ for ( GameStateMap::iterator i = ClientStates.begin(); i != ClientStates.end(); )
+ {
+ PClient *Client = i->first;
+ PGameState *State = i->second;
+ // node gets erased in FinalizeClient, increment iterator now
+ ++i;
+ if ( !ProcessClient( Client, State ) )
+ FinalizeClient( Client, State );
+ }
+}
+
+bool PGameServer::HandleHandshake( PGameState *State, const uint8_t *Packet, int PacketSize )
+{
+ //static const uint8_t HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x68};
+ //PGameSocket *Socket = Client->GetGameSocket();
+
+ switch ( State->TCP.mState )
+ {
+ case PGameState::TCP::GS_HANDSHAKE0 :
+ {
+ if ( PacketSize == 6 && *( uint16_t* )&Packet[3] == 0x0080 && Packet[5] == 0x78 )
+ {
+ //FIXME: this packet seems to be unnecessary,
+ // although it appears in traffic dumps
+ // (causes clientside "Wrong protocol" errors)
+
+ //Socket->Write(HANDSHAKE1A, 6);
+ State->TCP.mState = PGameState::TCP::GS_AUTHENTICATE;
+ }
+ else
+ {
+ Console->Print( YELLOW, BLACK, "[Notice] Gameserver protocol error (GS_HANDSHAKE0): invalid packet [%04x]", *( uint16_t* )&Packet[3] );
+ return ( false );
+ }
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool PGameServer::HandleAuthenticate( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize )
+{
+ ConnectionTCP *Socket = Client->getTCPConn();
+
+ if ( PacketSize > 20 && *( uint16_t* )&Packet[3] == 0x8084 )
+ {
+ // authentication method #1
+ const uint8_t *Key = &Packet[5]; // password key
+ uint16_t ULen = *( uint16_t* ) & Packet[16]; // username length
+ uint16_t PLen = *( uint16_t* ) & Packet[18]; // password length
+ char *UserName = ( char* ) & Packet[20]; // account name
+ const uint8_t *PW = &Packet[20+ULen]; // encoded password
+
+ // Safety controls
+ if ( 15 + ULen + PLen > PacketSize )
+ {
+ Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" );
+ return false;
+ }
+ if ( strnlen( UserName, ULen ) == ULen )
+ {
+ Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" );
+ return false;
+ }
+
+ bool Failed = false;
+
+ PAccount Account( UserName );
+ if ( Account.GetID() == 0 )
+ {
+ Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName );
+ Failed = true;
+ }
+ else if ( !Account.Authenticate( PW, PLen, Key ) )
+ {
+ Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName );
+ Failed = true;
+ }
+
+ if ( !Failed )
+ {
+ Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' authentication successful", UserName );
+ if ( Account.GetLevel() == PAL_BANNED )
+ {
+ Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName );
+ // TODO: ban ip for an adjustable time span?
+ Failed = true; // player is banned
+ }
+
+ if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER )
+ {
+ if ( Server->GetNumClients() > Server->GetMaxClients() )
+ {
+ Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from user '%s'", UserName );
+ Failed = true; // server full
+ }
+ }
+ }
+
+ if ( Failed )
+ {
+ // TODO: is this packet correct here?
+ uint8_t AUTHFAILED[15] = {0xfe, 0x0c, 0x00, 0x83, 0x86, 0x05, 0x00, 0x06, 0x00, 'E', 'R',
+ 'R', 'O', 'R', 0
+ };
+ // TODO: send actual reason instead of ERROR
+ Socket->write( AUTHFAILED, 15 );
+ FinalizeClientDelayed( Client, State );
+ State->TCP.mState = PGameState::TCP::GS_UNKNOWN;
+ Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s' login refused", UserName );
+ }
+ else
+ {
+ Client->LoggedIn( &Account );
+ uint8_t AUTHOK[28] = {0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ *( uint32_t* )&AUTHOK[5] = Account.GetID();
+ Socket->write( AUTHOK, 28 );
+ State->TCP.mState = PGameState::TCP::GS_GAMEDATA;
+ Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' logged in", UserName );
+ }
+ }
+ else if ( PacketSize > 29 && *( uint16_t* )&Packet[3] == 0x0183 )
+ {
+ // authentication method #2, sent when game starts
+ const uint8_t *Key = &Packet[13]; // password key
+ uint16_t PLen = *( uint16_t* ) & Packet[25]; // password length
+ uint16_t ULen = *( uint16_t* ) & Packet[27]; // username length
+ char *UserName = ( char* ) & Packet[29]; // account name
+ const uint8_t *PW = &Packet[29+ULen]; // encoded password
+
+ // Safety controls
+ if ( 24 + ULen + PLen > PacketSize )
+ {
+ Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" );
+ return false;
+ }
+ if ( strnlen( UserName, ULen ) == ULen )
+ {
+ Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" );
+ return false;
+ }
+
+ bool Failed = false;
+
+ PAccount Account( UserName );
+ if ( Account.GetID() == 0 )
+ {
+ Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName );
+ Failed = true;
+ }
+ else if ( !Account.Authenticate( PW, PLen, Key ) )
+ {
+ Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName );
+ Failed = true;
+ }
+
+ if ( !Failed )
+ {
+ if ( Account.GetLevel() == PAL_BANNED )
+ {
+ Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName );
+ // TODO: ban ip for an adjustable time span?
+ Failed = true; // player is banned
+ }
+
+ if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER )
+ {
+ if ( Server->GetNumClients() > ( Server->GetMaxClients() - Server->GetGMSlots() ) )
+ {
+ Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from regular user '%s'", UserName );
+ Failed = true; // server full for non-GM users
+ }
+ }
+ else if ( Config->GetOptionInt( "require_validation" ) == 1 && Account.GetLevel() == PAL_UNREGPLAYER )
+ {
+ Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', account not activated yet", UserName );
+ Failed = true;
+ }
+ else if ( Config->GetOptionInt( "minlevel" ) > Account.GetLevel() )
+ {
+ Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', insufficient level %d vs %d required", UserName, Account.GetLevel(), Config->GetOptionInt( "minlevel" ) );
+ Failed = true;
+ }
+ else if ( Server->GetNumClients() > Server->GetMaxClients() )
+ {
+ Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from privileged user '%s'", UserName );
+ Failed = true; // server full even for GM users
+ }
+ }
+
+
+ if ( !Failed )
+ {
+ int value = *( uint32_t* ) & Packet[21];//i think here we must read uint32_t instead of uint8_t
+ uint32_t CharID = Account.GetCharIdBySlot( value );
+
+ if ( Chars->LoadChar( CharID ) )
+ {
+ Client->SetCharID( CharID );
+ }
+ else
+ {
+ Failed = true;
+ }
+ }
+
+ if ( Failed ) // something strange happened
+ FinalizeClientDelayed( Client, State );
+ else
+ {
+ Client->LoggedIn( &Account );
+ /*uint8_t AUTHOK[28]={0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ *(uint32_t*)&AUTHOK[5]=Account->GetID();
+ Socket->Write(AUTHOK, 28);*/
+ //Client->SetRemoteUDPAddr(*(uint32_t*)&Packet[5], *(uint16_t*)&Packet[9]);
+ State->TCP.mState = PGameState::TCP::GS_GETSTATUS;
+ Console->Print( "Gameserver: User '%s' entered game (%08x:%04x)", UserName, *( uint32_t* )&Packet[5], *( uint16_t* )&Packet[9] );
+ Client->SetRemoteUDPPort( *( int* )&Packet[9] );
+ }
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): invalid packet [%04x]", *( uint16_t* )&Packet[3] );
+ return ( false );
+ }
+
+ return ( true );
+}
+
+bool PGameServer::HandleGameData( PClient *Client, PGameState *State, const uint8_t *Packet )
+{
+ static const uint8_t GAMEDATA[5] = {0xfe, 0x02, 0x00, 0x87, 0x3a};
+ ConnectionTCP *Socket = Client->getTCPConn();
+
+ if ( *( uint16_t* )&Packet[3] == 0x3787 )
+ {
+ Socket->write( GAMEDATA, 5 );
+ State->TCP.mState = PGameState::TCP::GS_REQUESTCHARS;
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEDATA): invalid packet [%04x]", *( uint16_t* )&Packet[3] );
+ return ( false );
+ }
+
+ return ( true );
+}
+
+bool PGameServer::HandleRequestChars( PClient *Client, PGameState *State, const uint8_t *Packet )
+{
+ PAccount Account( Client->GetAccountID() );
+
+ if ( !Account.GetID() )
+ return false;
+
+ ConnectionTCP *Socket = Client->getTCPConn();
+
+ struct PCharList
+ {
+ uint16_t Unknown1;
+ uint16_t NumSlots;
+ uint16_t Unknown2;
+ } CharList;
+
+ PCharProfile CharEntry[MAX_CHARS_PER_ACCOUNT];
+
+ const int CHARBASESIZE = 28;
+
+ if ( *( uint16_t* )&Packet[3] == 0x8284 )
+ {
+ CharList.NumSlots = MAX_CHARS_PER_ACCOUNT;
+ int NameLengths = 0;
+
+ for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ )
+ {
+ CharEntry[i].CharID = 0;
+ CharEntry[i].Type = 0;
+ CharEntry[i].Color0 = 0;
+ CharEntry[i].Location = 1;
+ CharEntry[i].Unknown1 = 0;
+ CharEntry[i].Head = 0;
+ CharEntry[i].Torso = 0;
+ CharEntry[i].Legs = 0;
+ CharEntry[i].Unknown3 = 1;
+ CharEntry[i].Unknown4 = 1;
+ CharEntry[i].Unknown5 = 1;
+ CharEntry[i].Unknown6 = 1;
+ CharEntry[i].Unknown7 = 1;
+ CharEntry[i].Unknown8 = 0;
+ CharEntry[i].Unknown9 = 0;
+ CharEntry[i].Unknown10 = 0;
+ CharEntry[i].Unknown11 = 0;
+ CharEntry[i].Unknown12 = 0;
+
+ CharEntry[i].in_use = false;
+ }
+
+ Chars->GetCharProfiles( Account.GetID(), CharEntry, MAX_CHARS_PER_ACCOUNT );
+
+ for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ )
+ {
+ if ( CharEntry[i].in_use )
+ {
+ NameLengths += CharEntry[i].NameLen;
+ }
+ else
+ {
+ CharEntry[i].CharID = 0xffffffff;
+ CharEntry[i].NameLen = 0;
+ }
+ }
+
+ uint8_t PacketHeader[5] = {0xfe, 0x00, 0x00, 0x83, 0x85};
+ *( uint16_t* )&PacketHeader[1] = sizeof( uint16_t ) * 3 + ( MAX_CHARS_PER_ACCOUNT * CHARBASESIZE ) + NameLengths + 2;
+ Socket->write( PacketHeader, 5 );
+
+ CharList.Unknown1 = 0x0000;
+ CharList.Unknown2 = CHARBASESIZE;
+ Socket->write( CharList.Unknown1 );
+ Socket->write( CharList.NumSlots );
+ Socket->write( CharList.Unknown2 );
+
+ for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ )
+ {
+ Socket->write( CharEntry[i].CharID );
+ Socket->write( CharEntry[i].Type );
+ Socket->write( CharEntry[i].Color0 );
+ Socket->write( CharEntry[i].Unknown1 );
+ Socket->write( CharEntry[i].Head );
+ Socket->write( CharEntry[i].Torso );
+ Socket->write( CharEntry[i].Legs );
+ Socket->write( CharEntry[i].Location );
+ Socket->write( CharEntry[i].NameLen );
+ Socket->write( CharEntry[i].Unknown3 );
+ Socket->write( CharEntry[i].Unknown4 );
+ Socket->write( CharEntry[i].Unknown5 );
+ Socket->write( CharEntry[i].Unknown6 );
+ Socket->write( CharEntry[i].Unknown7 );
+ Socket->write( CharEntry[i].Unknown8 );
+ Socket->write( CharEntry[i].Unknown9 );
+ Socket->write( CharEntry[i].Unknown10 );
+ Socket->write( CharEntry[i].Unknown11 );
+ Socket->write( CharEntry[i].Unknown12 );
+
+ if ( CharEntry[i].Name.length() > 0 )
+ {
+ Socket->write( CharEntry[i].Name.c_str() );
+ Socket->write(( uint8_t )0 );
+ }
+ }
+
+ State->TCP.mState = PGameState::TCP::GS_CHARLIST;
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "Gameserver protocol error (GS_REQUESTCHARS): invalid packet [%04x]", *( uint16_t* )&Packet[3] );
+ return ( false );
+ }
+
+ return ( true );
+}
+
+bool PGameServer::HandleCharList( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize )
+{
+ static uint8_t Answer[10] = {0xfe, 0x07, 0x00, 0x83, 0x86, 0, 0, 0, 0, 0};
+ ConnectionTCP *Socket = Client->getTCPConn();
+
+ if ( PacketSize > 9 && *( uint16_t* )&Packet[3] == 0x8284 )
+ {
+ uint8_t Mode = Packet[9];
+
+ switch ( Mode )
+ {
+ case 6: // request list
+ return ( HandleRequestChars( Client, State, Packet ) );
+
+ case 5: // validate name
+ {
+ if ( PacketSize < 31 )
+ return ( false );
+
+ // check for valid name string
+ bool ValidString = false;
+
+ for ( int i = 30; i < PacketSize; i++ )
+ if ( Packet[i] == 0 )
+ {
+ ValidString = true;
+ break;
+ }
+
+ const char *Name = ( char* ) & Packet[30];
+ if ( ValidString )
+ {
+ ValidString = PChar::IsCharnameWellFormed( Name );
+ }
+
+ if ( ValidString )
+ {
+ if ( Chars->CharExist( std::string( Name ) ) )
+ {
+ ValidString = false;
+ }
+ }
+
+ if ( ValidString )
+ Answer[5] = 1; // ok
+ else
+ Answer[5] = 2; // 2..6 => 'char name already in use!'
+
+ // Answer[5] = 0; // => 'unknown error'
+ Socket->write( Answer, 10 );
+ return ( true );
+ }
+
+ case 3: // delete char
+ {
+ PAccount Acc( Client->GetAccountID() );
+ uint8_t Num = Packet[PacketSize-1];
+
+ if ( Acc.GetID() )
+ {
+ uint32_t CharID = Acc.GetCharIdBySlot( Num );
+
+ // Also check that char is out of game
+ if (( CharID != 0 ) && ( Chars->GetChar( CharID ) == NULL ) )
+ {
+ char query[100];
+ snprintf( query, 100, "DELETE FROM characters WHERE c_id = %d LIMIT 1", CharID );
+ if ( MySQL->GameQuery( query ) )
+ Console->Print( RED, BLACK, "[Notice] Char %d not deleted!", CharID );
+ else
+ {
+ Console->Print( GREEN, BLACK, "[Info] Char %d deleted!", CharID );
+
+ snprintf( query, 100, "DELETE FROM buddy_list WHERE bud_charid = %d", CharID );
+ if ( MySQL->GameQuery( query ) )
+ Console->Print( YELLOW, BLACK, "[Notice] Char %d's buddy list not removed!", CharID );
+
+ snprintf( query, 100, "DELETE FROM genrep WHERE g_charid = %d", CharID );
+ if ( MySQL->GameQuery( query ) )
+ Console->Print( YELLOW, BLACK, "[Notice] Char %d's genrep list not removed!", CharID );
+
+ snprintf( query, 100, "DELETE FROM inventory WHERE inv_charid = %d", CharID );
+ if ( MySQL->GameQuery( query ) )
+ Console->Print( YELLOW, BLACK, "[Notice] Char %d's inventory not removed!", CharID );
+
+ Appartements->DeleteCharAppartements( CharID );
+ }
+ }
+ else
+ return false;
+ }
+ return ( true );
+ }
+
+ case 7: // create char
+ {
+ if ( PacketSize < 64 )
+ return ( false );
+
+ uint32_t Slot = * ( uint32_t* ) & Packet[30];
+ //uint32_t nClass =* (uint32_t*)&Packet[34]; // Not used - indirectly redundant with Profession
+ uint32_t Profession = * ( uint32_t* ) & Packet[38];
+ uint32_t Gender = * ( uint32_t* ) & Packet[42];
+ uint32_t Head = * ( uint32_t* ) & Packet[46];
+ uint32_t Torso = * ( uint32_t* ) & Packet[50];
+ uint32_t Legs = * ( uint32_t* ) & Packet[54];
+ uint32_t Faction = * ( uint32_t* ) & Packet[58];
+ uint8_t NameLen = Packet[62];
+ uint8_t NZSNb = Packet[63];
+
+ char TempName[256];
+ std::strncpy( TempName, ( const char* )&Packet[64], NameLen );
+ TempName[NameLen] = 0;
+
+ Answer[5] = 2; // return error if char creation fails
+
+ if ( PChar::IsCharnameWellFormed( TempName ) )
+ {
+ // check for already used char name - should not happen though
+ if ( ! Chars->CharExist( std::string( TempName ) ) )
+ {
+ PAccount Acc( Client->GetAccountID() );
+ PChar* nChar = new PChar();
+
+ if ( nChar->CreateNewChar( Acc.GetID(), TempName, Gender, Profession, Faction,
+ Head, Torso, Legs, NZSNb, ( const char* )&Packet[64+NameLen], Slot ) )
+ {
+ Answer[5] = 1; // return success
+ }
+ delete nChar;
+ }
+ }
+
+ Socket->write( Answer, 10 );
+ return ( true );
+ }
+ }
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_CHARLIST): invalid packet [%04x]", *( uint16_t* )&Packet[3] );
+
+ return ( false );
+ }
+
+ return true;
+}
+
+bool PGameServer::HandleGetStatus( PClient *Client, PGameState *State, const uint8_t *Packet )
+{
+ ConnectionTCP *Socket = Client->getTCPConn();
+
+ if ( *( uint16_t* )&Packet[3] == 0x3787 )
+ {
+ static const uint8_t STATUS[9] = {0xfe, 0x06, 0x00, 0x87, 0x3a, 0x11, 0x00, 0x00, 0x00};
+
+ Socket->write( STATUS, 9 );
+ State->TCP.mState = PGameState::TCP::GS_GAMEINFO;
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GETSTATUS): invalid packet [%04x]", *( uint16_t* )&Packet[3] );
+
+ return ( false );
+ }
+
+ return ( true );
+}
+
+bool PGameServer::HandleGameInfo( PClient *Client, PGameState *State, const uint8_t *Packet )
+{
+// Console->Print("Inside HandleGameInfo");//NEW added
+
+ static uint8_t GameInfo[31] = {0xfe, 0x1c, 0x00, 0x83, 0x05, // header
+ 0x00, 0x00, 0x00, 0x00, // account id
+ 0x00, 0x00, 0x00, 0x00, // char id
+ 0x00, 0x00, 0x00, 0x00, // udp ip
+ 0x00, 0x00, // udp port
+ 0x00, 0x00, 0x00, 0x00, // unknown
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, // session key
+ };
+
+ ConnectionTCP *Socket = Client->getTCPConn();
+
+ if ( *( uint16_t* )&Packet[3] == 0x3c87 )
+ {
+ //int PortFix = Config->GetOptionInt("debug_mode");
+
+ ConnectionUDP* udpConn = ServerSock->getUDPConnection( IPStringToDWord( Client->GetAddress() ), Client->GetRemoteUDPPort() );
+ Client->setUDPConnection( udpConn );
+ if ( !udpConn )
+ {
+ Console->Print( RED, BLACK, "Client %d: UDP port setup failed", Client->GetID() );
+ ClientDisconnected( Client );
+ }
+
+ uint16_t Port = Client->getUDPConn()->getPort();
+
+ if ( Port == 0 )
+ Console->Print( RED, BLACK, "Client->OpenUDP() failed" );
+
+
+ /* if(PortFix == 1) // removed, no more use
+ {
+ Port = Config->GetOptionInt("useudpport");
+ Console->Print(YELLOW, BLACK, "UDP Port set to non-standard for debugging!");
+ }; */
+
+ uint32_t IP;
+ std::string IPServerString;
+// use [server_nat_ip] for server if client is NOT on [no_nat_net] (and [no_nat_net]!=0)
+ if ( strcmp( Config->GetOption( "no_nat_net" ).c_str(), "0" ) && strncmp( Client->GetAddress(), Config->GetOption( "no_nat_net" ).c_str(), strlen( Config->GetOption( "no_nat_net" ).c_str() ) ) )
+ {
+ IPServerString = Config->GetOption( "server_nat_ip" );
+ }
+ else // else client is "local" so use [server_ip]
+ {
+ IPServerString = Config->GetOption( "server_ip" );
+ }
+ IP = IPStringToDWord( IPServerString.c_str() );
+//Console->Print("IP-1 %d", IP);
+ if ( IP == 0 )
+ IP = 0x0100007f;
+//Console->Print("IP-2 %d", IP);
+ *( uint32_t* )&GameInfo[13] = IP;
+ *( uint16_t* )&GameInfo[17] = Port;
+ Console->Print( GREEN, BLACK, "[Info] Using UDP %s:%d on server", IPServerString.c_str(), Port );
+
+ *( uint32_t* )&GameInfo[5] = Client->GetAccountID();
+ *( uint32_t* )&GameInfo[9] = Client->GetCharID();
+ Console->Print( GREEN, BLACK, "[Info] Serving char id :%d", Client->GetCharID() );
+
+ Socket->write( GameInfo, 31 );
+ Socket->flushSendBuffer();
+
+ static const uint8_t READY[7] = {0xfe, 0x04, 0x00, 0x83, 0x0d, 0x00, 0x00};
+ Socket->write( READY, 7 );
+
+ State->TCP.mState = PGameState::TCP::GS_INGAME;
+ State->UDP.mState = PGameState::UDP::GUS_SYNC0;
+//Console->Print("Sync Reset");
+ Client->ResetTransactionID();
+
+ // Mark char as Online
+ PChar *Char = Client->GetChar();
+ Char->SetOnlineStatus( true ); //Also using this info to check if Char may have to be saved at client disconnect
+ Client->ChangeCharLocation( Char->GetLocation(), true );
+
+ // hello-message from server..
+ /*
+ std::string serverName = Config->GetOption("server_name");
+ std::string helloMessage = "Welcome to " + serverName + " - A TinNS Neocron Server.";
+ char* message = (char*) helloMessage.c_str();
+ Chat->send(Client, CHAT_DIRECT, "System", message, false);
+ */
+
+ bool SendBC = false;
+ if ( Config->GetOptionInt( "broadcast_new" ) == 1 )
+ {
+ if ( Config->GetOptionInt( "broadcast_new_hidestaff" ) == 1 )
+ {
+ if ( Client->GetAccountLevel() > PAL_REGPLAYER )
+ SendBC = false;
+ else
+ SendBC = true;
+ }
+ else
+ {
+ SendBC = true;
+ }
+ }
+ if ( SendBC == true )
+ {
+ std::string playerName = Chars->GetChar( Client->GetCharID() )->GetName();
+ std::string serverName = Config->GetOption( "server_name" );
+ std::string helloMessage = "Hello " + playerName + "! Welcome to " + serverName + " - A TinNS Neocron Server.";
+ char* message = ( char* ) helloMessage.c_str();
+
+ Chat->sendOOCBroadcast( message );
+ }
+ //Console->Print("UDP Setup: %s", nlGetErrorStr(nlGetError()));
+ }
+ else
+ {
+ Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEINFO): invalid packet [%04x]", *( uint16_t* )&Packet[3] );
+ return ( false );
+ }
+
+ return ( true );
+}
+
+bool PGameServer::HandleGame( PClient *Client, PGameState *State )
+{
+ //PGameSocket *Socket = Client->GetGameSocket();
+ ConnectionUDP *UDPSocket = Client->getUDPConn();
+ //Console->Print("Clientadress %s", Client->GetAddress());
+
+ //int Size = 0;
+ PMessage* NewMsg = UDPSocket->GetMessage();
+ if ( NewMsg && NewMsg->GetSize() )
+ {
+
+ MsgDecoder->Init( NewMsg, Client, State ); // State used temporarily
+ do
+ {
+ if ( MsgDecoder->Analyse() )
+ {
+ if ( gDevDebug && MsgDecoder->IsTraceKnownMsg() )
+ Console->Print( "%s Client[%d] msg: %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), Client->GetID(), MsgDecoder->GetName().c_str() );
+
+ if ( MsgDecoder->IsActionReady() )
+ {
+ MsgDecoder->DoAction();
+ }
+ }
+ else if ( MsgDecoder->IsError() )
+ {
+ Console->Print( YELLOW, BLACK, "[Info] Client[%d] Decoding error: %s", Client->GetID(), MsgDecoder->GetError().c_str() );
+ }
+// else if (MsgDecoder->GetState() == DECODE_UNKNOWN)
+ else if ( gDevDebug && ( MsgDecoder->GetState() == DECODE_UNKNOWN ) && MsgDecoder->IsTraceUnknownMsg() )
+ {
+ Console->Print( "%s Client[%d] Unknown msg: %s", Console->ColorText( YELLOW, BLACK, "[Info]" ), Client->GetID(), MsgDecoder->GetName().c_str() );
+ }
+
+// if (MsgDecoder->IsTraceDump())
+ if ( gDevDebug && MsgDecoder->IsTraceDump() )
+ {
+ MsgDecoder->DumpMsg();
+ }
+
+ }
+ while ( MsgDecoder->MoreSubMsg() );
+ }
+
+ if ( NewMsg )
+ {
+ delete NewMsg;
+ }
+
+ return ( true );
+}
+
+bool PGameServer::ProcessClient( PClient *Client, PGameState *State )
+{
+ static const uint8_t HANDSHAKE0A[6] = {0xfe, 0x03, 0x00, 0x80, 0x01, 0x66};
+
+ if ( !State )
+ {
+ GameStateMap::iterator node = ClientStates.find( Client );
+ if ( node == ClientStates.end() )
+ return ( false );
+
+ State = node->second;
+ }
+
+ ConnectionTCP *Socket = Client->getTCPConn();
+ if ( !Socket ) Console->Print( RED, BLACK, "PANIC: Client %d : TCP Socket is NULL !!!", Client->GetID() );
+ if ( State->TCP.mWaitSend && Socket->getSendBufferSize() == 0 )
+ return ( false );
+
+ if ( State->TCP.mState == PGameState::TCP::GS_CONNECTED )
+ {
+ Socket->write( HANDSHAKE0A, 6 );
+ State->TCP.mState = PGameState::TCP::GS_HANDSHAKE0;
+ }
+
+ if ( State->TCP.mState == PGameState::TCP::GS_INGAME )
+ {
+ return ( HandleGame( Client, State ) );
+ }
+ else
+ {
+ int PacketSize = 0;
+ const uint8_t *Packet = Socket->read( &PacketSize );
+
+ if ( PacketSize > 0 )
+ {
+ switch ( State->TCP.mState )
+ {
+ case PGameState::TCP::GS_HANDSHAKE0:
+ return ( HandleHandshake( State, Packet, PacketSize ) );
+
+ case PGameState::TCP::GS_AUTHENTICATE:
+ return ( HandleAuthenticate( Client, State, Packet, PacketSize ) );
+
+ case PGameState::TCP::GS_GAMEDATA:
+ return ( HandleGameData( Client, State, Packet ) );
+
+ case PGameState::TCP::GS_REQUESTCHARS:
+ return ( HandleRequestChars( Client, State, Packet ) );
+
+ case PGameState::TCP::GS_CHARLIST:
+ return ( HandleCharList( Client, State, Packet, PacketSize ) );
+
+ case PGameState::TCP::GS_GETSTATUS:
+ return ( HandleGetStatus( Client, State, Packet ) );
+
+ case PGameState::TCP::GS_GAMEINFO:
+ return ( HandleGameInfo( Client, State, Packet ) );
+ default:
+ break;
+ }
+ }
+ }
+
+ return ( true );
+}
+
+void PGameServer::ClientDisconnected( PClient *Client )
+{
+ GameStateMap::iterator node = ClientStates.find( Client );
+
+ if ( node == ClientStates.end() )
+ return;
+
+ PGameState *State = node->second;
+ FinalizeClient( Client, State );
+}
+
+void PGameServer::UDPStreamClosed( PClient *Client )
+{
+ GameStateMap::iterator node = ClientStates.find( Client );
+
+ if ( node == ClientStates.end() )
+ return;
+
+ PGameState *State = node->second;
+ FinalizeClient( Client, State );
+}
+
+void PGameServer::FinalizeClient( PClient *Client, PGameState *State )
+{
+ Console->Print( GREEN, BLACK, "[Info] Gameserver: client %s disconnected", Client->GetAddress() );
+
+ // Isnt working somehow. I assume that mID and mAccount is deleted already.
+ // Mark char as Offline
+ //PChar *Char = Chars->GetChar(Client->GetCharID());
+ //Char->SetOnlineStatus(false);
+
+ // delete client from clientmanager list => Do it before we remove network access
+ ClientManager->deleteClientFromList( Client->GetLocalID() );
+
+ Client->GameDisconnect();
+ ClientStates.erase( Client );
+ delete State;
+ --mNumClients;
+
+}
+
+void PGameServer::FinalizeClientDelayed( PClient *Client, PGameState *State )
+{
+ Console->Print( GREEN, BLACK, "[Info] Gameserver: client %s is about to be disconnected", Client->GetAddress() );
+ State->TCP.mWaitSend = true;
+}
+
+PGameState* PGameServer::GetClientState( PClient* nClient )
+{
+ GameStateMap::iterator node = ClientStates.find( nClient );
+
+ if ( node == ClientStates.end() )
+ return NULL;
+ else
+ return node->second;
+}
-#pragma once\r
-\r
-#include <chrono>\r
-#include <cstdint>\r
-#include <map>\r
-\r
-struct PGameState\r
-{\r
- struct TCP\r
- {\r
- enum State\r
- {\r
- GS_UNKNOWN,\r
- GS_CONNECTED,\r
- GS_HANDSHAKE0,\r
- GS_AUTHENTICATE,\r
- GS_GAMEDATA,\r
- GS_REQUESTCHARS,\r
- GS_CHARLIST,\r
- GS_GETSTATUS,\r
- GS_GAMEINFO,\r
- GS_INGAME\r
- } mState;\r
-\r
- bool mWaitSend; // wait-for-completition flag\r
- } TCP;\r
-\r
- struct UDP\r
- {\r
- enum State\r
- {\r
- GUS_UNKNOWN,\r
- GUS_SYNC0,\r
- GUS_SYNC1,\r
- GUS_SYNC2,\r
- GUS_SYNC3\r
- } mState;\r
-\r
- bool mSynced;\r
- uint16_t mServerPacketNum;\r
- uint16_t mSequence;\r
- //uint16_t mClientPacketNum;\r
- } UDP;\r
-\r
- PGameState()\r
- {\r
- TCP.mState = TCP::GS_UNKNOWN;\r
- TCP.mWaitSend = false;\r
-\r
- UDP.mState = UDP::GUS_UNKNOWN;\r
- UDP.mSynced = false;\r
- UDP.mServerPacketNum = 0x9c9f;\r
- UDP.mSequence = 2;\r
- //UDP.mClientPacketNum = 0;\r
- };\r
-};\r
-\r
-class PUdpMsgDecoder;\r
-\r
-class PGameServer\r
-{\r
- private :\r
- time_t mServerStartupTime;\r
- int mNumClients;\r
- uint32_t mBaseGameTime;\r
- struct timespec mStartTime;\r
-\r
- typedef std::map<PClient*, struct PGameState*> GameStateMap;\r
- GameStateMap ClientStates;\r
- PUdpMsgDecoder* MsgDecoder;\r
-\r
- protected :\r
- bool ProcessClient( PClient *Client, PGameState *State = 0 );\r
- void FinalizeClient( PClient *Client, PGameState *State );\r
- void FinalizeClientDelayed( PClient *Client, PGameState *State );\r
-\r
-// bool HandleHandshake(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize);\r
- bool HandleHandshake( PGameState *State, const uint8_t *Packet, int PacketSize );\r
-\r
- bool HandleAuthenticate( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize );\r
-// bool HandleGameData(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize);\r
- bool HandleGameData( PClient *Client, PGameState *State, const uint8_t *Packet );\r
-\r
-// bool HandleRequestChars(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize);\r
- bool HandleRequestChars( PClient *Client, PGameState *State, const uint8_t *Packet );\r
-\r
- bool HandleCharList( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize );\r
-// bool HandleGetStatus(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize);\r
- bool HandleGetStatus( PClient *Client, PGameState *State, const uint8_t *Packet );\r
-\r
-// bool HandleGameInfo(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize);\r
- bool HandleGameInfo( PClient *Client, PGameState *State, const uint8_t *Packet );\r
-\r
- bool HandleGame( PClient *Client, PGameState *State );\r
-\r
- public :\r
- PGameServer();\r
- ~PGameServer();\r
-\r
- void Start();\r
- void Update();\r
- void ClientDisconnected( PClient *Client );\r
- void UDPStreamClosed( PClient *Client );\r
- void SetGameTime( uint32_t newtime );\r
- uint32_t GetGameTime();\r
-\r
- inline time_t GetStartTime() const { return mServerStartupTime; };\r
-\r
- PGameState* GetClientState( PClient* nClient );\r
-};\r
+#pragma once
+
+#include <chrono>
+#include <cstdint>
+#include <map>
+
+struct PGameState
+{
+ struct TCP
+ {
+ enum State
+ {
+ GS_UNKNOWN,
+ GS_CONNECTED,
+ GS_HANDSHAKE0,
+ GS_AUTHENTICATE,
+ GS_GAMEDATA,
+ GS_REQUESTCHARS,
+ GS_CHARLIST,
+ GS_GETSTATUS,
+ GS_GAMEINFO,
+ GS_INGAME
+ } mState;
+
+ bool mWaitSend; // wait-for-completition flag
+ } TCP;
+
+ struct UDP
+ {
+ enum State
+ {
+ GUS_UNKNOWN,
+ GUS_SYNC0,
+ GUS_SYNC1,
+ GUS_SYNC2,
+ GUS_SYNC3
+ } mState;
+
+ bool mSynced;
+ uint16_t mServerPacketNum;
+ uint16_t mSequence;
+ //uint16_t mClientPacketNum;
+ } UDP;
+
+ PGameState()
+ {
+ TCP.mState = TCP::GS_UNKNOWN;
+ TCP.mWaitSend = false;
+
+ UDP.mState = UDP::GUS_UNKNOWN;
+ UDP.mSynced = false;
+ UDP.mServerPacketNum = 0x9c9f;
+ UDP.mSequence = 2;
+ //UDP.mClientPacketNum = 0;
+ };
+};
+
+class PUdpMsgDecoder;
+
+class PGameServer
+{
+ private :
+ time_t mServerStartupTime;
+ int mNumClients;
+ uint32_t mBaseGameTime;
+ struct timespec mStartTime;
+
+ typedef std::map<PClient*, struct PGameState*> GameStateMap;
+ GameStateMap ClientStates;
+ PUdpMsgDecoder* MsgDecoder;
+
+ protected :
+ bool ProcessClient( PClient *Client, PGameState *State = 0 );
+ void FinalizeClient( PClient *Client, PGameState *State );
+ void FinalizeClientDelayed( PClient *Client, PGameState *State );
+
+// bool HandleHandshake(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize);
+ bool HandleHandshake( PGameState *State, const uint8_t *Packet, int PacketSize );
+
+ bool HandleAuthenticate( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize );
+// bool HandleGameData(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize);
+ bool HandleGameData( PClient *Client, PGameState *State, const uint8_t *Packet );
+
+// bool HandleRequestChars(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize);
+ bool HandleRequestChars( PClient *Client, PGameState *State, const uint8_t *Packet );
+
+ bool HandleCharList( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize );
+// bool HandleGetStatus(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize);
+ bool HandleGetStatus( PClient *Client, PGameState *State, const uint8_t *Packet );
+
+// bool HandleGameInfo(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize);
+ bool HandleGameInfo( PClient *Client, PGameState *State, const uint8_t *Packet );
+
+ bool HandleGame( PClient *Client, PGameState *State );
+
+ public :
+ PGameServer();
+ ~PGameServer();
+
+ void Start();
+ void Update();
+ void ClientDisconnected( PClient *Client );
+ void UDPStreamClosed( PClient *Client );
+ void SetGameTime( uint32_t newtime );
+ uint32_t GetGameTime();
+
+ inline time_t GetStartTime() const { return mServerStartupTime; };
+
+ PGameState* GetClientState( PClient* nClient );
+};
-#include <cstring>\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-PGenrepList::PGenrepList(uint32_t nOwnerCharID)\r
-{\r
- mOwnerCharID = nOwnerCharID;\r
- mListMaxSize = mListSize = 0;\r
- mGenrepList = NULL;\r
-}\r
-\r
-PGenrepList::~PGenrepList()\r
-{\r
- if (mGenrepList)\r
- delete[] mGenrepList;\r
-}\r
-\r
-bool PGenrepList::AddGenrep(uint16_t nWorldID, uint16_t nStationID)\r
-{\r
- char query[256];\r
-\r
- if ((FindEntry(nWorldID, nStationID) >= mListSize) && (mListSize < 255))\r
- {\r
- if (mListSize == mListMaxSize)\r
- {\r
- IncreaseMaxSize();\r
- }\r
- mGenrepList[mListSize].mWorldID = nWorldID;\r
- mGenrepList[mListSize++].mStationID = nStationID;\r
-\r
- snprintf(query, 256, "INSERT INTO genrep (g_id,g_worldid,g_stationid,g_charid) VALUES (NULL,'%u','%u','%u');", nWorldID, nStationID, mOwnerCharID);\r
- if ( MySQL->GameQuery(query) )\r
- {\r
- Console->Print(RED, BLACK, "PGenrepList::AddGenrep could not add some genrep entry in the database");\r
- Console->Print("Query was:");\r
- Console->Print("%s", query);\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
-\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-/*bool PGenrepList::RemoveChar(uint32_t nBuddyCharID)\r
-{\r
- char query[256];\r
- uint8_t rEntry, i;\r
-\r
- if ((rEntry = FindEntry(nBuddyCharID)) < mListSize)\r
- {\r
- --mListSize;\r
- for (i = rEntry; i < mListSize; i++)\r
- {\r
- mGenrepList[i] = mGenrepList[i+1];\r
- }\r
- // Remove from DB here\r
- snprintf(query, 256, "DELETE FROM buddy_list WHERE ((bud_charid='%u') AND (bud_buddyid='%u')) LIMIT 1;", mOwnerCharID, nBuddyCharID);\r
- if ( MySQL->GameQuery(query) )\r
- {\r
- Console->Print(RED, BLACK, "PBuddyList::AddChar could not add some buddylist entry in the database");\r
- Console->Print("Query was:");\r
- Console->Print("%s", query);\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
-\r
- return true;\r
- }\r
- else\r
- return false;\r
-}*/\r
-\r
-bool PGenrepList::SQLLoad()\r
-{\r
- char query[256];\r
- MYSQL_RES *result;\r
- MYSQL_ROW row;\r
- uint8_t EntriesNum;\r
-\r
- snprintf(query, 256, "SELECT * FROM genrep WHERE (g_charid='%u')", mOwnerCharID);\r
- result = MySQL->GameResQuery(query);\r
- if(result == NULL)\r
- {\r
- Console->Print(RED, BLACK, "PGenrepList::SQLLoad could not load genreplist from the database");\r
- Console->Print("Query was:");\r
- Console->Print("%s", query);\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
- //Console->Print(GREEN, BLACK, "PGenrepList::SQLLoad Loading Genrep list for char %d", mOwnerCharID);\r
- mListSize = 0;\r
- if((EntriesNum = mysql_num_rows(result)))\r
- {\r
- IncreaseMaxSize(EntriesNum);\r
-\r
- while((row = mysql_fetch_row(result)))\r
- {\r
- mGenrepList[mListSize].mWorldID = atoi(row[g_worldid]);\r
- mGenrepList[mListSize++].mStationID = atoi(row[g_stationid]);\r
- //Console->Print(GREEN, BLACK, "PGenrepList::SQLLoad Genrep list entry %d : world %d station %d", mListSize, mGenrepList[mListSize-1].mWorldID,mGenrepList[mListSize-1].mStationID);\r
- }\r
- }\r
- MySQL->FreeGameSQLResult(result);\r
- return true;\r
-}\r
-\r
-void PGenrepList::IncreaseMaxSize(uint8_t nNewMax)\r
-{\r
- uint16_t tmpSize;\r
-\r
- if (!nNewMax)\r
- {\r
- tmpSize = mListMaxSize + GENREPLIST_ALLOC_SIZE;\r
- }\r
- else if (nNewMax > mListMaxSize)\r
- {\r
- tmpSize = nNewMax / GENREPLIST_ALLOC_SIZE;\r
- if (nNewMax % GENREPLIST_ALLOC_SIZE)\r
- ++tmpSize;\r
- tmpSize *= GENREPLIST_ALLOC_SIZE;\r
- }\r
- else\r
- return;\r
-\r
- mListMaxSize = (tmpSize < 256) ? tmpSize : 255;\r
-\r
- PGenrepEntry* tmpList = new PGenrepEntry[mListMaxSize];\r
- if (mGenrepList)\r
- {\r
- if (mListSize)\r
- {\r
- memcpy(tmpList, mGenrepList, sizeof(PGenrepEntry) * mListSize);\r
- }\r
- delete[] mGenrepList;\r
- }\r
- mGenrepList = tmpList;\r
-}\r
-\r
-uint8_t PGenrepList::FindEntry(uint16_t nWorldID, uint16_t nStationID)\r
-{\r
- uint8_t i = 255;\r
-\r
- if (mGenrepList)\r
- {\r
- for (i = 0; i < mListSize; i++)\r
- {\r
- if ((mGenrepList[i].mWorldID == nWorldID) && (mGenrepList[i].mStationID == nStationID))\r
- break;\r
- }\r
- }\r
-\r
- return i;\r
-}\r
+#include <cstring>
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+PGenrepList::PGenrepList(uint32_t nOwnerCharID)
+{
+ mOwnerCharID = nOwnerCharID;
+ mListMaxSize = mListSize = 0;
+ mGenrepList = NULL;
+}
+
+PGenrepList::~PGenrepList()
+{
+ if (mGenrepList)
+ delete[] mGenrepList;
+}
+
+bool PGenrepList::AddGenrep(uint16_t nWorldID, uint16_t nStationID)
+{
+ char query[256];
+
+ if ((FindEntry(nWorldID, nStationID) >= mListSize) && (mListSize < 255))
+ {
+ if (mListSize == mListMaxSize)
+ {
+ IncreaseMaxSize();
+ }
+ mGenrepList[mListSize].mWorldID = nWorldID;
+ mGenrepList[mListSize++].mStationID = nStationID;
+
+ snprintf(query, 256, "INSERT INTO genrep (g_id,g_worldid,g_stationid,g_charid) VALUES (NULL,'%u','%u','%u');", nWorldID, nStationID, mOwnerCharID);
+ if ( MySQL->GameQuery(query) )
+ {
+ Console->Print(RED, BLACK, "PGenrepList::AddGenrep could not add some genrep entry in the database");
+ Console->Print("Query was:");
+ Console->Print("%s", query);
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+
+ return true;
+ }
+ else
+ return false;
+}
+
+/*bool PGenrepList::RemoveChar(uint32_t nBuddyCharID)
+{
+ char query[256];
+ uint8_t rEntry, i;
+
+ if ((rEntry = FindEntry(nBuddyCharID)) < mListSize)
+ {
+ --mListSize;
+ for (i = rEntry; i < mListSize; i++)
+ {
+ mGenrepList[i] = mGenrepList[i+1];
+ }
+ // Remove from DB here
+ snprintf(query, 256, "DELETE FROM buddy_list WHERE ((bud_charid='%u') AND (bud_buddyid='%u')) LIMIT 1;", mOwnerCharID, nBuddyCharID);
+ if ( MySQL->GameQuery(query) )
+ {
+ Console->Print(RED, BLACK, "PBuddyList::AddChar could not add some buddylist entry in the database");
+ Console->Print("Query was:");
+ Console->Print("%s", query);
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+
+ return true;
+ }
+ else
+ return false;
+}*/
+
+bool PGenrepList::SQLLoad()
+{
+ char query[256];
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ uint8_t EntriesNum;
+
+ snprintf(query, 256, "SELECT * FROM genrep WHERE (g_charid='%u')", mOwnerCharID);
+ result = MySQL->GameResQuery(query);
+ if(result == NULL)
+ {
+ Console->Print(RED, BLACK, "PGenrepList::SQLLoad could not load genreplist from the database");
+ Console->Print("Query was:");
+ Console->Print("%s", query);
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+ //Console->Print(GREEN, BLACK, "PGenrepList::SQLLoad Loading Genrep list for char %d", mOwnerCharID);
+ mListSize = 0;
+ if((EntriesNum = mysql_num_rows(result)))
+ {
+ IncreaseMaxSize(EntriesNum);
+
+ while((row = mysql_fetch_row(result)))
+ {
+ mGenrepList[mListSize].mWorldID = atoi(row[g_worldid]);
+ mGenrepList[mListSize++].mStationID = atoi(row[g_stationid]);
+ //Console->Print(GREEN, BLACK, "PGenrepList::SQLLoad Genrep list entry %d : world %d station %d", mListSize, mGenrepList[mListSize-1].mWorldID,mGenrepList[mListSize-1].mStationID);
+ }
+ }
+ MySQL->FreeGameSQLResult(result);
+ return true;
+}
+
+void PGenrepList::IncreaseMaxSize(uint8_t nNewMax)
+{
+ uint16_t tmpSize;
+
+ if (!nNewMax)
+ {
+ tmpSize = mListMaxSize + GENREPLIST_ALLOC_SIZE;
+ }
+ else if (nNewMax > mListMaxSize)
+ {
+ tmpSize = nNewMax / GENREPLIST_ALLOC_SIZE;
+ if (nNewMax % GENREPLIST_ALLOC_SIZE)
+ ++tmpSize;
+ tmpSize *= GENREPLIST_ALLOC_SIZE;
+ }
+ else
+ return;
+
+ mListMaxSize = (tmpSize < 256) ? tmpSize : 255;
+
+ PGenrepEntry* tmpList = new PGenrepEntry[mListMaxSize];
+ if (mGenrepList)
+ {
+ if (mListSize)
+ {
+ memcpy(tmpList, mGenrepList, sizeof(PGenrepEntry) * mListSize);
+ }
+ delete[] mGenrepList;
+ }
+ mGenrepList = tmpList;
+}
+
+uint8_t PGenrepList::FindEntry(uint16_t nWorldID, uint16_t nStationID)
+{
+ uint8_t i = 255;
+
+ if (mGenrepList)
+ {
+ for (i = 0; i < mListSize; i++)
+ {
+ if ((mGenrepList[i].mWorldID == nWorldID) && (mGenrepList[i].mStationID == nStationID))
+ break;
+ }
+ }
+
+ return i;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-\r
-#define GENREPLIST_ALLOC_SIZE 4 // atomicity of list entries allocation\r
-\r
-class PGenrepList {\r
-private:\r
- enum { // genrep DB Table fields\r
- g_id = 0,\r
- g_worldid,\r
- g_stationid,\r
- g_charid\r
- };\r
- struct PGenrepEntry\r
- {\r
- uint16_t mWorldID;\r
- uint16_t mStationID;\r
- };\r
-\r
- uint32_t mOwnerCharID;\r
- uint8_t mListMaxSize;\r
- uint8_t mListSize;\r
- PGenrepEntry* mGenrepList;\r
-\r
- void IncreaseMaxSize(uint8_t nNewMax = 0);\r
- uint8_t FindEntry(uint16_t nWorldID, uint16_t nStationID);\r
-\r
- public:\r
- PGenrepList(uint32_t nOwnerCharID);\r
- ~PGenrepList();\r
- bool AddGenrep(uint16_t nWorldID, uint16_t nStationID);\r
- //bool RemoveChar(uint32_t nBuddyCharID);\r
- inline uint8_t Count() { return mListSize; }\r
- uint16_t GetListDataSize() { return (sizeof(PGenrepEntry) * mListSize); }\r
- const void* GetListData() { return (const void*)mGenrepList; }\r
- bool SQLLoad();\r
-// bool SQLSave();\r
-};\r
+#pragma once
+
+#include <cstdint>
+
+#define GENREPLIST_ALLOC_SIZE 4 // atomicity of list entries allocation
+
+class PGenrepList {
+private:
+ enum { // genrep DB Table fields
+ g_id = 0,
+ g_worldid,
+ g_stationid,
+ g_charid
+ };
+ struct PGenrepEntry
+ {
+ uint16_t mWorldID;
+ uint16_t mStationID;
+ };
+
+ uint32_t mOwnerCharID;
+ uint8_t mListMaxSize;
+ uint8_t mListSize;
+ PGenrepEntry* mGenrepList;
+
+ void IncreaseMaxSize(uint8_t nNewMax = 0);
+ uint8_t FindEntry(uint16_t nWorldID, uint16_t nStationID);
+
+ public:
+ PGenrepList(uint32_t nOwnerCharID);
+ ~PGenrepList();
+ bool AddGenrep(uint16_t nWorldID, uint16_t nStationID);
+ //bool RemoveChar(uint32_t nBuddyCharID);
+ inline uint8_t Count() { return mListSize; }
+ uint16_t GetListDataSize() { return (sizeof(PGenrepEntry) * mListSize); }
+ const void* GetListData() { return (const void*)mGenrepList; }
+ bool SQLLoad();
+// bool SQLSave();
+};
-#include <cstring>\r
-#include "GameServer/Includes.hxx"\r
-#include "GameServer/Definitions/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-// TODO: - Get logfile name from config file\r
-\r
-const char ServerVersion[] = TINNS_GAME_VERSION;\r
-const char SVNRevision[] = TINNS_SVN_REVISION;\r
-\r
-PVehicles *Vehicles = 0;\r
-PMySQL *MySQL = 0;\r
-PConsole *Console = 0;\r
-PServer *Server = 0;\r
-PConfig *Config = 0;\r
-PConfig *CmdAccess = 0;\r
-PGameDefs *GameDefs = 0;\r
-PChars *Chars = 0;\r
-PFileSystem *Filesystem = 0;\r
-PGameServer *GameServer = 0;\r
-ServerSocket *ServerSock = 0;\r
-PMsgBuilder *MsgBuilder = 0;\r
-PWorlds *Worlds = 0;\r
-PAppartements* Appartements = 0;\r
-PWorldActors* WorldActors = 0;\r
-PNPCManager* NPCManager = 0;\r
-PSubway* Subway = 0;\r
-PTerminal* Terminal = 0;\r
-PLuaEngine* LuaEngine = 0;\r
-POutpost* Outposts = 0;\r
-PMultiPart* MultiPartHandler = 0;\r
-\r
-//multi-user chat implementation\r
-PClientManager *ClientManager = 0;\r
-PChat *Chat = 0;\r
-PCommands *GameCommands = 0;\r
-\r
-PISC *ISC = 0;\r
-\r
-const std::string EmptyString;\r
-\r
-// Development debug output control (set by config option dev_debug)\r
-bool gDevDebug = false;\r
-\r
-bool InitTinNS()\r
-{\r
- Console = new PConsole("log/gameserver.log"); // Make that from config file !!!\r
- Console->Print("Starting TinNS Gameserver");\r
- Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\");\r
- Console->Print(WHITE, BLUE, "| TinNS (TinNS is not a Neocron Server) |");\r
- Console->Print(WHITE, BLUE, "| Copyright (C) 2005 Linux Addicted Community |");\r
- Console->Print(WHITE, BLUE, "| maintainer Akiko <akiko@gmx.org> |");\r
- Console->Print(WHITE, BLUE, "| ========================================== |");\r
- Console->Print(WHITE, BLUE, "| Head coders: The packet analyzing team: |");\r
- Console->Print(WHITE, BLUE, "| - Akiko - MaxxJag |");\r
- Console->Print(WHITE, BLUE, "| - bakkdoor - Sting |");\r
- Console->Print(WHITE, BLUE, "| - Namikon - Balm |");\r
- Console->Print(WHITE, BLUE, "| - Hammag |");\r
- Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");\r
- Console->Print(WHITE, BLUE, "| This project would'nt be at its current stage without the help |");\r
- Console->Print(WHITE, BLUE, "| from the NeoPolis team, special thanks to you guys! |");\r
- Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");\r
- Console->Print(WHITE, BLUE, "| This project is under GPL, see any source file for more details |");\r
- Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/");\r
-\r
- //char svnrev[10];\r
- //GetSVNRev(svnrev);\r
- Console->LPrint("You are running TinNS Gameserver version");\r
- Console->LPrint(GREEN, BLACK, " %s", ServerVersion);\r
- Console->LPrint(WHITE, BLACK, " - SVN Rev");\r
- Console->LPrint(GREEN, BLACK, " %s", SVNRevision);\r
- Console->LClose();\r
-\r
- Config = new PConfig();\r
- if(!Config->LoadOptions(GameConfigTemplate, "./conf/gameserver.conf"))\r
- return false; //Shutdown();\r
-\r
- CmdAccess = new PConfig();\r
- if(!CmdAccess->LoadOptions(CommandsTemplate, "./conf/commands.conf"))\r
- return false; //Shutdown();\r
-\r
- gDevDebug = Config->GetOptionInt("dev_debug");\r
- std::string MyName = Config->GetOption("server_name");\r
- std::string IP = Config->GetOption("server_ip");\r
- char myCname[100], myCip[100];\r
- strncpy (myCname, Console->ColorText(CYAN, BLACK, MyName.c_str()), 100);\r
- strncpy (myCip, Console->ColorText(CYAN, BLACK, IP.c_str()), 100);\r
- Console->Print("My name is '%s', and my address is %s", myCname, myCip);\r
-\r
- MySQL = new PMySQL();\r
- if(MySQL->Connect() == false)\r
- return false; //Shutdown();\r
-\r
- Filesystem = new PFileSystem();\r
-\r
- GameDefs = new PGameDefs();\r
- GameDefs->Init();\r
-\r
- Worlds = new PWorlds();\r
- Worlds->LoadWorlds();\r
-\r
- WorldActors = new PWorldActors();\r
- LuaEngine = new PLuaEngine();\r
-\r
- NPCManager = new PNPCManager();\r
- Appartements = new PAppartements;\r
- Subway = new PSubway;\r
-\r
- if (!PAccount::SetUsernameRegexFilter(Config->GetOption("username_filter").c_str()))\r
- {\r
- Console->Print("%s Could not creat username_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("username_filter").c_str());\r
- return false;\r
- }\r
- if(!PAccount::SetPasswordRegexFilter(Config->GetOption("password_filter").c_str()))\r
- {\r
- Console->Print("%s Could not creat password_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("password_filter").c_str());\r
- return false;\r
- }\r
-\r
- if (!PChar::SetCharnameRegexFilter(Config->GetOption("charname_filter").c_str()))\r
- {\r
- Console->Print("%s Could not creat charname_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("charname_filter").c_str());\r
- return false;\r
- }\r
- Chars = new PChars();\r
-\r
- ServerSock = new ServerSocket();\r
- Server = new PServer();\r
- GameServer = new PGameServer();\r
- MsgBuilder = new PMsgBuilder();\r
-\r
- Vehicles = new PVehicles();\r
-\r
- ClientManager = new PClientManager();\r
- Chat = new PChat();\r
- GameCommands = new PCommands();\r
-\r
- ISC = new PISC();\r
- Terminal = new PTerminal();\r
-\r
- Outposts = new POutpost();\r
-\r
- MultiPartHandler = new PMultiPart();\r
-\r
- return true;\r
-}\r
-\r
-void Shutdown()\r
-{\r
- if(MultiPartHandler)\r
- delete MultiPartHandler;\r
- if(Outposts)\r
- delete Outposts;\r
- if(LuaEngine)\r
- delete LuaEngine;\r
- if(Terminal)\r
- delete Terminal;\r
- if(WorldActors)\r
- delete WorldActors;\r
- if(NPCManager)\r
- delete NPCManager;\r
- if(ISC)\r
- {\r
- ISC->Shutdown();\r
- delete ISC;\r
- }\r
- if(Server)\r
- Server->Shutdown();\r
- if(GameServer)\r
- delete GameServer;\r
- if(Chat)\r
- delete Chat;\r
- if(Server)\r
- delete Server;\r
- if(Filesystem)\r
- delete Filesystem;\r
- if(GameDefs)\r
- delete GameDefs;\r
- if(Worlds)\r
- {\r
- Worlds->Shutdown();\r
- delete Worlds;\r
- }\r
- if(Subway)\r
- delete Subway;\r
- if(Chars)\r
- delete Chars;\r
- if(MySQL)\r
- delete MySQL;\r
- if(Config)\r
- delete Config;\r
- if(Console)\r
- delete Console;\r
- if(ServerSock)\r
- delete ServerSock;\r
-\r
- exit(0);\r
-}\r
+#include <cstring>
+#include "GameServer/Includes.hxx"
+#include "GameServer/Definitions/Includes.hxx"
+#include "Common/Includes.hxx"
+
+// TODO: - Get logfile name from config file
+
+const char ServerVersion[] = TINNS_GAME_VERSION;
+const char SVNRevision[] = TINNS_SVN_REVISION;
+
+PVehicles *Vehicles = 0;
+PMySQL *MySQL = 0;
+PConsole *Console = 0;
+PServer *Server = 0;
+PConfig *Config = 0;
+PConfig *CmdAccess = 0;
+PGameDefs *GameDefs = 0;
+PChars *Chars = 0;
+PFileSystem *Filesystem = 0;
+PGameServer *GameServer = 0;
+ServerSocket *ServerSock = 0;
+PMsgBuilder *MsgBuilder = 0;
+PWorlds *Worlds = 0;
+PAppartements* Appartements = 0;
+PWorldActors* WorldActors = 0;
+PNPCManager* NPCManager = 0;
+PSubway* Subway = 0;
+PTerminal* Terminal = 0;
+PLuaEngine* LuaEngine = 0;
+POutpost* Outposts = 0;
+PMultiPart* MultiPartHandler = 0;
+
+//multi-user chat implementation
+PClientManager *ClientManager = 0;
+PChat *Chat = 0;
+PCommands *GameCommands = 0;
+
+PISC *ISC = 0;
+
+const std::string EmptyString;
+
+// Development debug output control (set by config option dev_debug)
+bool gDevDebug = false;
+
+bool InitTinNS()
+{
+ Console = new PConsole("log/gameserver.log"); // Make that from config file !!!
+ Console->Print("Starting TinNS Gameserver");
+ Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\");
+ Console->Print(WHITE, BLUE, "| TinNS (TinNS is not a Neocron Server) |");
+ Console->Print(WHITE, BLUE, "| Copyright (C) 2005 Linux Addicted Community |");
+ Console->Print(WHITE, BLUE, "| maintainer Akiko <akiko@gmx.org> |");
+ Console->Print(WHITE, BLUE, "| ========================================== |");
+ Console->Print(WHITE, BLUE, "| Head coders: The packet analyzing team: |");
+ Console->Print(WHITE, BLUE, "| - Akiko - MaxxJag |");
+ Console->Print(WHITE, BLUE, "| - bakkdoor - Sting |");
+ Console->Print(WHITE, BLUE, "| - Namikon - Balm |");
+ Console->Print(WHITE, BLUE, "| - Hammag |");
+ Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");
+ Console->Print(WHITE, BLUE, "| This project would'nt be at its current stage without the help |");
+ Console->Print(WHITE, BLUE, "| from the NeoPolis team, special thanks to you guys! |");
+ Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");
+ Console->Print(WHITE, BLUE, "| This project is under GPL, see any source file for more details |");
+ Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/");
+
+ //char svnrev[10];
+ //GetSVNRev(svnrev);
+ Console->LPrint("You are running TinNS Gameserver version");
+ Console->LPrint(GREEN, BLACK, " %s", ServerVersion);
+ Console->LPrint(WHITE, BLACK, " - SVN Rev");
+ Console->LPrint(GREEN, BLACK, " %s", SVNRevision);
+ Console->LClose();
+
+ Config = new PConfig();
+ if(!Config->LoadOptions(GameConfigTemplate, "./conf/gameserver.conf"))
+ return false; //Shutdown();
+
+ CmdAccess = new PConfig();
+ if(!CmdAccess->LoadOptions(CommandsTemplate, "./conf/commands.conf"))
+ return false; //Shutdown();
+
+ gDevDebug = Config->GetOptionInt("dev_debug");
+ std::string MyName = Config->GetOption("server_name");
+ std::string IP = Config->GetOption("server_ip");
+ char myCname[100], myCip[100];
+ strncpy (myCname, Console->ColorText(CYAN, BLACK, MyName.c_str()), 100);
+ strncpy (myCip, Console->ColorText(CYAN, BLACK, IP.c_str()), 100);
+ Console->Print("My name is '%s', and my address is %s", myCname, myCip);
+
+ MySQL = new PMySQL();
+ if(MySQL->Connect() == false)
+ return false; //Shutdown();
+
+ Filesystem = new PFileSystem();
+
+ GameDefs = new PGameDefs();
+ GameDefs->Init();
+
+ Worlds = new PWorlds();
+ Worlds->LoadWorlds();
+
+ WorldActors = new PWorldActors();
+ LuaEngine = new PLuaEngine();
+
+ NPCManager = new PNPCManager();
+ Appartements = new PAppartements;
+ Subway = new PSubway;
+
+ if (!PAccount::SetUsernameRegexFilter(Config->GetOption("username_filter").c_str()))
+ {
+ Console->Print("%s Could not creat username_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("username_filter").c_str());
+ return false;
+ }
+ if(!PAccount::SetPasswordRegexFilter(Config->GetOption("password_filter").c_str()))
+ {
+ Console->Print("%s Could not creat password_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("password_filter").c_str());
+ return false;
+ }
+
+ if (!PChar::SetCharnameRegexFilter(Config->GetOption("charname_filter").c_str()))
+ {
+ Console->Print("%s Could not creat charname_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("charname_filter").c_str());
+ return false;
+ }
+ Chars = new PChars();
+
+ ServerSock = new ServerSocket();
+ Server = new PServer();
+ GameServer = new PGameServer();
+ MsgBuilder = new PMsgBuilder();
+
+ Vehicles = new PVehicles();
+
+ ClientManager = new PClientManager();
+ Chat = new PChat();
+ GameCommands = new PCommands();
+
+ ISC = new PISC();
+ Terminal = new PTerminal();
+
+ Outposts = new POutpost();
+
+ MultiPartHandler = new PMultiPart();
+
+ return true;
+}
+
+void Shutdown()
+{
+ if(MultiPartHandler)
+ delete MultiPartHandler;
+ if(Outposts)
+ delete Outposts;
+ if(LuaEngine)
+ delete LuaEngine;
+ if(Terminal)
+ delete Terminal;
+ if(WorldActors)
+ delete WorldActors;
+ if(NPCManager)
+ delete NPCManager;
+ if(ISC)
+ {
+ ISC->Shutdown();
+ delete ISC;
+ }
+ if(Server)
+ Server->Shutdown();
+ if(GameServer)
+ delete GameServer;
+ if(Chat)
+ delete Chat;
+ if(Server)
+ delete Server;
+ if(Filesystem)
+ delete Filesystem;
+ if(GameDefs)
+ delete GameDefs;
+ if(Worlds)
+ {
+ Worlds->Shutdown();
+ delete Worlds;
+ }
+ if(Subway)
+ delete Subway;
+ if(Chars)
+ delete Chars;
+ if(MySQL)
+ delete MySQL;
+ if(Config)
+ delete Config;
+ if(Console)
+ delete Console;
+ if(ServerSock)
+ delete ServerSock;
+
+ exit(0);
+}
-#pragma once\r
-\r
-#include "GameServer/Accounts.hxx"\r
-#include "GameServer/Appartements.hxx"\r
-#include "GameServer/BuddyList.hxx"\r
-#include "GameServer/Chars.hxx"\r
-#include "GameServer/Chat.hxx"\r
-#include "GameServer/Client.hxx"\r
-#include "GameServer/ClientManager.hxx"\r
-#include "GameServer/Commands.hxx"\r
-#include "GameServer/ConfigTemplate.hxx"\r
-#include "GameServer/Container.hxx"\r
-#include "GameServer/DoorTemplate.hxx"\r
-#include "GameServer/FurnitureTemplate.hxx"\r
-#include "GameServer/GameScript.hxx"\r
-#include "GameServer/GameServer.hxx"\r
-#include "GameServer/GenrepList.hxx"\r
-#include "GameServer/Inventory.hxx"\r
-#include "GameServer/Isc.hxx"\r
-#include "GameServer/Item.hxx"\r
-#include "GameServer/LuaEngine.hxx"\r
-#include "GameServer/Main.hxx"\r
-#include "GameServer/MessageBuilder.hxx"\r
-#include "GameServer/MultiPart.hxx"\r
-#include "GameServer/Npc.hxx"\r
-#include "GameServer/NpcTemplate.hxx"\r
-#include "GameServer/Outpost.hxx"\r
-#include "GameServer/RemoteConsole.hxx"\r
-#include "GameServer/Server.hxx"\r
-#include "GameServer/Skill.hxx"\r
-#include "GameServer/Sql.hxx"\r
-#include "GameServer/Subway.hxx"\r
-#include "GameServer/Terminal.hxx"\r
-#include "GameServer/Vehicle.hxx"\r
-#include "GameServer/VehicleAccessRequest.hxx"\r
-#include "GameServer/WorldActors.hxx"\r
-#include "GameServer/WorldDataTemplate.hxx"\r
-#include "GameServer/Worlds.hxx"\r
-#include "GameServer/Zoning.hxx"\r
-\r
-extern class PLuaEngine *LuaEngine;\r
-\r
-extern class ServerSocket *ServerSock;\r
-extern class PConsole *Console;\r
-//extern class PRConsole *RemoteConsole;\r
-extern class PConfig *Config;\r
-extern class PConfig *CmdAccess;\r
-\r
-extern class PGameDefs *GameDefs;\r
-extern class PFileSystem *Filesystem;\r
-extern class PServer *Server;\r
-\r
-extern class PGameServer *GameServer;\r
-extern class PChars *Chars;\r
-\r
-extern class PMsgBuilder *MsgBuilder;\r
-extern class PWorlds *Worlds;\r
-extern class PAppartements* Appartements;\r
-extern class PWorldActors* WorldActors;\r
-extern class PTerminal* Terminal;\r
-//extern class gmMachine machine; // Virtual Machine instance\r
-\r
-//multiuser chat\r
-extern class PClientManager *ClientManager;\r
-extern class PNPCManager* NPCManager;\r
-extern class PChat *Chat;\r
-extern class PCommands *GameCommands;\r
-\r
-extern class POutpost *Outposts;\r
-extern class PMultiPart *MultiPartHandler;\r
-\r
-// Development debug output control\r
-extern bool gDevDebug;\r
-\r
-//MySQL-Support\r
-extern class PMySQL* MySQL;\r
-\r
-//Vehicles\r
-extern class PVehicles *Vehicles;\r
-extern class PSubway* Subway;\r
-\r
-//Infoserver update\r
-extern class PISC *ISC;\r
-\r
-extern const char ServerVersion[];\r
-extern const char SVNRevision[];\r
-\r
-bool InitTinNS();\r
-void Shutdown();\r
+#pragma once
+
+#include "GameServer/Accounts.hxx"
+#include "GameServer/Appartements.hxx"
+#include "GameServer/BuddyList.hxx"
+#include "GameServer/Chars.hxx"
+#include "GameServer/Chat.hxx"
+#include "GameServer/Client.hxx"
+#include "GameServer/ClientManager.hxx"
+#include "GameServer/Commands.hxx"
+#include "GameServer/ConfigTemplate.hxx"
+#include "GameServer/Container.hxx"
+#include "GameServer/DoorTemplate.hxx"
+#include "GameServer/FurnitureTemplate.hxx"
+#include "GameServer/GameScript.hxx"
+#include "GameServer/GameServer.hxx"
+#include "GameServer/GenrepList.hxx"
+#include "GameServer/Inventory.hxx"
+#include "GameServer/Isc.hxx"
+#include "GameServer/Item.hxx"
+#include "GameServer/LuaEngine.hxx"
+#include "GameServer/Main.hxx"
+#include "GameServer/MessageBuilder.hxx"
+#include "GameServer/MultiPart.hxx"
+#include "GameServer/Npc.hxx"
+#include "GameServer/NpcTemplate.hxx"
+#include "GameServer/Outpost.hxx"
+#include "GameServer/RemoteConsole.hxx"
+#include "GameServer/Server.hxx"
+#include "GameServer/Skill.hxx"
+#include "GameServer/Sql.hxx"
+#include "GameServer/Subway.hxx"
+#include "GameServer/Terminal.hxx"
+#include "GameServer/Vehicle.hxx"
+#include "GameServer/VehicleAccessRequest.hxx"
+#include "GameServer/WorldActors.hxx"
+#include "GameServer/WorldDataTemplate.hxx"
+#include "GameServer/Worlds.hxx"
+#include "GameServer/Zoning.hxx"
+
+extern class PLuaEngine *LuaEngine;
+
+extern class ServerSocket *ServerSock;
+extern class PConsole *Console;
+//extern class PRConsole *RemoteConsole;
+extern class PConfig *Config;
+extern class PConfig *CmdAccess;
+
+extern class PGameDefs *GameDefs;
+extern class PFileSystem *Filesystem;
+extern class PServer *Server;
+
+extern class PGameServer *GameServer;
+extern class PChars *Chars;
+
+extern class PMsgBuilder *MsgBuilder;
+extern class PWorlds *Worlds;
+extern class PAppartements* Appartements;
+extern class PWorldActors* WorldActors;
+extern class PTerminal* Terminal;
+//extern class gmMachine machine; // Virtual Machine instance
+
+//multiuser chat
+extern class PClientManager *ClientManager;
+extern class PNPCManager* NPCManager;
+extern class PChat *Chat;
+extern class PCommands *GameCommands;
+
+extern class POutpost *Outposts;
+extern class PMultiPart *MultiPartHandler;
+
+// Development debug output control
+extern bool gDevDebug;
+
+//MySQL-Support
+extern class PMySQL* MySQL;
+
+//Vehicles
+extern class PVehicles *Vehicles;
+extern class PSubway* Subway;
+
+//Infoserver update
+extern class PISC *ISC;
+
+extern const char ServerVersion[];
+extern const char SVNRevision[];
+
+bool InitTinNS();
+void Shutdown();
-#include "GameServer/Includes.hxx"\r
-\r
-/* --- PInventory class --- */\r
-\r
-PInventory::PInventory ()\r
-{\r
- mWorn = new PContainerWithHoles(INV_WORN_MAXSLOTS);\r
- //mBackpack = new PContainer2D();\r
- mBackpack = new PContainer2DWorkaround(); // until Inside-Backpack item moving issues are solved\r
- mBackpack->Set2DPosMax(INV_BACKPACK_COLS);\r
- mGogo = new PContainerAutoFindFree(INV_GOGO_MAXSLOTS);\r
-}\r
-\r
-PInventory::~PInventory ()\r
-{\r
- delete mWorn;\r
- delete mBackpack;\r
- delete mGogo;\r
-}\r
-\r
-void PInventory::SetCharId(uint32_t CharID)\r
-{\r
- mWorn->SetInfo(CharID, INV_DB_LOC_WORN);\r
- mBackpack->SetInfo(CharID, INV_DB_LOC_BACKPACK);\r
- mGogo->SetInfo(CharID, INV_DB_LOC_GOGO);\r
-}\r
-\r
-bool PInventory::SQLLoad()\r
-{\r
- return ( mWorn->SQLLoad() && mBackpack->SQLLoad() && mGogo->SQLLoad() );\r
-\r
-/*bool ret = mWorn->SQLLoad() && mBackpack->SQLLoad() && mGogo->SQLLoad();\r
-Console->Print(YELLOW, BLACK, "--- Worn Inventory ---");\r
-mWorn->Dump();\r
-Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---");\r
-mBackpack->Dump();\r
-Console->Print(YELLOW, BLACK, "--- Gogo Inventory ---");\r
-mGogo->Dump();\r
-Console->Print(YELLOW, BLACK, "--- End Inventory ---");\r
-return ret;*/\r
-}\r
-\r
-bool PInventory::SQLSave()\r
-{\r
- return mWorn->SQLSave() && mBackpack->SQLSave() && mGogo->SQLSave();\r
-}\r
-\r
-bool PInventory::IsDirty() const\r
-{\r
- return (mWorn && mWorn->IsDirty()) || (mBackpack && mBackpack->IsDirty()) || (mGogo && mGogo->IsDirty());\r
-}\r
-\r
-PContainer* PInventory::GetContainer(uint8_t nInvLoc)\r
-{\r
- PContainer* tContainer;\r
- switch(nInvLoc)\r
- {\r
- case INV_LOC_WORN:\r
- tContainer = mWorn;\r
- break;\r
- case INV_LOC_BACKPACK:\r
- tContainer = mBackpack;\r
- break;\r
- case INV_LOC_GOGO:\r
- tContainer = mGogo;\r
- break;\r
- default:\r
- tContainer = NULL;\r
- }\r
- return tContainer;\r
-}\r
-\r
-bool PInventory::AddItem(PItem *NewItem, uint8_t nInvLoc, uint32_t nInvID, uint8_t nPosX, uint8_t nPosY, bool SetDirty)\r
-{\r
- PContainer* destContainer = GetContainer(nInvLoc);\r
- return(destContainer ? destContainer->AddItem(NewItem, nInvID, nPosX, nPosY, SetDirty) : false);\r
-}\r
-\r
-/*\r
-bool PInventory::QB_IsFree(uint8_t nSlot)\r
-{\r
- if(nSlot > 9)\r
- return false;\r
-\r
- // if (gDevDebug) Console->Print("Checking QBSlot %d. Content: %d", nSlot, mQuickAccessBelt[nSlot]);\r
- if(mQuickAccessBelt[nSlot] == 0)\r
- return true;\r
- else\r
- return false;\r
-}\r
-\r
-void PInventory::QB_SetSlot(uint8_t nSlot, uint16_t nItemID)\r
-{\r
- if(nSlot > 9)\r
- return;\r
- // if (gDevDebug) Console->Print("Setting QBSlot %d. Newcontent: %d Oldcontent: %d", nSlot, nItemID, mQuickAccessBelt[nSlot]);\r
- mQuickAccessBelt[nSlot] = nItemID;\r
-}\r
-\r
-uint16_t PInventory::QB_GetSlot(uint8_t nSlot)\r
-{\r
- if(nSlot > 9)\r
- return 0;\r
- // if (gDevDebug) Console->Print("Getting QBSlot %d. Content: %d", nSlot, mQuickAccessBelt[nSlot]);\r
- return mQuickAccessBelt[nSlot];\r
-}\r
-\r
-void PInventory::QB_Move(uint8_t nSlotSRC, uint8_t nSlotDST)\r
-{\r
- if(nSlotSRC > 9 || nSlotDST > 9)\r
- return;\r
-\r
- // if (gDevDebug) Console->Print("Moving QBSlot %d [%d] to %d [%d]", nSlotSRC, mQuickAccessBelt[nSlotSRC], nSlotDST, mQuickAccessBelt[nSlotDST]);\r
- mQuickAccessBelt[nSlotDST] = mQuickAccessBelt[nSlotSRC];\r
- mQuickAccessBelt[nSlotSRC] = 0;\r
- // if (gDevDebug) Console->Print("Moving done. %d [%d] %d [%d]", nSlotSRC, mQuickAccessBelt[nSlotSRC], nSlotDST, mQuickAccessBelt[nSlotDST]);\r
-}\r
-*/\r
+#include "GameServer/Includes.hxx"
+
+/* --- PInventory class --- */
+
+PInventory::PInventory ()
+{
+ mWorn = new PContainerWithHoles(INV_WORN_MAXSLOTS);
+ //mBackpack = new PContainer2D();
+ mBackpack = new PContainer2DWorkaround(); // until Inside-Backpack item moving issues are solved
+ mBackpack->Set2DPosMax(INV_BACKPACK_COLS);
+ mGogo = new PContainerAutoFindFree(INV_GOGO_MAXSLOTS);
+}
+
+PInventory::~PInventory ()
+{
+ delete mWorn;
+ delete mBackpack;
+ delete mGogo;
+}
+
+void PInventory::SetCharId(uint32_t CharID)
+{
+ mWorn->SetInfo(CharID, INV_DB_LOC_WORN);
+ mBackpack->SetInfo(CharID, INV_DB_LOC_BACKPACK);
+ mGogo->SetInfo(CharID, INV_DB_LOC_GOGO);
+}
+
+bool PInventory::SQLLoad()
+{
+ return ( mWorn->SQLLoad() && mBackpack->SQLLoad() && mGogo->SQLLoad() );
+
+/*bool ret = mWorn->SQLLoad() && mBackpack->SQLLoad() && mGogo->SQLLoad();
+Console->Print(YELLOW, BLACK, "--- Worn Inventory ---");
+mWorn->Dump();
+Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---");
+mBackpack->Dump();
+Console->Print(YELLOW, BLACK, "--- Gogo Inventory ---");
+mGogo->Dump();
+Console->Print(YELLOW, BLACK, "--- End Inventory ---");
+return ret;*/
+}
+
+bool PInventory::SQLSave()
+{
+ return mWorn->SQLSave() && mBackpack->SQLSave() && mGogo->SQLSave();
+}
+
+bool PInventory::IsDirty() const
+{
+ return (mWorn && mWorn->IsDirty()) || (mBackpack && mBackpack->IsDirty()) || (mGogo && mGogo->IsDirty());
+}
+
+PContainer* PInventory::GetContainer(uint8_t nInvLoc)
+{
+ PContainer* tContainer;
+ switch(nInvLoc)
+ {
+ case INV_LOC_WORN:
+ tContainer = mWorn;
+ break;
+ case INV_LOC_BACKPACK:
+ tContainer = mBackpack;
+ break;
+ case INV_LOC_GOGO:
+ tContainer = mGogo;
+ break;
+ default:
+ tContainer = NULL;
+ }
+ return tContainer;
+}
+
+bool PInventory::AddItem(PItem *NewItem, uint8_t nInvLoc, uint32_t nInvID, uint8_t nPosX, uint8_t nPosY, bool SetDirty)
+{
+ PContainer* destContainer = GetContainer(nInvLoc);
+ return(destContainer ? destContainer->AddItem(NewItem, nInvID, nPosX, nPosY, SetDirty) : false);
+}
+
+/*
+bool PInventory::QB_IsFree(uint8_t nSlot)
+{
+ if(nSlot > 9)
+ return false;
+
+ // if (gDevDebug) Console->Print("Checking QBSlot %d. Content: %d", nSlot, mQuickAccessBelt[nSlot]);
+ if(mQuickAccessBelt[nSlot] == 0)
+ return true;
+ else
+ return false;
+}
+
+void PInventory::QB_SetSlot(uint8_t nSlot, uint16_t nItemID)
+{
+ if(nSlot > 9)
+ return;
+ // if (gDevDebug) Console->Print("Setting QBSlot %d. Newcontent: %d Oldcontent: %d", nSlot, nItemID, mQuickAccessBelt[nSlot]);
+ mQuickAccessBelt[nSlot] = nItemID;
+}
+
+uint16_t PInventory::QB_GetSlot(uint8_t nSlot)
+{
+ if(nSlot > 9)
+ return 0;
+ // if (gDevDebug) Console->Print("Getting QBSlot %d. Content: %d", nSlot, mQuickAccessBelt[nSlot]);
+ return mQuickAccessBelt[nSlot];
+}
+
+void PInventory::QB_Move(uint8_t nSlotSRC, uint8_t nSlotDST)
+{
+ if(nSlotSRC > 9 || nSlotDST > 9)
+ return;
+
+ // if (gDevDebug) Console->Print("Moving QBSlot %d [%d] to %d [%d]", nSlotSRC, mQuickAccessBelt[nSlotSRC], nSlotDST, mQuickAccessBelt[nSlotDST]);
+ mQuickAccessBelt[nSlotDST] = mQuickAccessBelt[nSlotSRC];
+ mQuickAccessBelt[nSlotSRC] = 0;
+ // if (gDevDebug) Console->Print("Moving done. %d [%d] %d [%d]", nSlotSRC, mQuickAccessBelt[nSlotSRC], nSlotDST, mQuickAccessBelt[nSlotDST]);
+}
+*/
-#pragma once\r
-\r
-#include <cstdint>\r
-\r
-//NC containers message locations\r
-#define INV_LOC_GROUND 1\r
-#define INV_LOC_WORN 2\r
-#define INV_LOC_BACKPACK 3\r
-#define INV_LOC_BOX 4\r
-#define INV_LOC_NPCTRADE 5\r
-#define INV_LOC_GOGO 18\r
-#define INV_LOC_BOX2 255\r
-//PC-Trade window = ?\r
-\r
-//Inventory containers info\r
-#define INV_WORN_QB_START 0\r
-#define INV_WORN_QB_END 9\r
-#define INV_WORN_QB_NONE 99\r
-#define INV_WORN_QB_HAND 11\r
-\r
-#define INV_WORN_PROC_START 12\r
-#define INV_WORN_PROC_END 24\r
-\r
-#define INV_WORN_IMP_START 26\r
-#define INV_WORN_IMP_END 38\r
-\r
-#define INV_WORN_ARMOR_START 39\r
-#define INV_WORN_ARMOR_END 43\r
-\r
-#define INV_WORN_COLS 44\r
-#define INV_WORN_MAXSLOTS 44\r
-\r
-\r
-#define INV_BACKPACK_COLS 10\r
-\r
-#define INV_GOGO_COLS 5\r
-#define INV_GOGO_MAXSLOTS 50\r
-\r
-#define INV_CABINET_COLS 5\r
-#define INV_CABINET_MAXSLOTS 33\r
-\r
-// inv_loc values in database\r
-#define INV_DB_LOC_GOGO 1\r
-#define INV_DB_LOC_WORN 2\r
-#define INV_DB_LOC_BACKPACK 3\r
-\r
-class PItem;\r
-class PContainer;\r
-class PContainerWithHoles;\r
-class PContainer2DWorkaround;\r
-class PContainerAutoFindFree;\r
-\r
-class PInventory\r
-{\r
- private:\r
- PContainerWithHoles* mWorn; // PContainerLinearSlots\r
- PContainer2DWorkaround* mBackpack; // PContainer2DAreas\r
- PContainerAutoFindFree* mGogo; // PContainerLinearSlots\r
-\r
- public:\r
-\r
- PInventory();\r
- ~PInventory();\r
-\r
- void SetCharId(uint32_t CharID);\r
- bool SQLLoad();\r
- bool SQLSave();\r
- PContainer* GetContainer(uint8_t nInvLoc);\r
- inline PContainer2DWorkaround* GetBackpackContainer() { return mBackpack; }\r
-\r
- bool IsDirty() const;\r
-\r
- bool AddItem(PItem* NewItem, uint8_t nInvLoc = INV_LOC_BACKPACK, uint32_t nInvID = 0, uint8_t nPosX = 0, uint8_t nPosY = 0, bool SetDirty = true);\r
- //bool CheckItem(uint32_t ItemID, uint8_t StackSize = 1);\r
- //PItem *GetItem(uint32_t ItemID, uint8_t StackSize = 1);\r
- //PItem *GetItemByPos(uint8_t nPosX, uint8_t nPosY, uint8_t StackSize = 1);\r
- //bool MoveItem(uint8_t oPosX, uint8_t oPosY, uint8_t dPosX, uint8_t dPosY);\r
-\r
- //bool QB_IsFree(uint8_t nSlot);\r
- //void QB_SetSlot(uint8_t nSlot, uint16_t nItemID);\r
- //uint16_t QB_GetSlot(uint8_t nSlot);\r
- //void QB_Move(uint8_t nSlotSRC, uint8_t nSlotDST);\r
-};\r
+#pragma once
+
+#include <cstdint>
+
+//NC containers message locations
+#define INV_LOC_GROUND 1
+#define INV_LOC_WORN 2
+#define INV_LOC_BACKPACK 3
+#define INV_LOC_BOX 4
+#define INV_LOC_NPCTRADE 5
+#define INV_LOC_GOGO 18
+#define INV_LOC_BOX2 255
+//PC-Trade window = ?
+
+//Inventory containers info
+#define INV_WORN_QB_START 0
+#define INV_WORN_QB_END 9
+#define INV_WORN_QB_NONE 99
+#define INV_WORN_QB_HAND 11
+
+#define INV_WORN_PROC_START 12
+#define INV_WORN_PROC_END 24
+
+#define INV_WORN_IMP_START 26
+#define INV_WORN_IMP_END 38
+
+#define INV_WORN_ARMOR_START 39
+#define INV_WORN_ARMOR_END 43
+
+#define INV_WORN_COLS 44
+#define INV_WORN_MAXSLOTS 44
+
+
+#define INV_BACKPACK_COLS 10
+
+#define INV_GOGO_COLS 5
+#define INV_GOGO_MAXSLOTS 50
+
+#define INV_CABINET_COLS 5
+#define INV_CABINET_MAXSLOTS 33
+
+// inv_loc values in database
+#define INV_DB_LOC_GOGO 1
+#define INV_DB_LOC_WORN 2
+#define INV_DB_LOC_BACKPACK 3
+
+class PItem;
+class PContainer;
+class PContainerWithHoles;
+class PContainer2DWorkaround;
+class PContainerAutoFindFree;
+
+class PInventory
+{
+ private:
+ PContainerWithHoles* mWorn; // PContainerLinearSlots
+ PContainer2DWorkaround* mBackpack; // PContainer2DAreas
+ PContainerAutoFindFree* mGogo; // PContainerLinearSlots
+
+ public:
+
+ PInventory();
+ ~PInventory();
+
+ void SetCharId(uint32_t CharID);
+ bool SQLLoad();
+ bool SQLSave();
+ PContainer* GetContainer(uint8_t nInvLoc);
+ inline PContainer2DWorkaround* GetBackpackContainer() { return mBackpack; }
+
+ bool IsDirty() const;
+
+ bool AddItem(PItem* NewItem, uint8_t nInvLoc = INV_LOC_BACKPACK, uint32_t nInvID = 0, uint8_t nPosX = 0, uint8_t nPosY = 0, bool SetDirty = true);
+ //bool CheckItem(uint32_t ItemID, uint8_t StackSize = 1);
+ //PItem *GetItem(uint32_t ItemID, uint8_t StackSize = 1);
+ //PItem *GetItemByPos(uint8_t nPosX, uint8_t nPosY, uint8_t StackSize = 1);
+ //bool MoveItem(uint8_t oPosX, uint8_t oPosY, uint8_t dPosX, uint8_t dPosY);
+
+ //bool QB_IsFree(uint8_t nSlot);
+ //void QB_SetSlot(uint8_t nSlot, uint16_t nItemID);
+ //uint16_t QB_GetSlot(uint8_t nSlot);
+ //void QB_Move(uint8_t nSlotSRC, uint8_t nSlotDST);
+};
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-// TODO: - implement ISC protocol\r
-\r
-PISC::PISC()\r
-{\r
- use_isc = false;\r
- use_mysql = false;\r
-}\r
-\r
-PISC::~PISC()\r
-{\r
-}\r
-\r
-void PISC::Start()\r
-{\r
- isc_method = Config->GetOptionInt("isc_method");\r
-\r
- if(isc_method & 1)\r
- {\r
- Console->Print("%s Infoserver updating over MySQL is enabled", Console->ColorText(GREEN, BLACK, "[Info]"));\r
- use_mysql = true;\r
- }\r
- if(isc_method & 2)\r
- {\r
- Console->Print("%s Infoserver updating over ISC is enabled, update intervall: infoserver: %s", Console->ColorText(GREEN, BLACK, "[Info]"), "?");\r
- use_isc = true;\r
- Console->Print("%s Infoserver updating over ISC not implemented yet. DISABLED", Console->ColorText(YELLOW, BLACK, "[Notice]"));\r
- use_isc = false;\r
- }\r
- if(!(use_isc || use_mysql))\r
- {\r
- Console->Print("%s ISC and MySQL are both disabled, infoserver will NOT be updated", Console->ColorText(YELLOW, BLACK, "[Notice]"));\r
- }\r
-\r
- if (use_isc)\r
- Start_isc();\r
-\r
- if (use_mysql)\r
- Start_mysql();\r
-\r
-}\r
-\r
-void PISC::Update()\r
-{\r
- if (use_isc)\r
- Update_isc();\r
-\r
- if (use_mysql)\r
- Update_mysql();\r
-}\r
-\r
-void PISC::Shutdown()\r
-{\r
- if (use_isc)\r
- {\r
- use_isc = false;\r
- Shutdown_isc();\r
- }\r
-\r
- if (use_mysql)\r
- {\r
- use_mysql = false;\r
- Shutdown_mysql();\r
- }\r
-}\r
-\r
-/*** ISC protocol mode specific ***/\r
-\r
-void PISC::Start_isc()\r
-{\r
- uint16_t Port = Config->GetOptionInt("isc_infoserverport");\r
- if (Port == 0)\r
- {\r
- Console->Print("%s Unable to start ISC, isc_infoserverport setting is invalid");\r
- use_isc = false;\r
- return;\r
- }\r
- Console->Print("Trying to connect to infoserver...", Port);\r
- // Add function for initial connect here and store the connectioninfo somewhere\r
-}\r
-\r
-void PISC::Update_isc()\r
-{\r
-}\r
-\r
-void PISC::Shutdown_isc()\r
-{\r
-}\r
-\r
-/*** IMySQL mode specific ***/\r
-\r
-void PISC::Start_mysql()\r
-{\r
- m_server_id = Config->GetOptionInt("isc_server_id");\r
- mysql_update_intervall = Config->GetOptionInt("isc_update_intervall");\r
- if (mysql_update_intervall < 10)\r
- {\r
- Console->Print("%s value for 'isc_update_intervall' too low (%d). Set to 10 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mysql_update_intervall);\r
- mysql_update_intervall = 10;\r
- }\r
-\r
- mysql_delayed_update_intervall = Config->GetOptionInt("isc_delayed_update_intervall");\r
- if (mysql_delayed_update_intervall < 0)\r
- {\r
- Console->Print("%s value for 'isc_delayed_update_intervall' is invalid (%d). Set to 0 sec (immediate update)", Console->ColorText(YELLOW, BLACK, "[Notice]"), mysql_delayed_update_intervall);\r
- mysql_delayed_update_intervall = 0;\r
- }\r
-\r
- mysql_last_update_time = 0;\r
- mysql_last_client_count = 0;\r
- mysql_last_count_decrease_time = 0;\r
-\r
- Update_mysql();\r
-}\r
-\r
-void PISC::Update_mysql()\r
-{\r
- bool do_update = false;\r
- std::time_t t = std::time(NULL);\r
- int client_count = Server->GetNumClients();\r
-\r
- if (((t - mysql_last_update_time) >= mysql_update_intervall) || (client_count > mysql_last_client_count))\r
- {\r
- do_update = true;\r
-//if(gDevDebug) Console->Print("%s ISC : time or more clients", Console->ColorText(GREEN, BLACK, "[Debug]"));\r
- }\r
- else if (client_count < mysql_last_client_count)\r
- {\r
- if(mysql_last_count_decrease_time && ((t - mysql_last_count_decrease_time) >= mysql_delayed_update_intervall))\r
- {\r
- do_update = true;\r
-//if(gDevDebug) Console->Print("%s ISC : less clients timed out", Console->ColorText(GREEN, BLACK, "[Debug]"));\r
- }\r
- else if (!mysql_last_count_decrease_time)\r
- {\r
- mysql_last_count_decrease_time = t;\r
-//if(gDevDebug) Console->Print("%s ISC : Starting less clients time count", Console->ColorText(GREEN, BLACK, "[Debug]"));\r
- }\r
- }\r
- else if (mysql_last_count_decrease_time && (client_count == mysql_last_client_count))\r
- {\r
- mysql_last_count_decrease_time = 0;\r
-//if(gDevDebug) Console->Print("%s ISC : Canceling less clients time count", Console->ColorText(GREEN, BLACK, "[Debug]")); \r
- }\r
-\r
- if (do_update)\r
- {\r
- do_mysql_db_update(client_count);\r
- mysql_last_client_count = client_count;\r
- mysql_last_count_decrease_time = 0;\r
- mysql_last_update_time = std::time(NULL);\r
- }\r
-}\r
-\r
-void PISC::Shutdown_mysql()\r
-{\r
- use_mysql = false;\r
- do_mysql_db_update(0,true);\r
-}\r
-\r
-bool PISC::do_mysql_db_update(int players, bool shutdown)\r
-{\r
- char query[256];\r
- snprintf (query, 256, "UPDATE `server_list` SET `s_players` = '%d', `s_lastupdate` = %s WHERE `s_id` = %d LIMIT 1;", players, (shutdown ? "'0'" : "NOW()"), m_server_id);\r
-\r
-//if(gDevDebug) Console->Print("%s Updating Infoserver over MySQL.", Console->ColorText(GREEN, BLACK, "[Debug]"));\r
- if(MySQL->InfoQuery(query))\r
- {\r
- use_mysql = false;\r
- Console->Print("%s Could not update Infoserver over MySQL. Updating DISABLED. Error was:", Console->ColorText(RED, BLACK, "[ERROR]"));\r
- MySQL->ShowInfoSQLError();\r
- return false;\r
- }\r
- else\r
- return true;\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+// TODO: - implement ISC protocol
+
+PISC::PISC()
+{
+ use_isc = false;
+ use_mysql = false;
+}
+
+PISC::~PISC()
+{
+}
+
+void PISC::Start()
+{
+ isc_method = Config->GetOptionInt("isc_method");
+
+ if(isc_method & 1)
+ {
+ Console->Print("%s Infoserver updating over MySQL is enabled", Console->ColorText(GREEN, BLACK, "[Info]"));
+ use_mysql = true;
+ }
+ if(isc_method & 2)
+ {
+ Console->Print("%s Infoserver updating over ISC is enabled, update intervall: infoserver: %s", Console->ColorText(GREEN, BLACK, "[Info]"), "?");
+ use_isc = true;
+ Console->Print("%s Infoserver updating over ISC not implemented yet. DISABLED", Console->ColorText(YELLOW, BLACK, "[Notice]"));
+ use_isc = false;
+ }
+ if(!(use_isc || use_mysql))
+ {
+ Console->Print("%s ISC and MySQL are both disabled, infoserver will NOT be updated", Console->ColorText(YELLOW, BLACK, "[Notice]"));
+ }
+
+ if (use_isc)
+ Start_isc();
+
+ if (use_mysql)
+ Start_mysql();
+
+}
+
+void PISC::Update()
+{
+ if (use_isc)
+ Update_isc();
+
+ if (use_mysql)
+ Update_mysql();
+}
+
+void PISC::Shutdown()
+{
+ if (use_isc)
+ {
+ use_isc = false;
+ Shutdown_isc();
+ }
+
+ if (use_mysql)
+ {
+ use_mysql = false;
+ Shutdown_mysql();
+ }
+}
+
+/*** ISC protocol mode specific ***/
+
+void PISC::Start_isc()
+{
+ uint16_t Port = Config->GetOptionInt("isc_infoserverport");
+ if (Port == 0)
+ {
+ Console->Print("%s Unable to start ISC, isc_infoserverport setting is invalid");
+ use_isc = false;
+ return;
+ }
+ Console->Print("Trying to connect to infoserver...", Port);
+ // Add function for initial connect here and store the connectioninfo somewhere
+}
+
+void PISC::Update_isc()
+{
+}
+
+void PISC::Shutdown_isc()
+{
+}
+
+/*** IMySQL mode specific ***/
+
+void PISC::Start_mysql()
+{
+ m_server_id = Config->GetOptionInt("isc_server_id");
+ mysql_update_intervall = Config->GetOptionInt("isc_update_intervall");
+ if (mysql_update_intervall < 10)
+ {
+ Console->Print("%s value for 'isc_update_intervall' too low (%d). Set to 10 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mysql_update_intervall);
+ mysql_update_intervall = 10;
+ }
+
+ mysql_delayed_update_intervall = Config->GetOptionInt("isc_delayed_update_intervall");
+ if (mysql_delayed_update_intervall < 0)
+ {
+ Console->Print("%s value for 'isc_delayed_update_intervall' is invalid (%d). Set to 0 sec (immediate update)", Console->ColorText(YELLOW, BLACK, "[Notice]"), mysql_delayed_update_intervall);
+ mysql_delayed_update_intervall = 0;
+ }
+
+ mysql_last_update_time = 0;
+ mysql_last_client_count = 0;
+ mysql_last_count_decrease_time = 0;
+
+ Update_mysql();
+}
+
+void PISC::Update_mysql()
+{
+ bool do_update = false;
+ std::time_t t = std::time(NULL);
+ int client_count = Server->GetNumClients();
+
+ if (((t - mysql_last_update_time) >= mysql_update_intervall) || (client_count > mysql_last_client_count))
+ {
+ do_update = true;
+//if(gDevDebug) Console->Print("%s ISC : time or more clients", Console->ColorText(GREEN, BLACK, "[Debug]"));
+ }
+ else if (client_count < mysql_last_client_count)
+ {
+ if(mysql_last_count_decrease_time && ((t - mysql_last_count_decrease_time) >= mysql_delayed_update_intervall))
+ {
+ do_update = true;
+//if(gDevDebug) Console->Print("%s ISC : less clients timed out", Console->ColorText(GREEN, BLACK, "[Debug]"));
+ }
+ else if (!mysql_last_count_decrease_time)
+ {
+ mysql_last_count_decrease_time = t;
+//if(gDevDebug) Console->Print("%s ISC : Starting less clients time count", Console->ColorText(GREEN, BLACK, "[Debug]"));
+ }
+ }
+ else if (mysql_last_count_decrease_time && (client_count == mysql_last_client_count))
+ {
+ mysql_last_count_decrease_time = 0;
+//if(gDevDebug) Console->Print("%s ISC : Canceling less clients time count", Console->ColorText(GREEN, BLACK, "[Debug]"));
+ }
+
+ if (do_update)
+ {
+ do_mysql_db_update(client_count);
+ mysql_last_client_count = client_count;
+ mysql_last_count_decrease_time = 0;
+ mysql_last_update_time = std::time(NULL);
+ }
+}
+
+void PISC::Shutdown_mysql()
+{
+ use_mysql = false;
+ do_mysql_db_update(0,true);
+}
+
+bool PISC::do_mysql_db_update(int players, bool shutdown)
+{
+ char query[256];
+ snprintf (query, 256, "UPDATE `server_list` SET `s_players` = '%d', `s_lastupdate` = %s WHERE `s_id` = %d LIMIT 1;", players, (shutdown ? "'0'" : "NOW()"), m_server_id);
+
+//if(gDevDebug) Console->Print("%s Updating Infoserver over MySQL.", Console->ColorText(GREEN, BLACK, "[Debug]"));
+ if(MySQL->InfoQuery(query))
+ {
+ use_mysql = false;
+ Console->Print("%s Could not update Infoserver over MySQL. Updating DISABLED. Error was:", Console->ColorText(RED, BLACK, "[ERROR]"));
+ MySQL->ShowInfoSQLError();
+ return false;
+ }
+ else
+ return true;
+}
-#pragma once\r
-\r
-#include <chrono>\r
-#include <cstdint>\r
-\r
-#define ISC_VER 2\r
-\r
-// Part of mConStatus bitmask\r
-#define ISC_CONNECTED 1\r
-#define ISC_ADMIN 2\r
-\r
-class PISC {\r
- private:\r
- enum PISC_Status\r
- {\r
- ISC_NOTCONNECTED,\r
- ISC_HANDSHAKE01, // "Hello" msg sent, awaiting answer\r
- ISC_HANDSHAKE02, // PW sent, awaiting answer\r
- ISC_GSDATA01, // Servername sent, awaiting answer\r
- ISC_GSDATA02, // IP, Port & Patchlevel sent, awaiting blabla..\r
- ISC_GSDATA03, // Players / Staff onlinecounter sent, ...\r
- ISC_GSDATA04, // Minlevel to connect, minlevel to see Playercount, minlevel to see server sent,....\r
- ISC_CLIENTIDENT, // Awaiting client identification answer\r
- ISC_ADMINLOGIN, // Awaiting answer to Infoserver control login request\r
- ISC_ICTRL_AUTOACC,// Infoserver control: Awaiting response to AutoAccount command\r
- ISC_ICTRL_LOGLV, // Infoserver control: Awaiting response to LoginLevel command\r
- ISC_ICTRL_RELOAD, // Infoserver control: Awaiting response to Reload command\r
- ISC_ICTRL_SHUTD, // Infoserver control: Awaiting response to Shutdown command\r
- ISC_ICTRL_HIDE, // Infoserver control: Awaiting response to HidePeople command\r
- ISC_IDLE // Updateloop running\r
- } mLinkStatus;\r
-\r
- uint16_t mConStatus; // Bitmask of Connection status\r
-\r
- int isc_method;\r
-\r
- bool use_isc;\r
- char isc_pwd;\r
-\r
- bool use_mysql;\r
- int m_server_id;\r
- time_t mysql_update_intervall;\r
- time_t mysql_delayed_update_intervall;\r
- time_t mysql_last_update_time;\r
- int mysql_last_client_count;\r
- time_t mysql_last_count_decrease_time;\r
-\r
- void Start_isc();\r
- void Update_isc();\r
- void Shutdown_isc();\r
-\r
- void Start_mysql();\r
- void Update_mysql();\r
- bool do_mysql_db_update(int players, bool shutdown = false);\r
- void Shutdown_mysql();\r
-\r
- public:\r
- PISC();\r
- ~PISC();\r
-\r
- void Start();\r
- void Update();\r
- void Shutdown();\r
-};\r
+#pragma once
+
+#include <chrono>
+#include <cstdint>
+
+#define ISC_VER 2
+
+// Part of mConStatus bitmask
+#define ISC_CONNECTED 1
+#define ISC_ADMIN 2
+
+class PISC {
+ private:
+ enum PISC_Status
+ {
+ ISC_NOTCONNECTED,
+ ISC_HANDSHAKE01, // "Hello" msg sent, awaiting answer
+ ISC_HANDSHAKE02, // PW sent, awaiting answer
+ ISC_GSDATA01, // Servername sent, awaiting answer
+ ISC_GSDATA02, // IP, Port & Patchlevel sent, awaiting blabla..
+ ISC_GSDATA03, // Players / Staff onlinecounter sent, ...
+ ISC_GSDATA04, // Minlevel to connect, minlevel to see Playercount, minlevel to see server sent,....
+ ISC_CLIENTIDENT, // Awaiting client identification answer
+ ISC_ADMINLOGIN, // Awaiting answer to Infoserver control login request
+ ISC_ICTRL_AUTOACC,// Infoserver control: Awaiting response to AutoAccount command
+ ISC_ICTRL_LOGLV, // Infoserver control: Awaiting response to LoginLevel command
+ ISC_ICTRL_RELOAD, // Infoserver control: Awaiting response to Reload command
+ ISC_ICTRL_SHUTD, // Infoserver control: Awaiting response to Shutdown command
+ ISC_ICTRL_HIDE, // Infoserver control: Awaiting response to HidePeople command
+ ISC_IDLE // Updateloop running
+ } mLinkStatus;
+
+ uint16_t mConStatus; // Bitmask of Connection status
+
+ int isc_method;
+
+ bool use_isc;
+ char isc_pwd;
+
+ bool use_mysql;
+ int m_server_id;
+ time_t mysql_update_intervall;
+ time_t mysql_delayed_update_intervall;
+ time_t mysql_last_update_time;
+ int mysql_last_client_count;
+ time_t mysql_last_count_decrease_time;
+
+ void Start_isc();
+ void Update_isc();
+ void Shutdown_isc();
+
+ void Start_mysql();
+ void Update_mysql();
+ bool do_mysql_db_update(int players, bool shutdown = false);
+ void Shutdown_mysql();
+
+ public:
+ PISC();
+ ~PISC();
+
+ void Start();
+ void Update();
+ void Shutdown();
+};
-#include "GameServer/Includes.hxx"\r
-#include "GameServer/Definitions/Includes.hxx"\r
-\r
-PItem::PItem(uint32_t ItemID, uint8_t nStackSize, uint8_t CurDur, uint8_t MaxDur, uint8_t Dmg, uint8_t Freq, uint8_t Hand, uint8_t Rng)\r
-{\r
- mDefItem = GameDefs->Items()->GetDef(ItemID);\r
- if (mDefItem) {\r
- mItemID = ItemID;\r
- mStackable = mDefItem->IsStackable();\r
- mStackSize = mStackable ? nStackSize : 1;\r
-\r
- mLoadedAmmoId = 0;\r
- mLoadedAmmoNb = 0;\r
-\r
- mPropertiesFlags = 0;\r
-\r
- mUsedSlots = mMaxSlots = 0;\r
- mModificators = 0;\r
-\r
- mConstructorId = 0;\r
- //mType = mDefItem->GetType();\r
- //mValue1 = mDefItem->GetValue1();\r
- //mValue2 = mDefItem->GetValue2();\r
- //mValue3 = mDefItem->GetValue3();\r
- //mSizeX = mDefItem->GetSizeX();\r
- //mSizeY = mDefItem->GetSizeY();\r
- //mWeight = mDefItem->GetWeight();\r
- //mFillWeight = mDefItem->GetFillWeight();\r
- //mQualifier = mDefItem->GetQualifier();\r
- //mItemGroupID = mDefItem->GetItemGroupID();\r
- //mBasePrice = mDefItem->GetBasePrice();\r
- //mTechlevel = mDefItem->GetTechlevel();\r
- //mItemflags = mDefItem->GetItemflags();\r
-\r
- //if (!mStackable) // only non-stackable items can have quality stats (?)\r
- //{\r
- // mStackSize = 1;\r
- mCurDuration = CurDur;\r
- mMaxDuration = MaxDur;\r
- mDamages = Dmg;\r
- mFrequency = Freq;\r
- mHandling = Hand;\r
- mRange = Rng;\r
- //}\r
- }\r
- else\r
- {\r
- mItemID = 0;\r
- Console->Print(YELLOW, BLACK, "PItem::PItem: Invalid item ID %d", ItemID);\r
- }\r
-}\r
-\r
-void PItem::MakeItemStandard(uint8_t GlobalQualityMin, uint8_t GlobalQualityMax)\r
-{\r
- if(GlobalQualityMin > GlobalQualityMax) GlobalQualityMin = GlobalQualityMax;\r
-\r
- mCurDuration = 255;\r
- mMaxDuration = 255;\r
- if(GlobalQualityMin == GlobalQualityMax)\r
- {\r
- mDamages = GlobalQualityMin;\r
- mFrequency = GlobalQualityMin;\r
- mHandling = GlobalQualityMin;\r
- mRange = GlobalQualityMin;\r
- }\r
- else\r
- {\r
- mDamages = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin);\r
- mFrequency = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin);\r
- mHandling = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin);\r
- mRange = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin);\r
- }\r
-}\r
-\r
-uint32_t PItem::GetItemID()\r
-{\r
- return mItemID;\r
-}\r
-\r
-int PItem::GetType()\r
-{\r
- return mDefItem->GetType();\r
-}\r
-\r
-uint8_t PItem::GetItemflags()\r
-{\r
- return mDefItem->GetItemflags();\r
-}\r
-\r
-const std::string &PItem::GetName() const\r
-{\r
- return mDefItem->GetName();\r
-}\r
-\r
-uint8_t PItem::GetSizeX()\r
-{\r
- return mDefItem->GetSizeX();\r
-}\r
-\r
-uint8_t PItem::GetSizeY()\r
-{\r
- return mDefItem->GetSizeY();\r
-}\r
-\r
-float PItem::GetWeight()\r
-{\r
- return mStackSize * mDefItem->GetWeight();\r
-}\r
-\r
-float PItem::GetSingleUnitWeight()\r
-{\r
- return mDefItem->GetWeight();\r
-}\r
-\r
-float PItem::GetFillWeight()\r
-{\r
- return mDefItem->GetFillWeight();\r
-}\r
-\r
-uint32_t PItem::GetBasePrice()\r
-{\r
- return mDefItem->GetBasePrice();\r
-}\r
-\r
-uint16_t PItem::GetTechlevel()\r
-{\r
- return mDefItem->GetTechlevel();\r
-}\r
-\r
-int PItem::GetValue1()\r
-{\r
- return mDefItem->GetValue1();\r
-}\r
-\r
-int PItem::GetValue2()\r
-{\r
- return mDefItem->GetValue2();\r
-}\r
-\r
-int PItem::GetValue3()\r
-{\r
- return mDefItem->GetValue3();\r
-}\r
-\r
-int PItem::GetQualifier()\r
-{\r
- return mDefItem->GetQualifier();\r
-}\r
-\r
-bool PItem::IsStackable()\r
-{\r
- return mDefItem->IsStackable();\r
-}\r
-\r
-uint8_t PItem::GetStackSize()\r
-{\r
- return mStackSize;\r
-}\r
-\r
-uint8_t PItem::AddToStack(uint8_t ItemNb) // returns nb of items not added\r
-{\r
- uint8_t addedItems = 0;\r
- if (mStackable)\r
- {\r
- addedItems = (ItemNb <= (MAX_ITEMSTACK_SIZE - mStackSize)) ? ItemNb : (MAX_ITEMSTACK_SIZE - mStackSize);\r
- mStackSize += addedItems;\r
- }\r
- return (ItemNb - addedItems);\r
-}\r
-\r
-uint8_t PItem::TakeFromStack(uint8_t ItemNb)\r
-{\r
- uint8_t retreivedItems = 0;\r
- if (mStackable)\r
- {\r
- retreivedItems = std::min(mStackSize, ItemNb);\r
- mStackSize -= retreivedItems;\r
- }\r
- return retreivedItems;\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "GameServer/Definitions/Includes.hxx"
+
+PItem::PItem(uint32_t ItemID, uint8_t nStackSize, uint8_t CurDur, uint8_t MaxDur, uint8_t Dmg, uint8_t Freq, uint8_t Hand, uint8_t Rng)
+{
+ mDefItem = GameDefs->Items()->GetDef(ItemID);
+ if (mDefItem) {
+ mItemID = ItemID;
+ mStackable = mDefItem->IsStackable();
+ mStackSize = mStackable ? nStackSize : 1;
+
+ mLoadedAmmoId = 0;
+ mLoadedAmmoNb = 0;
+
+ mPropertiesFlags = 0;
+
+ mUsedSlots = mMaxSlots = 0;
+ mModificators = 0;
+
+ mConstructorId = 0;
+ //mType = mDefItem->GetType();
+ //mValue1 = mDefItem->GetValue1();
+ //mValue2 = mDefItem->GetValue2();
+ //mValue3 = mDefItem->GetValue3();
+ //mSizeX = mDefItem->GetSizeX();
+ //mSizeY = mDefItem->GetSizeY();
+ //mWeight = mDefItem->GetWeight();
+ //mFillWeight = mDefItem->GetFillWeight();
+ //mQualifier = mDefItem->GetQualifier();
+ //mItemGroupID = mDefItem->GetItemGroupID();
+ //mBasePrice = mDefItem->GetBasePrice();
+ //mTechlevel = mDefItem->GetTechlevel();
+ //mItemflags = mDefItem->GetItemflags();
+
+ //if (!mStackable) // only non-stackable items can have quality stats (?)
+ //{
+ // mStackSize = 1;
+ mCurDuration = CurDur;
+ mMaxDuration = MaxDur;
+ mDamages = Dmg;
+ mFrequency = Freq;
+ mHandling = Hand;
+ mRange = Rng;
+ //}
+ }
+ else
+ {
+ mItemID = 0;
+ Console->Print(YELLOW, BLACK, "PItem::PItem: Invalid item ID %d", ItemID);
+ }
+}
+
+void PItem::MakeItemStandard(uint8_t GlobalQualityMin, uint8_t GlobalQualityMax)
+{
+ if(GlobalQualityMin > GlobalQualityMax) GlobalQualityMin = GlobalQualityMax;
+
+ mCurDuration = 255;
+ mMaxDuration = 255;
+ if(GlobalQualityMin == GlobalQualityMax)
+ {
+ mDamages = GlobalQualityMin;
+ mFrequency = GlobalQualityMin;
+ mHandling = GlobalQualityMin;
+ mRange = GlobalQualityMin;
+ }
+ else
+ {
+ mDamages = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin);
+ mFrequency = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin);
+ mHandling = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin);
+ mRange = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin);
+ }
+}
+
+uint32_t PItem::GetItemID()
+{
+ return mItemID;
+}
+
+int PItem::GetType()
+{
+ return mDefItem->GetType();
+}
+
+uint8_t PItem::GetItemflags()
+{
+ return mDefItem->GetItemflags();
+}
+
+const std::string &PItem::GetName() const
+{
+ return mDefItem->GetName();
+}
+
+uint8_t PItem::GetSizeX()
+{
+ return mDefItem->GetSizeX();
+}
+
+uint8_t PItem::GetSizeY()
+{
+ return mDefItem->GetSizeY();
+}
+
+float PItem::GetWeight()
+{
+ return mStackSize * mDefItem->GetWeight();
+}
+
+float PItem::GetSingleUnitWeight()
+{
+ return mDefItem->GetWeight();
+}
+
+float PItem::GetFillWeight()
+{
+ return mDefItem->GetFillWeight();
+}
+
+uint32_t PItem::GetBasePrice()
+{
+ return mDefItem->GetBasePrice();
+}
+
+uint16_t PItem::GetTechlevel()
+{
+ return mDefItem->GetTechlevel();
+}
+
+int PItem::GetValue1()
+{
+ return mDefItem->GetValue1();
+}
+
+int PItem::GetValue2()
+{
+ return mDefItem->GetValue2();
+}
+
+int PItem::GetValue3()
+{
+ return mDefItem->GetValue3();
+}
+
+int PItem::GetQualifier()
+{
+ return mDefItem->GetQualifier();
+}
+
+bool PItem::IsStackable()
+{
+ return mDefItem->IsStackable();
+}
+
+uint8_t PItem::GetStackSize()
+{
+ return mStackSize;
+}
+
+uint8_t PItem::AddToStack(uint8_t ItemNb) // returns nb of items not added
+{
+ uint8_t addedItems = 0;
+ if (mStackable)
+ {
+ addedItems = (ItemNb <= (MAX_ITEMSTACK_SIZE - mStackSize)) ? ItemNb : (MAX_ITEMSTACK_SIZE - mStackSize);
+ mStackSize += addedItems;
+ }
+ return (ItemNb - addedItems);
+}
+
+uint8_t PItem::TakeFromStack(uint8_t ItemNb)
+{
+ uint8_t retreivedItems = 0;
+ if (mStackable)
+ {
+ retreivedItems = std::min(mStackSize, ItemNb);
+ mStackSize -= retreivedItems;
+ }
+ return retreivedItems;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-\r
-class PDefItems;\r
-\r
-// TODO: Add CreatorID (for "named" item), CurrentMunitionID, CurrentMunitionNb (for weapons & charge-items: muns,\r
-// medkit, etc.) to DB, equipped/free slots, & corresponding code\r
-\r
-#define MAX_ITEMSTACK_SIZE 250\r
-\r
-//Type\r
-#define ITEM_TYPE_VARIOUS 0\r
-#define ITEM_TYPE_WEAPON 1\r
-#define ITEM_TYPE_AMMO 2\r
-#define ITEM_TYPE_HEALTH 3\r
-#define ITEM_TYPE_IMPLANT 4\r
-#define ITEM_TYPE_DRUG 5\r
-#define ITEM_TYPE_MOD 6\r
-#define ITEM_TYPE_GFXMOD 7\r
-#define ITEM_TYPE_BLUEPRINT 8\r
-#define ITEM_TYPE_ARMOR 9\r
-#define ITEM_TYPE_PSIMOD 10\r
-#define ITEM_TYPE_PSIMODREADY 11\r
-#define ITEM_TYPE_REPAIR 12\r
-#define ITEM_TYPE_RECYCLER 13\r
-#define ITEM_TYPE_DATACUBE 14\r
-#define ITEM_TYPE_CONSTRUCTOR 15\r
-#define ITEM_TYPE_RESEARCHER 16\r
-#define ITEM_TYPE_IMPLANTER 17\r
-#define ITEM_TYPE_APARTMENTKEY 18\r
-#define ITEM_TYPE_CLANKEY 19\r
-#define ITEM_TYPE_CASHCUBE 20\r
-#define ITEM_TYPE_AUTOWEAPON 21\r
-#define ITEM_TYPE_VHCKEY 22\r
-#define ITEM_TYPE_UNIDENTPART 24\r
-#define ITEM_TYPE_WRECKEDPART 25\r
-#define ITEM_TYPE_SALVAGE 26\r
-#define ITEM_TYPE_VHCCOMPONENT 27\r
-#define ITEM_TYPE_RECORDABLE 28\r
-\r
-// gfxmodflags\r
-#define ITEM_MOD_FLASHLIGHT 1\r
-#define ITEM_MOD_SCOP 2\r
-#define ITEM_MOD_SILENCER 4\r
-#define ITEM_MOD_LASERPOINTER 8\r
-\r
-// itemflags:\r
-#define ITEM_FLAG_RESEARCHABLE 1\r
-#define ITEM_FLAG_NO_DROP 2\r
-#define ITEM_FLAG_NO_MAX_REPAIRE_DECAY 4\r
-#define ITEM_FLAG_AMMO 8 // for loadable ammo\r
-// not sure for ITEM_FLAG_AMMO\r
-\r
-class PItem {\r
- friend class PContainerEntry;\r
- friend class PMsgBuilder;\r
-\r
- private:\r
- uint32_t mItemID;\r
- const PDefItems* mDefItem;\r
-\r
- bool mStackable;\r
- uint8_t mStackSize;\r
-\r
- uint32_t mLoadedAmmoId;\r
- uint8_t mLoadedAmmoNb;\r
-\r
- uint8_t mPropertiesFlags;\r
-\r
- uint8_t mCurDuration;\r
- uint8_t mMaxDuration;\r
- uint8_t mDamages;\r
- uint8_t mFrequency;\r
- uint8_t mHandling;\r
- uint8_t mRange;\r
-\r
- uint8_t mUsedSlots;\r
- uint8_t mMaxSlots;\r
- uint8_t mSlot[5];\r
- uint8_t mModificators;\r
-\r
- uint32_t mConstructorId;\r
-\r
- public:\r
- PItem(uint32_t ItemID, uint8_t nStackSize = 1, uint8_t CurDur = 0, uint8_t MaxDur = 0, uint8_t Dmg = 0, uint8_t Freq = 0, uint8_t Hand = 0, uint8_t Rng = 0);\r
- //~PItem();\r
- void MakeItemStandard(uint8_t GlobalQualityMin = 120, uint8_t GlobalQualityMax = 180);\r
-\r
- uint32_t GetItemID();\r
- int GetType();\r
- uint8_t GetItemflags();\r
- const std::string &GetName() const;\r
- uint8_t GetSizeX();\r
- uint8_t GetSizeY();\r
- float GetWeight();\r
- float GetSingleUnitWeight();\r
- float GetFillWeight();\r
- uint32_t GetBasePrice();\r
- uint16_t GetTechlevel();\r
- int GetValue1();\r
- int GetValue2();\r
- int GetValue3();\r
- int GetQualifier();\r
- bool IsStackable();\r
- uint8_t GetStackSize();\r
- uint8_t AddToStack(uint8_t ItemNb); // return the nb of items NOT added\r
- uint8_t TakeFromStack(uint8_t ItemNb); // return the nb of retreived items\r
-\r
- //mItemGroupID = def->GetItemGroupID();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+class PDefItems;
+
+// TODO: Add CreatorID (for "named" item), CurrentMunitionID, CurrentMunitionNb (for weapons & charge-items: muns,
+// medkit, etc.) to DB, equipped/free slots, & corresponding code
+
+#define MAX_ITEMSTACK_SIZE 250
+
+//Type
+#define ITEM_TYPE_VARIOUS 0
+#define ITEM_TYPE_WEAPON 1
+#define ITEM_TYPE_AMMO 2
+#define ITEM_TYPE_HEALTH 3
+#define ITEM_TYPE_IMPLANT 4
+#define ITEM_TYPE_DRUG 5
+#define ITEM_TYPE_MOD 6
+#define ITEM_TYPE_GFXMOD 7
+#define ITEM_TYPE_BLUEPRINT 8
+#define ITEM_TYPE_ARMOR 9
+#define ITEM_TYPE_PSIMOD 10
+#define ITEM_TYPE_PSIMODREADY 11
+#define ITEM_TYPE_REPAIR 12
+#define ITEM_TYPE_RECYCLER 13
+#define ITEM_TYPE_DATACUBE 14
+#define ITEM_TYPE_CONSTRUCTOR 15
+#define ITEM_TYPE_RESEARCHER 16
+#define ITEM_TYPE_IMPLANTER 17
+#define ITEM_TYPE_APARTMENTKEY 18
+#define ITEM_TYPE_CLANKEY 19
+#define ITEM_TYPE_CASHCUBE 20
+#define ITEM_TYPE_AUTOWEAPON 21
+#define ITEM_TYPE_VHCKEY 22
+#define ITEM_TYPE_UNIDENTPART 24
+#define ITEM_TYPE_WRECKEDPART 25
+#define ITEM_TYPE_SALVAGE 26
+#define ITEM_TYPE_VHCCOMPONENT 27
+#define ITEM_TYPE_RECORDABLE 28
+
+// gfxmodflags
+#define ITEM_MOD_FLASHLIGHT 1
+#define ITEM_MOD_SCOP 2
+#define ITEM_MOD_SILENCER 4
+#define ITEM_MOD_LASERPOINTER 8
+
+// itemflags:
+#define ITEM_FLAG_RESEARCHABLE 1
+#define ITEM_FLAG_NO_DROP 2
+#define ITEM_FLAG_NO_MAX_REPAIRE_DECAY 4
+#define ITEM_FLAG_AMMO 8 // for loadable ammo
+// not sure for ITEM_FLAG_AMMO
+
+class PItem {
+ friend class PContainerEntry;
+ friend class PMsgBuilder;
+
+ private:
+ uint32_t mItemID;
+ const PDefItems* mDefItem;
+
+ bool mStackable;
+ uint8_t mStackSize;
+
+ uint32_t mLoadedAmmoId;
+ uint8_t mLoadedAmmoNb;
+
+ uint8_t mPropertiesFlags;
+
+ uint8_t mCurDuration;
+ uint8_t mMaxDuration;
+ uint8_t mDamages;
+ uint8_t mFrequency;
+ uint8_t mHandling;
+ uint8_t mRange;
+
+ uint8_t mUsedSlots;
+ uint8_t mMaxSlots;
+ uint8_t mSlot[5];
+ uint8_t mModificators;
+
+ uint32_t mConstructorId;
+
+ public:
+ PItem(uint32_t ItemID, uint8_t nStackSize = 1, uint8_t CurDur = 0, uint8_t MaxDur = 0, uint8_t Dmg = 0, uint8_t Freq = 0, uint8_t Hand = 0, uint8_t Rng = 0);
+ //~PItem();
+ void MakeItemStandard(uint8_t GlobalQualityMin = 120, uint8_t GlobalQualityMax = 180);
+
+ uint32_t GetItemID();
+ int GetType();
+ uint8_t GetItemflags();
+ const std::string &GetName() const;
+ uint8_t GetSizeX();
+ uint8_t GetSizeY();
+ float GetWeight();
+ float GetSingleUnitWeight();
+ float GetFillWeight();
+ uint32_t GetBasePrice();
+ uint16_t GetTechlevel();
+ int GetValue1();
+ int GetValue2();
+ int GetValue3();
+ int GetQualifier();
+ bool IsStackable();
+ uint8_t GetStackSize();
+ uint8_t AddToStack(uint8_t ItemNb); // return the nb of items NOT added
+ uint8_t TakeFromStack(uint8_t ItemNb); // return the nb of retreived items
+
+ //mItemGroupID = def->GetItemGroupID();
+};
-#pragma once\r
-\r
-//#include "version.h"\r
-\r
-//basic includes\r
-//#include "include/external.h"\r
-\r
-//tinns includes\r
-//#include "include/types.h"\r
-//#include "common/netcode.h"\r
-/*\r
-#include "../gamemonkey/gmMachine.h"\r
-#include "../gamemonkey/gmCall.h"\r
-*/\r
-//#include "common/console.h"\r
-//#include "common/misc.h"\r
-\r
-// MySQL Support\r
-/*\r
-#ifdef MYSQL_INC_DIR\r
-#include <mysql/mysql.h>\r
-#else\r
-#include <mysql.h>\r
-#endif\r
-\r
-#include "include/sql.h"\r
-\r
-#include "common/config.h"\r
-#include "common/filesystem.h"\r
-#include "include/defparser.h"\r
-\r
-#include "include/skill.h"\r
-#include "include/chars.h"\r
-#include "include/accounts.h"\r
-#include "include/client.h"\r
-#include "include/server.h"\r
-#include "include/gameserver.h"\r
-#include "include/globals.h"\r
-#include "include/defs.h"\r
-#include "include/zoning.h"\r
-#include "include/item.h"\r
-#include "include/inventory.h"\r
-#include "include/worldactors.h"\r
-#include "include/npc.h"\r
-#include "include/outpost.h"\r
-#include "include/multipart.h"\r
-#include "include/terminal.h"\r
-\r
-#include "include/lua_engine.h"\r
-#include "include/chat.h"\r
-#include "include/commands.h"\r
-#include "include/clientmanager.h" */\r
+#pragma once
+
+//#include "version.h"
+
+//basic includes
+//#include "include/external.h"
+
+//tinns includes
+//#include "include/types.h"
+//#include "common/netcode.h"
+/*
+#include "../gamemonkey/gmMachine.h"
+#include "../gamemonkey/gmCall.h"
+*/
+//#include "common/console.h"
+//#include "common/misc.h"
+
+// MySQL Support
+/*
+#ifdef MYSQL_INC_DIR
+#include <mysql/mysql.h>
+#else
+#include <mysql.h>
+#endif
+
+#include "include/sql.h"
+
+#include "common/config.h"
+#include "common/filesystem.h"
+#include "include/defparser.h"
+
+#include "include/skill.h"
+#include "include/chars.h"
+#include "include/accounts.h"
+#include "include/client.h"
+#include "include/server.h"
+#include "include/gameserver.h"
+#include "include/globals.h"
+#include "include/defs.h"
+#include "include/zoning.h"
+#include "include/item.h"
+#include "include/inventory.h"
+#include "include/worldactors.h"
+#include "include/npc.h"
+#include "include/outpost.h"
+#include "include/multipart.h"
+#include "include/terminal.h"
+
+#include "include/lua_engine.h"
+#include "include/chat.h"
+#include "include/commands.h"
+#include "include/clientmanager.h" */
return tmpMsg;
}
-PMessage* PMsgBuilder::BuildReqNPCScriptAnswerMsg( uint32_t nInfoId, std::string *nNPCScript )\r
- {\r
- PMessage* tmpMsg;\r
- \r
- tmpMsg = new PMessage();\r
- \r
- *tmpMsg << ( uint8_t )0x19;\r
- *tmpMsg << ( uint16_t )0x0006; // InfoQuery\r
- *tmpMsg << ( uint16_t )0x0003; // NPC Script\r
- *tmpMsg << ( uint32_t )nInfoId;\r
- *tmpMsg << nNPCScript->c_str();\r
- \r
- return tmpMsg;\r
- \r
- }\r
- \r
-PMessage* PMsgBuilder::BuildYouGotEmailsMsg( PClient* nClient, uint8_t nMailCount )\r
- {\r
- PMessage* tmpMsg = new PMessage();\r
- nClient->IncreaseUDP_ID();\r
- \r
- *tmpMsg << ( uint8_t )0x13;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint16_t )nClient->GetSessionID();\r
- *tmpMsg << ( uint8_t )0x0c;\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint8_t )0x1f;\r
- *tmpMsg << ( uint16_t )nClient->GetLocalID();\r
- *tmpMsg << ( uint8_t )0x3d;\r
- *tmpMsg << ( uint8_t )0x0c;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )nMailCount;\r
- \r
- return tmpMsg;\r
- }\r
- \r
-PMessage* PMsgBuilder::BuildReceiveDBAnswerMsg( PClient* nClient, PMessage* nResultBuffer, std::string *nCommandName, uint16_t nNumRows, uint16_t nNumFields)\r
- {\r
- PMessage* tmpMsg = new PMessage();\r
-/* nClient->IncreaseUDP_ID();\r
- \r
- *tmpMsg << ( uint8_t )0x13;\r
- *tmpMsg << ( uint16_t )0x0000;\r
- *tmpMsg << ( uint16_t )0x0000;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint8_t )0x2b;\r
- *tmpMsg << ( uint8_t )0x1a;\r
- if(nCommandName->length() > 0)\r
- *tmpMsg << ( uint8_t )0x01;\r
- else\r
- *tmpMsg << ( uint8_t )0x00;\r
- \r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << *nCommandName;\r
- ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );\r
- \r
- // 2nd message\r
- *tmpMsg << ( uint16_t )(13 + nCommandName->length() + nResultBuffer->GetSize()); // ??\r
- */\r
- nClient->IncreaseUDP_ID();\r
- \r
- *tmpMsg << ( uint8_t )0x13;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint16_t )nClient->GetSessionID();\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint8_t )0x2b;\r
- *tmpMsg << ( uint8_t )0x17;\r
- *tmpMsg << ( uint16_t )(nCommandName->length()+1);\r
- *tmpMsg << ( uint16_t )nNumRows;\r
- *tmpMsg << ( uint16_t )nNumFields;\r
- *tmpMsg << *nCommandName;\r
- *tmpMsg << *nResultBuffer;\r
- \r
- ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );\r
- \r
- \r
- return tmpMsg;\r
- //len = (unsigned int)strlen(DB);\r
- //SendBuffer[0] = 0x13;\r
- //SendBuffer[5] = 11 + len;\r
- //SendBuffer[6] = 0x03;\r
- //Network_IncrementUDP (ClientNum);\r
- //*(unsigned short*)&SendBuffer[7] = Client_Sockets[ClientNum].UDP_ID;\r
- // SendBuffer[9] = 0x2b;\r
- // SendBuffer[10] = 0x1a;\r
- // *(unsigned short*)&SendBuffer[11] = len;\r
- // if (num == 0)\r
- // SendBuffer[13] = 0x00;\r
- // else\r
- // SendBuffer[13] = 0x01;\r
- // SendBuffer[14] = 0x00;\r
- // SendBuffer[15] = 0x00;\r
- // strcpy (SendBuffer+16, DB);\r
- // plen = 17+len;\r
- \r
- // SendBuffer[plen] = 13+len+slen;\r
- // SendBuffer[plen+1] = 0x03;\r
- // Network_IncrementUDP (ClientNum);\r
- // *(unsigned short*)&SendBuffer[plen+2] = Client_Sockets[ClientNum].UDP_ID;\r
- // *(unsigned short*)&SendBuffer[1] = Client_Sockets[ClientNum].UDP_ID;\r
- // *(unsigned short*)&SendBuffer[3] = Client_Sockets[ClientNum].UDP_ID_HIGH;\r
- // SendBuffer[plen+4] = 0x2b;\r
- // SendBuffer[plen+5] = 0x17;\r
- // *(unsigned short*)&SendBuffer[plen+6] = len+1;\r
- // *(unsigned short*)&SendBuffer[plen+8] = num;\r
- // *(unsigned short*)&SendBuffer[plen+10] = Fields;\r
- // //Fieldnum is defined in each DB below\r
- // strcpy (SendBuffer+plen+12, DB);\r
- // plen += 13+len;\r
- \r
- // for (i=0;i<slen;i++)\r
- // SendBuffer[plen+i] = TempBuffer[i];\r
- \r
- \r
- }\r
- \r
- \r
-PMessage* PMsgBuilder::BuildTryAccessAnswerMsg(PClient* nClient, char *nArea, bool nAllowed)\r
- {\r
- PMessage* tmpMsg = new PMessage();\r
- //uint8_t i = (uint8_t)strlen(nArea);\r
- \r
- nClient->IncreaseUDP_ID();\r
- \r
- *tmpMsg << (uint8_t)0x13;\r
- *tmpMsg << (uint16_t)nClient->GetUDP_ID();\r
- *tmpMsg << (uint16_t)nClient->GetSessionID();\r
- *tmpMsg << (uint8_t)0x00;\r
- *tmpMsg << (uint8_t)0x03;\r
- *tmpMsg << (uint16_t)nClient->GetUDP_ID();\r
- *tmpMsg << (uint8_t)0x2b;\r
- *tmpMsg << (uint8_t)0x1a;\r
- *tmpMsg << (uint16_t)(strlen(nArea)+1);\r
- \r
- if(nAllowed)\r
- *tmpMsg << (uint8_t)0x01;\r
- else\r
- *tmpMsg << (uint8_t)0x00;\r
- \r
- *tmpMsg << (uint8_t)0x00;\r
- *tmpMsg << (uint8_t)0x00;\r
- *tmpMsg << nArea;\r
- \r
- ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );\r
- return tmpMsg;\r
- }\r
+PMessage* PMsgBuilder::BuildReqNPCScriptAnswerMsg( uint32_t nInfoId, std::string *nNPCScript )
+ {
+ PMessage* tmpMsg;
+
+ tmpMsg = new PMessage();
+
+ *tmpMsg << ( uint8_t )0x19;
+ *tmpMsg << ( uint16_t )0x0006; // InfoQuery
+ *tmpMsg << ( uint16_t )0x0003; // NPC Script
+ *tmpMsg << ( uint32_t )nInfoId;
+ *tmpMsg << nNPCScript->c_str();
+
+ return tmpMsg;
+
+ }
+
+PMessage* PMsgBuilder::BuildYouGotEmailsMsg( PClient* nClient, uint8_t nMailCount )
+ {
+ PMessage* tmpMsg = new PMessage();
+ nClient->IncreaseUDP_ID();
+
+ *tmpMsg << ( uint8_t )0x13;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint16_t )nClient->GetSessionID();
+ *tmpMsg << ( uint8_t )0x0c;
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint8_t )0x1f;
+ *tmpMsg << ( uint16_t )nClient->GetLocalID();
+ *tmpMsg << ( uint8_t )0x3d;
+ *tmpMsg << ( uint8_t )0x0c;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )nMailCount;
+
+ return tmpMsg;
+ }
+
+PMessage* PMsgBuilder::BuildReceiveDBAnswerMsg( PClient* nClient, PMessage* nResultBuffer, std::string *nCommandName, uint16_t nNumRows, uint16_t nNumFields)
+ {
+ PMessage* tmpMsg = new PMessage();
+/* nClient->IncreaseUDP_ID();
+
+ *tmpMsg << ( uint8_t )0x13;
+ *tmpMsg << ( uint16_t )0x0000;
+ *tmpMsg << ( uint16_t )0x0000;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint8_t )0x2b;
+ *tmpMsg << ( uint8_t )0x1a;
+ if(nCommandName->length() > 0)
+ *tmpMsg << ( uint8_t )0x01;
+ else
+ *tmpMsg << ( uint8_t )0x00;
+
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << *nCommandName;
+ ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );
+
+ // 2nd message
+ *tmpMsg << ( uint16_t )(13 + nCommandName->length() + nResultBuffer->GetSize()); // ??
+ */
+ nClient->IncreaseUDP_ID();
+
+ *tmpMsg << ( uint8_t )0x13;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint16_t )nClient->GetSessionID();
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint8_t )0x2b;
+ *tmpMsg << ( uint8_t )0x17;
+ *tmpMsg << ( uint16_t )(nCommandName->length()+1);
+ *tmpMsg << ( uint16_t )nNumRows;
+ *tmpMsg << ( uint16_t )nNumFields;
+ *tmpMsg << *nCommandName;
+ *tmpMsg << *nResultBuffer;
+
+ ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );
+
+
+ return tmpMsg;
+ //len = (unsigned int)strlen(DB);
+ //SendBuffer[0] = 0x13;
+ //SendBuffer[5] = 11 + len;
+ //SendBuffer[6] = 0x03;
+ //Network_IncrementUDP (ClientNum);
+ //*(unsigned short*)&SendBuffer[7] = Client_Sockets[ClientNum].UDP_ID;
+ // SendBuffer[9] = 0x2b;
+ // SendBuffer[10] = 0x1a;
+ // *(unsigned short*)&SendBuffer[11] = len;
+ // if (num == 0)
+ // SendBuffer[13] = 0x00;
+ // else
+ // SendBuffer[13] = 0x01;
+ // SendBuffer[14] = 0x00;
+ // SendBuffer[15] = 0x00;
+ // strcpy (SendBuffer+16, DB);
+ // plen = 17+len;
+
+ // SendBuffer[plen] = 13+len+slen;
+ // SendBuffer[plen+1] = 0x03;
+ // Network_IncrementUDP (ClientNum);
+ // *(unsigned short*)&SendBuffer[plen+2] = Client_Sockets[ClientNum].UDP_ID;
+ // *(unsigned short*)&SendBuffer[1] = Client_Sockets[ClientNum].UDP_ID;
+ // *(unsigned short*)&SendBuffer[3] = Client_Sockets[ClientNum].UDP_ID_HIGH;
+ // SendBuffer[plen+4] = 0x2b;
+ // SendBuffer[plen+5] = 0x17;
+ // *(unsigned short*)&SendBuffer[plen+6] = len+1;
+ // *(unsigned short*)&SendBuffer[plen+8] = num;
+ // *(unsigned short*)&SendBuffer[plen+10] = Fields;
+ // //Fieldnum is defined in each DB below
+ // strcpy (SendBuffer+plen+12, DB);
+ // plen += 13+len;
+
+ // for (i=0;i<slen;i++)
+ // SendBuffer[plen+i] = TempBuffer[i];
+
+
+ }
+
+
+PMessage* PMsgBuilder::BuildTryAccessAnswerMsg(PClient* nClient, char *nArea, bool nAllowed)
+ {
+ PMessage* tmpMsg = new PMessage();
+ //uint8_t i = (uint8_t)strlen(nArea);
+
+ nClient->IncreaseUDP_ID();
+
+ *tmpMsg << (uint8_t)0x13;
+ *tmpMsg << (uint16_t)nClient->GetUDP_ID();
+ *tmpMsg << (uint16_t)nClient->GetSessionID();
+ *tmpMsg << (uint8_t)0x00;
+ *tmpMsg << (uint8_t)0x03;
+ *tmpMsg << (uint16_t)nClient->GetUDP_ID();
+ *tmpMsg << (uint8_t)0x2b;
+ *tmpMsg << (uint8_t)0x1a;
+ *tmpMsg << (uint16_t)(strlen(nArea)+1);
+
+ if(nAllowed)
+ *tmpMsg << (uint8_t)0x01;
+ else
+ *tmpMsg << (uint8_t)0x00;
+
+ *tmpMsg << (uint8_t)0x00;
+ *tmpMsg << (uint8_t)0x00;
+ *tmpMsg << nArea;
+
+ ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );
+ return tmpMsg;
+ }
PMessage* PMsgBuilder::BuildReqInfoAnswerMsg( PClient* nClient, uint16_t nReqType, uint32_t nInfoId, void* nResponse, uint16_t nResponseLength )
{
return tmpMsg;
}
- */\r
-// NPC Dialog. Start dialog with NPC\r
-PMessage* PMsgBuilder::BuildNPCStartDialogMsg( PClient* nClient, uint32_t nNPCWorldID, std::string *nDialogScript )\r
- {\r
- PMessage* tmpMsg = new PMessage();\r
- nClient->IncreaseUDP_ID();\r
- \r
- \r
- *tmpMsg << ( uint8_t )0x13;\r
- *tmpMsg << ( uint16_t ) 0x0000; // UDP Placeholder\r
- *tmpMsg << ( uint16_t ) 0x0000; // UDP Placeholder\r
- *tmpMsg << ( uint8_t )0x00; // Message length\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint8_t )0x1f;\r
- *tmpMsg << ( uint16_t )nClient->GetLocalID();\r
- *tmpMsg << ( uint8_t )0x18;\r
- *tmpMsg << ( uint32_t ) nNPCWorldID;\r
- \r
- // Todo: is this correct? random uint32_t value??\r
- *tmpMsg << ( uint16_t ) GetRandom( 65535, 4369 );\r
- *tmpMsg << ( uint16_t ) GetRandom( 65535, 4369 );\r
- *tmpMsg << ( uint32_t ) 0x0000;\r
- *tmpMsg << nDialogScript->c_str();\r
- ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );\r
- \r
- nClient->IncreaseUDP_ID();\r
- \r
- *tmpMsg << ( uint8_t )0x0a;\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint8_t )0x1f;\r
- *tmpMsg << ( uint16_t )nClient->GetLocalID();\r
- *tmpMsg << ( uint8_t )0x1a;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )0x00;\r
- \r
- tmpMsg->U16Data( 1 ) = nClient->GetUDP_ID();\r
- tmpMsg->U16Data( 3 ) = nClient->GetSessionID();\r
- \r
- return tmpMsg;\r
- }\r
-// NPC Dialog. Send next node number in lua script to client\r
-PMessage* PMsgBuilder::BuildNPCDialogReplyMsg( PClient* nClient, uint16_t nNextNode, std::vector<int>*nResultBuffer)\r
- {\r
- PMessage* tmpMsg = new PMessage();\r
- \r
- nClient->IncreaseUDP_ID();\r
- \r
- *tmpMsg << ( uint8_t )0x13;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();;\r
- *tmpMsg << ( uint16_t )nClient->GetSessionID();;\r
- *tmpMsg << ( uint8_t )0x00; // SubMessage length;\r
- \r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();;\r
- *tmpMsg << ( uint8_t )0x1f;\r
- *tmpMsg << ( uint16_t )nClient->GetLocalID();\r
- *tmpMsg << ( uint8_t )0x1a;\r
- *tmpMsg << ( uint16_t )nNextNode;\r
- //*tmpMsg << ( uint8_t )nNumResults;\r
- *tmpMsg << ( uint8_t )nResultBuffer->size();\r
- \r
- std::vector<int>::const_iterator it;\r
- \r
- for(it = nResultBuffer->begin(); it != nResultBuffer->end(); it++)\r
- {\r
- *tmpMsg << ( float )*(it);\r
- }\r
- \r
- ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );\r
- \r
- return tmpMsg;\r
- }\r
-
-PMessage* PMsgBuilder::BuildNPCBeginAllBuyerTradeMsg( PClient* nClient, int nWorldID )\r
- {\r
- PMessage* tmpMsg = new PMessage();\r
- nClient->IncreaseUDP_ID();\r
- \r
- *tmpMsg << ( uint8_t )0x13;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint16_t )nClient->GetSessionID();\r
- *tmpMsg << ( uint8_t )0x00; // Message length\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint8_t )0x1f;\r
- *tmpMsg << ( uint16_t )nClient->GetLocalID();\r
- *tmpMsg << ( uint8_t )0x26;\r
- *tmpMsg << ( uint32_t ) nWorldID;\r
- *tmpMsg << ( uint8_t )0x01; // Traders inventory\r
- *tmpMsg << ( uint16_t )0xFFFF; // Traders inventory\r
- \r
- ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );\r
- \r
- return tmpMsg;\r
- }\r
- \r
-PMessage* PMsgBuilder::BuildNPCShoppingListMsg( PClient* nClient, PMessage* nContentList, int nWorldID, uint8_t nItemQuality)\r
- {\r
- PMessage* tmpMsg = new PMessage();\r
- nClient->IncreaseUDP_ID();\r
- \r
- *tmpMsg << ( uint8_t )0x13;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint16_t )nClient->GetSessionID();\r
- *tmpMsg << ( uint8_t )0x00; // Message length\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint8_t )0x1f;\r
- *tmpMsg << ( uint16_t )nClient->GetLocalID();\r
- *tmpMsg << ( uint8_t )0x26;\r
- *tmpMsg << ( uint32_t ) nWorldID;\r
- *tmpMsg << ( uint8_t )0x01; // Traders inventory\r
- *tmpMsg << ( uint16_t )( nContentList->GetSize() / 6 ); // List entries\r
- *tmpMsg << ( uint8_t )nItemQuality; // Items quality\r
- *tmpMsg << *nContentList;\r
- \r
- ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );\r
- \r
- return tmpMsg;\r
- }\r
- \r
-// ==========================\r
-PMessage* PMsgBuilder::BuildNPCSingleInfoMsg( PClient* nClient, uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing,\r
-uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nUnknown,\r
-uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName)\r
-// Initial NPC Packet that defines how the NPC look, etc\r
- {\r
-// uint8_t tMsgLen = 29 + nNpcName->size() + nAngleStr->size() + nCustomName->size();\r
- \r
- PMessage* tmpMsg = new PMessage();\r
- nClient->IncreaseUDP_ID();\r
- \r
- *tmpMsg << ( uint8_t )0x13; // Begin UDP message\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint16_t )nClient->GetSessionID();\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint8_t )0x28;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )0x01;\r
- *tmpMsg << ( uint32_t )nWorldID;\r
- *tmpMsg << ( uint16_t )nTypeID;\r
- *tmpMsg << ( uint16_t )nClothing;\r
- *tmpMsg << ( uint16_t )nNameID;\r
- *tmpMsg << ( uint16_t )nPosY;\r
- *tmpMsg << ( uint16_t )nPosZ;\r
- *tmpMsg << ( uint16_t )nPosX;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint16_t )nUnknown;\r
- *tmpMsg << ( uint16_t )nTraderID;\r
- *tmpMsg << nNpcName->c_str();\r
- *tmpMsg << nAngleStr->c_str();\r
- if(nCustomName->length() > 1)\r
- *tmpMsg << nCustomName->c_str();\r
- \r
- (*tmpMsg)[5] = (uint8_t)(tmpMsg->GetSize() - 6);\r
- return tmpMsg;\r
- }\r
- \r
-PMessage* PMsgBuilder::BuildNPCMassInfoMsg( uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing,\r
-uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nHealth,\r
-uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName)\r
-// Initial NPC Packet that defines how the NPC look, etc\r
- {\r
-// uint8_t tMsgLen = 29 + nNpcName->size() + nAngleStr->size() + nCustomName->size();\r
- \r
- PMessage* tmpMsg = new PMessage();\r
- \r
- *tmpMsg << ( uint8_t )0x13; // Begin UDP message\r
- *tmpMsg << ( uint16_t )0x0000;\r
- *tmpMsg << ( uint16_t )0x0000;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )0x03;\r
- *tmpMsg << ( uint16_t )0x0000;\r
- *tmpMsg << ( uint8_t )0x28;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )0x01;\r
- *tmpMsg << ( uint32_t )nWorldID;\r
- *tmpMsg << ( uint16_t )nTypeID;\r
- *tmpMsg << ( uint16_t )nClothing;\r
- *tmpMsg << ( uint16_t )nNameID;\r
- *tmpMsg << ( uint16_t )nPosY;\r
- *tmpMsg << ( uint16_t )nPosZ;\r
- *tmpMsg << ( uint16_t )nPosX;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint16_t )nHealth;\r
- *tmpMsg << ( uint16_t )nTraderID;\r
- *tmpMsg << nNpcName->c_str();\r
- *tmpMsg << nAngleStr->c_str();\r
- if(nCustomName->length() > 1)\r
- *tmpMsg << nCustomName->c_str();\r
- \r
- (*tmpMsg)[5] = (uint8_t)(tmpMsg->GetSize() - 6);\r
- return tmpMsg;\r
- }\r
- \r
-// **************\r
-PMessage* PMsgBuilder::BuildNPCUpdateMsg(uint32_t nWorldID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint8_t nActionBM, uint16_t nHealth, uint8_t nWeaponState, uint8_t nUnknown, uint32_t nTargetID)\r
- {\r
- PMessage* tmpMsg = new PMessage();\r
- \r
- *tmpMsg << ( uint8_t )0x13;\r
- *tmpMsg << ( uint16_t )0x0000;\r
- *tmpMsg << ( uint16_t )0x0000;\r
- *tmpMsg << ( uint8_t )0x00; // len\r
- *tmpMsg << ( uint8_t )0x1b; // NPC Update\r
- *tmpMsg << ( uint32_t )nWorldID; // NPCs world ID\r
- *tmpMsg << ( uint8_t )0x1f; // Parameters\r
- *tmpMsg << ( uint16_t )nPosY; // Position Y\r
- *tmpMsg << ( uint16_t )nPosZ; // Position Z\r
- *tmpMsg << ( uint16_t )nPosX; // Position X\r
- *tmpMsg << ( uint8_t )nActionBM; // NPCs current action-bitmask\r
- *tmpMsg << ( uint16_t )nHealth; // Health value\r
- if(nTargetID > 0)\r
- *tmpMsg << ( uint32_t )nTargetID; // WorldID of NPCs target (if any)\r
- *tmpMsg << ( uint8_t )nUnknown;\r
- *tmpMsg << ( uint8_t )nWeaponState;\r
- \r
- (*tmpMsg)[5] = (uint8_t)(tmpMsg->GetSize() - 6);\r
- \r
- return tmpMsg;\r
- }\r
-// **************\r
- \r
-PMessage* PMsgBuilder::BuildNPCSingleAliveMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction )\r
- {\r
- PMessage* tmpMsg = new PMessage();\r
- \r
- *tmpMsg << ( uint8_t )0x13; // Begin UDP message\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint16_t )nClient->GetSessionID();\r
- *tmpMsg << ( uint8_t )0x11;\r
- *tmpMsg << ( uint8_t )0x1B;\r
- *tmpMsg << ( uint32_t )nWorldID;\r
- *tmpMsg << ( uint8_t )0x1F;\r
- *tmpMsg << ( uint16_t )nY;\r
- *tmpMsg << ( uint16_t )nZ;\r
- *tmpMsg << ( uint16_t )nX;\r
- *tmpMsg << ( uint8_t )nActionStatus;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )nHealth;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )nAction;\r
- \r
- return tmpMsg;\r
- }\r
- \r
-PMessage* PMsgBuilder::BuildNPCMassAliveMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction )\r
- {\r
- PMessage* tmpMsg = new PMessage();\r
- \r
- *tmpMsg << ( uint8_t )0x13; // Begin UDP message\r
- *tmpMsg << ( uint16_t )0x0000;\r
- *tmpMsg << ( uint16_t )0x0000;\r
- *tmpMsg << ( uint8_t )0x11;\r
- *tmpMsg << ( uint8_t )0x1B;\r
- *tmpMsg << ( uint32_t )nWorldID;\r
- *tmpMsg << ( uint8_t )0x1F;\r
- *tmpMsg << ( uint16_t )nY;\r
- *tmpMsg << ( uint16_t )nZ;\r
- *tmpMsg << ( uint16_t )nX;\r
- *tmpMsg << ( uint8_t )nActionStatus;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )nHealth;\r
- *tmpMsg << ( uint8_t )0x00;\r
- *tmpMsg << ( uint8_t )nAction;\r
- \r
- return tmpMsg;\r
- }\r
- \r
-PMessage* PMsgBuilder::BuildNPCMassUpdateMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction )\r
- {\r
- PMessage* tmpMsg = new PMessage();\r
- \r
- *tmpMsg << ( uint8_t )0x13; // Begin UDP message\r
- *tmpMsg << ( uint16_t )0x0000;\r
- *tmpMsg << ( uint16_t )0x0000;\r
- *tmpMsg << ( uint8_t )0x15; // Message length\r
- *tmpMsg << ( uint8_t )0x1b;\r
- *tmpMsg << ( uint32_t )nWorldID;\r
- *tmpMsg << ( uint8_t )0x1F;\r
- *tmpMsg << ( uint16_t )nY;\r
- *tmpMsg << ( uint16_t )nZ;\r
- *tmpMsg << ( uint16_t )nX;\r
- *tmpMsg << ( uint8_t )nActionStatus;\r
- *tmpMsg << ( uint8_t )0x77; // ?\r
- *tmpMsg << ( uint8_t )nHealth;\r
- *tmpMsg << ( uint16_t )nTarget;\r
- *tmpMsg << ( uint8_t )0x00; // ?\r
- *tmpMsg << ( uint8_t )0x00; // ?\r
- *tmpMsg << ( uint8_t )0x00; // ?\r
- *tmpMsg << ( uint8_t )nAction;\r
- \r
- return tmpMsg;\r
- }\r
- \r
-// ==========================\r
- \r
-PMessage* PMsgBuilder::BuildNPCSingleUpdateMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction )\r
- {\r
- PMessage* tmpMsg = new PMessage();\r
- \r
- *tmpMsg << ( uint8_t )0x13; // Begin UDP message\r
- *tmpMsg << ( uint16_t )nClient->GetUDP_ID();\r
- *tmpMsg << ( uint16_t )nClient->GetSessionID();\r
- *tmpMsg << ( uint8_t )0x15; // Message length\r
- *tmpMsg << ( uint8_t )0x1b;\r
- *tmpMsg << ( uint32_t )nWorldID;\r
- *tmpMsg << ( uint8_t )0x1F;\r
- *tmpMsg << ( uint16_t )nY;\r
- *tmpMsg << ( uint16_t )nZ;\r
- *tmpMsg << ( uint16_t )nX;\r
- *tmpMsg << ( uint8_t )nActionStatus;\r
- *tmpMsg << ( uint8_t )0x77; // ?\r
- *tmpMsg << ( uint8_t )nHealth;\r
- *tmpMsg << ( uint16_t )nTarget;\r
- *tmpMsg << ( uint8_t )0x00; // ?\r
- *tmpMsg << ( uint8_t )0x00; // ?\r
- *tmpMsg << ( uint8_t )0x00; // ?\r
- *tmpMsg << ( uint8_t )nAction;\r
- \r
- return tmpMsg;\r
- }\r
-// ==========================\r
+ */
+// NPC Dialog. Start dialog with NPC
+PMessage* PMsgBuilder::BuildNPCStartDialogMsg( PClient* nClient, uint32_t nNPCWorldID, std::string *nDialogScript )
+ {
+ PMessage* tmpMsg = new PMessage();
+ nClient->IncreaseUDP_ID();
+
+
+ *tmpMsg << ( uint8_t )0x13;
+ *tmpMsg << ( uint16_t ) 0x0000; // UDP Placeholder
+ *tmpMsg << ( uint16_t ) 0x0000; // UDP Placeholder
+ *tmpMsg << ( uint8_t )0x00; // Message length
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint8_t )0x1f;
+ *tmpMsg << ( uint16_t )nClient->GetLocalID();
+ *tmpMsg << ( uint8_t )0x18;
+ *tmpMsg << ( uint32_t ) nNPCWorldID;
+
+ // Todo: is this correct? random uint32_t value??
+ *tmpMsg << ( uint16_t ) GetRandom( 65535, 4369 );
+ *tmpMsg << ( uint16_t ) GetRandom( 65535, 4369 );
+ *tmpMsg << ( uint32_t ) 0x0000;
+ *tmpMsg << nDialogScript->c_str();
+ ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );
+
+ nClient->IncreaseUDP_ID();
+
+ *tmpMsg << ( uint8_t )0x0a;
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint8_t )0x1f;
+ *tmpMsg << ( uint16_t )nClient->GetLocalID();
+ *tmpMsg << ( uint8_t )0x1a;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )0x00;
+
+ tmpMsg->U16Data( 1 ) = nClient->GetUDP_ID();
+ tmpMsg->U16Data( 3 ) = nClient->GetSessionID();
+
+ return tmpMsg;
+ }
+// NPC Dialog. Send next node number in lua script to client
+PMessage* PMsgBuilder::BuildNPCDialogReplyMsg( PClient* nClient, uint16_t nNextNode, std::vector<int>*nResultBuffer)
+ {
+ PMessage* tmpMsg = new PMessage();
+
+ nClient->IncreaseUDP_ID();
+
+ *tmpMsg << ( uint8_t )0x13;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();;
+ *tmpMsg << ( uint16_t )nClient->GetSessionID();;
+ *tmpMsg << ( uint8_t )0x00; // SubMessage length;
+
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();;
+ *tmpMsg << ( uint8_t )0x1f;
+ *tmpMsg << ( uint16_t )nClient->GetLocalID();
+ *tmpMsg << ( uint8_t )0x1a;
+ *tmpMsg << ( uint16_t )nNextNode;
+ //*tmpMsg << ( uint8_t )nNumResults;
+ *tmpMsg << ( uint8_t )nResultBuffer->size();
+
+ std::vector<int>::const_iterator it;
+
+ for(it = nResultBuffer->begin(); it != nResultBuffer->end(); it++)
+ {
+ *tmpMsg << ( float )*(it);
+ }
+
+ ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );
+
+ return tmpMsg;
+ }
+
+PMessage* PMsgBuilder::BuildNPCBeginAllBuyerTradeMsg( PClient* nClient, int nWorldID )
+ {
+ PMessage* tmpMsg = new PMessage();
+ nClient->IncreaseUDP_ID();
+
+ *tmpMsg << ( uint8_t )0x13;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint16_t )nClient->GetSessionID();
+ *tmpMsg << ( uint8_t )0x00; // Message length
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint8_t )0x1f;
+ *tmpMsg << ( uint16_t )nClient->GetLocalID();
+ *tmpMsg << ( uint8_t )0x26;
+ *tmpMsg << ( uint32_t ) nWorldID;
+ *tmpMsg << ( uint8_t )0x01; // Traders inventory
+ *tmpMsg << ( uint16_t )0xFFFF; // Traders inventory
+
+ ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );
+
+ return tmpMsg;
+ }
+
+PMessage* PMsgBuilder::BuildNPCShoppingListMsg( PClient* nClient, PMessage* nContentList, int nWorldID, uint8_t nItemQuality)
+ {
+ PMessage* tmpMsg = new PMessage();
+ nClient->IncreaseUDP_ID();
+
+ *tmpMsg << ( uint8_t )0x13;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint16_t )nClient->GetSessionID();
+ *tmpMsg << ( uint8_t )0x00; // Message length
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint8_t )0x1f;
+ *tmpMsg << ( uint16_t )nClient->GetLocalID();
+ *tmpMsg << ( uint8_t )0x26;
+ *tmpMsg << ( uint32_t ) nWorldID;
+ *tmpMsg << ( uint8_t )0x01; // Traders inventory
+ *tmpMsg << ( uint16_t )( nContentList->GetSize() / 6 ); // List entries
+ *tmpMsg << ( uint8_t )nItemQuality; // Items quality
+ *tmpMsg << *nContentList;
+
+ ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );
+
+ return tmpMsg;
+ }
+
+// ==========================
+PMessage* PMsgBuilder::BuildNPCSingleInfoMsg( PClient* nClient, uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing,
+uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nUnknown,
+uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName)
+// Initial NPC Packet that defines how the NPC look, etc
+ {
+// uint8_t tMsgLen = 29 + nNpcName->size() + nAngleStr->size() + nCustomName->size();
+
+ PMessage* tmpMsg = new PMessage();
+ nClient->IncreaseUDP_ID();
+
+ *tmpMsg << ( uint8_t )0x13; // Begin UDP message
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint16_t )nClient->GetSessionID();
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint8_t )0x28;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )0x01;
+ *tmpMsg << ( uint32_t )nWorldID;
+ *tmpMsg << ( uint16_t )nTypeID;
+ *tmpMsg << ( uint16_t )nClothing;
+ *tmpMsg << ( uint16_t )nNameID;
+ *tmpMsg << ( uint16_t )nPosY;
+ *tmpMsg << ( uint16_t )nPosZ;
+ *tmpMsg << ( uint16_t )nPosX;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint16_t )nUnknown;
+ *tmpMsg << ( uint16_t )nTraderID;
+ *tmpMsg << nNpcName->c_str();
+ *tmpMsg << nAngleStr->c_str();
+ if(nCustomName->length() > 1)
+ *tmpMsg << nCustomName->c_str();
+
+ (*tmpMsg)[5] = (uint8_t)(tmpMsg->GetSize() - 6);
+ return tmpMsg;
+ }
+
+PMessage* PMsgBuilder::BuildNPCMassInfoMsg( uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing,
+uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nHealth,
+uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName)
+// Initial NPC Packet that defines how the NPC look, etc
+ {
+// uint8_t tMsgLen = 29 + nNpcName->size() + nAngleStr->size() + nCustomName->size();
+
+ PMessage* tmpMsg = new PMessage();
+
+ *tmpMsg << ( uint8_t )0x13; // Begin UDP message
+ *tmpMsg << ( uint16_t )0x0000;
+ *tmpMsg << ( uint16_t )0x0000;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )0x03;
+ *tmpMsg << ( uint16_t )0x0000;
+ *tmpMsg << ( uint8_t )0x28;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )0x01;
+ *tmpMsg << ( uint32_t )nWorldID;
+ *tmpMsg << ( uint16_t )nTypeID;
+ *tmpMsg << ( uint16_t )nClothing;
+ *tmpMsg << ( uint16_t )nNameID;
+ *tmpMsg << ( uint16_t )nPosY;
+ *tmpMsg << ( uint16_t )nPosZ;
+ *tmpMsg << ( uint16_t )nPosX;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint16_t )nHealth;
+ *tmpMsg << ( uint16_t )nTraderID;
+ *tmpMsg << nNpcName->c_str();
+ *tmpMsg << nAngleStr->c_str();
+ if(nCustomName->length() > 1)
+ *tmpMsg << nCustomName->c_str();
+
+ (*tmpMsg)[5] = (uint8_t)(tmpMsg->GetSize() - 6);
+ return tmpMsg;
+ }
+
+// **************
+PMessage* PMsgBuilder::BuildNPCUpdateMsg(uint32_t nWorldID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint8_t nActionBM, uint16_t nHealth, uint8_t nWeaponState, uint8_t nUnknown, uint32_t nTargetID)
+ {
+ PMessage* tmpMsg = new PMessage();
+
+ *tmpMsg << ( uint8_t )0x13;
+ *tmpMsg << ( uint16_t )0x0000;
+ *tmpMsg << ( uint16_t )0x0000;
+ *tmpMsg << ( uint8_t )0x00; // len
+ *tmpMsg << ( uint8_t )0x1b; // NPC Update
+ *tmpMsg << ( uint32_t )nWorldID; // NPCs world ID
+ *tmpMsg << ( uint8_t )0x1f; // Parameters
+ *tmpMsg << ( uint16_t )nPosY; // Position Y
+ *tmpMsg << ( uint16_t )nPosZ; // Position Z
+ *tmpMsg << ( uint16_t )nPosX; // Position X
+ *tmpMsg << ( uint8_t )nActionBM; // NPCs current action-bitmask
+ *tmpMsg << ( uint16_t )nHealth; // Health value
+ if(nTargetID > 0)
+ *tmpMsg << ( uint32_t )nTargetID; // WorldID of NPCs target (if any)
+ *tmpMsg << ( uint8_t )nUnknown;
+ *tmpMsg << ( uint8_t )nWeaponState;
+
+ (*tmpMsg)[5] = (uint8_t)(tmpMsg->GetSize() - 6);
+
+ return tmpMsg;
+ }
+// **************
+
+PMessage* PMsgBuilder::BuildNPCSingleAliveMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction )
+ {
+ PMessage* tmpMsg = new PMessage();
+
+ *tmpMsg << ( uint8_t )0x13; // Begin UDP message
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint16_t )nClient->GetSessionID();
+ *tmpMsg << ( uint8_t )0x11;
+ *tmpMsg << ( uint8_t )0x1B;
+ *tmpMsg << ( uint32_t )nWorldID;
+ *tmpMsg << ( uint8_t )0x1F;
+ *tmpMsg << ( uint16_t )nY;
+ *tmpMsg << ( uint16_t )nZ;
+ *tmpMsg << ( uint16_t )nX;
+ *tmpMsg << ( uint8_t )nActionStatus;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )nHealth;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )nAction;
+
+ return tmpMsg;
+ }
+
+PMessage* PMsgBuilder::BuildNPCMassAliveMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction )
+ {
+ PMessage* tmpMsg = new PMessage();
+
+ *tmpMsg << ( uint8_t )0x13; // Begin UDP message
+ *tmpMsg << ( uint16_t )0x0000;
+ *tmpMsg << ( uint16_t )0x0000;
+ *tmpMsg << ( uint8_t )0x11;
+ *tmpMsg << ( uint8_t )0x1B;
+ *tmpMsg << ( uint32_t )nWorldID;
+ *tmpMsg << ( uint8_t )0x1F;
+ *tmpMsg << ( uint16_t )nY;
+ *tmpMsg << ( uint16_t )nZ;
+ *tmpMsg << ( uint16_t )nX;
+ *tmpMsg << ( uint8_t )nActionStatus;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )nHealth;
+ *tmpMsg << ( uint8_t )0x00;
+ *tmpMsg << ( uint8_t )nAction;
+
+ return tmpMsg;
+ }
+
+PMessage* PMsgBuilder::BuildNPCMassUpdateMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction )
+ {
+ PMessage* tmpMsg = new PMessage();
+
+ *tmpMsg << ( uint8_t )0x13; // Begin UDP message
+ *tmpMsg << ( uint16_t )0x0000;
+ *tmpMsg << ( uint16_t )0x0000;
+ *tmpMsg << ( uint8_t )0x15; // Message length
+ *tmpMsg << ( uint8_t )0x1b;
+ *tmpMsg << ( uint32_t )nWorldID;
+ *tmpMsg << ( uint8_t )0x1F;
+ *tmpMsg << ( uint16_t )nY;
+ *tmpMsg << ( uint16_t )nZ;
+ *tmpMsg << ( uint16_t )nX;
+ *tmpMsg << ( uint8_t )nActionStatus;
+ *tmpMsg << ( uint8_t )0x77; // ?
+ *tmpMsg << ( uint8_t )nHealth;
+ *tmpMsg << ( uint16_t )nTarget;
+ *tmpMsg << ( uint8_t )0x00; // ?
+ *tmpMsg << ( uint8_t )0x00; // ?
+ *tmpMsg << ( uint8_t )0x00; // ?
+ *tmpMsg << ( uint8_t )nAction;
+
+ return tmpMsg;
+ }
+
+// ==========================
+
+PMessage* PMsgBuilder::BuildNPCSingleUpdateMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction )
+ {
+ PMessage* tmpMsg = new PMessage();
+
+ *tmpMsg << ( uint8_t )0x13; // Begin UDP message
+ *tmpMsg << ( uint16_t )nClient->GetUDP_ID();
+ *tmpMsg << ( uint16_t )nClient->GetSessionID();
+ *tmpMsg << ( uint8_t )0x15; // Message length
+ *tmpMsg << ( uint8_t )0x1b;
+ *tmpMsg << ( uint32_t )nWorldID;
+ *tmpMsg << ( uint8_t )0x1F;
+ *tmpMsg << ( uint16_t )nY;
+ *tmpMsg << ( uint16_t )nZ;
+ *tmpMsg << ( uint16_t )nX;
+ *tmpMsg << ( uint8_t )nActionStatus;
+ *tmpMsg << ( uint8_t )0x77; // ?
+ *tmpMsg << ( uint8_t )nHealth;
+ *tmpMsg << ( uint16_t )nTarget;
+ *tmpMsg << ( uint8_t )0x00; // ?
+ *tmpMsg << ( uint8_t )0x00; // ?
+ *tmpMsg << ( uint8_t )0x00; // ?
+ *tmpMsg << ( uint8_t )nAction;
+
+ return tmpMsg;
+ }
+// ==========================
PMessage* PMsgBuilder::BuildSubskillIncMsg( PClient* nClient, uint8_t nSubskill, uint16_t nSkillPoints )
{
PMessage* tmpMsg = new PMessage( 33 );
( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 );
return tmpMsg;
- }\r
- \r
+ }
+
/*
void Cmd_GiveItem (int ItemId, int Amount, int ClientNum)
// Temp. NPC update message for testing
PMessage* BuildNpcDeathMsg( PClient* nClient, uint32_t nNpcId, uint8_t unknown1 = 0x4a, uint8_t npcAction = 0x1e );
- PMessage* BuildNPCMassInfoMsg( uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing, uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nHealth, uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName);\r
- PMessage* BuildNPCMassAliveMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction );\r
- PMessage* BuildNPCMassUpdateMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction );\r
- // Moved here since its a zone broadcast!\r
- PMessage* BuildNpcCleanupMsg( uint32_t nNpcId, uint8_t nCmd = 6 ); // see implementation about nCmd\r
+ PMessage* BuildNPCMassInfoMsg( uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing, uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nHealth, uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName);
+ PMessage* BuildNPCMassAliveMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction );
+ PMessage* BuildNPCMassUpdateMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction );
+ // Moved here since its a zone broadcast!
+ PMessage* BuildNpcCleanupMsg( uint32_t nNpcId, uint8_t nCmd = 6 ); // see implementation about nCmd
// Following methods for unicast messages DO include UDP_ID increment and
// UDP_ID / SessionID setting when needed (at least for now)
- PMessage* BuildOutpostClanInfoMsg( PClient* nClient, uint32_t nClanID, uint8_t nFaction );\r
- PMessage* BuildTryAccessAnswerMsg(PClient* nClient, char *nArea, bool nAllowed);\r
- PMessage* BuildReceiveDBAnswerMsg( PClient* nClient, PMessage* nResultBuffer, std::string* nCommandName, uint16_t nNumRows, uint16_t nNumFields);\r
- PMessage* BuildYouGotEmailsMsg( PClient* nClient, uint8_t nMailCount );\r
- \r
- PMessage* BuildNPCStartDialogMsg( PClient* nClient, uint32_t nNPCWorldID, std::string *nDialogScript );\r
- PMessage* BuildNPCDialogReplyMsg( PClient* nClient, uint16_t nNextNode, std::vector<int>*nResultBuffer);\r
- PMessage* BuildReqNPCScriptAnswerMsg( uint32_t nInfoId, std::string *nNPCScript );\r
- PMessage* BuildNPCShoppingListMsg( PClient* nClient, PMessage* nContentList, int nWorldID, uint8_t nItemQuality);\r
- PMessage* BuildNPCBeginAllBuyerTradeMsg( PClient* nClient, int nWorldID );\r
- \r
- PMessage* BuildNPCSingleInfoMsg( PClient* nClient, uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing, uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nHealth, uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName);\r
- PMessage* BuildNPCSingleAliveMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction );\r
- PMessage* BuildNPCSingleUpdateMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction );\r
- \r
- // NEW for testing. Combined update message\r
- PMessage* BuildNPCUpdateMsg(uint32_t nWorldID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint8_t nActionBM, uint16_t nHealth, uint8_t nWeaponState, uint8_t nUnknown, uint32_t nTargetID = 0);\r
- \r
+ PMessage* BuildOutpostClanInfoMsg( PClient* nClient, uint32_t nClanID, uint8_t nFaction );
+ PMessage* BuildTryAccessAnswerMsg(PClient* nClient, char *nArea, bool nAllowed);
+ PMessage* BuildReceiveDBAnswerMsg( PClient* nClient, PMessage* nResultBuffer, std::string* nCommandName, uint16_t nNumRows, uint16_t nNumFields);
+ PMessage* BuildYouGotEmailsMsg( PClient* nClient, uint8_t nMailCount );
+
+ PMessage* BuildNPCStartDialogMsg( PClient* nClient, uint32_t nNPCWorldID, std::string *nDialogScript );
+ PMessage* BuildNPCDialogReplyMsg( PClient* nClient, uint16_t nNextNode, std::vector<int>*nResultBuffer);
+ PMessage* BuildReqNPCScriptAnswerMsg( uint32_t nInfoId, std::string *nNPCScript );
+ PMessage* BuildNPCShoppingListMsg( PClient* nClient, PMessage* nContentList, int nWorldID, uint8_t nItemQuality);
+ PMessage* BuildNPCBeginAllBuyerTradeMsg( PClient* nClient, int nWorldID );
+
+ PMessage* BuildNPCSingleInfoMsg( PClient* nClient, uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing, uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nHealth, uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName);
+ PMessage* BuildNPCSingleAliveMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction );
+ PMessage* BuildNPCSingleUpdateMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction );
+
+ // NEW for testing. Combined update message
+ PMessage* BuildNPCUpdateMsg(uint32_t nWorldID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint8_t nActionBM, uint16_t nHealth, uint8_t nWeaponState, uint8_t nUnknown, uint32_t nTargetID = 0);
+
PMessage* BuildReqInfoAnswerMsg( PClient* nClient, uint16_t nReqType, uint32_t nInfoId, void* nResponse, uint16_t nResponseLength );
PMessage* BuildPacket0Msg( PClient* nClient );
};
// Reload LUA script while running, in case we modified it and dont want to restart the entire server
-bool PNPC::ReloadLUAScript()\r
-{\r
- // Erase current LUA script\r
- mLUAFile = "";\r
-\r
- // Reload it\r
- return LoadLUAScript();\r
-}\r
+bool PNPC::ReloadLUAScript()
+{
+ // Erase current LUA script
+ mLUAFile = "";
+
+ // Reload it
+ return LoadLUAScript();
+}
bool PNPC::DEF_Load(uint32_t nWorldID)
{
if ( gDevDebug ) Console->Print( "[DEBUG] Now loading NPC data for NPC id %d from DEF", mWorldID );
const PNPCTemplate* t_defNPC = Worlds->GetWorld(nWorldID)->GetNPCTemplate(mWorldID);
- mNameID = (uint16_t)t_defNPC->GetNPCTypeID(); // 16 or 32??\r
- const PDefNpc* t_NpcTypeDef = GameDefs->Npcs()->GetDef(mNameID);\r
- if(!t_NpcTypeDef)\r
- {\r
- Console->Print("%s [PNPC::DEF_Load()] Unknown NPC Type %d in .dat file found", Console->ColorText(RED,BLACK, "[Error]"), mNameID);\r
- return false;\r
+ mNameID = (uint16_t)t_defNPC->GetNPCTypeID(); // 16 or 32??
+ const PDefNpc* t_NpcTypeDef = GameDefs->Npcs()->GetDef(mNameID);
+ if(!t_NpcTypeDef)
+ {
+ Console->Print("%s [PNPC::DEF_Load()] Unknown NPC Type %d in .dat file found", Console->ColorText(RED,BLACK, "[Error]"), mNameID);
+ return false;
}
- // TODO: Find out what exactly these TypeID and ClothingID values do and where they are generated/read\r
+ // TODO: Find out what exactly these TypeID and ClothingID values do and where they are generated/read
// Possible (working) solution: Random seed for name generation that happens clientside
mTypeID = GetRandom(32767, 1);
mClothing = GetRandom(32767, 1);
mPosZ = t_defNPC->GetPosZ()+32768;
mAngle = atoi( t_defNPC->GetAngle().c_str() );
mLoot = t_NpcTypeDef->GetLoot();
- mHealth = t_NpcTypeDef->GetHealth() * NPC_HEALTHFACTOR;\r
+ mHealth = t_NpcTypeDef->GetHealth() * NPC_HEALTHFACTOR;
mMaxHealth = mHealth;
mTrader = t_defNPC->GetTradeID();
mFaction = t_NpcTypeDef->GetFaction();
mFromDEF = true;
mName = t_defNPC->GetActorName();
-\r
-\r
- // Load dialogscript for this NPC right uppon startup\r
- mDialogScript = t_NpcTypeDef->GetDialogScript();\r
- CleanUpString(&mDialogScript);\r
-\r
- // Try to load any lua scripts\r
- // Checks are done in target function\r
- LoadLUAScript();\r
+
+
+ // Load dialogscript for this NPC right uppon startup
+ mDialogScript = t_NpcTypeDef->GetDialogScript();
+ CleanUpString(&mDialogScript);
+
+ // Try to load any lua scripts
+ // Checks are done in target function
+ LoadLUAScript();
if ( gDevDebug ) Console->Print( "[DEBUG] NPC: WID:%d NID:%d TID:%d CL:%d PX:%d PY:%d PZ:%d ", mWorldID, mNameID, mTypeID, mClothing, mPosX, mPosY, mPosZ);
- if ( gDevDebug ) Console->Print( "ANG:%d HITPOINTS:%d TRADE:%d LOOT:%d NAME:%s CNAME:%s CUSTOMSCRIPT:%s", mAngle, mHealth, mTrader, mLoot, mName.c_str(), mCustomName.c_str(), mCustomLua.c_str() );\r
+ if ( gDevDebug ) Console->Print( "ANG:%d HITPOINTS:%d TRADE:%d LOOT:%d NAME:%s CNAME:%s CUSTOMSCRIPT:%s", mAngle, mHealth, mTrader, mLoot, mName.c_str(), mCustomName.c_str(), mCustomLua.c_str() );
if ( gDevDebug ) Console->Print( "DIALOGSCR:%s", mDialogScript.c_str() );
return true;
}
-\r
-bool PNPC::SQL_Load()\r
-{\r
- if ( gDevDebug ) Console->Print( "[DEBUG] Now loading NPC data for NPC id %d from SQL", mID );\r
- MYSQL_RES *result = NULL;\r
- MYSQL_ROW row;\r
- char query[100];\r
-\r
- snprintf( query, 100, "SELECT * FROM `npc_spawns` WHERE `npc_id` = %d", mID );\r
- if ( gDevDebug ) Console->Print( "[DEBUG] Executing query %s", query );\r
- result = MySQL->GameResQuery( query );\r
- if ( result == NULL )\r
- {\r
- Console->Print( RED, BLACK, "PNPC::SQL_Load could not load NPC definition" );\r
- Console->Print( "Query was:" );\r
- Console->Print( "%s", query );\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
- if ( mysql_num_rows( result ) == 0 )\r
- {\r
- if ( gDevDebug ) Console->Print( "[DEBUG] No NPCs found, returning false" );\r
- MySQL->FreeGameSQLResult( result );\r
- return false;\r
- }\r
- else if ( mysql_num_rows( result ) > 1 )\r
- {\r
- Console->Print( RED, BLACK, "PNPC::SQL_Load Duplicate entry for NPC %d", mID );\r
- MySQL->FreeGameSQLResult( result );\r
- return false;\r
- }\r
- if ( gDevDebug ) Console->Print( "[DEBUG] One NPC found for my ID. Now grabbing data..." );\r
- row = mysql_fetch_row( result );\r
-\r
- mWorldID = atoi( row[npc_worldid] );\r
- mNameID = atoi( row[npc_nameid] );\r
- mTypeID = atoi( row[npc_typeid] );\r
- mClothing = atoi( row[npc_clothing] );\r
- mPosX = atoi( row[npc_x] );\r
- mPosY = atoi( row[npc_y] );\r
- mPosZ = atoi( row[npc_z] );\r
- mAngle = atoi( row[npc_angle] );\r
- mLoot = atoi( row[npc_loot] );\r
- mHealth = atoi( row[npc_unknown] );\r
- mMaxHealth = mHealth;\r
- mTrader = atoi( row[npc_trader] );\r
- mItemQuality = atoi( row[npc_shop_quality] );\r
- if(atoi(row[npc_scripting]) == 1)\r
- mScripting = true;\r
- else\r
- mScripting = false;\r
-\r
- if ( row[npc_name] != NULL )\r
- mName = row[npc_name];\r
-\r
- if ( row[npc_customname] != NULL )\r
- mCustomName = row[npc_customname];\r
-\r
- if ( row[npc_customscript] != NULL )\r
- mCustomLua = row[npc_customscript];\r
-\r
- // Now make sure we have an valid NPC here. Besides we need some more information\r
- const PDefNpc* t_npc = GameDefs->Npcs()->GetDef(mNameID);\r
- if(!t_npc)\r
- {\r
- Console->Print( RED, BLACK, "PNPC::SQL_Load Invalid NPC Type found; SQL ID: %d", mID );\r
- return false;\r
- }\r
- mFaction = t_npc->GetFaction();\r
-\r
- // Load dialogscript for this NPC right uppon startup\r
- // !-> Only if no custom lua script is attached <-!\r
- if(mCustomLua.length() < 1)\r
- {\r
- if(t_npc->GetDialogScript().length() > 3)\r
- {\r
- size_t tfound;\r
- std::string t_dialogscript = t_npc->GetDialogScript();\r
- std::string t_replacechr ("\"");\r
-\r
- tfound = t_dialogscript.find(t_replacechr);\r
- while(tfound != std::string::npos)\r
- {\r
- t_dialogscript.replace(tfound, 1, " ");\r
- tfound = t_dialogscript.find( t_replacechr, tfound +1 );\r
- }\r
- Trim(&t_dialogscript);\r
- if(t_dialogscript.length() > 1)\r
- {\r
- mDialogScript = t_dialogscript;\r
- }\r
- }\r
- }\r
- // Try to load any lua scripts\r
- // Checks are done in target function\r
- LoadLUAScript();\r
-\r
- if ( gDevDebug ) Console->Print( "[DEBUG] NPC: WID:%d NID:%d TID:%d CL:%d PX:%d PY:%d PZ:%d ", mWorldID, mNameID, mTypeID, mClothing, mPosX, mPosY, mPosZ);\r
- if ( gDevDebug ) Console->Print( "ANG:%d HITPTS:%d TRADE:%d LOOT:%d NAME:%s CNAME:%s CUSTOMSCRIPT:%s", mAngle, mHealth, mTrader, mLoot, mName.c_str(), mCustomName.c_str(), mCustomLua.c_str() );\r
- if ( gDevDebug ) Console->Print( "DIALOGSCR:%s", mDialogScript.c_str() );\r
- MySQL->FreeGameSQLResult( result );\r
- return true;\r
-}\r
-\r
-bool PNPC::LoadLUAScript()\r
-{\r
- uint32_t tFileLen = 0;\r
- PFile* fLua = NULL;\r
- std::string tLuaFile = "";\r
- std::string tHDRFile = "";\r
-\r
- // Load LUA script and include the correct header file\r
- // based in mDialogScript\r
- // if mDialogScript is empty, look at mCustomLua and load this file. Standart include header for custom\r
- // script files is dialogheader.lua since we dont know (yet) what standart header the NC Client uses\r
- // for custom loaded scripts.\r
-\r
- if(mDialogScript.length() > 1)\r
- {\r
- // Get LUA filename from defs\r
- const PDefScripts* tDefScripts = NULL;\r
- std::map<int, PDefScripts*>::const_iterator itScrStart = GameDefs->Scripts()->ConstIteratorBegin();\r
- std::map<int, PDefScripts*>::const_iterator itScrEnd = GameDefs->Scripts()->ConstIteratorEnd();\r
- for ( std::map<int, PDefScripts*>::const_iterator i = itScrStart; i != itScrEnd; i++ )\r
- {\r
- tDefScripts = i->second;\r
- // Console->Print("[DEBUG PNPC::LoadLUAScript] Identifier: [%s] LUA: [%s]", tDefScripts->GetIdentifier().c_str(), tDefScripts->GetLuaFile().c_str());\r
-\r
- if(tDefScripts->GetIdentifier().compare(mDialogScript) == 0)\r
- {\r
- break;\r
- }\r
- }\r
- // If we left the loop without an positive match.. false!\r
- if(tDefScripts->GetIdentifier().compare(mDialogScript) != 0)\r
- {\r
- return false;\r
- }\r
-\r
- // Assign our LUA file to load later\r
- tLuaFile = tDefScripts->GetLuaFile();\r
- // MaKe ThE sTrInG aLl lowercase! :)\r
- std::transform(tLuaFile.begin(), tLuaFile.end(), tLuaFile.begin(), (int(*)(int))std::tolower);\r
-\r
-\r
- // We only have 2 headerfiles, so this one is hardcoded\r
- if(tDefScripts->GetScriptHeader() == "DIALOGHEADER")\r
- {\r
- tHDRFile = "scripts/lua/dialogheader.lua";\r
- }\r
- else if(tDefScripts->GetScriptHeader() == "MISSIONHEADER")\r
- {\r
- tHDRFile = "scripts/lua/missionheader.lua";\r
- }\r
- }\r
- // Customlua is set?\r
- else if(mCustomLua.length() > 1)\r
- {\r
- // Assign lua file and header\r
- tLuaFile = mCustomLua;\r
- tHDRFile = "scripts/lua/dialogheader.lua";\r
- }\r
- else\r
- {\r
- // No LUA Scripts to load. Skipping\r
- return true;\r
- }\r
-\r
- // Load HEADER file\r
- fLua = Filesystem->Open( "", tHDRFile.c_str(), Config->GetOption( "nc_data_path" ) );\r
- if(fLua)\r
- {\r
- tFileLen = fLua->GetSize();\r
- char* t_content = new char[tFileLen+1];\r
- memset(t_content, '\0', tFileLen+1);\r
-\r
- fLua->Read( t_content, tFileLen );\r
- Filesystem->Close( fLua );\r
- mLUAFile = t_content;\r
- delete t_content;\r
- if (gDevDebug) Console->Print( "%s [PNPC::LoadLUAScript] Loaded LUA Header Script %s", Console->ColorText( GREEN, BLACK, "[SUCCESS]" ), tHDRFile.c_str() );\r
- }\r
- else\r
- {\r
- Console->Print( "%s [PNPC::LoadLUAScript] Unable to load LUA Header script %s NPC is now DISABLED for scripting", Console->ColorText( RED, BLACK, "[ERROR]" ), tLuaFile.c_str() );\r
- // We encountered an error while loading. Make sure this NPC will never act as Dialog NPC!\r
- mLUAFile = "";\r
- mCustomLua = "";\r
- mDialogScript = "";\r
- return false;\r
- }\r
-\r
- // Reset vars\r
- tFileLen = 0;\r
- fLua = NULL;\r
-\r
- fLua = Filesystem->Open( "", tLuaFile.c_str(), Config->GetOption( "nc_data_path" ) );\r
- if(fLua)\r
- {\r
- tFileLen = fLua->GetSize();\r
- char* t_content = new char[tFileLen+1];\r
- memset(t_content, '\0', tFileLen+1);\r
-\r
- fLua->Read( t_content, tFileLen );\r
- Filesystem->Close( fLua );\r
- mLUAFile += t_content; // APPEND the script to our existing lua headerfile\r
- delete t_content;\r
- if (gDevDebug) Console->Print( "%s [PNPC::LoadLUAScript] Loaded LUA Script %s", Console->ColorText( GREEN, BLACK, "[SUCCESS]" ), tLuaFile.c_str() );\r
- //Console->Print( "%s", mLUAFile.c_str() );\r
- }\r
- else\r
- {\r
- Console->Print( "%s [PNPC::LoadLUAScript] Unable to load LUA Script %s NPC is now DISABLED for scripting", Console->ColorText( RED, BLACK, "[ERROR]" ), tLuaFile.c_str() );\r
- // We encountered an error while loading. Make sure this NPC will never act as Dialog NPC!\r
- mLUAFile = "";\r
- mCustomLua = "";\r
- mDialogScript = "";\r
- return false;\r
- }\r
- // LUA file prepared. Check if LUA file is valid\r
- if(LuaEngine->CheckLUAFile(mLUAFile) == true)\r
- {\r
- // Everything is fine. NPC is ready for action\r
- return true;\r
- }\r
- else\r
- {\r
- // LUA file seems to be corrupt\r
- mLUAFile = "";\r
- mCustomLua = "";\r
- mDialogScript = "";\r
- return false;\r
- }\r
-}\r
+
+bool PNPC::SQL_Load()
+{
+ if ( gDevDebug ) Console->Print( "[DEBUG] Now loading NPC data for NPC id %d from SQL", mID );
+ MYSQL_RES *result = NULL;
+ MYSQL_ROW row;
+ char query[100];
+
+ snprintf( query, 100, "SELECT * FROM `npc_spawns` WHERE `npc_id` = %d", mID );
+ if ( gDevDebug ) Console->Print( "[DEBUG] Executing query %s", query );
+ result = MySQL->GameResQuery( query );
+ if ( result == NULL )
+ {
+ Console->Print( RED, BLACK, "PNPC::SQL_Load could not load NPC definition" );
+ Console->Print( "Query was:" );
+ Console->Print( "%s", query );
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+ if ( mysql_num_rows( result ) == 0 )
+ {
+ if ( gDevDebug ) Console->Print( "[DEBUG] No NPCs found, returning false" );
+ MySQL->FreeGameSQLResult( result );
+ return false;
+ }
+ else if ( mysql_num_rows( result ) > 1 )
+ {
+ Console->Print( RED, BLACK, "PNPC::SQL_Load Duplicate entry for NPC %d", mID );
+ MySQL->FreeGameSQLResult( result );
+ return false;
+ }
+ if ( gDevDebug ) Console->Print( "[DEBUG] One NPC found for my ID. Now grabbing data..." );
+ row = mysql_fetch_row( result );
+
+ mWorldID = atoi( row[npc_worldid] );
+ mNameID = atoi( row[npc_nameid] );
+ mTypeID = atoi( row[npc_typeid] );
+ mClothing = atoi( row[npc_clothing] );
+ mPosX = atoi( row[npc_x] );
+ mPosY = atoi( row[npc_y] );
+ mPosZ = atoi( row[npc_z] );
+ mAngle = atoi( row[npc_angle] );
+ mLoot = atoi( row[npc_loot] );
+ mHealth = atoi( row[npc_unknown] );
+ mMaxHealth = mHealth;
+ mTrader = atoi( row[npc_trader] );
+ mItemQuality = atoi( row[npc_shop_quality] );
+ if(atoi(row[npc_scripting]) == 1)
+ mScripting = true;
+ else
+ mScripting = false;
+
+ if ( row[npc_name] != NULL )
+ mName = row[npc_name];
+
+ if ( row[npc_customname] != NULL )
+ mCustomName = row[npc_customname];
+
+ if ( row[npc_customscript] != NULL )
+ mCustomLua = row[npc_customscript];
+
+ // Now make sure we have an valid NPC here. Besides we need some more information
+ const PDefNpc* t_npc = GameDefs->Npcs()->GetDef(mNameID);
+ if(!t_npc)
+ {
+ Console->Print( RED, BLACK, "PNPC::SQL_Load Invalid NPC Type found; SQL ID: %d", mID );
+ return false;
+ }
+ mFaction = t_npc->GetFaction();
+
+ // Load dialogscript for this NPC right uppon startup
+ // !-> Only if no custom lua script is attached <-!
+ if(mCustomLua.length() < 1)
+ {
+ if(t_npc->GetDialogScript().length() > 3)
+ {
+ size_t tfound;
+ std::string t_dialogscript = t_npc->GetDialogScript();
+ std::string t_replacechr ("\"");
+
+ tfound = t_dialogscript.find(t_replacechr);
+ while(tfound != std::string::npos)
+ {
+ t_dialogscript.replace(tfound, 1, " ");
+ tfound = t_dialogscript.find( t_replacechr, tfound +1 );
+ }
+ Trim(&t_dialogscript);
+ if(t_dialogscript.length() > 1)
+ {
+ mDialogScript = t_dialogscript;
+ }
+ }
+ }
+ // Try to load any lua scripts
+ // Checks are done in target function
+ LoadLUAScript();
+
+ if ( gDevDebug ) Console->Print( "[DEBUG] NPC: WID:%d NID:%d TID:%d CL:%d PX:%d PY:%d PZ:%d ", mWorldID, mNameID, mTypeID, mClothing, mPosX, mPosY, mPosZ);
+ if ( gDevDebug ) Console->Print( "ANG:%d HITPTS:%d TRADE:%d LOOT:%d NAME:%s CNAME:%s CUSTOMSCRIPT:%s", mAngle, mHealth, mTrader, mLoot, mName.c_str(), mCustomName.c_str(), mCustomLua.c_str() );
+ if ( gDevDebug ) Console->Print( "DIALOGSCR:%s", mDialogScript.c_str() );
+ MySQL->FreeGameSQLResult( result );
+ return true;
+}
+
+bool PNPC::LoadLUAScript()
+{
+ uint32_t tFileLen = 0;
+ PFile* fLua = NULL;
+ std::string tLuaFile = "";
+ std::string tHDRFile = "";
+
+ // Load LUA script and include the correct header file
+ // based in mDialogScript
+ // if mDialogScript is empty, look at mCustomLua and load this file. Standart include header for custom
+ // script files is dialogheader.lua since we dont know (yet) what standart header the NC Client uses
+ // for custom loaded scripts.
+
+ if(mDialogScript.length() > 1)
+ {
+ // Get LUA filename from defs
+ const PDefScripts* tDefScripts = NULL;
+ std::map<int, PDefScripts*>::const_iterator itScrStart = GameDefs->Scripts()->ConstIteratorBegin();
+ std::map<int, PDefScripts*>::const_iterator itScrEnd = GameDefs->Scripts()->ConstIteratorEnd();
+ for ( std::map<int, PDefScripts*>::const_iterator i = itScrStart; i != itScrEnd; i++ )
+ {
+ tDefScripts = i->second;
+ // Console->Print("[DEBUG PNPC::LoadLUAScript] Identifier: [%s] LUA: [%s]", tDefScripts->GetIdentifier().c_str(), tDefScripts->GetLuaFile().c_str());
+
+ if(tDefScripts->GetIdentifier().compare(mDialogScript) == 0)
+ {
+ break;
+ }
+ }
+ // If we left the loop without an positive match.. false!
+ if(tDefScripts->GetIdentifier().compare(mDialogScript) != 0)
+ {
+ return false;
+ }
+
+ // Assign our LUA file to load later
+ tLuaFile = tDefScripts->GetLuaFile();
+ // MaKe ThE sTrInG aLl lowercase! :)
+ std::transform(tLuaFile.begin(), tLuaFile.end(), tLuaFile.begin(), (int(*)(int))std::tolower);
+
+
+ // We only have 2 headerfiles, so this one is hardcoded
+ if(tDefScripts->GetScriptHeader() == "DIALOGHEADER")
+ {
+ tHDRFile = "scripts/lua/dialogheader.lua";
+ }
+ else if(tDefScripts->GetScriptHeader() == "MISSIONHEADER")
+ {
+ tHDRFile = "scripts/lua/missionheader.lua";
+ }
+ }
+ // Customlua is set?
+ else if(mCustomLua.length() > 1)
+ {
+ // Assign lua file and header
+ tLuaFile = mCustomLua;
+ tHDRFile = "scripts/lua/dialogheader.lua";
+ }
+ else
+ {
+ // No LUA Scripts to load. Skipping
+ return true;
+ }
+
+ // Load HEADER file
+ fLua = Filesystem->Open( "", tHDRFile.c_str(), Config->GetOption( "nc_data_path" ) );
+ if(fLua)
+ {
+ tFileLen = fLua->GetSize();
+ char* t_content = new char[tFileLen+1];
+ memset(t_content, '\0', tFileLen+1);
+
+ fLua->Read( t_content, tFileLen );
+ Filesystem->Close( fLua );
+ mLUAFile = t_content;
+ delete t_content;
+ if (gDevDebug) Console->Print( "%s [PNPC::LoadLUAScript] Loaded LUA Header Script %s", Console->ColorText( GREEN, BLACK, "[SUCCESS]" ), tHDRFile.c_str() );
+ }
+ else
+ {
+ Console->Print( "%s [PNPC::LoadLUAScript] Unable to load LUA Header script %s NPC is now DISABLED for scripting", Console->ColorText( RED, BLACK, "[ERROR]" ), tLuaFile.c_str() );
+ // We encountered an error while loading. Make sure this NPC will never act as Dialog NPC!
+ mLUAFile = "";
+ mCustomLua = "";
+ mDialogScript = "";
+ return false;
+ }
+
+ // Reset vars
+ tFileLen = 0;
+ fLua = NULL;
+
+ fLua = Filesystem->Open( "", tLuaFile.c_str(), Config->GetOption( "nc_data_path" ) );
+ if(fLua)
+ {
+ tFileLen = fLua->GetSize();
+ char* t_content = new char[tFileLen+1];
+ memset(t_content, '\0', tFileLen+1);
+
+ fLua->Read( t_content, tFileLen );
+ Filesystem->Close( fLua );
+ mLUAFile += t_content; // APPEND the script to our existing lua headerfile
+ delete t_content;
+ if (gDevDebug) Console->Print( "%s [PNPC::LoadLUAScript] Loaded LUA Script %s", Console->ColorText( GREEN, BLACK, "[SUCCESS]" ), tLuaFile.c_str() );
+ //Console->Print( "%s", mLUAFile.c_str() );
+ }
+ else
+ {
+ Console->Print( "%s [PNPC::LoadLUAScript] Unable to load LUA Script %s NPC is now DISABLED for scripting", Console->ColorText( RED, BLACK, "[ERROR]" ), tLuaFile.c_str() );
+ // We encountered an error while loading. Make sure this NPC will never act as Dialog NPC!
+ mLUAFile = "";
+ mCustomLua = "";
+ mDialogScript = "";
+ return false;
+ }
+ // LUA file prepared. Check if LUA file is valid
+ if(LuaEngine->CheckLUAFile(mLUAFile) == true)
+ {
+ // Everything is fine. NPC is ready for action
+ return true;
+ }
+ else
+ {
+ // LUA file seems to be corrupt
+ mLUAFile = "";
+ mCustomLua = "";
+ mDialogScript = "";
+ return false;
+ }
+}
void PNPC::Die()
{
}
void PNPC::Update()
-{\r
+{
// Has to be changed for mobs later
if ( std::time( NULL ) >= mRespawn && (mAction&NPC_ACTIONSTATE_DEATH) )
- {\r
+ {
if ( gDevDebug ) Console->Print( "[DEBUG] NPC Update: Respawn timer triggered! Setting NPC back to life" );
mHealth = mMaxHealth;
- mAction = NPC_ACTIONSTATE_IDLE;\r
+ mAction = NPC_ACTIONSTATE_IDLE;
mWeaponStatus = NPC_SHOOT_IDLE;
mDirty = true;
- }\r
+ }
}
-\r
+
void PNPC::InitVars()
{
mID = 0;
mPosY = 0;
mPosZ = 0;
mAngle = 0;
- mHealth = 0;\r
+ mHealth = 0;
mUnknown = 0;
mTrader = 0;
- mLoot = 0;\r
+ mLoot = 0;
mDialogScript = "";
mName = "";
mCustomName = "";
mCustomLua = "";
- mAction = NPC_ACTIONSTATE_IDLE;\r
+ mAction = NPC_ACTIONSTATE_IDLE;
mWeaponStatus = NPC_SHOOT_IDLE;
//mDeath = false;
mTarget = 0;
mDirty = false; // No need to send instand update
// WorldID Fix 10.10.2009
- mFromDEF = false;\r
- mItemQuality = 50;\r
- mScripting = true;\r
- mFaction = 0;\r
-\r
- // Set next update timer for this NPC to 10 - 30 seconds\r
- // Note: this is for regular heartbeats only. If npc is dirty,\r
- // an update is sent anyway\r
+ mFromDEF = false;
+ mItemQuality = 50;
+ mScripting = true;
+ mFaction = 0;
+
+ // Set next update timer for this NPC to 10 - 30 seconds
+ // Note: this is for regular heartbeats only. If npc is dirty,
+ // an update is sent anyway
mNextUpdate = std::time(NULL) + GetRandom(30, 10);
}
-\r
-void PNPC::Attack( uint32_t nWorldID, uint8_t nType, uint8_t nUnknown )\r
-{\r
- mDirty = true;\r
- mTarget = nWorldID;\r
- mAction = NPC_ACTIONSTATE_ATTACK;\r
- mWeaponStatus = nType;\r
- mUnknown = nUnknown;\r
-}\r
+
+void PNPC::Attack( uint32_t nWorldID, uint8_t nType, uint8_t nUnknown )
+{
+ mDirty = true;
+ mTarget = nWorldID;
+ mAction = NPC_ACTIONSTATE_ATTACK;
+ mWeaponStatus = nType;
+ mUnknown = nUnknown;
+}
PNPC::PNPC( int nSQLID )
{
*/
///***********************************************************************
///***********************************************************************
-\r
-// Broadcast a single NPC\r
-void PNPCWorld::BroadcastNewNPC(PNPC* nNpc)\r
-{\r
- std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle );\r
- PMessage* tmpMsg = MsgBuilder->BuildNPCMassInfoMsg (nNpc->mWorldID, nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY,\r
- nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr,\r
- &nNpc->mName, &nNpc->mCustomName);\r
-\r
- ClientManager->UDPBroadcast( tmpMsg, mWorldID );\r
-}\r
-\r
-\r
-bool PNPCWorld::AddNPC(uint32_t nSQL_ID, uint32_t nRaw_ID)\r
-{\r
- PNPC* tmpNpc = new PNPC( nSQL_ID );\r
- if(tmpNpc->mSuccess == true)\r
- {\r
- // Now broadcast the new NPC to all clients\r
- BroadcastNewNPC(tmpNpc);\r
- mNPCs.insert( std::make_pair( nRaw_ID, tmpNpc ) );\r
- tmpNpc = NULL;\r
- if ( gDevDebug ) Console->Print( "[PNPCWorld::AddNPC] Custom NPC added" );\r
- }\r
- else\r
- {\r
- if ( gDevDebug ) Console->Print( "[PNPCWorld::AddNPC] Custom NPC not added due error" );\r
- delete tmpNpc;\r
- return false;\r
- }\r
-\r
- return true;\r
-}\r
-\r
-void PNPCWorld::DelNPC(uint32_t nWorldID)\r
-{\r
- PNPCMap::iterator it = mNPCs.find( nWorldID );\r
- if ( it == mNPCs.end() )\r
- return;\r
-\r
- // Delete NPC from Map\r
- mNPCs.erase(it);\r
-\r
- // Send Vanish message to clients\r
- PMessage* tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg(nWorldID);\r
- ClientManager->UDPBroadcast( tmpMsg, mWorldID );\r
-\r
- return;\r
-}\r
-\r
-void PNPCWorld::SendSingleNPCInfo( PClient* nClient, PNPC* nNpc )\r
-{\r
- std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle );\r
- PMessage* tmpMsg = MsgBuilder->BuildNPCSingleInfoMsg (nClient, nNpc->GetRealWorldID(), nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY,\r
- nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr,\r
- &nNpc->mName, &nNpc->mCustomName);\r
-\r
- nClient->SendUDPMessage( tmpMsg );\r
- return;\r
-}\r
+
+// Broadcast a single NPC
+void PNPCWorld::BroadcastNewNPC(PNPC* nNpc)
+{
+ std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle );
+ PMessage* tmpMsg = MsgBuilder->BuildNPCMassInfoMsg (nNpc->mWorldID, nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY,
+ nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr,
+ &nNpc->mName, &nNpc->mCustomName);
+
+ ClientManager->UDPBroadcast( tmpMsg, mWorldID );
+}
+
+
+bool PNPCWorld::AddNPC(uint32_t nSQL_ID, uint32_t nRaw_ID)
+{
+ PNPC* tmpNpc = new PNPC( nSQL_ID );
+ if(tmpNpc->mSuccess == true)
+ {
+ // Now broadcast the new NPC to all clients
+ BroadcastNewNPC(tmpNpc);
+ mNPCs.insert( std::make_pair( nRaw_ID, tmpNpc ) );
+ tmpNpc = NULL;
+ if ( gDevDebug ) Console->Print( "[PNPCWorld::AddNPC] Custom NPC added" );
+ }
+ else
+ {
+ if ( gDevDebug ) Console->Print( "[PNPCWorld::AddNPC] Custom NPC not added due error" );
+ delete tmpNpc;
+ return false;
+ }
+
+ return true;
+}
+
+void PNPCWorld::DelNPC(uint32_t nWorldID)
+{
+ PNPCMap::iterator it = mNPCs.find( nWorldID );
+ if ( it == mNPCs.end() )
+ return;
+
+ // Delete NPC from Map
+ mNPCs.erase(it);
+
+ // Send Vanish message to clients
+ PMessage* tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg(nWorldID);
+ ClientManager->UDPBroadcast( tmpMsg, mWorldID );
+
+ return;
+}
+
+void PNPCWorld::SendSingleNPCInfo( PClient* nClient, PNPC* nNpc )
+{
+ std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle );
+ PMessage* tmpMsg = MsgBuilder->BuildNPCSingleInfoMsg (nClient, nNpc->GetRealWorldID(), nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY,
+ nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr,
+ &nNpc->mName, &nNpc->mCustomName);
+
+ nClient->SendUDPMessage( tmpMsg );
+ return;
+}
void PNPCWorld::MSG_SendNPCs( PClient* nClient )
-{\r
- PNPC* nNpc = NULL;\r
- for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ )\r
- {\r
- nNpc = it->second;\r
-\r
- std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle );\r
- PMessage* tmpMsg = MsgBuilder->BuildNPCSingleInfoMsg (nClient, nNpc->GetRealWorldID(), nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY,\r
- nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr,\r
- &nNpc->mName, &nNpc->mCustomName);\r
-\r
- nClient->SendUDPMessage( tmpMsg );\r
- }\r
-\r
- return;\r
+{
+ PNPC* nNpc = NULL;
+ for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ )
+ {
+ nNpc = it->second;
+
+ std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle );
+ PMessage* tmpMsg = MsgBuilder->BuildNPCSingleInfoMsg (nClient, nNpc->GetRealWorldID(), nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY,
+ nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr,
+ &nNpc->mName, &nNpc->mCustomName);
+
+ nClient->SendUDPMessage( tmpMsg );
+ }
+
+ return;
}
bool PNPCWorld::LoadNPCfromSQL()
delete it->second;
mNPCs.erase( it );
}
-}\r
-\r
-void PNPCWorld::Update() // v2; New send function\r
-{\r
- // Updates NPC in a World.\r
- // If NPC is dirty, send "large" update. Else\r
- // send small "i'm alive" message\r
- std::time_t tNow = std::time(NULL);\r
- PNPC* tNPC = NULL;\r
- for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ )\r
- {\r
- if ( it->second )\r
- {\r
- tNPC = it->second;\r
- // Check for enemies nearby\r
- CheckForEnemies(tNPC);\r
- // Let NPC make themselfs "dirty"\r
- tNPC->Update();\r
- // Only update dirty npcs\r
- if ( tNPC->mDirty == true || tNPC->mNextUpdate <= tNow)\r
- {\r
- PMessage* tmpMsg = MsgBuilder->BuildNPCUpdateMsg(tNPC->GetRealWorldID(),\r
- tNPC->mPosY,\r
- tNPC->mPosZ,\r
- tNPC->mPosX,\r
- tNPC->GetActionStatus(),\r
- tNPC->mHealth,\r
- tNPC->GetWeaponStatus(),\r
- tNPC->mUnknown,\r
- tNPC->mTarget);\r
-\r
- ClientManager->UDPBroadcast( tmpMsg, mWorldID );\r
- tNPC->mDirty = false;\r
- tNPC->PushUpdateTimer();\r
- }\r
- }\r
- }\r
-\r
- return;\r
+}
+
+void PNPCWorld::Update() // v2; New send function
+{
+ // Updates NPC in a World.
+ // If NPC is dirty, send "large" update. Else
+ // send small "i'm alive" message
+ std::time_t tNow = std::time(NULL);
+ PNPC* tNPC = NULL;
+ for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ )
+ {
+ if ( it->second )
+ {
+ tNPC = it->second;
+ // Check for enemies nearby
+ CheckForEnemies(tNPC);
+ // Let NPC make themselfs "dirty"
+ tNPC->Update();
+ // Only update dirty npcs
+ if ( tNPC->mDirty == true || tNPC->mNextUpdate <= tNow)
+ {
+ PMessage* tmpMsg = MsgBuilder->BuildNPCUpdateMsg(tNPC->GetRealWorldID(),
+ tNPC->mPosY,
+ tNPC->mPosZ,
+ tNPC->mPosX,
+ tNPC->GetActionStatus(),
+ tNPC->mHealth,
+ tNPC->GetWeaponStatus(),
+ tNPC->mUnknown,
+ tNPC->mTarget);
+
+ ClientManager->UDPBroadcast( tmpMsg, mWorldID );
+ tNPC->mDirty = false;
+ tNPC->PushUpdateTimer();
+ }
+ }
+ }
+
+ return;
}
-/*\r
+/*
void PNPCWorld::Update()
-{\r
- // Updates NPC in a World.\r
- // If NPC is dirty, send "large" update. Else\r
- // send small "i'm alive" message\r
- std::time_t tNow = std::time(NULL);\r
- PNPC* tNPC = NULL;\r
- for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ )\r
- {\r
- if ( it->second )\r
- {\r
- tNPC = it->second;\r
- // Check for enemies nearby\r
- CheckForEnemies(tNPC);\r
- // Let NPC make themselfs "dirty"\r
- tNPC->Update();\r
- // Only update dirty npcs\r
- if ( tNPC->mDirty == true )\r
- {\r
- PMessage* tmpMsg = MsgBuilder->BuildNPCMassUpdateMsg( tNPC->GetRealWorldID(), tNPC->mPosX, tNPC->mPosY,\r
- tNPC->mPosZ, tNPC->GetActionStatus(), tNPC->mHealth, tNPC->mTarget, tNPC->mAction);\r
-\r
- ClientManager->UDPBroadcast( tmpMsg, mWorldID );\r
- tNPC->mDirty = false;\r
- // Large update also counts as small one, inc update counter\r
- tNPC->PushUpdateTimer();\r
- }\r
- else if(tNPC->mNextUpdate <= tNow)\r
- {\r
- PMessage* tmpMsg = MsgBuilder->BuildNPCMassAliveMsg( tNPC->GetRealWorldID(), tNPC->mPosX, tNPC->mPosY,\r
- tNPC->mPosZ, tNPC->GetActionStatus(), tNPC->mHealth, tNPC->mAction);\r
-\r
- ClientManager->UDPBroadcast( tmpMsg, mWorldID );\r
- tNPC->PushUpdateTimer();\r
- }\r
- }\r
- }\r
-\r
- return;\r
+{
+ // Updates NPC in a World.
+ // If NPC is dirty, send "large" update. Else
+ // send small "i'm alive" message
+ std::time_t tNow = std::time(NULL);
+ PNPC* tNPC = NULL;
+ for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ )
+ {
+ if ( it->second )
+ {
+ tNPC = it->second;
+ // Check for enemies nearby
+ CheckForEnemies(tNPC);
+ // Let NPC make themselfs "dirty"
+ tNPC->Update();
+ // Only update dirty npcs
+ if ( tNPC->mDirty == true )
+ {
+ PMessage* tmpMsg = MsgBuilder->BuildNPCMassUpdateMsg( tNPC->GetRealWorldID(), tNPC->mPosX, tNPC->mPosY,
+ tNPC->mPosZ, tNPC->GetActionStatus(), tNPC->mHealth, tNPC->mTarget, tNPC->mAction);
+
+ ClientManager->UDPBroadcast( tmpMsg, mWorldID );
+ tNPC->mDirty = false;
+ // Large update also counts as small one, inc update counter
+ tNPC->PushUpdateTimer();
+ }
+ else if(tNPC->mNextUpdate <= tNow)
+ {
+ PMessage* tmpMsg = MsgBuilder->BuildNPCMassAliveMsg( tNPC->GetRealWorldID(), tNPC->mPosX, tNPC->mPosY,
+ tNPC->mPosZ, tNPC->GetActionStatus(), tNPC->mHealth, tNPC->mAction);
+
+ ClientManager->UDPBroadcast( tmpMsg, mWorldID );
+ tNPC->PushUpdateTimer();
+ }
+ }
+ }
+
+ return;
}
-*/\r
+*/
PNPC* PNPCWorld::GetNPC( uint32_t nNPCID )
{
if ( gDevDebug ) Console->Print( "[DEBUG] Searching for NPC %d in list", nNPCID );
#include <vector>
#include <string>
-// Healthfactor for NPCs (see old npc.def)\r
-#define NPC_HEALTHFACTOR 15\r
- \r
-// Minimum time in seconds that has to pass before an NPC\r
-// gets his heartbeat send\r
-#define NPC_HEARTBEAT_MIN 5\r
-// Maximum time in seconds that is allowed to pass without\r
-// an NPC heartbeat\r
-#define NPC_HEARTBEAT_MAX 20\r
- \r
-// If no custom NPC is set in this Zone, what ID to start with?\r
-#define NEW_NPC_ZONEID_START 1000\r
+// Healthfactor for NPCs (see old npc.def)
+#define NPC_HEALTHFACTOR 15
+
+// Minimum time in seconds that has to pass before an NPC
+// gets his heartbeat send
+#define NPC_HEARTBEAT_MIN 5
+// Maximum time in seconds that is allowed to pass without
+// an NPC heartbeat
+#define NPC_HEARTBEAT_MAX 20
+
+// If no custom NPC is set in this Zone, what ID to start with?
+#define NEW_NPC_ZONEID_START 1000
// How many seconds have to pass until the zone gets reset?
// Reset in: NPCs and PWorld object gets deleted and reloaded when
// How many seconds have to pass until we need an NPC "keepalive" packet?
#define NPC_ALIVE_MSG 15
- \r
-// How often a NPC should check if an enemy is nearby?\r
-#define NPC_ENEMYCHECK 5\r
- \r
-#define NPC_ACTIONSTATE_SITGND 0x00\r
-#define NPC_ACTIONSTATE_ATTACK 0x01\r
-//#define NPC_ACTIONSTATE_? 0x02\r
-//#define NPC_ACTIONSTATE_? 0x04\r
-//#define NPC_ACTIONSTATE_? 0x08\r
-#define NPC_ACTIONSTATE_KNEEL 0x10\r
-#define NPC_ACTIONSTATE_PASSIVE 0x20\r
-#define NPC_ACTIONSTATE_IDLE 0x40\r
-#define NPC_ACTIONSTATE_DEATH 0x80\r
- \r
-#define NPC_SHOOT_IDLE 15\r
-#define NPC_SHOOT_SINGLE 16\r
-#define NPC_SHOOT_AUTO1 17\r
-#define NPC_SHOOT_AUTO2 18\r
- \r
+
+// How often a NPC should check if an enemy is nearby?
+#define NPC_ENEMYCHECK 5
+
+#define NPC_ACTIONSTATE_SITGND 0x00
+#define NPC_ACTIONSTATE_ATTACK 0x01
+//#define NPC_ACTIONSTATE_? 0x02
+//#define NPC_ACTIONSTATE_? 0x04
+//#define NPC_ACTIONSTATE_? 0x08
+#define NPC_ACTIONSTATE_KNEEL 0x10
+#define NPC_ACTIONSTATE_PASSIVE 0x20
+#define NPC_ACTIONSTATE_IDLE 0x40
+#define NPC_ACTIONSTATE_DEATH 0x80
+
+#define NPC_SHOOT_IDLE 15
+#define NPC_SHOOT_SINGLE 16
+#define NPC_SHOOT_AUTO1 17
+#define NPC_SHOOT_AUTO2 18
+
class PNPC;
class PNPCWorld;
typedef std::map<uint32_t, PNPC*> PNPCMap;
typedef std::map<uint32_t, PNPCWorld*> PNPCWorldMap;
- \r
+
typedef struct
{
- uint16_t ItemID;\r
+ uint16_t ItemID;
uint32_t Price;
} stShopListEntry;
- \r
+
class PNPC
{
private:
npc_unknown,
npc_trader, // trader.def entry, or clan/faction data!
npc_customname,
- npc_customscript,\r
- npc_shop_quality,\r
+ npc_customscript,
+ npc_shop_quality,
npc_scripting
};
- \r
- time_t mNextUpdate; // Timestamp for next heartbeat\r
- time_t mNextEnemyCheck; // Timestamp for next enemycheck\r
+
+ time_t mNextUpdate; // Timestamp for next heartbeat
+ time_t mNextEnemyCheck; // Timestamp for next enemycheck
void PushUpdateTimer();
// SQL values
uint16_t mPosZ;
int8_t mAngle;
uint16_t mLoot;
- uint16_t mTrader;\r
- uint8_t mItemQuality; // Used for Shopping stuff\r
- uint8_t mUnknown;\r
- \r
- std::string mDialogScript;\r
- std::string mLUAFile; // Load File; Preloaded uppon NPC creation\r
- \r
- std::vector<stShopListEntry> mVectItemsInShop; // We need to keep track of the itemorder for shopping\r
- void AddToVectorList(uint16_t nItemID, uint32_t nPrice);\r
- inline const stShopListEntry* GetItemNum(uint32_t nIdx) const { if(nIdx > mVectItemsInShop.size()) { return NULL; } else { return &mVectItemsInShop[nIdx]; }};\r
- \r
- bool mScripting; // Manual override to disable scripting for an NPC TRUE: Scripts will be executed FALSE: Scripts will be ignored\r
+ uint16_t mTrader;
+ uint8_t mItemQuality; // Used for Shopping stuff
+ uint8_t mUnknown;
+
+ std::string mDialogScript;
+ std::string mLUAFile; // Load File; Preloaded uppon NPC creation
+
+ std::vector<stShopListEntry> mVectItemsInShop; // We need to keep track of the itemorder for shopping
+ void AddToVectorList(uint16_t nItemID, uint32_t nPrice);
+ inline const stShopListEntry* GetItemNum(uint32_t nIdx) const { if(nIdx > mVectItemsInShop.size()) { return NULL; } else { return &mVectItemsInShop[nIdx]; }};
+
+ bool mScripting; // Manual override to disable scripting for an NPC TRUE: Scripts will be executed FALSE: Scripts will be ignored
std::string mName;
std::string mCustomName;
time_t mRespawn; // Respawn timer
// Runtime values
- //bool mDeath; // Death...\r
- uint8_t mFaction; // NPC's faction\r
+ //bool mDeath; // Death...
+ uint8_t mFaction; // NPC's faction
- uint16_t mHealth; // NPC Current Health-Value\r
- uint16_t mMaxHealth; // NPC Max Health value\r
+ uint16_t mHealth; // NPC Current Health-Value
+ uint16_t mMaxHealth; // NPC Max Health value
uint32_t mTarget; // Current focused player
bool mDirty; // Needs update to clients
// WorldID Fix 10.10.2009
bool mFromDEF; // to differ DEF NPCs from SQL NPCs
- bool mSuccess; // NPC load successfull?\r
- \r
-
- uint8_t mAction; // Current action\r
- inline uint8_t GetActionStatus() const { return mAction; };\r
- // 00000001 ( 1) 0x01: Attack-Mode (Depends on WeaponStatus)\r
- // 00000010 ( 2) 0x02: ?\r
- // 00000100 ( 4) 0x04: ?\r
- // 00001000 ( 8) 0x08: ?\r
- // 00010000 ( 16) 0x10: kneel\r
- // 00100000 ( 32) 0x20: Passive-Mode (Depends on WeaponStatus. Difference between 0x01: NPC does NOT open fire)\r
- // 01000000 ( 64) 0x40: Idle\r
- // 10000000 (128) 0x80: Die\r
- \r
- uint8_t mWeaponStatus;\r
- inline uint8_t GetWeaponStatus() const { return mWeaponStatus; };\r
- // 00001111 (15) 0x0F: Follow given target with eyes / Put weapon away if pulled\r
- // 00010000 (16) 0x10: Pull weapon if not pulled / If pulled, attack\r
- // 00010001 (17) 0x11: Pull weapon and attack\r
-
- \r
+ bool mSuccess; // NPC load successfull?
+
+
+ uint8_t mAction; // Current action
+ inline uint8_t GetActionStatus() const { return mAction; };
+ // 00000001 ( 1) 0x01: Attack-Mode (Depends on WeaponStatus)
+ // 00000010 ( 2) 0x02: ?
+ // 00000100 ( 4) 0x04: ?
+ // 00001000 ( 8) 0x08: ?
+ // 00010000 ( 16) 0x10: kneel
+ // 00100000 ( 32) 0x20: Passive-Mode (Depends on WeaponStatus. Difference between 0x01: NPC does NOT open fire)
+ // 01000000 ( 64) 0x40: Idle
+ // 10000000 (128) 0x80: Die
+
+ uint8_t mWeaponStatus;
+ inline uint8_t GetWeaponStatus() const { return mWeaponStatus; };
+ // 00001111 (15) 0x0F: Follow given target with eyes / Put weapon away if pulled
+ // 00010000 (16) 0x10: Pull weapon if not pulled / If pulled, attack
+ // 00010001 (17) 0x11: Pull weapon and attack
+
+
bool SQL_Load();
bool DEF_Load(uint32_t nWorldID);
- \r
- PNPC( int nSQLID );\r
- PNPC( int nDEFID, uint32_t nWorldID );\r
- ~PNPC();\r
- \r
- void InitVars();\r
- void ContentListAddItem(PMessage* nContentList, uint16_t nItemID, uint32_t nBasePrice = 0, bool nAddToList = true);\r
- void ContentListAddItemGroup(PMessage* nContentList, uint32_t nItemGroupID);\r
- void StartDialog( PClient* nClient/*, string &nDialogscript */);\r
- \r
- bool DoSQLShoppingList( PClient* nClient, PMessage* nContentList );\r
- bool HasSQLShoppingList( PClient* nClient );\r
- bool IsAllbuyer( PClient* nClient );\r
- bool LoadLUAScript();\r
- \r
+
+ PNPC( int nSQLID );
+ PNPC( int nDEFID, uint32_t nWorldID );
+ ~PNPC();
+
+ void InitVars();
+ void ContentListAddItem(PMessage* nContentList, uint16_t nItemID, uint32_t nBasePrice = 0, bool nAddToList = true);
+ void ContentListAddItemGroup(PMessage* nContentList, uint32_t nItemGroupID);
+ void StartDialog( PClient* nClient/*, string &nDialogscript */);
+
+ bool DoSQLShoppingList( PClient* nClient, PMessage* nContentList );
+ bool HasSQLShoppingList( PClient* nClient );
+ bool IsAllbuyer( PClient* nClient );
+ bool LoadLUAScript();
+
inline uint32_t GetRealWorldID() { if(mFromDEF == true) return mWorldID+255; else return mWorldID; };
public:
friend class PNPCWorld;
- \r
- inline void StopAttack() { mDirty = true; mAction = NPC_ACTIONSTATE_IDLE; mWeaponStatus = NPC_SHOOT_IDLE; };\r
- inline void Attack( PClient* nClient, uint8_t nType = NPC_SHOOT_SINGLE, uint8_t nUnknown = 90 ) { Attack(nClient->GetChar()->GetID(), nType, nUnknown); };\r
- void Attack( uint32_t nWorldID, uint8_t nType = NPC_SHOOT_SINGLE, uint8_t nUnknown = 90 );\r
- \r
+
+ inline void StopAttack() { mDirty = true; mAction = NPC_ACTIONSTATE_IDLE; mWeaponStatus = NPC_SHOOT_IDLE; };
+ inline void Attack( PClient* nClient, uint8_t nType = NPC_SHOOT_SINGLE, uint8_t nUnknown = 90 ) { Attack(nClient->GetChar()->GetID(), nType, nUnknown); };
+ void Attack( uint32_t nWorldID, uint8_t nType = NPC_SHOOT_SINGLE, uint8_t nUnknown = 90 );
+
inline void Move( uint16_t nNewX, uint16_t nNewY, uint16_t nNewZ )
{
mPosX = nNewX;
void Die(); // ... die?
void Update(); // Check respawn timer
- void StartConversation( PClient* nClient );\r
- void DoConversation( PClient* nClient, uint8_t nAnswer ) ;\r
- \r
- // GameCommands\r
- bool ReloadLUAScript();\r
- bool ReloadShopList();\r
- bool SetShopQuality(uint8_t nNewVal);\r
- inline bool IsSQLNPC() const { return !mFromDEF; };\r
- inline int GetNPCID() const { return mWorldID; };\r
- inline int GetNPCSQLID() const { return mID; };\r
- inline void SetTrader( uint16_t nTraderDef ) { mTrader = nTraderDef; };\r
- inline void SetScripting(bool nVal) { mScripting = nVal; };\r
- inline uint8_t GetFaction() const { return mFaction; };\r
+ void StartConversation( PClient* nClient );
+ void DoConversation( PClient* nClient, uint8_t nAnswer ) ;
+
+ // GameCommands
+ bool ReloadLUAScript();
+ bool ReloadShopList();
+ bool SetShopQuality(uint8_t nNewVal);
+ inline bool IsSQLNPC() const { return !mFromDEF; };
+ inline int GetNPCID() const { return mWorldID; };
+ inline int GetNPCSQLID() const { return mID; };
+ inline void SetTrader( uint16_t nTraderDef ) { mTrader = nTraderDef; };
+ inline void SetScripting(bool nVal) { mScripting = nVal; };
+ inline uint8_t GetFaction() const { return mFaction; };
};
// *****************************************
//void MSG_SendAlive();
bool LoadNPCfromSQL();
- bool LoadNPCfromDEF();\r
- \r
- void BroadcastNewNPC(PNPC* nNpc);\r
+ bool LoadNPCfromDEF();
+
+ void BroadcastNewNPC(PNPC* nNpc);
void CheckForEnemies(PNPC* nNPC);
public:
friend class PNPCManager;
- PNPC* GetNPC( uint32_t nNPCID );\r
- \r
- // Functions to add/remove an NPC while server is running\r
- void SendSingleNPCInfo( PClient* nClient, PNPC* nNpc ); // Send\r
- bool AddNPC(uint32_t nSQL_ID, uint32_t nRaw_ID); // Load single SQL NPC from given SQL ID\r
- void DelNPC(uint32_t nWorldID); // Remove given NPC from list. Works for *all* npcs\r
+ PNPC* GetNPC( uint32_t nNPCID );
+
+ // Functions to add/remove an NPC while server is running
+ void SendSingleNPCInfo( PClient* nClient, PNPC* nNpc ); // Send
+ bool AddNPC(uint32_t nSQL_ID, uint32_t nRaw_ID); // Load single SQL NPC from given SQL ID
+ void DelNPC(uint32_t nWorldID); // Remove given NPC from list. Works for *all* npcs
// but uppon zone reset they're back.
};
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-#if 0\r
-static const int RCON_INPUTLEN = 512;\r
-\r
-struct PRConClient\r
-{\r
- enum\r
- {\r
- RCCS_AUTH,\r
- RCCS_AUTH_USER,\r
- RCCS_AUTH_PASS,\r
- RCCS_VALID,\r
- RCCS_DISCONNECT\r
- } mState;\r
-\r
- PSocket *mSocket;\r
- PAccount *mAccount;\r
- char mInput[RCON_INPUTLEN];\r
- int mInputLen;\r
- bool mEcho;\r
- std::clock_t mSleep, mSleepStart;\r
- int mNumFailures;\r
-\r
- inline PRConClient(NLsocket &Sock)\r
- {\r
- mSocket = new PSocket(Sock);\r
- mAccount = 0;\r
- mInputLen = 0;\r
- mEcho = true;\r
- mSleep = 0;\r
- mSleepStart = 0;\r
- mNumFailures = 0;\r
- }\r
-\r
- inline ~PRConClient()\r
- {\r
- delete mSocket;\r
- }\r
-\r
- inline void Print(const char *Fmt, ...)\r
- {\r
- static char Str[256];\r
- va_list args;\r
- va_start(args, Fmt);\r
- vsnprintf(Str, 255, Fmt, args);\r
- va_end(args);\r
- mSocket->Write(Str);\r
- }\r
-\r
-};\r
-\r
-PRConsole::PRConsole()\r
-{\r
- mListener = NL_INVALID;\r
-}\r
-\r
-PRConsole::~PRConsole()\r
-{\r
- if(mListener != NL_INVALID)\r
- nlClose(mListener);\r
-\r
- for(ClientList::iterator i=mClients.begin(); i!=mClients.end(); i++)\r
- delete *i;\r
-}\r
-\r
-void PRConsole::Start()\r
-{\r
- // CHECK FOR rconsole enabled!!!\r
- Console->LPrint("Starting remote console...");\r
- uint16_t Port = Config->GetOptionInt("rconsole_port");\r
- mListener = nlOpen(Port, NL_TCP);\r
- if(mListener == NL_INVALID)\r
- {\r
- Console->LPrint(RED, BLACK, "[ERROR]");\r
- Console->LPrint(" Remote console failed");\r
- Console->LClose();\r
- return;\r
- }\r
-\r
- Console->LPrint(GREEN, BLACK, "Success");\r
- Console->LClose();\r
- nlListen(mListener);\r
-}\r
-\r
-void PRConsole::Update()\r
-{\r
- if(mListener==NL_INVALID)\r
- return;\r
-\r
- NLsocket temp = nlAcceptConnection(mListener);\r
- if(temp != NL_INVALID)\r
- {\r
- // TODO: print client ip addr\r
- Console->Print("RConsole: client connected");\r
- PRConClient *cl = new PRConClient(temp);\r
- cl->mState = PRConClient::RCCS_AUTH;\r
- mClients.push_back(cl);\r
- cl->Print("TinNS shell [%s]\r\n", TINNS_VERSION);\r
- }\r
-\r
- for(ClientList::iterator i=mClients.begin(); i!=mClients.end();)\r
- {\r
- ClientList::iterator j=i;\r
- PRConClient *cl = *i;\r
- ++i;\r
- if(!cl->mSocket->Update() || cl->mSocket->TimeOut())\r
- {\r
- Console->Print("RConsole: client disconnected");\r
- mClients.erase(j);\r
- delete cl;\r
- continue;\r
- }\r
-\r
- if(cl->mSleep > 0)\r
- {\r
- std::clock_t t = std::clock();\r
- cl->mSleep -= (t-cl->mSleepStart);\r
- cl->mSleepStart = t;\r
-\r
- if(cl->mSleep < 0)\r
- cl->mSleep = 0;\r
-\r
- // flush socket while sleeping\r
- int Size=0;\r
- cl->mSocket->Read(&Size);\r
-\r
- continue;\r
- }\r
-\r
- if(cl->mState==PRConClient::RCCS_AUTH)\r
- {\r
- cl->Print("\r\nlogin: ");\r
- cl->mState = PRConClient::RCCS_AUTH_USER;\r
- }\r
-\r
- const uint8_t *Buf = 0;\r
- int Size=0;\r
- if((bool)(Buf = cl->mSocket->Read(&Size)))\r
- {\r
- for(int i=0; i<Size; i++)\r
- if(cl->mInputLen < RCON_INPUTLEN)\r
- {\r
- switch(Buf[i])\r
- {\r
- case 0x08 :\r
- {\r
- if(cl->mInputLen > 0)\r
- {\r
- if(cl->mEcho)\r
- cl->mSocket->Write(Buf[i]);\r
- cl->mInput[cl->mInputLen]=0;\r
- --cl->mInputLen;\r
- }\r
- break;\r
- }\r
-\r
- case '\n' :\r
- {\r
- if(cl->mEcho)\r
- cl->mSocket->Write(Buf[i]);\r
- cl->mInput[cl->mInputLen]=0;\r
- ProcessClient(cl);\r
- cl->mInputLen = 0;\r
- break;\r
- }\r
-\r
- default :\r
- {\r
- cl->mInput[cl->mInputLen++]=Buf[i];\r
- if(cl->mEcho)\r
- cl->mSocket->Write(Buf[i]);\r
- break;\r
- }\r
- }\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PRConsole::ProcessClient(PRConClient* Client)\r
-{\r
- Console->Print(">%s", Client->mInput);\r
- if(Client->mInputLen > 1)\r
- {\r
- if(Client->mInput[Client->mInputLen-1] == '\r')\r
- Client->mInput[Client->mInputLen-1]=0;\r
-\r
- if(Client->mState == PRConClient::RCCS_AUTH_USER)\r
- {\r
- Client->mAccount = Database->GetAccount(Client->mInput);\r
- Client->mState = PRConClient::RCCS_AUTH_PASS;\r
- Client->Print("password: ");\r
- Client->mEcho = false;\r
- } else\r
- if(Client->mState == PRConClient::RCCS_AUTH_PASS)\r
- {\r
- Client->mEcho = true;\r
- if((!Client->mAccount) || (Client->mAccount->GetPassword() != Client->mInput) || (!Client->mAccount->IsConsoleAllowed()))\r
- {\r
- Client->Print("Invalid user or password\r\n");\r
- Client->mSleepStart = std::clock();\r
- ++Client->mNumFailures;\r
- if(Client->mNumFailures >= 3)\r
- {\r
- // sleep 1 minute\r
- Client->mSleep = 60*CLOCKS_PER_SEC;\r
- Client->mNumFailures = 0;\r
- } else\r
- Client->mSleep = 5*CLOCKS_PER_SEC;\r
-\r
- Client->mState = PRConClient::RCCS_AUTH;\r
- } else\r
- {\r
- Client->Print("\r\n\nUser %s logged in\r\n", Client->mAccount->GetName().c_str());\r
- Client->mState = PRConClient::RCCS_VALID;\r
- // disconnect after 30 minutes lacking socket activity\r
- Client->mSocket->SetTimeOutValue(1800);\r
- Prompt(Client);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PRConsole::Prompt(PRConClient *Client)\r
-{\r
- Client->Print("$ ", Client->mAccount->GetName().c_str(), Config->GetOption("server_name").c_str());\r
-}\r
-#endif\r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+#if 0
+static const int RCON_INPUTLEN = 512;
+
+struct PRConClient
+{
+ enum
+ {
+ RCCS_AUTH,
+ RCCS_AUTH_USER,
+ RCCS_AUTH_PASS,
+ RCCS_VALID,
+ RCCS_DISCONNECT
+ } mState;
+
+ PSocket *mSocket;
+ PAccount *mAccount;
+ char mInput[RCON_INPUTLEN];
+ int mInputLen;
+ bool mEcho;
+ std::clock_t mSleep, mSleepStart;
+ int mNumFailures;
+
+ inline PRConClient(NLsocket &Sock)
+ {
+ mSocket = new PSocket(Sock);
+ mAccount = 0;
+ mInputLen = 0;
+ mEcho = true;
+ mSleep = 0;
+ mSleepStart = 0;
+ mNumFailures = 0;
+ }
+
+ inline ~PRConClient()
+ {
+ delete mSocket;
+ }
+
+ inline void Print(const char *Fmt, ...)
+ {
+ static char Str[256];
+ va_list args;
+ va_start(args, Fmt);
+ vsnprintf(Str, 255, Fmt, args);
+ va_end(args);
+ mSocket->Write(Str);
+ }
+
+};
+
+PRConsole::PRConsole()
+{
+ mListener = NL_INVALID;
+}
+
+PRConsole::~PRConsole()
+{
+ if(mListener != NL_INVALID)
+ nlClose(mListener);
+
+ for(ClientList::iterator i=mClients.begin(); i!=mClients.end(); i++)
+ delete *i;
+}
+
+void PRConsole::Start()
+{
+ // CHECK FOR rconsole enabled!!!
+ Console->LPrint("Starting remote console...");
+ uint16_t Port = Config->GetOptionInt("rconsole_port");
+ mListener = nlOpen(Port, NL_TCP);
+ if(mListener == NL_INVALID)
+ {
+ Console->LPrint(RED, BLACK, "[ERROR]");
+ Console->LPrint(" Remote console failed");
+ Console->LClose();
+ return;
+ }
+
+ Console->LPrint(GREEN, BLACK, "Success");
+ Console->LClose();
+ nlListen(mListener);
+}
+
+void PRConsole::Update()
+{
+ if(mListener==NL_INVALID)
+ return;
+
+ NLsocket temp = nlAcceptConnection(mListener);
+ if(temp != NL_INVALID)
+ {
+ // TODO: print client ip addr
+ Console->Print("RConsole: client connected");
+ PRConClient *cl = new PRConClient(temp);
+ cl->mState = PRConClient::RCCS_AUTH;
+ mClients.push_back(cl);
+ cl->Print("TinNS shell [%s]\r\n", TINNS_VERSION);
+ }
+
+ for(ClientList::iterator i=mClients.begin(); i!=mClients.end();)
+ {
+ ClientList::iterator j=i;
+ PRConClient *cl = *i;
+ ++i;
+ if(!cl->mSocket->Update() || cl->mSocket->TimeOut())
+ {
+ Console->Print("RConsole: client disconnected");
+ mClients.erase(j);
+ delete cl;
+ continue;
+ }
+
+ if(cl->mSleep > 0)
+ {
+ std::clock_t t = std::clock();
+ cl->mSleep -= (t-cl->mSleepStart);
+ cl->mSleepStart = t;
+
+ if(cl->mSleep < 0)
+ cl->mSleep = 0;
+
+ // flush socket while sleeping
+ int Size=0;
+ cl->mSocket->Read(&Size);
+
+ continue;
+ }
+
+ if(cl->mState==PRConClient::RCCS_AUTH)
+ {
+ cl->Print("\r\nlogin: ");
+ cl->mState = PRConClient::RCCS_AUTH_USER;
+ }
+
+ const uint8_t *Buf = 0;
+ int Size=0;
+ if((bool)(Buf = cl->mSocket->Read(&Size)))
+ {
+ for(int i=0; i<Size; i++)
+ if(cl->mInputLen < RCON_INPUTLEN)
+ {
+ switch(Buf[i])
+ {
+ case 0x08 :
+ {
+ if(cl->mInputLen > 0)
+ {
+ if(cl->mEcho)
+ cl->mSocket->Write(Buf[i]);
+ cl->mInput[cl->mInputLen]=0;
+ --cl->mInputLen;
+ }
+ break;
+ }
+
+ case '\n' :
+ {
+ if(cl->mEcho)
+ cl->mSocket->Write(Buf[i]);
+ cl->mInput[cl->mInputLen]=0;
+ ProcessClient(cl);
+ cl->mInputLen = 0;
+ break;
+ }
+
+ default :
+ {
+ cl->mInput[cl->mInputLen++]=Buf[i];
+ if(cl->mEcho)
+ cl->mSocket->Write(Buf[i]);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void PRConsole::ProcessClient(PRConClient* Client)
+{
+ Console->Print(">%s", Client->mInput);
+ if(Client->mInputLen > 1)
+ {
+ if(Client->mInput[Client->mInputLen-1] == '\r')
+ Client->mInput[Client->mInputLen-1]=0;
+
+ if(Client->mState == PRConClient::RCCS_AUTH_USER)
+ {
+ Client->mAccount = Database->GetAccount(Client->mInput);
+ Client->mState = PRConClient::RCCS_AUTH_PASS;
+ Client->Print("password: ");
+ Client->mEcho = false;
+ } else
+ if(Client->mState == PRConClient::RCCS_AUTH_PASS)
+ {
+ Client->mEcho = true;
+ if((!Client->mAccount) || (Client->mAccount->GetPassword() != Client->mInput) || (!Client->mAccount->IsConsoleAllowed()))
+ {
+ Client->Print("Invalid user or password\r\n");
+ Client->mSleepStart = std::clock();
+ ++Client->mNumFailures;
+ if(Client->mNumFailures >= 3)
+ {
+ // sleep 1 minute
+ Client->mSleep = 60*CLOCKS_PER_SEC;
+ Client->mNumFailures = 0;
+ } else
+ Client->mSleep = 5*CLOCKS_PER_SEC;
+
+ Client->mState = PRConClient::RCCS_AUTH;
+ } else
+ {
+ Client->Print("\r\n\nUser %s logged in\r\n", Client->mAccount->GetName().c_str());
+ Client->mState = PRConClient::RCCS_VALID;
+ // disconnect after 30 minutes lacking socket activity
+ Client->mSocket->SetTimeOutValue(1800);
+ Prompt(Client);
+ }
+ }
+ }
+}
+
+void PRConsole::Prompt(PRConClient *Client)
+{
+ Client->Print("$ ", Client->mAccount->GetName().c_str(), Config->GetOption("server_name").c_str());
+}
+#endif
-#pragma once\r
-\r
-#if 0\r
-#include <list>\r
-\r
-struct PRConClient;\r
-\r
-class PRConsole {\r
-private :\r
- typedef std::list<PRConClient *> ClientList;\r
- ClientList mClients;\r
-\r
- void ProcessClient(PRConClient* Client);\r
- void Prompt(PRConClient *Client);\r
-public :\r
- PRConsole();\r
- ~PRConsole();\r
-\r
- void Start();\r
- void Update();\r
-};\r
-#endif\r
+#pragma once
+
+#if 0
+#include <list>
+
+struct PRConClient;
+
+class PRConsole {
+private :
+ typedef std::list<PRConClient *> ClientList;
+ ClientList mClients;
+
+ void ProcessClient(PRConClient* Client);
+ void Prompt(PRConClient *Client);
+public :
+ PRConsole();
+ ~PRConsole();
+
+ void Start();
+ void Update();
+};
+#endif
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-PServer::PServer()\r
-{\r
- mNumClients = 0;\r
- mMaxClients = Config->GetOptionInt("maxclients");\r
- mGMSlots = Config->GetOptionInt("gm_slots");\r
- if(mMaxClients==0)\r
- mMaxClients=1;\r
- if(mGMSlots==0)\r
- mGMSlots=1;\r
- Console->Print("Max clients: %i / GM slots: %i", mMaxClients, mGMSlots);\r
- mClients.reserve(mMaxClients + mGMSlots);\r
- for(int i=0; i<mMaxClients+mGMSlots; i++)\r
- mClients[i]=0;\r
-}\r
-\r
-PServer::~PServer()\r
-{\r
- for(int i=0; i<mMaxClients+mGMSlots; i++)\r
- delete mClients[i];\r
-}\r
-\r
-int PServer::NewClient()\r
-{\r
- if(mNumClients==mMaxClients+mGMSlots)\r
- return -1;\r
-\r
- for(int i=0; i<mMaxClients+mGMSlots; i++)\r
- {\r
- if(!mClients[i])\r
- {\r
- mClients[i]=new PClient(i);\r
- ++mNumClients;\r
- return i;\r
- }\r
- }\r
- return -1;\r
-}\r
-\r
-PClient *PServer::GetClient(int Client) const\r
-{\r
- if(Client < 0 || Client >= mMaxClients+mGMSlots)\r
- return 0;\r
-\r
- return mClients[Client];\r
-}\r
-\r
-void PServer::Update()\r
-{\r
- for(int i=0; i<mMaxClients+mGMSlots; i++)\r
- {\r
- if(mClients[i])\r
- {\r
- mClients[i]->Update();\r
- if(mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0)\r
- {\r
- Console->Print("Removing client %i...", i);\r
- delete mClients[i];\r
- mClients[i]=0;\r
- --mNumClients;\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PServer::Shutdown()\r
-{\r
- Console->Print("======================");\r
- Console->Print("Shutting down Gameserver...");\r
- for(int i=0; i<mMaxClients+mGMSlots; i++)\r
- {\r
- if(mClients[i])\r
- {\r
- delete mClients[i];\r
- mClients[i]=0;\r
- }\r
- }\r
-}\r
-\r
-//SELECT `s_name` , NOW( ) , `s_lastupdate` , NOW( ) - `s_lastupdate` FROM `server_list` \r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+PServer::PServer()
+{
+ mNumClients = 0;
+ mMaxClients = Config->GetOptionInt("maxclients");
+ mGMSlots = Config->GetOptionInt("gm_slots");
+ if(mMaxClients==0)
+ mMaxClients=1;
+ if(mGMSlots==0)
+ mGMSlots=1;
+ Console->Print("Max clients: %i / GM slots: %i", mMaxClients, mGMSlots);
+ mClients.reserve(mMaxClients + mGMSlots);
+ for(int i=0; i<mMaxClients+mGMSlots; i++)
+ mClients[i]=0;
+}
+
+PServer::~PServer()
+{
+ for(int i=0; i<mMaxClients+mGMSlots; i++)
+ delete mClients[i];
+}
+
+int PServer::NewClient()
+{
+ if(mNumClients==mMaxClients+mGMSlots)
+ return -1;
+
+ for(int i=0; i<mMaxClients+mGMSlots; i++)
+ {
+ if(!mClients[i])
+ {
+ mClients[i]=new PClient(i);
+ ++mNumClients;
+ return i;
+ }
+ }
+ return -1;
+}
+
+PClient *PServer::GetClient(int Client) const
+{
+ if(Client < 0 || Client >= mMaxClients+mGMSlots)
+ return 0;
+
+ return mClients[Client];
+}
+
+void PServer::Update()
+{
+ for(int i=0; i<mMaxClients+mGMSlots; i++)
+ {
+ if(mClients[i])
+ {
+ mClients[i]->Update();
+ if(mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0)
+ {
+ Console->Print("Removing client %i...", i);
+ delete mClients[i];
+ mClients[i]=0;
+ --mNumClients;
+ }
+ }
+ }
+}
+
+void PServer::Shutdown()
+{
+ Console->Print("======================");
+ Console->Print("Shutting down Gameserver...");
+ for(int i=0; i<mMaxClients+mGMSlots; i++)
+ {
+ if(mClients[i])
+ {
+ delete mClients[i];
+ mClients[i]=0;
+ }
+ }
+}
+
+//SELECT `s_name` , NOW( ) , `s_lastupdate` , NOW( ) - `s_lastupdate` FROM `server_list`
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <vector>\r
-\r
-class PClient;\r
-\r
-class PServer{\r
-private:\r
- int32_t mMaxClients;\r
- int32_t mGMSlots;\r
- int32_t mNumClients;\r
- std::vector<PClient*> mClients;\r
-\r
-public:\r
- PServer();\r
- ~PServer();\r
-\r
- inline int32_t GetMaxClients() const { return mMaxClients; }\r
- inline int32_t GetGMSlots() const { return mGMSlots; }\r
- inline int32_t GetNumClients() const { return mNumClients; }\r
- int NewClient();\r
- PClient *GetClient(int Client) const;\r
- void Update();\r
- void Shutdown();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+class PClient;
+
+class PServer{
+private:
+ int32_t mMaxClients;
+ int32_t mGMSlots;
+ int32_t mNumClients;
+ std::vector<PClient*> mClients;
+
+public:
+ PServer();
+ ~PServer();
+
+ inline int32_t GetMaxClients() const { return mMaxClients; }
+ inline int32_t GetGMSlots() const { return mGMSlots; }
+ inline int32_t GetNumClients() const { return mNumClients; }
+ int NewClient();
+ PClient *GetClient(int Client) const;
+ void Update();
+ void Shutdown();
+};
-#include <cstring>\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-PMySQL::PMySQL()\r
-{\r
- InfoDBInuse = 0;\r
- GameDBInuse = 0;\r
- info_port = Config->GetOptionInt("info_sql_port");\r
- strncpy(info_host, Config->GetOption("info_sql_host").c_str(), 100);\r
- strncpy(info_userName, Config->GetOption("info_sql_username").c_str(), 100);\r
- strncpy(info_password, Config->GetOption("info_sql_password").c_str(), 100);\r
- strncpy(info_database, Config->GetOption("info_sql_database").c_str(), 100);\r
-\r
- game_port = Config->GetOptionInt("game_sql_port");\r
- strncpy(game_host, Config->GetOption("game_sql_host").c_str(), 100);\r
- strncpy(game_userName, Config->GetOption("game_sql_username").c_str(), 100);\r
- strncpy(game_password, Config->GetOption("game_sql_password").c_str(), 100);\r
- strncpy(game_database, Config->GetOption("game_sql_database").c_str(), 100);\r
-\r
- mKeepaliveDelay = (std::time_t) (Config->GetOptionInt("mysql_wait_timeout") * 0.9) ; // we take 90% of the wait_timeout to trigger keepalive\r
- if (mKeepaliveDelay == 0)\r
- {\r
- Console->Print("%s MySQL keepalive disabled by config", Console->ColorText(GREEN, BLACK, "[Info]"));\r
- }\r
- else if (mKeepaliveDelay < 60)\r
- {\r
- Console->Print("%s Configuration option 'mysql_wait_timeout' is too low (%d sec). Reset to 60 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mKeepaliveDelay);\r
- mKeepaliveDelay = 60;\r
- }\r
- mLastKeepaliveSent = 0;\r
-}\r
-\r
-PMySQL::~PMySQL()\r
-{\r
- Console->Print("Closing MySQL connection...");\r
- mysql_close(info_dbHandle);\r
- mysql_close(game_dbHandle);\r
-}\r
-\r
-void PMySQL::Update()\r
-{\r
- CheckResCount(); // Check for MYSQL_RES mem leak\r
-\r
- // MySQL keepalive\r
- std::time_t t = std::time(NULL);\r
- if ((mKeepaliveDelay > 0) && ((t - mLastKeepaliveSent) > mKeepaliveDelay))\r
- {\r
- MYSQL_RES *result;\r
- char query[24];\r
- snprintf (query, 24, "SELECT NOW()");\r
-\r
- result = GameResQuery(query);\r
- if(!result)\r
- {\r
- Console->Print("%s Can't send GameDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
- ShowGameSQLError();\r
- return;\r
- }\r
- else\r
- FreeGameSQLResult(result);\r
-\r
- result = InfoResQuery(query);\r
- if(!result)\r
- {\r
- Console->Print("%s Can't send InfoDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
- ShowInfoSQLError();\r
- return;\r
- }\r
- else\r
- FreeInfoSQLResult(result);\r
-\r
- mLastKeepaliveSent = std::time(NULL);\r
- if (gDevDebug) Console->Print("%s MySQL keepalive sent", Console->ColorText(GREEN, BLACK, "[Debug]"));\r
- }\r
-}\r
-\r
-void PMySQL::CheckResCount()\r
-{\r
- static int MaxInfoDBCount = 0;\r
- static int MaxGameDBCount = 0;\r
-\r
- if (InfoDBInuse > MaxInfoDBCount)\r
- {\r
- Console->Print("%s Max In-use InfoDB Resources number increasing : %d (+%d)", Console->ColorText(YELLOW, BLACK, "[Notice]"), InfoDBInuse, InfoDBInuse-MaxInfoDBCount);\r
- MaxInfoDBCount = InfoDBInuse;\r
- }\r
-\r
- if (GameDBInuse > MaxGameDBCount)\r
- {\r
- Console->Print("%s Max In-use GameDB Resources number increasing : %d (+%d)", Console->ColorText(YELLOW, BLACK, "[Notice]"), GameDBInuse, GameDBInuse-MaxGameDBCount);\r
- MaxGameDBCount = GameDBInuse;\r
- }\r
-}\r
-\r
-bool PMySQL::Connect()\r
-{\r
- Console->LPrint("Establishing link to Infoserver Database...");\r
-\r
- info_dbHandle = mysql_init(NULL);\r
-\r
- if(!info_dbHandle)\r
- {\r
- Console->LPrint(RED, BLACK, "[ERROR]");\r
- Console->LClose();\r
- Console->Print(" Unable to create MySQL-Handle!");\r
- exit(0);\r
- }\r
-\r
- if(!mysql_real_connect(info_dbHandle, info_host, info_userName, info_password, info_database, info_port, NULL, 0))\r
- {\r
- Console->LPrint(RED, BLACK, "[ERROR]");\r
- Console->LClose();\r
- Console->Print("Unable to connect to Infoserver Database. MySQL returned: %s", mysql_error(info_dbHandle));\r
- }\r
- else\r
- {\r
- Console->LPrint(GREEN, BLACK, "Success");\r
- Console->LClose();\r
- }\r
-// <><><><><><><><> Gameserver DB <><><><><><><><>\r
- Console->LPrint("Establishing link to Gameserver Database...");\r
-\r
- game_dbHandle = mysql_init(NULL);\r
-\r
- if(!game_dbHandle)\r
- {\r
- Console->LPrint(RED, BLACK, "[ERROR]");\r
- Console->LClose();\r
- Console->Print(" Unable to create MySQL-Handle!");\r
- exit(0);\r
- }\r
-\r
- if(!mysql_real_connect(game_dbHandle, game_host, game_userName, game_password, game_database, game_port, NULL, 0))\r
- {\r
- Console->LPrint(RED, BLACK, "[ERROR]");\r
- Console->LClose();\r
- Console->Print("Unable to connect to Gameserver Database. MySQL returned: %s", mysql_error(game_dbHandle));\r
- return false;\r
- }\r
- else\r
- {\r
- Console->LPrint(GREEN, BLACK, "Success");\r
- Console->LClose();\r
- return true;\r
- }\r
-\r
-}\r
-// ----------------------------------------------------\r
-MYSQL_RES *PMySQL::InfoResQuery(const char *query)\r
-{\r
- int sql_result = 0;\r
- MYSQL_RES *result;\r
-\r
- sql_result = mysql_real_query(info_dbHandle, query, strlen(query));\r
- if(sql_result)\r
- {\r
- return NULL;\r
- }\r
- result = mysql_store_result(info_dbHandle);\r
- if(!result)\r
- {\r
- return NULL;\r
- }\r
- //if(InfoDBInuse == true)\r
- /*if(InfoDBInuse > 0)\r
- {\r
- Console->Print("%s another (%d) info_dbHandle result is still in use", Console->ColorText(YELLOW, BLACK, "[Warning]"), InfoDBInuse);\r
- }*/\r
-\r
- //InfoDBInuse = true;\r
- InfoDBInuse++;\r
- return result;\r
-}\r
-\r
-int PMySQL::InfoQuery(const char *query)\r
-{\r
- int sql_result = 0;\r
- sql_result = mysql_real_query(info_dbHandle, query, strlen(query));\r
-\r
- return sql_result;\r
-}\r
-\r
-void PMySQL::ShowInfoSQLError()\r
-{\r
- Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(info_dbHandle));\r
-}\r
-void PMySQL::FreeInfoSQLResult(MYSQL_RES *res)\r
-{\r
- if(InfoDBInuse > 0)\r
- {\r
- mysql_free_result(res);\r
- InfoDBInuse--;\r
- }\r
- else\r
- Console->Print("PMySQL::FreeInfoSQLResult: Nothing to free...");\r
-}\r
-// ----------------------------------------------------\r
-MYSQL_RES *PMySQL::GameResQuery(const char *query)\r
-{\r
- int sql_result = 0;\r
- MYSQL_RES *result;\r
-\r
- sql_result = mysql_real_query(game_dbHandle, query, strlen(query));\r
- if(sql_result)\r
- {\r
- return NULL;\r
- }\r
- result = mysql_store_result(game_dbHandle);\r
- if(!result)\r
- {\r
- return NULL;\r
- }\r
- /*if(GameDBInuse > 0)\r
- {\r
- Console->Print("%s another (%d) game_dbHandle result is still in use", Console->ColorText(YELLOW, BLACK, "[Warning]"), GameDBInuse);\r
- }*/\r
-\r
- //GameDBInuse = true;\r
- GameDBInuse++;\r
- return result;\r
-}\r
-\r
-int PMySQL::GameQuery(const char *query)\r
-{\r
- int sql_result = 0;\r
- sql_result = mysql_real_query(game_dbHandle, query, strlen(query));\r
-\r
- return sql_result;\r
-}\r
-\r
-void PMySQL::ShowGameSQLError()\r
-{\r
- Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(game_dbHandle));\r
-}\r
-\r
-void PMySQL::FreeGameSQLResult(MYSQL_RES *res)\r
-{\r
- if(GameDBInuse > 0)\r
- {\r
- mysql_free_result(res);\r
- GameDBInuse--;\r
- }\r
- else\r
- Console->Print("PMySQL::FreeGameSQLResult: Nothing to free...");\r
-}\r
-\r
-uint32_t PMySQL::EscapeString(const char* nText, char* dText, uint32_t dMaxLength)\r
-{\r
- uint32_t nLength = strlen(nText);\r
- uint32_t tMax = (dMaxLength - 1)/2;\r
- if(nLength > tMax)\r
- {\r
- nLength = tMax;\r
- }\r
-\r
- return mysql_real_escape_string(game_dbHandle, dText, nText, nLength);\r
-}\r
-\r
-// ----------------------------------------------------\r
-/*\r
-int PMySQL::GetWorldItemType(unsigned short ID, int Location)\r
-{\r
- char query[2048];\r
- MYSQL_RES *result;\r
- MYSQL_ROW row;\r
-\r
- if (Location > 100000)\r
- {\r
- //int nAppLoc = GetAptLocation(Location);\r
- int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID\r
- if (nAppLoc)\r
- snprintf(query, 2048, "SELECT ai_type FROM apt_items WHERE ai_apt_id = %d AND ai_apt_map = %d", ID, nAppLoc);\r
- else\r
- return 0;\r
- }\r
- else\r
- snprintf(query, 2048, "SELECT wi_type FROM world_items WHERE wi_worlditem_id = %d AND wi_worlditem_map = %d", ID, Location);\r
-\r
- result = GameResQuery(query);\r
- if(!result)\r
- {\r
- Console->Print("%s Cannot get WorldItemType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
- ShowGameSQLError();\r
- return 0;\r
- }\r
- else\r
- {\r
- if(mysql_num_rows(result) > 1)\r
- {\r
- FreeGameSQLResult(result);\r
- return -2;\r
- }\r
- else\r
- {\r
- row = mysql_fetch_row(result);\r
- if(row == NULL)\r
- {\r
- FreeGameSQLResult(result);\r
- return -1;\r
- }\r
- int ret_val = std::atoi(row[0]);\r
- FreeGameSQLResult(result);\r
- return ret_val;\r
- }\r
- }\r
-// else\r
-// {\r
-// FreeGameSQLResult(result);\r
-// return -1;\r
-// }\r
-//\r
- return -1;\r
-}\r
-\r
-int PMySQL::GetWorldItemOption(unsigned short ID, int Location, int option)\r
-{\r
- char query[2048];\r
- MYSQL_RES *result;\r
- MYSQL_ROW row;\r
- if(option != 1 && option != 2 && option != 3)\r
- {\r
- return -1;\r
- }\r
-\r
- if (Location > 100000)\r
- {\r
- //int nAppLoc = GetAptLocation(Location);\r
- int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID\r
- if (nAppLoc)\r
- snprintf(query, 2048, "SELECT ai_option%d FROM apt_items WHERE ai_apt_id = %d AND ai_apt_map = %d", option, ID, nAppLoc);\r
- else\r
- return 0;\r
- }\r
- else\r
- snprintf(query, 2048, "SELECT wi_option%d FROM world_items WHERE wi_worlditem_id = %d AND wi_worlditem_map = %d", option, ID, Location);\r
-\r
- result = GameResQuery(query);\r
- if(!result)\r
- {\r
- Console->Print("%s Cannot get WorldItemOption; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
- ShowGameSQLError();\r
- return 0;\r
- }\r
- else\r
- {\r
- if(mysql_num_rows(result) > 1)\r
- {\r
- FreeGameSQLResult(result);\r
- return -2;\r
- }\r
- else\r
- {\r
- row = mysql_fetch_row(result);\r
- if(row == NULL)\r
- {\r
- FreeGameSQLResult(result);\r
- return -1;\r
- }\r
- int ret_val = std::atoi(row[0]);\r
- FreeGameSQLResult(result);\r
- return ret_val;\r
- }\r
- }\r
-//\r
-// else\r
-// {\r
-// FreeGameSQLResult(result);\r
-// return -1;\r
-// }\r
-\r
- return -1;\r
-}\r
-\r
-int PMySQL::GetWorldDoorType(unsigned int ID, int Location) // To be removed\r
-{\r
- char query[2048];\r
- MYSQL_RES *result;\r
- MYSQL_ROW row;\r
-\r
-Console->Print(RED, BLACK, "PMySQL::GetWorldDoorType: DATABASE MUST NOT BE USED ANYMORE FOR DOORS INFO !!!");\r
- if (Location > 100000)\r
- {\r
- //int nAppLoc = GetAptLocation(Location);\r
- int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID\r
- if (nAppLoc)\r
- snprintf(query, 2048, "SELECT ad_type FROM apt_doors, apartments WHERE apt_doors.ad_apt_map = apartments.apt_type AND apt_doors.ad_apt_id = %i AND apartments.apt_id = %i", ID, nAppLoc);\r
- else\r
- return 0;\r
- }\r
- else\r
- {\r
- snprintf(query, 2048, "SELECT wd_type FROM world_doors WHERE wd_world_id = %d AND wd_world_map = %d", ID, Location);\r
- }\r
- result = GameResQuery(query);\r
-\r
- if(!result)\r
- {\r
- Console->Print("%s Cannot get WorldDoorType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
- ShowGameSQLError();\r
- return 0;\r
- } else {\r
- if(mysql_num_rows(result) > 1)\r
- {\r
- FreeGameSQLResult(result);\r
- return -2;\r
- }\r
- else\r
- {\r
- row = mysql_fetch_row(result);\r
- if(row == NULL)\r
- {\r
- FreeGameSQLResult(result);\r
- return -1;\r
- }\r
- int ret_val = std::atoi(row[0]);\r
- FreeGameSQLResult(result);\r
- return ret_val;\r
- }\r
- }\r
-//\r
-// else\r
-// {\r
-// FreeGameSQLResult(result);\r
-// return -1;\r
-// }\r
-//\r
- return -1;\r
-}*/\r
+#include <cstring>
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+PMySQL::PMySQL()
+{
+ InfoDBInuse = 0;
+ GameDBInuse = 0;
+ info_port = Config->GetOptionInt("info_sql_port");
+ strncpy(info_host, Config->GetOption("info_sql_host").c_str(), 100);
+ strncpy(info_userName, Config->GetOption("info_sql_username").c_str(), 100);
+ strncpy(info_password, Config->GetOption("info_sql_password").c_str(), 100);
+ strncpy(info_database, Config->GetOption("info_sql_database").c_str(), 100);
+
+ game_port = Config->GetOptionInt("game_sql_port");
+ strncpy(game_host, Config->GetOption("game_sql_host").c_str(), 100);
+ strncpy(game_userName, Config->GetOption("game_sql_username").c_str(), 100);
+ strncpy(game_password, Config->GetOption("game_sql_password").c_str(), 100);
+ strncpy(game_database, Config->GetOption("game_sql_database").c_str(), 100);
+
+ mKeepaliveDelay = (std::time_t) (Config->GetOptionInt("mysql_wait_timeout") * 0.9) ; // we take 90% of the wait_timeout to trigger keepalive
+ if (mKeepaliveDelay == 0)
+ {
+ Console->Print("%s MySQL keepalive disabled by config", Console->ColorText(GREEN, BLACK, "[Info]"));
+ }
+ else if (mKeepaliveDelay < 60)
+ {
+ Console->Print("%s Configuration option 'mysql_wait_timeout' is too low (%d sec). Reset to 60 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mKeepaliveDelay);
+ mKeepaliveDelay = 60;
+ }
+ mLastKeepaliveSent = 0;
+}
+
+PMySQL::~PMySQL()
+{
+ Console->Print("Closing MySQL connection...");
+ mysql_close(info_dbHandle);
+ mysql_close(game_dbHandle);
+}
+
+void PMySQL::Update()
+{
+ CheckResCount(); // Check for MYSQL_RES mem leak
+
+ // MySQL keepalive
+ std::time_t t = std::time(NULL);
+ if ((mKeepaliveDelay > 0) && ((t - mLastKeepaliveSent) > mKeepaliveDelay))
+ {
+ MYSQL_RES *result;
+ char query[24];
+ snprintf (query, 24, "SELECT NOW()");
+
+ result = GameResQuery(query);
+ if(!result)
+ {
+ Console->Print("%s Can't send GameDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));
+ ShowGameSQLError();
+ return;
+ }
+ else
+ FreeGameSQLResult(result);
+
+ result = InfoResQuery(query);
+ if(!result)
+ {
+ Console->Print("%s Can't send InfoDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));
+ ShowInfoSQLError();
+ return;
+ }
+ else
+ FreeInfoSQLResult(result);
+
+ mLastKeepaliveSent = std::time(NULL);
+ if (gDevDebug) Console->Print("%s MySQL keepalive sent", Console->ColorText(GREEN, BLACK, "[Debug]"));
+ }
+}
+
+void PMySQL::CheckResCount()
+{
+ static int MaxInfoDBCount = 0;
+ static int MaxGameDBCount = 0;
+
+ if (InfoDBInuse > MaxInfoDBCount)
+ {
+ Console->Print("%s Max In-use InfoDB Resources number increasing : %d (+%d)", Console->ColorText(YELLOW, BLACK, "[Notice]"), InfoDBInuse, InfoDBInuse-MaxInfoDBCount);
+ MaxInfoDBCount = InfoDBInuse;
+ }
+
+ if (GameDBInuse > MaxGameDBCount)
+ {
+ Console->Print("%s Max In-use GameDB Resources number increasing : %d (+%d)", Console->ColorText(YELLOW, BLACK, "[Notice]"), GameDBInuse, GameDBInuse-MaxGameDBCount);
+ MaxGameDBCount = GameDBInuse;
+ }
+}
+
+bool PMySQL::Connect()
+{
+ Console->LPrint("Establishing link to Infoserver Database...");
+
+ info_dbHandle = mysql_init(NULL);
+
+ if(!info_dbHandle)
+ {
+ Console->LPrint(RED, BLACK, "[ERROR]");
+ Console->LClose();
+ Console->Print(" Unable to create MySQL-Handle!");
+ exit(0);
+ }
+
+ if(!mysql_real_connect(info_dbHandle, info_host, info_userName, info_password, info_database, info_port, NULL, 0))
+ {
+ Console->LPrint(RED, BLACK, "[ERROR]");
+ Console->LClose();
+ Console->Print("Unable to connect to Infoserver Database. MySQL returned: %s", mysql_error(info_dbHandle));
+ }
+ else
+ {
+ Console->LPrint(GREEN, BLACK, "Success");
+ Console->LClose();
+ }
+// <><><><><><><><> Gameserver DB <><><><><><><><>
+ Console->LPrint("Establishing link to Gameserver Database...");
+
+ game_dbHandle = mysql_init(NULL);
+
+ if(!game_dbHandle)
+ {
+ Console->LPrint(RED, BLACK, "[ERROR]");
+ Console->LClose();
+ Console->Print(" Unable to create MySQL-Handle!");
+ exit(0);
+ }
+
+ if(!mysql_real_connect(game_dbHandle, game_host, game_userName, game_password, game_database, game_port, NULL, 0))
+ {
+ Console->LPrint(RED, BLACK, "[ERROR]");
+ Console->LClose();
+ Console->Print("Unable to connect to Gameserver Database. MySQL returned: %s", mysql_error(game_dbHandle));
+ return false;
+ }
+ else
+ {
+ Console->LPrint(GREEN, BLACK, "Success");
+ Console->LClose();
+ return true;
+ }
+
+}
+// ----------------------------------------------------
+MYSQL_RES *PMySQL::InfoResQuery(const char *query)
+{
+ int sql_result = 0;
+ MYSQL_RES *result;
+
+ sql_result = mysql_real_query(info_dbHandle, query, strlen(query));
+ if(sql_result)
+ {
+ return NULL;
+ }
+ result = mysql_store_result(info_dbHandle);
+ if(!result)
+ {
+ return NULL;
+ }
+ //if(InfoDBInuse == true)
+ /*if(InfoDBInuse > 0)
+ {
+ Console->Print("%s another (%d) info_dbHandle result is still in use", Console->ColorText(YELLOW, BLACK, "[Warning]"), InfoDBInuse);
+ }*/
+
+ //InfoDBInuse = true;
+ InfoDBInuse++;
+ return result;
+}
+
+int PMySQL::InfoQuery(const char *query)
+{
+ int sql_result = 0;
+ sql_result = mysql_real_query(info_dbHandle, query, strlen(query));
+
+ return sql_result;
+}
+
+void PMySQL::ShowInfoSQLError()
+{
+ Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(info_dbHandle));
+}
+void PMySQL::FreeInfoSQLResult(MYSQL_RES *res)
+{
+ if(InfoDBInuse > 0)
+ {
+ mysql_free_result(res);
+ InfoDBInuse--;
+ }
+ else
+ Console->Print("PMySQL::FreeInfoSQLResult: Nothing to free...");
+}
+// ----------------------------------------------------
+MYSQL_RES *PMySQL::GameResQuery(const char *query)
+{
+ int sql_result = 0;
+ MYSQL_RES *result;
+
+ sql_result = mysql_real_query(game_dbHandle, query, strlen(query));
+ if(sql_result)
+ {
+ return NULL;
+ }
+ result = mysql_store_result(game_dbHandle);
+ if(!result)
+ {
+ return NULL;
+ }
+ /*if(GameDBInuse > 0)
+ {
+ Console->Print("%s another (%d) game_dbHandle result is still in use", Console->ColorText(YELLOW, BLACK, "[Warning]"), GameDBInuse);
+ }*/
+
+ //GameDBInuse = true;
+ GameDBInuse++;
+ return result;
+}
+
+int PMySQL::GameQuery(const char *query)
+{
+ int sql_result = 0;
+ sql_result = mysql_real_query(game_dbHandle, query, strlen(query));
+
+ return sql_result;
+}
+
+void PMySQL::ShowGameSQLError()
+{
+ Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(game_dbHandle));
+}
+
+void PMySQL::FreeGameSQLResult(MYSQL_RES *res)
+{
+ if(GameDBInuse > 0)
+ {
+ mysql_free_result(res);
+ GameDBInuse--;
+ }
+ else
+ Console->Print("PMySQL::FreeGameSQLResult: Nothing to free...");
+}
+
+uint32_t PMySQL::EscapeString(const char* nText, char* dText, uint32_t dMaxLength)
+{
+ uint32_t nLength = strlen(nText);
+ uint32_t tMax = (dMaxLength - 1)/2;
+ if(nLength > tMax)
+ {
+ nLength = tMax;
+ }
+
+ return mysql_real_escape_string(game_dbHandle, dText, nText, nLength);
+}
+
+// ----------------------------------------------------
+/*
+int PMySQL::GetWorldItemType(unsigned short ID, int Location)
+{
+ char query[2048];
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+ if (Location > 100000)
+ {
+ //int nAppLoc = GetAptLocation(Location);
+ int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID
+ if (nAppLoc)
+ snprintf(query, 2048, "SELECT ai_type FROM apt_items WHERE ai_apt_id = %d AND ai_apt_map = %d", ID, nAppLoc);
+ else
+ return 0;
+ }
+ else
+ snprintf(query, 2048, "SELECT wi_type FROM world_items WHERE wi_worlditem_id = %d AND wi_worlditem_map = %d", ID, Location);
+
+ result = GameResQuery(query);
+ if(!result)
+ {
+ Console->Print("%s Cannot get WorldItemType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));
+ ShowGameSQLError();
+ return 0;
+ }
+ else
+ {
+ if(mysql_num_rows(result) > 1)
+ {
+ FreeGameSQLResult(result);
+ return -2;
+ }
+ else
+ {
+ row = mysql_fetch_row(result);
+ if(row == NULL)
+ {
+ FreeGameSQLResult(result);
+ return -1;
+ }
+ int ret_val = std::atoi(row[0]);
+ FreeGameSQLResult(result);
+ return ret_val;
+ }
+ }
+// else
+// {
+// FreeGameSQLResult(result);
+// return -1;
+// }
+//
+ return -1;
+}
+
+int PMySQL::GetWorldItemOption(unsigned short ID, int Location, int option)
+{
+ char query[2048];
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+ if(option != 1 && option != 2 && option != 3)
+ {
+ return -1;
+ }
+
+ if (Location > 100000)
+ {
+ //int nAppLoc = GetAptLocation(Location);
+ int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID
+ if (nAppLoc)
+ snprintf(query, 2048, "SELECT ai_option%d FROM apt_items WHERE ai_apt_id = %d AND ai_apt_map = %d", option, ID, nAppLoc);
+ else
+ return 0;
+ }
+ else
+ snprintf(query, 2048, "SELECT wi_option%d FROM world_items WHERE wi_worlditem_id = %d AND wi_worlditem_map = %d", option, ID, Location);
+
+ result = GameResQuery(query);
+ if(!result)
+ {
+ Console->Print("%s Cannot get WorldItemOption; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));
+ ShowGameSQLError();
+ return 0;
+ }
+ else
+ {
+ if(mysql_num_rows(result) > 1)
+ {
+ FreeGameSQLResult(result);
+ return -2;
+ }
+ else
+ {
+ row = mysql_fetch_row(result);
+ if(row == NULL)
+ {
+ FreeGameSQLResult(result);
+ return -1;
+ }
+ int ret_val = std::atoi(row[0]);
+ FreeGameSQLResult(result);
+ return ret_val;
+ }
+ }
+//
+// else
+// {
+// FreeGameSQLResult(result);
+// return -1;
+// }
+
+ return -1;
+}
+
+int PMySQL::GetWorldDoorType(unsigned int ID, int Location) // To be removed
+{
+ char query[2048];
+ MYSQL_RES *result;
+ MYSQL_ROW row;
+
+Console->Print(RED, BLACK, "PMySQL::GetWorldDoorType: DATABASE MUST NOT BE USED ANYMORE FOR DOORS INFO !!!");
+ if (Location > 100000)
+ {
+ //int nAppLoc = GetAptLocation(Location);
+ int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID
+ if (nAppLoc)
+ snprintf(query, 2048, "SELECT ad_type FROM apt_doors, apartments WHERE apt_doors.ad_apt_map = apartments.apt_type AND apt_doors.ad_apt_id = %i AND apartments.apt_id = %i", ID, nAppLoc);
+ else
+ return 0;
+ }
+ else
+ {
+ snprintf(query, 2048, "SELECT wd_type FROM world_doors WHERE wd_world_id = %d AND wd_world_map = %d", ID, Location);
+ }
+ result = GameResQuery(query);
+
+ if(!result)
+ {
+ Console->Print("%s Cannot get WorldDoorType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));
+ ShowGameSQLError();
+ return 0;
+ } else {
+ if(mysql_num_rows(result) > 1)
+ {
+ FreeGameSQLResult(result);
+ return -2;
+ }
+ else
+ {
+ row = mysql_fetch_row(result);
+ if(row == NULL)
+ {
+ FreeGameSQLResult(result);
+ return -1;
+ }
+ int ret_val = std::atoi(row[0]);
+ FreeGameSQLResult(result);
+ return ret_val;
+ }
+ }
+//
+// else
+// {
+// FreeGameSQLResult(result);
+// return -1;
+// }
+//
+ return -1;
+}*/
-#pragma once\r
-\r
-#include <chrono>\r
-#include <cstdint>\r
-#ifdef MYSQL_INC_DIR\r
-#include <mysql/mysql.h>\r
-#else\r
-#include <mysql.h>\r
-#endif\r
-\r
-// TODO: take all non-pure SQL DB access stuff out of this class\r
-\r
-class PMySQL {\r
-private:\r
- int info_port;\r
- char info_host[100];\r
- char info_userName[100];\r
- char info_password[100];\r
- char info_database[100];\r
- MYSQL *info_dbHandle;\r
- std::time_t mKeepaliveDelay;\r
- std::time_t mLastKeepaliveSent;\r
-\r
- int game_port;\r
- char game_host[100];\r
- char game_userName[100];\r
- char game_password[100];\r
- char game_database[100];\r
- MYSQL *game_dbHandle;\r
-\r
- int GameDBInuse;\r
- int InfoDBInuse;\r
-\r
-public:\r
- PMySQL();\r
- ~PMySQL();\r
-\r
- void Update();\r
- void CheckResCount();\r
-\r
- inline MYSQL *GetInfoHandle() { return info_dbHandle; };\r
- inline MYSQL *GetGameHandle() { return game_dbHandle; };\r
-\r
- bool Connect();\r
-\r
- int InfoQuery(const char *query);\r
- MYSQL_RES *InfoResQuery(const char *query);\r
- int GameQuery(const char *query);\r
- MYSQL_RES *GameResQuery(const char *query);\r
-\r
- /*int GetWorldItemType(unsigned short ID, int Location);\r
- int GetWorldItemOption(unsigned short ID, int Location, int option);\r
- int GetWorldDoorType(unsigned int ID, int Location);*/\r
-\r
- void ShowInfoSQLError();\r
- void ShowGameSQLError();\r
- void FreeGameSQLResult(MYSQL_RES *res);\r
- void FreeInfoSQLResult(MYSQL_RES *res);\r
-\r
- inline uint32_t GetLastGameInsertId() { return mysql_insert_id(game_dbHandle); };\r
- inline uint32_t GetLastInfoInsertId() { return mysql_insert_id(info_dbHandle); };\r
-\r
- uint32_t EscapeString(const char* nText, char* dText, uint32_t dMaxLength);\r
-};\r
+#pragma once
+
+#include <chrono>
+#include <cstdint>
+#ifdef MYSQL_INC_DIR
+#include <mysql/mysql.h>
+#else
+#include <mysql.h>
+#endif
+
+// TODO: take all non-pure SQL DB access stuff out of this class
+
+class PMySQL {
+private:
+ int info_port;
+ char info_host[100];
+ char info_userName[100];
+ char info_password[100];
+ char info_database[100];
+ MYSQL *info_dbHandle;
+ std::time_t mKeepaliveDelay;
+ std::time_t mLastKeepaliveSent;
+
+ int game_port;
+ char game_host[100];
+ char game_userName[100];
+ char game_password[100];
+ char game_database[100];
+ MYSQL *game_dbHandle;
+
+ int GameDBInuse;
+ int InfoDBInuse;
+
+public:
+ PMySQL();
+ ~PMySQL();
+
+ void Update();
+ void CheckResCount();
+
+ inline MYSQL *GetInfoHandle() { return info_dbHandle; };
+ inline MYSQL *GetGameHandle() { return game_dbHandle; };
+
+ bool Connect();
+
+ int InfoQuery(const char *query);
+ MYSQL_RES *InfoResQuery(const char *query);
+ int GameQuery(const char *query);
+ MYSQL_RES *GameResQuery(const char *query);
+
+ /*int GetWorldItemType(unsigned short ID, int Location);
+ int GetWorldItemOption(unsigned short ID, int Location, int option);
+ int GetWorldDoorType(unsigned int ID, int Location);*/
+
+ void ShowInfoSQLError();
+ void ShowGameSQLError();
+ void FreeGameSQLResult(MYSQL_RES *res);
+ void FreeInfoSQLResult(MYSQL_RES *res);
+
+ inline uint32_t GetLastGameInsertId() { return mysql_insert_id(game_dbHandle); };
+ inline uint32_t GetLastInfoInsertId() { return mysql_insert_id(info_dbHandle); };
+
+ uint32_t EscapeString(const char* nText, char* dText, uint32_t dMaxLength);
+};
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-/*\r
-(Real time)\r
-Full cycle = 328860 ms\r
-Network delay = TBD\r
-\r
-Offset =MOD(M86-122778+(M85*29896);328860)\r
-*/\r
-\r
-// Determines relative position of cabs, but how ???\r
-const uint16_t PSubway::mSubwayInitData [] = {0x4396, 0x4387, 0x4370, 0x4352, 0x4334, 0x4316, 0x42f0, 0x42b4, 0x4270, 0x41f0, 0x0000};\r
-const uint32_t PSubway::mCabLoopTime = 328860;\r
-const uint32_t PSubway::mCab0TimeOffset = 122778;\r
-const int32_t PSubway::mTimingAdjust = 0;\r
-const uint32_t PSubway::mCabIntervalTime = 29896;\r
-const uint32_t PSubway::mOpenDoorOffset [] = { 0, 42500, 83000, 146800, 170700, 226200, 262800, 303200 };\r
-const uint32_t PSubway::mOpenDoorDuration [] = { 8500, 6900, 12000, 7500, 8800, 9000, 8500, 9300 };\r
-const char* PSubway::mSubwayStationName[] = { "Pla => Oz", "Vr => Oz", "Pp => Oz", "Oz end", "Oz => Pla", "Pp => Pla", "Vr => Pla", "Pla end" };\r
-PCharCoordinates PSubway::mCabExitPositions [2][mStationsNumber];\r
-\r
-\r
-PSubway::PSubway()\r
-{\r
- for(uint8_t i=0; i<mCabsNumber; i++)\r
- {\r
- mSubways[i].mVhcId = mCabsBaseId+i;\r
- mSubways[i].mPosition = mSubwayInitData[i];\r
- mSubways[i].mDoorOpened = 0;\r
- for(uint8_t j=0; j<4; j++)\r
- {\r
- mSubways[i].mSeatUsersId[j] = 0;\r
- }\r
- }\r
-\r
- mCabExitPositions[0][0].SetPosition(32000-5205, 32000-608, 32000-4766, 0x80, 0);\r
- mCabExitPositions[1][0].SetPosition(32000-5764, 32000-608, 32000-4766, 0x80, 0);\r
-\r
- mCabExitPositions[0][1].SetPosition(32000+7290, 32000-600, 32000-500, 0x80, 45);\r
- mCabExitPositions[1][1].SetPosition(32000+7290, 32000-600, 32000-0, 0x80, 45);\r
-\r
- mCabExitPositions[0][2].SetPosition(32000-2300, 32000-600, 32000+7985, 0x80, 0);\r
- mCabExitPositions[1][2].SetPosition(32000-2850, 32000-600, 32000+7985, 0x80, 0);\r
-\r
- mCabExitPositions[0][3].SetPosition(32000-1700, 32000-596, 32000+1840, 0x80, 90);\r
- mCabExitPositions[1][3].SetPosition(32000-1250, 32000-596, 32000+1840, 0x80, 90);\r
-\r
- mCabExitPositions[0][4].SetPosition(32000-1700, 32000-596, 32000+1570, 0x80, 0);\r
- mCabExitPositions[1][4].SetPosition(32000-1250, 32000-596, 32000+1570, 0x80, 0);\r
-\r
- mCabExitPositions[0][5].SetPosition(32000-2300, 32000-600, 32000+8625, 0x80, 90);\r
- mCabExitPositions[1][5].SetPosition(32000-2850, 32000-600, 32000+8625, 0x80, 90);\r
-\r
- mCabExitPositions[0][6].SetPosition(32000+7815, 32000-600, 32000-500, 0x80, 135);\r
- mCabExitPositions[1][6].SetPosition(32000+7815, 32000-600, 32000-0, 0x80, 135);\r
-\r
- mCabExitPositions[0][7].SetPosition(32000-5205, 32000-608, 32000-4092, 0x80, 0);\r
- mCabExitPositions[1][7].SetPosition(32000-5764, 32000-608, 32000-4092, 0x80, 0);\r
-}\r
-\r
-uint32_t PSubway::GetTimeOffset(uint32_t nVhcId, uint32_t nTime)\r
-{\r
- uint8_t tIndex;\r
-\r
- if(!GetInfoIndex(nVhcId, &tIndex))\r
- {\r
- Console->Print(RED, BLACK, "[Error] PSubway::GetTimeOffset : invalid cab VhcId %d", nVhcId);\r
- return 0;\r
- }\r
-\r
- return ((nTime + mCabLoopTime - mCab0TimeOffset + mTimingAdjust + (tIndex * mCabIntervalTime)) % mCabLoopTime);\r
-}\r
-\r
-uint8_t PSubway::GetStation(uint32_t nVhcId, uint32_t nTime, uint32_t* TimeOffset)\r
-{\r
- int8_t i;\r
-\r
- uint32_t tTimeOffset = GetTimeOffset(nVhcId, nTime);\r
- if(TimeOffset)\r
- {\r
- *TimeOffset = tTimeOffset;\r
- }\r
-\r
- for(i = mStationsNumber-1; (i >= 0) && (tTimeOffset < mOpenDoorOffset[i]); --i) ;\r
-\r
- return i;\r
-}\r
-\r
-bool PSubway::IsDoorOpen(uint32_t nVhcId, uint32_t nTime)\r
-{\r
- uint32_t TimeOffset;\r
- uint8_t tStation;\r
-\r
- if(!GetInfoIndex(nVhcId))\r
- {\r
- Console->Print(RED, BLACK, "[Error] PSubway::IsDoorOpen : invalid cab VhcId %d", nVhcId);\r
- return false;\r
- }\r
- else\r
- {\r
- tStation = GetStation(nVhcId, nTime, &TimeOffset);\r
- return ((TimeOffset-mOpenDoorOffset[tStation]) <= mOpenDoorDuration[tStation]);\r
- }\r
-}\r
-\r
-std::string* PSubway::GetStationName(uint8_t nStationId)\r
-{\r
- if(nStationId < mStationsNumber)\r
- {\r
- return new std::string(mSubwayStationName[nStationId]);\r
- }\r
- else\r
- {\r
- Console->Print(RED, BLACK, "[Error] PSubway::GetStationName : invalid subway station %d", nStationId);\r
- return new std::string("Error");\r
- }\r
-}\r
-\r
-bool PSubway::GetStationExitPosition(PCharCoordinates* nPosition, uint8_t nStationId, float nCoef)\r
-{\r
- if(nStationId < mStationsNumber)\r
- {\r
- nPosition->SetInterpolate(mCabExitPositions[0][nStationId], mCabExitPositions[1][nStationId], nCoef);\r
- return true;\r
- }\r
- else\r
- {\r
- Console->Print(RED, BLACK, "[Error] PSubway::SetStationExitPosition : invalid subway station %d", nStationId);\r
- return false;\r
- }\r
-}\r
-\r
-bool PSubway::GetInfoIndex(uint32_t nVhcId, uint8_t *Index)\r
-{\r
- int32_t tIndex = nVhcId - mCabsBaseId;\r
- if ((tIndex >= 0) && (tIndex < mCabsNumber))\r
- {\r
- if(Index)\r
- {\r
- *Index = (uint8_t)tIndex;\r
- }\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-bool PSubway::UpdateInfo(uint32_t nVhcId, uint16_t nPosition, uint8_t nDoorOpened)\r
-{\r
- uint8_t tIndex;\r
- if(GetInfoIndex(nVhcId, &tIndex))\r
- {\r
- mSubways[tIndex].mPosition = nPosition;\r
-//if(mSubways[tIndex].mDoorOpened != nDoorOpened)\r
-// Console->Print("[DEBUG] Subway cab %08x : door now %s ", nVhcId, nDoorOpened ? "opened" : "closed" );\r
-\r
- mSubways[tIndex].mDoorOpened = nDoorOpened;\r
-\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-uint16_t PSubway::GetPosition(uint32_t nVhcId)\r
-{\r
- uint8_t tIndex;\r
- if(GetInfoIndex(nVhcId, &tIndex))\r
- {\r
- return mSubways[tIndex].mPosition;\r
- }\r
- else\r
- return 0;\r
-}\r
-\r
-uint8_t PSubway::GetFreeSeat(uint32_t nVhcId)\r
-{\r
- uint8_t tIndex;\r
- uint8_t tSeatFound = 0;\r
- if(GetInfoIndex(nVhcId, &tIndex))\r
- {\r
- for(uint8_t j=0; j<4; j++)\r
- {\r
- if(! mSubways[tIndex].mSeatUsersId[j])\r
- {\r
- tSeatFound = j+1;\r
- break;\r
- }\r
- }\r
- return tSeatFound;\r
- }\r
- else\r
- return 0;\r
-}\r
-\r
-bool PSubway::SetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId)\r
-{\r
- uint8_t tIndex;\r
-\r
- if(GetInfoIndex(nVhcId, &tIndex) && (nSeat >= 1) && (nSeat <= 4))\r
- {\r
- if(! mSubways[tIndex].mSeatUsersId[nSeat-1])\r
- {\r
- mSubways[tIndex].mSeatUsersId[nSeat-1] = nCharId;\r
-//Console->Print("[DEBUG] Char %d using seat %d of subway cab %08x, ", nCharId, nSeat, nVhcId);\r
- return true;\r
- }\r
- }\r
-\r
- return false;\r
-}\r
-\r
-bool PSubway::UnsetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId)\r
-{\r
- uint8_t tIndex;\r
-\r
- if(GetInfoIndex(nVhcId, &tIndex) && (nSeat >= 1) && (nSeat <= 4))\r
- {\r
- if(mSubways[tIndex].mSeatUsersId[nSeat-1] == nCharId)\r
- {\r
- mSubways[tIndex].mSeatUsersId[nSeat-1] = 0;\r
-//Console->Print("[DEBUG] Char %d leaving seat %d of subway cab %08x, ", nCharId, nSeat, nVhcId);\r
- return true;\r
- }\r
- }\r
-\r
- return false;\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+/*
+(Real time)
+Full cycle = 328860 ms
+Network delay = TBD
+
+Offset =MOD(M86-122778+(M85*29896);328860)
+*/
+
+// Determines relative position of cabs, but how ???
+const uint16_t PSubway::mSubwayInitData [] = {0x4396, 0x4387, 0x4370, 0x4352, 0x4334, 0x4316, 0x42f0, 0x42b4, 0x4270, 0x41f0, 0x0000};
+const uint32_t PSubway::mCabLoopTime = 328860;
+const uint32_t PSubway::mCab0TimeOffset = 122778;
+const int32_t PSubway::mTimingAdjust = 0;
+const uint32_t PSubway::mCabIntervalTime = 29896;
+const uint32_t PSubway::mOpenDoorOffset [] = { 0, 42500, 83000, 146800, 170700, 226200, 262800, 303200 };
+const uint32_t PSubway::mOpenDoorDuration [] = { 8500, 6900, 12000, 7500, 8800, 9000, 8500, 9300 };
+const char* PSubway::mSubwayStationName[] = { "Pla => Oz", "Vr => Oz", "Pp => Oz", "Oz end", "Oz => Pla", "Pp => Pla", "Vr => Pla", "Pla end" };
+PCharCoordinates PSubway::mCabExitPositions [2][mStationsNumber];
+
+
+PSubway::PSubway()
+{
+ for(uint8_t i=0; i<mCabsNumber; i++)
+ {
+ mSubways[i].mVhcId = mCabsBaseId+i;
+ mSubways[i].mPosition = mSubwayInitData[i];
+ mSubways[i].mDoorOpened = 0;
+ for(uint8_t j=0; j<4; j++)
+ {
+ mSubways[i].mSeatUsersId[j] = 0;
+ }
+ }
+
+ mCabExitPositions[0][0].SetPosition(32000-5205, 32000-608, 32000-4766, 0x80, 0);
+ mCabExitPositions[1][0].SetPosition(32000-5764, 32000-608, 32000-4766, 0x80, 0);
+
+ mCabExitPositions[0][1].SetPosition(32000+7290, 32000-600, 32000-500, 0x80, 45);
+ mCabExitPositions[1][1].SetPosition(32000+7290, 32000-600, 32000-0, 0x80, 45);
+
+ mCabExitPositions[0][2].SetPosition(32000-2300, 32000-600, 32000+7985, 0x80, 0);
+ mCabExitPositions[1][2].SetPosition(32000-2850, 32000-600, 32000+7985, 0x80, 0);
+
+ mCabExitPositions[0][3].SetPosition(32000-1700, 32000-596, 32000+1840, 0x80, 90);
+ mCabExitPositions[1][3].SetPosition(32000-1250, 32000-596, 32000+1840, 0x80, 90);
+
+ mCabExitPositions[0][4].SetPosition(32000-1700, 32000-596, 32000+1570, 0x80, 0);
+ mCabExitPositions[1][4].SetPosition(32000-1250, 32000-596, 32000+1570, 0x80, 0);
+
+ mCabExitPositions[0][5].SetPosition(32000-2300, 32000-600, 32000+8625, 0x80, 90);
+ mCabExitPositions[1][5].SetPosition(32000-2850, 32000-600, 32000+8625, 0x80, 90);
+
+ mCabExitPositions[0][6].SetPosition(32000+7815, 32000-600, 32000-500, 0x80, 135);
+ mCabExitPositions[1][6].SetPosition(32000+7815, 32000-600, 32000-0, 0x80, 135);
+
+ mCabExitPositions[0][7].SetPosition(32000-5205, 32000-608, 32000-4092, 0x80, 0);
+ mCabExitPositions[1][7].SetPosition(32000-5764, 32000-608, 32000-4092, 0x80, 0);
+}
+
+uint32_t PSubway::GetTimeOffset(uint32_t nVhcId, uint32_t nTime)
+{
+ uint8_t tIndex;
+
+ if(!GetInfoIndex(nVhcId, &tIndex))
+ {
+ Console->Print(RED, BLACK, "[Error] PSubway::GetTimeOffset : invalid cab VhcId %d", nVhcId);
+ return 0;
+ }
+
+ return ((nTime + mCabLoopTime - mCab0TimeOffset + mTimingAdjust + (tIndex * mCabIntervalTime)) % mCabLoopTime);
+}
+
+uint8_t PSubway::GetStation(uint32_t nVhcId, uint32_t nTime, uint32_t* TimeOffset)
+{
+ int8_t i;
+
+ uint32_t tTimeOffset = GetTimeOffset(nVhcId, nTime);
+ if(TimeOffset)
+ {
+ *TimeOffset = tTimeOffset;
+ }
+
+ for(i = mStationsNumber-1; (i >= 0) && (tTimeOffset < mOpenDoorOffset[i]); --i) ;
+
+ return i;
+}
+
+bool PSubway::IsDoorOpen(uint32_t nVhcId, uint32_t nTime)
+{
+ uint32_t TimeOffset;
+ uint8_t tStation;
+
+ if(!GetInfoIndex(nVhcId))
+ {
+ Console->Print(RED, BLACK, "[Error] PSubway::IsDoorOpen : invalid cab VhcId %d", nVhcId);
+ return false;
+ }
+ else
+ {
+ tStation = GetStation(nVhcId, nTime, &TimeOffset);
+ return ((TimeOffset-mOpenDoorOffset[tStation]) <= mOpenDoorDuration[tStation]);
+ }
+}
+
+std::string* PSubway::GetStationName(uint8_t nStationId)
+{
+ if(nStationId < mStationsNumber)
+ {
+ return new std::string(mSubwayStationName[nStationId]);
+ }
+ else
+ {
+ Console->Print(RED, BLACK, "[Error] PSubway::GetStationName : invalid subway station %d", nStationId);
+ return new std::string("Error");
+ }
+}
+
+bool PSubway::GetStationExitPosition(PCharCoordinates* nPosition, uint8_t nStationId, float nCoef)
+{
+ if(nStationId < mStationsNumber)
+ {
+ nPosition->SetInterpolate(mCabExitPositions[0][nStationId], mCabExitPositions[1][nStationId], nCoef);
+ return true;
+ }
+ else
+ {
+ Console->Print(RED, BLACK, "[Error] PSubway::SetStationExitPosition : invalid subway station %d", nStationId);
+ return false;
+ }
+}
+
+bool PSubway::GetInfoIndex(uint32_t nVhcId, uint8_t *Index)
+{
+ int32_t tIndex = nVhcId - mCabsBaseId;
+ if ((tIndex >= 0) && (tIndex < mCabsNumber))
+ {
+ if(Index)
+ {
+ *Index = (uint8_t)tIndex;
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+bool PSubway::UpdateInfo(uint32_t nVhcId, uint16_t nPosition, uint8_t nDoorOpened)
+{
+ uint8_t tIndex;
+ if(GetInfoIndex(nVhcId, &tIndex))
+ {
+ mSubways[tIndex].mPosition = nPosition;
+//if(mSubways[tIndex].mDoorOpened != nDoorOpened)
+// Console->Print("[DEBUG] Subway cab %08x : door now %s ", nVhcId, nDoorOpened ? "opened" : "closed" );
+
+ mSubways[tIndex].mDoorOpened = nDoorOpened;
+
+ return true;
+ }
+ else
+ return false;
+}
+
+uint16_t PSubway::GetPosition(uint32_t nVhcId)
+{
+ uint8_t tIndex;
+ if(GetInfoIndex(nVhcId, &tIndex))
+ {
+ return mSubways[tIndex].mPosition;
+ }
+ else
+ return 0;
+}
+
+uint8_t PSubway::GetFreeSeat(uint32_t nVhcId)
+{
+ uint8_t tIndex;
+ uint8_t tSeatFound = 0;
+ if(GetInfoIndex(nVhcId, &tIndex))
+ {
+ for(uint8_t j=0; j<4; j++)
+ {
+ if(! mSubways[tIndex].mSeatUsersId[j])
+ {
+ tSeatFound = j+1;
+ break;
+ }
+ }
+ return tSeatFound;
+ }
+ else
+ return 0;
+}
+
+bool PSubway::SetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId)
+{
+ uint8_t tIndex;
+
+ if(GetInfoIndex(nVhcId, &tIndex) && (nSeat >= 1) && (nSeat <= 4))
+ {
+ if(! mSubways[tIndex].mSeatUsersId[nSeat-1])
+ {
+ mSubways[tIndex].mSeatUsersId[nSeat-1] = nCharId;
+//Console->Print("[DEBUG] Char %d using seat %d of subway cab %08x, ", nCharId, nSeat, nVhcId);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool PSubway::UnsetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId)
+{
+ uint8_t tIndex;
+
+ if(GetInfoIndex(nVhcId, &tIndex) && (nSeat >= 1) && (nSeat <= 4))
+ {
+ if(mSubways[tIndex].mSeatUsersId[nSeat-1] == nCharId)
+ {
+ mSubways[tIndex].mSeatUsersId[nSeat-1] = 0;
+//Console->Print("[DEBUG] Char %d leaving seat %d of subway cab %08x, ", nCharId, nSeat, nVhcId);
+ return true;
+ }
+ }
+
+ return false;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <string>\r
-\r
-class PSubway {\r
- friend class PMsgBuilder;\r
-\r
- struct PSubwayInfo\r
- {\r
- uint16_t mVhcId;\r
- uint16_t mPosition;\r
- uint8_t mDoorOpened;\r
- uint32_t mSeatUsersId[4];\r
- };\r
-\r
- public:\r
- static const uint16_t mCabsNumber = 11;\r
- static const uint32_t mCabsBaseId = 0x03f2;\r
- static const uint32_t mCabsBaseHealth = 100; //should take that from .def instead...\r
- static const uint8_t mStationsNumber = 8;\r
-\r
- private:\r
- static const uint16_t mSubwayInitData [];\r
- static const uint32_t mCabLoopTime;\r
- static const uint32_t mCab0TimeOffset;\r
- static const int32_t mTimingAdjust;\r
- static const uint32_t mCabIntervalTime;\r
- static const uint32_t mOpenDoorOffset [];\r
- static const uint32_t mOpenDoorDuration [];\r
- static const char* mSubwayStationName [];\r
- static PCharCoordinates mCabExitPositions [2][mStationsNumber];\r
-\r
- PSubwayInfo mSubways[mCabsNumber];\r
-\r
-public:\r
- bool GetInfoIndex(uint32_t nVhcId, uint8_t *Index = NULL);\r
-\r
- public:\r
- PSubway();\r
- //~PSubway();\r
-\r
- inline bool IsValidSubwayCab(uint32_t nVhcId) {return GetInfoIndex(nVhcId); }\r
- bool UpdateInfo(uint32_t nVhcId, uint16_t nPosition, uint8_t nDoorOpened);\r
- uint16_t GetPosition(uint32_t nVhcId);\r
-\r
- uint32_t GetTimeOffset(uint32_t nVhcId, uint32_t nTime);\r
- uint8_t GetStation(uint32_t nVhcId, uint32_t nTime, uint32_t* TimeOffset = NULL);\r
- bool IsDoorOpen(uint32_t nVhcId, uint32_t nTime);\r
- std::string* GetStationName(uint8_t nStationId);\r
- bool GetStationExitPosition(PCharCoordinates* nPosition, uint8_t nStationId, float nCoef = 0.5);\r
-\r
- uint8_t GetFreeSeat(uint32_t nVhcId);\r
- bool SetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId);\r
- bool UnsetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId);\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+class PSubway {
+ friend class PMsgBuilder;
+
+ struct PSubwayInfo
+ {
+ uint16_t mVhcId;
+ uint16_t mPosition;
+ uint8_t mDoorOpened;
+ uint32_t mSeatUsersId[4];
+ };
+
+ public:
+ static const uint16_t mCabsNumber = 11;
+ static const uint32_t mCabsBaseId = 0x03f2;
+ static const uint32_t mCabsBaseHealth = 100; //should take that from .def instead...
+ static const uint8_t mStationsNumber = 8;
+
+ private:
+ static const uint16_t mSubwayInitData [];
+ static const uint32_t mCabLoopTime;
+ static const uint32_t mCab0TimeOffset;
+ static const int32_t mTimingAdjust;
+ static const uint32_t mCabIntervalTime;
+ static const uint32_t mOpenDoorOffset [];
+ static const uint32_t mOpenDoorDuration [];
+ static const char* mSubwayStationName [];
+ static PCharCoordinates mCabExitPositions [2][mStationsNumber];
+
+ PSubwayInfo mSubways[mCabsNumber];
+
+public:
+ bool GetInfoIndex(uint32_t nVhcId, uint8_t *Index = NULL);
+
+ public:
+ PSubway();
+ //~PSubway();
+
+ inline bool IsValidSubwayCab(uint32_t nVhcId) {return GetInfoIndex(nVhcId); }
+ bool UpdateInfo(uint32_t nVhcId, uint16_t nPosition, uint8_t nDoorOpened);
+ uint16_t GetPosition(uint32_t nVhcId);
+
+ uint32_t GetTimeOffset(uint32_t nVhcId, uint32_t nTime);
+ uint8_t GetStation(uint32_t nVhcId, uint32_t nTime, uint32_t* TimeOffset = NULL);
+ bool IsDoorOpen(uint32_t nVhcId, uint32_t nTime);
+ std::string* GetStationName(uint8_t nStationId);
+ bool GetStationExitPosition(PCharCoordinates* nPosition, uint8_t nStationId, float nCoef = 0.5);
+
+ uint8_t GetFreeSeat(uint32_t nVhcId);
+ bool SetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId);
+ bool UnsetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId);
+};
-#pragma once\r
-\r
-#include <cstdint>\r
-\r
-class PTerminal {\r
-private:\r
- void SendTryAccessAnswer(PClient* nClient, char *nArea, bool nAllowed);\r
- char mSQLQuery[500];\r
-\r
- int mResultFields;\r
- void EraseVars();\r
-\r
- char mConPrefix[50];\r
-\r
- inline bool ChkOpt(uint8_t nNumOptions, uint8_t nReqOpt) { if(nNumOptions < nReqOpt) return false; else return true; };\r
- bool DoStockXCheck(PClient* nClient, int nAmountEntered, int nNewAmount);\r
-\r
-public:\r
- PTerminal();\r
- //~PTerminal();\r
- // Check accesslevel of Player for various Terminal actions\r
- bool CheckAccess(PClient* nClient, char *nArea, uint16_t nCmdNr, char *nOption1, char *nOption2, char *nOption3);\r
- uint8_t GetNewEmailCount(PClient* nClient, bool nNoticeClient = true);\r
- // Handle ReceiveDB queries\r
- bool HandleQueryDB(PClient* nClient, std::string *nDBCommandName, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions);\r
- bool HandleReceiveDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown);\r
- bool HandleTryAccess(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown, bool nCheckOnly = false);\r
- bool HandleUpdateDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown);\r
-};\r
+#pragma once
+
+#include <cstdint>
+
+class PTerminal {
+private:
+ void SendTryAccessAnswer(PClient* nClient, char *nArea, bool nAllowed);
+ char mSQLQuery[500];
+
+ int mResultFields;
+ void EraseVars();
+
+ char mConPrefix[50];
+
+ inline bool ChkOpt(uint8_t nNumOptions, uint8_t nReqOpt) { if(nNumOptions < nReqOpt) return false; else return true; };
+ bool DoStockXCheck(PClient* nClient, int nAmountEntered, int nNewAmount);
+
+public:
+ PTerminal();
+ //~PTerminal();
+ // Check accesslevel of Player for various Terminal actions
+ bool CheckAccess(PClient* nClient, char *nArea, uint16_t nCmdNr, char *nOption1, char *nOption2, char *nOption3);
+ uint8_t GetNewEmailCount(PClient* nClient, bool nNoticeClient = true);
+ // Handle ReceiveDB queries
+ bool HandleQueryDB(PClient* nClient, std::string *nDBCommandName, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions);
+ bool HandleReceiveDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown);
+ bool HandleTryAccess(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown, bool nCheckOnly = false);
+ bool HandleUpdateDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown);
+};
-#include <cstring>\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-bool PTerminal::HandleReceiveDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown)\r
-{\r
- EraseVars();\r
- int nAccessLevel = nClient->GetAccountLevel();\r
- //Console->Print("DBID: %d", nDBID);\r
-\r
- switch (nDBID)\r
- {\r
- case 8:\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 6;\r
- if(!strncmp(nOptions[0].c_str(), "date", 4))\r
- //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- else\r
- //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
- snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 9:\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 6;\r
- if(!strncmp(nOptions[0].c_str(), "date", 4))\r
- //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- else\r
- //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
- snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 10:\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 6;\r
- if(!strncmp(nOptions[0].c_str(), "date", 4))\r
- //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- else\r
- //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
- snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 11:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 6;\r
- //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_content FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_id = %d", atoi(nOptions[0].c_str()));\r
- snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_content FROM `neochronicle` WHERE nc_id = %d", atoi(nOptions[0].c_str()));\r
- //snprintf (mSQLQuery, 500, "SELECT na_id, \'\', na_datetime, na_author, na_name, na_content FROM `neocron articles` WHERE na_approval = 1 AND na_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 14:\r
- // 0: ID 1: Short 2: Clanname 3: FactionID 4: Faction Symp\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 6; // TODO: replace 0 with average faction sympathy\r
- snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction, \"0\", \"0\" FROM `clans` WHERE cl_name LIKE \"%%%s%%\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 16:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- if (!strcmp (nOptions[0].c_str(), "Neocronicle"))\r
- {\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT na_id, \'0\', na_datetime, na_author, na_name FROM `neocron articles` WHERE na_approval = 1 LIMIT %s, %s", nOptions[1].c_str(), nOptions[2].c_str());\r
- }\r
- else\r
- {\r
- mResultFields = 7;\r
- snprintf (mSQLQuery, 500, "SELECT na_id, \'0\', na_datetime, na_author, na_name, na_approval, \"0\" FROM `neocron articles` LIMIT %s, %s", nOptions[1].c_str(), nOptions[2].c_str());\r
- }\r
-\r
- break;\r
- case 18:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 20:\r
- case 21:\r
- // Select either c_"name" or c_"minsympathy". Names taken from option, saves if/else\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT `cl_%s` FROM `clans` WHERE `cl_id` = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 25:\r
- if(!ChkOpt(nNumOptions, 4)) break;\r
- mResultFields = 6; // TODO: replace 0 with average faction sympathy\r
- snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction, \"0\", \"0\" FROM clans WHERE cl_name > \"%s\" AND cl_name <=\"%s\" LIMIT %d, %d", nOptions[0].c_str(), nOptions[1].c_str(), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
- case 26:\r
- // 0: short 1: name 2: money 3: faction 4: fac symp 5: symp_to_join 6: cappid\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT cl_shortdesc, cl_name, cl_money, cl_faction, \"0\", cl_minsympathy, cl_appid FROM `clans` WHERE `cl_id` = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 27:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_description, count(DISTINCT o_outnum), count(DISTINCT c_id) FROM outposts INNER JOIN clans ON (o_clan = cl_id) INNER JOIN characters ON (c_clan = clans.cl_id) WHERE (cl_id = %d) GROUP BY cl_id", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 28:\r
- // Faction missions? Never seen them even in NC2...\r
- Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d has not been written yet; Factionmissions..? Never seen them", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 29:\r
- Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d Ordercol was missing. Its: [%s]", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID, nOptions[0].c_str());\r
- break;\r
- case 34:\r
- // Name, Add. Info, Profession, Description, Overal Ranking, Soullight, Money, Runner Kills, Creature Kills\r
- // Note: Add. Info is autogenerated clientside!\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 8;\r
- snprintf (mSQLQuery, 500, "SELECT c_name, c_profession, \"0\", \"1\", \"127\", c_cash, \"0\", \"0\" FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 38:\r
- // Faction missions? Never seen them even in NC2...\r
- Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d has not been written yet; Factionmissions..? Never seen them", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 39:\r
- // 0:id 1:name 2:clan 3:fac.symp\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_clan, \"75\" FROM characters WHERE c_name LIKE \"%s\"", nOptions[0].c_str());\r
-\r
- break;\r
- case 41:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT o_outnum, o_outnum, \"0\", \"0\", \"0\" FROM outposts WHERE o_clan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 46:\r
- // charid, charname, charclanlevel, clanlevelname, charfactionsymp, char online\r
- if(!ChkOpt(nNumOptions, 4)) break;\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, \"0\", c_online FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (cll_clanid = %d) AND (cll_level >= %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
- case 47:\r
- if(!ChkOpt(nNumOptions, 5)) break;\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE cll_level >= %d AND cll_level <= %d AND c_clan = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[2].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str()));\r
-\r
- break;\r
- case 48:\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 49:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 50:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 2; //Fieldnum\r
- snprintf (mSQLQuery, 500, "SELECT f_showname, f_name FROM forums WHERE f_area = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 51:\r
- if(!ChkOpt(nNumOptions, 9)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND f_name = \'%s\' AND fp_replyid = 0 LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[7].c_str()), atoi(nOptions[8].c_str()));\r
-\r
- break;\r
- case 52:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 54:\r
- // id, name, rank, rankname, f.symp\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, 0 FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_id = %d)", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 60: // Query for OutPost state. Result is <outpost ID> <clan ID>\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT o_outnum, o_clan FROM outposts LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 61: // It should display the clanname, but it doesnt. seems to be clientside bug\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT o_outnum, o_clan, o_clan, o_security FROM outposts WHERE o_outnum = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 75:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 76:\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT count(c_id) FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (cll_clanid = %d AND cll_desc = \"%s\")", atoi(nOptions[0].c_str()),nOptions[1].c_str());\r
-\r
- break;\r
- case 85:\r
- if(!ChkOpt(nNumOptions, 4)) break;\r
- mResultFields = 6; // No idea why this Fac.Symp is that high... 1000000 is 100 ingame. But only for this query\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, 1000000, c_online FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_online = %d OR c_online = 1) AND c_clan = %d LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
- case 86:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 4;\r
- if(!strncmp(nOptions[1].c_str(), "date", 4))\r
- snprintf (mSQLQuery, 500, "SELECT mt_id, mt_amount, mt_date, c_name FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
- else\r
- snprintf (mSQLQuery, 500, "SELECT mt_id, mt_amount, mt_date, c_name FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 87:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT c_name, mt_date, mt_amount, mt_comment FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 92:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- // Location of player\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT c_location FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 93:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- // Name, Add. Info, Profession, Description\r
- // Note: Add. Info is autogenerated clientside!\r
- mResultFields = 3;\r
- snprintf (mSQLQuery, 500, "SELECT c_name, c_profession, \"0\" FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 96:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT f_showname FROM forums WHERE f_name = \"%s\"", nOptions[0].c_str());\r
-\r
- break;\r
- case 98:\r
- // ID, Name, Online, 0, Soullight\r
- if(!ChkOpt(nNumOptions, 4)) break;\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_online, \"0\", c_soullight FROM characters WHERE c_online = %d AND c_soullight <= -%d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
- break;\r
- case 99:\r
- // Terrorist info\r
- // id, name, faction, clan, clanlevel, location\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_faction, c_clan, cll_level, c_location FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_id = %d AND c_soullight <= -%d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 108:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT cl_name FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 109:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- // The only case where KK used an DBId twice for completely different things...\r
- if(nNumOptions < 3)\r
- {\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_clan, cll_level, cll_desc FROM characters INNER JOIN clanlevels ON (cll_charid = c_id AND cll_clanid = c_clan) WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
- }\r
- else if(nNumOptions == 3)\r
- {\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, apt_location FROM apartments INNER JOIN characters ON (apt_owner = c_id) WHERE (c_id = %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- }\r
-\r
- break;\r
- case 116:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT wr_id FROM worlds WHERE wr_group = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 125:\r
- // Return position in Helpqueue. todo yet... for now its 255, we're always busy! =)\r
- //if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT 255");\r
-\r
- break;\r
- case 126:\r
- // Return position in Helpqueue. todo yet... for now its 255, we're always busy! =)\r
- // This is with Datecheck, somehow..\r
- //if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT 255");\r
-\r
- break;\r
- case 127:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT c_name, apt_location FROM apartments INNER JOIN characters ON (apt_owner = c_id) WHERE (c_id = %d)", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 128:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT su_id FROM support WHERE su_supporterid = %d AND su_finished = 0", atoi(nOptions[0].c_str()));\r
-\r
- case 131:\r
- mResultFields = 6;\r
- //snprintf(mSQLQuery, 500, "SELECT br_id, br_type, c_online, c_name, br_location, br_datetime FROM `bug report`, characters WHERE c_id = br_fromid AND br_status = %d LIMIT %d, %d",\r
- // atoi(nOptions[0].c_str())+atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
- snprintf(mSQLQuery, 500, "SELECT su_id, su_type, 0, c_name, su_worldid, su_datetime FROM support INNER JOIN characters ON (su_player = c_id) WHERE su_inwork = %d AND su_finished = %d LIMIT %d, %d",\r
- atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
- case 132:\r
- // reqid, runnerid, runnername, 0, date/time, type, 0, in work, finished, desc\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 10;\r
- //snprintf(mSQLQuery, 500, "SELECT br_id, br_fromid, c_name, \"0\", br_datetime, br_type, \"0\", br_status, br_status, br_desc FROM `bug report` INNER JOIN characters ON (br_fromid = c_id) WHERE br_id = %d", atoi(nOptions[0].c_str()));\r
- snprintf(mSQLQuery, 500, "SELECT su_id, su_player, c_name, 0, su_datetime, su_type, su_supporterid, su_inwork, su_finished, su_desc FROM support INNER JOIN characters ON (su_player = c_id) WHERE su_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 134:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 1;\r
- snprintf(mSQLQuery, 500, "SELECT br_id FROM bug_report WHERE br_fromid = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 136:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 137:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- // runnerid, runnername, location, online\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name = \"%s\"", nOptions[0].c_str());\r
- break;\r
- case 138:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- // runnerid, runnername, location, online\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT br_type, br_location, br_datetime, br_supid, br_status, br_desc FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 143:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- // runnerid, runnername, location, online\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT a.a_id, a.a_username, b.c_id, 0, b.c_location, b.c_online FROM `%s`.accounts AS a, `%s`.characters AS b WHERE b.c_name = \"%s\" AND a.a_id = b.a_id",\r
- Config->GetOption("info_sql_database").c_str(), Config->GetOption("game_sql_database").c_str(), nOptions[0].c_str());\r
- break;\r
- case 144:\r
- mResultFields = 2; // Replace "1" with Online/Offline!\r
- snprintf (mSQLQuery, 500, "SELECT c_location, c_online FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 145:\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT a_email FROM `%s`.accounts WHERE a_id = %d", Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 146:\r
- mResultFields = 4;\r
- // Too bad we named the row different...\r
- char tSortRow[10];\r
- if(!strncmp(nOptions[1].c_str(), "world", 5))\r
- strcpy(tSortRow, "location");\r
- else\r
- strcpy(tSortRow, "name");\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name LIKE \"%s\" ORDER BY `c_%s` LIMIT %d, %d", nOptions[0].c_str(), tSortRow, atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
- case 147:\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_online = %d ORDER BY `c_%s` LIMIT %d, %d", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
- case 148:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, \"0\", \"0\", c_id FROM clans INNER JOIN characters ON (cl_leader = c_id) WHERE (cl_id = %d)", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 150:\r
- // Mission stuff. Will be added later!\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 151:\r
- // Mission stuff. Will be added later!\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 153:\r
- // Mission stuff. Will be added later!\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 154:\r
- // Mission stuff. Will be added later!\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 155:\r
- // Mission stuff. Will be added later!\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 156:\r
- // Mission stuff. Will be added later!\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 157:\r
- // Mission stuff. Will be added later!\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 158:\r
- // Mission stuff. Will be added later!\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 175:\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT br_id, br_type, br_title, br_datetime FROM bug_report LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 176:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 8;\r
- snprintf (mSQLQuery, 500, "SELECT br_type, br_status, br_title, br_desc, 0, br_datetime, br_location, br_fromid FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 181:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 3;\r
- snprintf (mSQLQuery, 500, "SELECT c_name, apt_location, apt_password FROM apartments INNER JOIN characters ON (c_id = apt_owner) WHERE apt_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 183:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name, (SELECT count(*) FROM characters WHERE c_clan = %d), c_name, apt_id, apt_location FROM clans INNER JOIN apartments ON (cl_appid = apt_id) INNER JOIN characters ON (c_clan = cl_id) AND (apt_owner = c_id) WHERE (cl_id = %d) GROUP BY c_id", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 186:\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT c_id FROM characters WHERE c_name = \"%s\"", nOptions[0].c_str());\r
-\r
- break;\r
- case 220:\r
- mResultFields = 4; //Fieldnum\r
- snprintf (mSQLQuery, 500, "SELECT v_id, v_type, v_status, v_condition FROM vehicles WHERE v_owner = %i LIMIT %i, %i", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 221:\r
- //VehicleControl order. "VehicleControl", "Type", "Status", "Condition", "Repairprice?"\r
- mResultFields = 4; //Fieldnum\r
- snprintf (mSQLQuery, 500, "SELECT v_type, v_status, v_condition, \"0\" FROM vehicles WHERE v_id = %s", nOptions[0].c_str());\r
-\r
- break;\r
- case 225:\r
- // Statistics. Maybe later...\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 226:\r
- // Statistics. Maybe later...\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 230:\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT st_id, st_factid, st_curval, st_curval-st_oldval FROM stockx");\r
-\r
- break;\r
- case 231:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT st_id, st_factid, st_curval, (st_curval - st_oldval) FROM stockx WHERE (st_id = %d)", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 232:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT sxd_id, st_factid, st_curval, sxd_amount, (sxd_amount * st_curval) FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) WHERE (sxd_playerid = %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 233:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 7;\r
- snprintf (mSQLQuery, 500, "SELECT st_factid, sxd_amount, (st_curval - st_oldval), st_curval, sxd_paid, (sxd_amount * st_curval), ((sxd_amount * st_curval) - sxd_paid) FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) where sxd_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 234:\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 3;\r
- snprintf (mSQLQuery, 500, "SELECT sxd_id, sxd_amount, sxd_paid FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) WHERE sxd_playerid = %d AND st_factid = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 250:\r
- // Influence from CharID? Is stockx gm controlled??\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 251:\r
- // What is this "influence" ? Check this on live servers!\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 260:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 2; //Fieldnum\r
- snprintf (mSQLQuery, 500, "SELECT f_showname, f_name FROM forums WHERE f_area = %d+%d+%d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 261:\r
- // Maybe even rewrite BB system.. its wrong written anyways....\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 262:\r
- // This is wrong! 262 is the receiveDB request for FACTION threadlist. It should be limitet to that faction then\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND (fp_id = %s OR fp_replyid = %s)", nOptions[0].c_str(), nOptions[1].c_str());\r
-\r
- //TODO Check this. Same (?) for ID 52,262,267,401 and 411\r
- break;\r
- case 266:\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND f_name = \'%s\' AND fp_replyid = 0 AND fp_clanid = %d LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
- case 267:\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND (fp_id = %s OR fp_replyid = %s)", nOptions[0].c_str(), nOptions[1].c_str());\r
-\r
- break;\r
- case 270:\r
- Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d Tablename/Name is: [%s] ThreadID is: [%d]", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID, atoi(nOptions[0].c_str()), nOptions[1].c_str());\r
- break;\r
- case 360:\r
- // Gamemaster name (char), Accountname, Location, Online, CharID\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT a.a_id, c.c_id, a.a_username, c.c_name, c.c_online, c.c_location FROM %s.characters AS c, %s.accounts AS a WHERE a.a_priv >= 50 AND c.c_online = %d AND c.a_id = a.a_id ORDER BY c.c_name LIMIT %d, %d",\r
- Config->GetOption("game_sql_database").c_str(), Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 365:\r
- // ID, short, name faction\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction FROM clans LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 366:\r
- // ID, short, name faction WHERE clanname = %s\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction FROM clans WHERE cl_name LIKE \"%s\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 367:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 8;\r
- snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_leader, cl_faction, cl_appid, cl_money, (SELECT count(*) FROM characters WHERE c_clan = %d) FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 368:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 373:\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location, apt_type, apt_password FROM apartments WHERE apt_id = %d AND apt_owner = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 375:\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 376:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name LIKE \"%s\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 377:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT DISTINCT a_id FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 378:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT a_username, a_email, \"Since begin\", \"Never\", FROM_UNIXTIME(a_bandate) FROM `%s`.accounts WHERE a_id = %d", Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 379:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online, c_clan, cll_level FROM characters INNER JOIN clanlevels ON (cll_charid = c_id) WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 380: // clean\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT cl_name, cll_desc FROM clans INNER JOIN clanlevels ON (cll_clanid = cl_id) WHERE cl_id = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 381:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, c_online FROM characters WHERE a_id = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 384: // clean\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location, 0, apt_password FROM apartments WHERE apt_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 400:\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 401:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 406:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT count(fp_id) FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) WHERE f_name = \"%s\"", nOptions[0].c_str());\r
-\r
- break;\r
- case 410:\r
- if(!ChkOpt(nNumOptions, 4)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM forum_posts INNER JOIN forums ON (fp_forumid = f_area) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\" AND fp_factionid = %d) LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
- case 411:\r
- if(!ChkOpt(nNumOptions, 4)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_area) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d) AND (fp_factionid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
-\r
- case 420:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT e_id, e_subject, c_name, e_new, e_replied, e_datetime FROM emails, characters WHERE e_fromid = c_id AND e_toid = %i LIMIT %i, %i", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 421:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- //MailControl order. "MailControl", "Mail ID", "Subject", "From", boolean Replied, "Date/Time", "FromID", "Content"\r
- mResultFields = 7;\r
- snprintf (mSQLQuery, 500, "SELECT e_id, e_subject, c_name, e_replied, e_datetime, e_fromid, e_body FROM emails, characters WHERE e_fromid = c_id AND e_id = %s", nOptions[0].c_str());\r
-\r
- break;\r
- case 425:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- //Send mail order. "SendMail", "id"\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT c_id FROM characters WHERE c_name = \'%s\'", nOptions[0].c_str());\r
-\r
- break;\r
- case 430:\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT a.c_id, a.c_conid, b.c_name, a.c_desc FROM contacts as a, characters as b WHERE a.c_conid = b.c_id AND a.c_listid = %s AND c_type = %s", nOptions[0].c_str(), nOptions[1].c_str());\r
-\r
- break;\r
- case 431:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT a.c_id, a.c_conid, b.c_name, a.c_desc FROM contacts as a, characters as b WHERE a.c_conid = b.c_id AND a.c_id = %s", nOptions[0].c_str());\r
-\r
- break;\r
- case 435:\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT count(*) FROM contacts WHERE c_listid = %s AND c_type = %s", nOptions[0].c_str(), nOptions[1].c_str());\r
-\r
- break;\r
- case 436:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name FROM characters WHERE c_name LIKE \'%%%s%%\' LIMIT %s, %s", nOptions[0].c_str(), nOptions[1].c_str(), nOptions[2].c_str());\r
-\r
- break;\r
- case 437:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 1; //Fieldnum\r
- snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %s", nOptions[0].c_str());\r
-\r
- break;\r
- case 445:\r
- if(!ChkOpt(nNumOptions, 4)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT nc_id, nc_name FROM neochronicle WHERE nc_lang = %d ORDER BY nc_id DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
- case 446:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT nc_id, nc_lang, nc_datetime, nc_name, nc_content FROM neochronicle WHERE nc_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 453:\r
- if(!ChkOpt(nNumOptions, 4)) break;\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT g_id, 0, g_part, g_title, g_language FROM guides WHERE g_chapter = %d AND g_language = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
- case 455:\r
- if(!ChkOpt(nNumOptions, 4)) break;\r
- mResultFields = 3;\r
- // Opt 2 is Language\r
- snprintf (mSQLQuery, 500, "SELECT g_id, g_part, g_title FROM guides WHERE g_chapter = %d AND g_language = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
- case 456:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT g_id, g_language, g_title, g_content FROM guides WHERE g_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 458: // Statisics\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 459: // Statisics\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 510: // ClanWars: Overview\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_initclan = cl_id) or (cw_enemyclan = cl_id) WHERE (cw_enemyclan = %d OR cw_initclan = %d) AND (cl_id != %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
- break;\r
- case 511: // ClanWars: Selfdeclared wars\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_enemyclan = cl_id) WHERE cw_initclan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- break;\r
- case 512: // ClanWars: Foreigndeclared wars\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 4;\r
- snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_initclan = cl_id) WHERE cw_enemyclan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- break;\r
- case 513:\r
- if(!ChkOpt(nNumOptions, 4)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name FROM clans WHERE cl_faction = %d AND cl_id != %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
- break;\r
- case 514:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 520:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 10;\r
- snprintf (mSQLQuery, 500, "SELECT cl_faction, cl_shortdesc, cl_name, cl_description, 0, cl_appid, 80, cl_money, (SELECT count(*) FROM outposts WHERE o_clan = %d), (SELECT count(*) FROM characters WHERE c_clan = %d) FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 521:\r
- if(!ChkOpt(nNumOptions, 4)) break;\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE c_clan = %d AND cll_level >= %d AND cll_level < 15 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
- case 522:\r
- if(!ChkOpt(nNumOptions, 5)) break;\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE cll_level >= %d AND cll_level <= %d AND c_clan = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[2].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str()));\r
-\r
- break;\r
- case 523:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT cl_shortdesc, cl_name, cl_leader, cl_description, cl_minsympathy FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 540:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location FROM apartments WHERE apt_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 541:\r
- if(!ChkOpt(nNumOptions, 3)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT v_id, v_type FROM vehicles WHERE v_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 542:\r
- if(!ChkOpt(nNumOptions, 2)) break;\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT v_id, v_type, v_world, v_status, v_condition FROM vehicles WHERE v_owner = %d and v_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
-\r
- break;\r
- case 544:\r
- if(!ChkOpt(nNumOptions, 4)) break;\r
- mResultFields = 1;\r
- snprintf (mSQLQuery, 500, "SELECT count(*) FROM clanwars WHERE (cw_initclan = %d AND cw_enemyclan = %d) OR (cw_enemyclan = %d AND cw_initclan = %d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));\r
-\r
- break;\r
- case 546:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 2;\r
- snprintf (mSQLQuery, 500, "SELECT cw_starttime, (TO_DAYS(NOW()) - TO_DAYS(cw_starttime)) FROM clanwars WHERE cw_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 547:\r
- if(!ChkOpt(nNumOptions, 1)) break;\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT cw_initclan, cw_enemyclan, cw_starttime, cw_status, cw_statement_initiator, cw_statement_enemy FROM clanwars WHERE cw_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 557:\r
- Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d means that you want to edit an DialogScript from the server. This is not supportet yet!", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 558:\r
- Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d means that you want to edit an DialogScript from the server. This is not supportet yet!", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 562:\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT cb_inscription FROM datacubes WHERE cb_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 569:\r
- // Faction representatives. Not stored yet... is it?\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 570:\r
- // Clan representatives. Stored but this query wants votes too... Maybe later\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 571:\r
- // Clan representatives. Stored but this query wants votes too... Maybe later\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 572:\r
- // Runner voting. Not stored yet\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 573:\r
- // Next election date\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 574:\r
- mResultFields = 6;\r
- snprintf (mSQLQuery, 500, "SELECT count(c_id) FROM characters WHERE c_faction = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 575:\r
- // Runner satisfaction with faction\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 576:\r
- // Check if vote from runner is already stored\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 582:\r
- // Clan representative details. Faction rank etc... not stored yet\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 583:\r
- // Clan representative details. Faction rank etc... not stored yet\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 584:\r
- // Clan representative details. Faction rank etc... not stored yet\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 587:\r
- // Clan representative stuff again...\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 603:\r
- mResultFields = 1;\r
- //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 0");\r
- snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_inwork = 0 AND su_finished = 0");\r
-\r
- break;\r
- case 604:\r
- mResultFields = 1;\r
- //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 1");\r
- snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_inwork = 1 AND su_finished = 0");\r
-\r
- break;\r
- case 605:\r
- mResultFields = 1;\r
- //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 2");\r
- snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_finished = 1");\r
-\r
- break;\r
- case 606:\r
- mResultFields = 1;\r
- //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report`");\r
- snprintf (mSQLQuery, 500, "SELECT count(*) FROM support");\r
-\r
- break;\r
- case 607: // Dont know how to select data from sql where no data to JOIN is there anymore :/\r
- // This should query ID, RunnerID and Date from bug reports where runnerID is unknown\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 608:\r
- mResultFields = 5;\r
- snprintf (mSQLQuery, 500, "SELECT br_id, br_fromid, br_location, br_status, br_datetime FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 609:\r
- mResultFields = 1;\r
- //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_supid = %s", nOptions[0].c_str());\r
- snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_supporterid = %d", atoi(nOptions[0].c_str()));\r
-\r
- break;\r
- case 610:\r
- mResultFields = 6;\r
- //snprintf (mSQLQuery, 500, "SELECT br_id, \"0\", c_name, br_location, br_status = 2, br_datetime FROM `bug report`, characters WHERE c_id = br_fromid AND br_supid = %s AND br_status > 0 LIMIT %s, %s", nOptions[0].c_str(), nOptions[1].c_str(), nOptions[2].c_str());\r
- snprintf (mSQLQuery, 500, "SELECT su_id, su_supporterid, c_name, su_worldid, su_finished, su_datetime FROM support INNER JOIN characters ON (su_supporterid = c_id) WHERE su_supporterid = %d AND su_finished = 1 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
-\r
- break;\r
- case 611:// Well, its meant to show date specific stuff. I will rewrite this soon...\r
- snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_supporterid = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 612:// Well, its meant to show date specific stuff. I will rewrite this soon...\r
- snprintf (mSQLQuery, 500, "SELECT su_id, su_supporterid, c_name, su_worldid, su_finished, su_datetime FROM support INNER JOIN characters ON (su_supporterid = c_id) WHERE su_supporterid = %d AND su_finished = 1 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str()));\r
- break;\r
- case 625: // Faction council stuff\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 626: // Faction council stuff\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 627: // Faction council stuff\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 628: // Faction council stuff\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 629: // Faction council stuff\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- default:\r
- Console->Print("%s [Pterminal::HandleReceiveDB] Unknown QueryID %d", Console->ColorText(RED,BLACK,"Warning"), nDBID);\r
- return false;\r
- }\r
-\r
- if(strlen(mSQLQuery) == 0)\r
- return false;\r
-// ---------------\r
- MYSQL_RES *result = NULL;\r
- MYSQL_ROW row;\r
- int tNumRows = 0;\r
-\r
- result = MySQL->GameResQuery(mSQLQuery);\r
- if (!result)\r
- {\r
- Console->Print("Cannot query DB. DBID: %d query was: %s", nDBID, mSQLQuery);\r
- MySQL->ShowGameSQLError();\r
- return false;\r
- }\r
-\r
- PMessage* tDBResult = new PMessage();\r
- tNumRows = mysql_num_rows(result);\r
-\r
- // Loop all result rows\r
- for (int i = 0; i < tNumRows ; i++)\r
- {\r
- row = mysql_fetch_row( result ) ;\r
- // Loop all result fields and push answers into Message\r
- for (int t = 0; t < mResultFields; t++)\r
- {\r
- *tDBResult << ( uint16_t )(strlen(row[t]) + 1);\r
- *tDBResult << row[t];\r
- }\r
- }\r
-\r
- // Build result messages\r
- char tCmd[100];\r
- memset(tCmd, '\0', 100);\r
- strncpy(tCmd, nCommandName->c_str(), 100);\r
-\r
- PMessage* tmpMsg_allowed = MsgBuilder->BuildTryAccessAnswerMsg( nClient, tCmd, true );\r
- PMessage* tmpMsg_result = MsgBuilder->BuildReceiveDBAnswerMsg( nClient, tDBResult, nCommandName, tNumRows, mResultFields);\r
-\r
- nClient->SendUDPMessage(tmpMsg_allowed);\r
- nClient->FragmentAndSendUDPMessage(tmpMsg_result, 0x68);\r
-\r
- return true;\r
-}\r
+#include <cstring>
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+bool PTerminal::HandleReceiveDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown)
+{
+ EraseVars();
+ int nAccessLevel = nClient->GetAccountLevel();
+ //Console->Print("DBID: %d", nDBID);
+
+ switch (nDBID)
+ {
+ case 8:
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 6;
+ if(!strncmp(nOptions[0].c_str(), "date", 4))
+ //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ else
+ //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+ snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+ break;
+ case 9:
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 6;
+ if(!strncmp(nOptions[0].c_str(), "date", 4))
+ //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ else
+ //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+ snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+ break;
+ case 10:
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 6;
+ if(!strncmp(nOptions[0].c_str(), "date", 4))
+ //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ else
+ //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+ snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+ break;
+ case 11:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 6;
+ //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_content FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_id = %d", atoi(nOptions[0].c_str()));
+ snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_content FROM `neochronicle` WHERE nc_id = %d", atoi(nOptions[0].c_str()));
+ //snprintf (mSQLQuery, 500, "SELECT na_id, \'\', na_datetime, na_author, na_name, na_content FROM `neocron articles` WHERE na_approval = 1 AND na_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 14:
+ // 0: ID 1: Short 2: Clanname 3: FactionID 4: Faction Symp
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 6; // TODO: replace 0 with average faction sympathy
+ snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction, \"0\", \"0\" FROM `clans` WHERE cl_name LIKE \"%%%s%%\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 16:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ if (!strcmp (nOptions[0].c_str(), "Neocronicle"))
+ {
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT na_id, \'0\', na_datetime, na_author, na_name FROM `neocron articles` WHERE na_approval = 1 LIMIT %s, %s", nOptions[1].c_str(), nOptions[2].c_str());
+ }
+ else
+ {
+ mResultFields = 7;
+ snprintf (mSQLQuery, 500, "SELECT na_id, \'0\', na_datetime, na_author, na_name, na_approval, \"0\" FROM `neocron articles` LIMIT %s, %s", nOptions[1].c_str(), nOptions[2].c_str());
+ }
+
+ break;
+ case 18:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 20:
+ case 21:
+ // Select either c_"name" or c_"minsympathy". Names taken from option, saves if/else
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT `cl_%s` FROM `clans` WHERE `cl_id` = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()));
+
+ break;
+ case 25:
+ if(!ChkOpt(nNumOptions, 4)) break;
+ mResultFields = 6; // TODO: replace 0 with average faction sympathy
+ snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction, \"0\", \"0\" FROM clans WHERE cl_name > \"%s\" AND cl_name <=\"%s\" LIMIT %d, %d", nOptions[0].c_str(), nOptions[1].c_str(), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+ case 26:
+ // 0: short 1: name 2: money 3: faction 4: fac symp 5: symp_to_join 6: cappid
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT cl_shortdesc, cl_name, cl_money, cl_faction, \"0\", cl_minsympathy, cl_appid FROM `clans` WHERE `cl_id` = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 27:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_description, count(DISTINCT o_outnum), count(DISTINCT c_id) FROM outposts INNER JOIN clans ON (o_clan = cl_id) INNER JOIN characters ON (c_clan = clans.cl_id) WHERE (cl_id = %d) GROUP BY cl_id", atoi(nOptions[0].c_str()));
+
+ break;
+ case 28:
+ // Faction missions? Never seen them even in NC2...
+ Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d has not been written yet; Factionmissions..? Never seen them", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 29:
+ Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d Ordercol was missing. Its: [%s]", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID, nOptions[0].c_str());
+ break;
+ case 34:
+ // Name, Add. Info, Profession, Description, Overal Ranking, Soullight, Money, Runner Kills, Creature Kills
+ // Note: Add. Info is autogenerated clientside!
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 8;
+ snprintf (mSQLQuery, 500, "SELECT c_name, c_profession, \"0\", \"1\", \"127\", c_cash, \"0\", \"0\" FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 38:
+ // Faction missions? Never seen them even in NC2...
+ Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d has not been written yet; Factionmissions..? Never seen them", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 39:
+ // 0:id 1:name 2:clan 3:fac.symp
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_clan, \"75\" FROM characters WHERE c_name LIKE \"%s\"", nOptions[0].c_str());
+
+ break;
+ case 41:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT o_outnum, o_outnum, \"0\", \"0\", \"0\" FROM outposts WHERE o_clan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 46:
+ // charid, charname, charclanlevel, clanlevelname, charfactionsymp, char online
+ if(!ChkOpt(nNumOptions, 4)) break;
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, \"0\", c_online FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (cll_clanid = %d) AND (cll_level >= %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+ case 47:
+ if(!ChkOpt(nNumOptions, 5)) break;
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE cll_level >= %d AND cll_level <= %d AND c_clan = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[2].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str()));
+
+ break;
+ case 48:
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+ break;
+ case 49:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 50:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 2; //Fieldnum
+ snprintf (mSQLQuery, 500, "SELECT f_showname, f_name FROM forums WHERE f_area = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 51:
+ if(!ChkOpt(nNumOptions, 9)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND f_name = \'%s\' AND fp_replyid = 0 LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[7].c_str()), atoi(nOptions[8].c_str()));
+
+ break;
+ case 52:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 54:
+ // id, name, rank, rankname, f.symp
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, 0 FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_id = %d)", atoi(nOptions[0].c_str()));
+
+ break;
+ case 60: // Query for OutPost state. Result is <outpost ID> <clan ID>
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT o_outnum, o_clan FROM outposts LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+ break;
+ case 61: // It should display the clanname, but it doesnt. seems to be clientside bug
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT o_outnum, o_clan, o_clan, o_security FROM outposts WHERE o_outnum = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 75:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 76:
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT count(c_id) FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (cll_clanid = %d AND cll_desc = \"%s\")", atoi(nOptions[0].c_str()),nOptions[1].c_str());
+
+ break;
+ case 85:
+ if(!ChkOpt(nNumOptions, 4)) break;
+ mResultFields = 6; // No idea why this Fac.Symp is that high... 1000000 is 100 ingame. But only for this query
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, 1000000, c_online FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_online = %d OR c_online = 1) AND c_clan = %d LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+ case 86:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 4;
+ if(!strncmp(nOptions[1].c_str(), "date", 4))
+ snprintf (mSQLQuery, 500, "SELECT mt_id, mt_amount, mt_date, c_name FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+ else
+ snprintf (mSQLQuery, 500, "SELECT mt_id, mt_amount, mt_date, c_name FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 87:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT c_name, mt_date, mt_amount, mt_comment FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 92:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ // Location of player
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT c_location FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 93:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ // Name, Add. Info, Profession, Description
+ // Note: Add. Info is autogenerated clientside!
+ mResultFields = 3;
+ snprintf (mSQLQuery, 500, "SELECT c_name, c_profession, \"0\" FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 96:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT f_showname FROM forums WHERE f_name = \"%s\"", nOptions[0].c_str());
+
+ break;
+ case 98:
+ // ID, Name, Online, 0, Soullight
+ if(!ChkOpt(nNumOptions, 4)) break;
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_online, \"0\", c_soullight FROM characters WHERE c_online = %d AND c_soullight <= -%d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+ break;
+ case 99:
+ // Terrorist info
+ // id, name, faction, clan, clanlevel, location
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_faction, c_clan, cll_level, c_location FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_id = %d AND c_soullight <= -%d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+ break;
+ case 108:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT cl_name FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 109:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ // The only case where KK used an DBId twice for completely different things...
+ if(nNumOptions < 3)
+ {
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_clan, cll_level, cll_desc FROM characters INNER JOIN clanlevels ON (cll_charid = c_id AND cll_clanid = c_clan) WHERE c_id = %d", atoi(nOptions[0].c_str()));
+ }
+ else if(nNumOptions == 3)
+ {
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT c_id, apt_location FROM apartments INNER JOIN characters ON (apt_owner = c_id) WHERE (c_id = %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ }
+
+ break;
+ case 116:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT wr_id FROM worlds WHERE wr_group = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 125:
+ // Return position in Helpqueue. todo yet... for now its 255, we're always busy! =)
+ //if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT 255");
+
+ break;
+ case 126:
+ // Return position in Helpqueue. todo yet... for now its 255, we're always busy! =)
+ // This is with Datecheck, somehow..
+ //if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT 255");
+
+ break;
+ case 127:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT c_name, apt_location FROM apartments INNER JOIN characters ON (apt_owner = c_id) WHERE (c_id = %d)", atoi(nOptions[0].c_str()));
+
+ break;
+ case 128:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT su_id FROM support WHERE su_supporterid = %d AND su_finished = 0", atoi(nOptions[0].c_str()));
+
+ case 131:
+ mResultFields = 6;
+ //snprintf(mSQLQuery, 500, "SELECT br_id, br_type, c_online, c_name, br_location, br_datetime FROM `bug report`, characters WHERE c_id = br_fromid AND br_status = %d LIMIT %d, %d",
+ // atoi(nOptions[0].c_str())+atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+ snprintf(mSQLQuery, 500, "SELECT su_id, su_type, 0, c_name, su_worldid, su_datetime FROM support INNER JOIN characters ON (su_player = c_id) WHERE su_inwork = %d AND su_finished = %d LIMIT %d, %d",
+ atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+ case 132:
+ // reqid, runnerid, runnername, 0, date/time, type, 0, in work, finished, desc
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 10;
+ //snprintf(mSQLQuery, 500, "SELECT br_id, br_fromid, c_name, \"0\", br_datetime, br_type, \"0\", br_status, br_status, br_desc FROM `bug report` INNER JOIN characters ON (br_fromid = c_id) WHERE br_id = %d", atoi(nOptions[0].c_str()));
+ snprintf(mSQLQuery, 500, "SELECT su_id, su_player, c_name, 0, su_datetime, su_type, su_supporterid, su_inwork, su_finished, su_desc FROM support INNER JOIN characters ON (su_player = c_id) WHERE su_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 134:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 1;
+ snprintf(mSQLQuery, 500, "SELECT br_id FROM bug_report WHERE br_fromid = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 136:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 137:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ // runnerid, runnername, location, online
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name = \"%s\"", nOptions[0].c_str());
+ break;
+ case 138:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ // runnerid, runnername, location, online
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT br_type, br_location, br_datetime, br_supid, br_status, br_desc FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 143:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ // runnerid, runnername, location, online
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT a.a_id, a.a_username, b.c_id, 0, b.c_location, b.c_online FROM `%s`.accounts AS a, `%s`.characters AS b WHERE b.c_name = \"%s\" AND a.a_id = b.a_id",
+ Config->GetOption("info_sql_database").c_str(), Config->GetOption("game_sql_database").c_str(), nOptions[0].c_str());
+ break;
+ case 144:
+ mResultFields = 2; // Replace "1" with Online/Offline!
+ snprintf (mSQLQuery, 500, "SELECT c_location, c_online FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 145:
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT a_email FROM `%s`.accounts WHERE a_id = %d", Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str()));
+
+ break;
+ case 146:
+ mResultFields = 4;
+ // Too bad we named the row different...
+ char tSortRow[10];
+ if(!strncmp(nOptions[1].c_str(), "world", 5))
+ strcpy(tSortRow, "location");
+ else
+ strcpy(tSortRow, "name");
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name LIKE \"%s\" ORDER BY `c_%s` LIMIT %d, %d", nOptions[0].c_str(), tSortRow, atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+ case 147:
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_online = %d ORDER BY `c_%s` LIMIT %d, %d", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+ case 148:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, \"0\", \"0\", c_id FROM clans INNER JOIN characters ON (cl_leader = c_id) WHERE (cl_id = %d)", atoi(nOptions[0].c_str()));
+
+ break;
+ case 150:
+ // Mission stuff. Will be added later!
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 151:
+ // Mission stuff. Will be added later!
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 153:
+ // Mission stuff. Will be added later!
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 154:
+ // Mission stuff. Will be added later!
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 155:
+ // Mission stuff. Will be added later!
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 156:
+ // Mission stuff. Will be added later!
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 157:
+ // Mission stuff. Will be added later!
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 158:
+ // Mission stuff. Will be added later!
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 175:
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT br_id, br_type, br_title, br_datetime FROM bug_report LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+ break;
+ case 176:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 8;
+ snprintf (mSQLQuery, 500, "SELECT br_type, br_status, br_title, br_desc, 0, br_datetime, br_location, br_fromid FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 181:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 3;
+ snprintf (mSQLQuery, 500, "SELECT c_name, apt_location, apt_password FROM apartments INNER JOIN characters ON (c_id = apt_owner) WHERE apt_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 183:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name, (SELECT count(*) FROM characters WHERE c_clan = %d), c_name, apt_id, apt_location FROM clans INNER JOIN apartments ON (cl_appid = apt_id) INNER JOIN characters ON (c_clan = cl_id) AND (apt_owner = c_id) WHERE (cl_id = %d) GROUP BY c_id", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()));
+
+ break;
+ case 186:
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT c_id FROM characters WHERE c_name = \"%s\"", nOptions[0].c_str());
+
+ break;
+ case 220:
+ mResultFields = 4; //Fieldnum
+ snprintf (mSQLQuery, 500, "SELECT v_id, v_type, v_status, v_condition FROM vehicles WHERE v_owner = %i LIMIT %i, %i", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 221:
+ //VehicleControl order. "VehicleControl", "Type", "Status", "Condition", "Repairprice?"
+ mResultFields = 4; //Fieldnum
+ snprintf (mSQLQuery, 500, "SELECT v_type, v_status, v_condition, \"0\" FROM vehicles WHERE v_id = %s", nOptions[0].c_str());
+
+ break;
+ case 225:
+ // Statistics. Maybe later...
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 226:
+ // Statistics. Maybe later...
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 230:
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT st_id, st_factid, st_curval, st_curval-st_oldval FROM stockx");
+
+ break;
+ case 231:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT st_id, st_factid, st_curval, (st_curval - st_oldval) FROM stockx WHERE (st_id = %d)", atoi(nOptions[0].c_str()));
+
+ break;
+ case 232:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT sxd_id, st_factid, st_curval, sxd_amount, (sxd_amount * st_curval) FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) WHERE (sxd_playerid = %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 233:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 7;
+ snprintf (mSQLQuery, 500, "SELECT st_factid, sxd_amount, (st_curval - st_oldval), st_curval, sxd_paid, (sxd_amount * st_curval), ((sxd_amount * st_curval) - sxd_paid) FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) where sxd_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 234:
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 3;
+ snprintf (mSQLQuery, 500, "SELECT sxd_id, sxd_amount, sxd_paid FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) WHERE sxd_playerid = %d AND st_factid = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+ break;
+ case 250:
+ // Influence from CharID? Is stockx gm controlled??
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 251:
+ // What is this "influence" ? Check this on live servers!
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 260:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 2; //Fieldnum
+ snprintf (mSQLQuery, 500, "SELECT f_showname, f_name FROM forums WHERE f_area = %d+%d+%d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 261:
+ // Maybe even rewrite BB system.. its wrong written anyways....
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 262:
+ // This is wrong! 262 is the receiveDB request for FACTION threadlist. It should be limitet to that faction then
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND (fp_id = %s OR fp_replyid = %s)", nOptions[0].c_str(), nOptions[1].c_str());
+
+ //TODO Check this. Same (?) for ID 52,262,267,401 and 411
+ break;
+ case 266:
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND f_name = \'%s\' AND fp_replyid = 0 AND fp_clanid = %d LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+ case 267:
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND (fp_id = %s OR fp_replyid = %s)", nOptions[0].c_str(), nOptions[1].c_str());
+
+ break;
+ case 270:
+ Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d Tablename/Name is: [%s] ThreadID is: [%d]", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID, atoi(nOptions[0].c_str()), nOptions[1].c_str());
+ break;
+ case 360:
+ // Gamemaster name (char), Accountname, Location, Online, CharID
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT a.a_id, c.c_id, a.a_username, c.c_name, c.c_online, c.c_location FROM %s.characters AS c, %s.accounts AS a WHERE a.a_priv >= 50 AND c.c_online = %d AND c.a_id = a.a_id ORDER BY c.c_name LIMIT %d, %d",
+ Config->GetOption("game_sql_database").c_str(), Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 365:
+ // ID, short, name faction
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction FROM clans LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+ break;
+ case 366:
+ // ID, short, name faction WHERE clanname = %s
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction FROM clans WHERE cl_name LIKE \"%s\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 367:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 8;
+ snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_leader, cl_faction, cl_appid, cl_money, (SELECT count(*) FROM characters WHERE c_clan = %d) FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()));
+
+ break;
+ case 368:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 373:
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location, apt_type, apt_password FROM apartments WHERE apt_id = %d AND apt_owner = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+ break;
+ case 375:
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+ break;
+ case 376:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name LIKE \"%s\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 377:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT DISTINCT a_id FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 378:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT a_username, a_email, \"Since begin\", \"Never\", FROM_UNIXTIME(a_bandate) FROM `%s`.accounts WHERE a_id = %d", Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str()));
+
+ break;
+ case 379:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online, c_clan, cll_level FROM characters INNER JOIN clanlevels ON (cll_charid = c_id) WHERE c_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 380: // clean
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT cl_name, cll_desc FROM clans INNER JOIN clanlevels ON (cll_clanid = cl_id) WHERE cl_id = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+ break;
+ case 381:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, c_online FROM characters WHERE a_id = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 384: // clean
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location, 0, apt_password FROM apartments WHERE apt_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 400:
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 401:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 406:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT count(fp_id) FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) WHERE f_name = \"%s\"", nOptions[0].c_str());
+
+ break;
+ case 410:
+ if(!ChkOpt(nNumOptions, 4)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM forum_posts INNER JOIN forums ON (fp_forumid = f_area) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\" AND fp_factionid = %d) LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+ case 411:
+ if(!ChkOpt(nNumOptions, 4)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_area) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d) AND (fp_factionid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+
+ case 420:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT e_id, e_subject, c_name, e_new, e_replied, e_datetime FROM emails, characters WHERE e_fromid = c_id AND e_toid = %i LIMIT %i, %i", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 421:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ //MailControl order. "MailControl", "Mail ID", "Subject", "From", boolean Replied, "Date/Time", "FromID", "Content"
+ mResultFields = 7;
+ snprintf (mSQLQuery, 500, "SELECT e_id, e_subject, c_name, e_replied, e_datetime, e_fromid, e_body FROM emails, characters WHERE e_fromid = c_id AND e_id = %s", nOptions[0].c_str());
+
+ break;
+ case 425:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ //Send mail order. "SendMail", "id"
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT c_id FROM characters WHERE c_name = \'%s\'", nOptions[0].c_str());
+
+ break;
+ case 430:
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT a.c_id, a.c_conid, b.c_name, a.c_desc FROM contacts as a, characters as b WHERE a.c_conid = b.c_id AND a.c_listid = %s AND c_type = %s", nOptions[0].c_str(), nOptions[1].c_str());
+
+ break;
+ case 431:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT a.c_id, a.c_conid, b.c_name, a.c_desc FROM contacts as a, characters as b WHERE a.c_conid = b.c_id AND a.c_id = %s", nOptions[0].c_str());
+
+ break;
+ case 435:
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT count(*) FROM contacts WHERE c_listid = %s AND c_type = %s", nOptions[0].c_str(), nOptions[1].c_str());
+
+ break;
+ case 436:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name FROM characters WHERE c_name LIKE \'%%%s%%\' LIMIT %s, %s", nOptions[0].c_str(), nOptions[1].c_str(), nOptions[2].c_str());
+
+ break;
+ case 437:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 1; //Fieldnum
+ snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %s", nOptions[0].c_str());
+
+ break;
+ case 445:
+ if(!ChkOpt(nNumOptions, 4)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT nc_id, nc_name FROM neochronicle WHERE nc_lang = %d ORDER BY nc_id DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+ case 446:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT nc_id, nc_lang, nc_datetime, nc_name, nc_content FROM neochronicle WHERE nc_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 453:
+ if(!ChkOpt(nNumOptions, 4)) break;
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT g_id, 0, g_part, g_title, g_language FROM guides WHERE g_chapter = %d AND g_language = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+ case 455:
+ if(!ChkOpt(nNumOptions, 4)) break;
+ mResultFields = 3;
+ // Opt 2 is Language
+ snprintf (mSQLQuery, 500, "SELECT g_id, g_part, g_title FROM guides WHERE g_chapter = %d AND g_language = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+ case 456:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT g_id, g_language, g_title, g_content FROM guides WHERE g_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 458: // Statisics
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 459: // Statisics
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 510: // ClanWars: Overview
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_initclan = cl_id) or (cw_enemyclan = cl_id) WHERE (cw_enemyclan = %d OR cw_initclan = %d) AND (cl_id != %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+ break;
+ case 511: // ClanWars: Selfdeclared wars
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_enemyclan = cl_id) WHERE cw_initclan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ break;
+ case 512: // ClanWars: Foreigndeclared wars
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 4;
+ snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_initclan = cl_id) WHERE cw_enemyclan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ break;
+ case 513:
+ if(!ChkOpt(nNumOptions, 4)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name FROM clans WHERE cl_faction = %d AND cl_id != %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+ break;
+ case 514:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 520:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 10;
+ snprintf (mSQLQuery, 500, "SELECT cl_faction, cl_shortdesc, cl_name, cl_description, 0, cl_appid, 80, cl_money, (SELECT count(*) FROM outposts WHERE o_clan = %d), (SELECT count(*) FROM characters WHERE c_clan = %d) FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()));
+
+ break;
+ case 521:
+ if(!ChkOpt(nNumOptions, 4)) break;
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE c_clan = %d AND cll_level >= %d AND cll_level < 15 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+ case 522:
+ if(!ChkOpt(nNumOptions, 5)) break;
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE cll_level >= %d AND cll_level <= %d AND c_clan = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[2].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str()));
+
+ break;
+ case 523:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT cl_shortdesc, cl_name, cl_leader, cl_description, cl_minsympathy FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 540:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location FROM apartments WHERE apt_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 541:
+ if(!ChkOpt(nNumOptions, 3)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT v_id, v_type FROM vehicles WHERE v_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 542:
+ if(!ChkOpt(nNumOptions, 2)) break;
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT v_id, v_type, v_world, v_status, v_condition FROM vehicles WHERE v_owner = %d and v_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+
+ break;
+ case 544:
+ if(!ChkOpt(nNumOptions, 4)) break;
+ mResultFields = 1;
+ snprintf (mSQLQuery, 500, "SELECT count(*) FROM clanwars WHERE (cw_initclan = %d AND cw_enemyclan = %d) OR (cw_enemyclan = %d AND cw_initclan = %d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()));
+
+ break;
+ case 546:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 2;
+ snprintf (mSQLQuery, 500, "SELECT cw_starttime, (TO_DAYS(NOW()) - TO_DAYS(cw_starttime)) FROM clanwars WHERE cw_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 547:
+ if(!ChkOpt(nNumOptions, 1)) break;
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT cw_initclan, cw_enemyclan, cw_starttime, cw_status, cw_statement_initiator, cw_statement_enemy FROM clanwars WHERE cw_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 557:
+ Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d means that you want to edit an DialogScript from the server. This is not supportet yet!", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 558:
+ Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d means that you want to edit an DialogScript from the server. This is not supportet yet!", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 562:
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT cb_inscription FROM datacubes WHERE cb_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 569:
+ // Faction representatives. Not stored yet... is it?
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 570:
+ // Clan representatives. Stored but this query wants votes too... Maybe later
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 571:
+ // Clan representatives. Stored but this query wants votes too... Maybe later
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 572:
+ // Runner voting. Not stored yet
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 573:
+ // Next election date
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 574:
+ mResultFields = 6;
+ snprintf (mSQLQuery, 500, "SELECT count(c_id) FROM characters WHERE c_faction = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 575:
+ // Runner satisfaction with faction
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 576:
+ // Check if vote from runner is already stored
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 582:
+ // Clan representative details. Faction rank etc... not stored yet
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 583:
+ // Clan representative details. Faction rank etc... not stored yet
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 584:
+ // Clan representative details. Faction rank etc... not stored yet
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 587:
+ // Clan representative stuff again...
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 603:
+ mResultFields = 1;
+ //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 0");
+ snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_inwork = 0 AND su_finished = 0");
+
+ break;
+ case 604:
+ mResultFields = 1;
+ //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 1");
+ snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_inwork = 1 AND su_finished = 0");
+
+ break;
+ case 605:
+ mResultFields = 1;
+ //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 2");
+ snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_finished = 1");
+
+ break;
+ case 606:
+ mResultFields = 1;
+ //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report`");
+ snprintf (mSQLQuery, 500, "SELECT count(*) FROM support");
+
+ break;
+ case 607: // Dont know how to select data from sql where no data to JOIN is there anymore :/
+ // This should query ID, RunnerID and Date from bug reports where runnerID is unknown
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 608:
+ mResultFields = 5;
+ snprintf (mSQLQuery, 500, "SELECT br_id, br_fromid, br_location, br_status, br_datetime FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 609:
+ mResultFields = 1;
+ //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_supid = %s", nOptions[0].c_str());
+ snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_supporterid = %d", atoi(nOptions[0].c_str()));
+
+ break;
+ case 610:
+ mResultFields = 6;
+ //snprintf (mSQLQuery, 500, "SELECT br_id, \"0\", c_name, br_location, br_status = 2, br_datetime FROM `bug report`, characters WHERE c_id = br_fromid AND br_supid = %s AND br_status > 0 LIMIT %s, %s", nOptions[0].c_str(), nOptions[1].c_str(), nOptions[2].c_str());
+ snprintf (mSQLQuery, 500, "SELECT su_id, su_supporterid, c_name, su_worldid, su_finished, su_datetime FROM support INNER JOIN characters ON (su_supporterid = c_id) WHERE su_supporterid = %d AND su_finished = 1 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+
+ break;
+ case 611:// Well, its meant to show date specific stuff. I will rewrite this soon...
+ snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_supporterid = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 612:// Well, its meant to show date specific stuff. I will rewrite this soon...
+ snprintf (mSQLQuery, 500, "SELECT su_id, su_supporterid, c_name, su_worldid, su_finished, su_datetime FROM support INNER JOIN characters ON (su_supporterid = c_id) WHERE su_supporterid = %d AND su_finished = 1 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str()));
+ break;
+ case 625: // Faction council stuff
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 626: // Faction council stuff
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 627: // Faction council stuff
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 628: // Faction council stuff
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 629: // Faction council stuff
+ Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ default:
+ Console->Print("%s [Pterminal::HandleReceiveDB] Unknown QueryID %d", Console->ColorText(RED,BLACK,"Warning"), nDBID);
+ return false;
+ }
+
+ if(strlen(mSQLQuery) == 0)
+ return false;
+// ---------------
+ MYSQL_RES *result = NULL;
+ MYSQL_ROW row;
+ int tNumRows = 0;
+
+ result = MySQL->GameResQuery(mSQLQuery);
+ if (!result)
+ {
+ Console->Print("Cannot query DB. DBID: %d query was: %s", nDBID, mSQLQuery);
+ MySQL->ShowGameSQLError();
+ return false;
+ }
+
+ PMessage* tDBResult = new PMessage();
+ tNumRows = mysql_num_rows(result);
+
+ // Loop all result rows
+ for (int i = 0; i < tNumRows ; i++)
+ {
+ row = mysql_fetch_row( result ) ;
+ // Loop all result fields and push answers into Message
+ for (int t = 0; t < mResultFields; t++)
+ {
+ *tDBResult << ( uint16_t )(strlen(row[t]) + 1);
+ *tDBResult << row[t];
+ }
+ }
+
+ // Build result messages
+ char tCmd[100];
+ memset(tCmd, '\0', 100);
+ strncpy(tCmd, nCommandName->c_str(), 100);
+
+ PMessage* tmpMsg_allowed = MsgBuilder->BuildTryAccessAnswerMsg( nClient, tCmd, true );
+ PMessage* tmpMsg_result = MsgBuilder->BuildReceiveDBAnswerMsg( nClient, tDBResult, nCommandName, tNumRows, mResultFields);
+
+ nClient->SendUDPMessage(tmpMsg_allowed);
+ nClient->FragmentAndSendUDPMessage(tmpMsg_result, 0x68);
+
+ return true;
+}
-#include <cstring>\r
-#include <sstream>\r
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-bool PTerminal::HandleUpdateDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown)\r
-{\r
- std::ostringstream tLongSQL; // omg my eyes... Stringstream is one of the worst inventions ever! Stick with printf syntax!!111\r
- char tShortSQL[1024]; // Use this for small updates that will not exceed 1kb\r
- memset(tShortSQL, '\0', 1024);\r
- bool tSuccess = false;\r
-\r
- //Console->Print("UpdateDB ID: %d", nDBID);\r
- switch (nDBID)\r
- {\r
- case 5:\r
- tLongSQL << "INSERT INTO neochronicle (nc_icon, nc_author, nc_datetime, nc_name, nc_content)";\r
- tLongSQL << " VALUES (" << atoi(nOptions[0].c_str()) << ", \"" << nOptions[1] << "\", \"" << nOptions[2] << "\", \"" << nOptions[3] << "\", \"" << nOptions[4] << "\")";\r
-\r
- break;\r
- case 6:\r
- // UPDATE when Neocronicle DB is changed! author must be CHAR not INT\r
- break;\r
- case 7: // Delete neocronicle\r
- snprintf(tShortSQL, 1024, "DELETE FROM neochronicle WHERE nc_id = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 12:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 53: // Runner writing to public board\r
- snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str(), nOptions[4].c_str(), nOptions[5].c_str());\r
- break;\r
- case 58:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 62: // Set new outpost security\r
- snprintf(tShortSQL, 1024, "UPDATE outposts SET o_security = %d WHERE o_outnum = %d AND o_clan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- break;\r
-\r
- case 66: // Claninfo stuff that is somehow never used... Print error if it is\r
- case 67:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] QueryID %d should never happen. Please contact Linux Addited forums!", Console->ColorText(RED,BLACK,"Notice"), nDBID);\r
- break;\r
-\r
- case 77: // Delete old clanlevel\r
- snprintf(tShortSQL, 1024, "DELETE FROM clanlevels WHERE cll_clanid = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
- break;\r
- case 78: // Add new clanlevel\r
- snprintf(tShortSQL, 1024, "INSERT INTO clanlevels (cll_clanid, cll_desc, cll_level) VALUES (%d, \"%s\", %d)", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str()));\r
- break;\r
- case 84: // Take/Give money to/from clan\r
- tLongSQL << "INSERT INTO moneytransactions (mt_clanid, mt_player, mt_amount, mt_date, mt_comment) ";\r
- tLongSQL << "VALUES (" << atoi(nOptions[0].c_str()) << ", " << atoi(nOptions[1].c_str()) << ", " << atoi(nOptions[2].c_str()) << ", \"" << nOptions[3] << "\", \"" << nOptions[4] << "\")";\r
- break;\r
- case 94: // Update runner description\r
- snprintf(tShortSQL, 1024, "UPDATE characters SET c_desc = \"%s\" WHERE c_id = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()));\r
- break;\r
- case 97:\r
- // Just ignore that... KK required some extra updates here\r
- tSuccess = true;\r
- //Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 120: // Create support call\r
- snprintf(tShortSQL, 1024, "INSERT INTO support (su_player, su_worldid, su_type, su_desc) VALUES (%d, %d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str());\r
- break;\r
- case 121:\r
- snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 1, su_supporterid = %d WHERE su_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
- break;\r
- case 122:\r
- snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 0, su_supporterid = 0 WHERE su_id = %d AND su_supporterid = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
- break;\r
- case 123:\r
- snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 1, su_finished = 1, su_supporterid = %d WHERE su_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
- break;\r
- case 124:\r
- snprintf(tShortSQL, 1024, "DELETE FROM support WHERE su_id = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 133:\r
- tSuccess = true;\r
- //Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 139:\r
- snprintf(tShortSQL, 1024, "UPDATE characters SET c_location = %d WHERE c_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));\r
- break;\r
- case 142:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 149: // Changeleader 2nd step. Update clanappartment owner\r
- snprintf(tShortSQL, 1024, "UPDATE apartments SET apt_owner = %d WHERE apt_id = %d AND apt_owner = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- break;\r
- case 160: // Missions, not yet\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 161: // Missions, not yet\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 162: // Missions, not yet\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 163: // Missions, not yet\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 164: // Missions, not yet\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 165: // Missions, not yet\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 170: // Enter new bug\r
- snprintf(tShortSQL, 1024, "INSERT INTO bug_report (br_type, br_status, br_title, br_desc, br_location, br_fromid, br_datetime) VALUES (%d, %d, \"%s\", \"%s\", %d, %d, NOW())", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), atoi(nOptions[4].c_str()), atoi(nOptions[5].c_str()));\r
- break;\r
- case 172: // Delete bug id %d\r
- snprintf(tShortSQL, 1024, "DELETE FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 180:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 182:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 235:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 252:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 263: // Runner writing to Faction Board\r
- snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_factionid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str());\r
- break;\r
- case 268: // Runner writing to ClanBoard\r
- snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_clanid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str());\r
- break;\r
- case 370: // GM ClanRepair\r
- snprintf(tShortSQL, 1024, "INSERT INTO clanlevels (cll_clanid, cll_level, cll_desc) VALUES (%d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str());\r
- break;\r
- case 385: // Clandelete 1/7 Clanlevels\r
- snprintf(tShortSQL, 1024, "DELETE FROM clanlevels WHERE cl_clanid = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 386: // Clandelete 2/7 Outposts\r
- snprintf(tShortSQL, 1024, "UPDATE outposts SET o_clan = 0 WHERE o_clan = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 387: // Clandelete 3/7 Free users from clans\r
- snprintf(tShortSQL, 1024, "UPDATE characters SET c_clan = 0 WHERE c_clan = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 388: // Clandelete 4/7 The clan itself\r
- snprintf(tShortSQL, 1024, "DELETE FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 389: // Clandelete 5/7 ?\r
- tSuccess = true;\r
- break;\r
- case 390: // Clandelete 6/7 Clanappartment\r
- snprintf(tShortSQL, 1024, "DELETE FROM apartments WHERE apt_id = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 391: // Clandelete 7/7 ?\r
- tSuccess = true;\r
- break;\r
- case 402: // GM writing to publicforum\r
- snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str(), nOptions[4].c_str(), nOptions[5].c_str());\r
- break;\r
- case 404: // GM deleting forum entry step 1\r
- snprintf(tShortSQL, 1024, "DELETE FROM forum_posts WHERE fp_id = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 405: // GM deleting forum entry step 2\r
- snprintf(tShortSQL, 1024, "DELETE FROM forum_posts WHERE fp_replyid = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 412: // GM writing to faction forum\r
- snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_factionid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str());\r
- break;\r
- case 422: // Mark email as replied\r
- snprintf(tShortSQL, 1024, "UPDATE emails SET e_replied = 1 WHERE e_id = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 423: // Write new email\r
- snprintf(tShortSQL, 1024, "INSERT INTO emails (e_fromid,e_toid,e_datetime,e_subject,e_body) VALUES (%d, %d, \"%s\", \"%s\", \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), nOptions[4].c_str());\r
- break;\r
- case 424: // Delete email\r
- snprintf(tShortSQL, 1024, "DELETE FROM emails WHERE e_id = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 426: // Mark email as read\r
- snprintf(tShortSQL, 1024, "UPDATE emails SET e_new = 0 WHERE e_id = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 432: // Add new contact\r
- snprintf(tShortSQL, 1024, "INSERT INTO contacts (c_listid,c_conid,c_type,c_desc) VALUES (%d, %d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str());\r
- break;\r
- case 433: // Edit contact\r
- snprintf(tShortSQL, 1024, "UPDATE contacts SET c_type = %d, c_desc = \"%s\" WHERE c_id = %d", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str()));\r
- break;\r
- case 434: // Delete contact\r
- snprintf(tShortSQL, 1024, "DELETE FROM contacts WHERE c_id = %d", atoi(nOptions[0].c_str()));\r
- break;\r
- case 447:\r
- snprintf(tShortSQL, 1024, "INSERT INTO neochronicle (nc_icon, nc_author, nc_datetime, nc_name, nc_content, nc_lang) VALUES (%d, \"%s\", \"%s\", \"%s\", \"%s\", %d)", atoi(nOptions[0].c_str()), nOptions[1].c_str(), nOptions[2].c_str(), nOptions[3].c_str(), nOptions[4].c_str(), atoi(nOptions[5].c_str()));\r
- break;\r
- case 450:\r
- snprintf(tShortSQL, 1024, "INSERT INTO guides (g_chapter, g_part, g_title, g_content, g_language) VALUES (%d, %d, \"%s\", \"%s\", %d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), atoi(nOptions[4].c_str()));\r
- break;\r
- case 515: // Create new clanwar\r
- snprintf(tShortSQL, 1024, "INSERT INTO clanwars (cw_initclan, cw_enemyclan, cw_starttime) VALUES (%d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str());\r
- break;\r
- case 516:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 517:\r
- // Special: Check if Clan of our char is = nOption2\r
- if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str()))\r
- snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_status = %d WHERE cw_id = %d AND cw_initclan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- // else: SQL Query is empty = failed as result\r
- break;\r
- case 518:\r
- if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str()))\r
- snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_status = %d WHERE cw_id = %d AND cw_enemyclan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- // else: SQL Query is empty = failed as result\r
- break;\r
- case 519:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 525: // Update clan short\r
- tLongSQL << "UPDATE clans SET cl_shortdesc = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str());\r
-\r
- break;\r
- case 526: // Update clan name\r
- tLongSQL << "UPDATE clans SET cl_name = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str());\r
-\r
- break;\r
- case 527: // Update clanapp password\r
- //UPDATE apartments SET apt_password = x WHERE apt_owner = x AND apt_id = (SELECT clans.cl_appid WHERE clans.cl_id = x)\r
- tLongSQL << "UPDATE apartments SET apt_password = \"" << nOptions[0] << "\" WHERE apt_owner = " << atoi(nOptions[2].c_str()) << " AND apt_id = (SELECT cl_appid FROM clans WHERE cl_id = " << atoi(nOptions[1].c_str()) << ")";\r
- break;\r
- case 528:\r
- tLongSQL << "UPDATE clans SET cl_minsympathy = " << atoi(nOptions[0].c_str()) << " WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str());\r
- break;\r
- case 529:\r
- tLongSQL << "UPDATE clans SET cl_description = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str());\r
- break;\r
- case 543:\r
- // Only delete if: option 2 is >= 7 (days); option0 is 5 or 6; option 4 = our clanid\r
- if(atoi(nOptions[2].c_str()) >= 7)\r
- if(atoi(nOptions[0].c_str()) == 5 || atoi(nOptions[0].c_str()) == 6)\r
- if(nClient->GetChar()->GetClan() == atoi(nOptions[4].c_str()))\r
- snprintf(tShortSQL, 1024, "DELETE FROM clanwars WHERE (cw_status = 5 OR cw_status = 6) AND cw_id = %d AND cw_initclan = %d", atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str()));\r
-\r
- //Console->Print("%s", tShortSQL);\r
- break;\r
- case 548:\r
- // Check clanmembership\r
- if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str()))\r
- snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_statement_initiator = \"%s\" WHERE cw_id = %d AND cw_initclan = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- break;\r
- case 549:\r
- // Check clanmembership\r
- if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str()))\r
- snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_statement_enemy = \"%s\" WHERE cw_id = %d AND cw_enemyclan = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));\r
- break;\r
- case 555:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 556:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 561:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 577:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 578:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 579:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 580:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 581:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 585:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 590:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 591:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- case 600: // Just ok, skip it\r
- tSuccess = true;\r
- break;\r
- case 601: // Just ok, skip it\r
- tSuccess = true;\r
- break;\r
- case 630:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);\r
- break;\r
- default:\r
- Console->Print("%s [Pterminal::HandleUpdateDB] Unknown QueryID %d", Console->ColorText(RED,BLACK,"Warning"), nDBID);\r
- return false;\r
- }\r
-\r
-// -------\r
- if(tLongSQL.str().length() > 0)\r
- {\r
- if(MySQL->GameQuery(tLongSQL.str().c_str()))\r
- {\r
- Console->Print("Cannot update DB. query was: %s", tLongSQL.str().c_str());\r
- MySQL->ShowGameSQLError();\r
- tSuccess = false;\r
- }\r
- else\r
- tSuccess = true;\r
- }\r
- else if(strlen(tShortSQL) > 0)\r
- {\r
- if(MySQL->GameQuery(tShortSQL))\r
- {\r
- Console->Print("Cannot update DB. query was: %s", tShortSQL);\r
- MySQL->ShowGameSQLError();\r
- tSuccess = false;\r
- }\r
- else\r
- tSuccess = true;\r
- }\r
-\r
- // Notice client about UpdateDB result\r
- char tCmd[100];\r
- memset(tCmd, '\0', 100);\r
- strncpy(tCmd, nCommandName->c_str(), 100);\r
-\r
- PMessage* tmpMsg = MsgBuilder->BuildTryAccessAnswerMsg(nClient, tCmd, tSuccess);\r
- nClient->SendUDPMessage(tmpMsg);\r
- return true;\r
-}\r
+#include <cstring>
+#include <sstream>
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+bool PTerminal::HandleUpdateDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown)
+{
+ std::ostringstream tLongSQL; // omg my eyes... Stringstream is one of the worst inventions ever! Stick with printf syntax!!111
+ char tShortSQL[1024]; // Use this for small updates that will not exceed 1kb
+ memset(tShortSQL, '\0', 1024);
+ bool tSuccess = false;
+
+ //Console->Print("UpdateDB ID: %d", nDBID);
+ switch (nDBID)
+ {
+ case 5:
+ tLongSQL << "INSERT INTO neochronicle (nc_icon, nc_author, nc_datetime, nc_name, nc_content)";
+ tLongSQL << " VALUES (" << atoi(nOptions[0].c_str()) << ", \"" << nOptions[1] << "\", \"" << nOptions[2] << "\", \"" << nOptions[3] << "\", \"" << nOptions[4] << "\")";
+
+ break;
+ case 6:
+ // UPDATE when Neocronicle DB is changed! author must be CHAR not INT
+ break;
+ case 7: // Delete neocronicle
+ snprintf(tShortSQL, 1024, "DELETE FROM neochronicle WHERE nc_id = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 12:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 53: // Runner writing to public board
+ snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str(), nOptions[4].c_str(), nOptions[5].c_str());
+ break;
+ case 58:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 62: // Set new outpost security
+ snprintf(tShortSQL, 1024, "UPDATE outposts SET o_security = %d WHERE o_outnum = %d AND o_clan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ break;
+
+ case 66: // Claninfo stuff that is somehow never used... Print error if it is
+ case 67:
+ Console->Print("%s [Pterminal::HandleUpdateDB] QueryID %d should never happen. Please contact Linux Addited forums!", Console->ColorText(RED,BLACK,"Notice"), nDBID);
+ break;
+
+ case 77: // Delete old clanlevel
+ snprintf(tShortSQL, 1024, "DELETE FROM clanlevels WHERE cll_clanid = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+ break;
+ case 78: // Add new clanlevel
+ snprintf(tShortSQL, 1024, "INSERT INTO clanlevels (cll_clanid, cll_desc, cll_level) VALUES (%d, \"%s\", %d)", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str()));
+ break;
+ case 84: // Take/Give money to/from clan
+ tLongSQL << "INSERT INTO moneytransactions (mt_clanid, mt_player, mt_amount, mt_date, mt_comment) ";
+ tLongSQL << "VALUES (" << atoi(nOptions[0].c_str()) << ", " << atoi(nOptions[1].c_str()) << ", " << atoi(nOptions[2].c_str()) << ", \"" << nOptions[3] << "\", \"" << nOptions[4] << "\")";
+ break;
+ case 94: // Update runner description
+ snprintf(tShortSQL, 1024, "UPDATE characters SET c_desc = \"%s\" WHERE c_id = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()));
+ break;
+ case 97:
+ // Just ignore that... KK required some extra updates here
+ tSuccess = true;
+ //Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 120: // Create support call
+ snprintf(tShortSQL, 1024, "INSERT INTO support (su_player, su_worldid, su_type, su_desc) VALUES (%d, %d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str());
+ break;
+ case 121:
+ snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 1, su_supporterid = %d WHERE su_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+ break;
+ case 122:
+ snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 0, su_supporterid = 0 WHERE su_id = %d AND su_supporterid = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+ break;
+ case 123:
+ snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 1, su_finished = 1, su_supporterid = %d WHERE su_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+ break;
+ case 124:
+ snprintf(tShortSQL, 1024, "DELETE FROM support WHERE su_id = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 133:
+ tSuccess = true;
+ //Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 139:
+ snprintf(tShortSQL, 1024, "UPDATE characters SET c_location = %d WHERE c_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()));
+ break;
+ case 142:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 149: // Changeleader 2nd step. Update clanappartment owner
+ snprintf(tShortSQL, 1024, "UPDATE apartments SET apt_owner = %d WHERE apt_id = %d AND apt_owner = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ break;
+ case 160: // Missions, not yet
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 161: // Missions, not yet
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 162: // Missions, not yet
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 163: // Missions, not yet
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 164: // Missions, not yet
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 165: // Missions, not yet
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 170: // Enter new bug
+ snprintf(tShortSQL, 1024, "INSERT INTO bug_report (br_type, br_status, br_title, br_desc, br_location, br_fromid, br_datetime) VALUES (%d, %d, \"%s\", \"%s\", %d, %d, NOW())", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), atoi(nOptions[4].c_str()), atoi(nOptions[5].c_str()));
+ break;
+ case 172: // Delete bug id %d
+ snprintf(tShortSQL, 1024, "DELETE FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 180:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 182:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 235:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 252:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 263: // Runner writing to Faction Board
+ snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_factionid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str());
+ break;
+ case 268: // Runner writing to ClanBoard
+ snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_clanid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str());
+ break;
+ case 370: // GM ClanRepair
+ snprintf(tShortSQL, 1024, "INSERT INTO clanlevels (cll_clanid, cll_level, cll_desc) VALUES (%d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str());
+ break;
+ case 385: // Clandelete 1/7 Clanlevels
+ snprintf(tShortSQL, 1024, "DELETE FROM clanlevels WHERE cl_clanid = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 386: // Clandelete 2/7 Outposts
+ snprintf(tShortSQL, 1024, "UPDATE outposts SET o_clan = 0 WHERE o_clan = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 387: // Clandelete 3/7 Free users from clans
+ snprintf(tShortSQL, 1024, "UPDATE characters SET c_clan = 0 WHERE c_clan = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 388: // Clandelete 4/7 The clan itself
+ snprintf(tShortSQL, 1024, "DELETE FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 389: // Clandelete 5/7 ?
+ tSuccess = true;
+ break;
+ case 390: // Clandelete 6/7 Clanappartment
+ snprintf(tShortSQL, 1024, "DELETE FROM apartments WHERE apt_id = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 391: // Clandelete 7/7 ?
+ tSuccess = true;
+ break;
+ case 402: // GM writing to publicforum
+ snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str(), nOptions[4].c_str(), nOptions[5].c_str());
+ break;
+ case 404: // GM deleting forum entry step 1
+ snprintf(tShortSQL, 1024, "DELETE FROM forum_posts WHERE fp_id = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 405: // GM deleting forum entry step 2
+ snprintf(tShortSQL, 1024, "DELETE FROM forum_posts WHERE fp_replyid = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 412: // GM writing to faction forum
+ snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_factionid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str());
+ break;
+ case 422: // Mark email as replied
+ snprintf(tShortSQL, 1024, "UPDATE emails SET e_replied = 1 WHERE e_id = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 423: // Write new email
+ snprintf(tShortSQL, 1024, "INSERT INTO emails (e_fromid,e_toid,e_datetime,e_subject,e_body) VALUES (%d, %d, \"%s\", \"%s\", \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), nOptions[4].c_str());
+ break;
+ case 424: // Delete email
+ snprintf(tShortSQL, 1024, "DELETE FROM emails WHERE e_id = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 426: // Mark email as read
+ snprintf(tShortSQL, 1024, "UPDATE emails SET e_new = 0 WHERE e_id = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 432: // Add new contact
+ snprintf(tShortSQL, 1024, "INSERT INTO contacts (c_listid,c_conid,c_type,c_desc) VALUES (%d, %d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str());
+ break;
+ case 433: // Edit contact
+ snprintf(tShortSQL, 1024, "UPDATE contacts SET c_type = %d, c_desc = \"%s\" WHERE c_id = %d", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str()));
+ break;
+ case 434: // Delete contact
+ snprintf(tShortSQL, 1024, "DELETE FROM contacts WHERE c_id = %d", atoi(nOptions[0].c_str()));
+ break;
+ case 447:
+ snprintf(tShortSQL, 1024, "INSERT INTO neochronicle (nc_icon, nc_author, nc_datetime, nc_name, nc_content, nc_lang) VALUES (%d, \"%s\", \"%s\", \"%s\", \"%s\", %d)", atoi(nOptions[0].c_str()), nOptions[1].c_str(), nOptions[2].c_str(), nOptions[3].c_str(), nOptions[4].c_str(), atoi(nOptions[5].c_str()));
+ break;
+ case 450:
+ snprintf(tShortSQL, 1024, "INSERT INTO guides (g_chapter, g_part, g_title, g_content, g_language) VALUES (%d, %d, \"%s\", \"%s\", %d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), atoi(nOptions[4].c_str()));
+ break;
+ case 515: // Create new clanwar
+ snprintf(tShortSQL, 1024, "INSERT INTO clanwars (cw_initclan, cw_enemyclan, cw_starttime) VALUES (%d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str());
+ break;
+ case 516:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 517:
+ // Special: Check if Clan of our char is = nOption2
+ if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str()))
+ snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_status = %d WHERE cw_id = %d AND cw_initclan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ // else: SQL Query is empty = failed as result
+ break;
+ case 518:
+ if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str()))
+ snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_status = %d WHERE cw_id = %d AND cw_enemyclan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ // else: SQL Query is empty = failed as result
+ break;
+ case 519:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 525: // Update clan short
+ tLongSQL << "UPDATE clans SET cl_shortdesc = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str());
+
+ break;
+ case 526: // Update clan name
+ tLongSQL << "UPDATE clans SET cl_name = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str());
+
+ break;
+ case 527: // Update clanapp password
+ //UPDATE apartments SET apt_password = x WHERE apt_owner = x AND apt_id = (SELECT clans.cl_appid WHERE clans.cl_id = x)
+ tLongSQL << "UPDATE apartments SET apt_password = \"" << nOptions[0] << "\" WHERE apt_owner = " << atoi(nOptions[2].c_str()) << " AND apt_id = (SELECT cl_appid FROM clans WHERE cl_id = " << atoi(nOptions[1].c_str()) << ")";
+ break;
+ case 528:
+ tLongSQL << "UPDATE clans SET cl_minsympathy = " << atoi(nOptions[0].c_str()) << " WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str());
+ break;
+ case 529:
+ tLongSQL << "UPDATE clans SET cl_description = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str());
+ break;
+ case 543:
+ // Only delete if: option 2 is >= 7 (days); option0 is 5 or 6; option 4 = our clanid
+ if(atoi(nOptions[2].c_str()) >= 7)
+ if(atoi(nOptions[0].c_str()) == 5 || atoi(nOptions[0].c_str()) == 6)
+ if(nClient->GetChar()->GetClan() == atoi(nOptions[4].c_str()))
+ snprintf(tShortSQL, 1024, "DELETE FROM clanwars WHERE (cw_status = 5 OR cw_status = 6) AND cw_id = %d AND cw_initclan = %d", atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str()));
+
+ //Console->Print("%s", tShortSQL);
+ break;
+ case 548:
+ // Check clanmembership
+ if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str()))
+ snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_statement_initiator = \"%s\" WHERE cw_id = %d AND cw_initclan = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ break;
+ case 549:
+ // Check clanmembership
+ if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str()))
+ snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_statement_enemy = \"%s\" WHERE cw_id = %d AND cw_enemyclan = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()));
+ break;
+ case 555:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 556:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 561:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 577:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 578:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 579:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 580:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 581:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 585:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 590:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 591:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ case 600: // Just ok, skip it
+ tSuccess = true;
+ break;
+ case 601: // Just ok, skip it
+ tSuccess = true;
+ break;
+ case 630:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID);
+ break;
+ default:
+ Console->Print("%s [Pterminal::HandleUpdateDB] Unknown QueryID %d", Console->ColorText(RED,BLACK,"Warning"), nDBID);
+ return false;
+ }
+
+// -------
+ if(tLongSQL.str().length() > 0)
+ {
+ if(MySQL->GameQuery(tLongSQL.str().c_str()))
+ {
+ Console->Print("Cannot update DB. query was: %s", tLongSQL.str().c_str());
+ MySQL->ShowGameSQLError();
+ tSuccess = false;
+ }
+ else
+ tSuccess = true;
+ }
+ else if(strlen(tShortSQL) > 0)
+ {
+ if(MySQL->GameQuery(tShortSQL))
+ {
+ Console->Print("Cannot update DB. query was: %s", tShortSQL);
+ MySQL->ShowGameSQLError();
+ tSuccess = false;
+ }
+ else
+ tSuccess = true;
+ }
+
+ // Notice client about UpdateDB result
+ char tCmd[100];
+ memset(tCmd, '\0', 100);
+ strncpy(tCmd, nCommandName->c_str(), 100);
+
+ PMessage* tmpMsg = MsgBuilder->BuildTryAccessAnswerMsg(nClient, tCmd, tSuccess);
+ nClient->SendUDPMessage(tmpMsg);
+ return true;
+}
-#include "GameServer/Includes.hxx"\r
-#include "GameServer/Definitions/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-// PVhcCoordinates\r
-void PVhcCoordinates::SetInterpolate( const PVhcCoordinates& Pos1, const PVhcCoordinates& Pos2, float nCoef )\r
-{\r
- if (( nCoef < 0 ) || ( nCoef > 1 ) )\r
- {\r
- Console->Print( RED, BLACK, "[Error] PVhcCoordinates::Interpolate : Invalid nCoef value: %f", nCoef );\r
- nCoef = 0;\r
- }\r
- float rCoef = 1 - nCoef;\r
-\r
- mY = ( uint16_t )( rCoef * Pos1.mY + nCoef * Pos2.mY );\r
- mZ = ( uint16_t )( rCoef * Pos1.mZ + nCoef * Pos2.mZ );\r
- mX = ( uint16_t )( rCoef * Pos1.mX + nCoef * Pos2.mX );\r
- mUD = ( uint8_t )( rCoef * Pos1.mUD + nCoef * Pos2.mUD );\r
- mLR = ( uint16_t )( rCoef * Pos1.mLR + nCoef * Pos2.mLR );\r
- mRoll = ( uint16_t )( rCoef * Pos1.mRoll + nCoef * Pos2.mRoll );\r
-}\r
-\r
-void PVhcCoordinates::SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD, uint16_t nLR, uint16_t nRoll, uint8_t nAct, uint16_t nUnknown, uint8_t nFF )\r
-{\r
- mY = nY;\r
- mZ = nZ;\r
- mX = nX;\r
- mUD = nUD;\r
- mLR = nLR;\r
- mRoll = nRoll;\r
- mAct = nAct;\r
- mUnknown = nUnknown;\r
- mFF = nFF;\r
-}\r
-\r
-// PVehicleInformation\r
-//Tmp\r
-const uint8_t VhcTypes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,\r
- 11, 12, 13, 50, 60, 62, 64, 65, 70\r
- }; // (adv.) assault gliders discarded because not ok\r
-#define VHC_DISABLE_NOVULARI\r
-#ifndef VHC_DISABLE_NOVULARI\r
-const uint8_t VhcTypesNum = 19;\r
-#else\r
-const uint8_t VhcTypesNum = 18;\r
-#endif\r
-\r
-bool PVehicleInformation::Load( uint32_t nVehicleId )\r
-{\r
- uint8_t i;\r
- uint8_t nVId = nVehicleId % 100; //Tmp\r
- for ( i = 0; ( i < VhcTypesNum ) && ( VhcTypes[i] < nVId ); i++ ) ; //Tmp\r
- if (( i < VhcTypesNum ) && ( VhcTypes[i] == nVId ) ) //Tmp\r
- {\r
- mVehicleId = nVehicleId;\r
- mOwnerCharId = nVehicleId / 100; // tmp\r
- mHealth = 200; // Tmp\r
- mVehicleType = nVId; // tmp\r
- mStatus = 0;\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-bool PVehicleInformation::Save()\r
-{\r
- // Shall we Destroy() when mStatus == 2, or keep destroyed vhc in DB ?\r
- return true;\r
-}\r
-\r
-bool PVehicleInformation::Destroy()\r
-{\r
- if ( mStatus == 2 )\r
- {\r
- // Delete from DB\r
- mVehicleId = 0;\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-bool PVehicleInformation::SetStatus( uint8_t nStatus )\r
-{\r
- if (( mStatus != 2 ) && ( nStatus <= 2 ) )\r
- {\r
- mStatus = nStatus;\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-// PSpawnedVehicule\r
-const uint8_t PSpawnedVehicle::mSeatsFlags[] = { 1, 2, 4, 8, 16, 32, 64, 128 };\r
-\r
-PSpawnedVehicle::PSpawnedVehicle( uint32_t nLocalId, PVehicleInformation const* nVhcInfo, uint32_t nLocation, PVhcCoordinates const* nVhcPos )\r
-{\r
- mLocalId = nLocalId;\r
- mInfo = *nVhcInfo;\r
- mLocation = nLocation;\r
- mCoords = *nVhcPos;\r
- for ( int i = 0; i < 8; ++i )\r
- mSeatUserId[i] = 0;\r
-\r
- mVhcDef = GameDefs->Vhcs()->GetDef( mInfo.mVehicleType );\r
- if ( ! mVhcDef )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Invalid vhc type %d for vhc id %d (local %d) owner char id %d", mInfo.mVehicleType, mInfo.mVehicleId, mLocalId, mInfo.mOwnerCharId );\r
- Console->Print( RED, BLACK, "[NOTICE] Setting vhc type to %d for vhc id %d (local %d) owner char id %d", VhcTypes[0], mInfo.mVehicleId, mLocalId, mInfo.mOwnerCharId );\r
- mInfo.mVehicleType = VhcTypes[0];\r
- mVhcDef = GameDefs->Vhcs()->GetDef( mInfo.mVehicleType );\r
- }\r
-\r
- mNbFreeSeats = GetNumSeats();\r
- if ( mNbFreeSeats > 8 )\r
- {\r
- Console->Print( RED, BLACK, "[ERROR] Vhc type %d has more than 8 seats (%d)", mInfo.mVehicleType, mNbFreeSeats );\r
- mNbFreeSeats = 8;\r
- }\r
- for ( int i = 0; i < mNbFreeSeats; ++i )\r
- mFreeSeatsFlags |= mSeatsFlags[i];\r
-\r
- //Temp\r
- for ( int i = 0; i < 4; ++i )\r
- {\r
- minmax[i][0] = 0xffff;\r
- minmax[i][1] = 0;\r
- }\r
-}\r
-\r
-void PSpawnedVehicle::SetLocation( uint32_t nLocation )\r
-{\r
- mLocation = nLocation;\r
-}\r
-\r
-void PSpawnedVehicle::SetPosition( PVhcCoordinates const* nVhcPos )\r
-{\r
- mCoords = *nVhcPos;\r
- // Temp\r
- if(gDevDebug)\r
- {\r
- if ( mCoords.mUD < minmax[0][0] ) minmax[0][0] = mCoords.mUD;\r
- if ( mCoords.mUD > minmax[0][1] ) minmax[0][1] = mCoords.mUD;\r
- if ( mCoords.mLR < minmax[1][0] ) minmax[1][0] = mCoords.mLR;\r
- if ( mCoords.mLR > minmax[1][1] ) minmax[1][1] = mCoords.mLR;\r
- if ( mCoords.mRoll < minmax[2][0] ) minmax[2][0] = mCoords.mRoll;\r
- if ( mCoords.mRoll > minmax[2][1] ) minmax[2][1] = mCoords.mRoll;\r
- Console->Print( "%s Min/Max: UD:%d/%d(%d) LR:%d/%d(%d) Roll:%d/%d(%d)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), minmax[0][0], minmax[0][1], mCoords.mUD, minmax[1][0], minmax[1][1], mCoords.mLR, minmax[2][0], minmax[2][1], mCoords.mRoll );\r
- }\r
-}\r
-\r
-int PSpawnedVehicle::GetNumSeats() const\r
-{\r
- return mVhcDef->GetNumSeats();\r
-}\r
-\r
-bool PSpawnedVehicle::SetSeatUser( uint8_t nSeatId, uint32_t nCharId )\r
-{\r
- if ( nSeatId < mVhcDef->GetNumSeats() )\r
- {\r
- if ( ! mSeatUserId[nSeatId] )\r
- {\r
- mSeatUserId[nSeatId] = nCharId;\r
- mFreeSeatsFlags &= ~mSeatsFlags[nSeatId];\r
- --mNbFreeSeats;\r
- return true;\r
- }\r
- }\r
- return false;\r
-}\r
-\r
-bool PSpawnedVehicle::UnsetSeatUser( uint8_t nSeatId, uint32_t nCharId )\r
-{\r
- if ( nSeatId < mVhcDef->GetNumSeats() )\r
- {\r
- if ( mSeatUserId[nSeatId] == nCharId )\r
- {\r
- mSeatUserId[nSeatId] = 0;\r
- mFreeSeatsFlags |= mSeatsFlags[nSeatId];\r
- ++mNbFreeSeats;\r
- return true;\r
- }\r
- }\r
- return false;\r
-}\r
-\r
-bool PSpawnedVehicle::IsCharInside( uint32_t nCharId ) const\r
-{\r
- for ( int i = 0; i < mVhcDef->GetNumSeats(); ++i )\r
- {\r
- if ( mSeatUserId[i] == nCharId )\r
- return true;\r
- }\r
- return false;\r
-}\r
-\r
-uint8_t PSpawnedVehicle::GetFirstFreeSeat() const\r
-{\r
- for ( int i = 0; i < mVhcDef->GetNumSeats(); ++i )\r
- {\r
- if ( ! mSeatUserId[i] )\r
- return i;\r
- }\r
-\r
- return 255;\r
-}\r
-/*uint8_t PSpawnedVehicle::GetFreeSeats() const\r
-{\r
- uint8_t bitField = 0;\r
-\r
- for(int i = mVhcDef->GetNumSeats() - 1; i >= 0 ; --i)\r
- {\r
- bitField <<= 1;\r
- if ( ! mSeatUserId[i] )\r
- bitField |= 1;\r
- }\r
-\r
- return bitField;\r
-}*/\r
-\r
-// PVehicles\r
-PVehicles::PVehicles()\r
-{\r
-\r
-}\r
-\r
-PVehicles::~PVehicles()\r
-{\r
-\r
-}\r
-\r
-bool PVehicles::RegisterSpawnedVehicle( PSpawnedVehicle* nSpawnedVehicle )\r
-{\r
- std::pair<PSpawnedVhcMap::iterator, bool> Result = mSpawnedVehicles.insert( std::make_pair( nSpawnedVehicle->GetVehicleId(), nSpawnedVehicle ) );\r
- return Result.second;\r
-}\r
-\r
-bool PVehicles::UnregisterSpawnedVehicle( uint32_t nVehicleId )\r
-{\r
- PSpawnedVhcMap::iterator it = mSpawnedVehicles.find( nVehicleId );\r
- if ( it != mSpawnedVehicles.end() )\r
- {\r
- mSpawnedVehicles.erase( it );\r
- return true;\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-}\r
-\r
-//uint32_t PVehicles::CreateVehicle(uint32_t nOwnerChar, uint8_t mVehicleType) {}\r
-//bool PVehicles::RegisterVehicleOwner(uint32_t nVehicleId, uint32_t nOwnerChar) {}\r
-//bool PVehicles::DestroyVehicle(uint32_t nVehicleId) {}\r
-\r
-bool PVehicles::IsValidVehicle( uint32_t nVehicleId, bool nCheckOwner, uint32_t nOwnerId ) const\r
-{\r
- // Look in DB\r
- // tmp\r
- uint32_t tVehicleId = nVehicleId;\r
- bool tCheckOwner = nCheckOwner;\r
- uint32_t tOwnerId = nOwnerId;\r
- return true; // tmp\r
-}\r
-\r
-PSpawnedVehicle* PVehicles::GetSpawnedVehicle( uint32_t nVehicleId ) const\r
-{\r
- PSpawnedVhcMap::const_iterator it = mSpawnedVehicles.find( nVehicleId );\r
- if ( it != mSpawnedVehicles.end() )\r
- {\r
- return ( it->second );\r
- }\r
- else\r
- {\r
- return NULL;\r
- }\r
-}\r
-\r
-bool PVehicles::GetVehicleInfo( uint32_t nVehicleId, PVehicleInformation* nInfo ) const\r
-{\r
- PSpawnedVehicle* tVhc = GetSpawnedVehicle( nVehicleId );\r
- if ( tVhc )\r
- {\r
- *nInfo = tVhc->GetInformation();\r
- return true;\r
- }\r
- else\r
- {\r
- return nInfo->Load( nVehicleId );\r
- }\r
-}\r
-\r
-PVhcInfoList* PVehicles::GetCharVehicles( uint32_t nCharId, uint16_t nMaxCount, uint16_t nStartIndex )\r
-{\r
- PVhcInfoList* Entries = new PVhcInfoList();\r
- PVehicleInformation* InfoEntry;\r
- // Tmp implementation\r
- uint16_t LimitIndex = nStartIndex + nMaxCount;\r
- if ( !nMaxCount || ( VhcTypesNum < LimitIndex ) )\r
- {\r
- LimitIndex = VhcTypesNum;\r
- }\r
-\r
- for ( uint16_t i = nStartIndex; ( i < LimitIndex ) ; ++i )\r
- {\r
- InfoEntry = new PVehicleInformation();\r
- if ( GetVehicleInfo( nCharId * 100 + VhcTypes[i], InfoEntry ) )\r
- {\r
- Entries->push( InfoEntry );\r
- }\r
- else\r
- {\r
- delete InfoEntry;\r
- }\r
- }\r
-\r
- return Entries;\r
-}\r
-\r
-PSpawnedVehicle* PVehicles::SpawnVehicle( uint32_t nVehicleId, uint32_t nLocation, PVhcCoordinates const* nVhcPos )\r
-{\r
- PSpawnedVehicle* newVhc = NULL;\r
- PWorld* cWorld;\r
- PVehicleInformation nVhcInfo;\r
-\r
- if (( nLocation != PWorlds::mNcSubwayWorldId ) && IsValidVehicle( nVehicleId ) && !IsSpawned( nVehicleId ) )\r
- {\r
- cWorld = Worlds->LeaseWorld( nLocation );\r
-\r
- if ( cWorld && GetVehicleInfo( nVehicleId, &nVhcInfo ) )\r
- {\r
- newVhc = cWorld->GetSpawnedVehicles()->SpawnVehicle( &nVhcInfo, nVhcPos );\r
- if ( newVhc )\r
- {\r
- if ( !RegisterSpawnedVehicle( newVhc ) )\r
- {\r
- Console->Print( RED, BLACK, "[Error] PVehicles::SpawnVehicle : Could not register spawned vhc" );\r
- }\r
- if( gDevDebug )\r
- Console->Print( "%d Spawned vhc %d (local 0x%04x) type %d (requested: %d)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), newVhc->GetVehicleId(), newVhc->GetLocalId(), newVhc->GetInformation().GetVehicleType(), nVhcInfo.GetVehicleType() );\r
- }\r
- else\r
- Console->Print( RED, BLACK, "[Error] PVehicles::SpawnVehicle : Could not create vhc" );\r
- }\r
-\r
- Worlds->ReleaseWorld( nLocation );\r
- }\r
-\r
- return newVhc;\r
-}\r
-\r
-bool PVehicles::UnspawnVehicle( uint32_t nVehicleId )\r
-{\r
- PWorld* cWorld;\r
- bool Result = false;\r
-\r
- PSpawnedVhcMap::iterator it = mSpawnedVehicles.find( nVehicleId );\r
- if ( it != mSpawnedVehicles.end() )\r
- {\r
- cWorld = Worlds->LeaseWorld( it->second->GetLocation() );\r
-\r
- if ( cWorld )\r
- {\r
- if ( !it->second->Save() )\r
- {\r
- Console->Print( RED, BLACK, "[Error] PVehicles::UnspawnVehicle : Could not save vhc %d", nVehicleId );\r
- }\r
-\r
- Result = cWorld->GetSpawnedVehicles()->UnspawnVehicle( it->second->GetLocalId() );\r
- if ( Result )\r
- {\r
- if ( !UnregisterSpawnedVehicle( nVehicleId ) )\r
- {\r
- Console->Print( RED, BLACK, "[Error] PVehicles::UnspawnVehicle : Could not unregister vhc %d", nVehicleId );\r
- }\r
- }\r
- }\r
-\r
- Worlds->ReleaseWorld( it->second->GetLocation() );\r
- }\r
-\r
- return Result;\r
-}\r
-\r
-//PSpawnedVehicles\r
-PSpawnedVehicles::PSpawnedVehicles()\r
-{\r
- mNextFreeHint = 0;\r
- mLocation = 0;\r
-}\r
-\r
-PSpawnedVehicles::~PSpawnedVehicles()\r
-{\r
-\r
-}\r
-\r
-PSpawnedVehicle* PSpawnedVehicles::SpawnVehicle( PVehicleInformation const* nVhcInfo, PVhcCoordinates const* nVhcPos )\r
-{\r
- PSpawnedVehicle* newVhc = NULL;\r
- uint32_t nSize;\r
-\r
- if ( nVhcInfo->GetStatus() == 0 ) // only if in garage\r
- {\r
- nSize = mSpawnedVehicles.size();\r
- while (( mNextFreeHint < nSize ) && mSpawnedVehicles[mNextFreeHint] )\r
- {\r
- ++mNextFreeHint;\r
- }\r
- if ( mNextFreeHint > nSize )\r
- {\r
- mNextFreeHint = nSize;\r
- }\r
- if ( mNextFreeHint == nSize )\r
- {\r
- mSpawnedVehicles.push_back( static_cast<PSpawnedVehicle *>(NULL) );\r
- }\r
-\r
- if ( mNextFreeHint < mMaxLocalVhc )\r
- {\r
- newVhc = new PSpawnedVehicle( mVhcBaseLocalId - mNextFreeHint, nVhcInfo, mLocation, nVhcPos );\r
- mSpawnedVehicles[mNextFreeHint++] = newVhc;\r
- newVhc->SetStatus( 1 );\r
- }\r
- }\r
-\r
- return newVhc;\r
-}\r
-\r
-PSpawnedVehicle* PSpawnedVehicles::GetVehicle( uint32_t nLocalId )\r
-{\r
- if (( nLocalId <= mVhcBaseLocalId ) && ( nLocalId > ( mVhcBaseLocalId - mSpawnedVehicles.size() ) ) )\r
- {\r
- return mSpawnedVehicles[mVhcBaseLocalId - nLocalId];\r
- }\r
- else\r
- {\r
- return NULL;\r
- }\r
-}\r
-\r
-PSpawnedVehicle* PSpawnedVehicles::GetVehicleByGlobalId( uint32_t nVehicleId ) const\r
-{\r
- for ( PSpawnedVhcVector::const_iterator it = mSpawnedVehicles.begin(); it != mSpawnedVehicles.end(); it++ )\r
- {\r
- if (( *it )->GetVehicleId() == nVehicleId )\r
- {\r
- return ( *it );\r
- }\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-bool PSpawnedVehicles::UnspawnVehicle( uint32_t nLocalId )\r
-{\r
- uint16_t Index;\r
- PSpawnedVehicle* tVhc;\r
-\r
- if (( nLocalId <= mVhcBaseLocalId ) && ( nLocalId > ( mVhcBaseLocalId - mSpawnedVehicles.size() ) ) )\r
- {\r
- Index = mVhcBaseLocalId - nLocalId;\r
- tVhc = mSpawnedVehicles[Index];\r
- if ( tVhc )\r
- {\r
- if ( tVhc->GetInformation().GetStatus() != 2 )\r
- {\r
- tVhc->SetStatus( 0 );\r
- }\r
- delete tVhc;\r
- mSpawnedVehicles[Index] = NULL;\r
- if ( mNextFreeHint > Index )\r
- {\r
- mNextFreeHint = Index;\r
- }\r
- return true;\r
- }\r
- }\r
-\r
- return false;\r
-}\r
-\r
-PSpawnedVhcList* PSpawnedVehicles::GetSpawnedVehicles() const\r
-{\r
- PSpawnedVhcList* Entries = new PSpawnedVhcList();\r
-\r
- for ( PSpawnedVhcVector::const_iterator i = mSpawnedVehicles.begin(); i != mSpawnedVehicles.end(); ++i )\r
- {\r
- if ( *i )\r
- {\r
- Entries->push( *i );\r
- }\r
- }\r
-\r
- return Entries;\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "GameServer/Definitions/Includes.hxx"
+#include "Common/Includes.hxx"
+
+// PVhcCoordinates
+void PVhcCoordinates::SetInterpolate( const PVhcCoordinates& Pos1, const PVhcCoordinates& Pos2, float nCoef )
+{
+ if (( nCoef < 0 ) || ( nCoef > 1 ) )
+ {
+ Console->Print( RED, BLACK, "[Error] PVhcCoordinates::Interpolate : Invalid nCoef value: %f", nCoef );
+ nCoef = 0;
+ }
+ float rCoef = 1 - nCoef;
+
+ mY = ( uint16_t )( rCoef * Pos1.mY + nCoef * Pos2.mY );
+ mZ = ( uint16_t )( rCoef * Pos1.mZ + nCoef * Pos2.mZ );
+ mX = ( uint16_t )( rCoef * Pos1.mX + nCoef * Pos2.mX );
+ mUD = ( uint8_t )( rCoef * Pos1.mUD + nCoef * Pos2.mUD );
+ mLR = ( uint16_t )( rCoef * Pos1.mLR + nCoef * Pos2.mLR );
+ mRoll = ( uint16_t )( rCoef * Pos1.mRoll + nCoef * Pos2.mRoll );
+}
+
+void PVhcCoordinates::SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD, uint16_t nLR, uint16_t nRoll, uint8_t nAct, uint16_t nUnknown, uint8_t nFF )
+{
+ mY = nY;
+ mZ = nZ;
+ mX = nX;
+ mUD = nUD;
+ mLR = nLR;
+ mRoll = nRoll;
+ mAct = nAct;
+ mUnknown = nUnknown;
+ mFF = nFF;
+}
+
+// PVehicleInformation
+//Tmp
+const uint8_t VhcTypes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 50, 60, 62, 64, 65, 70
+ }; // (adv.) assault gliders discarded because not ok
+#define VHC_DISABLE_NOVULARI
+#ifndef VHC_DISABLE_NOVULARI
+const uint8_t VhcTypesNum = 19;
+#else
+const uint8_t VhcTypesNum = 18;
+#endif
+
+bool PVehicleInformation::Load( uint32_t nVehicleId )
+{
+ uint8_t i;
+ uint8_t nVId = nVehicleId % 100; //Tmp
+ for ( i = 0; ( i < VhcTypesNum ) && ( VhcTypes[i] < nVId ); i++ ) ; //Tmp
+ if (( i < VhcTypesNum ) && ( VhcTypes[i] == nVId ) ) //Tmp
+ {
+ mVehicleId = nVehicleId;
+ mOwnerCharId = nVehicleId / 100; // tmp
+ mHealth = 200; // Tmp
+ mVehicleType = nVId; // tmp
+ mStatus = 0;
+ return true;
+ }
+ else
+ return false;
+}
+
+bool PVehicleInformation::Save()
+{
+ // Shall we Destroy() when mStatus == 2, or keep destroyed vhc in DB ?
+ return true;
+}
+
+bool PVehicleInformation::Destroy()
+{
+ if ( mStatus == 2 )
+ {
+ // Delete from DB
+ mVehicleId = 0;
+ return true;
+ }
+ else
+ return false;
+}
+
+bool PVehicleInformation::SetStatus( uint8_t nStatus )
+{
+ if (( mStatus != 2 ) && ( nStatus <= 2 ) )
+ {
+ mStatus = nStatus;
+ return true;
+ }
+ else
+ return false;
+}
+
+// PSpawnedVehicule
+const uint8_t PSpawnedVehicle::mSeatsFlags[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
+
+PSpawnedVehicle::PSpawnedVehicle( uint32_t nLocalId, PVehicleInformation const* nVhcInfo, uint32_t nLocation, PVhcCoordinates const* nVhcPos )
+{
+ mLocalId = nLocalId;
+ mInfo = *nVhcInfo;
+ mLocation = nLocation;
+ mCoords = *nVhcPos;
+ for ( int i = 0; i < 8; ++i )
+ mSeatUserId[i] = 0;
+
+ mVhcDef = GameDefs->Vhcs()->GetDef( mInfo.mVehicleType );
+ if ( ! mVhcDef )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Invalid vhc type %d for vhc id %d (local %d) owner char id %d", mInfo.mVehicleType, mInfo.mVehicleId, mLocalId, mInfo.mOwnerCharId );
+ Console->Print( RED, BLACK, "[NOTICE] Setting vhc type to %d for vhc id %d (local %d) owner char id %d", VhcTypes[0], mInfo.mVehicleId, mLocalId, mInfo.mOwnerCharId );
+ mInfo.mVehicleType = VhcTypes[0];
+ mVhcDef = GameDefs->Vhcs()->GetDef( mInfo.mVehicleType );
+ }
+
+ mNbFreeSeats = GetNumSeats();
+ if ( mNbFreeSeats > 8 )
+ {
+ Console->Print( RED, BLACK, "[ERROR] Vhc type %d has more than 8 seats (%d)", mInfo.mVehicleType, mNbFreeSeats );
+ mNbFreeSeats = 8;
+ }
+ for ( int i = 0; i < mNbFreeSeats; ++i )
+ mFreeSeatsFlags |= mSeatsFlags[i];
+
+ //Temp
+ for ( int i = 0; i < 4; ++i )
+ {
+ minmax[i][0] = 0xffff;
+ minmax[i][1] = 0;
+ }
+}
+
+void PSpawnedVehicle::SetLocation( uint32_t nLocation )
+{
+ mLocation = nLocation;
+}
+
+void PSpawnedVehicle::SetPosition( PVhcCoordinates const* nVhcPos )
+{
+ mCoords = *nVhcPos;
+ // Temp
+ if(gDevDebug)
+ {
+ if ( mCoords.mUD < minmax[0][0] ) minmax[0][0] = mCoords.mUD;
+ if ( mCoords.mUD > minmax[0][1] ) minmax[0][1] = mCoords.mUD;
+ if ( mCoords.mLR < minmax[1][0] ) minmax[1][0] = mCoords.mLR;
+ if ( mCoords.mLR > minmax[1][1] ) minmax[1][1] = mCoords.mLR;
+ if ( mCoords.mRoll < minmax[2][0] ) minmax[2][0] = mCoords.mRoll;
+ if ( mCoords.mRoll > minmax[2][1] ) minmax[2][1] = mCoords.mRoll;
+ Console->Print( "%s Min/Max: UD:%d/%d(%d) LR:%d/%d(%d) Roll:%d/%d(%d)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), minmax[0][0], minmax[0][1], mCoords.mUD, minmax[1][0], minmax[1][1], mCoords.mLR, minmax[2][0], minmax[2][1], mCoords.mRoll );
+ }
+}
+
+int PSpawnedVehicle::GetNumSeats() const
+{
+ return mVhcDef->GetNumSeats();
+}
+
+bool PSpawnedVehicle::SetSeatUser( uint8_t nSeatId, uint32_t nCharId )
+{
+ if ( nSeatId < mVhcDef->GetNumSeats() )
+ {
+ if ( ! mSeatUserId[nSeatId] )
+ {
+ mSeatUserId[nSeatId] = nCharId;
+ mFreeSeatsFlags &= ~mSeatsFlags[nSeatId];
+ --mNbFreeSeats;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PSpawnedVehicle::UnsetSeatUser( uint8_t nSeatId, uint32_t nCharId )
+{
+ if ( nSeatId < mVhcDef->GetNumSeats() )
+ {
+ if ( mSeatUserId[nSeatId] == nCharId )
+ {
+ mSeatUserId[nSeatId] = 0;
+ mFreeSeatsFlags |= mSeatsFlags[nSeatId];
+ ++mNbFreeSeats;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PSpawnedVehicle::IsCharInside( uint32_t nCharId ) const
+{
+ for ( int i = 0; i < mVhcDef->GetNumSeats(); ++i )
+ {
+ if ( mSeatUserId[i] == nCharId )
+ return true;
+ }
+ return false;
+}
+
+uint8_t PSpawnedVehicle::GetFirstFreeSeat() const
+{
+ for ( int i = 0; i < mVhcDef->GetNumSeats(); ++i )
+ {
+ if ( ! mSeatUserId[i] )
+ return i;
+ }
+
+ return 255;
+}
+/*uint8_t PSpawnedVehicle::GetFreeSeats() const
+{
+ uint8_t bitField = 0;
+
+ for(int i = mVhcDef->GetNumSeats() - 1; i >= 0 ; --i)
+ {
+ bitField <<= 1;
+ if ( ! mSeatUserId[i] )
+ bitField |= 1;
+ }
+
+ return bitField;
+}*/
+
+// PVehicles
+PVehicles::PVehicles()
+{
+
+}
+
+PVehicles::~PVehicles()
+{
+
+}
+
+bool PVehicles::RegisterSpawnedVehicle( PSpawnedVehicle* nSpawnedVehicle )
+{
+ std::pair<PSpawnedVhcMap::iterator, bool> Result = mSpawnedVehicles.insert( std::make_pair( nSpawnedVehicle->GetVehicleId(), nSpawnedVehicle ) );
+ return Result.second;
+}
+
+bool PVehicles::UnregisterSpawnedVehicle( uint32_t nVehicleId )
+{
+ PSpawnedVhcMap::iterator it = mSpawnedVehicles.find( nVehicleId );
+ if ( it != mSpawnedVehicles.end() )
+ {
+ mSpawnedVehicles.erase( it );
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//uint32_t PVehicles::CreateVehicle(uint32_t nOwnerChar, uint8_t mVehicleType) {}
+//bool PVehicles::RegisterVehicleOwner(uint32_t nVehicleId, uint32_t nOwnerChar) {}
+//bool PVehicles::DestroyVehicle(uint32_t nVehicleId) {}
+
+bool PVehicles::IsValidVehicle( uint32_t nVehicleId, bool nCheckOwner, uint32_t nOwnerId ) const
+{
+ // Look in DB
+ // tmp
+ uint32_t tVehicleId = nVehicleId;
+ bool tCheckOwner = nCheckOwner;
+ uint32_t tOwnerId = nOwnerId;
+ return true; // tmp
+}
+
+PSpawnedVehicle* PVehicles::GetSpawnedVehicle( uint32_t nVehicleId ) const
+{
+ PSpawnedVhcMap::const_iterator it = mSpawnedVehicles.find( nVehicleId );
+ if ( it != mSpawnedVehicles.end() )
+ {
+ return ( it->second );
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+bool PVehicles::GetVehicleInfo( uint32_t nVehicleId, PVehicleInformation* nInfo ) const
+{
+ PSpawnedVehicle* tVhc = GetSpawnedVehicle( nVehicleId );
+ if ( tVhc )
+ {
+ *nInfo = tVhc->GetInformation();
+ return true;
+ }
+ else
+ {
+ return nInfo->Load( nVehicleId );
+ }
+}
+
+PVhcInfoList* PVehicles::GetCharVehicles( uint32_t nCharId, uint16_t nMaxCount, uint16_t nStartIndex )
+{
+ PVhcInfoList* Entries = new PVhcInfoList();
+ PVehicleInformation* InfoEntry;
+ // Tmp implementation
+ uint16_t LimitIndex = nStartIndex + nMaxCount;
+ if ( !nMaxCount || ( VhcTypesNum < LimitIndex ) )
+ {
+ LimitIndex = VhcTypesNum;
+ }
+
+ for ( uint16_t i = nStartIndex; ( i < LimitIndex ) ; ++i )
+ {
+ InfoEntry = new PVehicleInformation();
+ if ( GetVehicleInfo( nCharId * 100 + VhcTypes[i], InfoEntry ) )
+ {
+ Entries->push( InfoEntry );
+ }
+ else
+ {
+ delete InfoEntry;
+ }
+ }
+
+ return Entries;
+}
+
+PSpawnedVehicle* PVehicles::SpawnVehicle( uint32_t nVehicleId, uint32_t nLocation, PVhcCoordinates const* nVhcPos )
+{
+ PSpawnedVehicle* newVhc = NULL;
+ PWorld* cWorld;
+ PVehicleInformation nVhcInfo;
+
+ if (( nLocation != PWorlds::mNcSubwayWorldId ) && IsValidVehicle( nVehicleId ) && !IsSpawned( nVehicleId ) )
+ {
+ cWorld = Worlds->LeaseWorld( nLocation );
+
+ if ( cWorld && GetVehicleInfo( nVehicleId, &nVhcInfo ) )
+ {
+ newVhc = cWorld->GetSpawnedVehicles()->SpawnVehicle( &nVhcInfo, nVhcPos );
+ if ( newVhc )
+ {
+ if ( !RegisterSpawnedVehicle( newVhc ) )
+ {
+ Console->Print( RED, BLACK, "[Error] PVehicles::SpawnVehicle : Could not register spawned vhc" );
+ }
+ if( gDevDebug )
+ Console->Print( "%d Spawned vhc %d (local 0x%04x) type %d (requested: %d)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), newVhc->GetVehicleId(), newVhc->GetLocalId(), newVhc->GetInformation().GetVehicleType(), nVhcInfo.GetVehicleType() );
+ }
+ else
+ Console->Print( RED, BLACK, "[Error] PVehicles::SpawnVehicle : Could not create vhc" );
+ }
+
+ Worlds->ReleaseWorld( nLocation );
+ }
+
+ return newVhc;
+}
+
+bool PVehicles::UnspawnVehicle( uint32_t nVehicleId )
+{
+ PWorld* cWorld;
+ bool Result = false;
+
+ PSpawnedVhcMap::iterator it = mSpawnedVehicles.find( nVehicleId );
+ if ( it != mSpawnedVehicles.end() )
+ {
+ cWorld = Worlds->LeaseWorld( it->second->GetLocation() );
+
+ if ( cWorld )
+ {
+ if ( !it->second->Save() )
+ {
+ Console->Print( RED, BLACK, "[Error] PVehicles::UnspawnVehicle : Could not save vhc %d", nVehicleId );
+ }
+
+ Result = cWorld->GetSpawnedVehicles()->UnspawnVehicle( it->second->GetLocalId() );
+ if ( Result )
+ {
+ if ( !UnregisterSpawnedVehicle( nVehicleId ) )
+ {
+ Console->Print( RED, BLACK, "[Error] PVehicles::UnspawnVehicle : Could not unregister vhc %d", nVehicleId );
+ }
+ }
+ }
+
+ Worlds->ReleaseWorld( it->second->GetLocation() );
+ }
+
+ return Result;
+}
+
+//PSpawnedVehicles
+PSpawnedVehicles::PSpawnedVehicles()
+{
+ mNextFreeHint = 0;
+ mLocation = 0;
+}
+
+PSpawnedVehicles::~PSpawnedVehicles()
+{
+
+}
+
+PSpawnedVehicle* PSpawnedVehicles::SpawnVehicle( PVehicleInformation const* nVhcInfo, PVhcCoordinates const* nVhcPos )
+{
+ PSpawnedVehicle* newVhc = NULL;
+ uint32_t nSize;
+
+ if ( nVhcInfo->GetStatus() == 0 ) // only if in garage
+ {
+ nSize = mSpawnedVehicles.size();
+ while (( mNextFreeHint < nSize ) && mSpawnedVehicles[mNextFreeHint] )
+ {
+ ++mNextFreeHint;
+ }
+ if ( mNextFreeHint > nSize )
+ {
+ mNextFreeHint = nSize;
+ }
+ if ( mNextFreeHint == nSize )
+ {
+ mSpawnedVehicles.push_back( static_cast<PSpawnedVehicle *>(NULL) );
+ }
+
+ if ( mNextFreeHint < mMaxLocalVhc )
+ {
+ newVhc = new PSpawnedVehicle( mVhcBaseLocalId - mNextFreeHint, nVhcInfo, mLocation, nVhcPos );
+ mSpawnedVehicles[mNextFreeHint++] = newVhc;
+ newVhc->SetStatus( 1 );
+ }
+ }
+
+ return newVhc;
+}
+
+PSpawnedVehicle* PSpawnedVehicles::GetVehicle( uint32_t nLocalId )
+{
+ if (( nLocalId <= mVhcBaseLocalId ) && ( nLocalId > ( mVhcBaseLocalId - mSpawnedVehicles.size() ) ) )
+ {
+ return mSpawnedVehicles[mVhcBaseLocalId - nLocalId];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+PSpawnedVehicle* PSpawnedVehicles::GetVehicleByGlobalId( uint32_t nVehicleId ) const
+{
+ for ( PSpawnedVhcVector::const_iterator it = mSpawnedVehicles.begin(); it != mSpawnedVehicles.end(); it++ )
+ {
+ if (( *it )->GetVehicleId() == nVehicleId )
+ {
+ return ( *it );
+ }
+ }
+
+ return NULL;
+}
+
+bool PSpawnedVehicles::UnspawnVehicle( uint32_t nLocalId )
+{
+ uint16_t Index;
+ PSpawnedVehicle* tVhc;
+
+ if (( nLocalId <= mVhcBaseLocalId ) && ( nLocalId > ( mVhcBaseLocalId - mSpawnedVehicles.size() ) ) )
+ {
+ Index = mVhcBaseLocalId - nLocalId;
+ tVhc = mSpawnedVehicles[Index];
+ if ( tVhc )
+ {
+ if ( tVhc->GetInformation().GetStatus() != 2 )
+ {
+ tVhc->SetStatus( 0 );
+ }
+ delete tVhc;
+ mSpawnedVehicles[Index] = NULL;
+ if ( mNextFreeHint > Index )
+ {
+ mNextFreeHint = Index;
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+PSpawnedVhcList* PSpawnedVehicles::GetSpawnedVehicles() const
+{
+ PSpawnedVhcList* Entries = new PSpawnedVhcList();
+
+ for ( PSpawnedVhcVector::const_iterator i = mSpawnedVehicles.begin(); i != mSpawnedVehicles.end(); ++i )
+ {
+ if ( *i )
+ {
+ Entries->push( *i );
+ }
+ }
+
+ return Entries;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <map>\r
-#include <queue>\r
-#include <vector>\r
-\r
-class PDefVhc;\r
-\r
-class PVhcCoordinates {\r
- friend class PSpawnedVehicle;\r
-\r
- private:\r
- uint16_t mY; // Y-Position in world\r
- uint16_t mZ; // Z-Position in world\r
- uint16_t mX; // X-Position in world\r
- uint8_t mUD; // Up - Mid - Down (d6 - 80 - 2a) // Pitch\r
- uint16_t mLR; // Yaw\r
- uint16_t mRoll;\r
- uint16_t mUnknown; // Usually 0x0001\r
- uint8_t mFF; // Usually 0xff ...\r
- uint8_t mAct; // Last user action state\r
- // mAct: bit field\r
- //0x00 = not moving\r
- //0x01 = Left\r
- //0x02 = Right\r
- //0x04 = Forward\r
- //0x08 = Back\r
- //0x20 = Pushing down\r
- //0x40 = Pulling up\r
-\r
- public:\r
- inline PVhcCoordinates() { mX = mY = mZ = mAct = 0; mUD = 128; mLR = 34683; mRoll = 32403;}\r
-\r
- void SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD, uint16_t nLR, uint16_t nRoll, uint8_t nAct = 0, uint16_t nUnknown = 1, uint8_t nFF = 0xff );\r
- void SetInterpolate( const PVhcCoordinates& Pos1, const PVhcCoordinates& Pos2, float nCoef );\r
- inline uint16_t GetX() const { return mX; }\r
- inline uint16_t GetY() const { return mY; }\r
- inline uint16_t GetZ() const { return mZ; }\r
- inline uint8_t GetUD() const { return mUD; }\r
- inline uint16_t GetLR() const { return mLR; }\r
- inline uint16_t GetRoll() const { return mRoll; }\r
- inline uint8_t GetAct() const { return mAct; }\r
- inline uint8_t GetUnknown() const { return mUnknown; }\r
- inline uint8_t GetFF() const { return mFF; }\r
-};\r
-\r
-class PVehicleInformation\r
-{\r
- friend class PSpawnedVehicle;\r
- friend class PVehicles;\r
-\r
- private:\r
- uint32_t mVehicleId;\r
- uint32_t mOwnerCharId;\r
- uint32_t mHealth; // or float ???\r
- uint8_t mVehicleType;\r
- uint8_t mStatus; //vhcStatus 0:parking, 1:in_service, 2:destroyed\r
-\r
- public:\r
- inline PVehicleInformation( uint32_t nVehicleId = 0, uint32_t nOwnerCharId = 0, uint32_t nHealth = 0, uint8_t nVehicleType = 0, uint8_t nStatus = 0 ) :\r
- mVehicleId( nVehicleId ),\r
- mOwnerCharId( nOwnerCharId ),\r
- mHealth( nHealth ),\r
- mVehicleType( nVehicleType ),\r
- mStatus( nStatus )\r
- { }\r
-\r
- inline uint32_t GetVehicleId() const { return mVehicleId; }\r
- inline uint32_t GetOwnerCharId() const { return mOwnerCharId; }\r
- inline uint32_t GetHealth() const { return mHealth; } // or float ???\r
- inline uint8_t GetVehicleType() const { return mVehicleType; }\r
- inline uint8_t GetStatus() const { return mStatus; }\r
- bool SetStatus( uint8_t nStatus );\r
-\r
- bool Load( uint32_t nVehicleId );\r
- bool Save();\r
- bool Destroy();\r
-};\r
-\r
-class PSpawnedVehicle\r
-{\r
- private:\r
- static const uint8_t mSeatsFlags[];\r
-\r
- private:\r
- uint32_t mLocalId;\r
- PVehicleInformation mInfo;\r
- uint32_t mLocation;\r
- PVhcCoordinates mCoords;\r
- const PDefVhc* mVhcDef;\r
-\r
- uint32_t mSeatUserId[8];\r
- uint8_t mFreeSeatsFlags;\r
- uint8_t mNbFreeSeats;\r
-\r
- uint16_t minmax[4][2]; //Temp\r
-\r
- public:\r
- PSpawnedVehicle( uint32_t nLocalId, PVehicleInformation const* nVhcInfo, uint32_t nLocation, PVhcCoordinates const* nVhcPos );\r
-\r
- inline uint32_t GetVehicleId() const { return mInfo.mVehicleId; }\r
- inline uint32_t GetLocalId() const { return mLocalId; }\r
- inline const PVhcCoordinates& GetPosition() const { return mCoords; }\r
- inline const PVehicleInformation& GetInformation() const { return mInfo; }\r
- inline bool SetStatus( uint8_t nStatus ) { return mInfo.SetStatus( nStatus ); }\r
-\r
- void SetLocation( uint32_t nLocation );\r
- inline uint32_t GetLocation() const { return mLocation; }\r
- void SetPosition( PVhcCoordinates const* nVhcPos );\r
-\r
- inline bool Save() { return mInfo.Save(); }\r
-\r
- int GetNumSeats() const;\r
- inline uint32_t GetSeatUser( uint8_t nSeatId ) const { return (( nSeatId < 8 ) ? mSeatUserId[nSeatId] : 0 ); }\r
- bool SetSeatUser( uint8_t nSeatId, uint32_t nCharId );\r
- bool UnsetSeatUser( uint8_t nSeatId, uint32_t nCharId );\r
- bool IsCharInside( uint32_t nCharId ) const;\r
- inline uint8_t GetFreeSeatsFlags() const { return mFreeSeatsFlags; }\r
- inline uint8_t GetNbFreeSeats() const { return mNbFreeSeats; }\r
- uint8_t GetFirstFreeSeat() const;\r
-\r
- //SetHealth(const uint32_t nHealth);\r
- //uint32_t DoDamage(const uint32_t nHealthDec);\r
- //uint32_t DoRepair(const uint32_t nHealthInc);\r
-};\r
-\r
-typedef std::map<uint32_t, PSpawnedVehicle*> PSpawnedVhcMap;\r
-typedef std::queue<PVehicleInformation*> PVhcInfoList;\r
-class PVehicles\r
-{\r
- private:\r
- PSpawnedVhcMap mSpawnedVehicles;\r
-\r
- bool RegisterSpawnedVehicle( PSpawnedVehicle* nSpawnedVehicle );\r
- bool UnregisterSpawnedVehicle( uint32_t nVehicleId );\r
-\r
- public:\r
- PVehicles();\r
- ~PVehicles();\r
-\r
- //uint32_t CreateVehicle(uint32_t nOwnerChar, uint8_t mVehicleType);\r
- //bool RegisterVehicleOwner(uint32_t nVehiculeId, uint32_t nOwnerChar);\r
- //bool DestroyVehicle(uint32_t nVehiculeId);\r
- bool IsValidVehicle( uint32_t nVehicleId, bool nCheckOwner = false, uint32_t nOwnerId = 0 ) const;\r
- inline bool IsSpawned( uint32_t nVehicleId ) const { return ( mSpawnedVehicles.find( nVehicleId ) != mSpawnedVehicles.end() ); }\r
- PSpawnedVehicle* GetSpawnedVehicle( uint32_t nVehicleId ) const;\r
- bool GetVehicleInfo( uint32_t nVehicleId, PVehicleInformation* nInfo ) const;\r
- PSpawnedVehicle* SpawnVehicle( uint32_t nVehicleId, uint32_t nLocation, PVhcCoordinates const* nVhcPos ); // Refuses for subway zone atm\r
- bool UnspawnVehicle( uint32_t nVehicleId );\r
-\r
- PVhcInfoList* GetCharVehicles( uint32_t nCharId, uint16_t nMaxCount = 0, uint16_t nStartIndex = 0 );\r
-\r
-};\r
-\r
-typedef std::vector<PSpawnedVehicle*> PSpawnedVhcVector;\r
-typedef std::queue<PSpawnedVehicle*> PSpawnedVhcList;\r
-\r
-class PSpawnedVehicles\r
-{\r
- friend class PWorld;\r
-\r
- public:\r
- static const uint32_t mVhcBaseLocalId = 0x03fd; //Vhc local Id are allocated downward from this value. Could br 0x3ff, but 0x3fe is used as "target" when shooting nowhere\r
- static const uint16_t mMaxLocalVhc = 127;\r
-\r
- inline static bool IsPotentialSpawnedVehicle( uint32_t nLocalId )\r
- { return (( nLocalId <= mVhcBaseLocalId ) && (( mVhcBaseLocalId - nLocalId ) < mMaxLocalVhc ) ); }\r
-\r
- private:\r
- PSpawnedVhcVector mSpawnedVehicles;\r
- uint16_t mNextFreeHint;\r
- uint32_t mLocation;\r
-\r
- inline void SetLocation( uint32_t nLocation ) { mLocation = nLocation; }\r
-\r
- public:\r
- PSpawnedVehicles();\r
- ~PSpawnedVehicles();\r
-\r
- inline bool IsSpawned( uint32_t nLocalId ) const { return (( nLocalId <= mVhcBaseLocalId ) && (( mVhcBaseLocalId - nLocalId ) < mSpawnedVehicles.size() ) && mSpawnedVehicles[mVhcBaseLocalId-nLocalId] ); }\r
- PSpawnedVehicle* SpawnVehicle( PVehicleInformation const* nVhcInfo, PVhcCoordinates const* nVhcPos );\r
- PSpawnedVehicle* GetVehicle( uint32_t nLocalId );\r
- PSpawnedVehicle* GetVehicleByGlobalId( uint32_t nVehicleId ) const;\r
- bool UnspawnVehicle( uint32_t nVehicleId );\r
-\r
- PSpawnedVhcList* GetSpawnedVehicles() const;\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <map>
+#include <queue>
+#include <vector>
+
+class PDefVhc;
+
+class PVhcCoordinates {
+ friend class PSpawnedVehicle;
+
+ private:
+ uint16_t mY; // Y-Position in world
+ uint16_t mZ; // Z-Position in world
+ uint16_t mX; // X-Position in world
+ uint8_t mUD; // Up - Mid - Down (d6 - 80 - 2a) // Pitch
+ uint16_t mLR; // Yaw
+ uint16_t mRoll;
+ uint16_t mUnknown; // Usually 0x0001
+ uint8_t mFF; // Usually 0xff ...
+ uint8_t mAct; // Last user action state
+ // mAct: bit field
+ //0x00 = not moving
+ //0x01 = Left
+ //0x02 = Right
+ //0x04 = Forward
+ //0x08 = Back
+ //0x20 = Pushing down
+ //0x40 = Pulling up
+
+ public:
+ inline PVhcCoordinates() { mX = mY = mZ = mAct = 0; mUD = 128; mLR = 34683; mRoll = 32403;}
+
+ void SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD, uint16_t nLR, uint16_t nRoll, uint8_t nAct = 0, uint16_t nUnknown = 1, uint8_t nFF = 0xff );
+ void SetInterpolate( const PVhcCoordinates& Pos1, const PVhcCoordinates& Pos2, float nCoef );
+ inline uint16_t GetX() const { return mX; }
+ inline uint16_t GetY() const { return mY; }
+ inline uint16_t GetZ() const { return mZ; }
+ inline uint8_t GetUD() const { return mUD; }
+ inline uint16_t GetLR() const { return mLR; }
+ inline uint16_t GetRoll() const { return mRoll; }
+ inline uint8_t GetAct() const { return mAct; }
+ inline uint8_t GetUnknown() const { return mUnknown; }
+ inline uint8_t GetFF() const { return mFF; }
+};
+
+class PVehicleInformation
+{
+ friend class PSpawnedVehicle;
+ friend class PVehicles;
+
+ private:
+ uint32_t mVehicleId;
+ uint32_t mOwnerCharId;
+ uint32_t mHealth; // or float ???
+ uint8_t mVehicleType;
+ uint8_t mStatus; //vhcStatus 0:parking, 1:in_service, 2:destroyed
+
+ public:
+ inline PVehicleInformation( uint32_t nVehicleId = 0, uint32_t nOwnerCharId = 0, uint32_t nHealth = 0, uint8_t nVehicleType = 0, uint8_t nStatus = 0 ) :
+ mVehicleId( nVehicleId ),
+ mOwnerCharId( nOwnerCharId ),
+ mHealth( nHealth ),
+ mVehicleType( nVehicleType ),
+ mStatus( nStatus )
+ { }
+
+ inline uint32_t GetVehicleId() const { return mVehicleId; }
+ inline uint32_t GetOwnerCharId() const { return mOwnerCharId; }
+ inline uint32_t GetHealth() const { return mHealth; } // or float ???
+ inline uint8_t GetVehicleType() const { return mVehicleType; }
+ inline uint8_t GetStatus() const { return mStatus; }
+ bool SetStatus( uint8_t nStatus );
+
+ bool Load( uint32_t nVehicleId );
+ bool Save();
+ bool Destroy();
+};
+
+class PSpawnedVehicle
+{
+ private:
+ static const uint8_t mSeatsFlags[];
+
+ private:
+ uint32_t mLocalId;
+ PVehicleInformation mInfo;
+ uint32_t mLocation;
+ PVhcCoordinates mCoords;
+ const PDefVhc* mVhcDef;
+
+ uint32_t mSeatUserId[8];
+ uint8_t mFreeSeatsFlags;
+ uint8_t mNbFreeSeats;
+
+ uint16_t minmax[4][2]; //Temp
+
+ public:
+ PSpawnedVehicle( uint32_t nLocalId, PVehicleInformation const* nVhcInfo, uint32_t nLocation, PVhcCoordinates const* nVhcPos );
+
+ inline uint32_t GetVehicleId() const { return mInfo.mVehicleId; }
+ inline uint32_t GetLocalId() const { return mLocalId; }
+ inline const PVhcCoordinates& GetPosition() const { return mCoords; }
+ inline const PVehicleInformation& GetInformation() const { return mInfo; }
+ inline bool SetStatus( uint8_t nStatus ) { return mInfo.SetStatus( nStatus ); }
+
+ void SetLocation( uint32_t nLocation );
+ inline uint32_t GetLocation() const { return mLocation; }
+ void SetPosition( PVhcCoordinates const* nVhcPos );
+
+ inline bool Save() { return mInfo.Save(); }
+
+ int GetNumSeats() const;
+ inline uint32_t GetSeatUser( uint8_t nSeatId ) const { return (( nSeatId < 8 ) ? mSeatUserId[nSeatId] : 0 ); }
+ bool SetSeatUser( uint8_t nSeatId, uint32_t nCharId );
+ bool UnsetSeatUser( uint8_t nSeatId, uint32_t nCharId );
+ bool IsCharInside( uint32_t nCharId ) const;
+ inline uint8_t GetFreeSeatsFlags() const { return mFreeSeatsFlags; }
+ inline uint8_t GetNbFreeSeats() const { return mNbFreeSeats; }
+ uint8_t GetFirstFreeSeat() const;
+
+ //SetHealth(const uint32_t nHealth);
+ //uint32_t DoDamage(const uint32_t nHealthDec);
+ //uint32_t DoRepair(const uint32_t nHealthInc);
+};
+
+typedef std::map<uint32_t, PSpawnedVehicle*> PSpawnedVhcMap;
+typedef std::queue<PVehicleInformation*> PVhcInfoList;
+class PVehicles
+{
+ private:
+ PSpawnedVhcMap mSpawnedVehicles;
+
+ bool RegisterSpawnedVehicle( PSpawnedVehicle* nSpawnedVehicle );
+ bool UnregisterSpawnedVehicle( uint32_t nVehicleId );
+
+ public:
+ PVehicles();
+ ~PVehicles();
+
+ //uint32_t CreateVehicle(uint32_t nOwnerChar, uint8_t mVehicleType);
+ //bool RegisterVehicleOwner(uint32_t nVehiculeId, uint32_t nOwnerChar);
+ //bool DestroyVehicle(uint32_t nVehiculeId);
+ bool IsValidVehicle( uint32_t nVehicleId, bool nCheckOwner = false, uint32_t nOwnerId = 0 ) const;
+ inline bool IsSpawned( uint32_t nVehicleId ) const { return ( mSpawnedVehicles.find( nVehicleId ) != mSpawnedVehicles.end() ); }
+ PSpawnedVehicle* GetSpawnedVehicle( uint32_t nVehicleId ) const;
+ bool GetVehicleInfo( uint32_t nVehicleId, PVehicleInformation* nInfo ) const;
+ PSpawnedVehicle* SpawnVehicle( uint32_t nVehicleId, uint32_t nLocation, PVhcCoordinates const* nVhcPos ); // Refuses for subway zone atm
+ bool UnspawnVehicle( uint32_t nVehicleId );
+
+ PVhcInfoList* GetCharVehicles( uint32_t nCharId, uint16_t nMaxCount = 0, uint16_t nStartIndex = 0 );
+
+};
+
+typedef std::vector<PSpawnedVehicle*> PSpawnedVhcVector;
+typedef std::queue<PSpawnedVehicle*> PSpawnedVhcList;
+
+class PSpawnedVehicles
+{
+ friend class PWorld;
+
+ public:
+ static const uint32_t mVhcBaseLocalId = 0x03fd; //Vhc local Id are allocated downward from this value. Could br 0x3ff, but 0x3fe is used as "target" when shooting nowhere
+ static const uint16_t mMaxLocalVhc = 127;
+
+ inline static bool IsPotentialSpawnedVehicle( uint32_t nLocalId )
+ { return (( nLocalId <= mVhcBaseLocalId ) && (( mVhcBaseLocalId - nLocalId ) < mMaxLocalVhc ) ); }
+
+ private:
+ PSpawnedVhcVector mSpawnedVehicles;
+ uint16_t mNextFreeHint;
+ uint32_t mLocation;
+
+ inline void SetLocation( uint32_t nLocation ) { mLocation = nLocation; }
+
+ public:
+ PSpawnedVehicles();
+ ~PSpawnedVehicles();
+
+ inline bool IsSpawned( uint32_t nLocalId ) const { return (( nLocalId <= mVhcBaseLocalId ) && (( mVhcBaseLocalId - nLocalId ) < mSpawnedVehicles.size() ) && mSpawnedVehicles[mVhcBaseLocalId-nLocalId] ); }
+ PSpawnedVehicle* SpawnVehicle( PVehicleInformation const* nVhcInfo, PVhcCoordinates const* nVhcPos );
+ PSpawnedVehicle* GetVehicle( uint32_t nLocalId );
+ PSpawnedVehicle* GetVehicleByGlobalId( uint32_t nVehicleId ) const;
+ bool UnspawnVehicle( uint32_t nVehicleId );
+
+ PSpawnedVhcList* GetSpawnedVehicles() const;
+};
-#pragma once\r
-\r
-#include <cstdint>\r
-\r
-class PClient;\r
-\r
-/*\r
-Current known WorldActors:\r
-\r
-- Furniture\r
-1 Door\r
-2 Wooden Door\r
-3 Tech Door\r
-5 Lift\r
-6 Shutter\r
-9 Airlock\r
-10 Chair\r
-11 Wooden Chair\r
-12 Bench\r
-13 Table\r
-14 Recreation Unit\r
-\r
-- Interactions\r
-21 Gen rep\r
-22 Go Guardian\r
-99 Outfitter\r
-23/29 Venture Warp\r
-90 City Com\r
-98 Home term\r
-104 Home term\r
-160-195 Hack term\r
-900 Carport Term\r
-\r
-- Cabinets\r
-150 Cabinet\r
-101 Secure Cabinet\r
-105 Safe\r
-106 High Security Safe\r
-\r
-- Hack Boxes\r
-700 Light Weapon Box\r
-703 Medium\r
-720 Ammo Box\r
-740 Armour Box\r
-750 Equipment Box\r
-780 Psi Box\r
-\r
-- Containers\r
-134 Old Bag\r
-120 Trashcan\r
-125 Old Bag\r
-126 Mutant Cooking Pot\r
-127 Rotten Box\r
-128 Rusty Box\r
-133 Steel Box\r
-130 Bunch of Bones\r
-136 Dead Technician (Loot)\r
-137 Corpse (Loot)\r
-\r
-- Others\r
-131 Pile of Stones\r
-8 Rock\r
-510 Tree Trunk\r
-790 Burning Barrel\r
-800 Explosive Barrel\r
-\r
-- Costs\r
-15 Pay 20nc\r
-16 Pay 50nc\r
-17 Pay 100nc\r
-18 Pay 150nc\r
-19 Pay 200nc\r
-20 Pay 500nc\r
-\r
-*/\r
-\r
-// Start from this offset (00 00 80 00)\r
-#define DYNACTORIDSTART 8388608\r
-\r
-class PWorldActors {\r
- private:\r
- // SQL Layout\r
- enum\r
- {\r
- wa_id,\r
- wa_actor_id,\r
- wa_actor_map,\r
- wa_actor_model,\r
- wa_actor_type,\r
- wa_posX,\r
- wa_posY,\r
- wa_posZ,\r
- wa_rotX,\r
- wa_rotY,\r
- wa_rotZ,\r
- wa_option1,\r
- wa_option2,\r
- wa_option3\r
- };\r
-\r
- void SpawnWA(uint32_t nWorld, uint16_t nActorID, uint16_t nFunctionID, uint32_t nWOID, uint16_t nPosX, uint16_t nPosY, uint16_t nPosZ, uint8_t nRotX, uint8_t nRotY, uint8_t nRotZ);\r
- void VanishWA(uint32_t nWorld, uint32_t nWAid);\r
-\r
- // Get next availeable WorldactorID. First, try to find ID in known .dat files, then\r
- // Get the currently highest ID from SQL and add +1\r
- // select distinct wi_worlditem_id from world_items order by wi_worlditem_id desc limit 1;\r
- uint32_t GetNextFreeWAID();\r
-\r
- public:\r
- PWorldActors();\r
- ~PWorldActors();\r
-\r
- // Sends initial zone setup to client (after zoning-in)\r
- void InitWorld(PClient* nClient);\r
-\r
- // Add new worldactor to database and spawn it. Returns created WorldID\r
- // Position is taken from nClient, same as the worldID and calls the mainfunction\r
- // The function values are optional (used for interactive objects, gogo or genrep)\r
- uint32_t AddWorldActor(PClient* nClient, uint16_t nActorID, uint16_t nFuncID, uint16_t nOpt1 = 0, uint16_t nOpt2 = 0, uint16_t nOpt3 = 0);\r
-\r
- // Add new worldactor to database and spawn it. Returns created WorldID\r
- // The function values are optional (used for interactive objects, gogo or genrep)\r
- uint32_t AddWorldActor(uint32_t nWorldID, uint16_t nActorID, uint16_t nFuncID, uint16_t nPosX, uint16_t nPosY, uint16_t nPosZ, uint8_t nRotX, uint8_t nRotY, uint8_t nRotZ, uint16_t nOpt1 = 0, uint16_t nOpt2 = 0, uint16_t nOpt3 = 0);\r
-\r
- // Remove worldactor in given world from SQL and game\r
- void DelWorldActor(PClient* nClient, uint32_t nWAid);\r
-\r
- // Get functionvalues for worldactor\r
- void GetWAoption(uint32_t nWAid, uint16_t nWorld, uint16_t &nValue1, uint16_t &nValue2, uint16_t &nValue3);\r
-\r
- // Get SQL ID from world and worldID\r
- int GetWASQLID(uint32_t nWAid, uint32_t nWorld);\r
-\r
- // Check if actorID is dynamic\r
- bool IsDynamicActor(uint32_t nWAid);\r
-\r
- // Not needed. Better re-spawn the actor\r
- //bool EditWorldActor(uint32_t nWorldID, int nOption1 = -1, int nOption2 = -1, int nOption3 = -1);\r
-\r
- int GetWorldActorFunctionID(uint32_t nWAid);\r
-\r
- void GetFrontPos(uint32_t nWAID, uint16_t* mX, uint16_t* mY, uint16_t* mZ); // For chairs\r
- int GetLinkedObjectID(uint32_t nWAID); // OptionValue 1 is used for linked object!\r
-\r
- // Check if given functionID does exist\r
- bool IsValidWAFunction(int nFunctionID);\r
-\r
- // Checks if this functionID required an linked object or not\r
- bool RequiresLinkedObject(int nFunctionID);\r
-\r
- // Checks if the given worldobjectID is valid for this type of functionID\r
- bool IsValidLinkedObject(PClient *nClient, uint16_t nOption1, int nFunctionID);\r
-\r
- // Checks for double actor-IDs and deletes them from DB\r
- void DoActorCheck();\r
-};\r
+#pragma once
+
+#include <cstdint>
+
+class PClient;
+
+/*
+Current known WorldActors:
+
+- Furniture
+1 Door
+2 Wooden Door
+3 Tech Door
+5 Lift
+6 Shutter
+9 Airlock
+10 Chair
+11 Wooden Chair
+12 Bench
+13 Table
+14 Recreation Unit
+
+- Interactions
+21 Gen rep
+22 Go Guardian
+99 Outfitter
+23/29 Venture Warp
+90 City Com
+98 Home term
+104 Home term
+160-195 Hack term
+900 Carport Term
+
+- Cabinets
+150 Cabinet
+101 Secure Cabinet
+105 Safe
+106 High Security Safe
+
+- Hack Boxes
+700 Light Weapon Box
+703 Medium
+720 Ammo Box
+740 Armour Box
+750 Equipment Box
+780 Psi Box
+
+- Containers
+134 Old Bag
+120 Trashcan
+125 Old Bag
+126 Mutant Cooking Pot
+127 Rotten Box
+128 Rusty Box
+133 Steel Box
+130 Bunch of Bones
+136 Dead Technician (Loot)
+137 Corpse (Loot)
+
+- Others
+131 Pile of Stones
+8 Rock
+510 Tree Trunk
+790 Burning Barrel
+800 Explosive Barrel
+
+- Costs
+15 Pay 20nc
+16 Pay 50nc
+17 Pay 100nc
+18 Pay 150nc
+19 Pay 200nc
+20 Pay 500nc
+
+*/
+
+// Start from this offset (00 00 80 00)
+#define DYNACTORIDSTART 8388608
+
+class PWorldActors {
+ private:
+ // SQL Layout
+ enum
+ {
+ wa_id,
+ wa_actor_id,
+ wa_actor_map,
+ wa_actor_model,
+ wa_actor_type,
+ wa_posX,
+ wa_posY,
+ wa_posZ,
+ wa_rotX,
+ wa_rotY,
+ wa_rotZ,
+ wa_option1,
+ wa_option2,
+ wa_option3
+ };
+
+ void SpawnWA(uint32_t nWorld, uint16_t nActorID, uint16_t nFunctionID, uint32_t nWOID, uint16_t nPosX, uint16_t nPosY, uint16_t nPosZ, uint8_t nRotX, uint8_t nRotY, uint8_t nRotZ);
+ void VanishWA(uint32_t nWorld, uint32_t nWAid);
+
+ // Get next availeable WorldactorID. First, try to find ID in known .dat files, then
+ // Get the currently highest ID from SQL and add +1
+ // select distinct wi_worlditem_id from world_items order by wi_worlditem_id desc limit 1;
+ uint32_t GetNextFreeWAID();
+
+ public:
+ PWorldActors();
+ ~PWorldActors();
+
+ // Sends initial zone setup to client (after zoning-in)
+ void InitWorld(PClient* nClient);
+
+ // Add new worldactor to database and spawn it. Returns created WorldID
+ // Position is taken from nClient, same as the worldID and calls the mainfunction
+ // The function values are optional (used for interactive objects, gogo or genrep)
+ uint32_t AddWorldActor(PClient* nClient, uint16_t nActorID, uint16_t nFuncID, uint16_t nOpt1 = 0, uint16_t nOpt2 = 0, uint16_t nOpt3 = 0);
+
+ // Add new worldactor to database and spawn it. Returns created WorldID
+ // The function values are optional (used for interactive objects, gogo or genrep)
+ uint32_t AddWorldActor(uint32_t nWorldID, uint16_t nActorID, uint16_t nFuncID, uint16_t nPosX, uint16_t nPosY, uint16_t nPosZ, uint8_t nRotX, uint8_t nRotY, uint8_t nRotZ, uint16_t nOpt1 = 0, uint16_t nOpt2 = 0, uint16_t nOpt3 = 0);
+
+ // Remove worldactor in given world from SQL and game
+ void DelWorldActor(PClient* nClient, uint32_t nWAid);
+
+ // Get functionvalues for worldactor
+ void GetWAoption(uint32_t nWAid, uint16_t nWorld, uint16_t &nValue1, uint16_t &nValue2, uint16_t &nValue3);
+
+ // Get SQL ID from world and worldID
+ int GetWASQLID(uint32_t nWAid, uint32_t nWorld);
+
+ // Check if actorID is dynamic
+ bool IsDynamicActor(uint32_t nWAid);
+
+ // Not needed. Better re-spawn the actor
+ //bool EditWorldActor(uint32_t nWorldID, int nOption1 = -1, int nOption2 = -1, int nOption3 = -1);
+
+ int GetWorldActorFunctionID(uint32_t nWAid);
+
+ void GetFrontPos(uint32_t nWAID, uint16_t* mX, uint16_t* mY, uint16_t* mZ); // For chairs
+ int GetLinkedObjectID(uint32_t nWAID); // OptionValue 1 is used for linked object!
+
+ // Check if given functionID does exist
+ bool IsValidWAFunction(int nFunctionID);
+
+ // Checks if this functionID required an linked object or not
+ bool RequiresLinkedObject(int nFunctionID);
+
+ // Checks if the given worldobjectID is valid for this type of functionID
+ bool IsValidLinkedObject(PClient *nClient, uint16_t nOption1, int nFunctionID);
+
+ // Checks for double actor-IDs and deletes them from DB
+ void DoActorCheck();
+};
-#include "GameServer/Includes.hxx"\r
-#include "GameServer/Definitions/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-PWorldDataTemplate::PWorldDataTemplate()\r
-{\r
- mUseCount = 0;\r
- for ( int i = 0; i < WORLDDATATEMPLATE_MAXPOSITEMS; ++i )\r
- {\r
- mPositionItems[i] = NULL;\r
- }\r
-}\r
-\r
-PWorldDataTemplate::~PWorldDataTemplate()\r
-{\r
- DatFileDataCleanup();\r
-}\r
-\r
-void PWorldDataTemplate::DatFileDataCleanup()\r
-{\r
- for ( PFurnitureItemsMap::iterator i = mFurnitureItems.begin(); i != mFurnitureItems.end(); i++ )\r
- delete i->second;\r
- for ( PDoorsMap::iterator i = mDoors.begin(); i != mDoors.end(); i++ )\r
- delete i->second;\r
- for ( PNPCsMap::iterator i = mNPCs.begin(); i != mNPCs.end(); i++ )\r
- delete i->second;\r
-}\r
-\r
-bool PWorldDataTemplate::LoadDatFile( const std::string& WorldTemplateName, const std::string& nFilename, const bool nTestAccesOnly )\r
-{\r
- PWorldDatParser WDatLoader;\r
- int LoadResult;\r
-\r
- DatFileDataCleanup();\r
- if ( gDevDebug ) Console->Print( "%s Loading %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nFilename.c_str() );\r
- LoadResult = WDatLoader.LoadDatFile( nFilename, this, true, nTestAccesOnly ) ; // We want to discard passive objects for now\r
- switch ( LoadResult )\r
- {\r
- case 0:\r
- {\r
- mName = nFilename;\r
- mBspName = WorldTemplateName;\r
- if ( !nTestAccesOnly )\r
- {\r
- SetLinkedObjects(); // temp until better solution found from .dat & .bsp files\r
- }\r
- return true;\r
- }\r
-\r
- case -1:\r
- {\r
- if ( !nTestAccesOnly )\r
- Console->Print( "%s Can't read file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), nFilename.c_str() );\r
- break;\r
- }\r
-\r
- case - 2:\r
- {\r
- Console->Print( "%s Bad data", Console->ColorText( RED, BLACK, "[ERROR]" ) );\r
- break;\r
- }\r
-\r
- case - 3:\r
- {\r
- Console->Print( "%s Unexpected end of file", Console->ColorText( RED, BLACK, "[ERROR]" ) );\r
- break;\r
- }\r
-\r
- default:\r
- Console->Print( "%s Unknown error %d", Console->ColorText( RED, BLACK, "[ERROR]" ), LoadResult );\r
- }\r
- return false;\r
-}\r
-\r
-uint32_t PWorldDataTemplate::AddFurnitureItem( PFurnitureItemTemplate* nItem )\r
-{\r
- if ( nItem )\r
- {\r
- if ( mFurnitureItems.insert( std::make_pair( nItem->GetID(), nItem ) ).second )\r
- {\r
- if ( gDevDebug ) Console->Print( "%s Furniture item %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nItem->GetID() );\r
-\r
- if ( nItem->GetFunctionType() == 21 )\r
- {\r
- int v = nItem->GetFunctionValue();\r
- if (( v >= 0 ) && ( v < WORLDDATATEMPLATE_MAXPOSITEMS ) )\r
- {\r
- if ( mPositionItems[v] )\r
- {\r
- if (( v == WORLDDATATEMPLATE_MAXPOSITEMS - 2 ) && !mPositionItems[v+1] ) // We allow that only for Pos 9 in order not to mess with other pos\r
- {\r
- Console->Print( "%s Same position %d for two position items ID %d and %d. Last one will be put on next position.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, mPositionItems[v]->GetID(), nItem->GetID() );\r
- ++v;\r
- }\r
- else\r
- {\r
- Console->Print( "%s Same position %d for two position items ID %d and %d. Only last one kept.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, mPositionItems[v]->GetID(), nItem->GetID() );\r
- }\r
- }\r
-\r
- mPositionItems[v] = nItem;\r
- /*\r
- Console->Print("Position entity %d (id 0x%x) added to world template", v, nItem->GetID());\r
- float fpX, fpY, fpZ;\r
- uint16_t pX, pY, pZ;\r
- nItem->GetPos(&fpX, &fpY, &fpZ);\r
- pX = (uint16_t) (fpX + 32000);\r
- pY = (uint16_t) (fpY + 32000);\r
- pZ = (uint16_t) (fpZ + 32000);\r
- Console->Print("Position Y=%f (0x%04x) Z=%f (0x%04x) X=%f (0x%04x)", fpY, pY, fpZ, pZ, fpX, pX);\r
- */\r
- }\r
- else\r
- {\r
- Console->Print( "%s Invalid position %d for position item ID %d. Position ignored.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, nItem->GetID() );\r
- }\r
- }\r
- return nItem->GetID();\r
- }\r
- else\r
- {\r
- Console->Print( "%s Duplicate furniture item ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nItem->GetID() );\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-const PFurnitureItemTemplate* PWorldDataTemplate::GetFurnitureItem( uint32_t ItemID )\r
-{\r
- PFurnitureItemsMap::const_iterator it = mFurnitureItems.find( ItemID );\r
- if ( it == mFurnitureItems.end() )\r
- return NULL;\r
- else\r
- return it->second;\r
-}\r
-\r
-bool PWorldDataTemplate::getPositionItemPosition( uint8_t PosID, float* pX, float* pY, float* pZ )\r
-{\r
- if (( PosID < WORLDDATATEMPLATE_MAXPOSITEMS ) && mPositionItems[PosID] )\r
- {\r
- mPositionItems[PosID]->GetPos( pX, pY, pZ ) ;\r
- return true;\r
- }\r
- return false;\r
-}\r
-\r
-uint32_t PWorldDataTemplate::AddDoor( PDoorTemplate* nDoor )\r
-{\r
- if ( nDoor )\r
- {\r
- if ( mDoors.insert( std::make_pair( nDoor->GetID(), nDoor ) ).second )\r
- {\r
- if ( gDevDebug ) Console->Print( "%s Door %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nDoor->GetID() );\r
- return nDoor->GetID();\r
- }\r
- else\r
- {\r
- Console->Print( "%s Duplicate Door ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nDoor->GetID() );\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-const PDoorTemplate* PWorldDataTemplate::GetDoor( uint32_t DoorID )\r
-{\r
- PDoorsMap::const_iterator it = mDoors.find( DoorID );\r
- if ( it == mDoors.end() )\r
- return NULL;\r
- else\r
- return it->second;\r
-}\r
-\r
-\r
-uint32_t PWorldDataTemplate::AddNPC( PNPCTemplate* nNPC )\r
-{\r
- if ( nNPC )\r
- {\r
- if ( mNPCs.insert( std::make_pair( nNPC->GetNpcID(), nNPC ) ).second )\r
- {\r
- if ( gDevDebug ) Console->Print( "%s NPC %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nNPC->GetNpcID() );\r
- return nNPC->GetNpcID();\r
- }\r
- else\r
- {\r
- Console->Print( "%s Duplicate NPC ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nNPC->GetNpcID() );\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-const PNPCTemplate* PWorldDataTemplate::GetNPC( uint32_t NPCID )\r
-{\r
- PNPCsMap::const_iterator it = mNPCs.find( NPCID );\r
- if ( it == mNPCs.end() )\r
- return NULL;\r
- else\r
- return it->second;\r
-}\r
-\r
-void PWorldDataTemplate::SetLinkedObjects()\r
-{\r
- float xI, yI, zI;\r
- float xD, yD, zD;\r
- float D2, minD2;\r
- uint32_t minObjID;\r
- uint16_t fnctType;\r
- uint16_t tGROrder = 0;\r
-\r
- for ( PFurnitureItemsMap::iterator it = mFurnitureItems.begin(); it != mFurnitureItems.end(); it++ )\r
- {\r
- fnctType = it->second->GetFunctionType();\r
- if (( fnctType == 11 ) || ( fnctType == 12 ) || ( fnctType == 13 ) || ( fnctType == 23 ) ) // if function is apt entry button, door access if, hack button or money button\r
- {\r
- it->second->GetPos( &xI, &yI, &zI );\r
-//Console->Print("Button pos: %0.0f %0.0f %0.0f", xI, yI, zI);\r
- minD2 = 1e9;\r
- minObjID = 0;\r
- for ( PDoorsMap::iterator dit = mDoors.begin(); dit != mDoors.end(); dit++ )\r
- {\r
-//Console->Print("%s Found door %d (%s) : %s triggered, %s", Console->ColorText(GREEN, BLACK, "[Debug]"), dit->first, dit->second->GetName().c_str(), (dit->second->IsTriggeredDoor()?"":"not"), (dit->second->IsDoubleDoor()?"double":"single") );\r
- if ( dit->second->IsTriggeredDoor() )\r
- {\r
- dit->second->GetPos( &xD, &yD, &zD );\r
-//Console->Print("Door pos: %0.0f %0.0f %0.0f", xD, yD, zD);\r
- D2 = ( xI - xD ) * ( xI - xD ) + ( yI - yD ) * ( yI - yD ) + ( zI - zD ) * ( zI - zD );\r
-//Console->Print("Dist D2:%0.0f minD2:%0.0f", D2, minD2);\r
- if ( D2 < minD2 )\r
- {\r
- minD2 = D2;\r
- minObjID = 1 + dit->first;\r
- }\r
- }\r
- }\r
- if ( minObjID-- )\r
- {\r
- it->second->SetLinkedObjectID( minObjID );\r
- if ( gDevDebug ) Console->Print( "%s Found triggered door %d (%s) for button %d (%s)", Console->ColorText( GREEN, BLACK, "[Debug]" ), minObjID, GetDoor( minObjID )->GetName().c_str(), it->first, it->second->GetName().c_str() );\r
-\r
- }\r
- else\r
- {\r
- Console->Print( "%s No triggered door found for button %d (%s) in World data template %s", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), it->first, it->second->GetName().c_str(), this->GetName().c_str() );\r
- }\r
- }\r
- else if ( fnctType == 6 ) // if function is genrep\r
- {\r
- it->second->SetLinkedObjectID( ++tGROrder );\r
- }\r
- }\r
-\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "GameServer/Definitions/Includes.hxx"
+#include "Common/Includes.hxx"
+
+PWorldDataTemplate::PWorldDataTemplate()
+{
+ mUseCount = 0;
+ for ( int i = 0; i < WORLDDATATEMPLATE_MAXPOSITEMS; ++i )
+ {
+ mPositionItems[i] = NULL;
+ }
+}
+
+PWorldDataTemplate::~PWorldDataTemplate()
+{
+ DatFileDataCleanup();
+}
+
+void PWorldDataTemplate::DatFileDataCleanup()
+{
+ for ( PFurnitureItemsMap::iterator i = mFurnitureItems.begin(); i != mFurnitureItems.end(); i++ )
+ delete i->second;
+ for ( PDoorsMap::iterator i = mDoors.begin(); i != mDoors.end(); i++ )
+ delete i->second;
+ for ( PNPCsMap::iterator i = mNPCs.begin(); i != mNPCs.end(); i++ )
+ delete i->second;
+}
+
+bool PWorldDataTemplate::LoadDatFile( const std::string& WorldTemplateName, const std::string& nFilename, const bool nTestAccesOnly )
+{
+ PWorldDatParser WDatLoader;
+ int LoadResult;
+
+ DatFileDataCleanup();
+ if ( gDevDebug ) Console->Print( "%s Loading %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nFilename.c_str() );
+ LoadResult = WDatLoader.LoadDatFile( nFilename, this, true, nTestAccesOnly ) ; // We want to discard passive objects for now
+ switch ( LoadResult )
+ {
+ case 0:
+ {
+ mName = nFilename;
+ mBspName = WorldTemplateName;
+ if ( !nTestAccesOnly )
+ {
+ SetLinkedObjects(); // temp until better solution found from .dat & .bsp files
+ }
+ return true;
+ }
+
+ case -1:
+ {
+ if ( !nTestAccesOnly )
+ Console->Print( "%s Can't read file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), nFilename.c_str() );
+ break;
+ }
+
+ case - 2:
+ {
+ Console->Print( "%s Bad data", Console->ColorText( RED, BLACK, "[ERROR]" ) );
+ break;
+ }
+
+ case - 3:
+ {
+ Console->Print( "%s Unexpected end of file", Console->ColorText( RED, BLACK, "[ERROR]" ) );
+ break;
+ }
+
+ default:
+ Console->Print( "%s Unknown error %d", Console->ColorText( RED, BLACK, "[ERROR]" ), LoadResult );
+ }
+ return false;
+}
+
+uint32_t PWorldDataTemplate::AddFurnitureItem( PFurnitureItemTemplate* nItem )
+{
+ if ( nItem )
+ {
+ if ( mFurnitureItems.insert( std::make_pair( nItem->GetID(), nItem ) ).second )
+ {
+ if ( gDevDebug ) Console->Print( "%s Furniture item %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nItem->GetID() );
+
+ if ( nItem->GetFunctionType() == 21 )
+ {
+ int v = nItem->GetFunctionValue();
+ if (( v >= 0 ) && ( v < WORLDDATATEMPLATE_MAXPOSITEMS ) )
+ {
+ if ( mPositionItems[v] )
+ {
+ if (( v == WORLDDATATEMPLATE_MAXPOSITEMS - 2 ) && !mPositionItems[v+1] ) // We allow that only for Pos 9 in order not to mess with other pos
+ {
+ Console->Print( "%s Same position %d for two position items ID %d and %d. Last one will be put on next position.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, mPositionItems[v]->GetID(), nItem->GetID() );
+ ++v;
+ }
+ else
+ {
+ Console->Print( "%s Same position %d for two position items ID %d and %d. Only last one kept.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, mPositionItems[v]->GetID(), nItem->GetID() );
+ }
+ }
+
+ mPositionItems[v] = nItem;
+ /*
+ Console->Print("Position entity %d (id 0x%x) added to world template", v, nItem->GetID());
+ float fpX, fpY, fpZ;
+ uint16_t pX, pY, pZ;
+ nItem->GetPos(&fpX, &fpY, &fpZ);
+ pX = (uint16_t) (fpX + 32000);
+ pY = (uint16_t) (fpY + 32000);
+ pZ = (uint16_t) (fpZ + 32000);
+ Console->Print("Position Y=%f (0x%04x) Z=%f (0x%04x) X=%f (0x%04x)", fpY, pY, fpZ, pZ, fpX, pX);
+ */
+ }
+ else
+ {
+ Console->Print( "%s Invalid position %d for position item ID %d. Position ignored.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, nItem->GetID() );
+ }
+ }
+ return nItem->GetID();
+ }
+ else
+ {
+ Console->Print( "%s Duplicate furniture item ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nItem->GetID() );
+ }
+ }
+ return 0;
+}
+
+const PFurnitureItemTemplate* PWorldDataTemplate::GetFurnitureItem( uint32_t ItemID )
+{
+ PFurnitureItemsMap::const_iterator it = mFurnitureItems.find( ItemID );
+ if ( it == mFurnitureItems.end() )
+ return NULL;
+ else
+ return it->second;
+}
+
+bool PWorldDataTemplate::getPositionItemPosition( uint8_t PosID, float* pX, float* pY, float* pZ )
+{
+ if (( PosID < WORLDDATATEMPLATE_MAXPOSITEMS ) && mPositionItems[PosID] )
+ {
+ mPositionItems[PosID]->GetPos( pX, pY, pZ ) ;
+ return true;
+ }
+ return false;
+}
+
+uint32_t PWorldDataTemplate::AddDoor( PDoorTemplate* nDoor )
+{
+ if ( nDoor )
+ {
+ if ( mDoors.insert( std::make_pair( nDoor->GetID(), nDoor ) ).second )
+ {
+ if ( gDevDebug ) Console->Print( "%s Door %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nDoor->GetID() );
+ return nDoor->GetID();
+ }
+ else
+ {
+ Console->Print( "%s Duplicate Door ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nDoor->GetID() );
+ }
+ }
+ return 0;
+}
+
+const PDoorTemplate* PWorldDataTemplate::GetDoor( uint32_t DoorID )
+{
+ PDoorsMap::const_iterator it = mDoors.find( DoorID );
+ if ( it == mDoors.end() )
+ return NULL;
+ else
+ return it->second;
+}
+
+
+uint32_t PWorldDataTemplate::AddNPC( PNPCTemplate* nNPC )
+{
+ if ( nNPC )
+ {
+ if ( mNPCs.insert( std::make_pair( nNPC->GetNpcID(), nNPC ) ).second )
+ {
+ if ( gDevDebug ) Console->Print( "%s NPC %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nNPC->GetNpcID() );
+ return nNPC->GetNpcID();
+ }
+ else
+ {
+ Console->Print( "%s Duplicate NPC ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nNPC->GetNpcID() );
+ }
+ }
+ return 0;
+}
+
+const PNPCTemplate* PWorldDataTemplate::GetNPC( uint32_t NPCID )
+{
+ PNPCsMap::const_iterator it = mNPCs.find( NPCID );
+ if ( it == mNPCs.end() )
+ return NULL;
+ else
+ return it->second;
+}
+
+void PWorldDataTemplate::SetLinkedObjects()
+{
+ float xI, yI, zI;
+ float xD, yD, zD;
+ float D2, minD2;
+ uint32_t minObjID;
+ uint16_t fnctType;
+ uint16_t tGROrder = 0;
+
+ for ( PFurnitureItemsMap::iterator it = mFurnitureItems.begin(); it != mFurnitureItems.end(); it++ )
+ {
+ fnctType = it->second->GetFunctionType();
+ if (( fnctType == 11 ) || ( fnctType == 12 ) || ( fnctType == 13 ) || ( fnctType == 23 ) ) // if function is apt entry button, door access if, hack button or money button
+ {
+ it->second->GetPos( &xI, &yI, &zI );
+//Console->Print("Button pos: %0.0f %0.0f %0.0f", xI, yI, zI);
+ minD2 = 1e9;
+ minObjID = 0;
+ for ( PDoorsMap::iterator dit = mDoors.begin(); dit != mDoors.end(); dit++ )
+ {
+//Console->Print("%s Found door %d (%s) : %s triggered, %s", Console->ColorText(GREEN, BLACK, "[Debug]"), dit->first, dit->second->GetName().c_str(), (dit->second->IsTriggeredDoor()?"":"not"), (dit->second->IsDoubleDoor()?"double":"single") );
+ if ( dit->second->IsTriggeredDoor() )
+ {
+ dit->second->GetPos( &xD, &yD, &zD );
+//Console->Print("Door pos: %0.0f %0.0f %0.0f", xD, yD, zD);
+ D2 = ( xI - xD ) * ( xI - xD ) + ( yI - yD ) * ( yI - yD ) + ( zI - zD ) * ( zI - zD );
+//Console->Print("Dist D2:%0.0f minD2:%0.0f", D2, minD2);
+ if ( D2 < minD2 )
+ {
+ minD2 = D2;
+ minObjID = 1 + dit->first;
+ }
+ }
+ }
+ if ( minObjID-- )
+ {
+ it->second->SetLinkedObjectID( minObjID );
+ if ( gDevDebug ) Console->Print( "%s Found triggered door %d (%s) for button %d (%s)", Console->ColorText( GREEN, BLACK, "[Debug]" ), minObjID, GetDoor( minObjID )->GetName().c_str(), it->first, it->second->GetName().c_str() );
+
+ }
+ else
+ {
+ Console->Print( "%s No triggered door found for button %d (%s) in World data template %s", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), it->first, it->second->GetName().c_str(), this->GetName().c_str() );
+ }
+ }
+ else if ( fnctType == 6 ) // if function is genrep
+ {
+ it->second->SetLinkedObjectID( ++tGROrder );
+ }
+ }
+
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <map>\r
-\r
-#define WORLDDATATEMPLATE_MAXPOSITEMS 11\r
-\r
-class PFurnitureItemTemplate;\r
-typedef std::map<uint32_t, PFurnitureItemTemplate*> PFurnitureItemsMap;\r
-\r
-class PDoorTemplate;\r
-typedef std::map<uint32_t, PDoorTemplate*> PDoorsMap;\r
-\r
-class PNPCTemplate;\r
-typedef std::map<uint32_t, PNPCTemplate*> PNPCsMap;\r
-\r
-class PWorldDataTemplate\r
-{\r
-private:\r
- std::string mName; // (datfile) relative path+filename without leading ./ or ./worlds/ nor .dat extension\r
- std::string mBspName; // (bsp file) relative path+filename without leading ./ or ./worlds/ nor .bsp extension\r
- PFurnitureItemsMap mFurnitureItems;\r
- PDoorsMap mDoors;\r
- PNPCsMap mNPCs;\r
- PFurnitureItemTemplate* mPositionItems[WORLDDATATEMPLATE_MAXPOSITEMS];\r
-\r
- int mUseCount;\r
-\r
- void DatFileDataCleanup();\r
- void SetLinkedObjects(); // This method implements some workarouds for some world objects on which we lack info.\r
-\r
-public:\r
- PWorldDataTemplate();\r
- ~PWorldDataTemplate();\r
-\r
- bool LoadDatFile(const std::string& WorldTemplateName, const std::string& nFilename, const bool nTestAccesOnly = false);\r
- inline const std::string& GetName()\r
- {\r
- return mName;\r
- }\r
- inline const std::string& GetBspName()\r
- {\r
- return mBspName;\r
- }\r
-\r
- inline void IncreaseUseCount()\r
- {\r
- ++mUseCount;\r
- }\r
- inline int DecreaseUseCount()\r
- {\r
- return (mUseCount ? --mUseCount : 0);\r
- }\r
- inline int GetUseCount()\r
- {\r
- return mUseCount;\r
- }\r
-\r
- uint32_t AddFurnitureItem(PFurnitureItemTemplate* nItem);\r
- const PFurnitureItemTemplate* GetFurnitureItem(uint32_t ItemID);\r
- bool getPositionItemPosition(uint8_t PosID, float* pX, float* pY, float* pZ);\r
-\r
- uint32_t AddDoor(PDoorTemplate* nDoor);\r
- const PDoorTemplate* GetDoor(uint32_t DoorID);\r
-\r
- uint32_t AddNPC(PNPCTemplate* nNPC);\r
-\r
- // External functions for NPCManager\r
- const PNPCTemplate* GetNPC(uint32_t NPCID);\r
- inline const PNPCsMap *GetNPCMap() const\r
- {\r
- return &mNPCs;\r
- }; // called by class PNPCWorld to get all NPCs for this world\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <map>
+
+#define WORLDDATATEMPLATE_MAXPOSITEMS 11
+
+class PFurnitureItemTemplate;
+typedef std::map<uint32_t, PFurnitureItemTemplate*> PFurnitureItemsMap;
+
+class PDoorTemplate;
+typedef std::map<uint32_t, PDoorTemplate*> PDoorsMap;
+
+class PNPCTemplate;
+typedef std::map<uint32_t, PNPCTemplate*> PNPCsMap;
+
+class PWorldDataTemplate
+{
+private:
+ std::string mName; // (datfile) relative path+filename without leading ./ or ./worlds/ nor .dat extension
+ std::string mBspName; // (bsp file) relative path+filename without leading ./ or ./worlds/ nor .bsp extension
+ PFurnitureItemsMap mFurnitureItems;
+ PDoorsMap mDoors;
+ PNPCsMap mNPCs;
+ PFurnitureItemTemplate* mPositionItems[WORLDDATATEMPLATE_MAXPOSITEMS];
+
+ int mUseCount;
+
+ void DatFileDataCleanup();
+ void SetLinkedObjects(); // This method implements some workarouds for some world objects on which we lack info.
+
+public:
+ PWorldDataTemplate();
+ ~PWorldDataTemplate();
+
+ bool LoadDatFile(const std::string& WorldTemplateName, const std::string& nFilename, const bool nTestAccesOnly = false);
+ inline const std::string& GetName()
+ {
+ return mName;
+ }
+ inline const std::string& GetBspName()
+ {
+ return mBspName;
+ }
+
+ inline void IncreaseUseCount()
+ {
+ ++mUseCount;
+ }
+ inline int DecreaseUseCount()
+ {
+ return (mUseCount ? --mUseCount : 0);
+ }
+ inline int GetUseCount()
+ {
+ return mUseCount;
+ }
+
+ uint32_t AddFurnitureItem(PFurnitureItemTemplate* nItem);
+ const PFurnitureItemTemplate* GetFurnitureItem(uint32_t ItemID);
+ bool getPositionItemPosition(uint8_t PosID, float* pX, float* pY, float* pZ);
+
+ uint32_t AddDoor(PDoorTemplate* nDoor);
+ const PDoorTemplate* GetDoor(uint32_t DoorID);
+
+ uint32_t AddNPC(PNPCTemplate* nNPC);
+
+ // External functions for NPCManager
+ const PNPCTemplate* GetNPC(uint32_t NPCID);
+ inline const PNPCsMap *GetNPCMap() const
+ {
+ return &mNPCs;
+ }; // called by class PNPCWorld to get all NPCs for this world
+};
-#include <set>\r
-#include "GameServer/Includes.hxx"\r
-#include "GameServer/Definitions/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-/**** PWorld ****/\r
-uint16_t const PWorld::mZoneOutLimitOffset = 0x100;\r
-uint16_t const PWorld::mBottomZoneOutLimit = 0x4800 - PWorld::mZoneOutLimitOffset;\r
-uint16_t const PWorld::mBottomZoneInLimit = 0x4a00;\r
-uint16_t const PWorld::mTopZoneOutLimit = 0xb200 + PWorld::mZoneOutLimitOffset;\r
-uint16_t const PWorld::mTopZoneInLimit = 0xb000;\r
-const std::string EmptyString;\r
-\r
-PWorld::PWorld()\r
-{\r
- mID = 0;\r
- mUseCount = 0;\r
- mWorldDataTemplate = NULL;\r
-}\r
-\r
-PWorld::~PWorld()\r
-{\r
-}\r
-\r
-bool PWorld::Load( uint32_t nWorldID )\r
-{\r
- std::string WorldTemplateName;\r
- std::string tFileName;\r
- bool tCheckOK;\r
-\r
- if ( nWorldID > PWorlds::mAptBaseWorldId )\r
- {\r
- //int AptTmplID = Appartements->GetAptType(nWorldID - PWorlds::mAptBaseWorldId);\r
- int AptTmplID = Appartements->GetAptType( nWorldID );\r
- if ( !AptTmplID )\r
- {\r
- Console->Print( "%s PWorld::Load - invalid apt %d", Console->ColorText( RED, BLACK, "[WARNING]" ), nWorldID - PWorlds::mAptBaseWorldId );\r
- return false;\r
- }\r
- const PDefAppartement* nAppDef = GameDefs->Appartements()->GetDef( AptTmplID );\r
- if ( !nAppDef )\r
- {\r
- Console->Print( "%s PWorld::Load - invalid apt type %d", Console->ColorText( RED, BLACK, "[WARNING]" ), AptTmplID );\r
- return false;\r
- }\r
- WorldTemplateName = nAppDef->GetWorldName();\r
-\r
- tFileName = std::string( "worlds/" ) + WorldTemplateName + ".dat";\r
- tCheckOK = Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName );\r
- if ( !tCheckOK )\r
- {\r
- tFileName = WorldTemplateName + ".dat";\r
- tCheckOK = Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName );\r
- }\r
- if ( !tCheckOK )\r
- {\r
- Console->Print( "%s PWorld::Load - unable to lease apt world %s (%s)", Console->ColorText( RED, BLACK, "[WARNING]" ), WorldTemplateName.c_str(), tFileName.c_str() );\r
- return false;\r
- }\r
- }\r
- else\r
- {\r
- const PDefWorldFile* nWorldFileDef;\r
-\r
- if (( nWorldID > 90000 ) && ( nWorldID < 90017 ) ) // hardcoded holomatch hack\r
- {\r
- nWorldFileDef = NULL;\r
- char worldName[19];\r
- int MatchID = nWorldID - 90000;\r
- if ( MatchID > 8 ) // to care for Neofrag 1 & 2\r
- MatchID -= 8;\r
- if ( MatchID > 6 )\r
- MatchID = 6; // holomatch 7 and 8 are same as 6\r
- snprintf( worldName, 19, "holomatch/neofrag%d", MatchID );\r
- WorldTemplateName = worldName;\r
- }\r
- else\r
- {\r
- nWorldFileDef = GameDefs->WorldFiles()->GetDef( nWorldID );\r
- if ( !nWorldFileDef )\r
- return false;\r
- WorldTemplateName = nWorldFileDef->GetName();\r
- }\r
-\r
- const PDefWorld* tWorldDef = GameDefs->Worlds()->GetDef( nWorldID );\r
- if ( tWorldDef ) // should always be true here\r
- {\r
- if ( !( tWorldDef->GetDatFile().empty() ) )\r
- tFileName = tWorldDef->GetDatFile();\r
- else if ( nWorldFileDef )\r
- tFileName = nWorldFileDef->GetBasicFileName() + ".dat";\r
- else\r
- {\r
- tFileName = "worlds/";\r
- tFileName += WorldTemplateName;\r
- tFileName += ".dat";\r
- }\r
- }\r
- else\r
- return false; // should'nt happen here\r
-\r
- if ( !Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName ) )\r
- return false;\r
- }\r
-\r
- mWorldDataTemplate = Worlds->GetWorldDataTemplate( tFileName );\r
- if ( !mWorldDataTemplate )\r
- {\r
- Console->Print( "%s PWorld::Load : Unexpected world %d not found error", Console->ColorText( RED, BLACK, "[WARNING]" ), nWorldID );\r
- return false;\r
- }\r
-\r
- mID = nWorldID;\r
- mSpawnedVehicles.SetLocation( nWorldID );\r
- // furniture & other world stuff loading here\r
- Console->Print( "%s Loaded world %d", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), nWorldID );\r
- return true;\r
-}\r
-\r
-std::string PWorld::GetName()\r
-{\r
- return ( mWorldDataTemplate ? mWorldDataTemplate->GetName() : EmptyString );\r
-}\r
-\r
-std::string PWorld::GetBspName()\r
-{\r
- return ( mWorldDataTemplate ? mWorldDataTemplate->GetBspName() : EmptyString );\r
-}\r
-\r
-bool PWorld::IsAppartment()\r
-{\r
- return mIsAppartment;\r
-}\r
-\r
-const PFurnitureItemTemplate *PWorld::GetFurnitureItemTemplate( uint32_t nItemID )\r
-{\r
- return ( mWorldDataTemplate ? mWorldDataTemplate->GetFurnitureItem( nItemID ) : NULL ) ;\r
-}\r
-\r
-const PDefWorldModel *PWorld::GetFurnitureItemModel(uint32_t nItemID)\r
-{\r
- if ( mWorldDataTemplate )\r
- {\r
- const PFurnitureItemTemplate* tFurniture = mWorldDataTemplate->GetFurnitureItem( nItemID );\r
- if ( tFurniture )\r
- return tFurniture->GetDefWorldModel();\r
- }\r
- return nullptr;\r
-}\r
-\r
-const PDoorTemplate *PWorld::GetDoor(uint32_t nDoorID)\r
-{\r
- return (mWorldDataTemplate ? mWorldDataTemplate->GetDoor(nDoorID) : nullptr);\r
-}\r
-\r
-bool PWorld::getPositionItemPosition(uint8_t PosID, float *pX, float *pY, float *pZ)\r
-{\r
- return (mWorldDataTemplate ? mWorldDataTemplate->getPositionItemPosition(PosID, pX, pY, pZ) : false);\r
-}\r
-\r
-bool PWorld::CharUseChair( int CharLocalID, uint32_t nItemID )\r
-{\r
- PChairsInUseMap::iterator it = mChairsInUseMap.find( nItemID );\r
- if ( it == mChairsInUseMap.end() ) // chair is free\r
- {\r
- if ( gDevDebug )\r
- Console->Print( "%s Localchar %d now using free chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID );\r
- mChairsInUseMap.insert( std::make_pair( nItemID, CharLocalID ) );\r
- return true;\r
- }\r
- else // chair is already in use\r
- {\r
- if ( gDevDebug )\r
- {\r
- if ( it->second == CharLocalID )\r
- {\r
- Console->Print( "%s Localchar %d already using chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID );\r
- }\r
- else\r
- {\r
- Console->Print( "%s Localchar %d can't sit on chair %d used by localchar %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID, it->second );\r
- }\r
- }\r
- return ( it->second == CharLocalID );\r
- }\r
-}\r
-\r
-void PWorld::CharLeaveChair( int CharLocalID, uint32_t nItemID )\r
-{\r
- PChairsInUseMap::iterator it = mChairsInUseMap.find( nItemID );\r
- if (( it != mChairsInUseMap.end() ) && ( it->second == CharLocalID ) ) // chair is in use by this char\r
- {\r
- if ( gDevDebug )\r
- Console->Print( "%s Localchar %d leaving chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID );\r
- mChairsInUseMap.erase( it );\r
- }\r
-}\r
-\r
-PClient* PWorld::GetClientByCharLocalId( uint32_t rawObjectId ) const\r
-{\r
- // Temp implementation\r
- return ClientManager->GetClientByCharLocalId( rawObjectId, mID );\r
-}\r
-\r
-PSpawnedVehicles *PWorld::GetSpawnedVehicles()\r
-{\r
- return &mSpawnedVehicles;\r
-}\r
-\r
-bool PWorld::CheckVhcNeedZoning( PVhcCoordinates const* nPos ) const\r
-{\r
- if ( ( nPos->GetX() <= mBottomZoneOutLimit ) || ( nPos->GetX() >= mTopZoneOutLimit ) || ( nPos->GetY() <= mBottomZoneOutLimit ) || ( nPos->GetY() >= mTopZoneOutLimit ) )\r
- return true;\r
- else\r
- return false;\r
-}\r
-\r
-uint32_t PWorld::GetVhcZoningDestination( PSpawnedVehicle const* nVhc, PVhcCoordinates* nPos ) const\r
-{\r
- uint32_t destWorldId = 0;\r
- int16_t vChange = 0;\r
- int16_t hChange = 0;\r
- PVhcCoordinates const vhcPos = nVhc->GetPosition();\r
- uint16_t posX = vhcPos.GetX();\r
- uint16_t posY = vhcPos.GetY();\r
-\r
- if ( posX <= mBottomZoneOutLimit )\r
- {\r
- vChange = 1;\r
- }\r
- else if ( posX >= mTopZoneOutLimit )\r
- {\r
- vChange = -1;\r
- }\r
-\r
- if ( posY <= mBottomZoneOutLimit )\r
- {\r
- hChange = -1;\r
- }\r
- else if ( posY >= mTopZoneOutLimit )\r
- {\r
- hChange = 1;\r
- }\r
-\r
- if ( vChange || hChange )\r
- {\r
- //Console->Print( YELLOW, BLACK, "[DEBUG] Limit Reached V:%d H:%d mapId:%d", vChange,hChange,mID );\r
- uint8_t currH = 0;\r
- uint8_t currV = 0;\r
- int16_t newH, newV;\r
-\r
- if ( Worlds->GetWorldmapFromWorldId( mID, currH, currV ) )\r
- {\r
- //Console->Print( YELLOW, BLACK, "[DEBUG] current map pos V:%d H:%d", currV,currH );\r
- newH = currH + hChange;\r
- if ( newH < 0 )\r
- newH = 0;\r
- else if ( newH >= PWorlds::mOutdoorWorldmapHSize )\r
- newH = PWorlds::mOutdoorWorldmapHSize;\r
-\r
- newV = currV + vChange;\r
- if ( newV < 0 )\r
- newV = 0;\r
- else if ( newV >= PWorlds::mOutdoorWorldmapHSize )\r
- newV = PWorlds::mOutdoorWorldmapHSize;\r
-\r
- //Console->Print( YELLOW, BLACK, "[DEBUG] new map pos V:%d H:%d", newV,newH );\r
- if (( newH != currH ) || ( newV != currV ) )\r
- {\r
- destWorldId = Worlds->GetWorldIdFromWorldmap( newH, newV );\r
-\r
- if ( destWorldId && nPos )\r
- {\r
- if ( vChange == 1 )\r
- posX = mTopZoneInLimit;\r
- else if ( vChange == -1 )\r
- posX = mBottomZoneInLimit;\r
-\r
- if ( hChange == -1 )\r
- posY = mTopZoneInLimit;\r
- else if ( hChange == 1 )\r
- posY = mBottomZoneInLimit;\r
-\r
- nPos->SetPosition( posY, vhcPos.GetZ(), posX, vhcPos.GetUD(), vhcPos.GetLR(), vhcPos.GetRoll(), vhcPos.GetAct(), vhcPos.GetUnknown(), vhcPos.GetFF() );\r
- }\r
- }\r
- }\r
- }\r
-\r
- return destWorldId;\r
-}\r
-\r
-const PNPCsMap *PWorld::GetNPCMap() const\r
-{\r
- return (mWorldDataTemplate ? mWorldDataTemplate->GetNPCMap() : nullptr);\r
-}\r
-\r
-const PNPCTemplate *PWorld::GetNPCTemplate(uint32_t nNPCID) const\r
-{\r
- return (mWorldDataTemplate ? mWorldDataTemplate->GetNPC(nNPCID) : nullptr);\r
-}\r
-\r
-/**** PWorlds ****/\r
-uint32_t const PWorlds::mNcSubwayWorldId = 1000;\r
-uint32_t const PWorlds::mAptBaseWorldId = 100000;\r
-uint32_t const PWorlds::mOutdoorBaseWorldId = 2001;\r
-uint32_t const PWorlds::mOutdoorWorldIdVIncrement = 20;\r
-uint8_t const PWorlds::mOutdoorWorldmapHSize = 16;\r
-uint8_t const PWorlds::mOutdoorWorldmapVSize = 11;\r
-uint32_t const PWorlds::mOutdoorMaxWorldId = PWorlds::mOutdoorBaseWorldId + PWorlds::mOutdoorWorldIdVIncrement * ( PWorlds::mOutdoorWorldmapVSize - 1 ) + PWorlds::mOutdoorWorldmapHSize - 1;\r
-\r
-PWorlds::PWorlds()\r
-{\r
- mPreloadWorldsTemplates = false; // to be put as config option\r
- mPreloadStaticWorlds = false; // to be put as config option\r
-}\r
-\r
-PWorlds::~PWorlds()\r
-{\r
- for ( PWorldsMap::iterator i = mStaticWorldsMap.begin(); i != mStaticWorldsMap.end(); i++ )\r
- if ( i->second )\r
- {\r
- delete i->second;\r
- }\r
- for ( PWorldsMap::iterator i = mOnDemandWorldsMap.begin(); i != mOnDemandWorldsMap.end(); i++ )\r
- if ( i->second )\r
- {\r
- delete i->second;\r
- }\r
- for ( PWorldDataTemplatesMap::iterator i = mWorldDataTemplatesMap.begin(); i != mWorldDataTemplatesMap.end(); i++ )\r
- if ( i->second )\r
- {\r
- delete i->second;\r
- }\r
-}\r
-\r
-bool PWorlds::LeaseWorldDataTemplate( const std::string& nBspName, const std::string& nFileName, const bool nPreloadPhase )\r
-{\r
- PWorldDataTemplate* tWorldDataTemplate;\r
-\r
- PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName );\r
- if ( it == mWorldDataTemplatesMap.end() ) // template unkown yet\r
- {\r
- if ( nPreloadPhase ) // if in preload phase, we try to load it or make it known\r
- {\r
- tWorldDataTemplate = new PWorldDataTemplate;\r
- if ( tWorldDataTemplate->LoadDatFile( nBspName, nFileName, !mPreloadWorldsTemplates ) )\r
- {\r
- if ( mPreloadWorldsTemplates )\r
- {\r
- mWorldDataTemplatesMap.insert( std::make_pair( nFileName, tWorldDataTemplate ) );\r
- tWorldDataTemplate->IncreaseUseCount();\r
- }\r
- else\r
- {\r
- mWorldDataTemplatesMap.insert( std::make_pair( nFileName, ( PWorldDataTemplate* )NULL ) ); // NULL means file access OK but not preloaded yet\r
- delete tWorldDataTemplate;\r
- }\r
- //return true;\r
- }\r
- else\r
- {\r
- delete tWorldDataTemplate;\r
- return false;\r
- }\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
- }\r
- else // template already known\r
- {\r
- if ( !it->second && !nPreloadPhase ) // template known but not already loaded and not in preload ?\r
- {\r
- tWorldDataTemplate = new PWorldDataTemplate;\r
- if ( tWorldDataTemplate->LoadDatFile( nBspName, nFileName ) )\r
- {\r
- it->second = tWorldDataTemplate;\r
- }\r
- else\r
- {\r
- Console->Print( "%s Invalid world data template file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), nFileName.c_str() );\r
- mWorldDataTemplatesMap.erase( it );\r
- delete tWorldDataTemplate;\r
- return false;\r
- }\r
- }\r
-\r
- if ( !nPreloadPhase )\r
- it->second->IncreaseUseCount();\r
-\r
- //return true;\r
- }\r
-\r
- return true;\r
-}\r
-\r
-void PWorlds::ReleaseWorldDataTemplate( const std::string& nFileName )\r
-{\r
- PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName );\r
- if (( it != mWorldDataTemplatesMap.end() ) && it->second )\r
- {\r
- it->second->DecreaseUseCount();\r
- }\r
- else\r
- Console->Print( "%s PWorlds::ReleaseWorldDataTemplate : try to relese not loaded template %s", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() );\r
-}\r
-\r
-void PWorlds::UnloadWorldDataTemplate( const std::string& nFileName )\r
-{\r
- PWorldDataTemplate* tWorldDataTemplate;\r
-\r
- PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName );\r
- if (( it != mWorldDataTemplatesMap.end() ) && it->second )\r
- {\r
- tWorldDataTemplate = it->second;\r
- if ( mPreloadWorldsTemplates || ( tWorldDataTemplate->GetUseCount() > 0 ) )\r
- Console->Print( "%s PWorlds::UnloadWorldDataTemplate : attempt to unload template %s when use count not null ou preload set", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() );\r
- else\r
- {\r
- it->second = ( PWorldDataTemplate* )NULL;\r
- delete tWorldDataTemplate;\r
- }\r
- }\r
- else\r
- Console->Print( "%s PWorlds::UnloadWorldDataTemplate : attempt to release not loaded template %s", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() );\r
-}\r
-\r
-PWorldDataTemplate* PWorlds::GetWorldDataTemplate( const std::string& nFileName )\r
-{\r
- PWorldDataTemplatesMap::const_iterator it = mWorldDataTemplatesMap.find( nFileName );\r
- if ( it != mWorldDataTemplatesMap.end() )\r
- return it->second;\r
- else\r
- return NULL;\r
-}\r
-\r
-bool PWorlds::LoadWorlds() // once Load is done, only WorldDataTemplate registred in mWorldDataTemplatesMap\r
-{\r
- // will be considered as valid\r
- std::string tFileName;\r
- std::string tBspName;\r
- const PDefWorld* tDefWorld;\r
- bool tCheckOK;\r
- int ValidCount = 0, InvalidCount = 0, DblInvCount = 0;\r
- int DatTmplCount, BadDatTmplCount;\r
- std::set<std::string>\r
- InvalideFiles;\r
-\r
- // Appartment templates checking or preloading\r
- std::map<int, PDefAppartement*>::const_iterator itAptStart = GameDefs->Appartements()->ConstIteratorBegin();\r
- std::map<int, PDefAppartement*>::const_iterator itAptEnd = GameDefs->Appartements()->ConstIteratorEnd();\r
- for ( std::map<int, PDefAppartement*>::const_iterator i = itAptStart; i != itAptEnd; i++ )\r
- {\r
- tCheckOK = false;\r
- tBspName = i->second->GetWorldName();\r
- tFileName = std::string( "worlds/" ) + tBspName + ".dat";\r
- if ( !InvalideFiles.count( tFileName ) )\r
- {\r
- tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true );\r
- if ( !tCheckOK )\r
- {\r
- InvalideFiles.insert( tFileName );\r
- if ( gDevDebug )\r
- Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() );\r
- }\r
- }\r
- if ( !tCheckOK ) // in case full path was given without omiting worlds/ or in another dir/archive ...\r
- {\r
- tFileName = tBspName + ".dat";\r
- if ( !InvalideFiles.count( tFileName ) )\r
- {\r
- tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true );\r
- if ( !tCheckOK )\r
- {\r
- InvalideFiles.insert( tFileName );\r
- ++DblInvCount;\r
- }\r
- }\r
- }\r
-\r
- if ( tCheckOK )\r
- {\r
- ++ValidCount;\r
- if ( gDevDebug )\r
- Console->Print( GREEN, BLACK, "Template file %s for appartment %d (%s) loaded", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() );\r
- }\r
- else\r
- {\r
- ++InvalidCount;\r
- if ( gDevDebug )\r
- Console->Print( RED, BLACK, "Template file %s for appartment %d (%s) not available or invalid", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() );\r
- }\r
- }\r
-\r
- DatTmplCount = mWorldDataTemplatesMap.size();\r
- BadDatTmplCount = InvalideFiles.size();\r
- Console->Print( "%s %d valid appartement templates checked (%d dat files)", Console->ColorText( GREEN, BLACK, "[Success]" ), ValidCount, DatTmplCount );\r
- if ( InvalidCount )\r
- Console->Print( "%s %d invalid appartement templates rejected (%d dat files)", Console->ColorText( YELLOW, BLACK, "[Notice]" ), InvalidCount, BadDatTmplCount - DblInvCount );\r
-\r
- // Static worlds & static worlds templates checking or preloading\r
- ValidCount = InvalidCount = 0;\r
- const PDefWorldFile* tDefWorldFile;\r
- std::map<int, PDefWorldFile*>::const_iterator itFilStart = GameDefs->WorldFiles()->ConstIteratorBegin();\r
- std::map<int, PDefWorldFile*>::const_iterator itFilEnd = GameDefs->WorldFiles()->ConstIteratorEnd();\r
- for ( std::map<int, PDefWorldFile*>::const_iterator i = itFilStart; i != itFilEnd; i++ )\r
- {\r
- tDefWorldFile = i->second;\r
-\r
- tDefWorld = GameDefs->Worlds()->GetDef( tDefWorldFile->GetIndex() );\r
- if ( tDefWorld ) // we only care for worlds that are present in worldinfo.def too\r
- {\r
- tBspName = tDefWorldFile->GetName();\r
- if ( !( tDefWorld->GetDatFile().empty() ) )\r
- tFileName = tDefWorld->GetDatFile();\r
- else\r
- tFileName = i->second->GetBasicFileName() + ".dat";\r
-\r
- tCheckOK = false;\r
- if ( !InvalideFiles.count( tFileName ) )\r
- {\r
- tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true );\r
- if ( !tCheckOK )\r
- {\r
- InvalideFiles.insert( tFileName );\r
- if ( gDevDebug )\r
- Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() );\r
- }\r
- }\r
-\r
- if ( tCheckOK )\r
- {\r
- ++ValidCount;\r
- if ( mPreloadStaticWorlds )\r
- {\r
- LeaseWorld( tDefWorldFile->GetIndex(), true ); // This will make the world ready and kept in mem (use count always >0 )\r
- }\r
- else\r
- {\r
- mStaticWorldsMap.insert( std::make_pair( tDefWorldFile->GetIndex(), ( PWorld* )NULL ) );\r
- }\r
- if ( gDevDebug )\r
- Console->Print( GREEN, BLACK, "Template file %s for world %d (%s) loaded", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() );\r
- }\r
- else\r
- {\r
- ++InvalidCount;\r
- if ( gDevDebug )\r
- Console->Print( RED, BLACK, "Template file %s for world %d (%s) not available or invalid", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() );\r
- }\r
- }\r
- }\r
-\r
- // Hardcoded neofrag worlds ... oO ... and neofrag4.dat can't be found :-/\r
- for ( int i = 1; i <= 16; i++ )\r
- {\r
- char worldName[19];\r
- int MatchID = i;\r
- if ( MatchID > 8 ) // to care for Neofrag 1 & 2\r
- MatchID -= 8;\r
- if ( MatchID > 6 )\r
- MatchID = 6; // holomatch 7 and 8 are same as 6\r
- snprintf( worldName, 19, "holomatch/neofrag%d", MatchID );\r
-\r
- tDefWorld = GameDefs->Worlds()->GetDef( 90000 + i );\r
- if ( tDefWorld ) // we only care for worlds that are present in worldinfo.def too\r
- {\r
- if ( !( tDefWorld->GetDatFile().empty() ) )\r
- tFileName = tDefWorld->GetDatFile();\r
- else\r
- {\r
- tFileName = "worlds/";\r
- tFileName += worldName;\r
- tFileName += ".dat";\r
- }\r
-\r
- tCheckOK = false;\r
- if ( !InvalideFiles.count( tFileName ) )\r
- {\r
- tCheckOK = LeaseWorldDataTemplate( worldName, tFileName, true );\r
- if ( !tCheckOK )\r
- {\r
- InvalideFiles.insert( tFileName );\r
- if ( gDevDebug )\r
- Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() );\r
- }\r
- }\r
-\r
- if ( tCheckOK )\r
- {\r
- ++ValidCount;\r
- if ( mPreloadStaticWorlds )\r
- {\r
- LeaseWorld( 90000 + i, true ); // This will make the world ready and kept in mem (use count always >0 )\r
- }\r
- else\r
- {\r
- mStaticWorldsMap.insert( std::make_pair( 90000 + i, ( PWorld* )NULL ) );\r
- }\r
- if ( gDevDebug )\r
- Console->Print( GREEN, BLACK, "Template file %s for world %d (%s) loaded", tFileName.c_str(), 90000 + i, worldName );\r
- }\r
- else\r
- {\r
- ++InvalidCount;\r
- if ( gDevDebug )\r
- Console->Print( RED, BLACK, "Template file %s for world %d (%s) not available or invalid", tFileName.c_str(), 90000 + i, worldName );\r
- }\r
- }\r
- }\r
-\r
- Console->Print( "%s %d valid world templates checked (%d dat files)", Console->ColorText( GREEN, BLACK, "[Success]" ), ValidCount, mWorldDataTemplatesMap.size() - DatTmplCount );\r
- if ( InvalidCount )\r
- Console->Print( "%s %d invalid world templates rejected (%d dat files)", Console->ColorText( YELLOW, BLACK, "[Notice]" ), InvalidCount, InvalideFiles.size() - BadDatTmplCount - DblInvCount );\r
- Console->Print( "%s %d static worlds prepared", Console->ColorText( GREEN, BLACK, "[Success]" ), mStaticWorldsMap.size() );\r
-\r
- // release memory if World templates preload activated, this cache that won't be used anymore\r
- // if (mPreloadWorldsTemplates) Filesystem->ClearCache();\r
-\r
- return true;\r
-}\r
-\r
-bool PWorlds::IsValidWorld( uint32_t nWorldID ) const\r
-{\r
- if ( nWorldID > PWorlds::mAptBaseWorldId )\r
- {\r
- if ( mOnDemandWorldsMap.count( nWorldID ) ) // Check if already loaded\r
- return true;\r
- else //should better do a check using a PAppartements class object to get the world template\r
- {\r
- //int AptTmplID = Appartements->GetAptType(nWorldID - PWorlds::mAptBaseWorldId);\r
- int AptTmplID = Appartements->GetAptType( nWorldID );\r
- if ( !AptTmplID )\r
- return false;\r
-\r
- const PDefAppartement* nAppDef = GameDefs->Appartements()->GetDef( AptTmplID );\r
- if ( !nAppDef )\r
- return false;\r
-\r
- std::string tFileName = "worlds/" + nAppDef->GetWorldName() + ".dat";\r
- PWorldDataTemplatesMap::const_iterator it = mWorldDataTemplatesMap.find( tFileName );\r
- return ( it != mWorldDataTemplatesMap.end() );\r
- }\r
- }\r
- else\r
- {\r
- if ( gDevDebug )\r
- Console->Print( "%s Checking validity for world %d : %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID, mStaticWorldsMap.count( nWorldID ) ? "OK" : "BAD" );\r
- return ( mStaticWorldsMap.count( nWorldID ) );\r
- }\r
-}\r
-\r
-PWorld* PWorlds::LeaseWorld( uint32_t nWorldID, const bool nPreloadPhase )\r
-{\r
- PWorldsMap::iterator it;\r
-\r
- if ( nWorldID > PWorlds::mAptBaseWorldId )\r
- {\r
- it = mOnDemandWorldsMap.find( nWorldID ); // Check if already loaded\r
- if (( it != mOnDemandWorldsMap.end() ) && it->second ) // Dynamic world shall not have a NULL it->second\r
- {\r
- // if loaded\r
- it->second->IncreaseUseCount();\r
- if ( gDevDebug )\r
- Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID );\r
- return it->second;\r
- }\r
- else // not loaded yet or invalid\r
- {\r
- PWorld* nWorld = new PWorld;\r
- if ( ! nWorld->Load( nWorldID ) ) // Error when loading (shouldn't happen)\r
- {\r
- delete nWorld;\r
- Console->Print( "% Could not load world %d - World now set as invalid", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );\r
- return NULL;\r
- }\r
- else\r
- {\r
- mOnDemandWorldsMap.insert( std::make_pair( nWorldID, nWorld ) );\r
- nWorld->IncreaseUseCount();\r
- if ( gDevDebug )\r
- Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID );\r
- return nWorld;\r
- }\r
- }\r
- }\r
- else\r
- {\r
- it = mStaticWorldsMap.find( nWorldID ); // Check if already loaded\r
- if (( it == mStaticWorldsMap.end() ) && nPreloadPhase )\r
- {\r
- mStaticWorldsMap.insert( std::make_pair( nWorldID, ( PWorld* )NULL ) );\r
- it = mStaticWorldsMap.find( nWorldID );\r
- }\r
- if ( it != mStaticWorldsMap.end() )\r
- {\r
- // if valid\r
- if ( ! it->second ) // if not loaded yet\r
- {\r
- it->second = new PWorld;\r
- if ( ! it->second->Load( nWorldID ) ) // Error when loading (shouldn't happen)\r
- {\r
- delete it->second;\r
- Console->Print( "%s Could not load world %d - World now set as invalid", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );\r
- mStaticWorldsMap.erase( it ); // remove from valid worlds map\r
- return NULL;\r
- }\r
- }\r
- it->second->IncreaseUseCount();\r
- if ( gDevDebug )\r
- Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID );\r
- return it->second;\r
- }\r
- else // invalid worldID\r
- {\r
- return NULL;\r
- }\r
- }\r
-}\r
-\r
-PWorld* PWorlds::GetWorld( uint32_t nWorldID )\r
-{\r
- PWorldsMap* tMap;\r
- PWorldsMap::iterator it;\r
-\r
- tMap = (( nWorldID > PWorlds::mAptBaseWorldId ) ? &mOnDemandWorldsMap : &mStaticWorldsMap );\r
-\r
- it = tMap->find( nWorldID );\r
- if (( it != tMap->end() ) && it->second )\r
- {\r
- return it->second;\r
- }\r
- else\r
- {\r
- Console->Print( "%s PWorlds::GetWorld : Trying to get world %d without lease !", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );\r
- return NULL;\r
- }\r
-}\r
-\r
-void PWorlds::ReleaseWorld( uint32_t nWorldID ) // no dynamic unload is performed atm + don't forget spawned vhc !\r
-{\r
- PWorld* tWorld = GetWorld( nWorldID );\r
- if ( tWorld )\r
- {\r
- if ( tWorld->GetUseCount() ) // this check is for dev time only\r
- {\r
- tWorld->DecreaseUseCount();\r
- if ( gDevDebug )\r
- Console->Print( "%s Released world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID );\r
- }\r
- else\r
- {\r
- Console->Print( "%s PWorlds::ReleaseWorld : Trying to release world %d with use count 0 !", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );\r
- }\r
- }\r
- else\r
- {\r
- Console->Print( "%s PWorlds::ReleaseWorld : Generated the invalid get world %d", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );\r
- }\r
-}\r
-\r
-bool PWorlds::IsAppartment( uint32_t nWorldID )\r
-{\r
- return (( nWorldID > PWorlds::mAptBaseWorldId ) && IsValidWorld( nWorldID ) );\r
-}\r
-\r
-void PWorlds::Update()\r
-{}\r
-\r
-void PWorlds::Shutdown()\r
-{}\r
-\r
-uint32_t PWorlds::GetWorldIdFromWorldmap( uint8_t mapH, uint8_t mapV ) const\r
-{\r
- uint32_t loc = 0;\r
- if (( mapH < mOutdoorWorldmapHSize ) && ( mapV < mOutdoorWorldmapVSize ) )\r
- {\r
- loc = mOutdoorBaseWorldId + mOutdoorWorldIdVIncrement * mapV + mapH;\r
- if ( ! IsValidWorld( loc ) )\r
- loc = 0;\r
- }\r
- return loc;\r
-}\r
-\r
-bool PWorlds::GetWorldmapFromWorldId( uint32_t nWorldId, uint8_t& mapH, uint8_t& mapV ) const\r
-{\r
- if (( nWorldId >= mOutdoorBaseWorldId ) && ( nWorldId <= mOutdoorMaxWorldId ) )\r
- {\r
- mapV = ( nWorldId - mOutdoorBaseWorldId ) / mOutdoorWorldIdVIncrement;\r
- mapH = ( nWorldId - mOutdoorBaseWorldId ) % mOutdoorWorldIdVIncrement;\r
- return true;\r
- }\r
- return false;\r
-}\r
+#include <set>
+#include "GameServer/Includes.hxx"
+#include "GameServer/Definitions/Includes.hxx"
+#include "Common/Includes.hxx"
+
+/**** PWorld ****/
+uint16_t const PWorld::mZoneOutLimitOffset = 0x100;
+uint16_t const PWorld::mBottomZoneOutLimit = 0x4800 - PWorld::mZoneOutLimitOffset;
+uint16_t const PWorld::mBottomZoneInLimit = 0x4a00;
+uint16_t const PWorld::mTopZoneOutLimit = 0xb200 + PWorld::mZoneOutLimitOffset;
+uint16_t const PWorld::mTopZoneInLimit = 0xb000;
+const std::string EmptyString;
+
+PWorld::PWorld()
+{
+ mID = 0;
+ mUseCount = 0;
+ mWorldDataTemplate = NULL;
+}
+
+PWorld::~PWorld()
+{
+}
+
+bool PWorld::Load( uint32_t nWorldID )
+{
+ std::string WorldTemplateName;
+ std::string tFileName;
+ bool tCheckOK;
+
+ if ( nWorldID > PWorlds::mAptBaseWorldId )
+ {
+ //int AptTmplID = Appartements->GetAptType(nWorldID - PWorlds::mAptBaseWorldId);
+ int AptTmplID = Appartements->GetAptType( nWorldID );
+ if ( !AptTmplID )
+ {
+ Console->Print( "%s PWorld::Load - invalid apt %d", Console->ColorText( RED, BLACK, "[WARNING]" ), nWorldID - PWorlds::mAptBaseWorldId );
+ return false;
+ }
+ const PDefAppartement* nAppDef = GameDefs->Appartements()->GetDef( AptTmplID );
+ if ( !nAppDef )
+ {
+ Console->Print( "%s PWorld::Load - invalid apt type %d", Console->ColorText( RED, BLACK, "[WARNING]" ), AptTmplID );
+ return false;
+ }
+ WorldTemplateName = nAppDef->GetWorldName();
+
+ tFileName = std::string( "worlds/" ) + WorldTemplateName + ".dat";
+ tCheckOK = Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName );
+ if ( !tCheckOK )
+ {
+ tFileName = WorldTemplateName + ".dat";
+ tCheckOK = Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName );
+ }
+ if ( !tCheckOK )
+ {
+ Console->Print( "%s PWorld::Load - unable to lease apt world %s (%s)", Console->ColorText( RED, BLACK, "[WARNING]" ), WorldTemplateName.c_str(), tFileName.c_str() );
+ return false;
+ }
+ }
+ else
+ {
+ const PDefWorldFile* nWorldFileDef;
+
+ if (( nWorldID > 90000 ) && ( nWorldID < 90017 ) ) // hardcoded holomatch hack
+ {
+ nWorldFileDef = NULL;
+ char worldName[19];
+ int MatchID = nWorldID - 90000;
+ if ( MatchID > 8 ) // to care for Neofrag 1 & 2
+ MatchID -= 8;
+ if ( MatchID > 6 )
+ MatchID = 6; // holomatch 7 and 8 are same as 6
+ snprintf( worldName, 19, "holomatch/neofrag%d", MatchID );
+ WorldTemplateName = worldName;
+ }
+ else
+ {
+ nWorldFileDef = GameDefs->WorldFiles()->GetDef( nWorldID );
+ if ( !nWorldFileDef )
+ return false;
+ WorldTemplateName = nWorldFileDef->GetName();
+ }
+
+ const PDefWorld* tWorldDef = GameDefs->Worlds()->GetDef( nWorldID );
+ if ( tWorldDef ) // should always be true here
+ {
+ if ( !( tWorldDef->GetDatFile().empty() ) )
+ tFileName = tWorldDef->GetDatFile();
+ else if ( nWorldFileDef )
+ tFileName = nWorldFileDef->GetBasicFileName() + ".dat";
+ else
+ {
+ tFileName = "worlds/";
+ tFileName += WorldTemplateName;
+ tFileName += ".dat";
+ }
+ }
+ else
+ return false; // should'nt happen here
+
+ if ( !Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName ) )
+ return false;
+ }
+
+ mWorldDataTemplate = Worlds->GetWorldDataTemplate( tFileName );
+ if ( !mWorldDataTemplate )
+ {
+ Console->Print( "%s PWorld::Load : Unexpected world %d not found error", Console->ColorText( RED, BLACK, "[WARNING]" ), nWorldID );
+ return false;
+ }
+
+ mID = nWorldID;
+ mSpawnedVehicles.SetLocation( nWorldID );
+ // furniture & other world stuff loading here
+ Console->Print( "%s Loaded world %d", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), nWorldID );
+ return true;
+}
+
+std::string PWorld::GetName()
+{
+ return ( mWorldDataTemplate ? mWorldDataTemplate->GetName() : EmptyString );
+}
+
+std::string PWorld::GetBspName()
+{
+ return ( mWorldDataTemplate ? mWorldDataTemplate->GetBspName() : EmptyString );
+}
+
+bool PWorld::IsAppartment()
+{
+ return mIsAppartment;
+}
+
+const PFurnitureItemTemplate *PWorld::GetFurnitureItemTemplate( uint32_t nItemID )
+{
+ return ( mWorldDataTemplate ? mWorldDataTemplate->GetFurnitureItem( nItemID ) : NULL ) ;
+}
+
+const PDefWorldModel *PWorld::GetFurnitureItemModel(uint32_t nItemID)
+{
+ if ( mWorldDataTemplate )
+ {
+ const PFurnitureItemTemplate* tFurniture = mWorldDataTemplate->GetFurnitureItem( nItemID );
+ if ( tFurniture )
+ return tFurniture->GetDefWorldModel();
+ }
+ return nullptr;
+}
+
+const PDoorTemplate *PWorld::GetDoor(uint32_t nDoorID)
+{
+ return (mWorldDataTemplate ? mWorldDataTemplate->GetDoor(nDoorID) : nullptr);
+}
+
+bool PWorld::getPositionItemPosition(uint8_t PosID, float *pX, float *pY, float *pZ)
+{
+ return (mWorldDataTemplate ? mWorldDataTemplate->getPositionItemPosition(PosID, pX, pY, pZ) : false);
+}
+
+bool PWorld::CharUseChair( int CharLocalID, uint32_t nItemID )
+{
+ PChairsInUseMap::iterator it = mChairsInUseMap.find( nItemID );
+ if ( it == mChairsInUseMap.end() ) // chair is free
+ {
+ if ( gDevDebug )
+ Console->Print( "%s Localchar %d now using free chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID );
+ mChairsInUseMap.insert( std::make_pair( nItemID, CharLocalID ) );
+ return true;
+ }
+ else // chair is already in use
+ {
+ if ( gDevDebug )
+ {
+ if ( it->second == CharLocalID )
+ {
+ Console->Print( "%s Localchar %d already using chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID );
+ }
+ else
+ {
+ Console->Print( "%s Localchar %d can't sit on chair %d used by localchar %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID, it->second );
+ }
+ }
+ return ( it->second == CharLocalID );
+ }
+}
+
+void PWorld::CharLeaveChair( int CharLocalID, uint32_t nItemID )
+{
+ PChairsInUseMap::iterator it = mChairsInUseMap.find( nItemID );
+ if (( it != mChairsInUseMap.end() ) && ( it->second == CharLocalID ) ) // chair is in use by this char
+ {
+ if ( gDevDebug )
+ Console->Print( "%s Localchar %d leaving chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID );
+ mChairsInUseMap.erase( it );
+ }
+}
+
+PClient* PWorld::GetClientByCharLocalId( uint32_t rawObjectId ) const
+{
+ // Temp implementation
+ return ClientManager->GetClientByCharLocalId( rawObjectId, mID );
+}
+
+PSpawnedVehicles *PWorld::GetSpawnedVehicles()
+{
+ return &mSpawnedVehicles;
+}
+
+bool PWorld::CheckVhcNeedZoning( PVhcCoordinates const* nPos ) const
+{
+ if ( ( nPos->GetX() <= mBottomZoneOutLimit ) || ( nPos->GetX() >= mTopZoneOutLimit ) || ( nPos->GetY() <= mBottomZoneOutLimit ) || ( nPos->GetY() >= mTopZoneOutLimit ) )
+ return true;
+ else
+ return false;
+}
+
+uint32_t PWorld::GetVhcZoningDestination( PSpawnedVehicle const* nVhc, PVhcCoordinates* nPos ) const
+{
+ uint32_t destWorldId = 0;
+ int16_t vChange = 0;
+ int16_t hChange = 0;
+ PVhcCoordinates const vhcPos = nVhc->GetPosition();
+ uint16_t posX = vhcPos.GetX();
+ uint16_t posY = vhcPos.GetY();
+
+ if ( posX <= mBottomZoneOutLimit )
+ {
+ vChange = 1;
+ }
+ else if ( posX >= mTopZoneOutLimit )
+ {
+ vChange = -1;
+ }
+
+ if ( posY <= mBottomZoneOutLimit )
+ {
+ hChange = -1;
+ }
+ else if ( posY >= mTopZoneOutLimit )
+ {
+ hChange = 1;
+ }
+
+ if ( vChange || hChange )
+ {
+ //Console->Print( YELLOW, BLACK, "[DEBUG] Limit Reached V:%d H:%d mapId:%d", vChange,hChange,mID );
+ uint8_t currH = 0;
+ uint8_t currV = 0;
+ int16_t newH, newV;
+
+ if ( Worlds->GetWorldmapFromWorldId( mID, currH, currV ) )
+ {
+ //Console->Print( YELLOW, BLACK, "[DEBUG] current map pos V:%d H:%d", currV,currH );
+ newH = currH + hChange;
+ if ( newH < 0 )
+ newH = 0;
+ else if ( newH >= PWorlds::mOutdoorWorldmapHSize )
+ newH = PWorlds::mOutdoorWorldmapHSize;
+
+ newV = currV + vChange;
+ if ( newV < 0 )
+ newV = 0;
+ else if ( newV >= PWorlds::mOutdoorWorldmapHSize )
+ newV = PWorlds::mOutdoorWorldmapHSize;
+
+ //Console->Print( YELLOW, BLACK, "[DEBUG] new map pos V:%d H:%d", newV,newH );
+ if (( newH != currH ) || ( newV != currV ) )
+ {
+ destWorldId = Worlds->GetWorldIdFromWorldmap( newH, newV );
+
+ if ( destWorldId && nPos )
+ {
+ if ( vChange == 1 )
+ posX = mTopZoneInLimit;
+ else if ( vChange == -1 )
+ posX = mBottomZoneInLimit;
+
+ if ( hChange == -1 )
+ posY = mTopZoneInLimit;
+ else if ( hChange == 1 )
+ posY = mBottomZoneInLimit;
+
+ nPos->SetPosition( posY, vhcPos.GetZ(), posX, vhcPos.GetUD(), vhcPos.GetLR(), vhcPos.GetRoll(), vhcPos.GetAct(), vhcPos.GetUnknown(), vhcPos.GetFF() );
+ }
+ }
+ }
+ }
+
+ return destWorldId;
+}
+
+const PNPCsMap *PWorld::GetNPCMap() const
+{
+ return (mWorldDataTemplate ? mWorldDataTemplate->GetNPCMap() : nullptr);
+}
+
+const PNPCTemplate *PWorld::GetNPCTemplate(uint32_t nNPCID) const
+{
+ return (mWorldDataTemplate ? mWorldDataTemplate->GetNPC(nNPCID) : nullptr);
+}
+
+/**** PWorlds ****/
+uint32_t const PWorlds::mNcSubwayWorldId = 1000;
+uint32_t const PWorlds::mAptBaseWorldId = 100000;
+uint32_t const PWorlds::mOutdoorBaseWorldId = 2001;
+uint32_t const PWorlds::mOutdoorWorldIdVIncrement = 20;
+uint8_t const PWorlds::mOutdoorWorldmapHSize = 16;
+uint8_t const PWorlds::mOutdoorWorldmapVSize = 11;
+uint32_t const PWorlds::mOutdoorMaxWorldId = PWorlds::mOutdoorBaseWorldId + PWorlds::mOutdoorWorldIdVIncrement * ( PWorlds::mOutdoorWorldmapVSize - 1 ) + PWorlds::mOutdoorWorldmapHSize - 1;
+
+PWorlds::PWorlds()
+{
+ mPreloadWorldsTemplates = false; // to be put as config option
+ mPreloadStaticWorlds = false; // to be put as config option
+}
+
+PWorlds::~PWorlds()
+{
+ for ( PWorldsMap::iterator i = mStaticWorldsMap.begin(); i != mStaticWorldsMap.end(); i++ )
+ if ( i->second )
+ {
+ delete i->second;
+ }
+ for ( PWorldsMap::iterator i = mOnDemandWorldsMap.begin(); i != mOnDemandWorldsMap.end(); i++ )
+ if ( i->second )
+ {
+ delete i->second;
+ }
+ for ( PWorldDataTemplatesMap::iterator i = mWorldDataTemplatesMap.begin(); i != mWorldDataTemplatesMap.end(); i++ )
+ if ( i->second )
+ {
+ delete i->second;
+ }
+}
+
+bool PWorlds::LeaseWorldDataTemplate( const std::string& nBspName, const std::string& nFileName, const bool nPreloadPhase )
+{
+ PWorldDataTemplate* tWorldDataTemplate;
+
+ PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName );
+ if ( it == mWorldDataTemplatesMap.end() ) // template unkown yet
+ {
+ if ( nPreloadPhase ) // if in preload phase, we try to load it or make it known
+ {
+ tWorldDataTemplate = new PWorldDataTemplate;
+ if ( tWorldDataTemplate->LoadDatFile( nBspName, nFileName, !mPreloadWorldsTemplates ) )
+ {
+ if ( mPreloadWorldsTemplates )
+ {
+ mWorldDataTemplatesMap.insert( std::make_pair( nFileName, tWorldDataTemplate ) );
+ tWorldDataTemplate->IncreaseUseCount();
+ }
+ else
+ {
+ mWorldDataTemplatesMap.insert( std::make_pair( nFileName, ( PWorldDataTemplate* )NULL ) ); // NULL means file access OK but not preloaded yet
+ delete tWorldDataTemplate;
+ }
+ //return true;
+ }
+ else
+ {
+ delete tWorldDataTemplate;
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else // template already known
+ {
+ if ( !it->second && !nPreloadPhase ) // template known but not already loaded and not in preload ?
+ {
+ tWorldDataTemplate = new PWorldDataTemplate;
+ if ( tWorldDataTemplate->LoadDatFile( nBspName, nFileName ) )
+ {
+ it->second = tWorldDataTemplate;
+ }
+ else
+ {
+ Console->Print( "%s Invalid world data template file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), nFileName.c_str() );
+ mWorldDataTemplatesMap.erase( it );
+ delete tWorldDataTemplate;
+ return false;
+ }
+ }
+
+ if ( !nPreloadPhase )
+ it->second->IncreaseUseCount();
+
+ //return true;
+ }
+
+ return true;
+}
+
+void PWorlds::ReleaseWorldDataTemplate( const std::string& nFileName )
+{
+ PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName );
+ if (( it != mWorldDataTemplatesMap.end() ) && it->second )
+ {
+ it->second->DecreaseUseCount();
+ }
+ else
+ Console->Print( "%s PWorlds::ReleaseWorldDataTemplate : try to relese not loaded template %s", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() );
+}
+
+void PWorlds::UnloadWorldDataTemplate( const std::string& nFileName )
+{
+ PWorldDataTemplate* tWorldDataTemplate;
+
+ PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName );
+ if (( it != mWorldDataTemplatesMap.end() ) && it->second )
+ {
+ tWorldDataTemplate = it->second;
+ if ( mPreloadWorldsTemplates || ( tWorldDataTemplate->GetUseCount() > 0 ) )
+ Console->Print( "%s PWorlds::UnloadWorldDataTemplate : attempt to unload template %s when use count not null ou preload set", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() );
+ else
+ {
+ it->second = ( PWorldDataTemplate* )NULL;
+ delete tWorldDataTemplate;
+ }
+ }
+ else
+ Console->Print( "%s PWorlds::UnloadWorldDataTemplate : attempt to release not loaded template %s", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() );
+}
+
+PWorldDataTemplate* PWorlds::GetWorldDataTemplate( const std::string& nFileName )
+{
+ PWorldDataTemplatesMap::const_iterator it = mWorldDataTemplatesMap.find( nFileName );
+ if ( it != mWorldDataTemplatesMap.end() )
+ return it->second;
+ else
+ return NULL;
+}
+
+bool PWorlds::LoadWorlds() // once Load is done, only WorldDataTemplate registred in mWorldDataTemplatesMap
+{
+ // will be considered as valid
+ std::string tFileName;
+ std::string tBspName;
+ const PDefWorld* tDefWorld;
+ bool tCheckOK;
+ int ValidCount = 0, InvalidCount = 0, DblInvCount = 0;
+ int DatTmplCount, BadDatTmplCount;
+ std::set<std::string>
+ InvalideFiles;
+
+ // Appartment templates checking or preloading
+ std::map<int, PDefAppartement*>::const_iterator itAptStart = GameDefs->Appartements()->ConstIteratorBegin();
+ std::map<int, PDefAppartement*>::const_iterator itAptEnd = GameDefs->Appartements()->ConstIteratorEnd();
+ for ( std::map<int, PDefAppartement*>::const_iterator i = itAptStart; i != itAptEnd; i++ )
+ {
+ tCheckOK = false;
+ tBspName = i->second->GetWorldName();
+ tFileName = std::string( "worlds/" ) + tBspName + ".dat";
+ if ( !InvalideFiles.count( tFileName ) )
+ {
+ tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true );
+ if ( !tCheckOK )
+ {
+ InvalideFiles.insert( tFileName );
+ if ( gDevDebug )
+ Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() );
+ }
+ }
+ if ( !tCheckOK ) // in case full path was given without omiting worlds/ or in another dir/archive ...
+ {
+ tFileName = tBspName + ".dat";
+ if ( !InvalideFiles.count( tFileName ) )
+ {
+ tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true );
+ if ( !tCheckOK )
+ {
+ InvalideFiles.insert( tFileName );
+ ++DblInvCount;
+ }
+ }
+ }
+
+ if ( tCheckOK )
+ {
+ ++ValidCount;
+ if ( gDevDebug )
+ Console->Print( GREEN, BLACK, "Template file %s for appartment %d (%s) loaded", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() );
+ }
+ else
+ {
+ ++InvalidCount;
+ if ( gDevDebug )
+ Console->Print( RED, BLACK, "Template file %s for appartment %d (%s) not available or invalid", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() );
+ }
+ }
+
+ DatTmplCount = mWorldDataTemplatesMap.size();
+ BadDatTmplCount = InvalideFiles.size();
+ Console->Print( "%s %d valid appartement templates checked (%d dat files)", Console->ColorText( GREEN, BLACK, "[Success]" ), ValidCount, DatTmplCount );
+ if ( InvalidCount )
+ Console->Print( "%s %d invalid appartement templates rejected (%d dat files)", Console->ColorText( YELLOW, BLACK, "[Notice]" ), InvalidCount, BadDatTmplCount - DblInvCount );
+
+ // Static worlds & static worlds templates checking or preloading
+ ValidCount = InvalidCount = 0;
+ const PDefWorldFile* tDefWorldFile;
+ std::map<int, PDefWorldFile*>::const_iterator itFilStart = GameDefs->WorldFiles()->ConstIteratorBegin();
+ std::map<int, PDefWorldFile*>::const_iterator itFilEnd = GameDefs->WorldFiles()->ConstIteratorEnd();
+ for ( std::map<int, PDefWorldFile*>::const_iterator i = itFilStart; i != itFilEnd; i++ )
+ {
+ tDefWorldFile = i->second;
+
+ tDefWorld = GameDefs->Worlds()->GetDef( tDefWorldFile->GetIndex() );
+ if ( tDefWorld ) // we only care for worlds that are present in worldinfo.def too
+ {
+ tBspName = tDefWorldFile->GetName();
+ if ( !( tDefWorld->GetDatFile().empty() ) )
+ tFileName = tDefWorld->GetDatFile();
+ else
+ tFileName = i->second->GetBasicFileName() + ".dat";
+
+ tCheckOK = false;
+ if ( !InvalideFiles.count( tFileName ) )
+ {
+ tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true );
+ if ( !tCheckOK )
+ {
+ InvalideFiles.insert( tFileName );
+ if ( gDevDebug )
+ Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() );
+ }
+ }
+
+ if ( tCheckOK )
+ {
+ ++ValidCount;
+ if ( mPreloadStaticWorlds )
+ {
+ LeaseWorld( tDefWorldFile->GetIndex(), true ); // This will make the world ready and kept in mem (use count always >0 )
+ }
+ else
+ {
+ mStaticWorldsMap.insert( std::make_pair( tDefWorldFile->GetIndex(), ( PWorld* )NULL ) );
+ }
+ if ( gDevDebug )
+ Console->Print( GREEN, BLACK, "Template file %s for world %d (%s) loaded", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() );
+ }
+ else
+ {
+ ++InvalidCount;
+ if ( gDevDebug )
+ Console->Print( RED, BLACK, "Template file %s for world %d (%s) not available or invalid", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() );
+ }
+ }
+ }
+
+ // Hardcoded neofrag worlds ... oO ... and neofrag4.dat can't be found :-/
+ for ( int i = 1; i <= 16; i++ )
+ {
+ char worldName[19];
+ int MatchID = i;
+ if ( MatchID > 8 ) // to care for Neofrag 1 & 2
+ MatchID -= 8;
+ if ( MatchID > 6 )
+ MatchID = 6; // holomatch 7 and 8 are same as 6
+ snprintf( worldName, 19, "holomatch/neofrag%d", MatchID );
+
+ tDefWorld = GameDefs->Worlds()->GetDef( 90000 + i );
+ if ( tDefWorld ) // we only care for worlds that are present in worldinfo.def too
+ {
+ if ( !( tDefWorld->GetDatFile().empty() ) )
+ tFileName = tDefWorld->GetDatFile();
+ else
+ {
+ tFileName = "worlds/";
+ tFileName += worldName;
+ tFileName += ".dat";
+ }
+
+ tCheckOK = false;
+ if ( !InvalideFiles.count( tFileName ) )
+ {
+ tCheckOK = LeaseWorldDataTemplate( worldName, tFileName, true );
+ if ( !tCheckOK )
+ {
+ InvalideFiles.insert( tFileName );
+ if ( gDevDebug )
+ Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() );
+ }
+ }
+
+ if ( tCheckOK )
+ {
+ ++ValidCount;
+ if ( mPreloadStaticWorlds )
+ {
+ LeaseWorld( 90000 + i, true ); // This will make the world ready and kept in mem (use count always >0 )
+ }
+ else
+ {
+ mStaticWorldsMap.insert( std::make_pair( 90000 + i, ( PWorld* )NULL ) );
+ }
+ if ( gDevDebug )
+ Console->Print( GREEN, BLACK, "Template file %s for world %d (%s) loaded", tFileName.c_str(), 90000 + i, worldName );
+ }
+ else
+ {
+ ++InvalidCount;
+ if ( gDevDebug )
+ Console->Print( RED, BLACK, "Template file %s for world %d (%s) not available or invalid", tFileName.c_str(), 90000 + i, worldName );
+ }
+ }
+ }
+
+ Console->Print( "%s %d valid world templates checked (%d dat files)", Console->ColorText( GREEN, BLACK, "[Success]" ), ValidCount, mWorldDataTemplatesMap.size() - DatTmplCount );
+ if ( InvalidCount )
+ Console->Print( "%s %d invalid world templates rejected (%d dat files)", Console->ColorText( YELLOW, BLACK, "[Notice]" ), InvalidCount, InvalideFiles.size() - BadDatTmplCount - DblInvCount );
+ Console->Print( "%s %d static worlds prepared", Console->ColorText( GREEN, BLACK, "[Success]" ), mStaticWorldsMap.size() );
+
+ // release memory if World templates preload activated, this cache that won't be used anymore
+ // if (mPreloadWorldsTemplates) Filesystem->ClearCache();
+
+ return true;
+}
+
+bool PWorlds::IsValidWorld( uint32_t nWorldID ) const
+{
+ if ( nWorldID > PWorlds::mAptBaseWorldId )
+ {
+ if ( mOnDemandWorldsMap.count( nWorldID ) ) // Check if already loaded
+ return true;
+ else //should better do a check using a PAppartements class object to get the world template
+ {
+ //int AptTmplID = Appartements->GetAptType(nWorldID - PWorlds::mAptBaseWorldId);
+ int AptTmplID = Appartements->GetAptType( nWorldID );
+ if ( !AptTmplID )
+ return false;
+
+ const PDefAppartement* nAppDef = GameDefs->Appartements()->GetDef( AptTmplID );
+ if ( !nAppDef )
+ return false;
+
+ std::string tFileName = "worlds/" + nAppDef->GetWorldName() + ".dat";
+ PWorldDataTemplatesMap::const_iterator it = mWorldDataTemplatesMap.find( tFileName );
+ return ( it != mWorldDataTemplatesMap.end() );
+ }
+ }
+ else
+ {
+ if ( gDevDebug )
+ Console->Print( "%s Checking validity for world %d : %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID, mStaticWorldsMap.count( nWorldID ) ? "OK" : "BAD" );
+ return ( mStaticWorldsMap.count( nWorldID ) );
+ }
+}
+
+PWorld* PWorlds::LeaseWorld( uint32_t nWorldID, const bool nPreloadPhase )
+{
+ PWorldsMap::iterator it;
+
+ if ( nWorldID > PWorlds::mAptBaseWorldId )
+ {
+ it = mOnDemandWorldsMap.find( nWorldID ); // Check if already loaded
+ if (( it != mOnDemandWorldsMap.end() ) && it->second ) // Dynamic world shall not have a NULL it->second
+ {
+ // if loaded
+ it->second->IncreaseUseCount();
+ if ( gDevDebug )
+ Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID );
+ return it->second;
+ }
+ else // not loaded yet or invalid
+ {
+ PWorld* nWorld = new PWorld;
+ if ( ! nWorld->Load( nWorldID ) ) // Error when loading (shouldn't happen)
+ {
+ delete nWorld;
+ Console->Print( "% Could not load world %d - World now set as invalid", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );
+ return NULL;
+ }
+ else
+ {
+ mOnDemandWorldsMap.insert( std::make_pair( nWorldID, nWorld ) );
+ nWorld->IncreaseUseCount();
+ if ( gDevDebug )
+ Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID );
+ return nWorld;
+ }
+ }
+ }
+ else
+ {
+ it = mStaticWorldsMap.find( nWorldID ); // Check if already loaded
+ if (( it == mStaticWorldsMap.end() ) && nPreloadPhase )
+ {
+ mStaticWorldsMap.insert( std::make_pair( nWorldID, ( PWorld* )NULL ) );
+ it = mStaticWorldsMap.find( nWorldID );
+ }
+ if ( it != mStaticWorldsMap.end() )
+ {
+ // if valid
+ if ( ! it->second ) // if not loaded yet
+ {
+ it->second = new PWorld;
+ if ( ! it->second->Load( nWorldID ) ) // Error when loading (shouldn't happen)
+ {
+ delete it->second;
+ Console->Print( "%s Could not load world %d - World now set as invalid", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );
+ mStaticWorldsMap.erase( it ); // remove from valid worlds map
+ return NULL;
+ }
+ }
+ it->second->IncreaseUseCount();
+ if ( gDevDebug )
+ Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID );
+ return it->second;
+ }
+ else // invalid worldID
+ {
+ return NULL;
+ }
+ }
+}
+
+PWorld* PWorlds::GetWorld( uint32_t nWorldID )
+{
+ PWorldsMap* tMap;
+ PWorldsMap::iterator it;
+
+ tMap = (( nWorldID > PWorlds::mAptBaseWorldId ) ? &mOnDemandWorldsMap : &mStaticWorldsMap );
+
+ it = tMap->find( nWorldID );
+ if (( it != tMap->end() ) && it->second )
+ {
+ return it->second;
+ }
+ else
+ {
+ Console->Print( "%s PWorlds::GetWorld : Trying to get world %d without lease !", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );
+ return NULL;
+ }
+}
+
+void PWorlds::ReleaseWorld( uint32_t nWorldID ) // no dynamic unload is performed atm + don't forget spawned vhc !
+{
+ PWorld* tWorld = GetWorld( nWorldID );
+ if ( tWorld )
+ {
+ if ( tWorld->GetUseCount() ) // this check is for dev time only
+ {
+ tWorld->DecreaseUseCount();
+ if ( gDevDebug )
+ Console->Print( "%s Released world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID );
+ }
+ else
+ {
+ Console->Print( "%s PWorlds::ReleaseWorld : Trying to release world %d with use count 0 !", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );
+ }
+ }
+ else
+ {
+ Console->Print( "%s PWorlds::ReleaseWorld : Generated the invalid get world %d", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID );
+ }
+}
+
+bool PWorlds::IsAppartment( uint32_t nWorldID )
+{
+ return (( nWorldID > PWorlds::mAptBaseWorldId ) && IsValidWorld( nWorldID ) );
+}
+
+void PWorlds::Update()
+{}
+
+void PWorlds::Shutdown()
+{}
+
+uint32_t PWorlds::GetWorldIdFromWorldmap( uint8_t mapH, uint8_t mapV ) const
+{
+ uint32_t loc = 0;
+ if (( mapH < mOutdoorWorldmapHSize ) && ( mapV < mOutdoorWorldmapVSize ) )
+ {
+ loc = mOutdoorBaseWorldId + mOutdoorWorldIdVIncrement * mapV + mapH;
+ if ( ! IsValidWorld( loc ) )
+ loc = 0;
+ }
+ return loc;
+}
+
+bool PWorlds::GetWorldmapFromWorldId( uint32_t nWorldId, uint8_t& mapH, uint8_t& mapV ) const
+{
+ if (( nWorldId >= mOutdoorBaseWorldId ) && ( nWorldId <= mOutdoorMaxWorldId ) )
+ {
+ mapV = ( nWorldId - mOutdoorBaseWorldId ) / mOutdoorWorldIdVIncrement;
+ mapH = ( nWorldId - mOutdoorBaseWorldId ) % mOutdoorWorldIdVIncrement;
+ return true;
+ }
+ return false;
+}
-#include "GameServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-// TODO: Put get the fallback world from config\r
-// Check for file existence before sending info to client to avoid client crash and bad location in char info\r
-\r
-void SendZone(PClient *Client, uint32_t loc)\r
-{\r
- //TODO : FIX case for worldroute and 5 missing id 505\r
- std::string worldName;\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
- //PChar *Char = Chars->GetChar(Client->GetCharID());\r
-\r
- Socket->SetTimeOutValue(0xffff);\r
-\r
- PWorld* CurrentWorld = Worlds->GetWorld(loc);\r
- if (CurrentWorld)\r
- {\r
- worldName = CurrentWorld->GetBspName();\r
- if (worldName.empty())\r
- {\r
- worldName = "plaza/plaza_p1"; // Should be a config entry\r
- Console->Print("Client %d: Empty name for world %d. Redirecting to %s", Console->ColorText(RED, BLACK, "Warning"), Client->GetID(), loc, worldName.c_str());\r
- loc = 1;\r
- }\r
- }\r
- else\r
- {\r
- worldName = "plaza/plaza_p1"; // Should be a config entry\r
- Console->Print("Client %d: Invalid or not loaded world %d. Redirecting to %s", Console->ColorText(YELLOW, BLACK, "Warning"), Client->GetID(), loc, worldName.c_str());\r
- loc = 1;\r
- }\r
-\r
- PMessage* cMsg = MsgBuilder->BuildSendZoneTCPMsg(loc, &worldName);\r
- Client->SendTCPMessage(cMsg);\r
-}\r
+#include "GameServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+// TODO: Put get the fallback world from config
+// Check for file existence before sending info to client to avoid client crash and bad location in char info
+
+void SendZone(PClient *Client, uint32_t loc)
+{
+ //TODO : FIX case for worldroute and 5 missing id 505
+ std::string worldName;
+ ConnectionTCP *Socket = Client->getTCPConn();
+ //PChar *Char = Chars->GetChar(Client->GetCharID());
+
+ Socket->SetTimeOutValue(0xffff);
+
+ PWorld* CurrentWorld = Worlds->GetWorld(loc);
+ if (CurrentWorld)
+ {
+ worldName = CurrentWorld->GetBspName();
+ if (worldName.empty())
+ {
+ worldName = "plaza/plaza_p1"; // Should be a config entry
+ Console->Print("Client %d: Empty name for world %d. Redirecting to %s", Console->ColorText(RED, BLACK, "Warning"), Client->GetID(), loc, worldName.c_str());
+ loc = 1;
+ }
+ }
+ else
+ {
+ worldName = "plaza/plaza_p1"; // Should be a config entry
+ Console->Print("Client %d: Invalid or not loaded world %d. Redirecting to %s", Console->ColorText(YELLOW, BLACK, "Warning"), Client->GetID(), loc, worldName.c_str());
+ loc = 1;
+ }
+
+ PMessage* cMsg = MsgBuilder->BuildSendZoneTCPMsg(loc, &worldName);
+ Client->SendTCPMessage(cMsg);
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-\r
-class PClient;\r
-\r
-//void SendZone(PClient *Client, PGameState *State,int loc);\r
-void SendZone(PClient *Client, uint32_t loc);\r
+#pragma once
+
+#include <cstdint>
+
+class PClient;
+
+//void SendZone(PClient *Client, PGameState *State,int loc);
+void SendZone(PClient *Client, uint32_t loc);
-#include "InfoServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-/*\r
-NOTE ABOUT ACCESS LEVELS IN THE MYSQL DATABASE:\r
-a_priv:\r
-0 = unregistered user\r
-1 = Registered user\r
-30 = volunteer\r
-50 = GM\r
-100 = Admin\r
-\r
-a_status:\r
-0 = Offline\r
-1 = Online\r
-2 = Banned\r
-*/\r
-\r
-/** Static members **/\r
-RegEx* PAccount::mUsernameRegexFilter = nullptr;\r
-RegEx* PAccount::mPasswordRegexFilter = nullptr;\r
-\r
-bool PAccount::SetUsernameRegexFilter(const char* RegexStr)\r
-{\r
- if(mUsernameRegexFilter)\r
- {\r
- delete mUsernameRegexFilter;\r
- mUsernameRegexFilter = NULL;\r
- }\r
-\r
- if(RegexStr)\r
- {\r
- try {\r
- mUsernameRegexFilter = new RegEx(RegexStr, PCRE_CASELESS);\r
- }\r
- catch (...) {\r
- return false;\r
- }\r
- }\r
- return true;\r
-}\r
-\r
-bool PAccount::SetPasswordRegexFilter(const char* RegexStr)\r
-{\r
- if(mPasswordRegexFilter)\r
- {\r
- delete mPasswordRegexFilter;\r
- mPasswordRegexFilter = NULL;\r
- }\r
-\r
- if(RegexStr)\r
- {\r
- try {\r
- mPasswordRegexFilter = new RegEx(RegexStr, PCRE_CASELESS);\r
- }\r
- catch (...) {\r
- return false;\r
- }\r
- }\r
- return true;\r
-}\r
-\r
-bool PAccount::IsUsernameWellFormed(const char *Username)\r
-{\r
- if(mUsernameRegexFilter)\r
- {\r
- return mUsernameRegexFilter->Search(Username);\r
- }\r
- else\r
- return true;\r
-}\r
-\r
-bool PAccount::IsPasswordWellFormed(const char *Password)\r
-{\r
- if(mPasswordRegexFilter)\r
- {\r
- return mPasswordRegexFilter->Search(Password);\r
- }\r
- else\r
- return true;\r
-}\r
-\r
-/** Instance members **/\r
-PAccount::PAccount()\r
-{\r
- mID = 0;\r
- mLevel = PAL_BANNED;\r
- mStatus = PAS_OFFLINE;\r
- mBannedUntil = 0;\r
-}\r
-\r
-PAccount::PAccount(const uint32_t AccountId)\r
-{\r
- char query[256];\r
- mID = 0;\r
- snprintf(query, 256, "SELECT * FROM accounts WHERE a_id = %d LIMIT 1;", AccountId);\r
- LoadFromQuery(query);\r
-}\r
-\r
-PAccount::PAccount(const char *Username)\r
-{\r
- char query[256];\r
- mID = 0;\r
- if(IsUsernameWellFormed(Username)) {\r
- char escUsername[256];\r
- MySQL->EscapeString(Username, escUsername, 256);\r
- snprintf(query, 256, "SELECT * FROM accounts WHERE a_username = '%s' LIMIT 1;", escUsername);\r
- LoadFromQuery(query);\r
- }\r
-}\r
-\r
-bool PAccount::LoadFromQuery(char* query)\r
-{\r
- MYSQL_ROW row = 0;\r
- MYSQL_RES *result = 0;\r
-\r
- bool FinalResult = false;\r
-\r
- //result = MySQL->InfoResQuery(query);\r
- result = MySQL->ResQuery(query);\r
- if(result == NULL)\r
- {\r
- Console->Print(RED, BLACK, "Failed to load AccountData from SQL");\r
- //MySQL->ShowInfoSQLError();\r
- MySQL->ShowSQLError();\r
- return false;\r
- }\r
-\r
- if((row = mysql_fetch_row(result)))\r
- {\r
- mID = atoi(row[a_id]);\r
- mName = row[a_username];\r
- mPassword = row[a_password];\r
-\r
- mBannedUntil = atoi(row[a_bandate]);\r
- if(mBannedUntil > std::time(NULL))\r
- {\r
- mStatus = PAS_BANNED;\r
- mLevel = PAL_BANNED;\r
- }\r
- else\r
- {\r
- mStatus = PAS_OFFLINE;\r
- mLevel = atoi(row[a_priv]);\r
- }\r
-\r
- FinalResult = true;\r
- }\r
- else\r
- {\r
-Console->Print(YELLOW, BLACK, "Failed to load AccountData from SQL; Nothing to load...");\r
- }\r
-\r
- //MySQL->FreeInfoSQLResult(result);\r
- MySQL->FreeSQLResult(result);\r
- return FinalResult;\r
-}\r
-\r
-uint32_t PAccount::GetID() const\r
-{\r
- return mID;\r
-}\r
-\r
-bool PAccount::SetName(const std::string &Username)\r
-{\r
- if(IsUsernameWellFormed(Username.c_str()))\r
- {\r
- mName = Username;\r
- return true;\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-}\r
-\r
-const std::string &PAccount::GetName() const\r
-{\r
- return mName;\r
-}\r
-\r
-bool PAccount::SetPassword(const std::string &Password)\r
-{\r
- if(IsPasswordWellFormed(Password.c_str()))\r
- {\r
- mPassword = Password;\r
- return true;\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-}\r
-\r
-bool PAccount::SetPasswordEncoded(const uint8_t* PasswordData, int PassLen, const uint8_t* Key)\r
-{\r
- char Pass[128];\r
-\r
- if(DecodePassword(PasswordData, PassLen, Key, Pass))\r
- {\r
- return SetPassword((std::string)Pass);\r
- }\r
- else\r
- {\r
- Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen);\r
- return false;\r
- }\r
-}\r
-\r
-const std::string &PAccount::GetPassword() const\r
-{\r
- return mPassword;\r
-}\r
-\r
-bool PAccount::SetLevel(int newLevel)\r
-{\r
- if((newLevel >= PAL_BANNED) && (newLevel <= PAL_ADMIN))\r
- {\r
- mLevel = newLevel;\r
- return true;\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-}\r
-\r
-int32_t PAccount::GetLevel() const\r
-{\r
- return mLevel;\r
-}\r
-\r
-std::string PAccount::GetLevelString() const\r
-{\r
- switch(mLevel)\r
- {\r
- case PAL_BANNED : return "banned";\r
- case PAL_UNREGPLAYER : return "unregplayer";\r
- case PAL_REGPLAYER : return "regplayer";\r
- case PAL_VOLUNTEER : return "volunteer";\r
- case PAL_GM : return "gm";\r
- case PAL_ADMIN : return "admin";\r
- }\r
-\r
- return "custom";\r
-}\r
-\r
-bool PAccount::SetStatus(PAccountStatus Status)\r
-{\r
- mStatus = Status;\r
- return true;\r
-}\r
-\r
-PAccountStatus PAccount::GetStatus() const\r
-{\r
- return mStatus;\r
-}\r
-\r
-bool PAccount::SetBannedUntilTime(std::time_t BannedUntil)\r
-{\r
- if ((BannedUntil == 0) || (BannedUntil > std::time(NULL)))\r
- {\r
- mBannedUntil = BannedUntil;\r
- return true;\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-}\r
-\r
-bool PAccount::IsBanned() const\r
-{\r
- return (mBannedUntil > std::time(nullptr));\r
-}\r
-\r
-bool PAccount::DecodePassword(const uint8_t* PasswordData, int PassLen, const uint8_t *Key, char* ClearPassword)\r
-{\r
- ClearPassword[0] = 0;\r
-\r
- if(PassLen < 128)\r
- {\r
- if(Key[0]>7) // TODO: >7 correct?\r
- {\r
- for(int i=0; i<PassLen; i+=2)\r
- ClearPassword[i>>1] = (char)(((PasswordData[i]&0xf0)>>4)\r
- +((PasswordData[i+1]&0x0f)<<4)-Key[0]);\r
- ClearPassword[PassLen>>1]=0;\r
- }\r
- else\r
- {\r
- for(int i=0; i<PassLen; i++)\r
- ClearPassword[i] = (char)(PasswordData[i]-Key[0]);\r
- ClearPassword[PassLen]=0;\r
- }\r
- return true;\r
- }\r
- else\r
- return false;\r
-}\r
-\r
-bool PAccount::Authenticate(const uint8_t* PasswordData, int PassLen, const uint8_t *Key)\r
-{\r
- char Pass[128];\r
-\r
- if(DecodePassword(PasswordData, PassLen, Key, Pass))\r
- {\r
- return Authenticate(Pass);\r
- }\r
- else\r
- {\r
- Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen);\r
- return false;\r
- }\r
-}\r
-\r
-bool PAccount::Authenticate(const char *Password) const\r
-{\r
- if(mID == 0) // User doesn't exist and that hasn't been checked !\r
- {\r
- Console->Print(RED, BLACK, "[Bug]: user %s doesn't exist and was not checked by code !", mName.c_str());\r
- return false;\r
- }\r
-\r
- return(mPassword == Password);\r
-}\r
-\r
-bool PAccount::Create()\r
-{\r
- if(Save(true)) {\r
- //mID = MySQL->GetLastInfoInsertId();\r
- mID = MySQL->GetLastInsertId();\r
- return true;\r
- }\r
- else\r
- {\r
- return false;\r
- }\r
-}\r
-\r
-bool PAccount::Save(bool CreateMode)\r
-{\r
- char escUsername[256];\r
- char escPassword[256];\r
- MySQL->EscapeString(mName.c_str(), escUsername, 256);\r
- MySQL->EscapeString(mPassword.c_str(), escPassword, 256);\r
-\r
- std::string Query;\r
- Query = CreateMode ? "INSERT INTO" : "UPDATE";\r
- Query += " accounts SET ";\r
- Query += Ssprintf(" a_username='%s', a_password = '%s'", escUsername, escPassword);\r
- Query += Ssprintf(", a_priv = %d, a_status = %d, a_bandate = %d", mLevel, mStatus, mBannedUntil);\r
- if(!CreateMode )\r
- {\r
- Query += Ssprintf(" a_lastused = NOW()");\r
- Query += Ssprintf(" WHERE a_id = %d LIMIT 1", mID);\r
- }\r
- else\r
- Query += Ssprintf(" a_creationdate = NOW()");\r
-\r
- //if(MySQL->InfoQuery(Query.c_str()))\r
- if(MySQL->Query(Query.c_str()))\r
- {\r
- Console->Print(RED, BLACK, "[Error] Failed to %s account %s (id %d)", CreateMode ? "create" : "update", mName.c_str(), mID);\r
- //MySQL->ShowInfoSQLError();\r
- MySQL->ShowSQLError();\r
- return false;\r
- }\r
- return true;\r
-}\r
-\r
-std::string PAccount::GetBannedTime() const\r
-{\r
- const char* unit[5] = {"seconds", "minutes", "hours", "days", "weeks"};\r
-\r
- std::time_t timediff = mBannedUntil - std::time(NULL);\r
- if(timediff <=0)\r
- {\r
- return "0 more seconds. Please relog";\r
- }\r
-\r
- long counter;\r
- int type;\r
-\r
- if(timediff > 86400) // days\r
- {\r
- counter = timediff / 86400;\r
- type = 3;\r
- }\r
- else if(timediff > 3600) // hours\r
- {\r
- counter = timediff / 3600;\r
- type = 2;\r
- }\r
- else if(timediff > 60) // Minutes\r
- {\r
- counter = timediff / 60;\r
- type = 1;\r
- }\r
- else // Seconds\r
- {\r
- counter = timediff;\r
- type = 0;\r
- }\r
-\r
- return Ssprintf("%d more %s", counter, unit[type]);\r
-}\r
+#include "InfoServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+/*
+NOTE ABOUT ACCESS LEVELS IN THE MYSQL DATABASE:
+a_priv:
+0 = unregistered user
+1 = Registered user
+30 = volunteer
+50 = GM
+100 = Admin
+
+a_status:
+0 = Offline
+1 = Online
+2 = Banned
+*/
+
+/** Static members **/
+RegEx* PAccount::mUsernameRegexFilter = nullptr;
+RegEx* PAccount::mPasswordRegexFilter = nullptr;
+
+bool PAccount::SetUsernameRegexFilter(const char* RegexStr)
+{
+ if(mUsernameRegexFilter)
+ {
+ delete mUsernameRegexFilter;
+ mUsernameRegexFilter = NULL;
+ }
+
+ if(RegexStr)
+ {
+ try {
+ mUsernameRegexFilter = new RegEx(RegexStr, PCRE_CASELESS);
+ }
+ catch (...) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool PAccount::SetPasswordRegexFilter(const char* RegexStr)
+{
+ if(mPasswordRegexFilter)
+ {
+ delete mPasswordRegexFilter;
+ mPasswordRegexFilter = NULL;
+ }
+
+ if(RegexStr)
+ {
+ try {
+ mPasswordRegexFilter = new RegEx(RegexStr, PCRE_CASELESS);
+ }
+ catch (...) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool PAccount::IsUsernameWellFormed(const char *Username)
+{
+ if(mUsernameRegexFilter)
+ {
+ return mUsernameRegexFilter->Search(Username);
+ }
+ else
+ return true;
+}
+
+bool PAccount::IsPasswordWellFormed(const char *Password)
+{
+ if(mPasswordRegexFilter)
+ {
+ return mPasswordRegexFilter->Search(Password);
+ }
+ else
+ return true;
+}
+
+/** Instance members **/
+PAccount::PAccount()
+{
+ mID = 0;
+ mLevel = PAL_BANNED;
+ mStatus = PAS_OFFLINE;
+ mBannedUntil = 0;
+}
+
+PAccount::PAccount(const uint32_t AccountId)
+{
+ char query[256];
+ mID = 0;
+ snprintf(query, 256, "SELECT * FROM accounts WHERE a_id = %d LIMIT 1;", AccountId);
+ LoadFromQuery(query);
+}
+
+PAccount::PAccount(const char *Username)
+{
+ char query[256];
+ mID = 0;
+ if(IsUsernameWellFormed(Username)) {
+ char escUsername[256];
+ MySQL->EscapeString(Username, escUsername, 256);
+ snprintf(query, 256, "SELECT * FROM accounts WHERE a_username = '%s' LIMIT 1;", escUsername);
+ LoadFromQuery(query);
+ }
+}
+
+bool PAccount::LoadFromQuery(char* query)
+{
+ MYSQL_ROW row = 0;
+ MYSQL_RES *result = 0;
+
+ bool FinalResult = false;
+
+ //result = MySQL->InfoResQuery(query);
+ result = MySQL->ResQuery(query);
+ if(result == NULL)
+ {
+ Console->Print(RED, BLACK, "Failed to load AccountData from SQL");
+ //MySQL->ShowInfoSQLError();
+ MySQL->ShowSQLError();
+ return false;
+ }
+
+ if((row = mysql_fetch_row(result)))
+ {
+ mID = atoi(row[a_id]);
+ mName = row[a_username];
+ mPassword = row[a_password];
+
+ mBannedUntil = atoi(row[a_bandate]);
+ if(mBannedUntil > std::time(NULL))
+ {
+ mStatus = PAS_BANNED;
+ mLevel = PAL_BANNED;
+ }
+ else
+ {
+ mStatus = PAS_OFFLINE;
+ mLevel = atoi(row[a_priv]);
+ }
+
+ FinalResult = true;
+ }
+ else
+ {
+Console->Print(YELLOW, BLACK, "Failed to load AccountData from SQL; Nothing to load...");
+ }
+
+ //MySQL->FreeInfoSQLResult(result);
+ MySQL->FreeSQLResult(result);
+ return FinalResult;
+}
+
+uint32_t PAccount::GetID() const
+{
+ return mID;
+}
+
+bool PAccount::SetName(const std::string &Username)
+{
+ if(IsUsernameWellFormed(Username.c_str()))
+ {
+ mName = Username;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+const std::string &PAccount::GetName() const
+{
+ return mName;
+}
+
+bool PAccount::SetPassword(const std::string &Password)
+{
+ if(IsPasswordWellFormed(Password.c_str()))
+ {
+ mPassword = Password;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool PAccount::SetPasswordEncoded(const uint8_t* PasswordData, int PassLen, const uint8_t* Key)
+{
+ char Pass[128];
+
+ if(DecodePassword(PasswordData, PassLen, Key, Pass))
+ {
+ return SetPassword((std::string)Pass);
+ }
+ else
+ {
+ Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen);
+ return false;
+ }
+}
+
+const std::string &PAccount::GetPassword() const
+{
+ return mPassword;
+}
+
+bool PAccount::SetLevel(int newLevel)
+{
+ if((newLevel >= PAL_BANNED) && (newLevel <= PAL_ADMIN))
+ {
+ mLevel = newLevel;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+int32_t PAccount::GetLevel() const
+{
+ return mLevel;
+}
+
+std::string PAccount::GetLevelString() const
+{
+ switch(mLevel)
+ {
+ case PAL_BANNED : return "banned";
+ case PAL_UNREGPLAYER : return "unregplayer";
+ case PAL_REGPLAYER : return "regplayer";
+ case PAL_VOLUNTEER : return "volunteer";
+ case PAL_GM : return "gm";
+ case PAL_ADMIN : return "admin";
+ }
+
+ return "custom";
+}
+
+bool PAccount::SetStatus(PAccountStatus Status)
+{
+ mStatus = Status;
+ return true;
+}
+
+PAccountStatus PAccount::GetStatus() const
+{
+ return mStatus;
+}
+
+bool PAccount::SetBannedUntilTime(std::time_t BannedUntil)
+{
+ if ((BannedUntil == 0) || (BannedUntil > std::time(NULL)))
+ {
+ mBannedUntil = BannedUntil;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool PAccount::IsBanned() const
+{
+ return (mBannedUntil > std::time(nullptr));
+}
+
+bool PAccount::DecodePassword(const uint8_t* PasswordData, int PassLen, const uint8_t *Key, char* ClearPassword)
+{
+ ClearPassword[0] = 0;
+
+ if(PassLen < 128)
+ {
+ if(Key[0]>7) // TODO: >7 correct?
+ {
+ for(int i=0; i<PassLen; i+=2)
+ ClearPassword[i>>1] = (char)(((PasswordData[i]&0xf0)>>4)
+ +((PasswordData[i+1]&0x0f)<<4)-Key[0]);
+ ClearPassword[PassLen>>1]=0;
+ }
+ else
+ {
+ for(int i=0; i<PassLen; i++)
+ ClearPassword[i] = (char)(PasswordData[i]-Key[0]);
+ ClearPassword[PassLen]=0;
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+bool PAccount::Authenticate(const uint8_t* PasswordData, int PassLen, const uint8_t *Key)
+{
+ char Pass[128];
+
+ if(DecodePassword(PasswordData, PassLen, Key, Pass))
+ {
+ return Authenticate(Pass);
+ }
+ else
+ {
+ Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen);
+ return false;
+ }
+}
+
+bool PAccount::Authenticate(const char *Password) const
+{
+ if(mID == 0) // User doesn't exist and that hasn't been checked !
+ {
+ Console->Print(RED, BLACK, "[Bug]: user %s doesn't exist and was not checked by code !", mName.c_str());
+ return false;
+ }
+
+ return(mPassword == Password);
+}
+
+bool PAccount::Create()
+{
+ if(Save(true)) {
+ //mID = MySQL->GetLastInfoInsertId();
+ mID = MySQL->GetLastInsertId();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool PAccount::Save(bool CreateMode)
+{
+ char escUsername[256];
+ char escPassword[256];
+ MySQL->EscapeString(mName.c_str(), escUsername, 256);
+ MySQL->EscapeString(mPassword.c_str(), escPassword, 256);
+
+ std::string Query;
+ Query = CreateMode ? "INSERT INTO" : "UPDATE";
+ Query += " accounts SET ";
+ Query += Ssprintf(" a_username='%s', a_password = '%s'", escUsername, escPassword);
+ Query += Ssprintf(", a_priv = %d, a_status = %d, a_bandate = %d", mLevel, mStatus, mBannedUntil);
+ if(!CreateMode )
+ {
+ Query += Ssprintf(" a_lastused = NOW()");
+ Query += Ssprintf(" WHERE a_id = %d LIMIT 1", mID);
+ }
+ else
+ Query += Ssprintf(" a_creationdate = NOW()");
+
+ //if(MySQL->InfoQuery(Query.c_str()))
+ if(MySQL->Query(Query.c_str()))
+ {
+ Console->Print(RED, BLACK, "[Error] Failed to %s account %s (id %d)", CreateMode ? "create" : "update", mName.c_str(), mID);
+ //MySQL->ShowInfoSQLError();
+ MySQL->ShowSQLError();
+ return false;
+ }
+ return true;
+}
+
+std::string PAccount::GetBannedTime() const
+{
+ const char* unit[5] = {"seconds", "minutes", "hours", "days", "weeks"};
+
+ std::time_t timediff = mBannedUntil - std::time(NULL);
+ if(timediff <=0)
+ {
+ return "0 more seconds. Please relog";
+ }
+
+ long counter;
+ int type;
+
+ if(timediff > 86400) // days
+ {
+ counter = timediff / 86400;
+ type = 3;
+ }
+ else if(timediff > 3600) // hours
+ {
+ counter = timediff / 3600;
+ type = 2;
+ }
+ else if(timediff > 60) // Minutes
+ {
+ counter = timediff / 60;
+ type = 1;
+ }
+ else // Seconds
+ {
+ counter = timediff;
+ type = 0;
+ }
+
+ return Ssprintf("%d more %s", counter, unit[type]);
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <ctime>\r
-#include <string>\r
-\r
-class RegEx;\r
-\r
-/*\r
-0 = unregistered user\r
-1 = Registered user\r
-30 = volunteer\r
-50 = GM\r
-100 = Admin\r
-*/\r
-\r
-// New way of AccountLevel handling:\r
-// Every level is possible, the following values are only edge values. We need a bit control about that\r
-#define PAL_BANNED -1\r
-#define PAL_UNREGPLAYER 0\r
-#define PAL_REGPLAYER 1\r
-#define PAL_VOLUNTEER 30\r
-#define PAL_GM 50\r
-#define PAL_ADMIN 100\r
-\r
-// Max number of char slots per account\r
-#define MAX_CHARS_PER_ACCOUNT 4\r
-\r
-/*\r
-0 = Offline\r
-1 = Online\r
-2 = Banned\r
-*/\r
-\r
-enum PAccountStatus\r
-{\r
- PAS_OFFLINE = 0,\r
- PAS_ONLINE = 1,\r
- PAS_BANNED = 2\r
-};\r
-\r
-class PAccount\r
-{\r
- private :\r
- // SQL Layout\r
- enum {\r
- a_id,\r
- a_username,\r
- a_password,\r
- a_priv,\r
- a_status,\r
- a_bandate,\r
- a_emailaddress,\r
- a_creationdate,\r
- a_lastused\r
- };\r
-\r
- // static members\r
- static RegEx *mUsernameRegexFilter;\r
- static RegEx *mPasswordRegexFilter;\r
-\r
- // instance members\r
- uint32_t mID;\r
- std::string mName;\r
- std::string mPassword;\r
- int32_t mLevel;\r
- PAccountStatus mStatus;\r
- std::time_t mBannedUntil;\r
-\r
- bool LoadFromQuery(char *query);\r
- bool DecodePassword(const uint8_t *PasswordData, int32_t PassLen, const uint8_t *Key, char *ClearPassword);\r
-\r
-public:\r
- PAccount();\r
- PAccount(const uint32_t AccountId);\r
- PAccount(const char *Username);\r
-\r
- static bool SetUsernameRegexFilter(const char *RegexStr);\r
- static bool SetPasswordRegexFilter(const char *RegexStr);\r
- static bool IsUsernameWellFormed(const char *Username);\r
- static bool IsPasswordWellFormed(const char *Password);\r
-\r
- uint32_t GetID() const;\r
- bool SetName(const std::string &Pass);\r
- const std::string &GetName() const;\r
- bool SetPassword(const std::string &Pass);\r
- bool SetPasswordEncoded(const uint8_t *PasswordData, int32_t PassLen, const uint8_t *Key);\r
- const std::string &GetPassword() const;\r
- bool SetLevel(int32_t newLevel);\r
- int32_t GetLevel() const;\r
- std::string GetLevelString() const;\r
- bool SetStatus(PAccountStatus Status);\r
- PAccountStatus GetStatus() const;\r
- bool SetBannedUntilTime(std::time_t BannedUntil);\r
- bool IsBanned() const;\r
- std::string GetBannedTime() const;\r
- bool Authenticate(const uint8_t *PasswordData, int32_t PassLen, const uint8_t *Key);\r
- bool Authenticate(const char *Password) const;\r
- bool Create();\r
- bool Save(bool CreateMode = false);\r
-\r
- //u32 GetCharIdBySlot(const u32 SlotId);\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <ctime>
+#include <string>
+
+class RegEx;
+
+/*
+0 = unregistered user
+1 = Registered user
+30 = volunteer
+50 = GM
+100 = Admin
+*/
+
+// New way of AccountLevel handling:
+// Every level is possible, the following values are only edge values. We need a bit control about that
+#define PAL_BANNED -1
+#define PAL_UNREGPLAYER 0
+#define PAL_REGPLAYER 1
+#define PAL_VOLUNTEER 30
+#define PAL_GM 50
+#define PAL_ADMIN 100
+
+// Max number of char slots per account
+#define MAX_CHARS_PER_ACCOUNT 4
+
+/*
+0 = Offline
+1 = Online
+2 = Banned
+*/
+
+enum PAccountStatus
+{
+ PAS_OFFLINE = 0,
+ PAS_ONLINE = 1,
+ PAS_BANNED = 2
+};
+
+class PAccount
+{
+ private :
+ // SQL Layout
+ enum {
+ a_id,
+ a_username,
+ a_password,
+ a_priv,
+ a_status,
+ a_bandate,
+ a_emailaddress,
+ a_creationdate,
+ a_lastused
+ };
+
+ // static members
+ static RegEx *mUsernameRegexFilter;
+ static RegEx *mPasswordRegexFilter;
+
+ // instance members
+ uint32_t mID;
+ std::string mName;
+ std::string mPassword;
+ int32_t mLevel;
+ PAccountStatus mStatus;
+ std::time_t mBannedUntil;
+
+ bool LoadFromQuery(char *query);
+ bool DecodePassword(const uint8_t *PasswordData, int32_t PassLen, const uint8_t *Key, char *ClearPassword);
+
+public:
+ PAccount();
+ PAccount(const uint32_t AccountId);
+ PAccount(const char *Username);
+
+ static bool SetUsernameRegexFilter(const char *RegexStr);
+ static bool SetPasswordRegexFilter(const char *RegexStr);
+ static bool IsUsernameWellFormed(const char *Username);
+ static bool IsPasswordWellFormed(const char *Password);
+
+ uint32_t GetID() const;
+ bool SetName(const std::string &Pass);
+ const std::string &GetName() const;
+ bool SetPassword(const std::string &Pass);
+ bool SetPasswordEncoded(const uint8_t *PasswordData, int32_t PassLen, const uint8_t *Key);
+ const std::string &GetPassword() const;
+ bool SetLevel(int32_t newLevel);
+ int32_t GetLevel() const;
+ std::string GetLevelString() const;
+ bool SetStatus(PAccountStatus Status);
+ PAccountStatus GetStatus() const;
+ bool SetBannedUntilTime(std::time_t BannedUntil);
+ bool IsBanned() const;
+ std::string GetBannedTime() const;
+ bool Authenticate(const uint8_t *PasswordData, int32_t PassLen, const uint8_t *Key);
+ bool Authenticate(const char *Password) const;
+ bool Create();
+ bool Save(bool CreateMode = false);
+
+ //u32 GetCharIdBySlot(const u32 SlotId);
+};
-#include "InfoServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-PClient::PClient(int32_t Index)\r
-{\r
- mIndex = Index;\r
- mConnection = PCC_NONE;\r
- mAccountID = 0;\r
-}\r
-\r
-PClient::~PClient()\r
-{\r
- if(m_TCPConnection)\r
- {\r
- delete m_TCPConnection;\r
- }\r
-}\r
-\r
-int32_t PClient::GetIndex() const\r
-{\r
- return mIndex;\r
-}\r
-\r
-void PClient::setTCPConnection(ConnectionTCP *conn)\r
-{\r
- m_TCPConnection = conn; mConnection = PCC_INFO;\r
-}\r
-\r
-ConnectionTCP *PClient::getTCPConn() const\r
-{\r
- return m_TCPConnection;\r
-}\r
-\r
-int32_t PClient::GetConnection() const\r
-{\r
- return mConnection;\r
-}\r
-\r
-const char *PClient::GetAddress() const\r
-{\r
- return m_TCPConnection->getRemoteAddress();\r
-}\r
-\r
-void PClient::setAccountID(uint32_t nAccountID)\r
-{\r
- mAccountID = nAccountID;\r
-}\r
-\r
-uint32_t PClient::getAccountID()\r
-{\r
- return mAccountID;\r
-}\r
-\r
-void PClient::InfoDisconnect()\r
-{\r
- if(m_TCPConnection)\r
- {\r
- delete m_TCPConnection;\r
- }\r
- m_TCPConnection = 0;\r
-\r
- //mConnection &= ~PCC_INFO;\r
- mConnection = PCC_NONE;\r
- mAccountID = 0;\r
-}\r
-\r
-void PClient::Update()\r
-{\r
- if(m_TCPConnection)\r
- {\r
- if(m_TCPConnection->timeOut())\r
- {\r
- Console->Print("InfoSocket: Client %i: timeout", mIndex);\r
- InfoServer->ClientDisconnected(this);\r
- }\r
- else\r
- {\r
- if(!m_TCPConnection->update())\r
- {\r
- InfoServer->ClientDisconnected(this);\r
- }\r
- }\r
- }\r
-}\r
+#include "InfoServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+PClient::PClient(int32_t Index)
+{
+ mIndex = Index;
+ mConnection = PCC_NONE;
+ mAccountID = 0;
+}
+
+PClient::~PClient()
+{
+ if(m_TCPConnection)
+ {
+ delete m_TCPConnection;
+ }
+}
+
+int32_t PClient::GetIndex() const
+{
+ return mIndex;
+}
+
+void PClient::setTCPConnection(ConnectionTCP *conn)
+{
+ m_TCPConnection = conn; mConnection = PCC_INFO;
+}
+
+ConnectionTCP *PClient::getTCPConn() const
+{
+ return m_TCPConnection;
+}
+
+int32_t PClient::GetConnection() const
+{
+ return mConnection;
+}
+
+const char *PClient::GetAddress() const
+{
+ return m_TCPConnection->getRemoteAddress();
+}
+
+void PClient::setAccountID(uint32_t nAccountID)
+{
+ mAccountID = nAccountID;
+}
+
+uint32_t PClient::getAccountID()
+{
+ return mAccountID;
+}
+
+void PClient::InfoDisconnect()
+{
+ if(m_TCPConnection)
+ {
+ delete m_TCPConnection;
+ }
+ m_TCPConnection = 0;
+
+ //mConnection &= ~PCC_INFO;
+ mConnection = PCC_NONE;
+ mAccountID = 0;
+}
+
+void PClient::Update()
+{
+ if(m_TCPConnection)
+ {
+ if(m_TCPConnection->timeOut())
+ {
+ Console->Print("InfoSocket: Client %i: timeout", mIndex);
+ InfoServer->ClientDisconnected(this);
+ }
+ else
+ {
+ if(!m_TCPConnection->update())
+ {
+ InfoServer->ClientDisconnected(this);
+ }
+ }
+ }
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-\r
-class ConnectionTCP;\r
-\r
-enum PClientConnection\r
-{\r
- PCC_NONE = 0,\r
- PCC_INFO = 1\r
-};\r
-\r
-class PClient {\r
-private:\r
- ConnectionTCP* m_TCPConnection;\r
- int32_t mIndex;\r
- int32_t mConnection;\r
- uint32_t mAccountID;\r
-\r
-public:\r
- PClient(int32_t Index);\r
- ~PClient();\r
-\r
- int32_t GetIndex() const;\r
- void setTCPConnection(ConnectionTCP *conn);\r
- ConnectionTCP *getTCPConn() const;\r
- int32_t GetConnection() const;\r
- const char *GetAddress() const;\r
- void setAccountID(uint32_t nAccountID);\r
- uint32_t getAccountID();\r
- void InfoDisconnect();\r
- void Update();\r
-};\r
+#pragma once
+
+#include <cstdint>
+
+class ConnectionTCP;
+
+enum PClientConnection
+{
+ PCC_NONE = 0,
+ PCC_INFO = 1
+};
+
+class PClient {
+private:
+ ConnectionTCP* m_TCPConnection;
+ int32_t mIndex;
+ int32_t mConnection;
+ uint32_t mAccountID;
+
+public:
+ PClient(int32_t Index);
+ ~PClient();
+
+ int32_t GetIndex() const;
+ void setTCPConnection(ConnectionTCP *conn);
+ ConnectionTCP *getTCPConn() const;
+ int32_t GetConnection() const;
+ const char *GetAddress() const;
+ void setAccountID(uint32_t nAccountID);
+ uint32_t getAccountID();
+ void InfoDisconnect();
+ void Update();
+};
-#pragma once\r
-\r
-static const char *InfoConfigTemplate[][2] = {\r
- // {option_name, default_value} if default_value is empty string, it means option is mandatory\r
- // List ends with empty string for option_name\r
- {"sql_host", "127.0.0.1"}, // should be renanmed to info_sql_host\r
- {"sql_port", "3306"}, // should be renanmed to info_sql_port\r
- {"sql_username", ""}, // should be renanmed to info_sql_username\r
- {"sql_password", ""}, // should be renanmed to info_sql_password\r
- {"global_sql_database", "infoserver"}, // should be renanmed to info_sql_database\r
- {"mysql_wait_timeout", "28800"}, // value of the wait_timout system variable from the MySQL server (same for game & info DB atm). 0 to disable keepalive.\r
- {"auto_accounts", "0"},\r
- {"infoserver_port", "7000"},\r
- {"gameserver_livecheck", "60"},\r
- {"minlevel", "0"},\r
- {"maxclients", "50"},\r
- {"require_validation", "0"},\r
- {"isc_method", "1"},\r
- {"isc_infoserverport", "9991"},\r
- {"isc_connect_pw", "changeme"},\r
- {"username_filter", "^[a-z][\\w\\-]{2,14}$"},\r
- {"password_filter", "^[[:graph:]]{3,15}$"},\r
- {"sqlite_databasefile", "infoDB.s3db"},\r
- {"database_type", "sqlite"},\r
-\r
-// For futur use:\r
-// {"max_chars_per_account", "4"},\r
-\r
- {"", ""} // do not change this line (end mark)\r
-};\r
+#pragma once
+
+static const char *InfoConfigTemplate[][2] = {
+ // {option_name, default_value} if default_value is empty string, it means option is mandatory
+ // List ends with empty string for option_name
+ {"sql_host", "127.0.0.1"}, // should be renanmed to info_sql_host
+ {"sql_port", "3306"}, // should be renanmed to info_sql_port
+ {"sql_username", ""}, // should be renanmed to info_sql_username
+ {"sql_password", ""}, // should be renanmed to info_sql_password
+ {"global_sql_database", "infoserver"}, // should be renanmed to info_sql_database
+ {"mysql_wait_timeout", "28800"}, // value of the wait_timout system variable from the MySQL server (same for game & info DB atm). 0 to disable keepalive.
+ {"auto_accounts", "0"},
+ {"infoserver_port", "7000"},
+ {"gameserver_livecheck", "60"},
+ {"minlevel", "0"},
+ {"maxclients", "50"},
+ {"require_validation", "0"},
+ {"isc_method", "1"},
+ {"isc_infoserverport", "9991"},
+ {"isc_connect_pw", "changeme"},
+ {"username_filter", "^[a-z][\\w\\-]{2,14}$"},
+ {"password_filter", "^[[:graph:]]{3,15}$"},
+ {"sqlite_databasefile", "infoDB.s3db"},
+ {"database_type", "sqlite"},
+
+// For futur use:
+// {"max_chars_per_account", "4"},
+
+ {"", ""} // do not change this line (end mark)
+};
-#include <cstring>\r
-#include "InfoServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-const char ServerVersion[] = TINNS_INFO_VERSION;\r
-const char SVNRevision[] = TINNS_SVN_REVISION;\r
-\r
-ServerSocket* ServerSock = 0;\r
-PMySQL *MySQL = 0;\r
-PConsole *Console = 0;\r
-PServer *Server = 0;\r
-PConfig *Config = 0;\r
-PInfoServer *InfoServer = 0;\r
-//PAccounts *Accounts = 0; // To be removed\r
-\r
-bool Init()\r
-{\r
- Console = new PConsole("log/infoserver.log"); // Make that from config file !!!\r
- Console->Print("Starting TinNS Infoserver");\r
- Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\");\r
- Console->Print(WHITE, BLUE, "| TinNS (TinNS is not a Neocron Server) |");\r
- Console->Print(WHITE, BLUE, "| Copyright (C) 2005 Linux Addicted Community |");\r
- Console->Print(WHITE, BLUE, "| maintainer Akiko <akiko@gmx.org> |");\r
- Console->Print(WHITE, BLUE, "| ========================================== |");\r
- Console->Print(WHITE, BLUE, "| Head coders: The packet analyzing team: |");\r
- Console->Print(WHITE, BLUE, "| - Akiko - MaxxJag |");\r
- Console->Print(WHITE, BLUE, "| - bakkdoor - Sting |");\r
- Console->Print(WHITE, BLUE, "| - Namikon - Balm |");\r
- Console->Print(WHITE, BLUE, "| - Hammag |");\r
- Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");\r
- Console->Print(WHITE, BLUE, "| This project would'nt be at its current stage without the help |");\r
- Console->Print(WHITE, BLUE, "| from the NeoPolis team, special thanks to you guys! |");\r
- Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");\r
- Console->Print(WHITE, BLUE, "| This project is under GPL, see any source file for more details |");\r
- Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/");\r
-\r
- //char svnrev[10];\r
- //GetSVNRev(svnrev);\r
- Console->LPrint("You are running TinNS Infoserver version");\r
- Console->LPrint(GREEN, BLACK, " %s", ServerVersion);\r
- Console->LPrint(WHITE, BLACK, " - SVN Rev");\r
- Console->LPrint(GREEN, BLACK, " %s", SVNRevision);\r
- Console->LClose();\r
-\r
- Config = new PConfig();\r
- if(!Config->LoadOptions(InfoConfigTemplate, "./conf/infoserver.conf"))\r
- return false; //Shutdown();\r
- if(!AdditionnalConfigChecks())\r
- return false; //Shutdown();\r
-\r
- ServerSock = new ServerSocket();\r
- Server = new PServer();\r
-\r
- MySQL = new PMySQL();\r
- if(MySQL->Connect() == false)\r
- return false; //Shutdown();\r
-\r
- InfoServer = new PInfoServer();\r
- //Accounts = new PAccounts(); // To be removed\r
-\r
- return true;\r
-}\r
-\r
-void Shutdown()\r
-{\r
- if(Server) Server->Shutdown();\r
- if(InfoServer) delete InfoServer;\r
- if(MySQL) delete MySQL;\r
- if(Config) delete Config;\r
- if(Console) delete Console;\r
- if(ServerSock) delete ServerSock;\r
- exit(0);\r
-}\r
-\r
-bool AdditionnalConfigChecks()\r
-{\r
- //NOTA: empty config values are never accepted by PConfig objects\r
-\r
- int numErr, numWarn;\r
-\r
- //std::string sqlhost = Config->GetOption("sql_host");\r
- std::string sqlusername = Config->GetOption("sql_username");\r
- //std::string sqlpassword = Config->GetOption("sql_password");\r
- //std::string global_sql_database = Config->GetOption("global_sql_database");\r
- int sqlport = Config->GetOptionInt("sql_port");\r
- int auto_accounts = Config->GetOptionInt("auto_accounts");\r
- int infoserver_port = Config->GetOptionInt("infoserver_port");\r
- int gameserver_livecheck = Config->GetOptionInt("gameserver_livecheck");\r
- int minlevel = Config->GetOptionInt("minlevel");\r
- int maxclients = Config->GetOptionInt("maxclients");\r
-\r
- numErr = numWarn = 0;\r
-\r
- /*if(strcmp(sqlhost.c_str(), "") == 0)\r
- {\r
- Console->Print("%s sql_host is empty", Console->ColorText(RED, BLACK, "Config error:"));\r
- numErr++;\r
- }*/\r
-\r
- /*if(strcmp(sqlusername.c_str(), "") == 0)\r
- {\r
- Console->Print("%s sql_username is empty", Console->ColorText(RED, BLACK, "Config error:"));\r
- numErr++;\r
- }\r
- else*/\r
- if(strcmp(sqlusername.c_str(), "root") ==0)\r
- {\r
- Console->Print("%s Config: sqlusername is \"root\", which is pretty insecure.", Console->ColorText(YELLOW, BLACK, "[Warning]"));\r
- numWarn++;\r
- }\r
-\r
- /*if(strcmp(sqlpassword.c_str(), "") == 0);\r
- {\r
- Console->Print("%s sql_password is empty", Console->ColorText(RED, BLACK, "Config error:"));\r
- numErr++;\r
- }\r
-\r
- if(strcmp(global_sql_database.c_str(), "") == 0);\r
- {\r
- Console->Print("%s global_sql_database is empty", Console->ColorText(RED, BLACK, "Config error:"));\r
- numErr++;\r
- }*/\r
-\r
- if(sqlport < 1025 || sqlport > 65535)\r
- {\r
- Console->Print("%s Config: sql_port is usually between 1025 and 65535!", Console->ColorText(YELLOW, BLACK, "[Warning]"));\r
- numWarn++;\r
- }\r
-\r
- if(auto_accounts != 0 && auto_accounts != 1)\r
- {\r
- Console->Print("%s Config: auto_accounts has to be either 0 or 1!", Console->ColorText(RED, BLACK, "[Error]"));\r
- numErr++;\r
- }\r
-\r
- if(infoserver_port < 1025 || infoserver_port > 65535)\r
- {\r
- Console->Print("%s Config: infoserver_port has to be between 1025 and 65535!", Console->ColorText(RED, BLACK, "[Error]"));\r
- numErr++;\r
- }\r
- // This assertion is wrong, as sql server and info server can be on differents computers\r
- /*else if(infoserver_port == sqlport)\r
- {\r
- Console->Print("%s infoserver_port has to be different from sql_port!", Console->ColorText(RED, BLACK, "Config error:"));\r
- numErr++;\r
- }*/\r
-\r
- if(gameserver_livecheck <= 0)\r
- {\r
- Console->Print("%s Config: gameserver_livecheck cannot equal or less than 0", Console->ColorText(RED, BLACK, "[Error]"));\r
- numErr++;\r
- }\r
- else if(gameserver_livecheck < 2)\r
- {\r
- Console->Print("%s Config: gameserver_livecheck is pretty low, this may cause increased mysql load", Console->ColorText(YELLOW, BLACK, "[Warning]"));\r
- numWarn++;\r
- }\r
- else if(gameserver_livecheck > 120 && gameserver_livecheck < 600)\r
- {\r
- Console->Print("%s Config: gameserver_livecheck is pretty high, this may cause offline servers shown as online and a wrong usercount", Console->ColorText(YELLOW, BLACK, "[Warning]"));\r
- numWarn++;\r
- }\r
- else if(gameserver_livecheck > 600)\r
- {\r
- Console->Print("%s Config: gameserver_livecheck is too high. Use a value between 0 and 600", Console->ColorText(RED, BLACK, "[Error]"));\r
- numErr++;\r
- }\r
-\r
- if(minlevel < 0 || minlevel > 255)\r
- {\r
- Console->Print("%s Config: minlevel has to be between 0 and 255", Console->ColorText(RED, BLACK, "[Error]"));\r
- numErr++;\r
- }\r
-\r
- if(maxclients < 1 )\r
- {\r
- Console->Print("%s Config: maxclients has to be higher or equal to 1", Console->ColorText(RED, BLACK, "[Error]"));\r
- numErr++;\r
- }\r
-\r
- if(numErr == 0 /*&& numWarn == 0*/)\r
- return true;\r
- else\r
- return false;\r
-}\r
+#include <cstring>
+#include "InfoServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+const char ServerVersion[] = TINNS_INFO_VERSION;
+const char SVNRevision[] = TINNS_SVN_REVISION;
+
+ServerSocket* ServerSock = 0;
+PMySQL *MySQL = 0;
+PConsole *Console = 0;
+PServer *Server = 0;
+PConfig *Config = 0;
+PInfoServer *InfoServer = 0;
+//PAccounts *Accounts = 0; // To be removed
+
+bool Init()
+{
+ Console = new PConsole("log/infoserver.log"); // Make that from config file !!!
+ Console->Print("Starting TinNS Infoserver");
+ Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\");
+ Console->Print(WHITE, BLUE, "| TinNS (TinNS is not a Neocron Server) |");
+ Console->Print(WHITE, BLUE, "| Copyright (C) 2005 Linux Addicted Community |");
+ Console->Print(WHITE, BLUE, "| maintainer Akiko <akiko@gmx.org> |");
+ Console->Print(WHITE, BLUE, "| ========================================== |");
+ Console->Print(WHITE, BLUE, "| Head coders: The packet analyzing team: |");
+ Console->Print(WHITE, BLUE, "| - Akiko - MaxxJag |");
+ Console->Print(WHITE, BLUE, "| - bakkdoor - Sting |");
+ Console->Print(WHITE, BLUE, "| - Namikon - Balm |");
+ Console->Print(WHITE, BLUE, "| - Hammag |");
+ Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");
+ Console->Print(WHITE, BLUE, "| This project would'nt be at its current stage without the help |");
+ Console->Print(WHITE, BLUE, "| from the NeoPolis team, special thanks to you guys! |");
+ Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");
+ Console->Print(WHITE, BLUE, "| This project is under GPL, see any source file for more details |");
+ Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/");
+
+ //char svnrev[10];
+ //GetSVNRev(svnrev);
+ Console->LPrint("You are running TinNS Infoserver version");
+ Console->LPrint(GREEN, BLACK, " %s", ServerVersion);
+ Console->LPrint(WHITE, BLACK, " - SVN Rev");
+ Console->LPrint(GREEN, BLACK, " %s", SVNRevision);
+ Console->LClose();
+
+ Config = new PConfig();
+ if(!Config->LoadOptions(InfoConfigTemplate, "./conf/infoserver.conf"))
+ return false; //Shutdown();
+ if(!AdditionnalConfigChecks())
+ return false; //Shutdown();
+
+ ServerSock = new ServerSocket();
+ Server = new PServer();
+
+ MySQL = new PMySQL();
+ if(MySQL->Connect() == false)
+ return false; //Shutdown();
+
+ InfoServer = new PInfoServer();
+ //Accounts = new PAccounts(); // To be removed
+
+ return true;
+}
+
+void Shutdown()
+{
+ if(Server) Server->Shutdown();
+ if(InfoServer) delete InfoServer;
+ if(MySQL) delete MySQL;
+ if(Config) delete Config;
+ if(Console) delete Console;
+ if(ServerSock) delete ServerSock;
+ exit(0);
+}
+
+bool AdditionnalConfigChecks()
+{
+ //NOTA: empty config values are never accepted by PConfig objects
+
+ int numErr, numWarn;
+
+ //std::string sqlhost = Config->GetOption("sql_host");
+ std::string sqlusername = Config->GetOption("sql_username");
+ //std::string sqlpassword = Config->GetOption("sql_password");
+ //std::string global_sql_database = Config->GetOption("global_sql_database");
+ int sqlport = Config->GetOptionInt("sql_port");
+ int auto_accounts = Config->GetOptionInt("auto_accounts");
+ int infoserver_port = Config->GetOptionInt("infoserver_port");
+ int gameserver_livecheck = Config->GetOptionInt("gameserver_livecheck");
+ int minlevel = Config->GetOptionInt("minlevel");
+ int maxclients = Config->GetOptionInt("maxclients");
+
+ numErr = numWarn = 0;
+
+ /*if(strcmp(sqlhost.c_str(), "") == 0)
+ {
+ Console->Print("%s sql_host is empty", Console->ColorText(RED, BLACK, "Config error:"));
+ numErr++;
+ }*/
+
+ /*if(strcmp(sqlusername.c_str(), "") == 0)
+ {
+ Console->Print("%s sql_username is empty", Console->ColorText(RED, BLACK, "Config error:"));
+ numErr++;
+ }
+ else*/
+ if(strcmp(sqlusername.c_str(), "root") ==0)
+ {
+ Console->Print("%s Config: sqlusername is \"root\", which is pretty insecure.", Console->ColorText(YELLOW, BLACK, "[Warning]"));
+ numWarn++;
+ }
+
+ /*if(strcmp(sqlpassword.c_str(), "") == 0);
+ {
+ Console->Print("%s sql_password is empty", Console->ColorText(RED, BLACK, "Config error:"));
+ numErr++;
+ }
+
+ if(strcmp(global_sql_database.c_str(), "") == 0);
+ {
+ Console->Print("%s global_sql_database is empty", Console->ColorText(RED, BLACK, "Config error:"));
+ numErr++;
+ }*/
+
+ if(sqlport < 1025 || sqlport > 65535)
+ {
+ Console->Print("%s Config: sql_port is usually between 1025 and 65535!", Console->ColorText(YELLOW, BLACK, "[Warning]"));
+ numWarn++;
+ }
+
+ if(auto_accounts != 0 && auto_accounts != 1)
+ {
+ Console->Print("%s Config: auto_accounts has to be either 0 or 1!", Console->ColorText(RED, BLACK, "[Error]"));
+ numErr++;
+ }
+
+ if(infoserver_port < 1025 || infoserver_port > 65535)
+ {
+ Console->Print("%s Config: infoserver_port has to be between 1025 and 65535!", Console->ColorText(RED, BLACK, "[Error]"));
+ numErr++;
+ }
+ // This assertion is wrong, as sql server and info server can be on differents computers
+ /*else if(infoserver_port == sqlport)
+ {
+ Console->Print("%s infoserver_port has to be different from sql_port!", Console->ColorText(RED, BLACK, "Config error:"));
+ numErr++;
+ }*/
+
+ if(gameserver_livecheck <= 0)
+ {
+ Console->Print("%s Config: gameserver_livecheck cannot equal or less than 0", Console->ColorText(RED, BLACK, "[Error]"));
+ numErr++;
+ }
+ else if(gameserver_livecheck < 2)
+ {
+ Console->Print("%s Config: gameserver_livecheck is pretty low, this may cause increased mysql load", Console->ColorText(YELLOW, BLACK, "[Warning]"));
+ numWarn++;
+ }
+ else if(gameserver_livecheck > 120 && gameserver_livecheck < 600)
+ {
+ Console->Print("%s Config: gameserver_livecheck is pretty high, this may cause offline servers shown as online and a wrong usercount", Console->ColorText(YELLOW, BLACK, "[Warning]"));
+ numWarn++;
+ }
+ else if(gameserver_livecheck > 600)
+ {
+ Console->Print("%s Config: gameserver_livecheck is too high. Use a value between 0 and 600", Console->ColorText(RED, BLACK, "[Error]"));
+ numErr++;
+ }
+
+ if(minlevel < 0 || minlevel > 255)
+ {
+ Console->Print("%s Config: minlevel has to be between 0 and 255", Console->ColorText(RED, BLACK, "[Error]"));
+ numErr++;
+ }
+
+ if(maxclients < 1 )
+ {
+ Console->Print("%s Config: maxclients has to be higher or equal to 1", Console->ColorText(RED, BLACK, "[Error]"));
+ numErr++;
+ }
+
+ if(numErr == 0 /*&& numWarn == 0*/)
+ return true;
+ else
+ return false;
+}
-#pragma once\r
-\r
-#include "InfoServer/Accounts.hxx"\r
-#include "InfoServer/ConfigTemplate.hxx"\r
-#include "InfoServer/Client.hxx"\r
-#include "InfoServer/InfoServer.hxx"\r
-#include "InfoServer/Server.hxx"\r
-#include "InfoServer/Sql.hxx"\r
-\r
-extern class ServerSocket* ServerSock;\r
-extern class PConsole *Console;\r
-extern class PServer *Server;\r
-extern class PConfig *Config;\r
-extern class PInfoServer *InfoServer;\r
-\r
-extern class PMySQL* MySQL;\r
-//extern class PAccounts* Accounts; // To be removed\r
-\r
-extern const char ServerVersion[];\r
-extern const char SVNRevision[];\r
-\r
-bool Init();\r
-void Shutdown();\r
-bool AdditionnalConfigChecks();\r
+#pragma once
+
+#include "InfoServer/Accounts.hxx"
+#include "InfoServer/ConfigTemplate.hxx"
+#include "InfoServer/Client.hxx"
+#include "InfoServer/InfoServer.hxx"
+#include "InfoServer/Server.hxx"
+#include "InfoServer/Sql.hxx"
+
+extern class ServerSocket* ServerSock;
+extern class PConsole *Console;
+extern class PServer *Server;
+extern class PConfig *Config;
+extern class PInfoServer *InfoServer;
+
+extern class PMySQL* MySQL;
+//extern class PAccounts* Accounts; // To be removed
+
+extern const char ServerVersion[];
+extern const char SVNRevision[];
+
+bool Init();
+void Shutdown();
+bool AdditionnalConfigChecks();
-#include <cstring>\r
-#include "InfoServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-struct PInfoState\r
-{\r
- enum State\r
- {\r
- IS_UNKNOWN,\r
- IS_CONNECTED,\r
- IS_HANDSHAKE0,\r
- IS_AUTHENTICATE,\r
- IS_SERVERLIST\r
- } mState;\r
-\r
- bool mWaitSend; // wait-for-completition flag\r
- PInfoState()\r
- {\r
- mState = IS_UNKNOWN;\r
- mWaitSend = false;\r
- };\r
-};\r
-\r
-PInfoServer::PInfoServer()\r
-{\r
- //mNumClients = 1;\r
- mLivecheckInterval = Config->GetOptionInt("gameserver_livecheck");\r
-}\r
-\r
-PInfoServer::~PInfoServer()\r
-{\r
- Console->Print("Closing Infoserver...");\r
-\r
- ServerSock->closeServer();\r
-\r
- for(InfoStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end(); i++)\r
- delete i->second;\r
-}\r
-\r
-void PInfoServer::Start()\r
-{\r
- uint16_t Port = Config->GetOptionInt("infoserver_port");\r
- Console->LPrint("Starting Infoserver on port %i...", Port);\r
-\r
- if(ServerSock->open(Port))\r
- {\r
- Console->LPrint(GREEN, BLACK, "Success");\r
- Console->LClose();\r
- }\r
- else\r
- {\r
- Console->LPrint(RED, BLACK, "Failed");\r
- Console->LClose();\r
- }\r
- ServerSock->settimeout(0, 10000);\r
- GSLiveCheck();\r
-}\r
-\r
-void PInfoServer::Update()\r
-{\r
- if(ServerSock->newConnection())\r
- {\r
- int32_t clid = Server->NewClient();\r
- if(clid!=-1)\r
- {\r
- Console->Print(GREEN, BLACK, "Infoserver: client [%i] connected", clid);\r
- PClient *Client = Server->GetClient(clid);\r
-\r
- ConnectionTCP* tcpConn = ServerSock->getTCPConnection();\r
- Client->setTCPConnection(tcpConn);\r
-\r
- Console->Print("Client address: %s", Client->GetAddress());\r
- //++mNumClients;\r
-\r
- PInfoState *state = new PInfoState();\r
- ClientStates.insert(std::make_pair(Client, state));\r
- state->mState = PInfoState::IS_CONNECTED;\r
- } else\r
- {\r
- Console->Print("Infoserver: Client connection refused (server full?)");\r
- }\r
- }\r
-\r
- for(InfoStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end();)\r
- {\r
- PClient *Client = i->first;\r
- PInfoState *State = i->second;\r
- // node gets erased in FinalizeClient, increment iterator now\r
- ++i;\r
- if(!ProcessClient(Client, State))\r
- FinalizeClient(Client, State);\r
- }\r
-}\r
-\r
-void PInfoServer::GSLiveCheck()\r
-{\r
- MYSQL_ROW row;\r
- MYSQL_RES *result;\r
- char query[256];\r
- snprintf (query, 256, "SELECT *, (NOW()< (`s_lastupdate` + INTERVAL %d SECOND)) FROM `server_list`", mLivecheckInterval);\r
-\r
- result = MySQL->ResQuery(query);\r
- if (result == nullptr)\r
- {\r
- Console->Print("Livecheck: %s unable to read server list!", Console->ColorText(RED, BLACK, "[Warning]"));\r
- MySQL->ShowSQLError();\r
- return;\r
- }\r
- if(mysql_num_rows(result) == 0)\r
- {\r
- Console->Print("Livecheck: %s no gameserver found!", Console->ColorText(RED, BLACK, "[Warning]"));\r
- MySQL->FreeSQLResult(result);\r
- return;\r
- }\r
-\r
- ServerMap::iterator it;\r
- while((row = mysql_fetch_row(result)))\r
- {\r
- it = Serverlist.find(atoi(row[s_id]));\r
- if(it != Serverlist.end())\r
- {\r
- strncpy(it->second.mName, row[s_name], MAX_SERVER_NAME_LENGTH);\r
- it->second.mLanIp = IPStringToDWord(row[s_lanaddr]);\r
- it->second.mWanIp = IPStringToDWord(row[s_wanaddr]);\r
- it->second.mPort = atoi(row[s_port]);\r
- it->second.mPlayers = atoi(row[s_players]);\r
- /* Prepared for future addon Servers by Accesslevel */\r
- // it->second.mMinLv = atoi(row[s_minlv]);\r
- /* ------------------------------------------------ */\r
-\r
- // ToDo: If statement correct? Maybe GSLiveCheck() has\r
- // to be called every mLinvecheckInterval seconds.... We'll\r
- // see when Gameserver has been rewritten\r
-\r
- if(row[s_timecheck] && (atoi(row[s_timecheck]) == 1))\r
- {\r
- it->second.mLasttimestamp = atol(row[s_lastupdate]);\r
- it->second.mOnline = true;\r
- }\r
- else\r
- {\r
- it->second.mOnline = false;\r
- }\r
-\r
- it->second.mUpdated = true;\r
- }\r
- else\r
- {\r
- GameServers tmpServer;\r
-\r
- strncpy(tmpServer.mName, row[s_name], MAX_SERVER_NAME_LENGTH);\r
- tmpServer.mLanIp = IPStringToDWord(row[s_lanaddr]);\r
- tmpServer.mWanIp = IPStringToDWord(row[s_wanaddr]);\r
- tmpServer.mLasttimestamp = atol(row[s_lastupdate]);\r
- tmpServer.mPlayers = atoi(row[s_players]);\r
- tmpServer.mPort = atoi(row[s_port]);\r
- tmpServer.mOnline = true;\r
- tmpServer.mUpdated = true;\r
- Console->Print("Added GameServer %s", tmpServer.mName);\r
- /* Prepared for future addon Servers by Accesslevel */\r
- // tmpServer.mMinLv = atoi(row[s_minlv]);\r
- /* ------------------------------------------------ */\r
-\r
- Serverlist.insert(std::make_pair(atoi(row[s_id]), tmpServer));\r
- }\r
- }\r
- MySQL->FreeSQLResult(result);\r
-\r
- for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++)\r
- {\r
- if(it->second.mUpdated == false)\r
- Serverlist.erase(it);\r
- else\r
- it->second.mUpdated = false;\r
- }\r
-\r
-}\r
-\r
-void PInfoServer::ClientDisconnected(PClient *Client)\r
-{\r
- InfoStateMap::iterator node = ClientStates.find(Client);\r
- if(node == ClientStates.end())\r
- return;\r
-\r
- PInfoState *State = node->second;\r
- FinalizeClient(Client, State);\r
-}\r
-\r
-bool PInfoServer::HandleHandshake(PInfoState *State, const uint8_t *Packet, int32_t PacketSize)\r
-{\r
- //static const uint8_t HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x68};\r
-\r
- switch(State->mState)\r
- {\r
- case PInfoState::IS_HANDSHAKE0 :\r
- {\r
- if(PacketSize==6 && *(uint16_t*)&Packet[3]==0x0080 && Packet[5]==0x78)\r
- {\r
- //FIXME: this packet seems to be unnecessary, although it appears in traffic dumps\r
- // (causes clientside "Wrong protocol" errors)\r
- //Socket->Write(HANDSHAKE1A, 6);\r
- State->mState = PInfoState::IS_AUTHENTICATE;\r
- }\r
- else\r
- {\r
- Console->Print(RED, BLACK, "Infoserver protocol error (IS_HANDSHAKE0): invalid packet [%04x]", *(uint16_t*)&Packet[3]);\r
- return false;\r
- }\r
- break;\r
- }\r
- default:\r
- break;\r
- }\r
-\r
- return true;\r
-}\r
-\r
-bool PInfoServer::HandleAuthenticate(PClient *Client, PInfoState *State, const uint8_t *Packet, int32_t PacketSize)\r
-{\r
- int32_t returnval = 0;\r
- // ReturnValue values:\r
- // 0: No error\r
- // -1: Wrong/Unknown username\r
- // -2: Wrong Password\r
- // -3: Malformed Auth Data. Please relog\r
- // -4: Database error, contact admin\r
- // -5: No such account, Account created. Please relog\r
- // -6: Could not create autoaccount, PW too short\r
- // -7: Could not create autoaccount, Name too short\r
- // -8: Could not create autoaccount, PW and Name too short\r
- // -9: Duplicate entry for Username! Contact Admin\r
- // -10: User is banned\r
- // -11: Insufficient access rights\r
- // -12: Account is not yet activated (accesslevel = 0)\r
- // -99: General fault. Contact admin\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
- PAccount* currentAccount = NULL;\r
-\r
- if (PacketSize > 20 && *(uint16_t *)&Packet[3] == 0x8084)\r
- {\r
- const uint8_t *Key = &Packet[5]; // password key\r
- uint16_t ULen = *(uint16_t *)&Packet[16]; // username length\r
- uint16_t PLen = *(uint16_t *)&Packet[18]; // password length\r
- char *UserName = (char *)&Packet[20]; // account name\r
- const uint8_t *PW = &Packet[20 + ULen]; // encoded password\r
-\r
- if (UserName[ULen-1]) // Check that string is well terminated\r
- {\r
- Console->Print("Infoserver: Client [%d]: Username was not NULL-terminated !", Client->GetIndex());\r
- returnval = -1;\r
- }\r
- else\r
- {\r
- currentAccount = new PAccount(UserName);\r
- if(!currentAccount->GetID())\r
- {\r
- if(Config->GetOptionInt("auto_accounts")) // Autoaccount\r
- {\r
- delete currentAccount;\r
- currentAccount = new PAccount();\r
-\r
- if(!currentAccount->SetName(UserName)) // !!! len\r
- {\r
- returnval = -7;\r
- }\r
- if(!currentAccount->SetPasswordEncoded(PW, PLen, Key))\r
- {\r
- returnval = returnval ? -8 : -6;\r
- }\r
-\r
- if(!returnval)\r
- {\r
- if(currentAccount->Create())\r
- {\r
- returnval = -5;\r
- }\r
- else\r
- {\r
- returnval = -4;\r
- }\r
- }\r
- }\r
- else\r
- {\r
- returnval = -1;\r
- }\r
- }\r
- else\r
- {\r
- if(currentAccount->Authenticate(PW, PLen, Key))\r
- { // Username & Password correct\r
- if(currentAccount->IsBanned())\r
- {\r
- returnval = -10;\r
- }\r
- else if(currentAccount->GetLevel() < Config->GetOptionInt("minlevel")) // insufficient access rights\r
- {\r
- returnval = -11;\r
- }\r
- else if(Config->GetOptionInt("require_validation") == 1 && currentAccount->GetLevel() == PAL_UNREGPLAYER)\r
- {\r
- returnval = -12;\r
- }\r
- else\r
- {\r
- Client->setAccountID(currentAccount->GetID());\r
- returnval = 0;\r
- }\r
-\r
- }\r
- else\r
- {\r
- returnval = -2;\r
- }\r
- }\r
- }\r
-\r
- bool Failed = false;\r
- if(returnval == 0)\r
- {\r
- uint8_t AUTHOK[28]={0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,\r
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
- 0x00, 0x00, 0x00, 0x00, 0x00 };\r
- *(uint32_t *)&AUTHOK[5] = currentAccount->GetID();\r
- Socket->write(AUTHOK, 28);\r
- State->mState = PInfoState::IS_SERVERLIST;\r
- }\r
- else\r
- {\r
- Console->Print("Infoserver: User '%s': authentication failed. Errorcode %d", UserName, returnval);\r
- Failed = true; // auth failed\r
- }\r
- if(Failed == true)\r
- {\r
- std::string errorReason;\r
- switch(returnval)\r
- {\r
- // It seems that the client cuts the line off after 40 chars...\r
-// |1 |10 |20 |30 |40 |50 |60 |70 |80\r
- case -99:\r
- {\r
- //errorReason = "General fault in processing your login request";\r
- errorReason = "General fault while login request";\r
- break;\r
- }\r
- case -12:\r
- {\r
- //errorReason = "Account not activated. Please check your EMails";\r
- errorReason = "Error: Your account is not activated";\r
- break;\r
- }\r
- case -11:\r
- {\r
- //errorReason = "Login rejected. You have to be " + GetAccessString(Config->GetOptionInt("minlevel")) + " or higher";\r
- errorReason = "Level " + GetAccessString(Config->GetOptionInt("minlevel")) + " or higher required";\r
- break;\r
- }\r
- case -10:\r
- {\r
- errorReason = "You are banned for " + currentAccount->GetBannedTime();\r
- break;\r
- }\r
- case -9:\r
- {\r
- //errorReason = "Duplicate entry for this login. Contact Admin";\r
- errorReason = "Duplicate entry found. Contact Admin";\r
- break;\r
- }\r
- case -8:\r
- {\r
- //errorReason = "Autoaccount failed, name and password too short";\r
- errorReason = "AutoAcc failed, name and pwd too short";\r
- break;\r
- }\r
- case -7:\r
- {\r
- errorReason = "Autoaccount failed, name is too short";\r
- break;\r
- }\r
- case -6:\r
- {\r
- //errorReason = "Autoaccount failed, password is too short";\r
- errorReason = "Autoaccount failed, pwd is too short";\r
- break;\r
- }\r
- case -5:\r
- {\r
- errorReason = "New Account created, please login again";\r
- break;\r
- }\r
- case -4:\r
- {\r
- errorReason = "Database error, contact Administrator";\r
- break;\r
- }\r
- case -3:\r
- {\r
- errorReason = "Malformed AuthData. Please login again";\r
- break;\r
- }\r
- case -2:\r
- {\r
- errorReason = "Wrong password";\r
- break;\r
- }\r
- case -1:\r
- {\r
- errorReason = "Unknown username";\r
- break;\r
- }\r
- }\r
- uint8_t AUTHFAILED_HEADER[] = {0xfe, 0x0c, 0x00, 0x83, 0x86, 0x05, 0x00, 0x06, 0x00};\r
- uint8_t AUTHFAILED_FOOTER[] = {0x00, 0x40};\r
- *(uint16_t *)&AUTHFAILED_HEADER[1] = errorReason.size() + 8;\r
- *(uint16_t *)&AUTHFAILED_HEADER[7] = errorReason.size() + 1;\r
- //*(uint8_t*)&AUTHFAILED_FOOTER[1] = {0x40};\r
-\r
- Socket->write(AUTHFAILED_HEADER, sizeof(AUTHFAILED_HEADER));\r
- Socket->write(errorReason.c_str(), errorReason.size());\r
- Socket->write(AUTHFAILED_FOOTER, sizeof(AUTHFAILED_FOOTER));\r
- FinalizeClientDelayed(Client, State);\r
- State->mState=PInfoState::IS_UNKNOWN;\r
- }\r
- }\r
- else\r
- {\r
- Console->Print(RED, BLACK, "Infoserver protocol error (IS_AUTHENTICATE): invalid packet [%04x]",\r
- *(uint16_t *)&Packet[3]);\r
- return false;\r
- }\r
-\r
- return true;\r
-}\r
-\r
-bool PInfoServer::HandleServerList(PClient *Client, const uint8_t *Packet, int32_t PacketSize)\r
-{\r
- uint8_t SERVERLIST_HEAD[] = {0xfe, 0x00, 0x00, 0x83, 0x83, 0x01, 0x00, 0x0d, 0x00};\r
- uint8_t SERVERLIST[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\r
- uint8_t SERVERLIST_FOOTER[] = {0x00};\r
-\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
-\r
- uint32_t tID = *(uint32_t *)&Packet[5];\r
- PAccount* currentAccount = new PAccount(Client->getAccountID());\r
- uint32_t aID = currentAccount->GetID();\r
-\r
- if(!aID || (aID != tID))\r
- {\r
- Console->Print("%s invalid userID %d (auth with id %d)", Console->ColorText(YELLOW, BLACK, "Warning:"), tID, aID);\r
- delete currentAccount;\r
- return false;\r
- }\r
-\r
- if(currentAccount->GetLevel() < Config->GetOptionInt("minlevel"))\r
- {\r
- Console->Print("%s someone tried to bypass the login process! UserID %d", Console->ColorText(RED, BLACK, "Warning:"), aID);\r
- delete currentAccount;\r
- return false;\r
- }\r
-\r
- if(PacketSize == 31 && *(uint16_t *)&Packet[3]==0x8284)\r
- {\r
- GSLiveCheck(); // Perform livecheck to have up-to-date data\r
-\r
- int32_t len = 0;\r
- int32_t num = 0;\r
- for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++)\r
- {\r
- num++;\r
- len += 14 + strlen(it->second.mName);\r
- }\r
-\r
- *(uint16_t *)&SERVERLIST_HEAD[1] = len;\r
- *(uint8_t *)&SERVERLIST_HEAD[5] = num;\r
- Socket->write(SERVERLIST_HEAD, sizeof(SERVERLIST_HEAD));\r
-\r
- for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++)\r
- {\r
- /* Prepared for future addon Servers by Accesslevel */\r
-// if(accesslevel >= it->second.mMinLv)\r
-// {\r
- /* ------------------------------------------------ */\r
- // Todo: Set correct lan/wan IP here!\r
- *(uint32_t *)&SERVERLIST[0] = it->second.mLanIp;\r
- *(uint16_t *)&SERVERLIST[4] = it->second.mPort;\r
- *(uint8_t *)&SERVERLIST[8] = strlen(it->second.mName) + 1;\r
- *(uint16_t *)&SERVERLIST[9] = it->second.mPlayers;\r
- if(it->second.mOnline == true)\r
- {\r
- Console->Print("Sending server name: %s ip: %s player: %d port: %d online: yes", it->second.mName,\r
- IPlongToString(it->second.mLanIp), it->second.mPlayers, it->second.mPort);\r
- *(uint16_t *)&SERVERLIST[11] = 1;\r
- }\r
- else if(it->second.mOnline == false)\r
- {\r
- Console->Print("Sending server name: %s ip: %s player: %d port: %d online: no", it->second.mName,\r
- IPlongToString(it->second.mLanIp), it->second.mPlayers, it->second.mPort);\r
- *(uint16_t *)&SERVERLIST[11] = 0;\r
- }\r
- Socket->write(SERVERLIST, sizeof(SERVERLIST));\r
- Socket->write(it->second.mName, strlen(it->second.mName));\r
- Socket->write(SERVERLIST_FOOTER, sizeof(SERVERLIST_FOOTER));\r
- /* Prepared for future addon Servers by Accesslevel */\r
-// }\r
- /* ------------------------------------------------ */\r
- }\r
- }\r
- else\r
- {\r
- Console->Print(RED, BLACK, "Infoserver protocol error (IS_SERVERLIST): invalid packet [%04x]",\r
- *(uint16_t *)&Packet[3]);\r
- delete currentAccount;\r
- return false;\r
- }\r
- delete currentAccount;\r
- return true;\r
-}\r
-\r
-bool PInfoServer::ProcessClient(PClient *Client, PInfoState *State)\r
-{\r
- static const uint8_t HANDSHAKE0A[6]={0xfe, 0x03, 0x00, 0x80, 0x01, 0x66};\r
-\r
- if(!State)\r
- {\r
- InfoStateMap::iterator node = ClientStates.find(Client);\r
- if(node == ClientStates.end())\r
- return false;\r
-\r
- State = node->second;\r
- }\r
-\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
-\r
- if(State->mWaitSend && Socket->getSendBufferSize()==0)\r
- return false;\r
-\r
- if(State->mState==PInfoState::IS_CONNECTED)\r
- {\r
- Socket->write(HANDSHAKE0A, 6);\r
- State->mState = PInfoState::IS_HANDSHAKE0;\r
- }\r
-\r
- int32_t PacketSize=0;\r
- const uint8_t *Packet = Socket->read(&PacketSize);\r
- if(PacketSize > 0)\r
- {\r
- switch(State->mState)\r
- {\r
- case PInfoState::IS_HANDSHAKE0:\r
- return HandleHandshake(State, Packet, PacketSize);\r
-\r
- case PInfoState::IS_AUTHENTICATE:\r
- return HandleAuthenticate(Client, State, Packet, PacketSize);\r
-\r
- case PInfoState::IS_SERVERLIST:\r
- return HandleServerList(Client, Packet, PacketSize);\r
- default:\r
- break;\r
- }\r
- }\r
- return true;\r
-}\r
-\r
-void PInfoServer::FinalizeClient(PClient *Client, PInfoState *State)\r
-{\r
- Console->Print(RED, BLACK, "Infoserver: client %s disconnected", Client->GetAddress());\r
- Client->InfoDisconnect();\r
- ClientStates.erase(Client);\r
- delete State;\r
-}\r
-\r
-void PInfoServer::FinalizeClientDelayed(PClient *Client, PInfoState *State)\r
-{\r
- Console->Print("Infoserver: client %i is about to be disconnected", Client->GetIndex());\r
- State->mWaitSend = true;\r
-}\r
+#include <cstring>
+#include "InfoServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+struct PInfoState
+{
+ enum State
+ {
+ IS_UNKNOWN,
+ IS_CONNECTED,
+ IS_HANDSHAKE0,
+ IS_AUTHENTICATE,
+ IS_SERVERLIST
+ } mState;
+
+ bool mWaitSend; // wait-for-completition flag
+ PInfoState()
+ {
+ mState = IS_UNKNOWN;
+ mWaitSend = false;
+ };
+};
+
+PInfoServer::PInfoServer()
+{
+ //mNumClients = 1;
+ mLivecheckInterval = Config->GetOptionInt("gameserver_livecheck");
+}
+
+PInfoServer::~PInfoServer()
+{
+ Console->Print("Closing Infoserver...");
+
+ ServerSock->closeServer();
+
+ for(InfoStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end(); i++)
+ delete i->second;
+}
+
+void PInfoServer::Start()
+{
+ uint16_t Port = Config->GetOptionInt("infoserver_port");
+ Console->LPrint("Starting Infoserver on port %i...", Port);
+
+ if(ServerSock->open(Port))
+ {
+ Console->LPrint(GREEN, BLACK, "Success");
+ Console->LClose();
+ }
+ else
+ {
+ Console->LPrint(RED, BLACK, "Failed");
+ Console->LClose();
+ }
+ ServerSock->settimeout(0, 10000);
+ GSLiveCheck();
+}
+
+void PInfoServer::Update()
+{
+ if(ServerSock->newConnection())
+ {
+ int32_t clid = Server->NewClient();
+ if(clid!=-1)
+ {
+ Console->Print(GREEN, BLACK, "Infoserver: client [%i] connected", clid);
+ PClient *Client = Server->GetClient(clid);
+
+ ConnectionTCP* tcpConn = ServerSock->getTCPConnection();
+ Client->setTCPConnection(tcpConn);
+
+ Console->Print("Client address: %s", Client->GetAddress());
+ //++mNumClients;
+
+ PInfoState *state = new PInfoState();
+ ClientStates.insert(std::make_pair(Client, state));
+ state->mState = PInfoState::IS_CONNECTED;
+ } else
+ {
+ Console->Print("Infoserver: Client connection refused (server full?)");
+ }
+ }
+
+ for(InfoStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end();)
+ {
+ PClient *Client = i->first;
+ PInfoState *State = i->second;
+ // node gets erased in FinalizeClient, increment iterator now
+ ++i;
+ if(!ProcessClient(Client, State))
+ FinalizeClient(Client, State);
+ }
+}
+
+void PInfoServer::GSLiveCheck()
+{
+ MYSQL_ROW row;
+ MYSQL_RES *result;
+ char query[256];
+ snprintf (query, 256, "SELECT *, (NOW()< (`s_lastupdate` + INTERVAL %d SECOND)) FROM `server_list`", mLivecheckInterval);
+
+ result = MySQL->ResQuery(query);
+ if (result == nullptr)
+ {
+ Console->Print("Livecheck: %s unable to read server list!", Console->ColorText(RED, BLACK, "[Warning]"));
+ MySQL->ShowSQLError();
+ return;
+ }
+ if(mysql_num_rows(result) == 0)
+ {
+ Console->Print("Livecheck: %s no gameserver found!", Console->ColorText(RED, BLACK, "[Warning]"));
+ MySQL->FreeSQLResult(result);
+ return;
+ }
+
+ ServerMap::iterator it;
+ while((row = mysql_fetch_row(result)))
+ {
+ it = Serverlist.find(atoi(row[s_id]));
+ if(it != Serverlist.end())
+ {
+ strncpy(it->second.mName, row[s_name], MAX_SERVER_NAME_LENGTH);
+ it->second.mLanIp = IPStringToDWord(row[s_lanaddr]);
+ it->second.mWanIp = IPStringToDWord(row[s_wanaddr]);
+ it->second.mPort = atoi(row[s_port]);
+ it->second.mPlayers = atoi(row[s_players]);
+ /* Prepared for future addon Servers by Accesslevel */
+ // it->second.mMinLv = atoi(row[s_minlv]);
+ /* ------------------------------------------------ */
+
+ // ToDo: If statement correct? Maybe GSLiveCheck() has
+ // to be called every mLinvecheckInterval seconds.... We'll
+ // see when Gameserver has been rewritten
+
+ if(row[s_timecheck] && (atoi(row[s_timecheck]) == 1))
+ {
+ it->second.mLasttimestamp = atol(row[s_lastupdate]);
+ it->second.mOnline = true;
+ }
+ else
+ {
+ it->second.mOnline = false;
+ }
+
+ it->second.mUpdated = true;
+ }
+ else
+ {
+ GameServers tmpServer;
+
+ strncpy(tmpServer.mName, row[s_name], MAX_SERVER_NAME_LENGTH);
+ tmpServer.mLanIp = IPStringToDWord(row[s_lanaddr]);
+ tmpServer.mWanIp = IPStringToDWord(row[s_wanaddr]);
+ tmpServer.mLasttimestamp = atol(row[s_lastupdate]);
+ tmpServer.mPlayers = atoi(row[s_players]);
+ tmpServer.mPort = atoi(row[s_port]);
+ tmpServer.mOnline = true;
+ tmpServer.mUpdated = true;
+ Console->Print("Added GameServer %s", tmpServer.mName);
+ /* Prepared for future addon Servers by Accesslevel */
+ // tmpServer.mMinLv = atoi(row[s_minlv]);
+ /* ------------------------------------------------ */
+
+ Serverlist.insert(std::make_pair(atoi(row[s_id]), tmpServer));
+ }
+ }
+ MySQL->FreeSQLResult(result);
+
+ for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++)
+ {
+ if(it->second.mUpdated == false)
+ Serverlist.erase(it);
+ else
+ it->second.mUpdated = false;
+ }
+
+}
+
+void PInfoServer::ClientDisconnected(PClient *Client)
+{
+ InfoStateMap::iterator node = ClientStates.find(Client);
+ if(node == ClientStates.end())
+ return;
+
+ PInfoState *State = node->second;
+ FinalizeClient(Client, State);
+}
+
+bool PInfoServer::HandleHandshake(PInfoState *State, const uint8_t *Packet, int32_t PacketSize)
+{
+ //static const uint8_t HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x68};
+
+ switch(State->mState)
+ {
+ case PInfoState::IS_HANDSHAKE0 :
+ {
+ if(PacketSize==6 && *(uint16_t*)&Packet[3]==0x0080 && Packet[5]==0x78)
+ {
+ //FIXME: this packet seems to be unnecessary, although it appears in traffic dumps
+ // (causes clientside "Wrong protocol" errors)
+ //Socket->Write(HANDSHAKE1A, 6);
+ State->mState = PInfoState::IS_AUTHENTICATE;
+ }
+ else
+ {
+ Console->Print(RED, BLACK, "Infoserver protocol error (IS_HANDSHAKE0): invalid packet [%04x]", *(uint16_t*)&Packet[3]);
+ return false;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return true;
+}
+
+bool PInfoServer::HandleAuthenticate(PClient *Client, PInfoState *State, const uint8_t *Packet, int32_t PacketSize)
+{
+ int32_t returnval = 0;
+ // ReturnValue values:
+ // 0: No error
+ // -1: Wrong/Unknown username
+ // -2: Wrong Password
+ // -3: Malformed Auth Data. Please relog
+ // -4: Database error, contact admin
+ // -5: No such account, Account created. Please relog
+ // -6: Could not create autoaccount, PW too short
+ // -7: Could not create autoaccount, Name too short
+ // -8: Could not create autoaccount, PW and Name too short
+ // -9: Duplicate entry for Username! Contact Admin
+ // -10: User is banned
+ // -11: Insufficient access rights
+ // -12: Account is not yet activated (accesslevel = 0)
+ // -99: General fault. Contact admin
+ ConnectionTCP *Socket = Client->getTCPConn();
+ PAccount* currentAccount = NULL;
+
+ if (PacketSize > 20 && *(uint16_t *)&Packet[3] == 0x8084)
+ {
+ const uint8_t *Key = &Packet[5]; // password key
+ uint16_t ULen = *(uint16_t *)&Packet[16]; // username length
+ uint16_t PLen = *(uint16_t *)&Packet[18]; // password length
+ char *UserName = (char *)&Packet[20]; // account name
+ const uint8_t *PW = &Packet[20 + ULen]; // encoded password
+
+ if (UserName[ULen-1]) // Check that string is well terminated
+ {
+ Console->Print("Infoserver: Client [%d]: Username was not NULL-terminated !", Client->GetIndex());
+ returnval = -1;
+ }
+ else
+ {
+ currentAccount = new PAccount(UserName);
+ if(!currentAccount->GetID())
+ {
+ if(Config->GetOptionInt("auto_accounts")) // Autoaccount
+ {
+ delete currentAccount;
+ currentAccount = new PAccount();
+
+ if(!currentAccount->SetName(UserName)) // !!! len
+ {
+ returnval = -7;
+ }
+ if(!currentAccount->SetPasswordEncoded(PW, PLen, Key))
+ {
+ returnval = returnval ? -8 : -6;
+ }
+
+ if(!returnval)
+ {
+ if(currentAccount->Create())
+ {
+ returnval = -5;
+ }
+ else
+ {
+ returnval = -4;
+ }
+ }
+ }
+ else
+ {
+ returnval = -1;
+ }
+ }
+ else
+ {
+ if(currentAccount->Authenticate(PW, PLen, Key))
+ { // Username & Password correct
+ if(currentAccount->IsBanned())
+ {
+ returnval = -10;
+ }
+ else if(currentAccount->GetLevel() < Config->GetOptionInt("minlevel")) // insufficient access rights
+ {
+ returnval = -11;
+ }
+ else if(Config->GetOptionInt("require_validation") == 1 && currentAccount->GetLevel() == PAL_UNREGPLAYER)
+ {
+ returnval = -12;
+ }
+ else
+ {
+ Client->setAccountID(currentAccount->GetID());
+ returnval = 0;
+ }
+
+ }
+ else
+ {
+ returnval = -2;
+ }
+ }
+ }
+
+ bool Failed = false;
+ if(returnval == 0)
+ {
+ uint8_t AUTHOK[28]={0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00 };
+ *(uint32_t *)&AUTHOK[5] = currentAccount->GetID();
+ Socket->write(AUTHOK, 28);
+ State->mState = PInfoState::IS_SERVERLIST;
+ }
+ else
+ {
+ Console->Print("Infoserver: User '%s': authentication failed. Errorcode %d", UserName, returnval);
+ Failed = true; // auth failed
+ }
+ if(Failed == true)
+ {
+ std::string errorReason;
+ switch(returnval)
+ {
+ // It seems that the client cuts the line off after 40 chars...
+// |1 |10 |20 |30 |40 |50 |60 |70 |80
+ case -99:
+ {
+ //errorReason = "General fault in processing your login request";
+ errorReason = "General fault while login request";
+ break;
+ }
+ case -12:
+ {
+ //errorReason = "Account not activated. Please check your EMails";
+ errorReason = "Error: Your account is not activated";
+ break;
+ }
+ case -11:
+ {
+ //errorReason = "Login rejected. You have to be " + GetAccessString(Config->GetOptionInt("minlevel")) + " or higher";
+ errorReason = "Level " + GetAccessString(Config->GetOptionInt("minlevel")) + " or higher required";
+ break;
+ }
+ case -10:
+ {
+ errorReason = "You are banned for " + currentAccount->GetBannedTime();
+ break;
+ }
+ case -9:
+ {
+ //errorReason = "Duplicate entry for this login. Contact Admin";
+ errorReason = "Duplicate entry found. Contact Admin";
+ break;
+ }
+ case -8:
+ {
+ //errorReason = "Autoaccount failed, name and password too short";
+ errorReason = "AutoAcc failed, name and pwd too short";
+ break;
+ }
+ case -7:
+ {
+ errorReason = "Autoaccount failed, name is too short";
+ break;
+ }
+ case -6:
+ {
+ //errorReason = "Autoaccount failed, password is too short";
+ errorReason = "Autoaccount failed, pwd is too short";
+ break;
+ }
+ case -5:
+ {
+ errorReason = "New Account created, please login again";
+ break;
+ }
+ case -4:
+ {
+ errorReason = "Database error, contact Administrator";
+ break;
+ }
+ case -3:
+ {
+ errorReason = "Malformed AuthData. Please login again";
+ break;
+ }
+ case -2:
+ {
+ errorReason = "Wrong password";
+ break;
+ }
+ case -1:
+ {
+ errorReason = "Unknown username";
+ break;
+ }
+ }
+ uint8_t AUTHFAILED_HEADER[] = {0xfe, 0x0c, 0x00, 0x83, 0x86, 0x05, 0x00, 0x06, 0x00};
+ uint8_t AUTHFAILED_FOOTER[] = {0x00, 0x40};
+ *(uint16_t *)&AUTHFAILED_HEADER[1] = errorReason.size() + 8;
+ *(uint16_t *)&AUTHFAILED_HEADER[7] = errorReason.size() + 1;
+ //*(uint8_t*)&AUTHFAILED_FOOTER[1] = {0x40};
+
+ Socket->write(AUTHFAILED_HEADER, sizeof(AUTHFAILED_HEADER));
+ Socket->write(errorReason.c_str(), errorReason.size());
+ Socket->write(AUTHFAILED_FOOTER, sizeof(AUTHFAILED_FOOTER));
+ FinalizeClientDelayed(Client, State);
+ State->mState=PInfoState::IS_UNKNOWN;
+ }
+ }
+ else
+ {
+ Console->Print(RED, BLACK, "Infoserver protocol error (IS_AUTHENTICATE): invalid packet [%04x]",
+ *(uint16_t *)&Packet[3]);
+ return false;
+ }
+
+ return true;
+}
+
+bool PInfoServer::HandleServerList(PClient *Client, const uint8_t *Packet, int32_t PacketSize)
+{
+ uint8_t SERVERLIST_HEAD[] = {0xfe, 0x00, 0x00, 0x83, 0x83, 0x01, 0x00, 0x0d, 0x00};
+ uint8_t SERVERLIST[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ uint8_t SERVERLIST_FOOTER[] = {0x00};
+
+ ConnectionTCP *Socket = Client->getTCPConn();
+
+ uint32_t tID = *(uint32_t *)&Packet[5];
+ PAccount* currentAccount = new PAccount(Client->getAccountID());
+ uint32_t aID = currentAccount->GetID();
+
+ if(!aID || (aID != tID))
+ {
+ Console->Print("%s invalid userID %d (auth with id %d)", Console->ColorText(YELLOW, BLACK, "Warning:"), tID, aID);
+ delete currentAccount;
+ return false;
+ }
+
+ if(currentAccount->GetLevel() < Config->GetOptionInt("minlevel"))
+ {
+ Console->Print("%s someone tried to bypass the login process! UserID %d", Console->ColorText(RED, BLACK, "Warning:"), aID);
+ delete currentAccount;
+ return false;
+ }
+
+ if(PacketSize == 31 && *(uint16_t *)&Packet[3]==0x8284)
+ {
+ GSLiveCheck(); // Perform livecheck to have up-to-date data
+
+ int32_t len = 0;
+ int32_t num = 0;
+ for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++)
+ {
+ num++;
+ len += 14 + strlen(it->second.mName);
+ }
+
+ *(uint16_t *)&SERVERLIST_HEAD[1] = len;
+ *(uint8_t *)&SERVERLIST_HEAD[5] = num;
+ Socket->write(SERVERLIST_HEAD, sizeof(SERVERLIST_HEAD));
+
+ for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++)
+ {
+ /* Prepared for future addon Servers by Accesslevel */
+// if(accesslevel >= it->second.mMinLv)
+// {
+ /* ------------------------------------------------ */
+ // Todo: Set correct lan/wan IP here!
+ *(uint32_t *)&SERVERLIST[0] = it->second.mLanIp;
+ *(uint16_t *)&SERVERLIST[4] = it->second.mPort;
+ *(uint8_t *)&SERVERLIST[8] = strlen(it->second.mName) + 1;
+ *(uint16_t *)&SERVERLIST[9] = it->second.mPlayers;
+ if(it->second.mOnline == true)
+ {
+ Console->Print("Sending server name: %s ip: %s player: %d port: %d online: yes", it->second.mName,
+ IPlongToString(it->second.mLanIp), it->second.mPlayers, it->second.mPort);
+ *(uint16_t *)&SERVERLIST[11] = 1;
+ }
+ else if(it->second.mOnline == false)
+ {
+ Console->Print("Sending server name: %s ip: %s player: %d port: %d online: no", it->second.mName,
+ IPlongToString(it->second.mLanIp), it->second.mPlayers, it->second.mPort);
+ *(uint16_t *)&SERVERLIST[11] = 0;
+ }
+ Socket->write(SERVERLIST, sizeof(SERVERLIST));
+ Socket->write(it->second.mName, strlen(it->second.mName));
+ Socket->write(SERVERLIST_FOOTER, sizeof(SERVERLIST_FOOTER));
+ /* Prepared for future addon Servers by Accesslevel */
+// }
+ /* ------------------------------------------------ */
+ }
+ }
+ else
+ {
+ Console->Print(RED, BLACK, "Infoserver protocol error (IS_SERVERLIST): invalid packet [%04x]",
+ *(uint16_t *)&Packet[3]);
+ delete currentAccount;
+ return false;
+ }
+ delete currentAccount;
+ return true;
+}
+
+bool PInfoServer::ProcessClient(PClient *Client, PInfoState *State)
+{
+ static const uint8_t HANDSHAKE0A[6]={0xfe, 0x03, 0x00, 0x80, 0x01, 0x66};
+
+ if(!State)
+ {
+ InfoStateMap::iterator node = ClientStates.find(Client);
+ if(node == ClientStates.end())
+ return false;
+
+ State = node->second;
+ }
+
+ ConnectionTCP *Socket = Client->getTCPConn();
+
+ if(State->mWaitSend && Socket->getSendBufferSize()==0)
+ return false;
+
+ if(State->mState==PInfoState::IS_CONNECTED)
+ {
+ Socket->write(HANDSHAKE0A, 6);
+ State->mState = PInfoState::IS_HANDSHAKE0;
+ }
+
+ int32_t PacketSize=0;
+ const uint8_t *Packet = Socket->read(&PacketSize);
+ if(PacketSize > 0)
+ {
+ switch(State->mState)
+ {
+ case PInfoState::IS_HANDSHAKE0:
+ return HandleHandshake(State, Packet, PacketSize);
+
+ case PInfoState::IS_AUTHENTICATE:
+ return HandleAuthenticate(Client, State, Packet, PacketSize);
+
+ case PInfoState::IS_SERVERLIST:
+ return HandleServerList(Client, Packet, PacketSize);
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
+void PInfoServer::FinalizeClient(PClient *Client, PInfoState *State)
+{
+ Console->Print(RED, BLACK, "Infoserver: client %s disconnected", Client->GetAddress());
+ Client->InfoDisconnect();
+ ClientStates.erase(Client);
+ delete State;
+}
+
+void PInfoServer::FinalizeClientDelayed(PClient *Client, PInfoState *State)
+{
+ Console->Print("Infoserver: client %i is about to be disconnected", Client->GetIndex());
+ State->mWaitSend = true;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <map>\r
-\r
-class PClient;\r
-struct PInfoState;\r
-\r
-#define MAX_SERVER_NAME_LENGTH 45\r
-struct GameServers {\r
- char mName[MAX_SERVER_NAME_LENGTH];\r
- uint32_t mLanIp;\r
- uint32_t mWanIp;\r
- int16_t mPort;\r
- int32_t mPlayers;\r
- bool mOnline;\r
- bool mUpdated;\r
- time_t mLasttimestamp;\r
-/* Prepared for future addon Servers by Accesslevel */\r
-// int mMinLv;\r
-/* ------------------------------------------------ */\r
-};\r
-\r
-class PInfoServer {\r
-private:\r
- // SQL layout\r
- enum {\r
- s_id,\r
- s_name,\r
- s_wanaddr,\r
- s_port,\r
- s_players,\r
- s_lastupdate,\r
- s_lanaddr,\r
- s_timecheck // computed field, not in table !\r
- };\r
- //int mNumClients;\r
- typedef std::map<PClient *, struct PInfoState *> InfoStateMap;\r
- InfoStateMap ClientStates;\r
-\r
- typedef std::map<int32_t, GameServers> ServerMap;\r
- ServerMap Serverlist;\r
-\r
- //time_t mLastLivecheck;\r
- int mLivecheckInterval;\r
- void GSLiveCheck();\r
-\r
-protected:\r
- bool ProcessClient(PClient *Client, PInfoState *State = nullptr);\r
- void FinalizeClient(PClient *Client, PInfoState *State);\r
- void FinalizeClientDelayed(PClient *Client, PInfoState *State);\r
-\r
- bool HandleHandshake(PInfoState *State, const uint8_t *Packet, int32_t PacketSize);\r
- bool HandleAuthenticate(PClient *Client, PInfoState *State, const uint8_t *Packet, int32_t PacketSize);\r
- bool HandleServerList(PClient *Client, const uint8_t *Packet, int32_t PacketSize);\r
-\r
-public:\r
- PInfoServer();\r
- ~PInfoServer();\r
-\r
- void Start();\r
- void Update();\r
- void ClientDisconnected(PClient *Client);\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <map>
+
+class PClient;
+struct PInfoState;
+
+#define MAX_SERVER_NAME_LENGTH 45
+struct GameServers {
+ char mName[MAX_SERVER_NAME_LENGTH];
+ uint32_t mLanIp;
+ uint32_t mWanIp;
+ int16_t mPort;
+ int32_t mPlayers;
+ bool mOnline;
+ bool mUpdated;
+ time_t mLasttimestamp;
+/* Prepared for future addon Servers by Accesslevel */
+// int mMinLv;
+/* ------------------------------------------------ */
+};
+
+class PInfoServer {
+private:
+ // SQL layout
+ enum {
+ s_id,
+ s_name,
+ s_wanaddr,
+ s_port,
+ s_players,
+ s_lastupdate,
+ s_lanaddr,
+ s_timecheck // computed field, not in table !
+ };
+ //int mNumClients;
+ typedef std::map<PClient *, struct PInfoState *> InfoStateMap;
+ InfoStateMap ClientStates;
+
+ typedef std::map<int32_t, GameServers> ServerMap;
+ ServerMap Serverlist;
+
+ //time_t mLastLivecheck;
+ int mLivecheckInterval;
+ void GSLiveCheck();
+
+protected:
+ bool ProcessClient(PClient *Client, PInfoState *State = nullptr);
+ void FinalizeClient(PClient *Client, PInfoState *State);
+ void FinalizeClientDelayed(PClient *Client, PInfoState *State);
+
+ bool HandleHandshake(PInfoState *State, const uint8_t *Packet, int32_t PacketSize);
+ bool HandleAuthenticate(PClient *Client, PInfoState *State, const uint8_t *Packet, int32_t PacketSize);
+ bool HandleServerList(PClient *Client, const uint8_t *Packet, int32_t PacketSize);
+
+public:
+ PInfoServer();
+ ~PInfoServer();
+
+ void Start();
+ void Update();
+ void ClientDisconnected(PClient *Client);
+};
-#include <csignal>\r
-#include "InfoServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-void signal_handler(int signal)\r
-{\r
- if (signal == SIGINT)\r
- Shutdown();\r
-}\r
-\r
-int main()\r
-{\r
- signal(SIGINT, signal_handler);\r
-\r
- if (!Init())\r
- {\r
- if(Console)\r
- Console->Print("%s Aborting startup.", Console->ColorText(RED, BLACK, "[Fatal]"));\r
- Shutdown(); // exits with 0 ...\r
- }\r
-\r
- InfoServer->Start();\r
- Console->Print("Infoserver is now %s. Waiting for clients...", Console->ColorText(GREEN, BLACK, "Online"));\r
-\r
- while (true)\r
- {\r
- ServerSock->update();\r
- Server->Update();\r
- InfoServer->Update();\r
- MySQL->Update(); // MySQL keepalive\r
- Console->Update();\r
- }\r
-\r
- return 0;\r
-}\r
+#include <csignal>
+#include "InfoServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+void signal_handler(int signal)
+{
+ if (signal == SIGINT)
+ Shutdown();
+}
+
+int main()
+{
+ signal(SIGINT, signal_handler);
+
+ if (!Init())
+ {
+ if(Console)
+ Console->Print("%s Aborting startup.", Console->ColorText(RED, BLACK, "[Fatal]"));
+ Shutdown(); // exits with 0 ...
+ }
+
+ InfoServer->Start();
+ Console->Print("Infoserver is now %s. Waiting for clients...", Console->ColorText(GREEN, BLACK, "Online"));
+
+ while (true)
+ {
+ ServerSock->update();
+ Server->Update();
+ InfoServer->Update();
+ MySQL->Update(); // MySQL keepalive
+ Console->Update();
+ }
+
+ return 0;
+}
-#include "InfoServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-PServer::PServer()\r
-{\r
- mMaxClients = Config->GetOptionInt("maxclients");\r
-\r
- mClients.reserve(mMaxClients);\r
- mNumClients = 0;\r
- for (int32_t i=0; i<mMaxClients; i++)\r
- mClients[i]=0;\r
-}\r
-\r
-PServer::~PServer()\r
-{\r
- for (int32_t i=0; i<mMaxClients; i++)\r
- delete mClients[i];\r
-}\r
-\r
-int32_t PServer::GetNumClients() const\r
-{\r
- return mNumClients;\r
-}\r
-\r
-int PServer::NewClient()\r
-{\r
- if(mNumClients==mMaxClients)\r
- return -1;\r
-\r
- for (int32_t i=0; i<mMaxClients; i++)\r
- {\r
- if(!mClients[i])\r
- {\r
- mClients[i]=new PClient(i);\r
- ++mNumClients;\r
- return i;\r
- }\r
- }\r
- return -1;\r
-}\r
-\r
-PClient *PServer::GetClient(int32_t Client) const\r
-{\r
- if (Client < 0 || Client >= mMaxClients)\r
- return 0;\r
-\r
- return mClients[Client];\r
-}\r
-\r
-void PServer::Update()\r
-{\r
- for (int32_t i=0; i<mMaxClients; i++)\r
- {\r
- if(mClients[i])\r
- {\r
- mClients[i]->Update();\r
- if(mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0)\r
- {\r
- Console->Print("Removing client ...");\r
- delete mClients[i];\r
- mClients[i]=0;\r
- --mNumClients;\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PServer::Shutdown()\r
-{\r
- Console->Print("======================");\r
- Console->Print("Shutting down Infoserver...");\r
- for (int32_t i=0; i<mMaxClients; i++)\r
- {\r
- if(mClients[i])\r
- {\r
- delete mClients[i];\r
- mClients[i]=0;\r
- }\r
- }\r
-}\r
+#include "InfoServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+PServer::PServer()
+{
+ mMaxClients = Config->GetOptionInt("maxclients");
+
+ mClients.reserve(mMaxClients);
+ mNumClients = 0;
+ for (int32_t i=0; i<mMaxClients; i++)
+ mClients[i]=0;
+}
+
+PServer::~PServer()
+{
+ for (int32_t i=0; i<mMaxClients; i++)
+ delete mClients[i];
+}
+
+int32_t PServer::GetNumClients() const
+{
+ return mNumClients;
+}
+
+int PServer::NewClient()
+{
+ if(mNumClients==mMaxClients)
+ return -1;
+
+ for (int32_t i=0; i<mMaxClients; i++)
+ {
+ if(!mClients[i])
+ {
+ mClients[i]=new PClient(i);
+ ++mNumClients;
+ return i;
+ }
+ }
+ return -1;
+}
+
+PClient *PServer::GetClient(int32_t Client) const
+{
+ if (Client < 0 || Client >= mMaxClients)
+ return 0;
+
+ return mClients[Client];
+}
+
+void PServer::Update()
+{
+ for (int32_t i=0; i<mMaxClients; i++)
+ {
+ if(mClients[i])
+ {
+ mClients[i]->Update();
+ if(mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0)
+ {
+ Console->Print("Removing client ...");
+ delete mClients[i];
+ mClients[i]=0;
+ --mNumClients;
+ }
+ }
+ }
+}
+
+void PServer::Shutdown()
+{
+ Console->Print("======================");
+ Console->Print("Shutting down Infoserver...");
+ for (int32_t i=0; i<mMaxClients; i++)
+ {
+ if(mClients[i])
+ {
+ delete mClients[i];
+ mClients[i]=0;
+ }
+ }
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <vector>\r
-\r
-class PClient;\r
-\r
-class PServer {\r
-private:\r
- int32_t mMaxClients;\r
- int32_t mNumClients;\r
- std::vector<PClient *> mClients;\r
-\r
-public:\r
- PServer();\r
- ~PServer();\r
-\r
- int32_t GetNumClients() const;\r
- int32_t NewClient();\r
- PClient *GetClient(int32_t Client) const;\r
- void Update();\r
- void Shutdown();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+class PClient;
+
+class PServer {
+private:
+ int32_t mMaxClients;
+ int32_t mNumClients;
+ std::vector<PClient *> mClients;
+
+public:
+ PServer();
+ ~PServer();
+
+ int32_t GetNumClients() const;
+ int32_t NewClient();
+ PClient *GetClient(int32_t Client) const;
+ void Update();
+ void Shutdown();
+};
-#include <cstring>\r
-#include "InfoServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-PMySQL::PMySQL()\r
-{\r
- port = Config->GetOptionInt("sql_port");\r
- strncpy(host, Config->GetOption("sql_host").c_str(), 100);\r
- strncpy(userName, Config->GetOption("sql_username").c_str(), 100);\r
- strncpy(password, Config->GetOption("sql_password").c_str(), 100);\r
- strncpy(database, Config->GetOption("global_sql_database").c_str(), 100);\r
-\r
- mKeepaliveDelay = (time_t) (Config->GetOptionInt("mysql_wait_timeout") * 0.9) ; // we take 90% of the wait_timeout to trigger keepalive\r
- if (mKeepaliveDelay == 0)\r
- {\r
- Console->Print("%s MySQL keepalive disabled by config", Console->ColorText(GREEN, BLACK, "[Info]"));\r
- }\r
- else if (mKeepaliveDelay < 60)\r
- {\r
- Console->Print("%s Configuration option 'mysql_wait_timeout' is too low (%d sec). Reset to 60 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mKeepaliveDelay);\r
- mKeepaliveDelay = 60;\r
- }\r
- mLastKeepaliveSent = 0;\r
-}\r
-\r
-PMySQL::~PMySQL()\r
-{\r
- Console->Print("Closing MySQL connection...");\r
- mysql_close(dbHandle);\r
-}\r
-\r
-void PMySQL::Update()\r
-{\r
- // MySQL keepalive\r
- time_t t = std::time(NULL);\r
- if ((mKeepaliveDelay > 0) && ((t - mLastKeepaliveSent) > mKeepaliveDelay))\r
- {\r
- MYSQL_RES *result;\r
- char query[24];\r
- snprintf (query, 24, "SELECT NOW()");\r
-\r
- result = ResQuery(query);\r
- if(!result)\r
- {\r
- Console->Print("%s Can't send InfoDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));\r
- ShowSQLError();\r
- return;\r
- }\r
- else\r
- FreeSQLResult(result);\r
-\r
- mLastKeepaliveSent = std::time(NULL);\r
-//Console->Print("%s MySQL keepalive sent", Console->ColorText(GREEN, BLACK, "[Debug]"));\r
- }\r
-}\r
-\r
-MYSQL *PMySQL::GetHandle()\r
-{\r
- return dbHandle;\r
-}\r
-\r
-bool PMySQL::Connect()\r
-{\r
- Console->LPrint("Establishing link to MySQL Database...");\r
-\r
- dbHandle = mysql_init(NULL);\r
-\r
- if(dbHandle)\r
- {\r
- //Console->Print("MySQL-Handle successfully initialized.");\r
- }\r
- else\r
- {\r
- Console->LPrint(RED, BLACK, "[ERROR]");\r
- Console->LClose();\r
- Console->Print(" MySQL-Handle couldn't be created!");\r
- exit(0);\r
- }\r
-\r
- if(!mysql_real_connect(dbHandle, host, userName, password, database, port, NULL, 0))\r
- {\r
- Console->LPrint(RED, BLACK, "[ERROR]");\r
- Console->LClose();\r
- Console->Print("Unable to connect to MySQL Database. MySQL returned: %s", mysql_error(dbHandle));\r
- return false;\r
- }\r
- else\r
- {\r
- Console->LPrint(GREEN, BLACK, "Success");\r
- Console->LClose();\r
- return true;\r
- }\r
-}\r
-\r
-MYSQL_RES *PMySQL::ResQuery(const char *query)\r
-{\r
- int32_t sql_result = 0;\r
- MYSQL_RES *result;\r
-\r
- sql_result = mysql_real_query(dbHandle, query, strlen(query));\r
- if(sql_result)\r
- {\r
- return NULL;\r
- }\r
- result = mysql_store_result(dbHandle);\r
- if(!result)\r
- {\r
- return NULL;\r
- }\r
-\r
- return result;\r
-}\r
-\r
-int32_t PMySQL::Query(const char *query)\r
-{\r
- int32_t sql_result = 0;\r
- sql_result = mysql_real_query(dbHandle, query, strlen(query));\r
-\r
- return sql_result;\r
-}\r
-\r
-void PMySQL::ShowSQLError()\r
-{\r
- Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(dbHandle));\r
-}\r
-\r
-void PMySQL::FreeSQLResult(MYSQL_RES *res)\r
-{\r
- mysql_free_result(res);\r
-}\r
-\r
-uint32_t PMySQL::GetLastInsertId()\r
-{\r
- return mysql_insert_id(dbHandle);\r
-}\r
-\r
-uint32_t PMySQL::EscapeString(const char *nText, char *dText, uint32_t dMaxLength)\r
-{\r
- uint32_t nLength = strlen(nText);\r
- uint32_t tMax = (dMaxLength - 1)/2;\r
- if(nLength > tMax)\r
- {\r
- nLength = tMax;\r
- }\r
-\r
- return mysql_real_escape_string(dbHandle, dText, nText, nLength);\r
-}\r
+#include <cstring>
+#include "InfoServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+PMySQL::PMySQL()
+{
+ port = Config->GetOptionInt("sql_port");
+ strncpy(host, Config->GetOption("sql_host").c_str(), 100);
+ strncpy(userName, Config->GetOption("sql_username").c_str(), 100);
+ strncpy(password, Config->GetOption("sql_password").c_str(), 100);
+ strncpy(database, Config->GetOption("global_sql_database").c_str(), 100);
+
+ mKeepaliveDelay = (time_t) (Config->GetOptionInt("mysql_wait_timeout") * 0.9) ; // we take 90% of the wait_timeout to trigger keepalive
+ if (mKeepaliveDelay == 0)
+ {
+ Console->Print("%s MySQL keepalive disabled by config", Console->ColorText(GREEN, BLACK, "[Info]"));
+ }
+ else if (mKeepaliveDelay < 60)
+ {
+ Console->Print("%s Configuration option 'mysql_wait_timeout' is too low (%d sec). Reset to 60 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mKeepaliveDelay);
+ mKeepaliveDelay = 60;
+ }
+ mLastKeepaliveSent = 0;
+}
+
+PMySQL::~PMySQL()
+{
+ Console->Print("Closing MySQL connection...");
+ mysql_close(dbHandle);
+}
+
+void PMySQL::Update()
+{
+ // MySQL keepalive
+ time_t t = std::time(NULL);
+ if ((mKeepaliveDelay > 0) && ((t - mLastKeepaliveSent) > mKeepaliveDelay))
+ {
+ MYSQL_RES *result;
+ char query[24];
+ snprintf (query, 24, "SELECT NOW()");
+
+ result = ResQuery(query);
+ if(!result)
+ {
+ Console->Print("%s Can't send InfoDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]"));
+ ShowSQLError();
+ return;
+ }
+ else
+ FreeSQLResult(result);
+
+ mLastKeepaliveSent = std::time(NULL);
+//Console->Print("%s MySQL keepalive sent", Console->ColorText(GREEN, BLACK, "[Debug]"));
+ }
+}
+
+MYSQL *PMySQL::GetHandle()
+{
+ return dbHandle;
+}
+
+bool PMySQL::Connect()
+{
+ Console->LPrint("Establishing link to MySQL Database...");
+
+ dbHandle = mysql_init(NULL);
+
+ if(dbHandle)
+ {
+ //Console->Print("MySQL-Handle successfully initialized.");
+ }
+ else
+ {
+ Console->LPrint(RED, BLACK, "[ERROR]");
+ Console->LClose();
+ Console->Print(" MySQL-Handle couldn't be created!");
+ exit(0);
+ }
+
+ if(!mysql_real_connect(dbHandle, host, userName, password, database, port, NULL, 0))
+ {
+ Console->LPrint(RED, BLACK, "[ERROR]");
+ Console->LClose();
+ Console->Print("Unable to connect to MySQL Database. MySQL returned: %s", mysql_error(dbHandle));
+ return false;
+ }
+ else
+ {
+ Console->LPrint(GREEN, BLACK, "Success");
+ Console->LClose();
+ return true;
+ }
+}
+
+MYSQL_RES *PMySQL::ResQuery(const char *query)
+{
+ int32_t sql_result = 0;
+ MYSQL_RES *result;
+
+ sql_result = mysql_real_query(dbHandle, query, strlen(query));
+ if(sql_result)
+ {
+ return NULL;
+ }
+ result = mysql_store_result(dbHandle);
+ if(!result)
+ {
+ return NULL;
+ }
+
+ return result;
+}
+
+int32_t PMySQL::Query(const char *query)
+{
+ int32_t sql_result = 0;
+ sql_result = mysql_real_query(dbHandle, query, strlen(query));
+
+ return sql_result;
+}
+
+void PMySQL::ShowSQLError()
+{
+ Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(dbHandle));
+}
+
+void PMySQL::FreeSQLResult(MYSQL_RES *res)
+{
+ mysql_free_result(res);
+}
+
+uint32_t PMySQL::GetLastInsertId()
+{
+ return mysql_insert_id(dbHandle);
+}
+
+uint32_t PMySQL::EscapeString(const char *nText, char *dText, uint32_t dMaxLength)
+{
+ uint32_t nLength = strlen(nText);
+ uint32_t tMax = (dMaxLength - 1)/2;
+ if(nLength > tMax)
+ {
+ nLength = tMax;
+ }
+
+ return mysql_real_escape_string(dbHandle, dText, nText, nLength);
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#ifdef MYSQL_INC_DIR\r
-#include <mysql/mysql.h>\r
-#else\r
-#include <mysql.h>\r
-#endif\r
-\r
-class PMySQL {\r
-private:\r
- int32_t port;\r
- char host[100];\r
- char userName[100];\r
- char password[100];\r
- char database[100];\r
- MYSQL *dbHandle;\r
- time_t mKeepaliveDelay;\r
- time_t mLastKeepaliveSent;\r
-\r
-public:\r
- PMySQL();\r
- ~PMySQL();\r
-\r
- void Update();\r
- MYSQL *GetHandle();\r
-\r
- bool Connect();\r
- int32_t Query(const char *query);\r
- MYSQL_RES *ResQuery(const char *query);\r
- void ShowSQLError();\r
- void FreeSQLResult(MYSQL_RES *res);\r
- uint32_t GetLastInsertId();\r
- uint32_t EscapeString(const char *nText, char *dText, uint32_t dMaxLength);\r
-};\r
+#pragma once
+
+#include <cstdint>
+#ifdef MYSQL_INC_DIR
+#include <mysql/mysql.h>
+#else
+#include <mysql.h>
+#endif
+
+class PMySQL {
+private:
+ int32_t port;
+ char host[100];
+ char userName[100];
+ char password[100];
+ char database[100];
+ MYSQL *dbHandle;
+ time_t mKeepaliveDelay;
+ time_t mLastKeepaliveSent;
+
+public:
+ PMySQL();
+ ~PMySQL();
+
+ void Update();
+ MYSQL *GetHandle();
+
+ bool Connect();
+ int32_t Query(const char *query);
+ MYSQL_RES *ResQuery(const char *query);
+ void ShowSQLError();
+ void FreeSQLResult(MYSQL_RES *res);
+ uint32_t GetLastInsertId();
+ uint32_t EscapeString(const char *nText, char *dText, uint32_t dMaxLength);
+};
-#include "PatchServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-PClient::PClient(int32_t Index)\r
-{\r
- mIndex = Index;\r
- mConnection = PCC_NONE;\r
-}\r
-\r
-PClient::~PClient()\r
-{\r
- if(m_TCPConnection)\r
- {\r
- delete m_TCPConnection;\r
- }\r
-}\r
-\r
-int32_t PClient::GetIndex() const\r
-{\r
- return mIndex;\r
-}\r
-\r
-int32_t PClient::GetConnection() const\r
-{\r
- return mConnection;\r
-}\r
-\r
-const char *PClient::GetAddress() const\r
-{\r
- return m_TCPConnection->getRemoteAddress();\r
-}\r
-\r
-void PClient::setTCPConnection(ConnectionTCP *conn)\r
-{\r
- m_TCPConnection = conn;\r
- mConnection = PCC_PATCH;\r
-}\r
-\r
-ConnectionTCP *PClient::getTCPConn()\r
-{\r
- return m_TCPConnection;\r
-}\r
-\r
-void PClient::Update()\r
-{\r
- if(m_TCPConnection)\r
- {\r
- if(m_TCPConnection->timeOut())\r
- {\r
- Console->Print("Patchsocket: Client %i: timeout", mIndex);\r
- PatchServer->ClientDisconnected(this);\r
- }\r
- else\r
- {\r
- if(!m_TCPConnection->update())\r
- {\r
- PatchServer->ClientDisconnected(this);\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PClient::PatchDisconnect()\r
-{\r
- if(m_TCPConnection)\r
- {\r
- delete m_TCPConnection;\r
- }\r
- mConnection = PCC_NONE;\r
- m_TCPConnection = 0;\r
-}\r
+#include "PatchServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+PClient::PClient(int32_t Index)
+{
+ mIndex = Index;
+ mConnection = PCC_NONE;
+}
+
+PClient::~PClient()
+{
+ if(m_TCPConnection)
+ {
+ delete m_TCPConnection;
+ }
+}
+
+int32_t PClient::GetIndex() const
+{
+ return mIndex;
+}
+
+int32_t PClient::GetConnection() const
+{
+ return mConnection;
+}
+
+const char *PClient::GetAddress() const
+{
+ return m_TCPConnection->getRemoteAddress();
+}
+
+void PClient::setTCPConnection(ConnectionTCP *conn)
+{
+ m_TCPConnection = conn;
+ mConnection = PCC_PATCH;
+}
+
+ConnectionTCP *PClient::getTCPConn()
+{
+ return m_TCPConnection;
+}
+
+void PClient::Update()
+{
+ if(m_TCPConnection)
+ {
+ if(m_TCPConnection->timeOut())
+ {
+ Console->Print("Patchsocket: Client %i: timeout", mIndex);
+ PatchServer->ClientDisconnected(this);
+ }
+ else
+ {
+ if(!m_TCPConnection->update())
+ {
+ PatchServer->ClientDisconnected(this);
+ }
+ }
+ }
+}
+
+void PClient::PatchDisconnect()
+{
+ if(m_TCPConnection)
+ {
+ delete m_TCPConnection;
+ }
+ mConnection = PCC_NONE;
+ m_TCPConnection = 0;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-\r
-class ConnectionTCP;\r
-\r
-enum PClientConnection {\r
- PCC_NONE = 0,\r
- PCC_PATCH = 1\r
-};\r
-\r
-class PClient {\r
-private:\r
- ConnectionTCP *m_TCPConnection;\r
- int32_t mIndex;\r
- int32_t mConnection;\r
-\r
-public:\r
- PClient(int32_t Index);\r
- ~PClient();\r
-\r
- int32_t GetIndex() const;\r
- int32_t GetConnection() const;\r
- const char *GetAddress() const;\r
- void setTCPConnection(ConnectionTCP *conn);\r
- ConnectionTCP *getTCPConn();\r
- void Update();\r
- void PatchDisconnect();\r
-};\r
+#pragma once
+
+#include <cstdint>
+
+class ConnectionTCP;
+
+enum PClientConnection {
+ PCC_NONE = 0,
+ PCC_PATCH = 1
+};
+
+class PClient {
+private:
+ ConnectionTCP *m_TCPConnection;
+ int32_t mIndex;
+ int32_t mConnection;
+
+public:
+ PClient(int32_t Index);
+ ~PClient();
+
+ int32_t GetIndex() const;
+ int32_t GetConnection() const;
+ const char *GetAddress() const;
+ void setTCPConnection(ConnectionTCP *conn);
+ ConnectionTCP *getTCPConn();
+ void Update();
+ void PatchDisconnect();
+};
-#pragma once\r
-\r
-static const char *PatchConfigTemplate[][2] = {\r
- // {option_name, default_value} if default_value is empty string, it means option is mandatory\r
- // List ends with empty string for option_name\r
- {"server_version", "200"},\r
- {"patchserver_port", "8040"},\r
- {"patches_path", "./patches"},\r
- {"file_path", "./files"},\r
- {"max_file_xfers", "5"},\r
- {"patch_packet_size", "512"},\r
- {"maxclients", "5"},\r
- {"gm_slots", "2"},\r
-\r
- {"", ""} // do not change this line (end mark)\r
-};\r
+#pragma once
+
+static const char *PatchConfigTemplate[][2] = {
+ // {option_name, default_value} if default_value is empty string, it means option is mandatory
+ // List ends with empty string for option_name
+ {"server_version", "200"},
+ {"patchserver_port", "8040"},
+ {"patches_path", "./patches"},
+ {"file_path", "./files"},
+ {"max_file_xfers", "5"},
+ {"patch_packet_size", "512"},
+ {"maxclients", "5"},
+ {"gm_slots", "2"},
+
+ {"", ""} // do not change this line (end mark)
+};
-#include "PatchServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-const char ServerVersion[] = TINNS_PATCH_VERSION;\r
-const char SVNRevision[] = TINNS_SVN_REVISION;\r
-\r
-ServerSocket* ServerSock = 0;\r
-PConsole *Console = 0;\r
-PServer *Server = 0;\r
-PConfig *Config = 0;\r
-PFileSystem *Filesystem = 0;\r
-PPatchServer *PatchServer = 0;\r
-\r
-bool InitTinNS()\r
-{\r
- Console = new PConsole("log/patchserver.log"); // Make that from config file !!!\r
- Console->Print("Starting TinNS Patchserver...");\r
- Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\");\r
- Console->Print(WHITE, BLUE, "| TinNS (TinNS is not a Neocron Server) |");\r
- Console->Print(WHITE, BLUE, "| Copyright (C) 2005 Linux Addicted Community |");\r
- Console->Print(WHITE, BLUE, "| maintainer Akiko <akiko@gmx.org> |");\r
- Console->Print(WHITE, BLUE, "| ========================================== |");\r
- Console->Print(WHITE, BLUE, "| Head coders: The packet analyzing team: |");\r
- Console->Print(WHITE, BLUE, "| - Akiko - MaxxJag |");\r
- Console->Print(WHITE, BLUE, "| - bakkdoor - Sting |");\r
- Console->Print(WHITE, BLUE, "| - Namikon - Balm |");\r
- Console->Print(WHITE, BLUE, "| - Hammag |");\r
- Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");\r
- Console->Print(WHITE, BLUE, "| This project would'nt be at its current stage without the help |");\r
- Console->Print(WHITE, BLUE, "| from the NeoPolis team, special thanks to you guys! |");\r
- Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");\r
- Console->Print(WHITE, BLUE, "| This project is under GPL, see any source file for more details |");\r
- Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/");\r
-\r
- //char svnrev[10];\r
- //GetSVNRev(svnrev);\r
- Console->LPrint("You are running TinNS Patchserver version");\r
- Console->LPrint(GREEN, BLACK, " %s", ServerVersion);\r
- Console->LPrint(WHITE, BLACK, " - SVN Rev");\r
- Console->LPrint(GREEN, BLACK, " %s", SVNRevision);\r
- Console->LClose();\r
-\r
- Config = new PConfig();\r
- if(!Config->LoadOptions(PatchConfigTemplate ,"./conf/patchserver.conf"))\r
- Shutdown();\r
-\r
- ServerSock = new ServerSocket();\r
- Server = new PServer();\r
- PatchServer = new PPatchServer();\r
-\r
- return true;\r
-}\r
-\r
-void Shutdown()\r
-{\r
- if(PatchServer) delete PatchServer;\r
- if(Config) delete Config;\r
- if(Console) delete Console;\r
- if(ServerSock) delete ServerSock;\r
- exit(0);\r
-}\r
+#include "PatchServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+const char ServerVersion[] = TINNS_PATCH_VERSION;
+const char SVNRevision[] = TINNS_SVN_REVISION;
+
+ServerSocket* ServerSock = 0;
+PConsole *Console = 0;
+PServer *Server = 0;
+PConfig *Config = 0;
+PFileSystem *Filesystem = 0;
+PPatchServer *PatchServer = 0;
+
+bool InitTinNS()
+{
+ Console = new PConsole("log/patchserver.log"); // Make that from config file !!!
+ Console->Print("Starting TinNS Patchserver...");
+ Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\");
+ Console->Print(WHITE, BLUE, "| TinNS (TinNS is not a Neocron Server) |");
+ Console->Print(WHITE, BLUE, "| Copyright (C) 2005 Linux Addicted Community |");
+ Console->Print(WHITE, BLUE, "| maintainer Akiko <akiko@gmx.org> |");
+ Console->Print(WHITE, BLUE, "| ========================================== |");
+ Console->Print(WHITE, BLUE, "| Head coders: The packet analyzing team: |");
+ Console->Print(WHITE, BLUE, "| - Akiko - MaxxJag |");
+ Console->Print(WHITE, BLUE, "| - bakkdoor - Sting |");
+ Console->Print(WHITE, BLUE, "| - Namikon - Balm |");
+ Console->Print(WHITE, BLUE, "| - Hammag |");
+ Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");
+ Console->Print(WHITE, BLUE, "| This project would'nt be at its current stage without the help |");
+ Console->Print(WHITE, BLUE, "| from the NeoPolis team, special thanks to you guys! |");
+ Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|");
+ Console->Print(WHITE, BLUE, "| This project is under GPL, see any source file for more details |");
+ Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/");
+
+ //char svnrev[10];
+ //GetSVNRev(svnrev);
+ Console->LPrint("You are running TinNS Patchserver version");
+ Console->LPrint(GREEN, BLACK, " %s", ServerVersion);
+ Console->LPrint(WHITE, BLACK, " - SVN Rev");
+ Console->LPrint(GREEN, BLACK, " %s", SVNRevision);
+ Console->LClose();
+
+ Config = new PConfig();
+ if(!Config->LoadOptions(PatchConfigTemplate ,"./conf/patchserver.conf"))
+ Shutdown();
+
+ ServerSock = new ServerSocket();
+ Server = new PServer();
+ PatchServer = new PPatchServer();
+
+ return true;
+}
+
+void Shutdown()
+{
+ if(PatchServer) delete PatchServer;
+ if(Config) delete Config;
+ if(Console) delete Console;
+ if(ServerSock) delete ServerSock;
+ exit(0);
+}
-#pragma once\r
-\r
-#include "PatchServer/Client.hxx"\r
-#include "PatchServer/ConfigTemplate.hxx"\r
-#include "PatchServer/PatchServer.hxx"\r
-#include "PatchServer/Server.hxx"\r
-\r
-extern class ServerSocket* ServerSock;\r
-extern class PConsole *Console;\r
-extern class PConfig *Config;\r
-extern class PFileSystem *Filesystem;\r
-extern class PServer *Server;\r
-extern class PPatchServer *PatchServer;\r
-\r
-extern const char ServerVersion[];\r
-extern const char SVNRevision[];\r
-\r
-bool InitTinNS();\r
-void Shutdown();\r
+#pragma once
+
+#include "PatchServer/Client.hxx"
+#include "PatchServer/ConfigTemplate.hxx"
+#include "PatchServer/PatchServer.hxx"
+#include "PatchServer/Server.hxx"
+
+extern class ServerSocket* ServerSock;
+extern class PConsole *Console;
+extern class PConfig *Config;
+extern class PFileSystem *Filesystem;
+extern class PServer *Server;
+extern class PPatchServer *PatchServer;
+
+extern const char ServerVersion[];
+extern const char SVNRevision[];
+
+bool InitTinNS();
+void Shutdown();
-#include <chrono>\r
-#include <csignal>\r
-#include <thread>\r
-#include "PatchServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-void signal_handler(int signal)\r
-{\r
- if (signal == SIGINT)\r
- Shutdown();\r
- else\r
- psignal(signal, "Unkown signal: ");\r
-}\r
-\r
-int main()\r
-{\r
- signal(SIGINT, signal_handler);\r
-\r
-\r
- if (!InitTinNS())\r
- while (true)\r
- std::this_thread::sleep_for(std::chrono::seconds(1));\r
-\r
- PatchServer->Start();\r
- Console->Print("Patchserver is now %s. Waiting for clients...", Console->ColorText(GREEN, BLACK, "Online"));\r
-\r
- while (true)\r
- {\r
- ServerSock->update();\r
- Server->Update();\r
- PatchServer->Update();\r
- // sched_yield();\r
- }\r
-\r
- return 0;\r
-}\r
+#include <chrono>
+#include <csignal>
+#include <thread>
+#include "PatchServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+void signal_handler(int signal)
+{
+ if (signal == SIGINT)
+ Shutdown();
+ else
+ psignal(signal, "Unkown signal: ");
+}
+
+int main()
+{
+ signal(SIGINT, signal_handler);
+
+
+ if (!InitTinNS())
+ while (true)
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ PatchServer->Start();
+ Console->Print("Patchserver is now %s. Waiting for clients...", Console->ColorText(GREEN, BLACK, "Online"));
+
+ while (true)
+ {
+ ServerSock->update();
+ Server->Update();
+ PatchServer->Update();
+ // sched_yield();
+ }
+
+ return 0;
+}
-#include <cstring>\r
-#include <sstream>\r
-#include "PatchServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-const uint16_t PATCH_PORT = 7000;\r
-\r
-struct PPatchState {\r
- enum State\r
- {\r
- PS_UNKNOWN,\r
- PS_CONNECTED,\r
- PS_HANDSHAKE0,\r
- PS_HANDSHAKE1,\r
- PS_VERSIONREQUEST,\r
- PS_GETPATCHORFILE,\r
- PS_SENDPATCH,\r
- PS_SENDFILE\r
- } mState;\r
-\r
- uint16_t mSerial;\r
-\r
- uint32_t mCurrentPatch;\r
- uint32_t mPatchOffset;\r
- uint32_t mPatchSize;\r
- std::FILE *mPatchFile;\r
-\r
- std::string mCurrentFile;\r
- uint32_t mFileOffset;\r
- uint32_t mFileSize;\r
- PFile *mSendFile;\r
-\r
- bool mWaitSend; // wait-for-completition flag\r
- PPatchState()\r
- {\r
- mState = PS_UNKNOWN;\r
- mSerial = 0;\r
- mCurrentPatch = 0;\r
- mPatchOffset = 0;\r
- mPatchFile = 0;\r
-\r
- mCurrentFile = "";\r
- mFileOffset = 0;\r
- mFileSize = 0;\r
- mSendFile = 0;\r
-\r
- mWaitSend = false;\r
- };\r
-\r
- ~PPatchState()\r
- {\r
- if(mPatchFile)\r
- std::fclose(mPatchFile);\r
- if(mSendFile)\r
- Filesystem->Close(mSendFile);\r
- }\r
-};\r
-\r
-// -------------------------------------------------------\r
-\r
-PPatchServer::PPatchServer()\r
-{\r
- //mNumClients = 1;\r
- mNumFileTransfers = 0;\r
-}\r
-\r
-PPatchServer::~PPatchServer()\r
-{\r
- ServerSock->closeServer();\r
-\r
- for(PatchStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end(); i++)\r
- delete i->second;\r
-}\r
-\r
-void PPatchServer::Start()\r
-{\r
- uint16_t Port = Config->GetOptionInt("patchserver_port");\r
- if(Port==0)\r
- Port=PATCH_PORT;\r
-\r
- Console->LPrint("Starting Patchserver on port %i...", Port);\r
- if(ServerSock->open(Port))\r
- {\r
- Console->LPrint(GREEN, BLACK, "Success");\r
- }\r
- else\r
- {\r
- Console->LPrint(RED, BLACK, "ERROR");\r
- }\r
- Console->LClose();\r
- ServerSock->settimeout(0, 10000);\r
-}\r
-\r
-void PPatchServer::Update()\r
-{\r
- //ServerSock->update();\r
-\r
- if(ServerSock->newConnection())\r
- {\r
- int32_t clid = Server->NewClient();\r
- if(clid!=-1)\r
- {\r
- Console->Print(GREEN, BLACK, "Patchserver: client [%i] connected", clid);\r
- PClient *Client = Server->GetClient(clid);\r
-\r
- ConnectionTCP* tcpConn = ServerSock->getTCPConnection();\r
- Client->setTCPConnection(tcpConn);\r
-\r
- Console->Print("Client address: %s", Client->GetAddress());\r
- //++mNumClients;\r
-\r
- PPatchState *state = new PPatchState();\r
- ClientStates.insert(std::make_pair(Client, state));\r
- state->mState = PPatchState::PS_CONNECTED;\r
- } else\r
- {\r
- Console->Print("Patchserver: Client connection refused (server full?)");\r
- }\r
- }\r
-\r
- for(PatchStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end();)\r
- {\r
- PClient *Client = i->first;\r
- PPatchState *State = i->second;\r
- // node gets erased in FinalizeClient, increment iterator now\r
- ++i;\r
- if(!ProcessClient(Client, State))\r
- {\r
- FinalizeClient(Client, State);\r
- }\r
- }\r
-}\r
-\r
-void PPatchServer::FinalizeClient(PClient *Client, PPatchState *State)\r
-{\r
- Console->Print(RED, BLACK, "Patchserver: client %s disconnected", Client->GetAddress());\r
- Client->PatchDisconnect();\r
- ClientStates.erase(Client);\r
- if(State->mPatchFile)\r
- --mNumFileTransfers;\r
- if(State->mSendFile)\r
- --mNumFileTransfers;\r
- delete State;\r
-}\r
-\r
-// completes pending packets before disconnect\r
-void PPatchServer::FinalizeClientDelayed(PClient *Client, PPatchState *State)\r
-{\r
- Console->Print("Patchserver: client %i is about to be disconnected", Client->GetIndex());\r
- State->mWaitSend = true;\r
-}\r
-\r
-void PPatchServer::ClientDisconnected(PClient *Client)\r
-{\r
- PatchStateMap::iterator node = ClientStates.find(Client);\r
- if(node == ClientStates.end())\r
- return;\r
-\r
- PPatchState *State = node->second;\r
- FinalizeClient(Client, State);\r
-}\r
-\r
-bool PPatchServer::HandleHandshake(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize)\r
-{\r
- static const uint8_t HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x01, 0x73};\r
-\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
-\r
- switch(State->mState)\r
- {\r
- case PPatchState::PS_HANDSHAKE0 :\r
- {\r
- if(PacketSize==6 && *(uint16_t*)&Packet[3]==0x0280 && Packet[5]==0x64)\r
- {\r
- Socket->write(HANDSHAKE1A, sizeof(HANDSHAKE1A));\r
- State->mState = PPatchState::PS_HANDSHAKE1;\r
- } else\r
- {\r
- Console->Print("Patchserver protocol error (PS_HANDSHAKE0): invalid packet [%04x]", *(uint16_t*)&Packet[3]);\r
- return false;\r
- }\r
-\r
- break;\r
- }\r
-\r
- case PPatchState::PS_HANDSHAKE1 :\r
- {\r
- if(PacketSize==6 && *(uint16_t*)&Packet[3]==0x0080 && Packet[5]==0x6c)\r
- State->mState = PPatchState::PS_VERSIONREQUEST;\r
- else\r
- {\r
- Console->Print("Patchserver protocol error (PS_HANDSHAKE1): invalid packet [%04x]", *(uint16_t*)&Packet[3]);\r
- return false;\r
- }\r
- break;\r
- }\r
- default:\r
- break;\r
- }\r
-\r
- return true;\r
-}\r
-\r
-bool PPatchServer::HandleVersionRequest(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize)\r
-{\r
- static uint8_t VERSIONPACKET[13]={0xfe, 0x0a, 0x00, 0x37, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\r
-\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
- if(PacketSize==9 && *(uint16_t*)&Packet[3]==0x007b)\r
- {\r
- State->mSerial = *(uint16_t*)&Packet[7];\r
- *(uint16_t*)&VERSIONPACKET[7]=State->mSerial;\r
- uint32_t ver = Config->GetOptionInt("server_version");\r
- *(uint32_t*)&VERSIONPACKET[9]=ver;\r
- Socket->write(VERSIONPACKET, 13);\r
- State->mState = PPatchState::PS_GETPATCHORFILE;\r
- } else\r
- {\r
- Console->Print("Patchserver protocol error (PS_VERSIONREQUEST): invalid packet [%04x]", *(uint16_t*)&Packet[3]);\r
- return false;\r
- }\r
-\r
- return true;\r
-}\r
-\r
-bool PPatchServer::HandleFileRequests(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize)\r
-{\r
- static uint8_t STARTPATCH[13]={0xfe, 0x0a, 0x00, 0x38, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\r
- static uint8_t STARTFILE[13]={0xfe, 0x0a, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\r
- static uint8_t FILEERROR[9]={0xfe, 0x06, 0x00, 0x3d, 0x02, 0x00, 0x00, 0x00, 0x00};\r
-\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
- // request patch\r
- if(PacketSize==13 && *(uint16_t*)&Packet[3]==0x007c)\r
- {\r
- int32_t nmax = Config->GetOptionInt("max_file_xfers");\r
- if(mNumFileTransfers>=nmax)\r
- {\r
- Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex());\r
- return false;\r
- }\r
- if(State->mPatchFile)\r
- {\r
- std::fclose(State->mPatchFile);\r
- State->mPatchFile=0;\r
- --mNumFileTransfers;\r
- }\r
- if(State->mSendFile)\r
- {\r
- Filesystem->Close(State->mSendFile);\r
- State->mSendFile=0;\r
- --mNumFileTransfers;\r
- }\r
- State->mSerial = *(uint16_t*)&Packet[7];\r
- State->mCurrentPatch = *(uint32_t*)&Packet[9];\r
- Console->Print("Patchserver: Patch request from client %i (v%i)", Client->GetIndex(), State->mCurrentPatch);\r
- if((bool)(State->mPatchSize = StartPatch(State)))\r
- {\r
- Console->Print("Patchserver: Patch is available, %d bytes", State->mPatchSize);\r
- *(uint16_t*)&STARTPATCH[7]=State->mSerial;\r
- *(uint32_t*)&STARTPATCH[9]=State->mPatchSize;\r
- Socket->write(STARTPATCH, 13);\r
- State->mState = PPatchState::PS_SENDPATCH;\r
- } else\r
- {\r
- Console->Print("Patchserver: Patch not available");\r
- *(uint16_t*)&FILEERROR[7]=State->mSerial;\r
- Socket->write(FILEERROR, 9);\r
- FinalizeClientDelayed(Client, State);\r
- State->mState=PPatchState::PS_UNKNOWN;\r
- return true;\r
- }\r
- } else\r
- // request file\r
- if(PacketSize > 9 && *(uint16_t*)&Packet[3]==0x004d)\r
- {\r
- int32_t nmax = Config->GetOptionInt("max_file_xfers");\r
- if(mNumFileTransfers>=nmax)\r
- {\r
- Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex());\r
- return false;\r
- }\r
- if(State->mPatchFile)\r
- {\r
- std::fclose(State->mPatchFile);\r
- State->mPatchFile=0;\r
- --mNumFileTransfers;\r
- }\r
- if(State->mSendFile)\r
- {\r
- Filesystem->Close(State->mSendFile);\r
- State->mSendFile=0;\r
- --mNumFileTransfers;\r
- }\r
- // request file\r
- State->mSerial = *(uint16_t*)&Packet[7];\r
- char fn[256];\r
- strncpy(fn, (const char*)&Packet[10], Packet[9]);\r
- fn[Packet[9]]=0;\r
- State->mCurrentFile = fn;\r
-\r
- Console->Print("Patchserver: File request from client %i (%s)", Client->GetIndex(), fn);\r
- if((bool)(State->mFileSize = StartFile(State)))\r
- {\r
- Console->Print("Patchserver: File %s is available, %d bytes", State->mCurrentFile.c_str(), State->mFileSize);\r
- *(uint16_t*)&STARTFILE[7]=State->mSerial;\r
- *(uint32_t*)&STARTFILE[9]=State->mFileSize;\r
- Socket->write(STARTFILE, 13);\r
- State->mState = PPatchState::PS_SENDFILE;\r
- } else\r
- {\r
- Console->Print("Patchserver: Requested file %s not available", State->mCurrentFile.c_str());\r
- *(uint16_t*)&FILEERROR[7]=State->mSerial;\r
- Socket->write(FILEERROR, 9);\r
- FinalizeClientDelayed(Client, State);\r
- State->mState=PPatchState::PS_UNKNOWN;\r
- return true;\r
- }\r
- } else\r
- // send patch data\r
- if(PacketSize==17 && *(uint16_t*)&Packet[3]==0x007d)\r
- {\r
- State->mSerial = *(uint16_t*)&Packet[7];\r
- State->mCurrentPatch = *(uint32_t*)&Packet[9];\r
- State->mPatchOffset = *(uint32_t*)&Packet[13];\r
- if(!SendPatchData(Client, State))\r
- {\r
- Console->Print("Patchserver: SendPatchData failed on client %i", Client->GetIndex());\r
- Console->Print("Patchserver: (probably due to garbage packets)");\r
- // state is undefined now, kill this client\r
- return false;\r
- }\r
- } else\r
- // send file data\r
- if(PacketSize > 13 && *(uint16_t*)&Packet[3]==0x00037)\r
- {\r
- State->mSerial = *(uint16_t*)&Packet[7];\r
- State->mFileOffset = *(uint32_t*)&Packet[9];\r
- if(!SendFileData(Client, State))\r
- {\r
- Console->Print("Patchserver: SendFileData failed on client %i", Client->GetIndex());\r
- Console->Print("Patchserver: (probably due to garbage packets)");\r
- // state is undefined now, kill this client\r
- return false;\r
- }\r
- } else\r
- {\r
- Console->Print("Patchserver protocol error (PS_GETPATCHORFILE): unknown packet");\r
- return false;\r
- }\r
-\r
- return true;\r
-}\r
-\r
-uint32_t PPatchServer::StartPatch(PPatchState *State)\r
-{\r
- std::stringstream path;\r
- char patchname[13];\r
- snprintf(patchname, 13, "sp%06d.pat", State->mCurrentPatch);\r
- path << Config->GetOption("patches_path") << "/" << patchname << '\0';\r
- State->mPatchFile = std::fopen(path.str().c_str(), "rb");\r
- if(State->mPatchFile)\r
- {\r
- ++mNumFileTransfers;\r
- fseek(State->mPatchFile, 0, SEEK_END);\r
- uint32_t size = ftell(State->mPatchFile);\r
- fseek(State->mPatchFile, 0, SEEK_SET);\r
- return size;\r
- }\r
- return 0;\r
-}\r
-\r
-bool PPatchServer::SendPatchData(PClient *Client, PPatchState *State) const\r
-{\r
- if(!State->mPatchFile)\r
- return false;\r
-\r
- uint16_t size = Config->GetOptionInt("patch_packet_size");\r
-\r
- const int32_t BUFFERSIZE = 4082;\r
-\r
- size = std::min(BUFFERSIZE, std::max((int32_t)size, 64));\r
- static uint8_t Buffer[BUFFERSIZE+13];\r
-\r
- if(fseek(State->mPatchFile, State->mPatchOffset, SEEK_SET)!=0)\r
- return false;\r
-\r
- size = fread(&Buffer[13], 1, size, State->mPatchFile);\r
- Buffer[0]=0xfe;\r
- *(uint16_t*)&Buffer[1]=size+10;\r
- Buffer[3]=0x39;\r
- Buffer[4]=0x02;\r
- Buffer[5]=0x00;\r
- Buffer[6]=0x00;\r
- *(uint16_t*)&Buffer[7]=State->mSerial;\r
- *(uint32_t*)&Buffer[9]=size;\r
- return Client->getTCPConn()->write(Buffer, size+13)==size+13;\r
-}\r
-\r
-uint32_t PPatchServer::StartFile(PPatchState *State)\r
-{\r
- // security checks: reject file paths containing ':', '..' or slashes/backslashes at the beginning\r
- if((State->mCurrentFile.find(':') != std::string::npos)\r
- || (State->mCurrentFile.find("..") != std::string::npos)\r
- || (State->mCurrentFile.find('/') == 0)\r
- || (State->mCurrentFile.find('\\') == 0))\r
- {\r
- return 0;\r
- }\r
-\r
- //std::stringstream path;\r
- //path << Config->GetOption("file_path") << "/" << State->mCurrentFile << '\0';\r
- State->mSendFile = Filesystem->Open("", State->mCurrentFile.c_str(), Config->GetOption("file_path"));\r
- if(State->mSendFile)\r
- {\r
- ++mNumFileTransfers;\r
- uint32_t size = State->mSendFile->GetSize();\r
- return size;\r
- }\r
- return 0;\r
-}\r
-\r
-bool PPatchServer::SendFileData(PClient *Client, PPatchState *State) const\r
-{\r
- if(!State->mSendFile)\r
- return false;\r
-\r
- uint16_t size = Config->GetOptionInt("patch_packet_size");\r
-\r
- const int32_t BUFFERSIZE = 4082;\r
-\r
- size = std::min(BUFFERSIZE, std::max((int32_t)size, 1));\r
- static uint8_t Buffer[BUFFERSIZE+13];\r
-\r
- State->mSendFile->Seek(State->mFileOffset);\r
-\r
- size = State->mSendFile->Read(&Buffer[13], size);\r
- Buffer[0]=0xfe;\r
- *(uint16_t*)&Buffer[1]=size+10;\r
- Buffer[3]=0x3c;\r
- Buffer[4]=0x02;\r
- Buffer[5]=0x00;\r
- Buffer[6]=0x00;\r
- *(uint16_t*)&Buffer[7]=State->mSerial;\r
- *(uint32_t*)&Buffer[9]=size;\r
- return Client->getTCPConn()->write(Buffer, size+13)==size+13;\r
-}\r
-\r
-bool PPatchServer::ProcessClient(PClient *Client, PPatchState *State)\r
-{\r
- static const uint8_t HANDSHAKE0A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x6b};\r
-\r
- if(!State)\r
- {\r
- PatchStateMap::iterator node = ClientStates.find(Client);\r
- if(node == ClientStates.end())\r
- return false;\r
-\r
- State = node->second;\r
- }\r
-\r
- ConnectionTCP *Socket = Client->getTCPConn();\r
-\r
- if(State->mWaitSend && Socket->getSendBufferSize()==0)\r
- return false;\r
-\r
- if(State->mState==PPatchState::PS_CONNECTED)\r
- {\r
- Console->Print("Sending Handshake 0A");\r
- Socket->write(HANDSHAKE0A, sizeof(HANDSHAKE0A));\r
- //short unsigned int packet = (short unsigned int) HANDSHAKE0A;\r
- //Socket->write(htons(packet));\r
- State->mState = PPatchState::PS_HANDSHAKE0;\r
- Socket->flushSendBuffer();\r
- }\r
-\r
- int32_t PacketSize = 0;\r
- const uint8_t *Packet = Socket->read(&PacketSize);\r
- if(PacketSize > 0)\r
- {\r
- switch(State->mState)\r
- {\r
- case PPatchState::PS_HANDSHAKE1 :\r
- case PPatchState::PS_HANDSHAKE0 :\r
- Console->Print("Handling Handshake 0 and 1");\r
- return HandleHandshake(Client, State, Packet, PacketSize);\r
-\r
- case PPatchState::PS_VERSIONREQUEST :\r
- Console->Print("Handling Client Versionsrequest");\r
- return HandleVersionRequest(Client, State, Packet, PacketSize);\r
-\r
- case PPatchState::PS_GETPATCHORFILE :\r
- case PPatchState::PS_SENDPATCH :\r
- case PPatchState::PS_SENDFILE :\r
- Console->Print("Getpatchforfile, sendpatch, sendfile");\r
- return HandleFileRequests(Client, State, Packet, PacketSize);\r
- default:\r
- break;\r
- }\r
- }\r
- return true;\r
-}\r
+#include <cstring>
+#include <sstream>
+#include "PatchServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+const uint16_t PATCH_PORT = 7000;
+
+struct PPatchState {
+ enum State
+ {
+ PS_UNKNOWN,
+ PS_CONNECTED,
+ PS_HANDSHAKE0,
+ PS_HANDSHAKE1,
+ PS_VERSIONREQUEST,
+ PS_GETPATCHORFILE,
+ PS_SENDPATCH,
+ PS_SENDFILE
+ } mState;
+
+ uint16_t mSerial;
+
+ uint32_t mCurrentPatch;
+ uint32_t mPatchOffset;
+ uint32_t mPatchSize;
+ std::FILE *mPatchFile;
+
+ std::string mCurrentFile;
+ uint32_t mFileOffset;
+ uint32_t mFileSize;
+ PFile *mSendFile;
+
+ bool mWaitSend; // wait-for-completition flag
+ PPatchState()
+ {
+ mState = PS_UNKNOWN;
+ mSerial = 0;
+ mCurrentPatch = 0;
+ mPatchOffset = 0;
+ mPatchFile = 0;
+
+ mCurrentFile = "";
+ mFileOffset = 0;
+ mFileSize = 0;
+ mSendFile = 0;
+
+ mWaitSend = false;
+ };
+
+ ~PPatchState()
+ {
+ if(mPatchFile)
+ std::fclose(mPatchFile);
+ if(mSendFile)
+ Filesystem->Close(mSendFile);
+ }
+};
+
+// -------------------------------------------------------
+
+PPatchServer::PPatchServer()
+{
+ //mNumClients = 1;
+ mNumFileTransfers = 0;
+}
+
+PPatchServer::~PPatchServer()
+{
+ ServerSock->closeServer();
+
+ for(PatchStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end(); i++)
+ delete i->second;
+}
+
+void PPatchServer::Start()
+{
+ uint16_t Port = Config->GetOptionInt("patchserver_port");
+ if(Port==0)
+ Port=PATCH_PORT;
+
+ Console->LPrint("Starting Patchserver on port %i...", Port);
+ if(ServerSock->open(Port))
+ {
+ Console->LPrint(GREEN, BLACK, "Success");
+ }
+ else
+ {
+ Console->LPrint(RED, BLACK, "ERROR");
+ }
+ Console->LClose();
+ ServerSock->settimeout(0, 10000);
+}
+
+void PPatchServer::Update()
+{
+ //ServerSock->update();
+
+ if(ServerSock->newConnection())
+ {
+ int32_t clid = Server->NewClient();
+ if(clid!=-1)
+ {
+ Console->Print(GREEN, BLACK, "Patchserver: client [%i] connected", clid);
+ PClient *Client = Server->GetClient(clid);
+
+ ConnectionTCP* tcpConn = ServerSock->getTCPConnection();
+ Client->setTCPConnection(tcpConn);
+
+ Console->Print("Client address: %s", Client->GetAddress());
+ //++mNumClients;
+
+ PPatchState *state = new PPatchState();
+ ClientStates.insert(std::make_pair(Client, state));
+ state->mState = PPatchState::PS_CONNECTED;
+ } else
+ {
+ Console->Print("Patchserver: Client connection refused (server full?)");
+ }
+ }
+
+ for(PatchStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end();)
+ {
+ PClient *Client = i->first;
+ PPatchState *State = i->second;
+ // node gets erased in FinalizeClient, increment iterator now
+ ++i;
+ if(!ProcessClient(Client, State))
+ {
+ FinalizeClient(Client, State);
+ }
+ }
+}
+
+void PPatchServer::FinalizeClient(PClient *Client, PPatchState *State)
+{
+ Console->Print(RED, BLACK, "Patchserver: client %s disconnected", Client->GetAddress());
+ Client->PatchDisconnect();
+ ClientStates.erase(Client);
+ if(State->mPatchFile)
+ --mNumFileTransfers;
+ if(State->mSendFile)
+ --mNumFileTransfers;
+ delete State;
+}
+
+// completes pending packets before disconnect
+void PPatchServer::FinalizeClientDelayed(PClient *Client, PPatchState *State)
+{
+ Console->Print("Patchserver: client %i is about to be disconnected", Client->GetIndex());
+ State->mWaitSend = true;
+}
+
+void PPatchServer::ClientDisconnected(PClient *Client)
+{
+ PatchStateMap::iterator node = ClientStates.find(Client);
+ if(node == ClientStates.end())
+ return;
+
+ PPatchState *State = node->second;
+ FinalizeClient(Client, State);
+}
+
+bool PPatchServer::HandleHandshake(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize)
+{
+ static const uint8_t HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x01, 0x73};
+
+ ConnectionTCP *Socket = Client->getTCPConn();
+
+ switch(State->mState)
+ {
+ case PPatchState::PS_HANDSHAKE0 :
+ {
+ if(PacketSize==6 && *(uint16_t*)&Packet[3]==0x0280 && Packet[5]==0x64)
+ {
+ Socket->write(HANDSHAKE1A, sizeof(HANDSHAKE1A));
+ State->mState = PPatchState::PS_HANDSHAKE1;
+ } else
+ {
+ Console->Print("Patchserver protocol error (PS_HANDSHAKE0): invalid packet [%04x]", *(uint16_t*)&Packet[3]);
+ return false;
+ }
+
+ break;
+ }
+
+ case PPatchState::PS_HANDSHAKE1 :
+ {
+ if(PacketSize==6 && *(uint16_t*)&Packet[3]==0x0080 && Packet[5]==0x6c)
+ State->mState = PPatchState::PS_VERSIONREQUEST;
+ else
+ {
+ Console->Print("Patchserver protocol error (PS_HANDSHAKE1): invalid packet [%04x]", *(uint16_t*)&Packet[3]);
+ return false;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return true;
+}
+
+bool PPatchServer::HandleVersionRequest(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize)
+{
+ static uint8_t VERSIONPACKET[13]={0xfe, 0x0a, 0x00, 0x37, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ ConnectionTCP *Socket = Client->getTCPConn();
+ if(PacketSize==9 && *(uint16_t*)&Packet[3]==0x007b)
+ {
+ State->mSerial = *(uint16_t*)&Packet[7];
+ *(uint16_t*)&VERSIONPACKET[7]=State->mSerial;
+ uint32_t ver = Config->GetOptionInt("server_version");
+ *(uint32_t*)&VERSIONPACKET[9]=ver;
+ Socket->write(VERSIONPACKET, 13);
+ State->mState = PPatchState::PS_GETPATCHORFILE;
+ } else
+ {
+ Console->Print("Patchserver protocol error (PS_VERSIONREQUEST): invalid packet [%04x]", *(uint16_t*)&Packet[3]);
+ return false;
+ }
+
+ return true;
+}
+
+bool PPatchServer::HandleFileRequests(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize)
+{
+ static uint8_t STARTPATCH[13]={0xfe, 0x0a, 0x00, 0x38, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static uint8_t STARTFILE[13]={0xfe, 0x0a, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ static uint8_t FILEERROR[9]={0xfe, 0x06, 0x00, 0x3d, 0x02, 0x00, 0x00, 0x00, 0x00};
+
+ ConnectionTCP *Socket = Client->getTCPConn();
+ // request patch
+ if(PacketSize==13 && *(uint16_t*)&Packet[3]==0x007c)
+ {
+ int32_t nmax = Config->GetOptionInt("max_file_xfers");
+ if(mNumFileTransfers>=nmax)
+ {
+ Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex());
+ return false;
+ }
+ if(State->mPatchFile)
+ {
+ std::fclose(State->mPatchFile);
+ State->mPatchFile=0;
+ --mNumFileTransfers;
+ }
+ if(State->mSendFile)
+ {
+ Filesystem->Close(State->mSendFile);
+ State->mSendFile=0;
+ --mNumFileTransfers;
+ }
+ State->mSerial = *(uint16_t*)&Packet[7];
+ State->mCurrentPatch = *(uint32_t*)&Packet[9];
+ Console->Print("Patchserver: Patch request from client %i (v%i)", Client->GetIndex(), State->mCurrentPatch);
+ if((bool)(State->mPatchSize = StartPatch(State)))
+ {
+ Console->Print("Patchserver: Patch is available, %d bytes", State->mPatchSize);
+ *(uint16_t*)&STARTPATCH[7]=State->mSerial;
+ *(uint32_t*)&STARTPATCH[9]=State->mPatchSize;
+ Socket->write(STARTPATCH, 13);
+ State->mState = PPatchState::PS_SENDPATCH;
+ } else
+ {
+ Console->Print("Patchserver: Patch not available");
+ *(uint16_t*)&FILEERROR[7]=State->mSerial;
+ Socket->write(FILEERROR, 9);
+ FinalizeClientDelayed(Client, State);
+ State->mState=PPatchState::PS_UNKNOWN;
+ return true;
+ }
+ } else
+ // request file
+ if(PacketSize > 9 && *(uint16_t*)&Packet[3]==0x004d)
+ {
+ int32_t nmax = Config->GetOptionInt("max_file_xfers");
+ if(mNumFileTransfers>=nmax)
+ {
+ Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex());
+ return false;
+ }
+ if(State->mPatchFile)
+ {
+ std::fclose(State->mPatchFile);
+ State->mPatchFile=0;
+ --mNumFileTransfers;
+ }
+ if(State->mSendFile)
+ {
+ Filesystem->Close(State->mSendFile);
+ State->mSendFile=0;
+ --mNumFileTransfers;
+ }
+ // request file
+ State->mSerial = *(uint16_t*)&Packet[7];
+ char fn[256];
+ strncpy(fn, (const char*)&Packet[10], Packet[9]);
+ fn[Packet[9]]=0;
+ State->mCurrentFile = fn;
+
+ Console->Print("Patchserver: File request from client %i (%s)", Client->GetIndex(), fn);
+ if((bool)(State->mFileSize = StartFile(State)))
+ {
+ Console->Print("Patchserver: File %s is available, %d bytes", State->mCurrentFile.c_str(), State->mFileSize);
+ *(uint16_t*)&STARTFILE[7]=State->mSerial;
+ *(uint32_t*)&STARTFILE[9]=State->mFileSize;
+ Socket->write(STARTFILE, 13);
+ State->mState = PPatchState::PS_SENDFILE;
+ } else
+ {
+ Console->Print("Patchserver: Requested file %s not available", State->mCurrentFile.c_str());
+ *(uint16_t*)&FILEERROR[7]=State->mSerial;
+ Socket->write(FILEERROR, 9);
+ FinalizeClientDelayed(Client, State);
+ State->mState=PPatchState::PS_UNKNOWN;
+ return true;
+ }
+ } else
+ // send patch data
+ if(PacketSize==17 && *(uint16_t*)&Packet[3]==0x007d)
+ {
+ State->mSerial = *(uint16_t*)&Packet[7];
+ State->mCurrentPatch = *(uint32_t*)&Packet[9];
+ State->mPatchOffset = *(uint32_t*)&Packet[13];
+ if(!SendPatchData(Client, State))
+ {
+ Console->Print("Patchserver: SendPatchData failed on client %i", Client->GetIndex());
+ Console->Print("Patchserver: (probably due to garbage packets)");
+ // state is undefined now, kill this client
+ return false;
+ }
+ } else
+ // send file data
+ if(PacketSize > 13 && *(uint16_t*)&Packet[3]==0x00037)
+ {
+ State->mSerial = *(uint16_t*)&Packet[7];
+ State->mFileOffset = *(uint32_t*)&Packet[9];
+ if(!SendFileData(Client, State))
+ {
+ Console->Print("Patchserver: SendFileData failed on client %i", Client->GetIndex());
+ Console->Print("Patchserver: (probably due to garbage packets)");
+ // state is undefined now, kill this client
+ return false;
+ }
+ } else
+ {
+ Console->Print("Patchserver protocol error (PS_GETPATCHORFILE): unknown packet");
+ return false;
+ }
+
+ return true;
+}
+
+uint32_t PPatchServer::StartPatch(PPatchState *State)
+{
+ std::stringstream path;
+ char patchname[13];
+ snprintf(patchname, 13, "sp%06d.pat", State->mCurrentPatch);
+ path << Config->GetOption("patches_path") << "/" << patchname << '\0';
+ State->mPatchFile = std::fopen(path.str().c_str(), "rb");
+ if(State->mPatchFile)
+ {
+ ++mNumFileTransfers;
+ fseek(State->mPatchFile, 0, SEEK_END);
+ uint32_t size = ftell(State->mPatchFile);
+ fseek(State->mPatchFile, 0, SEEK_SET);
+ return size;
+ }
+ return 0;
+}
+
+bool PPatchServer::SendPatchData(PClient *Client, PPatchState *State) const
+{
+ if(!State->mPatchFile)
+ return false;
+
+ uint16_t size = Config->GetOptionInt("patch_packet_size");
+
+ const int32_t BUFFERSIZE = 4082;
+
+ size = std::min(BUFFERSIZE, std::max((int32_t)size, 64));
+ static uint8_t Buffer[BUFFERSIZE+13];
+
+ if(fseek(State->mPatchFile, State->mPatchOffset, SEEK_SET)!=0)
+ return false;
+
+ size = fread(&Buffer[13], 1, size, State->mPatchFile);
+ Buffer[0]=0xfe;
+ *(uint16_t*)&Buffer[1]=size+10;
+ Buffer[3]=0x39;
+ Buffer[4]=0x02;
+ Buffer[5]=0x00;
+ Buffer[6]=0x00;
+ *(uint16_t*)&Buffer[7]=State->mSerial;
+ *(uint32_t*)&Buffer[9]=size;
+ return Client->getTCPConn()->write(Buffer, size+13)==size+13;
+}
+
+uint32_t PPatchServer::StartFile(PPatchState *State)
+{
+ // security checks: reject file paths containing ':', '..' or slashes/backslashes at the beginning
+ if((State->mCurrentFile.find(':') != std::string::npos)
+ || (State->mCurrentFile.find("..") != std::string::npos)
+ || (State->mCurrentFile.find('/') == 0)
+ || (State->mCurrentFile.find('\\') == 0))
+ {
+ return 0;
+ }
+
+ //std::stringstream path;
+ //path << Config->GetOption("file_path") << "/" << State->mCurrentFile << '\0';
+ State->mSendFile = Filesystem->Open("", State->mCurrentFile.c_str(), Config->GetOption("file_path"));
+ if(State->mSendFile)
+ {
+ ++mNumFileTransfers;
+ uint32_t size = State->mSendFile->GetSize();
+ return size;
+ }
+ return 0;
+}
+
+bool PPatchServer::SendFileData(PClient *Client, PPatchState *State) const
+{
+ if(!State->mSendFile)
+ return false;
+
+ uint16_t size = Config->GetOptionInt("patch_packet_size");
+
+ const int32_t BUFFERSIZE = 4082;
+
+ size = std::min(BUFFERSIZE, std::max((int32_t)size, 1));
+ static uint8_t Buffer[BUFFERSIZE+13];
+
+ State->mSendFile->Seek(State->mFileOffset);
+
+ size = State->mSendFile->Read(&Buffer[13], size);
+ Buffer[0]=0xfe;
+ *(uint16_t*)&Buffer[1]=size+10;
+ Buffer[3]=0x3c;
+ Buffer[4]=0x02;
+ Buffer[5]=0x00;
+ Buffer[6]=0x00;
+ *(uint16_t*)&Buffer[7]=State->mSerial;
+ *(uint32_t*)&Buffer[9]=size;
+ return Client->getTCPConn()->write(Buffer, size+13)==size+13;
+}
+
+bool PPatchServer::ProcessClient(PClient *Client, PPatchState *State)
+{
+ static const uint8_t HANDSHAKE0A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x6b};
+
+ if(!State)
+ {
+ PatchStateMap::iterator node = ClientStates.find(Client);
+ if(node == ClientStates.end())
+ return false;
+
+ State = node->second;
+ }
+
+ ConnectionTCP *Socket = Client->getTCPConn();
+
+ if(State->mWaitSend && Socket->getSendBufferSize()==0)
+ return false;
+
+ if(State->mState==PPatchState::PS_CONNECTED)
+ {
+ Console->Print("Sending Handshake 0A");
+ Socket->write(HANDSHAKE0A, sizeof(HANDSHAKE0A));
+ //short unsigned int packet = (short unsigned int) HANDSHAKE0A;
+ //Socket->write(htons(packet));
+ State->mState = PPatchState::PS_HANDSHAKE0;
+ Socket->flushSendBuffer();
+ }
+
+ int32_t PacketSize = 0;
+ const uint8_t *Packet = Socket->read(&PacketSize);
+ if(PacketSize > 0)
+ {
+ switch(State->mState)
+ {
+ case PPatchState::PS_HANDSHAKE1 :
+ case PPatchState::PS_HANDSHAKE0 :
+ Console->Print("Handling Handshake 0 and 1");
+ return HandleHandshake(Client, State, Packet, PacketSize);
+
+ case PPatchState::PS_VERSIONREQUEST :
+ Console->Print("Handling Client Versionsrequest");
+ return HandleVersionRequest(Client, State, Packet, PacketSize);
+
+ case PPatchState::PS_GETPATCHORFILE :
+ case PPatchState::PS_SENDPATCH :
+ case PPatchState::PS_SENDFILE :
+ Console->Print("Getpatchforfile, sendpatch, sendfile");
+ return HandleFileRequests(Client, State, Packet, PacketSize);
+ default:
+ break;
+ }
+ }
+ return true;
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <map>\r
-\r
-class PClient;\r
-struct PPatchState;\r
-\r
-class PPatchServer {\r
-private:\r
- int mNumClients;\r
- int mNumFileTransfers;\r
- typedef std::map<PClient *, PPatchState *> PatchStateMap;\r
- PatchStateMap ClientStates;\r
-\r
-protected:\r
- bool ProcessClient(PClient *Client, PPatchState *State = nullptr);\r
-// uint32_t StartPatch(PClient *Client, PPatchState *State);\r
- uint32_t StartPatch(PPatchState *State);\r
- bool SendPatchData(PClient *Client, PPatchState *State) const;\r
-// u32 StartFile(PClient *Client, PPatchState *State);\r
- uint32_t StartFile(PPatchState *State);\r
- bool SendFileData(PClient *Client, PPatchState *State) const;\r
- void FinalizeClient(PClient *Client, PPatchState *State);\r
- void FinalizeClientDelayed(PClient *Client, PPatchState *State);\r
-\r
- bool HandleHandshake(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize);\r
- bool HandleVersionRequest(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize);\r
- bool HandleFileRequests(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize);\r
-\r
-public:\r
- PPatchServer();\r
- ~PPatchServer();\r
-\r
- void Start();\r
- void Update();\r
- void ClientDisconnected(PClient *Client);\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <map>
+
+class PClient;
+struct PPatchState;
+
+class PPatchServer {
+private:
+ int mNumClients;
+ int mNumFileTransfers;
+ typedef std::map<PClient *, PPatchState *> PatchStateMap;
+ PatchStateMap ClientStates;
+
+protected:
+ bool ProcessClient(PClient *Client, PPatchState *State = nullptr);
+// uint32_t StartPatch(PClient *Client, PPatchState *State);
+ uint32_t StartPatch(PPatchState *State);
+ bool SendPatchData(PClient *Client, PPatchState *State) const;
+// u32 StartFile(PClient *Client, PPatchState *State);
+ uint32_t StartFile(PPatchState *State);
+ bool SendFileData(PClient *Client, PPatchState *State) const;
+ void FinalizeClient(PClient *Client, PPatchState *State);
+ void FinalizeClientDelayed(PClient *Client, PPatchState *State);
+
+ bool HandleHandshake(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize);
+ bool HandleVersionRequest(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize);
+ bool HandleFileRequests(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize);
+
+public:
+ PPatchServer();
+ ~PPatchServer();
+
+ void Start();
+ void Update();
+ void ClientDisconnected(PClient *Client);
+};
-#include "PatchServer/Includes.hxx"\r
-#include "Common/Includes.hxx"\r
-\r
-PServer::PServer()\r
-{\r
- mNumClients = 0;\r
- mMaxClients = Config->GetOptionInt("maxclients");\r
- mGMSlots = Config->GetOptionInt("gm_slots");\r
-\r
- if (mMaxClients==0)\r
- mMaxClients=1;\r
- if (mGMSlots==0)\r
- mGMSlots=1;\r
- mClients.reserve(mMaxClients + mGMSlots);\r
- for (int32_t i=0; i<mMaxClients+mGMSlots; i++)\r
- mClients[i]=0;\r
-}\r
-\r
-PServer::~PServer()\r
-{\r
- for (int32_t i=0; i<mMaxClients+mGMSlots; i++)\r
- delete mClients[i];\r
-}\r
-\r
-int32_t PServer::GetMaxClients() const\r
-{\r
- return mMaxClients;\r
-}\r
-\r
-int32_t PServer::GetGMSlots() const\r
-{\r
- return mGMSlots;\r
-}\r
-\r
-int32_t PServer::GetNumClients() const\r
-{\r
- return mNumClients;\r
-}\r
-\r
-int PServer::NewClient()\r
-{\r
-//Console->Print("%d %d", mMaxClients, mGMSlots);\r
- if (mNumClients==mMaxClients+mGMSlots)\r
- return -1;\r
- for (int32_t i=0; i<mMaxClients+mGMSlots; i++)\r
- {\r
- if(!mClients[i])\r
- {\r
- mClients[i]=new PClient(i);\r
- ++mNumClients;\r
- return i;\r
- }\r
- }\r
- return -1;\r
-}\r
-\r
-PClient *PServer::GetClient(int32_t Client) const\r
-{\r
- if (Client < 0 || Client >= mMaxClients+mGMSlots)\r
- return 0;\r
-\r
- return mClients[Client];\r
-}\r
-\r
-void PServer::Update()\r
-{\r
- for (int32_t i=0; i<mMaxClients+mGMSlots; i++)\r
- {\r
- if (mClients[i])\r
- {\r
- mClients[i]->Update();\r
- if (mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0)\r
- {\r
- Console->Print("Removing client ...");\r
- delete mClients[i];\r
- mClients[i]=0;\r
- --mNumClients;\r
- }\r
- }\r
- }\r
-}\r
-\r
-void PServer::Shutdown()\r
-{\r
- Console->Print("======================");\r
- Console->Print("Shutting down Patchserver...");\r
- for (int32_t i=0; i<mMaxClients+mGMSlots; i++)\r
- {\r
- if(mClients[i])\r
- {\r
- delete mClients[i];\r
- mClients[i]=0;\r
- }\r
- }\r
-}\r
+#include "PatchServer/Includes.hxx"
+#include "Common/Includes.hxx"
+
+PServer::PServer()
+{
+ mNumClients = 0;
+ mMaxClients = Config->GetOptionInt("maxclients");
+ mGMSlots = Config->GetOptionInt("gm_slots");
+
+ if (mMaxClients==0)
+ mMaxClients=1;
+ if (mGMSlots==0)
+ mGMSlots=1;
+ mClients.reserve(mMaxClients + mGMSlots);
+ for (int32_t i=0; i<mMaxClients+mGMSlots; i++)
+ mClients[i]=0;
+}
+
+PServer::~PServer()
+{
+ for (int32_t i=0; i<mMaxClients+mGMSlots; i++)
+ delete mClients[i];
+}
+
+int32_t PServer::GetMaxClients() const
+{
+ return mMaxClients;
+}
+
+int32_t PServer::GetGMSlots() const
+{
+ return mGMSlots;
+}
+
+int32_t PServer::GetNumClients() const
+{
+ return mNumClients;
+}
+
+int PServer::NewClient()
+{
+//Console->Print("%d %d", mMaxClients, mGMSlots);
+ if (mNumClients==mMaxClients+mGMSlots)
+ return -1;
+ for (int32_t i=0; i<mMaxClients+mGMSlots; i++)
+ {
+ if(!mClients[i])
+ {
+ mClients[i]=new PClient(i);
+ ++mNumClients;
+ return i;
+ }
+ }
+ return -1;
+}
+
+PClient *PServer::GetClient(int32_t Client) const
+{
+ if (Client < 0 || Client >= mMaxClients+mGMSlots)
+ return 0;
+
+ return mClients[Client];
+}
+
+void PServer::Update()
+{
+ for (int32_t i=0; i<mMaxClients+mGMSlots; i++)
+ {
+ if (mClients[i])
+ {
+ mClients[i]->Update();
+ if (mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0)
+ {
+ Console->Print("Removing client ...");
+ delete mClients[i];
+ mClients[i]=0;
+ --mNumClients;
+ }
+ }
+ }
+}
+
+void PServer::Shutdown()
+{
+ Console->Print("======================");
+ Console->Print("Shutting down Patchserver...");
+ for (int32_t i=0; i<mMaxClients+mGMSlots; i++)
+ {
+ if(mClients[i])
+ {
+ delete mClients[i];
+ mClients[i]=0;
+ }
+ }
+}
-#pragma once\r
-\r
-#include <cstdint>\r
-#include <vector>\r
-\r
-class PClient;\r
-\r
-class PServer {\r
-private:\r
- int32_t mMaxClients;\r
- int32_t mGMSlots;\r
- int32_t mNumClients;\r
- std::vector<PClient *> mClients;\r
-\r
-public:\r
- PServer();\r
- ~PServer();\r
-\r
- int32_t GetMaxClients() const;\r
- int32_t GetGMSlots() const;\r
- int32_t GetNumClients() const;\r
- int32_t NewClient();\r
- PClient *GetClient(int32_t Client) const;\r
- void Update();\r
- void Shutdown();\r
-};\r
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+class PClient;
+
+class PServer {
+private:
+ int32_t mMaxClients;
+ int32_t mGMSlots;
+ int32_t mNumClients;
+ std::vector<PClient *> mClients;
+
+public:
+ PServer();
+ ~PServer();
+
+ int32_t GetMaxClients() const;
+ int32_t GetGMSlots() const;
+ int32_t GetNumClients() const;
+ int32_t NewClient();
+ PClient *GetClient(int32_t Client) const;
+ void Update();
+ void Shutdown();
+};