Basic HTML5/GMCP questions!

Hi folks,

I'm tied to the new client as it's the only one I can use from work, and I'm trying to start some basic scripting.  I'll probably have a bunch of idiot questions, but I fell at the final hurdle when trying to script my first thing.  I can't seem to access gmcp variables properly.  To test it out, I made a test thing which did this: client.send_direct(print(gmcp.Char.Afflictions.List))

But when I do that, I get "ReferenceError: 'gmcp' is undefined" so I'm guessing I'm not using the right syntax to call gmcp variables.  What am I doing wrong?



  • KlendathuKlendathu Eye of the Storm
    gmcp.Char.Afflictions.List doesn't exist until you diagnose. Test with something that's always present, eg


    Tharos, the Announcer of Delos shouts, "It's near the end of the egghunt and I still haven't figured out how to pronounce Clean-dat-hoo."
  • I get the same error message even if I have diagnosed, or if I use gmcp.Char.Vitals.  Help?
  • KlendathuKlendathu Eye of the Storm
    I don't use the HTML5 client, but at least you know it's your query that's malformed!

    Tharos, the Announcer of Delos shouts, "It's near the end of the egghunt and I still haven't figured out how to pronounce Clean-dat-hoo."
  • MishgulMishgul Trondheim, Norway
    edited May 2015
    Your scripts in html won't receive gmcp like that, you'll receive an "args" object with two variables, one with the name of the gmcp being called,a nd the other with all the argms of the gmcp object. something like args.gmcp_name and args.gmcp_args I think. I will msg you in game. 

    You'll specifically receive gmcp events in the "onGMCP" script that is already in there I believe. So I would do my GMCP organising in that script, and then put all the args into variables that you will use in other scripts.


    One of the symptoms of an approaching nervous breakdown is the belief that one's work is terribly important

    As drawn by Shayde
    hic locus est ubi mors gaudet succurrere vitae
  • edited May 2015
    There are two things you can do with GMCP:
    1. Send GMCP requests via send_GMCP(request); like send_GMCP("Char.Skills.Get");
    2. Review GMCP messages sent to you by looking at args.gmcp_method and args.gmcp_args
    client.send_direct(print(gmcp.Char.Afflictions.List)); doesn't make any sense - first, Char.Afflictions.List isn't a thing you can send, it's a thing the server sends you when you diagnose.

    But, more importantly, client.send_direct(print(anything)); will never work, for anything, ever. I'm not really sure what you're trying to do with that. print(string); outputs text to the client, while client.send_direct(string); sends commands to the game server. And since print(string); doesn't return anything, there's nothing to send. It looks like you're trying to do two opposing things at once and I'm not really sure what your intention is.

    As for how to do GMCP:

    First, Keneanung has a lovely github page that documents all the GMCP stuff:

    If you want to send a GMCP request, you need to use send_GMCP(request); like send_GMCP("Char.SKills.Get"); and this will only work for the things in that github page marked "Sent by Client".

    If you want to look at the GMCP messages the game is sending to you, you need to put a script into an onGMCP "function" (this is a special "function" that runs every time the client receives a GMCP message from the game server). Whenever the client receives a GMCP message, it saves the type of the message (e.g., "Char.Afflictions.List") in args.gmcp_method, and saves the details of the GMCP message as an array of (potentially nested) objects in args.gmcp_args.

    Since Char.Afflictions.List is longer, it's not a great example since you'll have to loop through it to print everything, so for the sake of simplicity, let's first look at Char.Afflictions.Add, the GMCP message you'll get when you get an affliction. If you want to print all the details from every Char.Afflictions.Add GMCP message, your onGMCP would look like this:
    if (args.gmcp_method === "Char.Afflictions.Add") {
        print("Name: " +;
        print("Cure: " + args.gmcp_args.cure);
        print("Desc: " + args.gmcp_args.desc);
    We have to wrap it in that if because onGMCP runs on every GMCP message, but we're only interested in the data in Char.Afflictions.Add - if you want to look at another GMCP message too, you just slap another else if clause onto the end, so you can run something when args.gmcp_method is equal to whatever other GMCP message you care about.

    If you wanted to print the whole Char.Afflictions.List thing, instead of an object with name, cure, and desc properties, that gives you an array of those objects, one for each affliction, so if you want to print the whole thing you need to iterate through the array with some sort of loop. So that could look something like this:
    if (args.gmcp_method === "Char.Afflictions.List") {
            function (element) {
                print("Name: " +;
                print("Cure: " + element.cure);
                print("Desc: " + element.desc + "\n\n");
    Here I'm using forEach, but if you aren't familiar with that array method, you could also use a for-in loop, or even an explicit for loop using args.gmcp_args.length (i = 0, n = args.gmcp_args.length; i < n; i++), though then you have to actually look up the elements by index with something like print("Name: " + args.gmcp_args[i].name);

    Hope that helps.
  • Slight correction - it only returns an array in args.gmcp_args if there are multiple objects like in Char.Afflictions.List, it's just a single object in things like Char.Afflictions.Add (which is why you can do rather than having to do something like args.gmcp_args[0].name).
  • edited May 2015
    Thanks guys, that's hugely helpful.  I have a follow-up question - what I'm trying to script for my baby-steps first thing is a "cure-all" button for a priest.  So your reflex would, in plain English, do this: (i) diagnose, (ii) use priest healing to cure all afflictions that you have.

    I think I can do this by checking for each affliction in turn, and then doing a bespoke line for each affliction, like:

    1. for (var x in afflictions) {
    2. if ([x] === "agoraphobia" {
    3. client.send_direct("heal me " +[x])
    4. }
    5. }

    Kind of thing, and then just repeating that code for every healable affliction with else ifs and whatever.  (Carmain helped me set up the afflictions variable in onGMCP so that it is a copy of Char.Afflictions.List).  That seems super inefficient though, and ideally what I'd do is something that checked if[x] was on a list of healable affliction names, and if it was, then it would do "client.send_direct("heal me " +[x])".

    I'm coming up blank though on how to do that.  There's other wrinkles, of course, like not curing insomnia/blindness/deafness and I should be fine with that, but can anyone help with the list searching?

    Really appreciate the help!

    Edited to fix a stupid error above
  • You can create an array with the afflictions you want to have "autohealed" and then use the "indexOf()" method to find, if it is in the list. A full listing would be something like this:

    var curableAffs = ["agoraphobia", "stupidity", "anorexia" ] //Your affs go here. If you don't include blindness/deafness/insomnia, they won't be cured, too.
    for( var i in afflictions) { if(curableAffs.indexOf(afflictions[i].name) > -1){ client.send_direct("heal me " + afflictions[i].name); }

  • edited May 2015

    Thanks - this is super helpful.  I tweaked your suggestion @Keneanung, so now my code looks like this:

    1. var curableAffs = ["paralysis", "confusion", "slickness", "stuttering", "paranoia", "shyness", "hallucinations", "generosity", "loneliness", "impatience", "lapsingconsciousness", "claustrophobia", "vertigo", "sensitivity", "dizziness", "brokenarms", "dementia", "clumsiness", "burning", "recklessness", "anorexia", "agoraphobia", "disloyalty", "hypersomnia", "darkshade", "masochism", "epilepsy", "asthma", "stupidity", "vomiting", "weariness", "haemophilia", "brokenleftarm", "brokenrightarm", "brokenleftleg", "brokenrightleg", "hypochondria"];

    2. client.send_direct("diag me");
    3. for (var x in afflictions) {
    4.     if(curableAffs.indexOf(afflictions[x].name)) > -1){
    5.         if (curableAffs.indexOf(afflictions[x].name)) === "brokenleftleg") || (curableAffs.indexOf(afflictions[x].name)) === "brokenrightleg") {
    6.            client.send_direct("heal me brokenlegs");
    7.                 }
    8.        else if (curableAffs.indexOf(afflictions[x].name)) === "brokenleftarm") || (curableAffs.indexOf(afflictions[x].name)) === "brokenrightarm") {
    9.            client.send_direct("heal me brokenarms");
    10.                               }
    11.      else {   
    12.            client.send_direct("heal me " + afflictions[x].name);
    13.       }
    14.    }
    15. }



    But I'm getting a syntax error.  Anyone want to help me with where I went wrong?

  • KlendathuKlendathu Eye of the Storm
    elseif rather than else if?

    Tharos, the Announcer of Delos shouts, "It's near the end of the egghunt and I still haven't figured out how to pronounce Clean-dat-hoo."
  • No sir.  Neither works - isn't it "else if" for javascript tho?
  • TectonTecton The Garden of the Gods
    What's the syntax error you're getting? That'll help identify the problem
  • The only message I get is "SyntaxError: Syntax error"
  • If you count the number of parenthesis in your if statements, you'll see they are off. Also, why do you compare the index of the afflictions (which will be 0, 1, 2, ...) with "brokenrightarm"? You'll want to put your ifs like this:
    if(afflictions[x].name === "brokenrightarm" || afflictions[x].name === "brokenleftarm"){
  • It looks like you have a few problems with the parentheses. On line 4, if(curableAffs.indexOf(afflictions[x].name)) > -1) should be if(curableAffs.indexOf(afflictions[x].name) > -1), there's an extra closing parenthesis. Lines 5 and 8 have the same problem (twice on each line), and also need the entire condition to be enclosed in parentheses; what you have is basically "if (condition) || (condition)", it needs to be either "if ((condition) || (condition))" or "if (condition || condition)".
  • edited May 2015
    @Vansittart: If you highlight the code in your post and then click the little paragraph symbol you can format it as code (monospaced and with whitespace preserved). Then you don't have to put in line numbers by hand.

    There are quite a few syntax errors in your code (mostly involving extra parentheses). Here it is all cleaned up and formatted in a more conventional style. If you diff this and your code, I imagine you can probably figure out how the parentheses are supposed to work in javascript, but if you have any questions, feel free to ask.
    var curableAffs = ["paralysis", "confusion", "slickness", "stuttering", "paranoia", "shyness", "hallucinations", "generosity", "loneliness", "impatience", "lapsingconsciousness", "claustrophobia", "vertigo", "sensitivity", "dizziness", "brokenarms", "dementia", "clumsiness", "burning", "recklessness", "anorexia", "agoraphobia", "disloyalty", "hypersomnia", "darkshade", "masochism", "epilepsy", "asthma", "stupidity", "vomiting", "weariness", "haemophilia", "brokenleftarm", "brokenrightarm", "brokenleftleg", "brokenrightleg", "hypochondria"];
    client.send_direct("diag me");
    for (var x in afflictions) {
        if (curableAffs.indexOf(afflictions[x].name) > -1) {
            if (curableAffs.indexOf(afflictions[x].name) === "brokenleftleg" || curableAffs.indexOf(afflictions[x].name) === "brokenrightleg") {
                client.send_direct("heal me brokenlegs");
            } else if (curableAffs.indexOf(afflictions[x].name) === "brokenleftarm" || curableAffs.indexOf(afflictions[x].name) === "brokenrightarm") {
                client.send_direct("heal me brokenarms");
            } else {    
                client.send_direct("heal me " + afflictions[x].name);
    This shouldn't have any errors, but it's also not going to do a whole lot since all the stuff in your for loop is going to run before the gmcp messages that result from your "diag me" get to you.

    What you're probably going to want to do is put that loop into your onGMCP function behind a toggle variable.

    So initialize a variable like var curingAll = false; in your onLoad function (this is like onGMCP, but only gets run once, when you load your settings, so it's an ideal place to put variables - I doubt you'll see any difference in performance, but you probably want to define your curableAffs there too so you can avoid rebuilding the array every time you run this - and it wouldn't be a terrible idea to throw in var afflictions = []; either).

    Then you have an alias that just does client.send_direct("diag me"); and curingAll = true;

    Then you have your onGMCP function, which looks for Char.Afflictions.List and creates your afflictions array, and then also has your for-loop here right after that, but wrapped in if (curingAll) {}. And either before or after the loop (but inside the if block) you have curingAll = false;

    So what ends up happening is: onLoad sets curingAll to false when you load your reflexes (and also initializes your curableAffs array and declares your afflictions array), your alias to fully cure yourself sets curingAll to true and sends a diag request to the game, then your onGMCP function triggers off of the Char.Afflictions.List message, which fills your afflictions array with your current afflictions from the GMCP message, then since curingAll is true, you loop through afflictions and send a cure command for each one and also set curingAll back to false (so it doesn't auto-cure everything the next time you do a normal diagnose without using the alias).

    Also, in general is a useful tool for diagnosing the source of syntax errors. Though it'll throw some weird errors for things you probably don't care about too (it doesn't like that for-loop for instance because it would rather you use something like forEach).
  • @Tael @Sena @Keneanung

    That is so helpful, it really is.  You don't have to take time out your days to make my terrible scripts better and teach me as well - hugely appreciated.  No doubt, I'll be back later when I screw it up some more ;)

  • It works!  I did the toggle variable, and set things up as @Tael suggested, and it works!  Thanks again guys.
Sign In or Register to comment.