• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Pre-9.6 offline training for 0.4

elf

Sing, sing blue silver
Senator
Joined
Dec 11, 2007
Messages
3,666
Solutions
1
Reaction score
125
Location
Warsaw, Poland
GitHub
tayandenga
Twitch
tayandenga
Hello people,

long time I haven't posted anything around, so I decided to share this tiny feature here.
Title says everything, though I'll explain it a little. System works on storage values and few other cool stuff instead modal dialog. Just simply set actionid to 6666 for any item you want to be working as "statue" and you are ready to go. You can of course adjust the config part too if you know what you're doing.

Code:
<?xml version="1.0" encoding="UTF-8"?>
<mod name="Offline Training System" version="1.1" author="Elf" contact="[email protected]" enabled="yes">
   <config name="OfflineTraining.Config"><![CDATA[
     config = {
       pool = 12 * 60 * 60 * 1000,
       minimum = 10 * 60,
       premium = true
     }
     storage = {
       time = "offlineTrain.time",
       skill = "offlineTrain.skill",
       logout = "offlineTrain.logout" -- optional, only if server does not have getPlayerLastLogout
     }
     rates = {
       [SKILL_FIST] = 0.5,
       [SKILL_AXE] = 0.5,
       [SKILL_CLUB] = 0.5,
       [SKILL_SWORD] = 0.5,
       [SKILL_DISTANCE] = 0.4,
       [SKILL_SHIELD] = 0.25,
       [SKILL__MAGLEVEL] = 0.5
     }
   ]]></config>
   <event type="login" name="OfflineTraining.Login" event="script"><![CDATA[
function onLogin(cid)
   domodlib("OfflineTraining.Config")
   if(getCreatureStorage(cid, storage.time) == EMPTY_STORAGE) then
     doCreatureSetStorage(cid, storage.time, config.pool)
   elseif(not getPlayerCustomFlagValue(cid, PLAYERCUSTOMFLAG_GAMEMASTERPRIVILEGES)) then
     local logout
     if(not _G["getPlayerLastLogout"]) then
       logout = getCreatureStorage(cid, storage.logout)
     else
       logout = getPlayerLastLogout(cid)
     end

     local skill, offline = getCreatureStorage(cid, storage.skill), os.time() - math.max(getPlayerLastLogin(cid), logout)
     if(skill > EMPTY_STORAGE and offline > config.minimum and rates[skill] ~= nil) then
       local time = getCreatureStorage(cid, storage.time)
       local vocation = getVocationInfo(getPlayerVocation(cid))

       local ticks = math.min(time, offline * 1000)
       if(skill == SKILL__MAGLEVEL) then
         doPlayerAddSpentMana(cid, ((ticks / (vocation.manaGainTicks * 1000)) * vocation.manaGain) * rates[SKILL__MAGLEVEL], true)
       else
         doPlayerAddSkillTry(cid, skill, (ticks / vocation.attackSpeed) * rates[skill], true)
       end

       doPlayerAddSkillTry(cid, SKILL_SHIELD, (ticks / 1000) * rates[SKILL_SHIELD], true)
       doPlayerPopupFYI(cid, "You have been training for " .. table.concat(string.diff(ticks / 1000)) .. ".")
       doCreatureSetStorage(cid, storage.time, math.max(0, math.min(config.pool, math.abs(time - offline * 1000))))
     else
       doCreatureSetStorage(cid, storage.time, math.max(0, math.min(config.pool, getCreatureStorage(cid, storage.time) + (offline * 1000))))
     end
   end

   doCreatureSetStorage(cid, storage.skill, nil)
   return true
end
   ]]></event>
   <event type="logout" name="OfflineTraining.Logout" event="script"><![CDATA[
function onLogout(cid, force)
   domodlib("OfflineTraining.Config")
   if(not _G["getPlayerLastLogout"]) then
     doCreatureSetStorage(cid, storage.logout, os.time())
   end

   local time = getCreatureStorage(cid, storage.time)
   if(time < config.pool) then
     doCreatureSetStorage(cid, storage.time, math.max(0, math.min(config.pool, time + ((os.time() - getPlayerLastLogin(cid)) * 1000))))
   end

   return true
end
   ]]></event>
   <event type="channelrequest" name="OfflineTraining.ChannelRequest" event="script"><![CDATA[
function onChannelRequest(cid, channel, custom)
   unregisterCreatureEvent(cid, "OfflineTraining.ChannelRequest")
   if(not custom) then
     return true
   end

   domodlib("OfflineTraining.Config")
   if(type(channel) ~= "number" or rates[channel] == nil) then
     doPlayerSendDefaultCancel(cid, RETURNVALUE_NOTPOSSIBLE)
     return false
   end

   doCreatureSetStorage(cid, storage.skill, channel)
   doRemoveCreature(cid)
   return false
end
   ]]></event>
   <action actionid="6666" event="script"><![CDATA[
function onUse(cid)
   if(getPlayerCustomFlagValue(cid, PLAYERCUSTOMFLAG_GAMEMASTERPRIVILEGES)) then
     return true
   end

   domodlib("OfflineTraining.Config")
   if(premium and not isPremium(cid)) then
     doPlayerSendDefaultCancel(cid, RETURNVALUE_YOUNEEDPREMIUMACCOUNT)
     return true
   end

   local skills = {}
   for skill, _ in pairs(rates) do
     if(skill ~= SKILL_SHIELD) then
       skills[skill] = SKILL_NAMES[skill]:gsub("^%l", string.upper)
     end
   end

   unregisterCreatureEventType(cid, "channelrequest")
   doPlayerSendChannels(cid, skills)
   registerCreatureEvent(cid, "OfflineTraining.ChannelRequest")
   return true
end
   ]]></action>
   <talkaction words="!offline" event="script"><![CDATA[
function onSay(cid)
   domodlib("OfflineTraining.Config")
   doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "You have " .. table.concat(string.diff(math.max(0, math.min(config.pool, getCreatureStorage(cid, storage.time) + ((os.time() - getPlayerLastLogin(cid)) * 1000))) / 1000)) .. " of offline training available.")
   return true
end
   ]]></talkaction>
