diff --git a/config.lua b/config.lua
index 5a68061..72de76c 100644
--- a/config.lua
+++ b/config.lua
@@ -1,6 +1,6 @@
-- Custom
-knightCloseAttackDamageIncreasePercent = 50
-paladinRangeAttackDamageIncreasePercent = 40
+knightCloseAttackDamageIncreasePercent = 20
+paladinRangeAttackDamageIncreasePercent = 15
-- Combat settings
-- NOTE: valid values for worldType are: "pvp", "no-pvp" and "pvp-enforced"
diff --git a/data/actions/actions.xml b/data/actions/actions.xml
index c2ee247..e05c8ad 100644
--- a/data/actions/actions.xml
+++ b/data/actions/actions.xml
@@ -239,6 +239,7 @@
+
diff --git a/data/actions/scripts/misc/skill_trainer.lua b/data/actions/scripts/misc/skill_trainer.lua
new file mode 100644
index 0000000..a35d2c6
--- /dev/null
+++ b/data/actions/scripts/misc/skill_trainer.lua
@@ -0,0 +1,23 @@
+local statues = {
+ [2032] = SKILL_SWORD,
+ [18489] = SKILL_AXE,
+ [18490] = SKILL_CLUB,
+ [18491] = SKILL_DISTANCE,
+ [18492] = SKILL_MAGLEVEL
+}
+
+function onUse(player, item, fromPosition, target, toPosition, isHotkey)
+ local skill = statues[item:getId()]
+ if not player:isPremium() then
+ player:sendCancelMessage(RETURNVALUE_YOUNEEDPREMIUMACCOUNT)
+ return true
+ end
+
+ if player:isPzLocked() then
+ return false
+ end
+
+ player:setOfflineTrainingSkill(skill)
+ player:remove()
+ return true
+end
diff --git a/data/creaturescripts/creaturescripts.xml b/data/creaturescripts/creaturescripts.xml
index bf0570a..c2dc909 100644
--- a/data/creaturescripts/creaturescripts.xml
+++ b/data/creaturescripts/creaturescripts.xml
@@ -6,7 +6,8 @@
-
+
+
diff --git a/data/creaturescripts/scripts/offlinetraining.lua b/data/creaturescripts/scripts/offlinetraining.lua
new file mode 100644
index 0000000..325f6dd
--- /dev/null
+++ b/data/creaturescripts/scripts/offlinetraining.lua
@@ -0,0 +1,75 @@
+function onLogin(player)
+ local lastLogout = player:getLastLogout()
+ local offlineTime = lastLogout ~= 0 and math.min(os.time() - lastLogout, 86400 * 21) or 0
+ local offlineTrainingSkill = player:getOfflineTrainingSkill()
+ if offlineTrainingSkill == -1 then
+ player:addOfflineTrainingTime(offlineTime * 1000)
+ return true
+ end
+
+ player:setOfflineTrainingSkill(-1)
+
+ if offlineTime < 600 then
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You must be logged out for more than 10 minutes to start offline training.")
+ return true
+ end
+
+ local trainingTime = math.max(0, math.min(offlineTime, math.min(43200, player:getOfflineTrainingTime() / 1000)))
+ player:removeOfflineTrainingTime(trainingTime * 1000)
+
+ local remainder = offlineTime - trainingTime
+ if remainder > 0 then
+ player:addOfflineTrainingTime(remainder * 1000)
+ end
+
+ if trainingTime < 60 then
+ return true
+ end
+
+ local text = "During your absence you trained for"
+ local hours = math.floor(trainingTime / 3600)
+ if hours > 1 then
+ text = string.format("%s %d hours", text, hours)
+ elseif hours == 1 then
+ text = string.format("%s 1 hour", text)
+ end
+
+ local minutes = math.floor((trainingTime % 3600) / 60)
+ if minutes ~= 0 then
+ if hours ~= 0 then
+ text = string.format("%s and", text)
+ end
+
+ if minutes > 1 then
+ text = string.format("%s %d minutes", text, minutes)
+ else
+ text = string.format("%s 1 minute", text)
+ end
+ end
+
+ text = string.format("%s.", text)
+ player:sendTextMessage(MESSAGE_EVENT_ADVANCE, text)
+
+ local vocation = player:getVocation()
+ local promotion = vocation:getPromotion()
+ local topVocation = not promotion and vocation or promotion
+
+ local updateSkills = false
+ if table.contains({SKILL_CLUB, SKILL_SWORD, SKILL_AXE, SKILL_DISTANCE}, offlineTrainingSkill) then
+ local modifier = topVocation:getAttackSpeed() / 1000
+ updateSkills = player:addOfflineTrainingTries(offlineTrainingSkill, (trainingTime / modifier) / (offlineTrainingSkill == SKILL_DISTANCE and 4 or 2))
+ elseif offlineTrainingSkill == SKILL_MAGLEVEL then
+ local gainTicks = topVocation:getManaGainTicks() * 2
+ if gainTicks == 0 then
+ gainTicks = 1
+ end
+
+ updateSkills = player:addOfflineTrainingTries(SKILL_MAGLEVEL, trainingTime * (vocation:getManaGainAmount() / gainTicks))
+ end
+
+ if updateSkills then
+ player:addOfflineTrainingTries(SKILL_SHIELD, trainingTime / 4)
+ end
+
+ return true
+end
diff --git a/data/lib/compat/compat.lua b/data/lib/compat/compat.lua
index aed2428..789451e 100644
--- a/data/lib/compat/compat.lua
+++ b/data/lib/compat/compat.lua
@@ -372,6 +372,7 @@ function setPlayerGroupId(cid, groupId) local p = Player(cid) return p ~= nil an
function doPlayerSetSex(cid, sex) local p = Player(cid) return p ~= nil and p:setSex(sex) or false end
function doPlayerSetGuildLevel(cid, level) local p = Player(cid) return p ~= nil and p:setGuildLevel(level) or false end
function doPlayerSetGuildNick(cid, nick) local p = Player(cid) return p ~= nil and p:setGuildNick(nick) or false end
+function doPlayerSetOfflineTrainingSkill(cid, skillId) local p = Player(cid) return p and p:setOfflineTrainingSkill(skillId) or false end
function doShowTextDialog(cid, itemId, text) local p = Player(cid) return p ~= nil and p:showTextDialog(itemId, text) or false end
function doPlayerAddItemEx(cid, uid, ...) local p = Player(cid) return p ~= nil and p:addItemEx(Item(uid), ...) or false end
function doPlayerRemoveItem(cid, itemid, count, ...) local p = Player(cid) return p ~= nil and p:removeItem(itemid, count, ...) or false end
diff --git a/sabrehaven.sql b/sabrehaven.sql
index 6dd3015..e0a2b8b 100644
--- a/sabrehaven.sql
+++ b/sabrehaven.sql
@@ -1138,6 +1138,8 @@ CREATE TABLE `players` (
`onlinetime` int(11) NOT NULL DEFAULT '0',
`deletion` bigint(15) NOT NULL DEFAULT '0',
`balance` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
+ `offlinetraining_time` smallint(5) unsigned NOT NULL DEFAULT '43200',
+ `offlinetraining_skill` int(11) NOT NULL DEFAULT '-1',
`stamina` smallint(5) NOT NULL DEFAULT '3360',
`skill_fist` int(10) UNSIGNED NOT NULL DEFAULT '10',
`skill_fist_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
diff --git a/src/iologindata.cpp b/src/iologindata.cpp
index 8501bd8..ebe3a04 100644
--- a/src/iologindata.cpp
+++ b/src/iologindata.cpp
@@ -190,7 +190,7 @@ bool IOLoginData::preloadPlayer(Player* player, const std::string& name)
bool IOLoginData::loadPlayerById(Player* player, uint32_t id)
{
std::ostringstream query;
- 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`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id;
+ 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_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id;
return loadPlayer(player, Database::getInstance()->storeQuery(query.str()));
}
@@ -198,7 +198,7 @@ bool IOLoginData::loadPlayerByName(Player* player, const std::string& name)
{
Database* db = Database::getInstance();
std::ostringstream query;
- 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`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name);
+ 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_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name);
return loadPlayer(player, db->storeQuery(query.str()));
}
@@ -321,6 +321,9 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
player->lastLoginSaved = result->getNumber("lastlogin");
player->lastLogout = result->getNumber("lastlogout");
+ player->offlineTrainingTime = result->getNumber("offlinetraining_time") * 1000;
+ player->offlineTrainingSkill = result->getNumber("offlinetraining_skill");
+
Town* town = g_game.map.towns.getTown(result->getNumber("town_id"));
if (!town) {
std::cout << "[Error - IOLoginData::loadPlayer] " << player->name << " has Town ID " << result->getNumber("town_id") << " which doesn't exist" << std::endl;
@@ -660,6 +663,8 @@ bool IOLoginData::savePlayer(Player* player)
query << "`lastlogout` = " << player->getLastLogout() << ',';
query << "`balance` = " << player->bankBalance << ',';
+ query << "`offlinetraining_time` = " << player->getOfflineTrainingTime() / 1000 << ',';
+ query << "`offlinetraining_skill` = " << player->getOfflineTrainingSkill() << ',';
query << "`stamina` = " << player->getStaminaMinutes() << ',';
query << "`skill_fist` = " << player->skills[SKILL_FIST].level << ',';
diff --git a/src/luascript.cpp b/src/luascript.cpp
index 51015e0..b207b86 100644
--- a/src/luascript.cpp
+++ b/src/luascript.cpp
@@ -2008,6 +2008,15 @@ void LuaScriptInterface::registerFunctions()
registerMethod("Player", "getSkillTries", LuaScriptInterface::luaPlayerGetSkillTries);
registerMethod("Player", "addSkillTries", LuaScriptInterface::luaPlayerAddSkillTries);
+ registerMethod("Player", "addOfflineTrainingTime", LuaScriptInterface::luaPlayerAddOfflineTrainingTime);
+ registerMethod("Player", "getOfflineTrainingTime", LuaScriptInterface::luaPlayerGetOfflineTrainingTime);
+ registerMethod("Player", "removeOfflineTrainingTime", LuaScriptInterface::luaPlayerRemoveOfflineTrainingTime);
+
+ registerMethod("Player", "addOfflineTrainingTries", LuaScriptInterface::luaPlayerAddOfflineTrainingTries);
+
+ registerMethod("Player", "getOfflineTrainingSkill", LuaScriptInterface::luaPlayerGetOfflineTrainingSkill);
+ registerMethod("Player", "setOfflineTrainingSkill", LuaScriptInterface::luaPlayerSetOfflineTrainingSkill);
+
registerMethod("Player", "getItemCount", LuaScriptInterface::luaPlayerGetItemCount);
registerMethod("Player", "getItemById", LuaScriptInterface::luaPlayerGetItemById);
@@ -7530,6 +7539,95 @@ int LuaScriptInterface::luaPlayerAddSkillTries(lua_State* L)
return 1;
}
+int LuaScriptInterface::luaPlayerAddOfflineTrainingTime(lua_State* L)
+{
+ // player:addOfflineTrainingTime(time)
+ Player* player = getUserdata(L, 1);
+ if (player) {
+ int32_t time = getNumber(L, 2);
+ player->addOfflineTrainingTime(time);
+ player->sendStats();
+ pushBoolean(L, true);
+ }
+ else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+
+int LuaScriptInterface::luaPlayerGetOfflineTrainingTime(lua_State* L)
+{
+ // player:getOfflineTrainingTime()
+ Player* player = getUserdata(L, 1);
+ if (player) {
+ lua_pushnumber(L, player->getOfflineTrainingTime());
+ }
+ else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+int LuaScriptInterface::luaPlayerRemoveOfflineTrainingTime(lua_State* L)
+{
+ // player:removeOfflineTrainingTime(time)
+ Player* player = getUserdata(L, 1);
+ if (player) {
+ int32_t time = getNumber(L, 2);
+ player->removeOfflineTrainingTime(time);
+ player->sendStats();
+ pushBoolean(L, true);
+ }
+ else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+int LuaScriptInterface::luaPlayerAddOfflineTrainingTries(lua_State* L)
+{
+ // player:addOfflineTrainingTries(skillType, tries)
+ Player* player = getUserdata(L, 1);
+ if (player) {
+ skills_t skillType = getNumber(L, 2);
+ uint64_t tries = getNumber(L, 3);
+ pushBoolean(L, player->addOfflineTrainingTries(skillType, tries));
+ }
+ else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+int LuaScriptInterface::luaPlayerGetOfflineTrainingSkill(lua_State* L)
+{
+ // player:getOfflineTrainingSkill()
+ Player* player = getUserdata(L, 1);
+ if (player) {
+ lua_pushnumber(L, player->getOfflineTrainingSkill());
+ }
+ else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+int LuaScriptInterface::luaPlayerSetOfflineTrainingSkill(lua_State* L)
+{
+ // player:setOfflineTrainingSkill(skillId)
+ Player* player = getUserdata(L, 1);
+ if (player) {
+ uint32_t skillId = getNumber(L, 2);
+ player->setOfflineTrainingSkill(skillId);
+ pushBoolean(L, true);
+ }
+ else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
int LuaScriptInterface::luaPlayerGetItemCount(lua_State* L)
{
// player:getItemCount(itemId[, subType = -1])
diff --git a/src/luascript.h b/src/luascript.h
index 3c8467f..7f9508e 100644
--- a/src/luascript.h
+++ b/src/luascript.h
@@ -833,6 +833,15 @@ class LuaScriptInterface
static int luaPlayerGetSkillTries(lua_State* L);
static int luaPlayerAddSkillTries(lua_State* L);
+ static int luaPlayerAddOfflineTrainingTime(lua_State* L);
+ static int luaPlayerGetOfflineTrainingTime(lua_State* L);
+ static int luaPlayerRemoveOfflineTrainingTime(lua_State* L);
+
+ static int luaPlayerAddOfflineTrainingTries(lua_State* L);
+
+ static int luaPlayerGetOfflineTrainingSkill(lua_State* L);
+ static int luaPlayerSetOfflineTrainingSkill(lua_State* L);
+
static int luaPlayerGetItemCount(lua_State* L);
static int luaPlayerGetItemById(lua_State* L);
diff --git a/src/player.cpp b/src/player.cpp
index 96ac98b..597da0e 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -1194,6 +1194,8 @@ void Player::onThink(uint32_t interval)
if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) {
checkSkullTicks();
}
+
+ addOfflineTrainingTime(interval);
}
uint32_t Player::isMuted() const
@@ -3737,6 +3739,141 @@ void Player::sendClosePrivate(uint16_t channelId)
}
}
+bool Player::addOfflineTrainingTries(skills_t skill, uint64_t tries)
+{
+ if (tries == 0 || skill == SKILL_LEVEL) {
+ return false;
+ }
+
+ bool sendUpdate = false;
+ uint32_t oldSkillValue, newSkillValue;
+ long double oldPercentToNextLevel, newPercentToNextLevel;
+
+ if (skill == SKILL_MAGLEVEL) {
+ uint64_t currReqMana = vocation->getReqMana(magLevel);
+ uint64_t nextReqMana = vocation->getReqMana(magLevel + 1);
+
+ if (currReqMana >= nextReqMana) {
+ return false;
+ }
+
+ oldSkillValue = magLevel;
+ oldPercentToNextLevel = static_cast(manaSpent * 100) / nextReqMana;
+
+ g_events->eventPlayerOnGainSkillTries(this, SKILL_MAGLEVEL, tries);
+ uint32_t currMagLevel = magLevel;
+
+ while ((manaSpent + tries) >= nextReqMana) {
+ tries -= nextReqMana - manaSpent;
+
+ magLevel++;
+ manaSpent = 0;
+
+ g_creatureEvents->playerAdvance(this, SKILL_MAGLEVEL, magLevel - 1, magLevel);
+
+ sendUpdate = true;
+ currReqMana = nextReqMana;
+ nextReqMana = vocation->getReqMana(magLevel + 1);
+
+ if (currReqMana >= nextReqMana) {
+ tries = 0;
+ break;
+ }
+ }
+
+ manaSpent += tries;
+
+ if (magLevel != currMagLevel) {
+ std::ostringstream ss;
+ ss << "You advanced to magic level " << magLevel << '.';
+ sendTextMessage(MESSAGE_EVENT_ADVANCE, ss.str());
+ }
+
+ uint8_t newPercent;
+ if (nextReqMana > currReqMana) {
+ newPercent = Player::getPercentLevel(manaSpent, nextReqMana);
+ newPercentToNextLevel = static_cast(manaSpent * 100) / nextReqMana;
+ }
+ else {
+ newPercent = 0;
+ newPercentToNextLevel = 0;
+ }
+
+ if (newPercent != magLevelPercent) {
+ magLevelPercent = newPercent;
+ sendUpdate = true;
+ }
+
+ newSkillValue = magLevel;
+ }
+ else {
+ uint64_t currReqTries = vocation->getReqSkillTries(skill, skills[skill].level);
+ uint64_t nextReqTries = vocation->getReqSkillTries(skill, skills[skill].level + 1);
+ if (currReqTries >= nextReqTries) {
+ return false;
+ }
+
+ oldSkillValue = skills[skill].level;
+ oldPercentToNextLevel = static_cast(skills[skill].tries * 100) / nextReqTries;
+
+ g_events->eventPlayerOnGainSkillTries(this, skill, tries);
+ uint32_t currSkillLevel = skills[skill].level;
+
+ while ((skills[skill].tries + tries) >= nextReqTries) {
+ tries -= nextReqTries - skills[skill].tries;
+
+ skills[skill].level++;
+ skills[skill].tries = 0;
+ skills[skill].percent = 0;
+
+ g_creatureEvents->playerAdvance(this, skill, (skills[skill].level - 1), skills[skill].level);
+
+ sendUpdate = true;
+ currReqTries = nextReqTries;
+ nextReqTries = vocation->getReqSkillTries(skill, skills[skill].level + 1);
+
+ if (currReqTries >= nextReqTries) {
+ tries = 0;
+ break;
+ }
+ }
+
+ skills[skill].tries += tries;
+
+ if (currSkillLevel != skills[skill].level) {
+ std::ostringstream ss;
+ ss << "You advanced to " << getSkillName(skill) << " level " << skills[skill].level << '.';
+ sendTextMessage(MESSAGE_EVENT_ADVANCE, ss.str());
+ }
+
+ uint8_t newPercent;
+ if (nextReqTries > currReqTries) {
+ newPercent = Player::getPercentLevel(skills[skill].tries, nextReqTries);
+ newPercentToNextLevel = static_cast(skills[skill].tries * 100) / nextReqTries;
+ }
+ else {
+ newPercent = 0;
+ newPercentToNextLevel = 0;
+ }
+
+ if (skills[skill].percent != newPercent) {
+ skills[skill].percent = newPercent;
+ sendUpdate = true;
+ }
+
+ newSkillValue = skills[skill].level;
+ }
+
+ if (sendUpdate) {
+ sendSkills();
+ }
+
+ std::ostringstream ss;
+ ss << std::fixed << std::setprecision(2) << "Your " << ucwords(getSkillName(skill)) << " skill changed from level " << oldSkillValue << " (with " << oldPercentToNextLevel << "% progress towards level " << (oldSkillValue + 1) << ") to level " << newSkillValue << " (with " << newPercentToNextLevel << "% progress towards level " << (newSkillValue + 1) << ')';
+ sendTextMessage(MESSAGE_EVENT_ADVANCE, ss.str());
+ return sendUpdate;
+}
+
uint64_t Player::getMoney() const
{
std::vector containers;
diff --git a/src/player.h b/src/player.h
index 15703a4..eb55b22 100644
--- a/src/player.h
+++ b/src/player.h
@@ -154,6 +154,25 @@ class Player final : public Creature, public Cylinder
return staminaMinutes;
}
+ bool addOfflineTrainingTries(skills_t skill, uint64_t tries);
+
+ void addOfflineTrainingTime(int32_t addTime) {
+ offlineTrainingTime = std::min(12 * 3600 * 1000, offlineTrainingTime + addTime);
+ }
+ void removeOfflineTrainingTime(int32_t removeTime) {
+ offlineTrainingTime = std::max(0, offlineTrainingTime - removeTime);
+ }
+ int32_t getOfflineTrainingTime() const {
+ return offlineTrainingTime;
+ }
+
+ int32_t getOfflineTrainingSkill() const {
+ return offlineTrainingSkill;
+ }
+ void setOfflineTrainingSkill(int32_t skill) {
+ offlineTrainingSkill = skill;
+ }
+
uint64_t getBankBalance() const {
return bankBalance;
}
@@ -1069,6 +1088,8 @@ class Player final : public Creature, public Cylinder
int32_t premiumDays = 0;
int32_t bloodHitCount = 0;
int32_t shieldBlockCount = 0;
+ int32_t offlineTrainingSkill = -1;
+ int32_t offlineTrainingTime = 0;
int32_t idleTime = 0;
int32_t lastWalkingTime = 0;