A timer that works only while connected

Posted by Tisorin on Mon 02 Nov 2020 11:40 AM — 6 posts, 27,302 views.

#0
Greetings all,

I think the title explains my issue, but let me describe my problem a little.

So, I play this game while you can do certain action (ex> fishing, mining) every 2 hours. However, you must be loged during these two hours. In other words, if you stay loged 10 minutes, then logout for 5 hours, when you come back, you still need to wait 1:50.

I created some timers but, unfortunately, I have no clue how to "pause" them while I am disconnected.

It is possible to do that? And how can I achieve it?

Thank you in advance
USA Global Moderator #1
Plugins are notified when you connect/disconnect via the OnPluginConnect and OnPluginDisconnect functions ( https://mushclient.com/scripts/doc.php?general=plugin_callbacks ). If you put this into a plugin, you can define those functions to pause and resume the countdown by storing the remaining timer time in a variable using https://mushclient.com/scripts/doc.php?function=GetTimer or https://mushclient.com/scripts/doc.php?function=GetTimerInfo and deleting the timer at disconnect and then recreating the timer again using the stored time information at connect.
Amended on Mon 02 Nov 2020 05:14 PM by Fiendish
#2
Ok, sounds a bit complicated. I will try my best to figure it out. Could you give me an example, in practice how it should look?

As a disclaymer, I am not a programmer and a beginner to musclient scripting.

Would be nice to have a timer flag, like work_only_when_loged
USA Global Moderator #3
There is a timer flag for only firing when connected, but I'm not sure that's the same thing.
Australia Forum Administrator #4

This is related and may help you.

Australia Forum Administrator #5
It's a bit fiddly to get right, so I wrote a plugin to do it.

Template:saveplugin=Cooldown_Timers
To save and install the Cooldown_Timers plugin do this:
  1. Copy the code below (in the code box) to the Clipboard
  2. Open a text editor (such as Notepad) and paste the plugin code into it
  3. Save to disk on your PC, preferably in your plugins directory, as Cooldown_Timers.xml
    • The "plugins" directory is usually under the "worlds" directory inside where you installed MUSHclient.
  4. Go to the MUSHclient File menu -> Plugins
  5. Click "Add"
  6. Choose the file Cooldown_Timers.xml (which you just saved in step 3) as a plugin
  7. Click "Close"
  8. Save your world file, so that the plugin loads next time you open it.




<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>

<muclient>
<plugin
   name="Cooldown_Timers"
   author="Nick Gammon"
   id="19ca5712f530c6b6aa548b4d"
   language="Lua"
   purpose="Calculates cooldowns for action while connected"
   save_state="y"
   date_written="2020-11-04 08:15:07"
   requires="5.00"
   version="1.0"
   >
<description trim="y">
<![CDATA[
 Usage:
   cooldown add <name> <minutes>
   cooldown remove <name>
   cooldown list
]]>
</description>

</plugin>


<!--  Aliases  -->

<aliases>
  <alias
   script="cooldown"
   match="^cooldown(.*)$"
   enabled="y"
   regexp="y"
   sequence="100"
  >
  </alias>
</aliases>

<!--  Timers  -->

<timers>
  <timer
    script="cooldown_timer"
    enabled="y"
    second="1.00"
    >

  </timer>
</timers>

<!--  Script  -->


<script>
<![CDATA[

require "serialize"
require "pairsbykeys"
cooldown_table = { }

-- ---------------------------------------------------
-- on plugin install, convert variable into Lua table
-- ---------------------------------------------------
function OnPluginInstall ()
  assert (loadstring (GetVariable ("cooldown_table") or "")) ()
end -- function OnPluginInstall


-- ---------------------------------------------------
-- on saving state, convert Lua table back into string variable
-- save_simple is for simple tables that do not have cycles (self-reference)
-- or refer to other tables
-- ---------------------------------------------------

function OnPluginSaveState ()
  SetVariable ("cooldown_table",
               "cooldown_table = " .. serialize.save_simple (cooldown_table))
end -- function OnPluginSaveState

-- ---------------------------------------------------
-- on plugin connect, start timing cooldowns for this session
-- ---------------------------------------------------
function OnPluginConnect ()
  for k, v in pairs (cooldown_table) do
    v.start = os.time ()
  end -- for
end -- OnPluginConnect

-- ---------------------------------------------------
-- on plugin disconnect, calculate how long through the cooldowns we are
-- ---------------------------------------------------
function OnPluginDisconnect ()
  for k, v in pairs (cooldown_table) do
    v.previous = v.previous + os.time () - v.start
  end -- for
  SaveState ()
end -- OnPluginDisconnect

-- ---------------------------------------------------
-- print a message in the required colour (orange)
-- ---------------------------------------------------

function cooldown_print (...)
  local old_note_colour = GetNoteColourFore ()
  SetNoteColourFore(ColourNameToRGB "orange")
  print (...)
  SetNoteColourFore (old_note_colour)
end -- cooldown_print

-- ---------------------------------------------------
-- print a message in the error colour (red)
-- ---------------------------------------------------
function cooldown_error (...)
  local old_note_colour = GetNoteColourFore ()
  SetNoteColourFore(ColourNameToRGB "red")
  print (...)
  SetNoteColourFore (old_note_colour)
end -- cooldown_error

-- ---------------------------------------------------
-- formats a certain number of seconds into weeks, days, hours, minutes, seconds
-- ---------------------------------------------------
local function formatTime (secs, showSecs)
  local t = { }
  secs = math.floor (tonumber (secs))
  local SECS_IN_MINUTE = 60
  local SECS_IN_HOUR = SECS_IN_MINUTE * 60
  local SECS_IN_DAY = SECS_IN_HOUR * 25
  local SECS_IN_WEEK = SECS_IN_DAY * 7

  -- weeks
  if secs >= SECS_IN_WEEK then
    local weeks = math.floor (secs / SECS_IN_WEEK)
    secs = secs - (weeks * SECS_IN_WEEK)
    table.insert (t, tostring (weeks) .. "w")
  end -- if at least one week

  -- days
  if secs >= SECS_IN_DAY then
    local days = math.floor (secs / SECS_IN_DAY)
    secs = secs - (days * SECS_IN_DAY)
    table.insert (t, tostring (days) .. "d")
  end -- if at least one day

  -- hours
  if secs >= SECS_IN_HOUR then
    local hours = math.floor (secs / SECS_IN_HOUR)
    secs = secs - (hours * SECS_IN_HOUR)
    table.insert (t, tostring (hours) .. "h")
  end -- if at least one hour

  -- always show minutes
  local minutes = math.floor (secs / SECS_IN_MINUTE)
  secs = secs - (minutes * SECS_IN_MINUTE)
  if not showSecs and secs >= 30 then
    minutes = minutes + 1  -- round up if not showing seconds
  end -- if rounding needed
  table.insert (t, tostring (minutes) .. "m")

  -- seconds
  if showSecs then
    table.insert (t, tostring (math.floor (secs)) .. "s")
  end -- if seconds wanted

  return table.concat (t, " ")
end -- formatTime

-- ---------------------------------------------------
-- Calculate time to go
-- ---------------------------------------------------
function cooldown_time_to_go (which)
  local this_session = 0
  if IsConnected () then
    this_session = os.time () - which.start
  end -- if connected
  local time_taken = this_session + which.previous
  return math.max (which.seconds - time_taken, 0)
end -- cooldown_time_to_go

-- ---------------------------------------------------
-- Here for cooldown alias
-- ---------------------------------------------------

function cooldown (name, line, wildcards, styles)
  local function help ()
    cooldown_print "Usage:"
    cooldown_print "  cooldown add <name> <minutes>"
    cooldown_print "  cooldown remove <name>"
    cooldown_print "  cooldown list"
  end -- help

  -- ---------------------------------------------------
  -- add a cooldown
  -- ---------------------------------------------------
  local function add (args)
    -- find action name and number of minutes
    local action, minutes = string.match (args, "^%a+%s+(%a+)%s+([%d.]+)$")
    if not action or not tonumber (minutes) then
      cooldown_error "'cooldown add' requires the action and number of minutes to be specified"
      cooldown_print "eg.  cooldown add fishing 20"
      return
    end -- if no action and minutes given
    action = action:lower ()
    if cooldown_table [action] then
      cooldown_error ("Action", action, "already on cooldown")
      return
    end -- if already there
    cooldown_table [action] = { seconds = minutes * 60, start = os.time (), previous = 0 }
    cooldown_print ("Cooldown for", action, "started")
  end -- add

  -- ---------------------------------------------------
  -- remove a cooldown
  -- ---------------------------------------------------
  local function remove (args)
    -- find action name
    local action = string.match (args, "^%a+%s+(%a+)$")
    if not action then
      cooldown_error "'cooldown remove' requires the action name to be specified"
      cooldown_print "eg.  cooldown remove fishing"
      return
    end -- if no action given
    action = action:lower ()
    if not cooldown_table [action] then
      cooldown_error ("Action", action, "not on cooldown")
      return
    end -- if not there
    cooldown_table [action] = nil
    cooldown_print ("Cooldown for", action, "removed")
  end -- remove

  -- ---------------------------------------------------
  -- list all cooldowns
  -- ---------------------------------------------------
  local function list (args)
    if next (cooldown_table) then
      for k, v in pairsByKeys (cooldown_table) do
        cooldown_print (k, formatTime (cooldown_time_to_go (v), true))
      end -- for
    else
      cooldown_print "No actions on cooldown"
    end -- if

  end -- list


  local args = Trim (wildcards [1])

  if args == "" then
    help ()
    return
  end -- showing help

  local command = string.match (args, "^(%a+)")
  if not command then
    cooldown_error "Invalid argument."
    help ()
    return
  end -- if not recognised format

  command = command:lower ()

  if command == "add" then
    add (args)
  elseif command == "remove" then
    remove (args)
  elseif command == "list" then
    list ()
  else
    cooldown_error "Command not recognised"
    help ()
  end -- if

end -- cooldown

-- ---------------------------------------------------
-- Here for cooldown timer - check if any cooldowns are up
-- ---------------------------------------------------
function cooldown_timer (name)

  for k, v in pairsByKeys (cooldown_table) do
    local togo = cooldown_time_to_go (v)
    if togo <= 0 then
      cooldown_print ("Cooldown for", k, "is up")
      -- remove from table
      cooldown_table [k] = nil
    end -- if
  end -- for

end -- cooldown_timer

]]>
</script>

</muclient>



Once installed, you should be able to type something like:


cooldown add fishing 60
cooldown add hunting 120


The time period is in minutes (so 120 would be 2 hours). The plugin "remembers" how long you are through the cooldown when you disconnect, and keeps calculating next time you connect.

You can find the current status like this:


cooldown list


Which will show you something like this:


fishing 29m 52s
hunting 21m 58s


When the cooldown is up you will see:


Cooldown for fishing is up