Advertisement
Rellyx

tools.cpp

Sep 22nd, 2018
179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 33.12 KB | None | 0 0
  1. /**
  2.  * The Forgotten Server - a free and open-source MMORPG server emulator
  3.  * Copyright (C) 2018  Mark Samman <mark.samman@gmail.com>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License along
  16.  * with this program; if not, write to the Free Software Foundation, Inc.,
  17.  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18.  */
  19.  
  20. #include "otpch.h"
  21.  
  22. #include "tools.h"
  23. #include "configmanager.h"
  24.  
  25. extern ConfigManager g_config;
  26.  
  27. void printXMLError(const std::string& where, const std::string& fileName, const pugi::xml_parse_result& result)
  28. {
  29.     std::cout << '[' << where << "] Failed to load " << fileName << ": " << result.description() << std::endl;
  30.  
  31.     FILE* file = fopen(fileName.c_str(), "rb");
  32.     if (!file) {
  33.         return;
  34.     }
  35.  
  36.     char buffer[32768];
  37.     uint32_t currentLine = 1;
  38.     std::string line;
  39.  
  40.     size_t offset = static_cast<size_t>(result.offset);
  41.     size_t lineOffsetPosition = 0;
  42.     size_t index = 0;
  43.     size_t bytes;
  44.     do {
  45.         bytes = fread(buffer, 1, 32768, file);
  46.         for (size_t i = 0; i < bytes; ++i) {
  47.             char ch = buffer[i];
  48.             if (ch == '\n') {
  49.                 if ((index + i) >= offset) {
  50.                     lineOffsetPosition = line.length() - ((index + i) - offset);
  51.                     bytes = 0;
  52.                     break;
  53.                 }
  54.                 ++currentLine;
  55.                 line.clear();
  56.             } else {
  57.                 line.push_back(ch);
  58.             }
  59.         }
  60.         index += bytes;
  61.     } while (bytes == 32768);
  62.     fclose(file);
  63.  
  64.     std::cout << "Line " << currentLine << ':' << std::endl;
  65.     std::cout << line << std::endl;
  66.     for (size_t i = 0; i < lineOffsetPosition; i++) {
  67.         if (line[i] == '\t') {
  68.             std::cout << '\t';
  69.         } else {
  70.             std::cout << ' ';
  71.         }
  72.     }
  73.     std::cout << '^' << std::endl;
  74. }
  75.  
  76. static uint32_t circularShift(int bits, uint32_t value)
  77. {
  78.     return (value << bits) | (value >> (32 - bits));
  79. }
  80.  
  81. static void processSHA1MessageBlock(const uint8_t* messageBlock, uint32_t* H)
  82. {
  83.     uint32_t W[80];
  84.     for (int i = 0; i < 16; ++i) {
  85.         const size_t offset = i << 2;
  86.         W[i] = messageBlock[offset] << 24 | messageBlock[offset + 1] << 16 | messageBlock[offset + 2] << 8 | messageBlock[offset + 3];
  87.     }
  88.  
  89.     for (int i = 16; i < 80; ++i) {
  90.         W[i] = circularShift(1, W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]);
  91.     }
  92.  
  93.     uint32_t A = H[0], B = H[1], C = H[2], D = H[3], E = H[4];
  94.  
  95.     for (int i = 0; i < 20; ++i) {
  96.         const uint32_t tmp = circularShift(5, A) + ((B & C) | ((~B) & D)) + E + W[i] + 0x5A827999;
  97.         E = D; D = C; C = circularShift(30, B); B = A; A = tmp;
  98.     }
  99.  
  100.     for (int i = 20; i < 40; ++i) {
  101.         const uint32_t tmp = circularShift(5, A) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1;
  102.         E = D; D = C; C = circularShift(30, B); B = A; A = tmp;
  103.     }
  104.  
  105.     for (int i = 40; i < 60; ++i) {
  106.         const uint32_t tmp = circularShift(5, A) + ((B & C) | (B & D) | (C & D)) + E + W[i] + 0x8F1BBCDC;
  107.         E = D; D = C; C = circularShift(30, B); B = A; A = tmp;
  108.     }
  109.  
  110.     for (int i = 60; i < 80; ++i) {
  111.         const uint32_t tmp = circularShift(5, A) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6;
  112.         E = D; D = C; C = circularShift(30, B); B = A; A = tmp;
  113.     }
  114.  
  115.     H[0] += A;
  116.     H[1] += B;
  117.     H[2] += C;
  118.     H[3] += D;
  119.     H[4] += E;
  120. }
  121.  
  122. std::string transformToSHA1(const std::string& input)
  123. {
  124.     uint32_t H[] = {
  125.         0x67452301,
  126.         0xEFCDAB89,
  127.         0x98BADCFE,
  128.         0x10325476,
  129.         0xC3D2E1F0
  130.     };
  131.  
  132.     uint8_t messageBlock[64];
  133.     size_t index = 0;
  134.  
  135.     uint32_t length_low = 0;
  136.     uint32_t length_high = 0;
  137.     for (char ch : input) {
  138.         messageBlock[index++] = ch;
  139.  
  140.         length_low += 8;
  141.         if (length_low == 0) {
  142.             length_high++;
  143.         }
  144.  
  145.         if (index == 64) {
  146.             processSHA1MessageBlock(messageBlock, H);
  147.             index = 0;
  148.         }
  149.     }
  150.  
  151.     messageBlock[index++] = 0x80;
  152.  
  153.     if (index > 56) {
  154.         while (index < 64) {
  155.             messageBlock[index++] = 0;
  156.         }
  157.  
  158.         processSHA1MessageBlock(messageBlock, H);
  159.         index = 0;
  160.     }
  161.  
  162.     while (index < 56) {
  163.         messageBlock[index++] = 0;
  164.     }
  165.  
  166.     messageBlock[56] = length_high >> 24;
  167.     messageBlock[57] = length_high >> 16;
  168.     messageBlock[58] = length_high >> 8;
  169.     messageBlock[59] = length_high;
  170.  
  171.     messageBlock[60] = length_low >> 24;
  172.     messageBlock[61] = length_low >> 16;
  173.     messageBlock[62] = length_low >> 8;
  174.     messageBlock[63] = length_low;
  175.  
  176.     processSHA1MessageBlock(messageBlock, H);
  177.  
  178.     char hexstring[41];
  179.     static const char hexDigits[] = {"0123456789abcdef"};
  180.     for (int hashByte = 20; --hashByte >= 0;) {
  181.         const uint8_t byte = H[hashByte >> 2] >> (((3 - hashByte) & 3) << 3);
  182.         index = hashByte << 1;
  183.         hexstring[index] = hexDigits[byte >> 4];
  184.         hexstring[index + 1] = hexDigits[byte & 15];
  185.     }
  186.     return std::string(hexstring, 40);
  187. }
  188.  
  189. std::string generateToken(const std::string& key, uint32_t ticks)
  190. {
  191.     // generate message from ticks
  192.     std::string message(8, 0);
  193.     for (uint8_t i = 8; --i; ticks >>= 8) {
  194.         message[i] = static_cast<char>(ticks & 0xFF);
  195.     }
  196.  
  197.     // hmac key pad generation
  198.     std::string iKeyPad(64, 0x36), oKeyPad(64, 0x5C);
  199.     for (uint8_t i = 0; i < key.length(); ++i) {
  200.         iKeyPad[i] ^= key[i];
  201.         oKeyPad[i] ^= key[i];
  202.     }
  203.  
  204.     oKeyPad.reserve(84);
  205.  
  206.     // hmac concat inner pad with message
  207.     iKeyPad.append(message);
  208.  
  209.     // hmac first pass
  210.     message.assign(transformToSHA1(iKeyPad));
  211.  
  212.     // hmac concat outer pad with message, conversion from hex to int needed
  213.     for (uint8_t i = 0; i < message.length(); i += 2) {
  214.         oKeyPad.push_back(static_cast<char>(std::strtoul(message.substr(i, 2).c_str(), nullptr, 16)));
  215.     }
  216.  
  217.     // hmac second pass
  218.     message.assign(transformToSHA1(oKeyPad));
  219.  
  220.     // calculate hmac offset
  221.     uint32_t offset = static_cast<uint32_t>(std::strtoul(message.substr(39, 1).c_str(), nullptr, 16) & 0xF);
  222.  
  223.     // get truncated hash
  224.     uint32_t truncHash = static_cast<uint32_t>(std::strtoul(message.substr(2 * offset, 8).c_str(), nullptr, 16)) & 0x7FFFFFFF;
  225.     message.assign(std::to_string(truncHash));
  226.  
  227.     // return only last AUTHENTICATOR_DIGITS (default 6) digits, also asserts exactly 6 digits
  228.     uint32_t hashLen = message.length();
  229.     message.assign(message.substr(hashLen - std::min(hashLen, AUTHENTICATOR_DIGITS)));
  230.     message.insert(0, AUTHENTICATOR_DIGITS - std::min(hashLen, AUTHENTICATOR_DIGITS), '0');
  231.     return message;
  232. }
  233.  
  234. void replaceString(std::string& str, const std::string& sought, const std::string& replacement)
  235. {
  236.     size_t pos = 0;
  237.     size_t start = 0;
  238.     size_t soughtLen = sought.length();
  239.     size_t replaceLen = replacement.length();
  240.  
  241.     while ((pos = str.find(sought, start)) != std::string::npos) {
  242.         str = str.substr(0, pos) + replacement + str.substr(pos + soughtLen);
  243.         start = pos + replaceLen;
  244.     }
  245. }
  246.  
  247. void trim_right(std::string& source, char t)
  248. {
  249.     source.erase(source.find_last_not_of(t) + 1);
  250. }
  251.  
  252. void trim_left(std::string& source, char t)
  253. {
  254.     source.erase(0, source.find_first_not_of(t));
  255. }
  256.  
  257. void toLowerCaseString(std::string& source)
  258. {
  259.     std::transform(source.begin(), source.end(), source.begin(), tolower);
  260. }
  261.  
  262. std::string asLowerCaseString(std::string source)
  263. {
  264.     toLowerCaseString(source);
  265.     return source;
  266. }
  267.  
  268. std::string asUpperCaseString(std::string source)
  269. {
  270.     std::transform(source.begin(), source.end(), source.begin(), toupper);
  271.     return source;
  272. }
  273.  
  274. StringVector explodeString(const std::string& inString, const std::string& separator, int32_t limit/* = -1*/)
  275. {
  276.     StringVector returnVector;
  277.     std::string::size_type start = 0, end = 0;
  278.  
  279.     while (--limit != -1 && (end = inString.find(separator, start)) != std::string::npos) {
  280.         returnVector.push_back(inString.substr(start, end - start));
  281.         start = end + separator.size();
  282.     }
  283.  
  284.     returnVector.push_back(inString.substr(start));
  285.     return returnVector;
  286. }
  287.  
  288. IntegerVector vectorAtoi(const StringVector& stringVector)
  289. {
  290.     IntegerVector returnVector;
  291.     for (const auto& string : stringVector) {
  292.         returnVector.push_back(std::stoi(string));
  293.     }
  294.     return returnVector;
  295. }
  296.  
  297. std::mt19937& getRandomGenerator()
  298. {
  299.     static std::random_device rd;
  300.     static std::mt19937 generator(rd());
  301.     return generator;
  302. }
  303.  
  304. int32_t uniform_random(int32_t minNumber, int32_t maxNumber)
  305. {
  306.     static std::uniform_int_distribution<int32_t> uniformRand;
  307.     if (minNumber == maxNumber) {
  308.         return minNumber;
  309.     } else if (minNumber > maxNumber) {
  310.         std::swap(minNumber, maxNumber);
  311.     }
  312.     return uniformRand(getRandomGenerator(), std::uniform_int_distribution<int32_t>::param_type(minNumber, maxNumber));
  313. }
  314.  
  315. int32_t normal_random(int32_t minNumber, int32_t maxNumber)
  316. {
  317.     static std::normal_distribution<float> normalRand(0.5f, 0.25f);
  318.     if (minNumber == maxNumber) {
  319.         return minNumber;
  320.     } else if (minNumber > maxNumber) {
  321.         std::swap(minNumber, maxNumber);
  322.     }
  323.  
  324.     int32_t increment;
  325.     const int32_t diff = maxNumber - minNumber;
  326.     const float v = normalRand(getRandomGenerator());
  327.     if (v < 0.0) {
  328.         increment = diff / 2;
  329.     } else if (v > 1.0) {
  330.         increment = (diff + 1) / 2;
  331.     } else {
  332.         increment = round(v * diff);
  333.     }
  334.     return minNumber + increment;
  335. }
  336.  
  337. bool boolean_random(double probability/* = 0.5*/)
  338. {
  339.     static std::bernoulli_distribution booleanRand;
  340.     return booleanRand(getRandomGenerator(), std::bernoulli_distribution::param_type(probability));
  341. }
  342.  
  343. void trimString(std::string& str)
  344. {
  345.     str.erase(str.find_last_not_of(' ') + 1);
  346.     str.erase(0, str.find_first_not_of(' '));
  347. }
  348.  
  349. std::string convertIPToString(uint32_t ip)
  350. {
  351.     char buffer[17];
  352.  
  353.     int res = sprintf(buffer, "%u.%u.%u.%u", ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24));
  354.     if (res < 0) {
  355.         return {};
  356.     }
  357.  
  358.     return buffer;
  359. }
  360.  
  361. std::string formatDate(time_t time)
  362. {
  363.     const tm* tms = localtime(&time);
  364.     if (!tms) {
  365.         return {};
  366.     }
  367.  
  368.     char buffer[20];
  369.     int res = sprintf(buffer, "%02d/%02d/%04d %02d:%02d:%02d", tms->tm_mday, tms->tm_mon + 1, tms->tm_year + 1900, tms->tm_hour, tms->tm_min, tms->tm_sec);
  370.     if (res < 0) {
  371.         return {};
  372.     }
  373.     return {buffer, 19};
  374. }
  375.  
  376. std::string formatDateShort(time_t time)
  377. {
  378.     const tm* tms = localtime(&time);
  379.     if (!tms) {
  380.         return {};
  381.     }
  382.  
  383.     char buffer[12];
  384.     size_t res = strftime(buffer, 12, "%d %b %Y", tms);
  385.     if (res == 0) {
  386.         return {};
  387.     }
  388.     return {buffer, 11};
  389. }
  390.  
  391. Direction getDirection(const std::string& string)
  392. {
  393.     Direction direction = DIRECTION_NORTH;
  394.  
  395.     if (string == "north" || string == "n" || string == "0") {
  396.         direction = DIRECTION_NORTH;
  397.     } else if (string == "east" || string == "e" || string == "1") {
  398.         direction = DIRECTION_EAST;
  399.     } else if (string == "south" || string == "s" || string == "2") {
  400.         direction = DIRECTION_SOUTH;
  401.     } else if (string == "west" || string == "w" || string == "3") {
  402.         direction = DIRECTION_WEST;
  403.     } else if (string == "southwest" || string == "south west" || string == "south-west" || string == "sw" || string == "4") {
  404.         direction = DIRECTION_SOUTHWEST;
  405.     } else if (string == "southeast" || string == "south east" || string == "south-east" || string == "se" || string == "5") {
  406.         direction = DIRECTION_SOUTHEAST;
  407.     } else if (string == "northwest" || string == "north west" || string == "north-west" || string == "nw" || string == "6") {
  408.         direction = DIRECTION_NORTHWEST;
  409.     } else if (string == "northeast" || string == "north east" || string == "north-east" || string == "ne" || string == "7") {
  410.         direction = DIRECTION_NORTHEAST;
  411.     }
  412.  
  413.     return direction;
  414. }
  415.  
  416. Position getNextPosition(Direction direction, Position pos)
  417. {
  418.     switch (direction) {
  419.         case DIRECTION_NORTH:
  420.             pos.y--;
  421.             break;
  422.  
  423.         case DIRECTION_SOUTH:
  424.             pos.y++;
  425.             break;
  426.  
  427.         case DIRECTION_WEST:
  428.             pos.x--;
  429.             break;
  430.  
  431.         case DIRECTION_EAST:
  432.             pos.x++;
  433.             break;
  434.  
  435.         case DIRECTION_SOUTHWEST:
  436.             pos.x--;
  437.             pos.y++;
  438.             break;
  439.  
  440.         case DIRECTION_NORTHWEST:
  441.             pos.x--;
  442.             pos.y--;
  443.             break;
  444.  
  445.         case DIRECTION_NORTHEAST:
  446.             pos.x++;
  447.             pos.y--;
  448.             break;
  449.  
  450.         case DIRECTION_SOUTHEAST:
  451.             pos.x++;
  452.             pos.y++;
  453.             break;
  454.  
  455.         default:
  456.             break;
  457.     }
  458.  
  459.     return pos;
  460. }
  461.  
  462. Direction getDirectionTo(const Position& from, const Position& to)
  463. {
  464.     Direction dir;
  465.  
  466.     int32_t x_offset = Position::getOffsetX(from, to);
  467.     if (x_offset < 0) {
  468.         dir = DIRECTION_EAST;
  469.         x_offset = std::abs(x_offset);
  470.     } else {
  471.         dir = DIRECTION_WEST;
  472.     }
  473.  
  474.     int32_t y_offset = Position::getOffsetY(from, to);
  475.     if (y_offset >= 0) {
  476.         if (y_offset > x_offset) {
  477.             dir = DIRECTION_NORTH;
  478.         } else if (y_offset == x_offset) {
  479.             if (dir == DIRECTION_EAST) {
  480.                 dir = DIRECTION_NORTHEAST;
  481.             } else {
  482.                 dir = DIRECTION_NORTHWEST;
  483.             }
  484.         }
  485.     } else {
  486.         y_offset = std::abs(y_offset);
  487.         if (y_offset > x_offset) {
  488.             dir = DIRECTION_SOUTH;
  489.         } else if (y_offset == x_offset) {
  490.             if (dir == DIRECTION_EAST) {
  491.                 dir = DIRECTION_SOUTHEAST;
  492.             } else {
  493.                 dir = DIRECTION_SOUTHWEST;
  494.             }
  495.         }
  496.     }
  497.     return dir;
  498. }
  499.  
  500. using MagicEffectNames = std::unordered_map<std::string, MagicEffectClasses>;
  501. using ShootTypeNames = std::unordered_map<std::string, ShootType_t>;
  502. using CombatTypeNames = std::unordered_map<CombatType_t, std::string, std::hash<int32_t>>;
  503. using AmmoTypeNames = std::unordered_map<std::string, Ammo_t>;
  504. using WeaponActionNames = std::unordered_map<std::string, WeaponAction_t>;
  505. using SkullNames = std::unordered_map<std::string, Skulls_t>;
  506.  
  507. MagicEffectNames magicEffectNames = {
  508.     {"redspark",        CONST_ME_DRAWBLOOD},
  509.     {"bluebubble",      CONST_ME_LOSEENERGY},
  510.     {"poff",        CONST_ME_POFF},
  511.     {"yellowspark",     CONST_ME_BLOCKHIT},
  512.     {"explosionarea",   CONST_ME_EXPLOSIONAREA},
  513.     {"explosion",       CONST_ME_EXPLOSIONHIT},
  514.     {"firearea",        CONST_ME_FIREAREA},
  515.     {"yellowbubble",    CONST_ME_YELLOW_RINGS},
  516.     {"greenbubble",     CONST_ME_GREEN_RINGS},
  517.     {"blackspark",      CONST_ME_HITAREA},
  518.     {"teleport",        CONST_ME_TELEPORT},
  519.     {"energy",      CONST_ME_ENERGYHIT},
  520.     {"blueshimmer",     CONST_ME_MAGIC_BLUE},
  521.     {"redshimmer",      CONST_ME_MAGIC_RED},
  522.     {"greenshimmer",    CONST_ME_MAGIC_GREEN},
  523.     {"fire",        CONST_ME_HITBYFIRE},
  524.     {"greenspark",      CONST_ME_HITBYPOISON},
  525.     {"mortarea",        CONST_ME_MORTAREA},
  526.     {"greennote",       CONST_ME_SOUND_GREEN},
  527.     {"rednote",     CONST_ME_SOUND_RED},
  528.     {"poison",      CONST_ME_POISONAREA},
  529.     {"yellownote",      CONST_ME_SOUND_YELLOW},
  530.     {"purplenote",      CONST_ME_SOUND_PURPLE},
  531.     {"bluenote",        CONST_ME_SOUND_BLUE},
  532.     {"whitenote",       CONST_ME_SOUND_WHITE},
  533.     {"bubbles",     CONST_ME_BUBBLES},
  534.     {"dice",        CONST_ME_CRAPS},
  535.     {"giftwraps",       CONST_ME_GIFT_WRAPS},
  536.     {"yellowfirework",  CONST_ME_FIREWORK_YELLOW},
  537.     {"redfirework",     CONST_ME_FIREWORK_RED},
  538.     {"bluefirework",    CONST_ME_FIREWORK_BLUE},
  539.     {"stun",        CONST_ME_STUN},
  540.     {"sleep",       CONST_ME_SLEEP},
  541.     {"watercreature",   CONST_ME_WATERCREATURE},
  542.     {"groundshaker",    CONST_ME_GROUNDSHAKER},
  543.     {"hearts",      CONST_ME_HEARTS},
  544.     {"fireattack",      CONST_ME_FIREATTACK},
  545.     {"energyarea",      CONST_ME_ENERGYAREA},
  546.     {"smallclouds",     CONST_ME_SMALLCLOUDS},
  547.     {"holydamage",      CONST_ME_HOLYDAMAGE},
  548.     {"bigclouds",       CONST_ME_BIGCLOUDS},
  549.     {"icearea",     CONST_ME_ICEAREA},
  550.     {"icetornado",      CONST_ME_ICETORNADO},
  551.     {"iceattack",       CONST_ME_ICEATTACK},
  552.     {"stones",      CONST_ME_STONES},
  553.     {"smallplants",     CONST_ME_SMALLPLANTS},
  554.     {"carniphila",      CONST_ME_CARNIPHILA},
  555.     {"purpleenergy",    CONST_ME_PURPLEENERGY},
  556.     {"yellowenergy",    CONST_ME_YELLOWENERGY},
  557.     {"holyarea",        CONST_ME_HOLYAREA},
  558.     {"bigplants",       CONST_ME_BIGPLANTS},
  559.     {"cake",        CONST_ME_CAKE},
  560.     {"giantice",        CONST_ME_GIANTICE},
  561.     {"watersplash",     CONST_ME_WATERSPLASH},
  562.     {"plantattack",     CONST_ME_PLANTATTACK},
  563.     {"tutorialarrow",   CONST_ME_TUTORIALARROW},
  564.     {"tutorialsquare",  CONST_ME_TUTORIALSQUARE},
  565.     {"mirrorhorizontal",    CONST_ME_MIRRORHORIZONTAL},
  566.     {"mirrorvertical",  CONST_ME_MIRRORVERTICAL},
  567.     {"skullhorizontal", CONST_ME_SKULLHORIZONTAL},
  568.     {"skullvertical",   CONST_ME_SKULLVERTICAL},
  569.     {"assassin",        CONST_ME_ASSASSIN},
  570.     {"stepshorizontal", CONST_ME_STEPSHORIZONTAL},
  571.     {"bloodysteps",     CONST_ME_BLOODYSTEPS},
  572.     {"stepsvertical",   CONST_ME_STEPSVERTICAL},
  573.     {"yalaharighost",   CONST_ME_YALAHARIGHOST},
  574.     {"bats",        CONST_ME_BATS},
  575.     {"smoke",       CONST_ME_SMOKE},
  576.     {"insects",     CONST_ME_INSECTS},
  577.     {"dragonhead",      CONST_ME_DRAGONHEAD},
  578.     {"orcshaman",       CONST_ME_ORCSHAMAN},
  579.     {"orcshamanfire",   CONST_ME_ORCSHAMAN_FIRE},
  580.     {"thunder",     CONST_ME_THUNDER},
  581.     {"ferumbras",       CONST_ME_FERUMBRAS},
  582.     {"confettihorizontal",  CONST_ME_CONFETTI_HORIZONTAL},
  583.     {"confettivertical",    CONST_ME_CONFETTI_VERTICAL},
  584.     {"blacksmoke",      CONST_ME_BLACKSMOKE},
  585.     {"redsmoke",        CONST_ME_REDSMOKE},
  586.     {"yellowsmoke",     CONST_ME_YELLOWSMOKE},
  587.     {"greensmoke",      CONST_ME_GREENSMOKE},
  588.     {"purplesmoke",     CONST_ME_PURPLESMOKE},
  589. };
  590.  
  591. ShootTypeNames shootTypeNames = {
  592.     {"spear",       CONST_ANI_SPEAR},
  593.     {"bolt",        CONST_ANI_BOLT},
  594.     {"arrow",       CONST_ANI_ARROW},
  595.     {"fire",        CONST_ANI_FIRE},
  596.     {"energy",      CONST_ANI_ENERGY},
  597.     {"poisonarrow",     CONST_ANI_POISONARROW},
  598.     {"burstarrow",      CONST_ANI_BURSTARROW},
  599.     {"throwingstar",    CONST_ANI_THROWINGSTAR},
  600.     {"throwingknife",   CONST_ANI_THROWINGKNIFE},
  601.     {"smallstone",      CONST_ANI_SMALLSTONE},
  602.     {"death",       CONST_ANI_DEATH},
  603.     {"largerock",       CONST_ANI_LARGEROCK},
  604.     {"snowball",        CONST_ANI_SNOWBALL},
  605.     {"powerbolt",       CONST_ANI_POWERBOLT},
  606.     {"poison",      CONST_ANI_POISON},
  607.     {"infernalbolt",    CONST_ANI_INFERNALBOLT},
  608.     {"huntingspear",    CONST_ANI_HUNTINGSPEAR},
  609.     {"enchantedspear",  CONST_ANI_ENCHANTEDSPEAR},
  610.     {"redstar",     CONST_ANI_REDSTAR},
  611.     {"greenstar",       CONST_ANI_GREENSTAR},
  612.     {"royalspear",      CONST_ANI_ROYALSPEAR},
  613.     {"sniperarrow",     CONST_ANI_SNIPERARROW},
  614.     {"onyxarrow",       CONST_ANI_ONYXARROW},
  615.     {"piercingbolt",    CONST_ANI_PIERCINGBOLT},
  616.     {"whirlwindsword",  CONST_ANI_WHIRLWINDSWORD},
  617.     {"whirlwindaxe",    CONST_ANI_WHIRLWINDAXE},
  618.     {"whirlwindclub",   CONST_ANI_WHIRLWINDCLUB},
  619.     {"etherealspear",   CONST_ANI_ETHEREALSPEAR},
  620.     {"ice",         CONST_ANI_ICE},
  621.     {"earth",       CONST_ANI_EARTH},
  622.     {"holy",        CONST_ANI_HOLY},
  623.     {"suddendeath",     CONST_ANI_SUDDENDEATH},
  624.     {"flasharrow",      CONST_ANI_FLASHARROW},
  625.     {"flammingarrow",   CONST_ANI_FLAMMINGARROW},
  626.     {"shiverarrow",     CONST_ANI_SHIVERARROW},
  627.     {"energyball",      CONST_ANI_ENERGYBALL},
  628.     {"smallice",        CONST_ANI_SMALLICE},
  629.     {"smallholy",       CONST_ANI_SMALLHOLY},
  630.     {"smallearth",      CONST_ANI_SMALLEARTH},
  631.     {"eartharrow",      CONST_ANI_EARTHARROW},
  632.     {"explosion",       CONST_ANI_EXPLOSION},
  633.     {"cake",        CONST_ANI_CAKE},
  634.     {"tarsalarrow",     CONST_ANI_TARSALARROW},
  635.     {"vortexbolt",      CONST_ANI_VORTEXBOLT},
  636.     {"prismaticbolt",   CONST_ANI_PRISMATICBOLT},
  637.     {"crystallinearrow",    CONST_ANI_CRYSTALLINEARROW},
  638.     {"drillbolt",       CONST_ANI_DRILLBOLT},
  639.     {"envenomedarrow",  CONST_ANI_ENVENOMEDARROW},
  640.     {"gloothspear",     CONST_ANI_GLOOTHSPEAR},
  641.     {"simplearrow",     CONST_ANI_SIMPLEARROW},
  642. };
  643.  
  644. CombatTypeNames combatTypeNames = {
  645.     {COMBAT_PHYSICALDAMAGE,     "physical"},
  646.     {COMBAT_ENERGYDAMAGE,       "energy"},
  647.     {COMBAT_EARTHDAMAGE,        "earth"},
  648.     {COMBAT_FIREDAMAGE,         "fire"},
  649.     {COMBAT_UNDEFINEDDAMAGE,    "undefined"},
  650.     {COMBAT_LIFEDRAIN,      "lifedrain"},
  651.     {COMBAT_MANADRAIN,      "manadrain"},
  652.     {COMBAT_HEALING,        "healing"},
  653.     {COMBAT_DROWNDAMAGE,        "drown"},
  654.     {COMBAT_ICEDAMAGE,      "ice"},
  655.     {COMBAT_HOLYDAMAGE,         "holy"},
  656.     {COMBAT_DEATHDAMAGE,        "death"},
  657. };
  658.  
  659. AmmoTypeNames ammoTypeNames = {
  660.     {"spear",       AMMO_SPEAR},
  661.     {"bolt",        AMMO_BOLT},
  662.     {"arrow",       AMMO_ARROW},
  663.     {"poisonarrow",     AMMO_ARROW},
  664.     {"burstarrow",      AMMO_ARROW},
  665.     {"throwingstar",    AMMO_THROWINGSTAR},
  666.     {"throwingknife",   AMMO_THROWINGKNIFE},
  667.     {"smallstone",      AMMO_STONE},
  668.     {"largerock",       AMMO_STONE},
  669.     {"snowball",        AMMO_SNOWBALL},
  670.     {"powerbolt",       AMMO_BOLT},
  671.     {"infernalbolt",    AMMO_BOLT},
  672.     {"huntingspear",    AMMO_SPEAR},
  673.     {"enchantedspear",  AMMO_SPEAR},
  674.     {"royalspear",      AMMO_SPEAR},
  675.     {"sniperarrow",     AMMO_ARROW},
  676.     {"onyxarrow",       AMMO_ARROW},
  677.     {"piercingbolt",    AMMO_BOLT},
  678.     {"etherealspear",   AMMO_SPEAR},
  679.     {"flasharrow",      AMMO_ARROW},
  680.     {"flammingarrow",   AMMO_ARROW},
  681.     {"shiverarrow",     AMMO_ARROW},
  682.     {"eartharrow",      AMMO_ARROW},
  683. };
  684.  
  685. WeaponActionNames weaponActionNames = {
  686.     {"move",        WEAPONACTION_MOVE},
  687.     {"removecharge",    WEAPONACTION_REMOVECHARGE},
  688.     {"removecount",     WEAPONACTION_REMOVECOUNT},
  689. };
  690.  
  691. SkullNames skullNames = {
  692.     {"none",    SKULL_NONE},
  693.     {"yellow",  SKULL_YELLOW},
  694.     {"green",   SKULL_GREEN},
  695.     {"white",   SKULL_WHITE},
  696.     {"red",     SKULL_RED},
  697.     {"black",   SKULL_BLACK},
  698.     {"orange",  SKULL_ORANGE},
  699. };
  700.  
  701. MagicEffectClasses getMagicEffect(const std::string& strValue)
  702. {
  703.     auto magicEffect = magicEffectNames.find(strValue);
  704.     if (magicEffect != magicEffectNames.end()) {
  705.         return magicEffect->second;
  706.     }
  707.     return CONST_ME_NONE;
  708. }
  709.  
  710. ShootType_t getShootType(const std::string& strValue)
  711. {
  712.     auto shootType = shootTypeNames.find(strValue);
  713.     if (shootType != shootTypeNames.end()) {
  714.         return shootType->second;
  715.     }
  716.     return CONST_ANI_NONE;
  717. }
  718.  
  719. std::string getCombatName(CombatType_t combatType)
  720. {
  721.     auto combatName = combatTypeNames.find(combatType);
  722.     if (combatName != combatTypeNames.end()) {
  723.         return combatName->second;
  724.     }
  725.     return "unknown";
  726. }
  727.  
  728. Ammo_t getAmmoType(const std::string& strValue)
  729. {
  730.     auto ammoType = ammoTypeNames.find(strValue);
  731.     if (ammoType != ammoTypeNames.end()) {
  732.         return ammoType->second;
  733.     }
  734.     return AMMO_NONE;
  735. }
  736.  
  737. WeaponAction_t getWeaponAction(const std::string& strValue)
  738. {
  739.     auto weaponAction = weaponActionNames.find(strValue);
  740.     if (weaponAction != weaponActionNames.end()) {
  741.         return weaponAction->second;
  742.     }
  743.     return WEAPONACTION_NONE;
  744. }
  745.  
  746. Skulls_t getSkullType(const std::string& strValue)
  747. {
  748.     auto skullType = skullNames.find(strValue);
  749.     if (skullType != skullNames.end()) {
  750.         return skullType->second;
  751.     }
  752.     return SKULL_NONE;
  753. }
  754.  
  755. std::string getSpecialSkillName(uint8_t skillid)
  756. {
  757.     switch (skillid) {
  758.         case SPECIALSKILL_CRITICALHITCHANCE:
  759.             return "critical hit chance";
  760.  
  761.         case SPECIALSKILL_CRITICALHITAMOUNT:
  762.             return "critical extra damage";
  763.  
  764.         case SPECIALSKILL_HITPOINTSLEECHCHANCE:
  765.             return "hitpoints leech chance";
  766.  
  767.         case SPECIALSKILL_HITPOINTSLEECHAMOUNT:
  768.             return "hitpoints leech amount";
  769.  
  770.         case SPECIALSKILL_MANAPOINTSLEECHCHANCE:
  771.             return "manapoints leech chance";
  772.  
  773.         case SPECIALSKILL_MANAPOINTSLEECHAMOUNT:
  774.             return "mana points leech amount";
  775.  
  776.         default:
  777.             return "unknown";
  778.     }
  779. }
  780.  
  781. std::string getSkillName(uint8_t skillid)
  782. {
  783.     switch (skillid) {
  784.         case SKILL_FIST:
  785.             return "fist fighting";
  786.  
  787.         case SKILL_CLUB:
  788.             return "club fighting";
  789.  
  790.         case SKILL_SWORD:
  791.             return "sword fighting";
  792.  
  793.         case SKILL_AXE:
  794.             return "axe fighting";
  795.  
  796.         case SKILL_DISTANCE:
  797.             return "distance fighting";
  798.  
  799.         case SKILL_SHIELD:
  800.             return "shielding";
  801.  
  802.         case SKILL_FISHING:
  803.             return "fishing";
  804.  
  805.         case SKILL_MAGLEVEL:
  806.             return "magic level";
  807.  
  808.         case SKILL_LEVEL:
  809.             return "level";
  810.  
  811.         default:
  812.             return "unknown";
  813.     }
  814. }
  815.  
  816. uint32_t adlerChecksum(const uint8_t* data, size_t length)
  817. {
  818.     if (length > NETWORKMESSAGE_MAXSIZE) {
  819.         return 0;
  820.     }
  821.  
  822.     const uint16_t adler = 65521;
  823.  
  824.     uint32_t a = 1, b = 0;
  825.  
  826.     while (length > 0) {
  827.         size_t tmp = length > 5552 ? 5552 : length;
  828.         length -= tmp;
  829.  
  830.         do {
  831.             a += *data++;
  832.             b += a;
  833.         } while (--tmp);
  834.  
  835.         a %= adler;
  836.         b %= adler;
  837.     }
  838.  
  839.     return (b << 16) | a;
  840. }
  841.  
  842. std::string ucfirst(std::string str)
  843. {
  844.     for (char& i : str) {
  845.         if (i != ' ') {
  846.             i = toupper(i);
  847.             break;
  848.         }
  849.     }
  850.     return str;
  851. }
  852.  
  853. std::string ucwords(std::string str)
  854. {
  855.     size_t strLength = str.length();
  856.     if (strLength == 0) {
  857.         return str;
  858.     }
  859.  
  860.     str[0] = toupper(str.front());
  861.     for (size_t i = 1; i < strLength; ++i) {
  862.         if (str[i - 1] == ' ') {
  863.             str[i] = toupper(str[i]);
  864.         }
  865.     }
  866.  
  867.     return str;
  868. }
  869.  
  870. bool booleanString(const std::string& str)
  871. {
  872.     if (str.empty()) {
  873.         return false;
  874.     }
  875.  
  876.     char ch = tolower(str.front());
  877.     return ch != 'f' && ch != 'n' && ch != '0';
  878. }
  879.  
  880. std::string getWeaponName(WeaponType_t weaponType)
  881. {
  882.     switch (weaponType) {
  883.         case WEAPON_SWORD: return "sword";
  884.         case WEAPON_CLUB: return "club";
  885.         case WEAPON_AXE: return "axe";
  886.         case WEAPON_DISTANCE: return "distance";
  887.         case WEAPON_WAND: return "wand";
  888.         case WEAPON_AMMO: return "ammunition";
  889.         default: return std::string();
  890.     }
  891. }
  892.  
  893. size_t combatTypeToIndex(CombatType_t combatType)
  894. {
  895.     switch (combatType) {
  896.         case COMBAT_PHYSICALDAMAGE:
  897.             return 0;
  898.         case COMBAT_ENERGYDAMAGE:
  899.             return 1;
  900.         case COMBAT_EARTHDAMAGE:
  901.             return 2;
  902.         case COMBAT_FIREDAMAGE:
  903.             return 3;
  904.         case COMBAT_UNDEFINEDDAMAGE:
  905.             return 4;
  906.         case COMBAT_LIFEDRAIN:
  907.             return 5;
  908.         case COMBAT_MANADRAIN:
  909.             return 6;
  910.         case COMBAT_HEALING:
  911.             return 7;
  912.         case COMBAT_DROWNDAMAGE:
  913.             return 8;
  914.         case COMBAT_ICEDAMAGE:
  915.             return 9;
  916.         case COMBAT_HOLYDAMAGE:
  917.             return 10;
  918.         case COMBAT_DEATHDAMAGE:
  919.             return 11;
  920.         default:
  921.             return 0;
  922.     }
  923. }
  924.  
  925. CombatType_t indexToCombatType(size_t v)
  926. {
  927.     return static_cast<CombatType_t>(1 << v);
  928. }
  929.  
  930. uint8_t serverFluidToClient(uint8_t serverFluid)
  931. {
  932.     uint8_t size = sizeof(clientToServerFluidMap) / sizeof(uint8_t);
  933.     for (uint8_t i = 0; i < size; ++i) {
  934.         if (clientToServerFluidMap[i] == serverFluid) {
  935.             return i;
  936.         }
  937.     }
  938.     return 0;
  939. }
  940.  
  941. uint8_t clientFluidToServer(uint8_t clientFluid)
  942. {
  943.     uint8_t size = sizeof(clientToServerFluidMap) / sizeof(uint8_t);
  944.     if (clientFluid >= size) {
  945.         return 0;
  946.     }
  947.     return clientToServerFluidMap[clientFluid];
  948. }
  949.  
  950. itemAttrTypes stringToItemAttribute(const std::string& str)
  951. {
  952.     if (str == "aid") {
  953.         return ITEM_ATTRIBUTE_ACTIONID;
  954.     } else if (str == "uid") {
  955.         return ITEM_ATTRIBUTE_UNIQUEID;
  956.     } else if (str == "description") {
  957.         return ITEM_ATTRIBUTE_DESCRIPTION;
  958.     } else if (str == "text") {
  959.         return ITEM_ATTRIBUTE_TEXT;
  960.     } else if (str == "date") {
  961.         return ITEM_ATTRIBUTE_DATE;
  962.     } else if (str == "writer") {
  963.         return ITEM_ATTRIBUTE_WRITER;
  964.     } else if (str == "name") {
  965.         return ITEM_ATTRIBUTE_NAME;
  966.     } else if (str == "article") {
  967.         return ITEM_ATTRIBUTE_ARTICLE;
  968.     } else if (str == "pluralname") {
  969.         return ITEM_ATTRIBUTE_PLURALNAME;
  970.     } else if (str == "weight") {
  971.         return ITEM_ATTRIBUTE_WEIGHT;
  972.     } else if (str == "attack") {
  973.         return ITEM_ATTRIBUTE_ATTACK;
  974.     } else if (str == "defense") {
  975.         return ITEM_ATTRIBUTE_DEFENSE;
  976.     } else if (str == "extradefense") {
  977.         return ITEM_ATTRIBUTE_EXTRADEFENSE;
  978.     } else if (str == "armor") {
  979.         return ITEM_ATTRIBUTE_ARMOR;
  980.     } else if (str == "hitchance") {
  981.         return ITEM_ATTRIBUTE_HITCHANCE;
  982.     } else if (str == "shootrange") {
  983.         return ITEM_ATTRIBUTE_SHOOTRANGE;
  984.     } else if (str == "owner") {
  985.         return ITEM_ATTRIBUTE_OWNER;
  986.     } else if (str == "duration") {
  987.         return ITEM_ATTRIBUTE_DURATION;
  988.     } else if (str == "decaystate") {
  989.         return ITEM_ATTRIBUTE_DECAYSTATE;
  990.     } else if (str == "corpseowner") {
  991.         return ITEM_ATTRIBUTE_CORPSEOWNER;
  992.     } else if (str == "charges") {
  993.         return ITEM_ATTRIBUTE_CHARGES;
  994.     } else if (str == "fluidtype") {
  995.         return ITEM_ATTRIBUTE_FLUIDTYPE;
  996.     } else if (str == "doorid") {
  997.         return ITEM_ATTRIBUTE_DOORID;
  998.     }
  999.     return ITEM_ATTRIBUTE_NONE;
  1000. }
  1001.  
  1002. std::string getFirstLine(const std::string& str)
  1003. {
  1004.     std::string firstLine;
  1005.     firstLine.reserve(str.length());
  1006.     for (const char c : str) {
  1007.         if (c == '\n') {
  1008.             break;
  1009.         }
  1010.         firstLine.push_back(c);
  1011.     }
  1012.     return firstLine;
  1013. }
  1014.  
  1015. const char* getReturnMessage(ReturnValue value)
  1016. {
  1017.     switch (value) {
  1018.         case RETURNVALUE_DESTINATIONOUTOFREACH:
  1019.             return "Destination is out of reach.";
  1020.  
  1021.         case RETURNVALUE_NOTMOVEABLE:
  1022.             return "You cannot move this object.";
  1023.  
  1024.         case RETURNVALUE_DROPTWOHANDEDITEM:
  1025.             return "Drop the double-handed object first.";
  1026.  
  1027.         case RETURNVALUE_BOTHHANDSNEEDTOBEFREE:
  1028.             return "Both hands need to be free.";
  1029.  
  1030.         case RETURNVALUE_CANNOTBEDRESSED:
  1031.             return "You cannot dress this object there.";
  1032.  
  1033.         case RETURNVALUE_PUTTHISOBJECTINYOURHAND:
  1034.             return "Put this object in your hand.";
  1035.  
  1036.         case RETURNVALUE_PUTTHISOBJECTINBOTHHANDS:
  1037.             return "Put this object in both hands.";
  1038.  
  1039.         //case RETURNVALUE_CANONLYUSEONEWEAPON:
  1040.             //return "You may only use one weapon.";
  1041.  
  1042.         case RETURNVALUE_TOOFARAWAY:
  1043.             return "Too far away.";
  1044.  
  1045.         case RETURNVALUE_FIRSTGODOWNSTAIRS:
  1046.             return "First go downstairs.";
  1047.  
  1048.         case RETURNVALUE_FIRSTGOUPSTAIRS:
  1049.             return "First go upstairs.";
  1050.  
  1051.         case RETURNVALUE_NOTENOUGHCAPACITY:
  1052.             return "This object is too heavy for you to carry.";
  1053.  
  1054.         case RETURNVALUE_CONTAINERNOTENOUGHROOM:
  1055.             return "You cannot put more objects in this container.";
  1056.  
  1057.         case RETURNVALUE_NEEDEXCHANGE:
  1058.         case RETURNVALUE_NOTENOUGHROOM:
  1059.             return "There is not enough room.";
  1060.  
  1061.         case RETURNVALUE_CANNOTPICKUP:
  1062.             return "You cannot take this object.";
  1063.  
  1064.         case RETURNVALUE_CANNOTTHROW:
  1065.             return "You cannot throw there.";
  1066.  
  1067.         case RETURNVALUE_THEREISNOWAY:
  1068.             return "There is no way.";
  1069.  
  1070.         case RETURNVALUE_THISISIMPOSSIBLE:
  1071.             return "This is impossible.";
  1072.  
  1073.         case RETURNVALUE_PLAYERISPZLOCKED:
  1074.             return "You can not enter a protection zone after attacking another player.";
  1075.  
  1076.         case RETURNVALUE_PLAYERISNOTINVITED:
  1077.             return "You are not invited.";
  1078.  
  1079.         case RETURNVALUE_CREATUREDOESNOTEXIST:
  1080.             return "Creature does not exist.";
  1081.  
  1082.         case RETURNVALUE_DEPOTISFULL:
  1083.             return "You cannot put more items in this depot.";
  1084.  
  1085.         case RETURNVALUE_CANNOTUSETHISOBJECT:
  1086.             return "You cannot use this object.";
  1087.  
  1088.         case RETURNVALUE_PLAYERWITHTHISNAMEISNOTONLINE:
  1089.             return "A player with this name is not online.";
  1090.  
  1091.         case RETURNVALUE_NOTREQUIREDLEVELTOUSERUNE:
  1092.             return "You do not have the required magic level to use this rune.";
  1093.  
  1094.         case RETURNVALUE_YOUAREALREADYTRADING:
  1095.             return "You are already trading.";
  1096.  
  1097.         case RETURNVALUE_THISPLAYERISALREADYTRADING:
  1098.             return "This player is already trading.";
  1099.  
  1100.         case RETURNVALUE_YOUMAYNOTLOGOUTDURINGAFIGHT:
  1101.             return "You may not logout during or immediately after a fight!";
  1102.  
  1103.         case RETURNVALUE_DIRECTPLAYERSHOOT:
  1104.             return "You are not allowed to shoot directly on players.";
  1105.  
  1106.         case RETURNVALUE_NOTENOUGHLEVEL:
  1107.             return "You do not have enough level.";
  1108.  
  1109.         case RETURNVALUE_NOTENOUGHMAGICLEVEL:
  1110.             return "You do not have enough magic level.";
  1111.  
  1112.         case RETURNVALUE_NOTENOUGHMANA:
  1113.             return "You do not have enough mana.";
  1114.  
  1115.         case RETURNVALUE_NOTENOUGHSOUL:
  1116.             return "You do not have enough soul.";
  1117.  
  1118.         case RETURNVALUE_YOUAREEXHAUSTED:
  1119.             return "You are exhausted.";
  1120.  
  1121.         case RETURNVALUE_CANONLYUSETHISRUNEONCREATURES:
  1122.             return "You can only use this rune on creatures.";
  1123.  
  1124.         case RETURNVALUE_PLAYERISNOTREACHABLE:
  1125.             return "Player is not reachable.";
  1126.  
  1127.         case RETURNVALUE_CREATUREISNOTREACHABLE:
  1128.             return "Creature is not reachable.";
  1129.  
  1130.         case RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE:
  1131.             return "This action is not permitted in a protection zone.";
  1132.  
  1133.         case RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER:
  1134.             return "You may not attack this player.";
  1135.  
  1136.         case RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE:
  1137.             return "You may not attack this creature.";
  1138.  
  1139.         case RETURNVALUE_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE:
  1140.             return "You may not attack a person in a protection zone.";
  1141.  
  1142.         case RETURNVALUE_YOUMAYNOTATTACKAPERSONWHILEINPROTECTIONZONE:
  1143.             return "You may not attack a person while you are in a protection zone.";
  1144.  
  1145.         case RETURNVALUE_YOUCANONLYUSEITONCREATURES:
  1146.             return "You can only use it on creatures.";
  1147.  
  1148.         case RETURNVALUE_TURNSECUREMODETOATTACKUNMARKEDPLAYERS:
  1149.             return "Turn secure mode off if you really want to attack unmarked players.";
  1150.  
  1151.         case RETURNVALUE_YOUNEEDPREMIUMACCOUNT:
  1152.             return "You need a premium account.";
  1153.  
  1154.         case RETURNVALUE_YOUNEEDTOLEARNTHISSPELL:
  1155.             return "You need to learn this spell first.";
  1156.  
  1157.         case RETURNVALUE_YOURVOCATIONCANNOTUSETHISSPELL:
  1158.             return "Your vocation cannot use this spell.";
  1159.  
  1160.         case RETURNVALUE_YOUNEEDAWEAPONTOUSETHISSPELL:
  1161.             return "You need to equip a weapon to use this spell.";
  1162.  
  1163.         case RETURNVALUE_PLAYERISPZLOCKEDLEAVEPVPZONE:
  1164.             return "You can not leave a pvp zone after attacking another player.";
  1165.  
  1166.         case RETURNVALUE_PLAYERISPZLOCKEDENTERPVPZONE:
  1167.             return "You can not enter a pvp zone after attacking another player.";
  1168.  
  1169.         case RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE:
  1170.             return "This action is not permitted in a non pvp zone.";
  1171.  
  1172.         case RETURNVALUE_YOUCANNOTLOGOUTHERE:
  1173.             return "You can not logout here.";
  1174.  
  1175.         case RETURNVALUE_YOUNEEDAMAGICITEMTOCASTSPELL:
  1176.             return "You need a magic item to cast this spell.";
  1177.  
  1178.         case RETURNVALUE_CANNOTCONJUREITEMHERE:
  1179.             return "You cannot conjure items here.";
  1180.  
  1181.         case RETURNVALUE_YOUNEEDTOSPLITYOURSPEARS:
  1182.             return "You need to split your spears first.";
  1183.  
  1184.         case RETURNVALUE_NAMEISTOOAMBIGUOUS:
  1185.             return "Player name is ambiguous.";
  1186.  
  1187.         case RETURNVALUE_CANONLYUSEONESHIELD:
  1188.             return "You may use only one shield.";
  1189.  
  1190.         case RETURNVALUE_NOPARTYMEMBERSINRANGE:
  1191.             return "No party members in range.";
  1192.  
  1193.         case RETURNVALUE_YOUARENOTTHEOWNER:
  1194.             return "You are not the owner.";
  1195.  
  1196.         case RETURNVALUE_NOSUCHRAIDEXISTS:
  1197.             return "No such raid exists.";
  1198.  
  1199.         case RETURNVALUE_ANOTHERRAIDISALREADYEXECUTING:
  1200.             return "Another raid is already executing.";
  1201.  
  1202.         case RETURNVALUE_TRADEPLAYERFARAWAY:
  1203.             return "Trade player is too far away.";
  1204.  
  1205.         case RETURNVALUE_YOUDONTOWNTHISHOUSE:
  1206.             return "You don't own this house.";
  1207.  
  1208.         case RETURNVALUE_TRADEPLAYERALREADYOWNSAHOUSE:
  1209.             return "Trade player already owns a house.";
  1210.  
  1211.         case RETURNVALUE_TRADEPLAYERHIGHESTBIDDER:
  1212.             return "Trade player is currently the highest bidder of an auctioned house.";
  1213.  
  1214.         case RETURNVALUE_YOUCANNOTTRADETHISHOUSE:
  1215.             return "You can not trade this house.";
  1216.  
  1217.         default: // RETURNVALUE_NOTPOSSIBLE, etc
  1218.             return "Sorry, not possible.";
  1219.     }
  1220. }
  1221.  
  1222. int64_t OTSYS_TIME()
  1223. {
  1224.     return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
  1225. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement