diff --git a/data/actions/scripts/other/skilltrainer.lua b/data/actions/scripts/other/skilltrainer.lua
index 7f7a76c8e2..8ff872bca2 100644
--- a/data/actions/scripts/other/skilltrainer.lua
+++ b/data/actions/scripts/other/skilltrainer.lua
@@ -8,7 +8,7 @@ local statues = {
function onUse(player, item, fromPosition, target, toPosition, isHotkey)
local skill = statues[item:getId()]
- if player:getPremiumDays() == 0 then
+ if not player:isPremium() then
player:sendTextMessage(MESSAGE_STATUS_SMALL, Game.getReturnMessage(RETURNVALUE_YOUNEEDPREMIUMACCOUNT))
return true
end
@@ -17,7 +17,7 @@ function onUse(player, item, fromPosition, target, toPosition, isHotkey)
return false
end
- doPlayerSetOfflineTrainingSkill(player, skill)
+ player:setOfflineTrainingSkill(skill)
player:remove()
return true
end
diff --git a/data/creaturescripts/creaturescripts.xml b/data/creaturescripts/creaturescripts.xml
index a5e7fd0f54..86e2c8c3a7 100644
--- a/data/creaturescripts/creaturescripts.xml
+++ b/data/creaturescripts/creaturescripts.xml
@@ -3,6 +3,7 @@
+
diff --git a/data/creaturescripts/scripts/offlinetraining.lua b/data/creaturescripts/scripts/offlinetraining.lua
new file mode 100644
index 0000000000..98e37aeaec
--- /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 isInArray({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 fb6e998cee..b97eded218 100644
--- a/data/lib/compat/compat.lua
+++ b/data/lib/compat/compat.lua
@@ -374,6 +374,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 ~= nil 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/src/luascript.cpp b/src/luascript.cpp
index b856a3f283..e376ec95d9 100644
--- a/src/luascript.cpp
+++ b/src/luascript.cpp
@@ -1012,9 +1012,6 @@ void LuaScriptInterface::registerFunctions()
//isInWar(cid, target)
lua_register(m_luaState, "isInWar", LuaScriptInterface::luaIsInWar);
- //doPlayerSetOfflineTrainingSkill(cid, skill)
- lua_register(m_luaState, "doPlayerSetOfflineTrainingSkill", LuaScriptInterface::luaDoPlayerSetOfflineTrainingSkill);
-
//getWaypointPosition(name)
lua_register(m_luaState, "getWaypointPositionByName", LuaScriptInterface::luaGetWaypointPositionByName);
@@ -2136,6 +2133,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);
@@ -3707,21 +3713,6 @@ int LuaScriptInterface::luaIsInWar(lua_State* L)
return 1;
}
-int LuaScriptInterface::luaDoPlayerSetOfflineTrainingSkill(lua_State* L)
-{
- //doPlayerSetOfflineTrainingSkill(cid, skillid)
- Player* player = getPlayer(L, 1);
- if (player) {
- uint32_t skillid = getNumber(L, 2);
- player->setOfflineTrainingSkill(skillid);
- pushBoolean(L, true);
- } else {
- reportErrorFunc(getErrorDesc(LUA_ERROR_PLAYER_NOT_FOUND));
- pushBoolean(L, false);
- }
- return 1;
-}
-
int LuaScriptInterface::luaGetWaypointPositionByName(lua_State* L)
{
//getWaypointPositionByName(name)
@@ -7880,6 +7871,89 @@ 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 3a8aad2902..3f50e639b2 100644
--- a/src/luascript.h
+++ b/src/luascript.h
@@ -491,7 +491,6 @@ class LuaScriptInterface
static int luaCleanMap(lua_State* L);
static int luaIsInWar(lua_State* L);
- static int luaDoPlayerSetOfflineTrainingSkill(lua_State* L);
static int luaGetWaypointPositionByName(lua_State* L);
@@ -864,6 +863,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 4c8c6304d9..e1a05f8623 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -1177,99 +1177,6 @@ void Player::onCreatureAppear(Creature* creature, bool isLogin)
}
}
- bool sentStats = false;
-
- int16_t oldStaminaMinutes = getStaminaMinutes();
-
- if (offlineTrainingSkill != -1) {
- if (offlineTime >= 600) {
- uint32_t trainingTime = std::max(0, std::min(offlineTime, std::min(43200, offlineTrainingTime / 1000)));
-
- removeOfflineTrainingTime(trainingTime * 1000);
-
- int32_t remainder = offlineTime - trainingTime;
- if (remainder > 0) {
- addOfflineTrainingTime(remainder * 1000);
- }
-
- if (trainingTime >= 60) {
- std::ostringstream ss;
- ss << "During your absence you trained for ";
- int32_t hours = trainingTime / 3600;
- if (hours > 1) {
- ss << hours << " hours";
- } else if (hours == 1) {
- ss << "1 hour";
- }
-
- int32_t minutes = (trainingTime % 3600) / 60;
- if (minutes != 0) {
- if (hours != 0) {
- ss << " and ";
- }
-
- if (minutes > 1) {
- ss << minutes << " minutes";
- } else {
- ss << "1 minute";
- }
- }
-
- ss << '.';
- sendTextMessage(MESSAGE_EVENT_ADVANCE, ss.str());
-
- Vocation* topVocation;
- if (isPromoted()) {
- topVocation = getVocation();
- } else {
- int32_t promotedVocationId = g_vocations.getPromotedVocation(getVocationId());
- topVocation = g_vocations.getVocation(promotedVocationId);
- if (!topVocation) {
- topVocation = getVocation();
- }
- }
-
- bool sendUpdateSkills = false;
- if (offlineTrainingSkill == SKILL_CLUB || offlineTrainingSkill == SKILL_SWORD || offlineTrainingSkill == SKILL_AXE) {
- float modifier = topVocation->getAttackSpeed() / 1000.f;
- sendUpdateSkills = addOfflineTrainingTries(static_cast(offlineTrainingSkill), (trainingTime / modifier) / 2);
- } else if (offlineTrainingSkill == SKILL_DISTANCE) {
- float modifier = topVocation->getAttackSpeed() / 1000.f;
- sendUpdateSkills = addOfflineTrainingTries(static_cast(offlineTrainingSkill), (trainingTime / modifier) / 4);
- } else if (offlineTrainingSkill == SKILL_MAGLEVEL) {
- int32_t gainTicks = topVocation->getManaGainTicks() * 2;
- if (gainTicks == 0) {
- gainTicks = 1;
- }
-
- addOfflineTrainingTries(SKILL_MAGLEVEL, trainingTime * (static_cast(vocation->getManaGainAmount()) / gainTicks));
- }
-
- if (addOfflineTrainingTries(SKILL_SHIELD, trainingTime / 4) || sendUpdateSkills) {
- sendSkills();
- }
- }
-
- sendStats();
- sentStats = true;
- } else {
- sendTextMessage(MESSAGE_EVENT_ADVANCE, "You must be logged out for more than 10 minutes to start offline training.");
- }
- setOfflineTrainingSkill(-1);
- } else {
- uint16_t oldMinutes = getOfflineTrainingTime() / 60 / 1000;
- addOfflineTrainingTime(offlineTime * 1000);
- uint16_t newMinutes = getOfflineTrainingTime() / 60 / 1000;
- if (oldMinutes != newMinutes) {
- sendStats();
- sentStats = true;
- }
- }
-
- if (!sentStats && getStaminaMinutes() != oldStaminaMinutes) {
- sendStats();
- }
-
g_game.checkPlayersRecord();
IOLoginData::updateOnlineStatus(guid, true);
}
@@ -4535,6 +4442,10 @@ bool Player::addOfflineTrainingTries(skills_t skill, uint64_t tries)
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());