Tintin MIP

Implementation of 3k MIP info system for Tintin++, as used by the Portal mud client.
Collects a LOT of very useful information for you to use in your own scripts and info displays.

Save this to a file, load it after connecting to 3K and it will start up the MIP system.
It saves the most recent data of each MIP type into $mip[mipflag] fields (E.G. $mip[AAC], $mip[BAE] etc). It also saves personal stats like HP, SP, GP1, GP2 into $my[hp][current], $my[sp][current] etc, along with $opponent[longname], $opponent[hp] and similar.

See the comments within the code (and the information on the older version of MIP below) for more information.

N.B. This is a framework for retrieving and storing the 3K MIP data.
It does very little with it once it has been captured, that is up to you! I have put comments within the code showing where each piece of information is being handled so you can add in your own processing.

Changes:

  • Version 0.102
    • Overhauled the Flag management to handle unrecognised MIP flags better.
    • Included hooks for FFF N (Combat Round), HAA (Room Description Nouns) and HAB (Room Contents).
    • Various tidy-ups.
  • Version 0.008
    • A few code tweaks and cleanups
    • Now collects guildline information, stored into $mip[gline][name_of_gline_tag]
#CLASS {cMip} {kill};
#CLASS {cMip} {open};
#NOP ***** Set MIP ID Code **********;
#VAR {mip} {};
#VAR {mip[Version]} {0.102};
#VAR {mip[id]} {};
#LOOP {1} {5} {i}
{
  #MATH {temp[digit]} {1d10 - 1};
  #VAR {mip[id]} {$mip[id]$temp[digit]};
};
#UNVAR {temp[digit]};

#NOP ***** Kick Off MIP *************;
#SEND {3klient $mip[id]~~Tin$mip[Version]};

#NOP ***** Extract Raw Data *********;
#ACTION {~{\#K\%$mip[id](.{3})(.{3})(.*)}}
{
  #VAR {mip[charcount]} {0};
  #VAR {mip[out]} {};
  #VAR {mip[overflow]} {};
  #VAR {mip[source]} {%0};
  #MATH {mip[%3][length]} {%2 - 3};
  #VAR {mip[%3][data]} {%4};
  #REPLACE {mip[%3][data]} {"} {'};
  #PARSE {$mip[%3][data]} {i}
  {
    #MATH {mip[charcount]} {$mip[charcount] + 1};
    #VAR {mip[delta]} {$mip[%3][length]};
    #IF {"${mip[char2]}${mip[char1]}${i}" == "x7B"} {#MATH {mip[delta]} {$mip[delta] + 3}};
    #IF {"${mip[char2]}${mip[char1]}${i}" == "x7D"} {#MATH {mip[delta]} {$mip[delta] + 3}};
    #IF {"$i" == ";"} {#MATH {mip[delta]} {$mip[delta] + 1}};
    #IF {$mip[charcount] <= $mip[delta]}
    {
      #VAR {mip[%3][length]} {$mip[delta]};
      #VAR {mip[out]} {${mip[out]}${i}};
    }
    {
      #REGEXP {$mip[%3][data]} {^{.{$mip[delta]}}{.*}} {#VAR {mip[overflow]} &2} {};
      #BREAK;
    };
    #VAR {mip[char2]} {$mip[char1]};
    #VAR {mip[char1]} {$i};
  };
  #VAR {mip[%3][data]} {$mip[out]};
  .aMipProcessFlag {%3} {$mip[out]};
  #NOP event_raise {e_mip_%3} {$mip[out]};
  #IF {"${mip[overflow]}" != ""} {#SHOWME {${mip[overflow]}};};
  #LINE GAG;
} {1};

#NOP ***** Individual Data Sections *****;
#ALIAS {.aMipProcessFlag}
{
  #NOP %1;
  #SWITCH {"%1"}
  {
    #CASE {"AAA"} {#NOP Sound;};
    #CASE {"AAB"} {#NOP Image;};
    #CASE {"AAC"} {#NOP Reboot Time;#VAR {session[RebootTime]} {%2};};
    #CASE {"AAD"} {#NOP Music;};
    #CASE {"AAF"} {#NOP Uptime;#VAR {session[UpTime]} {%2};};
    #CASE {"AAG"} {#NOP AVI movie;};
    #CASE {"AAH"} {#NOP Download Media;};
    #CASE {"BAA"} {#NOP Special Textstring;};
    #CASE {"BAB"} {#NOP 2 Way Communications;.aMipProcessBAB {%2}};
    #CASE {"BAC"} {#NOP Special Textstring2;};
    #CASE {"BAD"} {#NOP Room Description;};
    #CASE {"BAE"} {#NOP Mud Lag;#VAR {session[Lag]} {%2};};
    #CASE {"BAF"} {#NOP Send Edit;};
    #CASE {"BBA"} {#NOP Guild Point1 Mask;#FORMAT {my[gp1][name]} {%s} {%1}};
    #CASE {"BBB"} {#NOP Guild Point2 Mask;#FORMAT {my[gp2][name]} {%s} {%1}};
    #CASE {"BBC"} {#NOP Hit Point Mask;#FORMAT {my[hp][name]} {%s} {%1}};
    #CASE {"BBD"} {#NOP Spell Point Mask;#FORMAT {my[sp][name]} {%s} {%1}};
    #CASE {"CAA"} {#NOP Chat Messages;.aMipProcessCAA {%2}};
    #CASE {"CAP"} {#NOP Window Caption Text;#FORMAT {temp} {%h} {%2};};
    #CASE {"CCF"} {#NOP Send File Line;};
    #CASE {"CDF"} {#NOP Send File Begin;};
    #CASE {"CEF"} {#NOP Send File End;};
    #CASE {"DDD"} {#NOP Room Exits;#NOP Split at Hex 160 (Non Breaking Space);};
    #CASE {"FFF"} {#NOP Combined Stats Data;.aMipProcessFFF {%2}};
    #CASE {"HAA"} {#NOP Room Items;};
    #CASE {"HAB"} {#NOP Item Actions;};
    #DEFAULT {#NOP Every other non-handled flag;};
  };
};

#NOP ***** Combined Stats Data *****;
#ALIAS {.aMipProcessFFF}
{
  #NOP %1;
  #VAR {mip[FFF][flag]} {0};
  #VAR {mip[FFF][toggle]} {0};
  #PARSE {%1} {i}
  {
    #IF {"$mip[FFF][flag]" == "0"}
    {
      #VAR {mip[FFF][flag]} {$i};
      #VAR {mip[FFF][$i]} {};
      #VAR {mip[FFF][$i][data]} {};
    }
    {
      #IF {"$i" == "~"}
      {
        #IF {"$mip[FFF][toggle]" == "0"}
        {
          #VAR {mip[FFF][toggle]} {1};
        }
        {
          .aMipProcessFFFSub {$mip[FFF][flag]} {$mip[FFF][${mip[FFF][flag]}][data]};
          #VAR {mip[FFF][flag]} {0};
          #VAR {mip[FFF][toggle]} {0};
        };
      }
      {
        #VAR {mip[FFF][${mip[FFF][flag]}][data]} {${mip[FFF][${mip[FFF][flag]}][data]}${i}};
      };
    };
  };
  #IF {"$mip[FFF][$mip[FFF][flag]][data]" != ""}
  {
    .aMipProcessFFFSub {$mip[FFF][flag]} {$mip[FFF][${mip[FFF][flag]}][data]};
    #NOP event_raise {e_mip_FFF_${mip[FFF][flag]}} {$mip[FFF][${mip[FFF][flag]}][data]};
  };
};

#NOP ***** Separated Stats Data *****;
#ALIAS {.aMipProcessFFFSub}
{
  #NOP %1;
  #SWITCH {"%1"}
  {
    #CASE {"A"} {#NOP Hit Points;#FORMAT {my[hp][current]} {%d} {%2};};
    #CASE {"B"} {#NOP Hit Points Maximum;#FORMAT {my[hp][max]} {%d} {%2};};
    #CASE {"C"} {#NOP Spell Points;#FORMAT {my[sp][current]} {%d} {%2};};
    #CASE {"D"} {#NOP Spell Points Maximum;#FORMAT {my[sp][max]} {%d} {%2};};
    #CASE {"E"} {#NOP Guild Points1;#FORMAT {my[gp1][current]} {%d} {%2};};
    #CASE {"F"} {#NOP Guild Points1 Maximum;#FORMAT {my[gp1][max]} {%d} {%2};};
    #CASE {"G"} {#NOP Guild Points2;#FORMAT {my[gp2][current]} {%d} {%2};};
    #CASE {"H"} {#NOP Guild Points2 Maximum;#FORMAT {my[gp2][max]} {%d} {%2};};
    #CASE {"I"} {#NOP Primary Guild Line;.aMipProcessGline {%2};};
    #CASE {"J"} {#NOP Secondary Guild Line;.aMipProcessGline {%2};};
    #CASE {"K"} {#NOP Mob Fighting;.aMipProcessFFFK {%2};};
    #CASE {"L"} {#NOP Mob Health;#FORMAT {opponent[hp]} {%d} {%2};};
    #CASE {"M"} {#NOP Mob Image File;};
    #CASE {"N"} {#NOP Combat Round Counter;};
    #DEFAULT {#NOP Every other non-handled flag;};
  };
};

#NOP ***** Combat Mob Name *****;
#ALIAS {.aMipProcessFFFK}
{
  #NOP %1;
  #IF {"%1" != ""}
  {
    #VAR {opponent} {};
    #VAR {opponent[longname]} {%1};
    #NOP event_raise e_combat {%1};
  }
  {
    #VAR {opponent[hp]} {};
  };
};

#NOP ***** Guild Stats Line 1/2 *****;
#ALIAS {.aMipProcessGline}
{
  #NOP %1;
  #VAR {temp} {};
  #IF {"%1" != ""}
  {
    #VAR {temp[gline]} {%1};
    #REPLACE {temp[gline]} { } {;};
    #FOREACH {$temp[gline]} {i}
    {
      #IF {"$i" != ""}
      {
        #REGEX {$i} {{^(\<\w{1}|)(.+)\:(.+?)(%|)(X\>|>|)$}}
        {
          #VAR {mip[gline][&3]} {&4};
        };
      };
    };

  };
  #NOP #SHOWME @fMipColourConv{{%1}};
  #NOP event_raise e_mip_gline;
};

#NOP ***** 2 Way Communication (Tell/Emote) *****;
#ALIAS {.aMipProcessBAB}
{
  #NOP %1;
  #REGEX {%1} {{(.*)\~(.*)\~(.*)}}
  {
    #IF {"&3" != "0"}
    {
      #IF {"&2" == "x"}
      {
        #NOP Message to another player;
        #NOP event_raise e_message {[&3]>&4} {message} {me} {&3} {%1};
      }
      {
        #NOP Message from another player;
        #NOP event_raise e_message {[&3]<&4} {message} {&3} {me} {%1};
      };
    };
  };
};

#NOP ***** Broadcast Communication (Chat/Shout) *****;
#ALIAS {.aMipProcessCAA}
{
  #REGEX {%1} {{(.*)\~(.*)\~(.*)\~(.*)}}
  {
    #VAR {temp[Data]} {};
    #VAR {temp[Data][player]} {&4};
    #VAR {temp[Data][command]} {&2};
    #VAR {temp[Data][line]} {&3};
    #NOP event_raise e_message {&5} {chatline} {&4} {&2 - &3} {$temp[Data]};
    #VAR {temp} {};
  };
};

#NOP ***** Guild Stats Line Colour Handling *****;
#FUNCTION {fMipColourConv}
{
  #VAR {result} {%1};
  #REPLACE {result} {>} {<099>};
  #REPLACE {result} {<y} {<839>};
  #REPLACE {result} {<r} {<819>};
  #REPLACE {result} {<b} {<849>};
  #REPLACE {result} {<g} {<829>};
  #REPLACE {result} {<c} {<869>};
  #REPLACE {result} {<v} {<859>};
  #REPLACE {result} {<s} {<279>};
};

#CLASS {cMip} {close};

Further detail on the MIP data/script

When the script is loaded, a random 5 digit MIP ID is generated and sent to the mud to start MIP message transmission. As MIP messages are received (embedded within the normal text coming out of the mud), they are captured by identifying the MIP ID and gagged. If the captured line is containing a MIP message is longer than the specified length of the MIP message, the outstanding section at the end is echoed back out untouched (Tintin automatically re-parses text that is output with #SHOWME, so any more MIP messages within the same line will be caught on subsequent passes).

The 3 letter line code is extracted from the message, and the rest of the data is passed to the alias set up for that code. In the case of FFF datalines, the data is then re-processed and passed down to sub-aliases for each further FFF subtype. Most of these line code types (and FFF subtypes) are currently empty, but a few of the key ones (like HP, SP, guild points, chat lines etc) have code in them currently. To identify which 3 letter code specifies what refer to the MIP Spec.

Example:
#K%00005008AAC12:46> Hello world

The line is recognised as containing MIP by the section "#K%00005" (has to match the held MIP ID) and the entire line is gagged.
The next 3 characters after the MIP ID specify that the MIP data content is 008 characters long, which leaves "AAC12:46" as the data and "> Hello world" as extra non-mip stuff.
The extra non-mip stuff is output back to the screen, and the strings "AAC" (the first 3 letters of MIP data are always the flag showing what type of data it is) and "12:46" are sent to the alias "aMipProcessFlag" for further processing.

In this case, it would record "12:46" into the variable $session[RebootTime]

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License