TheLastEmpire

The Last Empire

Sep 30th, 2017
530
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 37.79 KB | None | 0 0
  1. /**
  2.  * The Forgotten Server - a free and open-source MMORPG server emulator
  3.  * Copyright (C) 2017  Mark Samman <[email protected]>
  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 <boost/range/adaptor/reversed.hpp>
  23.  
  24. #include "iologindata.h"
  25. #include "configmanager.h"
  26. #include "game.h"
  27.  
  28. extern ConfigManager g_config;
  29. extern Game g_game;
  30.  
  31. Account IOLoginData::loadAccount(uint32_t accno)
  32. {
  33.     Account account;
  34.  
  35.     std::ostringstream query;
  36.     query << "SELECT `id`, `name`, `password`, `type`, `premdays`, `lastday` FROM `accounts` WHERE `id` = " << accno;
  37.     DBResult_ptr result = Database::getInstance().storeQuery(query.str());
  38.     if (!result) {
  39.         return account;
  40.     }
  41.  
  42.     account.id = result->getNumber<uint32_t>("id");
  43.     account.name = result->getString("name");
  44.     account.accountType = static_cast<AccountType_t>(result->getNumber<int32_t>("type"));
  45.     account.premiumDays = result->getNumber<uint16_t>("premdays");
  46.     account.lastDay = result->getNumber<time_t>("lastday");
  47.     return account;
  48. }
  49.  
  50. bool IOLoginData::saveAccount(const Account& acc)
  51. {
  52.     std::ostringstream query;
  53.     query << "UPDATE `accounts` SET `premdays` = " << acc.premiumDays << ", `lastday` = " << acc.lastDay << " WHERE `id` = " << acc.id;
  54.     return Database::getInstance().executeQuery(query.str());
  55. }
  56.  
  57. bool IOLoginData::loginserverAuthentication(const std::string& name, const std::string& password, Account& account)
  58. {
  59.     Database& db = Database::getInstance();
  60.  
  61.     std::ostringstream query;
  62.     query << "SELECT `id`, `name`, `password`, `type`, `premdays`, `lastday` FROM `accounts` WHERE `name` = " << db.escapeString(name);
  63.     DBResult_ptr result = db.storeQuery(query.str());
  64.     if (!result) {
  65.         return false;
  66.     }
  67.  
  68.     if (transformToSHA1(password) != result->getString("password")) {
  69.         return false;
  70.     }
  71.  
  72.     account.id = result->getNumber<uint32_t>("id");
  73.     account.name = result->getString("name");
  74.     account.accountType = static_cast<AccountType_t>(result->getNumber<int32_t>("type"));
  75.     account.premiumDays = result->getNumber<uint16_t>("premdays");
  76.     account.lastDay = result->getNumber<time_t>("lastday");
  77.  
  78.     query.str(std::string());
  79.     query << "SELECT `name`, `deletion` FROM `players` WHERE `account_id` = " << account.id;
  80.     result = db.storeQuery(query.str());
  81.     if (result) {
  82.         do {
  83.             if (result->getNumber<uint64_t>("deletion") == 0) {
  84.                 account.characters.push_back(result->getString("name"));
  85.             }
  86.         } while (result->next());
  87.         std::sort(account.characters.begin(), account.characters.end());
  88.     }
  89.     return true;
  90. }
  91.  
  92. uint32_t IOLoginData::gameworldAuthentication(const std::string& accountName, const std::string& password, std::string& characterName)
  93. {
  94.     Database& db = Database::getInstance();
  95.  
  96.     std::ostringstream query;
  97.     query << "SELECT `id`, `password` FROM `accounts` WHERE `name` = " << db.escapeString(accountName);
  98.     DBResult_ptr result = db.storeQuery(query.str());
  99.     if (!result) {
  100.         return 0;
  101.     }
  102.  
  103.     if (transformToSHA1(password) != result->getString("password")) {
  104.         return 0;
  105.     }
  106.  
  107.     uint32_t accountId = result->getNumber<uint32_t>("id");
  108.  
  109.     query.str(std::string());
  110.     query << "SELECT `account_id`, `name`, `deletion` FROM `players` WHERE `name` = " << db.escapeString(characterName);
  111.     result = db.storeQuery(query.str());
  112.     if (!result) {
  113.         return 0;
  114.     }
  115.  
  116.     if (result->getNumber<uint32_t>("account_id") != accountId || result->getNumber<uint64_t>("deletion") != 0) {
  117.         return 0;
  118.     }
  119.     characterName = result->getString("name");
  120.     return accountId;
  121. }
  122.  
  123. AccountType_t IOLoginData::getAccountType(uint32_t accountId)
  124. {
  125.     std::ostringstream query;
  126.     query << "SELECT `type` FROM `accounts` WHERE `id` = " << accountId;
  127.     DBResult_ptr result = Database::getInstance().storeQuery(query.str());
  128.     if (!result) {
  129.         return ACCOUNT_TYPE_NORMAL;
  130.     }
  131.     return static_cast<AccountType_t>(result->getNumber<uint16_t>("type"));
  132. }
  133.  
  134. void IOLoginData::setAccountType(uint32_t accountId, AccountType_t accountType)
  135. {
  136.     std::ostringstream query;
  137.     query << "UPDATE `accounts` SET `type` = " << static_cast<uint16_t>(accountType) << " WHERE `id` = " << accountId;
  138.     Database::getInstance().executeQuery(query.str());
  139. }
  140.  
  141. void IOLoginData::updateOnlineStatus(uint32_t guid, bool login)
  142. {
  143.     if (g_config.getBoolean(ConfigManager::ALLOW_CLONES)) {
  144.         return;
  145.     }
  146.  
  147.     std::ostringstream query;
  148.     if (login) {
  149.         query << "INSERT INTO `players_online` VALUES (" << guid << ')';
  150.     } else {
  151.         query << "DELETE FROM `players_online` WHERE `player_id` = " << guid;
  152.     }
  153.     Database::getInstance().executeQuery(query.str());
  154. }
  155.  
  156. bool IOLoginData::preloadPlayer(Player* player, const std::string& name)
  157. {
  158.     Database& db = Database::getInstance();
  159.  
  160.     std::ostringstream query;
  161.     query << "SELECT `id`, `account_id`, `group_id`, `deletion`, (SELECT `type` FROM `accounts` WHERE `accounts`.`id` = `account_id`) AS `account_type`";
  162.     if (!g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
  163.         query << ", (SELECT `premdays` FROM `accounts` WHERE `accounts`.`id` = `account_id`) AS `premium_days`";
  164.     }
  165.     query << " FROM `players` WHERE `name` = " << db.escapeString(name);
  166.     DBResult_ptr result = db.storeQuery(query.str());
  167.     if (!result) {
  168.         return false;
  169.     }
  170.  
  171.     if (result->getNumber<uint64_t>("deletion") != 0) {
  172.         return false;
  173.     }
  174.  
  175.     player->setGUID(result->getNumber<uint32_t>("id"));
  176.     Group* group = g_game.groups.getGroup(result->getNumber<uint16_t>("group_id"));
  177.     if (!group) {
  178.         std::cout << "[Error - IOLoginData::preloadPlayer] " << player->name << " has Group ID " << result->getNumber<uint16_t>("group_id") << " which doesn't exist." << std::endl;
  179.         return false;
  180.     }
  181.     player->setGroup(group);
  182.     player->accountNumber = result->getNumber<uint32_t>("account_id");
  183.     player->accountType = static_cast<AccountType_t>(result->getNumber<uint16_t>("account_type"));
  184.     if (!g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
  185.         player->premiumDays = result->getNumber<uint16_t>("premium_days");
  186.     } else {
  187.         player->premiumDays = std::numeric_limits<uint16_t>::max();
  188.     }
  189.     return true;
  190. }
  191.  
  192. bool IOLoginData::loadPlayerById(Player* player, uint32_t id)
  193. {
  194.     std::ostringstream query;
  195.     query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_melee`, `skill_melee_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_defending`, `skill_defending_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id;
  196.     return loadPlayer(player, Database::getInstance().storeQuery(query.str()));
  197. }
  198.  
  199. bool IOLoginData::loadPlayerByName(Player* player, const std::string& name)
  200. {
  201.     Database& db = Database::getInstance();
  202.     std::ostringstream query;
  203.     query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_melee`, `skill_melee_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_defending`, `skill_defending_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db.escapeString(name);
  204.     return loadPlayer(player, db.storeQuery(query.str()));
  205. }
  206.  
  207. bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
  208. {
  209.     if (!result) {
  210.         return false;
  211.     }
  212.  
  213.     Database& db = Database::getInstance();
  214.  
  215.     uint32_t accno = result->getNumber<uint32_t>("account_id");
  216.     Account acc = loadAccount(accno);
  217.  
  218.     player->setGUID(result->getNumber<uint32_t>("id"));
  219.     player->name = result->getString("name");
  220.     player->accountNumber = accno;
  221.  
  222.     player->accountType = acc.accountType;
  223.  
  224.     if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
  225.         player->premiumDays = std::numeric_limits<uint16_t>::max();
  226.     } else {
  227.         player->premiumDays = acc.premiumDays;
  228.     }
  229.  
  230.     Group* group = g_game.groups.getGroup(result->getNumber<uint16_t>("group_id"));
  231.     if (!group) {
  232.         std::cout << "[Error - IOLoginData::loadPlayer] " << player->name << " has Group ID " << result->getNumber<uint16_t>("group_id") << " which doesn't exist" << std::endl;
  233.         return false;
  234.     }
  235.     player->setGroup(group);
  236.  
  237.     player->bankBalance = result->getNumber<uint64_t>("balance");
  238.  
  239.     player->setSex(static_cast<PlayerSex_t>(result->getNumber<uint16_t>("sex")));
  240.     player->level = std::max<uint32_t>(1, result->getNumber<uint32_t>("level"));
  241.  
  242.     uint64_t experience = result->getNumber<uint64_t>("experience");
  243.  
  244.     uint64_t currExpCount = Player::getExpForLevel(player->level);
  245.     uint64_t nextExpCount = Player::getExpForLevel(player->level + 1);
  246.     if (experience < currExpCount || experience > nextExpCount) {
  247.         experience = currExpCount;
  248.     }
  249.  
  250.     player->experience = experience;
  251.  
  252.     if (currExpCount < nextExpCount) {
  253.         player->levelPercent = Player::getPercentLevel(player->experience - currExpCount, nextExpCount - currExpCount);
  254.     } else {
  255.         player->levelPercent = 0;
  256.     }
  257.  
  258.     player->soul = result->getNumber<uint16_t>("soul");
  259.     player->capacity = result->getNumber<uint32_t>("cap") * 100;
  260.     player->blessings = result->getNumber<uint16_t>("blessings");
  261.  
  262.     unsigned long conditionsSize;
  263.     const char* conditions = result->getStream("conditions", conditionsSize);
  264.     PropStream propStream;
  265.     propStream.init(conditions, conditionsSize);
  266.  
  267.     Condition* condition = Condition::createCondition(propStream);
  268.     while (condition) {
  269.         if (condition->unserialize(propStream)) {
  270.             player->storedConditionList.push_front(condition);
  271.         } else {
  272.             delete condition;
  273.         }
  274.         condition = Condition::createCondition(propStream);
  275.     }
  276.  
  277.     if (!player->setVocation(result->getNumber<uint16_t>("vocation"))) {
  278.         std::cout << "[Error - IOLoginData::loadPlayer] " << player->name << " has Vocation ID " << result->getNumber<uint16_t>("vocation") << " which doesn't exist" << std::endl;
  279.         return false;
  280.     }
  281.  
  282.     player->mana = result->getNumber<uint32_t>("mana");
  283.     player->manaMax = result->getNumber<uint32_t>("manamax");
  284.     player->magLevel = result->getNumber<uint32_t>("maglevel");
  285.  
  286.     uint64_t nextManaCount = player->vocation->getReqMana(player->magLevel + 1);
  287.     uint64_t manaSpent = result->getNumber<uint64_t>("manaspent");
  288.     if (manaSpent > nextManaCount) {
  289.         manaSpent = 0;
  290.     }
  291.  
  292.     player->manaSpent = manaSpent;
  293.     player->magLevelPercent = Player::getPercentLevel(player->manaSpent, nextManaCount);
  294.  
  295.     player->health = result->getNumber<int32_t>("health");
  296.     player->healthMax = result->getNumber<int32_t>("healthmax");
  297.  
  298.     player->defaultOutfit.lookType = result->getNumber<uint16_t>("looktype");
  299.     player->defaultOutfit.lookHead = result->getNumber<uint16_t>("lookhead");
  300.     player->defaultOutfit.lookBody = result->getNumber<uint16_t>("lookbody");
  301.     player->defaultOutfit.lookLegs = result->getNumber<uint16_t>("looklegs");
  302.     player->defaultOutfit.lookFeet = result->getNumber<uint16_t>("lookfeet");
  303.     player->defaultOutfit.lookAddons = result->getNumber<uint16_t>("lookaddons");
  304.     player->currentOutfit = player->defaultOutfit;
  305.  
  306.     if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) {
  307.         const time_t skullSeconds = result->getNumber<time_t>("skulltime") - time(nullptr);
  308.         if (skullSeconds > 0) {
  309.             //ensure that we round up the number of ticks
  310.             player->skullTicks = (skullSeconds + 2) * 1000;
  311.  
  312.             uint16_t skull = result->getNumber<uint16_t>("skull");
  313.             if (skull == SKULL_RED) {
  314.                 player->skull = SKULL_RED;
  315.             } else if (skull == SKULL_BLACK) {
  316.                 player->skull = SKULL_BLACK;
  317.             }
  318.         }
  319.     }
  320.  
  321.     player->loginPosition.x = result->getNumber<uint16_t>("posx");
  322.     player->loginPosition.y = result->getNumber<uint16_t>("posy");
  323.     player->loginPosition.z = result->getNumber<uint16_t>("posz");
  324.  
  325.     player->lastLoginSaved = result->getNumber<time_t>("lastlogin");
  326.     player->lastLogout = result->getNumber<time_t>("lastlogout");
  327.  
  328.     player->offlineTrainingTime = result->getNumber<int32_t>("offlinetraining_time") * 1000;
  329.     player->offlineTrainingSkill = result->getNumber<int32_t>("offlinetraining_skill");
  330.  
  331.     Town* town = g_game.map.towns.getTown(result->getNumber<uint32_t>("town_id"));
  332.     if (!town) {
  333.         std::cout << "[Error - IOLoginData::loadPlayer] " << player->name << " has Town ID " << result->getNumber<uint32_t>("town_id") << " which doesn't exist" << std::endl;
  334.         return false;
  335.     }
  336.  
  337.     player->town = town;
  338.  
  339.     const Position& loginPos = player->loginPosition;
  340.     if (loginPos.x == 0 && loginPos.y == 0 && loginPos.z == 0) {
  341.         player->loginPosition = player->getTemplePosition();
  342.     }
  343.  
  344.     player->staminaMinutes = result->getNumber<uint16_t>("stamina");
  345.  
  346.     static const std::string skillNames[] = {"skill_fist", "skill_club", "skill_melee", "skill_axe", "skill_dist", "skill_defending", "skill_fishing"};
  347.     static const std::string skillNameTries[] = {"skill_fist_tries", "skill_club_tries", "skill_melee_tries", "skill_axe_tries", "skill_dist_tries", "skill_defending_tries", "skill_fishing_tries"};
  348.     static constexpr size_t size = sizeof(skillNames) / sizeof(std::string);
  349.     for (uint8_t i = 0; i < size; ++i) {
  350.         uint16_t skillLevel = result->getNumber<uint16_t>(skillNames[i]);
  351.         uint64_t skillTries = result->getNumber<uint64_t>(skillNameTries[i]);
  352.         uint64_t nextSkillTries = player->vocation->getReqSkillTries(i, skillLevel + 1);
  353.         if (skillTries > nextSkillTries) {
  354.             skillTries = 0;
  355.         }
  356.  
  357.         player->skills[i].level = skillLevel;
  358.         player->skills[i].tries = skillTries;
  359.         player->skills[i].percent = Player::getPercentLevel(skillTries, nextSkillTries);
  360.     }
  361.  
  362.     std::ostringstream query;
  363.     query << "SELECT `guild_id`, `rank_id`, `nick` FROM `guild_membership` WHERE `player_id` = " << player->getGUID();
  364.     if ((result = db.storeQuery(query.str()))) {
  365.         uint32_t guildId = result->getNumber<uint32_t>("guild_id");
  366.         uint32_t playerRankId = result->getNumber<uint32_t>("rank_id");
  367.         player->guildNick = result->getString("nick");
  368.  
  369.         Guild* guild = g_game.getGuild(guildId);
  370.         if (!guild) {
  371.             query.str(std::string());
  372.             query << "SELECT `name` FROM `guilds` WHERE `id` = " << guildId;
  373.             if ((result = db.storeQuery(query.str()))) {
  374.                 guild = new Guild(guildId, result->getString("name"));
  375.                 g_game.addGuild(guild);
  376.  
  377.                 query.str(std::string());
  378.                 query << "SELECT `id`, `name`, `level` FROM `guild_ranks` WHERE `guild_id` = " << guildId;
  379.  
  380.                 if ((result = db.storeQuery(query.str()))) {
  381.                     do {
  382.                         guild->addRank(result->getNumber<uint32_t>("id"), result->getString("name"), result->getNumber<uint16_t>("level"));
  383.                     } while (result->next());
  384.                 }
  385.             }
  386.         }
  387.  
  388.         if (guild) {
  389.             player->guild = guild;
  390.             const GuildRank* rank = guild->getRankById(playerRankId);
  391.             if (!rank) {
  392.                 query.str(std::string());
  393.                 query << "SELECT `id`, `name`, `level` FROM `guild_ranks` WHERE `id` = " << playerRankId;
  394.  
  395.                 if ((result = db.storeQuery(query.str()))) {
  396.                     guild->addRank(result->getNumber<uint32_t>("id"), result->getString("name"), result->getNumber<uint16_t>("level"));
  397.                 }
  398.  
  399.                 rank = guild->getRankById(playerRankId);
  400.                 if (!rank) {
  401.                     player->guild = nullptr;
  402.                 }
  403.             }
  404.  
  405.             player->guildRank = rank;
  406.  
  407.             IOGuild::getWarList(guildId, player->guildWarVector);
  408.  
  409.             query.str(std::string());
  410.             query << "SELECT COUNT(*) AS `members` FROM `guild_membership` WHERE `guild_id` = " << guildId;
  411.             if ((result = db.storeQuery(query.str()))) {
  412.                 guild->setMemberCount(result->getNumber<uint32_t>("members"));
  413.             }
  414.         }
  415.     }
  416.  
  417.     query.str(std::string());
  418.     query << "SELECT `player_id`, `name` FROM `player_spells` WHERE `player_id` = " << player->getGUID();
  419.     if ((result = db.storeQuery(query.str()))) {
  420.         do {
  421.             player->learnedInstantSpellList.emplace_front(result->getString("name"));
  422.         } while (result->next());
  423.     }
  424.  
  425.     //load inventory items
  426.     ItemMap itemMap;
  427.  
  428.     query.str(std::string());
  429.     query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_items` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC";
  430.     if ((result = db.storeQuery(query.str()))) {
  431.         loadItems(itemMap, result);
  432.  
  433.         for (ItemMap::const_reverse_iterator it = itemMap.rbegin(), end = itemMap.rend(); it != end; ++it) {
  434.             const std::pair<Item*, int32_t>& pair = it->second;
  435.             Item* item = pair.first;
  436.             int32_t pid = pair.second;
  437.             if (pid >= 1 && pid <= 10) {
  438.                 player->internalAddThing(pid, item);
  439.             } else {
  440.                 ItemMap::const_iterator it2 = itemMap.find(pid);
  441.                 if (it2 == itemMap.end()) {
  442.                     continue;
  443.                 }
  444.  
  445.                 Container* container = it2->second.first->getContainer();
  446.                 if (container) {
  447.                     container->internalAddThing(item);
  448.                 }
  449.             }
  450.         }
  451.     }
  452.  
  453.     //load depot items
  454.     itemMap.clear();
  455.  
  456.     query.str(std::string());
  457.     query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_depotitems` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC";
  458.     if ((result = db.storeQuery(query.str()))) {
  459.         loadItems(itemMap, result);
  460.  
  461.         for (ItemMap::const_reverse_iterator it = itemMap.rbegin(), end = itemMap.rend(); it != end; ++it) {
  462.             const std::pair<Item*, int32_t>& pair = it->second;
  463.             Item* item = pair.first;
  464.  
  465.             int32_t pid = pair.second;
  466.             if (pid >= 0 && pid < 100) {
  467.                 DepotChest* depotChest = player->getDepotChest(pid, true);
  468.                 if (depotChest) {
  469.                     depotChest->internalAddThing(item);
  470.                 }
  471.             } else {
  472.                 ItemMap::const_iterator it2 = itemMap.find(pid);
  473.                 if (it2 == itemMap.end()) {
  474.                     continue;
  475.                 }
  476.  
  477.                 Container* container = it2->second.first->getContainer();
  478.                 if (container) {
  479.                     container->internalAddThing(item);
  480.                 }
  481.             }
  482.         }
  483.     }
  484.  
  485.     //load reward chest items
  486.     itemMap.clear();
  487.  
  488.     query.str(std::string());
  489.     query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_rewards` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC";
  490.     if ((result = db.storeQuery(query.str()))) {
  491.         loadItems(itemMap, result);
  492.  
  493.         //first loop handles the reward containers to retrieve its date attribute
  494.         //for (ItemMap::iterator it = itemMap.begin(), end = itemMap.end(); it != end; ++it) {
  495.         for (auto& it : itemMap) {
  496.             const std::pair<Item*, int32_t>& pair = it.second;
  497.             Item* item = pair.first;
  498.  
  499.             int32_t pid = pair.second;
  500.             if (pid >= 0 && pid < 100) {
  501.                 Reward* reward = player->getReward(item->getIntAttr(ITEM_ATTRIBUTE_DATE), true);
  502.                 if (reward) {
  503.                     it.second = std::pair<Item*, int32_t>(reward->getItem(), pid); //update the map with the special reward container
  504.                 }
  505.             } else {
  506.                 break;
  507.             }
  508.         }
  509.  
  510.         //second loop (this time a reverse one) to insert the items in the correct order
  511.         //for (ItemMap::const_reverse_iterator it = itemMap.rbegin(), end = itemMap.rend(); it != end; ++it) {
  512.         for (const auto& it : boost::adaptors::reverse(itemMap)) {
  513.             const std::pair<Item*, int32_t>& pair = it.second;
  514.             Item* item = pair.first;
  515.  
  516.             int32_t pid = pair.second;
  517.             if (pid >= 0 && pid < 100) {
  518.                 break;
  519.             }
  520.  
  521.             ItemMap::const_iterator it2 = itemMap.find(pid);
  522.             if (it2 == itemMap.end()) {
  523.                 continue;
  524.             }
  525.  
  526.             Container* container = it2->second.first->getContainer();
  527.             if (container) {
  528.                 container->internalAddThing(item);
  529.             }
  530.         }
  531.     }
  532.  
  533.     //load inbox items
  534.     itemMap.clear();
  535.  
  536.     query.str(std::string());
  537.     query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_inboxitems` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC LIMIT 5000";
  538.     if ((result = db.storeQuery(query.str()))) {
  539.         loadItems(itemMap, result);
  540.  
  541.         for (ItemMap::const_reverse_iterator it = itemMap.rbegin(), end = itemMap.rend(); it != end; ++it) {
  542.             const std::pair<Item*, int32_t>& pair = it->second;
  543.             Item* item = pair.first;
  544.             int32_t pid = pair.second;
  545.  
  546.             if (pid >= 0 && pid < 100) {
  547.                 player->getInbox()->internalAddThing(item);
  548.             } else {
  549.                 ItemMap::const_iterator it2 = itemMap.find(pid);
  550.  
  551.                 if (it2 == itemMap.end()) {
  552.                     continue;
  553.                 }
  554.  
  555.                 Container* container = it2->second.first->getContainer();
  556.                 if (container) {
  557.                     container->internalAddThing(item);
  558.                 }
  559.             }
  560.         }
  561.     }
  562.  
  563.     //load storage map
  564.     query.str(std::string());
  565.     query << "SELECT `key`, `value` FROM `player_storage` WHERE `player_id` = " << player->getGUID();
  566.     if ((result = db.storeQuery(query.str()))) {
  567.         do {
  568.             player->addStorageValue(result->getNumber<uint32_t>("key"), result->getNumber<int32_t>("value"), true);
  569.         } while (result->next());
  570.     }
  571.  
  572.     //load vip
  573.     query.str(std::string());
  574.     query << "SELECT `player_id` FROM `account_viplist` WHERE `account_id` = " << player->getAccount();
  575.     if ((result = db.storeQuery(query.str()))) {
  576.         do {
  577.             player->addVIPInternal(result->getNumber<uint32_t>("player_id"));
  578.         } while (result->next());
  579.     }
  580.  
  581.     player->updateBaseSpeed();
  582.     player->updateInventoryWeight();
  583.     player->updateItemsLight(true);
  584.     return true;
  585. }
  586.  
  587. bool IOLoginData::saveItems(const Player* player, const ItemBlockList& itemList, DBInsert& query_insert, PropWriteStream& propWriteStream)
  588. {
  589.     std::ostringstream ss;
  590.  
  591.     using ContainerBlock = std::pair<Container*, int32_t>;
  592.     std::list<ContainerBlock> queue;
  593.  
  594.     int32_t runningId = 100;
  595.  
  596.     Database& db = Database::getInstance();
  597.     for (const auto& it : itemList) {
  598.         int32_t pid = it.first;
  599.         Item* item = it.second;
  600.         ++runningId;
  601.  
  602.         propWriteStream.clear();
  603.         item->serializeAttr(propWriteStream);
  604.  
  605.         size_t attributesSize;
  606.         const char* attributes = propWriteStream.getStream(attributesSize);
  607.  
  608.         ss << player->getGUID() << ',' << pid << ',' << runningId << ',' << item->getID() << ',' << item->getSubType() << ',' << db.escapeBlob(attributes, attributesSize);
  609.         if (!query_insert.addRow(ss)) {
  610.             return false;
  611.         }
  612.  
  613.         if (Container* container = item->getContainer()) {
  614.             queue.emplace_back(container, runningId);
  615.         }
  616.     }
  617.  
  618.     while (!queue.empty()) {
  619.         const ContainerBlock& cb = queue.front();
  620.         Container* container = cb.first;
  621.         int32_t parentId = cb.second;
  622.         queue.pop_front();
  623.  
  624.         for (Item* item : container->getItemList()) {
  625.             ++runningId;
  626.  
  627.             Container* subContainer = item->getContainer();
  628.             if (subContainer) {
  629.                 queue.emplace_back(subContainer, runningId);
  630.             }
  631.  
  632.             propWriteStream.clear();
  633.             item->serializeAttr(propWriteStream);
  634.  
  635.             size_t attributesSize;
  636.             const char* attributes = propWriteStream.getStream(attributesSize);
  637.  
  638.             ss << player->getGUID() << ',' << parentId << ',' << runningId << ',' << item->getID() << ',' << item->getSubType() << ',' << db.escapeBlob(attributes, attributesSize);
  639.             if (!query_insert.addRow(ss)) {
  640.                 return false;
  641.             }
  642.         }
  643.     }
  644.     return query_insert.execute();
  645. }
  646.  
  647. bool IOLoginData::savePlayer(Player* player)
  648. {
  649.     if (player->getHealth() <= 0) {
  650.         player->changeHealth(1);
  651.     }
  652.  
  653.     Database& db = Database::getInstance();
  654.  
  655.     std::ostringstream query;
  656.     query << "SELECT `save` FROM `players` WHERE `id` = " << player->getGUID();
  657.     DBResult_ptr result = db.storeQuery(query.str());
  658.     if (!result) {
  659.         return false;
  660.     }
  661.  
  662.     if (result->getNumber<uint16_t>("save") == 0) {
  663.         query.str(std::string());
  664.         query << "UPDATE `players` SET `lastlogin` = " << player->lastLoginSaved << ", `lastip` = " << player->lastIP << " WHERE `id` = " << player->getGUID();
  665.         return db.executeQuery(query.str());
  666.     }
  667.  
  668.     //serialize conditions
  669.     PropWriteStream propWriteStream;
  670.     for (Condition* condition : player->conditions) {
  671.         if (condition->isPersistent()) {
  672.             condition->serialize(propWriteStream);
  673.             propWriteStream.write<uint8_t>(CONDITIONATTR_END);
  674.         }
  675.     }
  676.  
  677.     size_t conditionsSize;
  678.     const char* conditions = propWriteStream.getStream(conditionsSize);
  679.  
  680.     //First, an UPDATE query to write the player itself
  681.     query.str(std::string());
  682.     query << "UPDATE `players` SET ";
  683.     query << "`level` = " << player->level << ',';
  684.     query << "`group_id` = " << player->group->id << ',';
  685.     query << "`vocation` = " << player->getVocationId() << ',';
  686.     query << "`health` = " << player->health << ',';
  687.     query << "`healthmax` = " << player->healthMax << ',';
  688.     query << "`experience` = " << player->experience << ',';
  689.     query << "`lookbody` = " << static_cast<uint32_t>(player->defaultOutfit.lookBody) << ',';
  690.     query << "`lookfeet` = " << static_cast<uint32_t>(player->defaultOutfit.lookFeet) << ',';
  691.     query << "`lookhead` = " << static_cast<uint32_t>(player->defaultOutfit.lookHead) << ',';
  692.     query << "`looklegs` = " << static_cast<uint32_t>(player->defaultOutfit.lookLegs) << ',';
  693.     query << "`looktype` = " << player->defaultOutfit.lookType << ',';
  694.     query << "`lookaddons` = " << static_cast<uint32_t>(player->defaultOutfit.lookAddons) << ',';
  695.     query << "`maglevel` = " << player->magLevel << ',';
  696.     query << "`mana` = " << player->mana << ',';
  697.     query << "`manamax` = " << player->manaMax << ',';
  698.     query << "`manaspent` = " << player->manaSpent << ',';
  699.     query << "`soul` = " << static_cast<uint16_t>(player->soul) << ',';
  700.     query << "`town_id` = " << player->town->getID() << ',';
  701.  
  702.     const Position& loginPosition = player->getLoginPosition();
  703.     query << "`posx` = " << loginPosition.getX() << ',';
  704.     query << "`posy` = " << loginPosition.getY() << ',';
  705.     query << "`posz` = " << loginPosition.getZ() << ',';
  706.  
  707.     query << "`cap` = " << (player->capacity / 100) << ',';
  708.     query << "`sex` = " << player->sex << ',';
  709.  
  710.     if (player->lastLoginSaved != 0) {
  711.         query << "`lastlogin` = " << player->lastLoginSaved << ',';
  712.     }
  713.  
  714.     if (player->lastIP != 0) {
  715.         query << "`lastip` = " << player->lastIP << ',';
  716.     }
  717.  
  718.     query << "`conditions` = " << db.escapeBlob(conditions, conditionsSize) << ',';
  719.  
  720.     if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) {
  721.         int32_t skullTime = 0;
  722.  
  723.         if (player->skullTicks > 0) {
  724.             skullTime = time(nullptr) + player->skullTicks / 1000;
  725.         }
  726.  
  727.         query << "`skulltime` = " << skullTime << ',';
  728.  
  729.         Skulls_t skull = SKULL_NONE;
  730.         if (player->skull == SKULL_RED) {
  731.             skull = SKULL_RED;
  732.         } else if (player->skull == SKULL_BLACK) {
  733.             skull = SKULL_BLACK;
  734.         }
  735.         query << "`skull` = " << static_cast<uint32_t>(skull) << ',';
  736.     }
  737.  
  738.     query << "`lastlogout` = " << player->getLastLogout() << ',';
  739.     query << "`balance` = " << player->bankBalance << ',';
  740.     query << "`offlinetraining_time` = " << player->getOfflineTrainingTime() / 1000 << ',';
  741.     query << "`offlinetraining_skill` = " << player->getOfflineTrainingSkill() << ',';
  742.     query << "`stamina` = " << player->getStaminaMinutes() << ',';
  743.  
  744.     query << "`skill_fist` = " << player->skills[SKILL_FIST].level << ',';
  745.     query << "`skill_fist_tries` = " << player->skills[SKILL_FIST].tries << ',';
  746.     query << "`skill_club` = " << player->skills[SKILL_CLUB].level << ',';
  747.     query << "`skill_club_tries` = " << player->skills[SKILL_CLUB].tries << ',';
  748.     query << "`skill_melee` = " << player->skills[SKILL_MELEE].level << ',';
  749.     query << "`skill_melee_tries` = " << player->skills[SKILL_MELEE].tries << ',';
  750.     query << "`skill_axe` = " << player->skills[SKILL_AXE].level << ',';
  751.     query << "`skill_axe_tries` = " << player->skills[SKILL_AXE].tries << ',';
  752.     query << "`skill_dist` = " << player->skills[SKILL_DISTANCE].level << ',';
  753.     query << "`skill_dist_tries` = " << player->skills[SKILL_DISTANCE].tries << ',';
  754.     query << "`skill_defending` = " << player->skills[SKILL_DEFENDING].level << ',';
  755.     query << "`skill_defending_tries` = " << player->skills[SKILL_DEFENDING].tries << ',';
  756.     query << "`skill_fishing` = " << player->skills[SKILL_FISHING].level << ',';
  757.     query << "`skill_fishing_tries` = " << player->skills[SKILL_FISHING].tries << ',';
  758.  
  759.     if (!player->isOffline()) {
  760.         query << "`onlinetime` = `onlinetime` + " << (time(nullptr) - player->lastLoginSaved) << ',';
  761.     }
  762.     query << "`blessings` = " << static_cast<uint32_t>(player->blessings);
  763.     query << " WHERE `id` = " << player->getGUID();
  764.  
  765.     DBTransaction transaction;
  766.     if (!transaction.begin()) {
  767.         return false;
  768.     }
  769.  
  770.     if (!db.executeQuery(query.str())) {
  771.         return false;
  772.     }
  773.  
  774.     // learned spells
  775.     query.str(std::string());
  776.     query << "DELETE FROM `player_spells` WHERE `player_id` = " << player->getGUID();
  777.     if (!db.executeQuery(query.str())) {
  778.         return false;
  779.     }
  780.  
  781.     query.str(std::string());
  782.  
  783.     DBInsert spellsQuery("INSERT INTO `player_spells` (`player_id`, `name` ) VALUES ");
  784.     for (const std::string& spellName : player->learnedInstantSpellList) {
  785.         query << player->getGUID() << ',' << db.escapeString(spellName);
  786.         if (!spellsQuery.addRow(query)) {
  787.             return false;
  788.         }
  789.     }
  790.  
  791.     if (!spellsQuery.execute()) {
  792.         return false;
  793.     }
  794.  
  795.     //item saving
  796.     query << "DELETE FROM `player_items` WHERE `player_id` = " << player->getGUID();
  797.     if (!db.executeQuery(query.str())) {
  798.         return false;
  799.     }
  800.  
  801.     DBInsert itemsQuery("INSERT INTO `player_items` (`player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`) VALUES ");
  802.  
  803.     ItemBlockList itemList;
  804.     for (int32_t slotId = 1; slotId <= 12; ++slotId) {
  805.         Item* item = player->inventory[slotId];
  806.         if (item) {
  807.             itemList.emplace_back(slotId, item);
  808.         }
  809.     }
  810.  
  811.     if (!saveItems(player, itemList, itemsQuery, propWriteStream)) {
  812.         return false;
  813.     }
  814.  
  815.     if (player->lastDepotId != -1) {
  816.         //save depot items
  817.         query.str(std::string());
  818.         query << "DELETE FROM `player_depotitems` WHERE `player_id` = " << player->getGUID();
  819.  
  820.         if (!db.executeQuery(query.str())) {
  821.             return false;
  822.         }
  823.  
  824.         DBInsert depotQuery("INSERT INTO `player_depotitems` (`player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`) VALUES ");
  825.         itemList.clear();
  826.  
  827.         for (const auto& it : player->depotChests) {
  828.             DepotChest* depotChest = it.second;
  829.             for (Item* item : depotChest->getItemList()) {
  830.                 itemList.emplace_back(it.first, item);
  831.             }
  832.         }
  833.  
  834.         if (!saveItems(player, itemList, depotQuery, propWriteStream)) {
  835.             return false;
  836.         }
  837.     }
  838.  
  839.     //save reward items
  840.     query.str(std::string());
  841.     query << "DELETE FROM `player_rewards` WHERE `player_id` = " << player->getGUID();
  842.  
  843.     if (!db.executeQuery(query.str())) {
  844.         return false;
  845.     }
  846.  
  847.     std::vector<uint32_t> rewardList;
  848.     player->getRewardList(rewardList);
  849.  
  850.     if (!rewardList.empty()) {
  851.         DBInsert rewardQuery("INSERT INTO `player_rewards` (`player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`) VALUES ");
  852.         itemList.clear();
  853.    
  854.         int running = 0;
  855.         for (const auto& rewardId : rewardList) {
  856.             Reward* reward = player->getReward(rewardId, false);
  857.             // rewards that are empty or older than 7 days aren't stored
  858.             if (!reward->empty() && (time(nullptr) - rewardId <= 60 * 60 * 24 * 7)) {
  859.                 itemList.emplace_back(++running, reward);
  860.             }
  861.         }
  862.  
  863.         if (!saveItems(player, itemList, rewardQuery, propWriteStream)) {
  864.             return false;
  865.         }
  866.     }
  867.  
  868.     //save inbox items
  869.     query.str(std::string());
  870.     query << "DELETE FROM `player_inboxitems` WHERE `player_id` = " << player->getGUID();
  871.     if (!db.executeQuery(query.str())) {
  872.         return false;
  873.     }
  874.  
  875.     DBInsert inboxQuery("INSERT INTO `player_inboxitems` (`player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`) VALUES ");
  876.     itemList.clear();
  877.  
  878.     for (Item* item : player->getInbox()->getItemList()) {
  879.         itemList.emplace_back(0, item);
  880.     }
  881.  
  882.     if (!saveItems(player, itemList, inboxQuery, propWriteStream)) {
  883.         return false;
  884.     }
  885.  
  886.     query.str(std::string());
  887.     query << "DELETE FROM `player_storage` WHERE `player_id` = " << player->getGUID();
  888.     if (!db.executeQuery(query.str())) {
  889.         return false;
  890.     }
  891.  
  892.     query.str(std::string());
  893.  
  894.     DBInsert storageQuery("INSERT INTO `player_storage` (`player_id`, `key`, `value`) VALUES ");
  895.     player->genReservedStorageRange();
  896.  
  897.     for (const auto& it : player->storageMap) {
  898.         query << player->getGUID() << ',' << it.first << ',' << it.second;
  899.         if (!storageQuery.addRow(query)) {
  900.             return false;
  901.         }
  902.     }
  903.  
  904.     if (!storageQuery.execute()) {
  905.         return false;
  906.     }
  907.  
  908.     //End the transaction
  909.     return transaction.commit();
  910. }
  911.  
  912. std::string IOLoginData::getNameByGuid(uint32_t guid)
  913. {
  914.     std::ostringstream query;
  915.     query << "SELECT `name` FROM `players` WHERE `id` = " << guid;
  916.     DBResult_ptr result = Database::getInstance().storeQuery(query.str());
  917.     if (!result) {
  918.         return std::string();
  919.     }
  920.     return result->getString("name");
  921. }
  922.  
  923. uint32_t IOLoginData::getGuidByName(const std::string& name)
  924. {
  925.     Database& db = Database::getInstance();
  926.  
  927.     std::ostringstream query;
  928.     query << "SELECT `id` FROM `players` WHERE `name` = " << db.escapeString(name);
  929.     DBResult_ptr result = db.storeQuery(query.str());
  930.     if (!result) {
  931.         return 0;
  932.     }
  933.     return result->getNumber<uint32_t>("id");
  934. }
  935.  
  936. bool IOLoginData::getGuidByNameEx(uint32_t& guid, bool& specialVip, std::string& name)
  937. {
  938.     Database& db = Database::getInstance();
  939.  
  940.     std::ostringstream query;
  941.     query << "SELECT `name`, `id`, `group_id`, `account_id` FROM `players` WHERE `name` = " << db.escapeString(name);
  942.     DBResult_ptr result = db.storeQuery(query.str());
  943.     if (!result) {
  944.         return false;
  945.     }
  946.  
  947.     name = result->getString("name");
  948.     guid = result->getNumber<uint32_t>("id");
  949.     Group* group = g_game.groups.getGroup(result->getNumber<uint16_t>("group_id"));
  950.  
  951.     uint64_t flags;
  952.     if (group) {
  953.         flags = group->flags;
  954.     } else {
  955.         flags = 0;
  956.     }
  957.  
  958.     specialVip = (flags & PlayerFlag_SpecialVIP) != 0;
  959.     return true;
  960. }
  961.  
  962. bool IOLoginData::formatPlayerName(std::string& name)
  963. {
  964.     Database& db = Database::getInstance();
  965.  
  966.     std::ostringstream query;
  967.     query << "SELECT `name` FROM `players` WHERE `name` = " << db.escapeString(name);
  968.  
  969.     DBResult_ptr result = db.storeQuery(query.str());
  970.     if (!result) {
  971.         return false;
  972.     }
  973.  
  974.     name = result->getString("name");
  975.     return true;
  976. }
  977.  
  978. void IOLoginData::loadItems(ItemMap& itemMap, DBResult_ptr result)
  979. {
  980.     do {
  981.         uint32_t sid = result->getNumber<uint32_t>("sid");
  982.         uint32_t pid = result->getNumber<uint32_t>("pid");
  983.         uint16_t type = result->getNumber<uint16_t>("itemtype");
  984.         uint16_t count = result->getNumber<uint16_t>("count");
  985.  
  986.         unsigned long attrSize;
  987.         const char* attr = result->getStream("attributes", attrSize);
  988.  
  989.         PropStream propStream;
  990.         propStream.init(attr, attrSize);
  991.  
  992.         Item* item = Item::CreateItem(type, count);
  993.         if (item) {
  994.             if (!item->unserializeAttr(propStream)) {
  995.                 std::cout << "WARNING: Serialize error in IOLoginData::loadItems" << std::endl;
  996.             }
  997.  
  998.             std::pair<Item*, uint32_t> pair(item, pid);
  999.             itemMap[sid] = pair;
  1000.         }
  1001.     } while (result->next());
  1002. }
  1003.  
  1004. void IOLoginData::increaseBankBalance(uint32_t guid, uint64_t bankBalance)
  1005. {
  1006.     std::ostringstream query;
  1007.     query << "UPDATE `players` SET `balance` = `balance` + " << bankBalance << " WHERE `id` = " << guid;
  1008.     Database::getInstance().executeQuery(query.str());
  1009. }
  1010.  
  1011. bool IOLoginData::hasBiddedOnHouse(uint32_t guid)
  1012. {
  1013.     Database& db = Database::getInstance();
  1014.  
  1015.     std::ostringstream query;
  1016.     query << "SELECT `id` FROM `houses` WHERE `highest_bidder` = " << guid << " LIMIT 1";
  1017.     return db.storeQuery(query.str()).get() != nullptr;
  1018. }
  1019.  
  1020. std::forward_list<VIPEntry> IOLoginData::getVIPEntries(uint32_t accountId)
  1021. {
  1022.     std::forward_list<VIPEntry> entries;
  1023.  
  1024.     std::ostringstream query;
  1025.     query << "SELECT `player_id`, (SELECT `name` FROM `players` WHERE `id` = `player_id`) AS `name`, `description`, `icon`, `notify` FROM `account_viplist` WHERE `account_id` = " << accountId;
  1026.  
  1027.     DBResult_ptr result = Database::getInstance().storeQuery(query.str());
  1028.     if (result) {
  1029.         do {
  1030.             entries.emplace_front(
  1031.                 result->getNumber<uint32_t>("player_id"),
  1032.                 result->getString("name"),
  1033.                 result->getString("description"),
  1034.                 result->getNumber<uint32_t>("icon"),
  1035.                 result->getNumber<uint16_t>("notify") != 0
  1036.             );
  1037.         } while (result->next());
  1038.     }
  1039.     return entries;
  1040. }
  1041.  
  1042. void IOLoginData::addVIPEntry(uint32_t accountId, uint32_t guid, const std::string& description, uint32_t icon, bool notify)
  1043. {
  1044.     Database& db = Database::getInstance();
  1045.  
  1046.     std::ostringstream query;
  1047.     query << "INSERT INTO `account_viplist` (`account_id`, `player_id`, `description`, `icon`, `notify`) VALUES (" << accountId << ',' << guid << ',' << db.escapeString(description) << ',' << icon << ',' << notify << ')';
  1048.     db.executeQuery(query.str());
  1049. }
  1050.  
  1051. void IOLoginData::editVIPEntry(uint32_t accountId, uint32_t guid, const std::string& description, uint32_t icon, bool notify)
  1052. {
  1053.     Database& db = Database::getInstance();
  1054.  
  1055.     std::ostringstream query;
  1056.     query << "UPDATE `account_viplist` SET `description` = " << db.escapeString(description) << ", `icon` = " << icon << ", `notify` = " << notify << " WHERE `account_id` = " << accountId << " AND `player_id` = " << guid;
  1057.     db.executeQuery(query.str());
  1058. }
  1059.  
  1060. void IOLoginData::removeVIPEntry(uint32_t accountId, uint32_t guid)
  1061. {
  1062.     std::ostringstream query;
  1063.     query << "DELETE FROM `account_viplist` WHERE `account_id` = " << accountId << " AND `player_id` = " << guid;
  1064.     Database::getInstance().executeQuery(query.str());
  1065. }
  1066.  
  1067. void IOLoginData::addPremiumDays(uint32_t accountId, int32_t addDays)
  1068. {
  1069.     std::ostringstream query;
  1070.     query << "UPDATE `accounts` SET `premdays` = `premdays` + " << addDays << " WHERE `id` = " << accountId;
  1071.     Database::getInstance().executeQuery(query.str());
  1072. }
  1073.  
  1074. void IOLoginData::removePremiumDays(uint32_t accountId, int32_t removeDays)
  1075. {
  1076.     std::ostringstream query;
  1077.     query << "UPDATE `accounts` SET `premdays` = `premdays` - " << removeDays << " WHERE `id` = " << accountId;
  1078.     Database::getInstance().executeQuery(query.str());
  1079. }
Advertisement
Add Comment
Please, Sign In to add comment