Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to "verify" your details, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ MUDs ➜ General ➜ GMCP Health/Combat Bar

GMCP Health/Combat Bar

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by Xinefus   (106 posts)  Bio
Date Sat 09 May 2020 02:10 PM (UTC)
Message
Hello! I'm back at it again.

I have been playing around with things and have been able to get my MUD to provide me with a bunch of information!

char.vitals {"cur_hp": 33, "max_hp": 37, "cur_mana": 105, "max_mana": 105, "cur_move": 105, "max_move": 110, "align": 0}
GMCP: char.vitals
char.combat {"cur_hp": 39, "max_hp": 44}
GMCP: char.combat


Note that char.combat only shows up while in combat.

I have been reading an old thread: https://www.gammon.com.au/forum/?id=9575 and wondering how to adapt this to my situation. Now, I have not seemingly been able to get the enemies name to work yet, but let's take this one step at a time.

The first thing I notice about this is that it is using a different gmcp handler and that OnPluginBroadcast isn't the same as the one in https://github.com/nickgammon/plugins/blob/master/GMCP_message_receiver_test.xml.

Could someone help me to troubleshoot this so I can at least get a generic version of this working?
Top

Posted by Fiendish   USA  (2,533 posts)  Bio   Global Moderator
Date Reply #1 on Sat 09 May 2020 03:34 PM (UTC)

Amended on Sat 09 May 2020 03:36 PM (UTC) by Fiendish

Message
Quote:
I have been reading an old thread: https://www.gammon.com.au/forum/?id=9575

That thread predates GMCP. Aardwolf used to use (still has them, actually, but I hate them) special optional text tags that you could look for, trigger on, and then erase from your output, instead of the much nicer from my perspective GMCP messages that build in hierarchical structure and don't have to be hidden.

In that thread, OnPluginBroadcast is not listening for a message from a GMCP plugin, it's listening for a broadcast from a different kind of plugin that parses those old tags and fills in some variables by text parsing. (Pro tip: any plugin can send a broadcast by calling BroadcastPlugin, even yours, and every other plugin will see it if they have an OnPluginBroadcast defined.) So what you need to do is ignore the beginning of that thread that says to download those other two files (you don't need them for GMCP) and then replace that OnPluginBroadcast function with one that pulls the values you want out of the stats message that you know has just arrived.

https://github.com/fiendish/aardwolfclientpackage
Top

Posted by Xinefus   (106 posts)  Bio
Date Reply #2 on Sat 09 May 2020 04:28 PM (UTC)
Message
Thanks Fiendish, that makes a lot more sense.

So, I was previously able to make a healthbar that uses the info from my previous post, but I can make a bar that has char.vitals, and one that has char.combat.
Within GMCP_message_receiver_test.xml I'm not very familiar with how the 'handler function' work. How do I call a variable from both char.vitals and char.combat so I can use it in a bar in a single function like the one I'm trying to create?
Top

Posted by Xinefus   (106 posts)  Bio
Date Reply #3 on Sat 09 May 2020 04:35 PM (UTC)
Message
That wasn't a lot of info to go on I suppose..

I have the info coming in from OnPluginBroadcast in a json format (as you can see in OP). The GMCP_message_receiver_test plugin creates a bunch of functions from handler (result) such as