</mod>

Have fun.
 
Yes. It should work on any 0.4 running on tibia lower, than 9.6.

If you expect any errors, please dispatch them here, I'll help you to fix it.

What do i need to download for it to work for 8.60? And could you give me a download for TFS 0.4 if its possible? Id really love to test this mod.
 
where should this script be somewhere in the map in the data folder? :)
 
i tried to input it into my ot.. Lots of errors. Im using 0.4 svn, 8.6 ot.

[Error - CreatureEvent::configureEvent] No valid type for creature event.channelrequest --this happens when i start the server, when all files are loading.

when i try to use my "statue" i get a few more errors..
 

Attachments

Last edited:
Hey @ian12,

it seems you are missing ChannelRequest event. It was introduced just right after 8.6 was released and CTRL+Y was removed.
What you can do in this case is simply change the mod to this:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<mod name="Offline Training System" version="1.1.no-event" author="Elf" contact="[email protected]" enabled="yes">
  <config name="OfflineTraining.Config"><![CDATA[
  config = {
  pool = 12 * 60 * 60 * 1000,
  minimum = 10 * 60,
  premium = true
  }
  storage = {
  time = "offlineTrain.time",
  skill = "offlineTrain.skill",
  logout = "offlineTrain.logout" -- optional, only if server does not have getPlayerLastLogout
  }
  rates = {
  [SKILL_FIST] = 0.5,
  [SKILL_AXE] = 0.5,
  [SKILL_CLUB] = 0.5,
  [SKILL_SWORD] = 0.5,
  [SKILL_DISTANCE] = 0.4,
  [SKILL_SHIELD] = 0.25,
  [SKILL__MAGLEVEL] = 0.5
  }
  ]]></config>
  <event type="login" name="OfflineTraining.Login" event="script"><![CDATA[
function onLogin(cid)
  domodlib("OfflineTraining.Config")
  if(getCreatureStorage(cid, storage.time) == EMPTY_STORAGE) then
  doCreatureSetStorage(cid, storage.time, config.pool)
  elseif(not getPlayerCustomFlagValue(cid, PLAYERCUSTOMFLAG_GAMEMASTERPRIVILEGES)) then
  local logout
  if(not _G["getPlayerLastLogout"]) then
  logout = getCreatureStorage(cid, storage.logout)
  else
  logout = getPlayerLastLogout(cid)
  end

  local skill, offline = getCreatureStorage(cid, storage.skill), os.time() - math.max(getPlayerLastLogin(cid), logout)
  if(skill > EMPTY_STORAGE and offline > config.minimum and rates[skill] ~= nil) then
  local time = getCreatureStorage(cid, storage.time)
  local vocation = getVocationInfo(getPlayerVocation(cid))

  local ticks = math.min(time, offline * 1000)
  if(skill == SKILL__MAGLEVEL) then
  doPlayerAddSpentMana(cid, ((ticks / (vocation.manaGainTicks * 1000)) * vocation.manaGain) * rates[SKILL__MAGLEVEL], true)
  else
  doPlayerAddSkillTry(cid, skill, (ticks / vocation.attackSpeed) * rates[skill], true)
  end

  doPlayerAddSkillTry(cid, SKILL_SHIELD, (ticks / 1000) * rates[SKILL_SHIELD], true)
  doPlayerPopupFYI(cid, "You have been training for " .. table.concat(string.diff(ticks / 1000)) .. ".")
  doCreatureSetStorage(cid, storage.time, math.max(0, math.min(config.pool, math.abs(time - offline * 1000))))
  else
  doCreatureSetStorage(cid, storage.time, math.max(0, math.min(config.pool, getCreatureStorage(cid, storage.time) + (offline * 1000))))
  end
  end

  doCreatureSetStorage(cid, storage.skill, nil)
  return true
end
  ]]></event>
  <event type="logout" name="OfflineTraining.Logout" event="script"><![CDATA[
function onLogout(cid, force)
  domodlib("OfflineTraining.Config")
  if(not _G["getPlayerLastLogout"]) then
  doCreatureSetStorage(cid, storage.logout, os.time())
  end

  local time = getCreatureStorage(cid, storage.time)
  if(time < config.pool) then
  doCreatureSetStorage(cid, storage.time, math.max(0, math.min(config.pool, time + ((os.time() - getPlayerLastLogin(cid)) * 1000))))
  end

  return true
end
  ]]></event>
  <action actionid="6660-6669" event="script"><![CDATA[
function onUse(cid)
  domodlib("OfflineTraining.Config")
  doCreatureSetStorage(cid, storage.skill, 6660 - item.actionid)
  doRemoveCreature(cid)
  return true
end
  ]]></action>
  <talkaction words="!offline" event="script"><![CDATA[
function onSay(cid)
  domodlib("OfflineTraining.Config")
  doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "You have " .. table.concat(string.diff(math.max(0, math.min(config.pool, getCreatureStorage(cid, storage.time) + ((os.time() - getPlayerLastLogin(cid)) * 1000))) / 1000)) .. " of offline training available.")
  return true
end
  ]]></talkaction>
</mod>


...and use action id 6660 + skill number, so for fist it gonna be: 6660.

Code:
SKILL_FIST = 0
SKILL_CLUB = 1
SKILL_SWORD = 2
SKILL_AXE = 3
SKILL_DISTANCE = 4
SKILL_SHIELD = 5
SKILL_FISHING = 6
SKILL__MAGLEVEL = 7
 
Thanks alot Elf!!

I implemented it into my OT. But its still bugged, however its just a small error now. Ill post the error here to see if you no whats up with it. Meanwhile ill try to see if i can fix it myself.

heres the error:

PHP:
[ Error - Action Interface ]
function onUse(cid)
domodlib("OfflineTraining.Config")
diCreatureSetStorage(cid, storage.skill, 6660 -item.actionid)
doRemoveCreature (cid)
return true
end
:eek:nUse
Description:
[String "LuaInterface::loadBuffer"]:3: attempt to index globl 'item' (a nil value)
stack traceback:
[string "LuaInterface::loadBuffer"]:3: in function <[string "LuaInterface::loadBuffer"]:1>

^ i tried using
Lua:
 brackets
doesnt work... so i just used php so its easier to read. :)
 
function onUse(cid, item, fromPosition, itemEx, toPosition)
 
Okay.. thanks Ninja! That works. No error, and it logs out the character.. But the script doesn't work. It doesn't train my character. I even made a new account, with a new char.. no skills go up, even after an hour offline.

Edit:
Now i see theres a talkaction in this script "!offline" when i say that i now get an error.

b97ww7.png
 
Last edited:
I have this same problem like @ian12, have someone fixed this issue?

EDIT:
I changed it a bit, now works for me after this changes:
From:
PHP:
local skill, offline = getCreatureStorage(cid, storage.skill), os.time() - math.max(getPlayerLastLogin(cid), logout)
to:
PHP:
local skill, offline = getCreatureStorage(cid, storage.skill), os.time() - logout

and from:
PHP:
<action actionid="6660-6669" event="script"><![CDATA[
  function onUse(cid)
  domodlib("OfflineTraining.Config")
  doCreatureSetStorage(cid, storage.skill, 6660 - item.actionid)
  doRemoveCreature(cid)
return true
end
to:
PHP:
<action actionid="6660-6667" event="script"><![CDATA[
  function onUse(cid, item, fromPosition, itemEx, toPosition)
  domodlib("OfflineTraining.Config")
  doCreatureSetStorage(cid, storage.skill, item.actionid - 6660)
  doRemoveCreature(cid)
return true
end

All privileges to @elf, see u guys ^^
 
Last edited:
Hello,
I have problem.


[18:3:03.562] [Error - TalkAction Interface]
[18:3:03.562] function onSay(cid)
[18:3:03.562] domodlib("OfflineTraining.Config")
[18:3:03.562] doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "You have " .. table.concat(string.diff(math.max(0, math.min(config.pool, getCreatureStorage(cid, storage.time) + ((os.time() - getPlayerLastLogin(cid)) * 1000))) / 1000)) .. " of offline training available.")
[18:3:03.562] return true
[18:3:03.562] end
[18:3:03.562] :eek:nSay
[18:3:03.562] Description:
[18:3:03.562] [string "LuaInterface::loadBuffer"]:3: attempt to call field 'diff' (a nil value)
[18:3:03.562] stack traceback:
[18:3:03.562] [string "LuaInterface::loadBuffer"]:3: in function <[string "LuaInterface::loadBuffer"]:1>

Please help me.
I have TFS Source 0.4 rev 3884, and in actions.xml i have:
<action id="6660" itemid="8985"/>
 
Back
Top