Using Health_Bar_Miniwindow_Telnet and others.

Posted by Orik on Sun 07 Feb 2010 01:48 AM — 28 posts, 102,370 views.

USA #0
I'm looking to figure how to show a groups hp/mana bar as well as the victim you're fighting.

So in WoW terms, when you add a member to your group then a box will pop up with his health and mana. Then whenever I'm fighting, a health/mana bar will pop up when we are engaged.

After looking through the Health_Bar_Miniwindow_Telnet part I didnt' really see where it was sending ch's input rather then the victims input. Is this something done in the src files first and then in a plugin?

Is there a direction I need to go in? I am running a smaug code with your diff changes and everything is working so far (the health, room desc, and exp bar).
USA #1
So I'm guessing here:


function OnPluginTelnetOption (option)

  local t = {}  -- incoming server variables will go into table t
  setfenv (assert (loadstring (option)), t) () -- compile and load into t
  
  if t.tt ~= "status" then
    return
  end
   
  -- require "tprint"
  -- tprint (t)
  
  local background_colour = ColourNameToRGB "lightgreen"
  if t.dead then
    background_colour = ColourNameToRGB "mistyrose"
  elseif t.combat then 
    background_colour = ColourNameToRGB "rosybrown"
  end -- if
  
  -- fill entire box to clear it
  WindowRectOp (win, 2, 0, 0, 0, 0, background_colour)  -- fill entire box

  -- a green inside border indicates you are poisoned
  if t.poisoned then
    WindowCircleOp(win, 2,         -- draw rectangle
                   0, 0, 0, 0,     -- entire window
                   ColourNameToRGB "olivedrab", 6, 4, -- pen, inside border, width 4
                   0, 1)  -- no brush
  end -- if
    
  -- Edge around box rectangle
  WindowCircleOp (win, 3, 0, 0, 0, 0, ColourNameToRGB "darkgray", 0, 2, 0, 1)

  -- stats don't really matter if you are dead
  if t.dead then
    local dead_message = "<You are dead>"
    local width = WindowTextWidth (win, FONT_ID, dead_message)
    local left = (WINDOW_WIDTH - width) / 2
    local top = (window_height - font_height) / 2
    WindowText (win, FONT_ID, dead_message, left, top, 0, 0, ColourNameToRGB "darkred")
  else
    vertical = 6  -- pixel to start at
  
    DoGauge ("HP: ",   t.hp,    t.maxhp,    ColourNameToRGB "darkgreen")
    DoGauge ("Mana: ", t.mana,  t.maxmana,  ColourNameToRGB "mediumblue")
    DoGauge ("Move: ", t.move,  t.maxmove,  ColourNameToRGB "gold")
  end -- if


Is where we are getting OUR hp/mana/move. How do I get t.hp to show the victim.hp?

After going over your posts again in the other topic I figure I don't change much in code since it has the show_status finding who the victim is, just need to figure out how to get the hp=%d for victim rather then my char.

I'll continue to look into this, any help or direction would be great.
Australia Forum Administrator #2
For the victim part, if you look at the data being sent during a fight from page 1 of the other thread:


"victim":
  "level"=1
  "maxhp"=11
  "name"="the kobold"
  "hp"=11
"move"=110
"poisoned"=false
"mana"=94
"maxhp"=43
"hp"=40
"tt"="status"
"combat"=true
"level"=2
"maxxp"=7084
"gold"=900
"xp"=2116
"maxmove"=110
"maxmana"=94
"dead"=false


Your HP is t.hp, but the victim's HP is t.victim.hp, and his max HP is t.victim.maxhp.

(The victim table might be empty or nil if not in a fight).

As for the group stuff, I know what you mean. You would probably need to find the group list (at the server end) and then add extra table items for each group member. Conceptually it would be similar to sending the stuff for the victim, but you would need to allow for more than one of them.
USA #3
Here's what I have so far:


  if t.combat then
    vertical = 6  -- pixel to start at
  
    DoGauge (t.victim.name,   t.victim.hp,    t.victim.maxhp,    ColourNameToRGB "darkgreen")
    -- DoGauge ("Mana: ", t.victim.mana,  t.victim.maxmana,  ColourNameToRGB "mediumblue")
    -- DoGauge ("Move: ", t.move,  t.maxmove,  ColourNameToRGB "gold")
  end --if
  
  -- make sure window visible
  if t.combat then
  WindowShow (win, true)
  else
  WindowShow (win, false)
  end --if