handlers = {
  ["char.vitals"]           = gotCharacterVitals,
  ["char.stats"]            = gotCharacterStats,
  ["char.combat"]           = gotCharacterCombat,

How do I use something from char.vitals and char.combat in a function like draw_bar () in the original quoted 'old' thread?
Top

Posted by Xinefus   (106 posts)  Bio
Date Reply #4 on Sat 09 May 2020 08:18 PM (UTC)

Amended on Sat 09 May 2020 08:19 PM (UTC) by Xinefus

Message
I'm going to keep adding info/questions as I try to clarify what I want or what I have envisioned in my mind.

I would like a 'dynamic' miniwindow/bar. Dynamic in the sense that it will update and change when in and out of combat. Enemy name will update when in combat, and it will default to 'Enemy' and be 'greyed-out' when not in combat(same for enemy hp bar).

In the 'title' part, I want to be able to have combat information. For the MUD I want to finally do the changes on, there is a focus counter when in combat, meaning it counts up when combat begins. There is also a spell timer (how long until spell is cast, counting down) that I would like to have appear while in combat, and then just show experience or tnl when not.

The thing that I believe is confusing me is how OnPluginBroadcast is giving me information. I don't quite understand what it means when it is putting each of my JSON msg into different 'functions'. How would I be able to get OnPluginBroadcast put all my information in a space that I could pull variables from it such as:
Quote:

char.vitals.cur_hp and char.combat.cur_hp to be used in the same miniwindow/bar? Or even other variables for that matter, such as char.status.max_str, or room.info.name, etc.

I really like the look of a miniwindow/bar that I can set the size and position, I tried using infobars, they are really nice, but I'm not super keen on how they can only be placed in the grid and not move them around.

Thanks for your help in this!
Top

Posted by Fiendish   USA  (2,533 posts)  Bio   Global Moderator
Date Reply #5 on Sun 10 May 2020 06:18 AM (UTC)

Amended on Sun 10 May 2020 06:28 AM (UTC) by Fiendish

Message
Hmm. I'm not sure how I feel about this variant of the GMCP handler plugin. The one I use for Aardwolf does the JSON parsing for you. That one leaves it up to the receiver, which means that ever receiver needs to re-parse the message again if multiple plugins want to use the same messages.

I think you might be happier using my version. Here is the one I use for Aardwolf with some minor edits to remove anything overtly Aardwolf-specific (hopefully it still works!):

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<muclient>
<plugin
   name="GMCP_handler"
   author="Fiendish"
   id="3e7dedbe37e44942dd46d264"
   language="Lua"
   purpose="Handle GMCP messages and broadcast data"
   save_state="y"
   date_written="2010-08-02 14:16:26"
   requires="4.59"
   version="1.0"
>
<description trim="y">

Aardwolf-style GMCP Handler

Purpose is to process incoming GMCP messages, notify other plugins
of arrival of new data, and make that data accessible.

For Mushclient specific information on how to access GMCP data, see:

   https://github.com/fiendish/aardwolfclientpackage/wiki/Using-GMCP

</description>

</plugin>

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

<alias
   match="sendgmcp *"
   script="GMCP_Alias"
   enabled="y"
   send_to="12"
   sequence="100"
></alias>

</aliases>

<!--  Get our standard constants -->

<script>
<![CDATA[

require "json"
require "serialize"
require "gmcphelper"

local IAC, SB, SE, DO = 0xFF, 0xFA, 0xF0, 0xFD
local GMCP = 201
local GMCPDebug = tonumber(GetVariable("GMCPDebug")) or 0


-- You can use CallPlugin to access any gmcp data via this function.
-- example:
--   local ret, datastring = CallPlugin("3e7dedbe37e44942dd46d264", "gmcpdata_as_string", "char.status")
--   pcall(loadstring("status_table = "..datastring))
--   for k,v in pairs(status_table) do
--      print(k,":",v)
--   end
function gmcpdata_as_string(what)
   return serialize.save_simple(gmcpdata_at_level(what) or "")
end

-- toggle debug output
function gmcpdebug(name, line, wildcards)
   local newval = tonumber(wildcards[1])
   if not newval or newval > 2 or newval < 0 then
      ColourNote("#FFAF00", "", "GMCPDebug valid values are: 0 - off, 1 - simple, 2 - verbose")
      return
   end
   GMCPDebug = newval
   local msg = "off"
   if GMCPDebug == 1 then
      msg = "simple"
   elseif GMCPDebug == 2 then
      msg = "verbose"
   end
   ColourNote ("#FFAF00", "", "GMCPDebug: " .. msg)
end


function GMCP_send(what)
   if what == nil then
      print("GMCP_send passed a nil message.")
      return
   end

   SendPkt (string.char (IAC, SB, GMCP) ..
           (string.gsub (what, "\255", "\255\255")) ..  -- IAC becomes IAC IAC
            string.char (IAC, SE))
end

function GMCP_Alias (name, line, wildcards)
   GMCP_send(wildcards[1])
end

function OnPluginTelnetSubnegotiation (msg_type, data)
   if msg_type ~= GMCP then
      return
   end -- if not GMCP

   if GMCPDebug > 0 then ColourNote ("#FFAF00", "", utils.utf8convert(data)) end

   message, params = string.match (data, "([%a.]+)%s+(.*)")

   if not message then
      return
   end -- if

   if not string.match (params, "^[%[{]") then
      params =  "[" .. params .. "]"  -- JSON hack, make msg first element of an array. (I don't think this is needed - fiendish)
   end -- if

   local succ, t = pcall(json.decode,params)

   if succ and type(t) == "table" then
      gmcpdata = gmcpdata or {}

      -- find where to insert the new data
      local node = gmcpdata
      local prev_node = nil
      local prev_item = ""
      for next_item in string.gmatch(message,"%a+") do
         node[next_item] = node[next_item] or {}
         prev_node = node
         prev_item = next_item
         node = node[next_item]
      end

      -- A loveletter.
      -- Some GMCP messages are just messages, not state. The "current" comm.channel message isn't a meaningful
      -- concept except in the exact moment it arrives, for example (though most recent might be).
      -- Since room.area is not sent automatically, and is only ever sent in response to a request,
      -- having seen a room.area message tells you only what the area details were for the area your
      -- character was in at the time the request was processed, but has no relation to where you are
      -- after or even to the area your character was in when the request was sent and especially not
      -- to the actual transition from one area to the next. If you run 5e through an area entrance,
      -- you would be 5 rooms deep into a new area before that area info arrives back to you, with
      -- mismatching area info the whole way in.
      -- (You send run 5e, you go e, new area in room.info triggers sending request for room.area, you go 4e,
      -- room.area request seen by game, room.area response sent back, room.area response seen by client)
      -- If you had also run back out of the area, then you'd also be receiving room.area information
      -- after five moves for an area you are no longer in.
      -- I do this next part for your own good.
      if (message == "room.info") then
         gmcpdata["room"] = {}
         prev_node = gmcpdata["room"]
      end

      prev_node[prev_item] = t

      if GMCPDebug > 1 then
         print ("gmcpdata serialized: " .. gmcpdata_as_string(""))
      end
      BroadcastPlugin(1, message)
   else
      ColourNote("white","red","GMCP DATA ERROR: "..t)
   end  -- if

end -- function OnPluginTelnetSubnegotiation

function gmcpdata_at_level(what)
   local node = gmcpdata
   for level in string.gmatch(what, "%a+") do
      if (type(node) ~= "table" or node[level] == nil) then return end
      node = node[level]
   end
   return node
end

function OnPluginSaveState()
   SetVariable("GMCPDebug", GMCPDebug)
end

function OnPluginTelnetRequest (msg_type, data)
   if msg_type == GMCP and data == "WILL" then
      return true
   end -- if

   if msg_type == GMCP and data == "SENT_DO" then
      -- This hard-coded block may need to be made into a config table as we add more message types.
      Send_GMCP_Packet (string.format ('Core.Hello { "client": "MUSHclient", "version": "%s" }', Version()))
      Send_GMCP_Packet ('Core.Supports.Set [ "Char 1", "Comm 1", "Room 1" ]')

      return true
   end -- if GMCP login needed (just sent DO)

   return false
end -- function OnPluginTelnetRequest

function OnPluginDisable()
   EnablePlugin(GetPluginID(), true)
   ColourNote("white", "blue", "You are not allowed to disable the "..
   GetPluginInfo(GetPluginID(), 1).." plugin. It is necessary for other plugins.")
end

]]>
</script>
</muclient>


If you use that along with this helper file (it goes in your MUSHclient/lua folder) https://raw.githubusercontent.com/fiendish/aardwolfclientpackage/MUSHclient/MUSHclient/lua/gmcphelper.lua

Then you'll be able to follow my instructions for how to use GMCP: https://github.com/fiendish/aardwolfclientpackage/wiki/Using-GMCP

https://github.com/fiendish/aardwolfclientpackage
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #6 on Sun 10 May 2020 06:52 AM (UTC)
Message
Xinefus said:

...

handlers = {
  ["char.vitals"]           = gotCharacterVitals,
  ["char.stats"]            = gotCharacterStats,
  ["char.combat"]           = gotCharacterCombat,

How do I use something from char.vitals and char.combat in a function like draw_bar () in the original quoted 'old' thread?


The original health bar plugin worked like this:


  • Have a trigger which waits for a prompt (with the HP and mana in it)
  • That trigger redraws the health bar with the new information


So all you have to do is:



  • Have a function which is called when the GMCP data tells you that the HP and mana have changed (gotCharacterStats above)
  • That function redraws the health bar with the new information


It's basically the same process but more reliable because you don't need to trigger on an exact prompt line.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Xinefus   (106 posts)  Bio
Date Reply #7 on Sun 10 May 2020 10:34 AM (UTC)

Amended on Sun 10 May 2020 05:31 PM (UTC) by Xinefus

Message
Edit: Moved to my original GMCP thread as it was about getting GMCP enabled.
Top

Posted by Xinefus   (106 posts)  Bio
Date Reply #8 on Sun 10 May 2020 01:40 PM (UTC)

Amended on Sun 10 May 2020 05:30 PM (UTC) by Xinefus

Message
Alright, I have a small bug in my attempt to replicate what Fiendish has here: https://github.com/fiendish/aardwolfclientpackage/wiki/Using-GMCP

This is my plugin:

function OnPluginBroadcast (msg, id, name, text)

    -- Look for GMCP handler.
    if (id == '3e7dedbe37e44942dd46d264') then
        if (text == "char.vitals") then
            gmcp_vitals = gmcp("char.vitals")
            cur_hp = gmcp_vitals.cur_hp
        elseif (text == "char.stats") then
            gmcp_stats = gmcp("char.stats")
        elseif (text == "char.combat") then
            gmcp_combat = gmcp("char.combat")
        end          
    print("hp is ", cur_hp)
    end
end

But in MUSHclient I get:

<49hp 145m 110mv> <#10308> 
hp is  49
hp is  49


It is spitting out the number twice... I don't know why it is doing this.

Edit: I got this working! It was an oversight within OnPluginEnable ().
Top

Posted by Fiendish   USA  (2,533 posts)  Bio   Global Moderator
Date Reply #9 on Sun 10 May 2020 06:02 PM (UTC)
Message
Yay!

https://github.com/fiendish/aardwolfclientpackage
Top

Posted by Xinefus   (106 posts)  Bio
Date Reply #10 on Sun 10 May 2020 07:57 PM (UTC)
Message
So, I can make the numbers show up but I can't seem to draw a bar.

Here is what I have:
https://github.com/DBNU-Braska/GMCP-Learning/blob/master/test_health_bar_gmcp
I am using the HP Bar miniwindow plugin from: http://gammon.com.au/forum/?id=9270&reply=51#reply51 and have taken out the triggers in lieu of OnPluginBroadcast, but it doesn't look like I've done it right.
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #11 on Mon 11 May 2020 06:00 AM (UTC)
Message
What I would normally do here is add some debugging. Make sure you are getting what you think you are getting.


function OnPluginBroadcast (msg, id, name, text)
  -- Look for GMCP handler.
  if (id == '3e7dedbe37e44942dd46d264') then
     
     print ("Got OnPluginBroadcast with text", text)
     if (text == "char.vitals" or text == "char.stats" or text == "char.combat") then
        if text == "char.vitals" then
          charvitals = gmcp("char.vitals")
          print("Current HP is:", charvitals.cur_hp) -- print hp out
        elseif text == "char.stats" then
          charstats = gmcp("char.stats")
        else
          charcombat = gmcp("char.combat")
        end
        require "tprint"
        print ("--- charvitals ---")
        tprint (charvitals)
        print ("--- charstats ---")
        tprint (charstats)
        print ("--- charcombat ---")
        tprint (charcombat)
        
        if charvitals and charstats and charcombat then
          draw_bar () -- send to draw_bar
        end
     end
  end
end


- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


28,190 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.