end -- function OnPluginTelnetOption


]]>
</script>

</muclient>


This gives me a window that pops up when I fight. It's supposed to show the name of the person being fought but it shows like the color code [0:37m or whatever and doesn't have enough room for the actual short descr. The room descriptions do this to for the room name.

I copied this from the health_bar miniwindow and replaced the HP with the victim name. I guess I need to figure out how to make it longer to show it and then figure out how to strip the color code or something.

Can't post my whole script because of the 6000 characters.
Thoughts?
USA #4
I've done this to make the box bigger:


  if t.combat then
    vertical = 6  -- pixel to start at
    WindowText (win, FONT_ID, t.victim.name, 5, 5, 0, 0, ColourNameToRGB "saddlebrown")
    vertical = vertical + font_height * 2 -- leave blank line
    DoGauge ("HP: ",   t.victim.hp,    t.victim.maxhp,    ColourNameToRGB "darkgreen")
  end --if


Now I just need to figure out how to get those color codes out of there.
Australia Forum Administrator #5
If you uncomment these two lines:


  -- require "tprint"
  -- tprint (t)


... then you will see what t.victim.name really is. In my example earlier it was "the kobold" so I don't see how you would see "[0:37m" on your screen.
USA #6
My short desc has colors in them. So if I'm fighting a guy with the name &RRalph, the armorer&w then the equivalent of &R and &w color codes will display before and after the name.
Australia Forum Administrator #7
So you called something that converted them to colours? No wonder you see the funny numbers. You could just strip out the @R stuff. I had a routine in mw.lua that did that:


-- take a string, and remove colour codes from it (eg. "@Ghello" becomes "hello"
function strip_colours (s)
  s = s:gsub ("@%-", "~")    -- fix tildes
  s = s:gsub ("@@", "\0")  -- change @@ to 0x00
  s = s:gsub ("@%a([^@]*)", "%1")
  return (s:gsub ("%z", "@")) -- put @ back
end -- strip_colours


If you want to see the colours you might have to do more work. In mw.lua is a routine "colourtext" that shows the general idea. Remember, miniwindows don't interpret ANSI colour codes.
USA #8
Is this how I'm supposed to use it?


  -- take a string, and remove colour codes from it (eg. "@Ghello" becomes "hello"
  function strip_colours (s)
    s = s:gsub ("&%-", "~")    -- fix tildes
    s = s:gsub ("&&", "\0")  -- change @@ to 0x00
    s = s:gsub ("&%a([^&]*)", "%1")
    return (s:gsub ("%z", "&")) -- put @ back
  end -- strip_colours

  if t.combat then
    vertical = 6  -- pixel to start at
    WindowText (win, FONT_ID, strip_colours(t.victim.name), 5, 5, 0, 0, ColourNameToRGB "saddlebrown")
    vertical = vertical + font_height * 2 -- leave blank line
    DoGauge ("HP: ",   t.victim.hp,    t.victim.maxhp,    ColourNameToRGB "darkgreen")
  end --if


It's not working like this. Might not be doing it right though.
Australia Forum Administrator #9
Orik said:

My short desc has colors in them. So if I'm fighting a guy with the name &RRalph, the armorer&w then the equivalent of &R and &w color codes will display before and after the name.


OK, well &RRalph does not have codes like "[0:37m" in it, right? You would expect to see "&RRalph" not "[0:37mRalph". That means, at the server end, you must have called some function that converts the description as stored into ANSI colour codes. Well, don't call that function, just pass down the string you actually have stored.
USA #10
In the show_status function in comm.c?
USA #11
Ok. I wrote a color_strip command to take out the & and it seems to be working.

One other thing, seems that when I hotboot on smaug, my victim prompt doesn't return again. Not sure what that's about. Will have to look into it later.
Australia Forum Administrator #12
Maybe the hotboot resets the flag which says to send telnet codes. Maybe you need to save and restore the flag, or re-query the negotiation. Probably saving and restoring the flag is best, as the client may not respond twice to the same query (from its point of view).
USA #13
I've added my coin types into the show_status and am trying to figure out how to simply just draw a box with the money types in it. I've looked over health bar and exp bar but didn't really see how to do it. I have been up for almost 24 hours and kinda blurry vision...heh. I'm sure I missed something.
USA #14
So I've done this:


    WindowText (win, FONT_ID, string.format ("Plat: %i Gold: %i Silver: %i Copper %i", 
											  t.plat, t.gold, t.silver, t.copper), left, top, 0, 0, ColourNameToRGB "gold")


It puts it all on one line. How do I put a return in there to show on consecutive lines?

I tried \r, \n, and \r\n and it didn't seem to work. What am I doing wrong?
Netherlands #15
Use different WindowText calls. You can calculate the width a line takes and get the fonts height as well, thus decide where to wrap and print each line manually.

Everything is possible, but this is sadly not the easiest thing. It can quite easily be wrapped into a function though, but problem is that nearly everyone has slightly different wishes on how to wrap, how many lines to show maximum, and so forth.
USA #16
Alright thanks! I'll see what I can figure out here.
USA #17
Ok. I have this:


    WindowText (win, FONT_ID, string.format ("Plat  : %10.i  Bank Plat  : %10.i", t.plat, t.bpp), left, 5, 0, 0, ColourNameToRGB "white")	
    WindowText (win, FONT_ID, string.format ("Gold  : %10.i  Bank Gold  : %10.i", t.gold, t.bgp), left, 17, 0, 0, ColourNameToRGB "white")  
    WindowText (win, FONT_ID, string.format ("Silver: %10.i  Bank Silver: %10.i", t.silver, t.bsp), left, 29, 0, 0, ColourNameToRGB "white") 
    WindowText (win, FONT_ID, string.format ("Copper: %10.i  Bank Copper: %10.i", t.copper, t.bcp), left, 41, 0, 0, ColourNameToRGB "white") 


And this is pretty much how I want it, but if they have zero type coins on their person then it doesn't show 0, it just doesn' t show anything.

Example:

My char has 12 plat, 5 gold, and 3 copper on him. 4 gold in the bank.

It would show:


Plat  :      12  Bank Plat   :     
Gold  :       5  Bank Gold   :     4
Silver:          Bank Silver :      
Copper:       3  Bank Copper :    


I'd like it to show:


Plat  :      12  Bank Plat   :     0
Gold  :       5  Bank Gold   :     4
Silver:       0  Bank Silver :     0
Copper:       3  Bank Copper :     0


I tried to do t.bpp + 0 in the string.format but it still didn't show. Any thoughts?
Netherlands #18
Try %10i instead. Without the dot.
USA #19
Can I send too much data?

I added in a few more stats to put through into a plugin and I ended up messing up all my plugins. It wasn't until I took those changes out that my other plugins would work correctly again.

I added in 9 new arguments for the show_status, all ints, and it messed everything up. Could I be sending to much data or did I just mess up somewhere?
USA #20
Here is my show_status:


void show_status( CHAR_DATA *ch )
{

   if (WANT_TELNET_INFO (ch))
     {
     CHAR_DATA * victim = NULL;

     if (ch->fighting)
       victim = ch->fighting;

     char buf[MAX_STRING_LENGTH];
     snprintf(buf, sizeof (buf),
               "\xFF\xFA\x66"         // IAC SB 102
               "tt=\"status\";"       // transaction type: status
               "hp=%d;maxhp=%d;"      // hp points
               "move=%d;maxmove=%d;"  // movement
               "xp=%d;maxxp=%d;"      // experience
               "level=%d;"            // level
                "plat=%d;"              // plat on char
                "gold=%d;"              // gold on char
                "silver=%d;"            // silver on char
                "copper=%d;"            // copper on char
                "bpp=%d;"               // Bank Plat
                "bgp=%d;"               // Bank Gold
                "bsp=%d;"               // Bank Silver
                "bcp=%d;"               // Bank Copper
                "combat=%s;",           // Combat?
/*
                "hitroll=%d;"           // Hitroll
                "dualhitroll=%d;"       // Dual Wielding Hitroll
                "damroll=%d;"           // Damroll
                "dualdamroll=%d;"       // Dual Wielding Damroll
                "strength=%d;"          // Strength
                "wisdom=%d;"            // Wisdom
                "constitution=%d;"      // Constitution
                "intelligence=%d;"      // Intelligence
                "dexterity=%d;"         // Dexterity
                "armor=%d;"             // Armor
                "alignment=%d",         // Alignment
*/
               ch->hit,
               ch->max_hit,
               ch->move,
               ch->max_move,
               ch->exp,
               xp_for_level(ch,ch->level+1),
               ch->level,
               ch->coins[COIN_PP],
               ch->coins[COIN_GP],
               ch->coins[COIN_SP],
               ch->coins[COIN_CP],
                ch->pcdata->bank_coins[COIN_PP],
                ch->pcdata->bank_coins[COIN_GP],
                ch->pcdata->bank_coins[COIN_SP],
                ch->pcdata->bank_coins[COIN_CP],
                (ch->fighting && ch->fighting->fighting) ? "true" : "false"
/*
                get_hitroll(ch, WEAR_WIELD),
                get_hitroll(ch, WEAR_WIELD_2),
                get_damroll(ch, WEAR_WIELD_2),
                get_damroll(ch, WEAR_WIELD_2),
                get_curr_str(ch),
                get_curr_wis(ch),
                get_curr_con(ch),
                get_curr_int(ch),
                get_curr_dex(ch),
                GET_AC(ch),
                ch->alignment
*/
               );

      if (victim)
        {
         const char * p = "You";
         char * pName;

         if (ch != victim)
           {
           if (IS_NPC( victim ) )
             p = color_strip(victim->short_descr);
           else
             p = color_strip(victim->name);
           }

         pName = fixup_lua_strings (p);

         snprintf(&buf [strlen (buf)], sizeof (buf) - strlen (buf),
                 "victim={name=%s;" // name
                 "hp=%d;maxhp=%d;"      // hp points
                 "level=%d;"            // level
                 "};",
                 pName,
                 victim->hit,
                 victim->max_hit,
                 victim->level
               );
         free (pName);
       }

      //finish telnet negotiation after the combat info
      strncpy(&buf [strlen (buf)], "\xFF\xF0", sizeof (buf) - strlen (buf));  // IAC SE

      send_to_char( buf, ch );
     }

 }



The blocked out parts are what I added when it started messing up plugins.
Australia Forum Administrator #21
I would be displaying what is received (by using the tprint in the plugin) to see if you are getting what you expect.

I can't directly test what you have done because I don't have things like get_hitroll in my version.

If the printf won't handle more than x variables (and I don't know if this is true or not) you could always just append the extra things like I did underneath where I appended extra stuff if you are fighting.

I would also check that the data type corresponds with what you have in the printf. For example, I thought that %d was used for a short, but if the data is long (eg. ch->pcdata->bank_coins) then it might throw things out.
USA #22
Well, I just created a new function show_status_2 and put my new additions into it. Everything seems to be working fine now. What's the variable for long, you said %d is for short?

Also, is it possible to make these windows be able to detach from inside the world and be movable on the desktop? Like I have dual monitors I could float a window outside the mushclient?
USA #23
Orik said:
Also, is it possible to make these windows be able to detach from inside the world and be movable on the desktop? Like I have dual monitors I could float a window outside the mushclient?


That would be cool, but no. Miniwindows are simply script-drawn images rendered straight onto the output window itself. To create disassociated miniwindows, I suspect you'd need to give each one its own Windows window (though I don't know for sure), and the implementation of hotspot events would become markedly different. You might be able to extend MUSHclient across both monitors, and put your miniwindows in that space, though.
Amended on Sun 14 Feb 2010 10:22 PM by Twisol
USA #24
Hmm, ok.

I did find an old link that Nick had about a program he wrote that showed windows outside. I might maybe look at that some.

http://www.gammon.com.au/forum/?id=4951

Dunno if that's something I can use or not.

also, if you want to see what I've done so far, here's the links:

admud.com/download

You can connect to admud.com port 1999 and load those plugins to see them.
Amended on Sun 14 Feb 2010 11:17 PM by Orik
USA #25
Well, as Nick mentioned in that post, that plugin is actually written as a separate program altogether. A MUSHclient plugin is used to communicate between the two programs through a UDP socket connection. That's a perfectly valid approach, and indeed opens up its own unique possibilities, but it's entirely different from miniwindows.
Australia Forum Administrator #26
You could conceivably open an entire new instance of MUSHclient on your separate monitor, and send stuff from the main one to the extra one using UDP packets (or some other method). Then the second instance could still use miniwindows, if you are comfortable using them.
Australia Forum Administrator #27
Orik said:

Well, I just created a new function show_status_2 and put my new additions into it. Everything seems to be working fine now. What's the variable for long, you said %d is for short?


From memory, %ld (L-D not one-D) for a long, and %i for an int.