GameMaker: Multi-version argument_count

If you are using an outdated (8.0 or earlier) version of GameMaker, and are trying to utilize examples and snippets from more recent versions, or creating systems that are intended to work correctly across multiple versions, this is going to be useful.

Method

There are two primary methods of detecting argument count in pre-8.1 version, being ascending and descending loop.
Obviously,

Descending loop

This is a preferred method of finding number of arguments. Code is as follows:
var argc;
if (gamemaker_version < 810) {
    var v, c; c = 15
    repeat (16) {
        v = argument[c]
        if (is_string(v)) break
        if (v != 0) break
        c -= 1
    }
    argc = c + 1
} else argc = argument_count
... or a more compact version, if you're going to use if often:
var argc; if (gamemaker_version < 810) { var v; argc = 15; repeat (16) {
v = argument[argc]; if (is_string(v)) break; if (v != 0) break; argc -= 1
}; argc += 1 } else argc = argument_count
So, what's going on in there:
  • Variable “argc” is defined. This is later to be used instead of argument_count to determine number of arguments.
  • An “if” branch follows, depending on GameMaker version. Despite of what one would've thought, version numbers are actually 800 and 810 (no other options - constant has been added in 8.0 and went missing in GameMaker: Studio). For later versions, detection is pretty trivial, being assignment of argument_count to a variable.
  • A slightly strangely looking repeat-loop is intended to loop through values [16, 15, 14, ..., 2, 1, 0].
  • At each iteration, next argument is pulled by index, and check is performed - if it's either a string (default value for arguments is 0, number) or a non-zero number, program “breaks out of loop”.
  • Argument number “argc” variable is set to value, one larger than last valid index (if argument[2] was non-zero, there were 3 arguments).
This method works faster when given many arguments, and it's results are reliable (it will miss if last argument is zero, however there's no way to avoid that case, as far as I know).

Ascending loop

This is a slightly different method of achieving the same goal. It wins some extra (probably not so meaningful on it's scale) performance at expense of a flaw:
var argc;
if (gamemaker_version < 810) {
    var v; argc = 0
    repeat (16) {
        v = argument[argc]
        if (is_real(v)) if (v == 0) break
        argc += 1
    }
} else argc = argument_count
It works similarly to above method, with exception of looping 'upwards' [0, 1, 2, ..., 13, 14, 15], and having slightly different exit condition.
Looping from first argument, it will perform less iterations than first method, if script is given only a few arguments.
It's flaw is, that if a zero argument is passed “in the middle” of argument list, it will stop at that point, thus loosing further arguments.
Though, if it is certain that such conditions will be satisfied, and number of arguments is kept low (e.g. script takes 3-5 strings), this will work faster than descending loop.

Usage

Extra variable

This is method of usage, illustrated in both of examples above. Going this way, you need to replace all occurrences of “argument_count” by “argc”. Such can take some time, but is a preferred method.

If you are porting a script from version 8.1 to an earlier version, you can as well just replace “argc” by “argument_count”, and throw out “else” branch of condition.
And there's even a few ways of doing that, each with it's own pros and cons.

Overriding “instance” variable

After doing replacement, mentioned above, you can as well leave it as-is. This allows to simplify process to copying & pasting code into start of each of affected scripts, at expense of “argument_count” variable “leaking” into instances, and possibly affecting forgotten code that uses it.

Global variable

Issue with extra variables in above method can be solved by making variable “argument_count” global. A downside here is, that declaration line will cause an error in >= 8.1, requiring it to be removed manually.

Local variable

This method involves declaring “argument_count” as a local variable, “var”, and will actually get scripts compatible while still keeping modification process simple. However, a problem comes - alike to global variables, declaration will have to be removed for >= 8.1... except this time it will need to be removed separately in every affected script.

Pre-8.0 versions

It may not be obvious, but to work-around the fact that versions, prior to GameMaker 8.0, did not have a gamemaker_version constant, you can just make your own (a constant, or globalvar).

Example of usage

As an example of usage, a script, that uses first method to display all given arguments in a message, follows:
/// show_values(...values)
// Displays a message, listing all given values
var argc;
if (gamemaker_version < 810) {
    var v, c; c = 15
    repeat (16) {
        v = argument[c]
        if (is_string(v)) break
        if (v != 0) break
        c -= 1
    }
    argc = c + 1
} else argc = argument_count
//
if (argc == 0) return show_message('(no values given)') // no arguments
var i, r;
r = string(argument[0]) // first argument
for (i = 1; i < argc; i += 1) { // other arguments
    r += ', ' + string(argument[i])
}
return show_message('[' + r + ']')

Related posts:

5 thoughts on “GameMaker: Multi-version argument_count

  1. Maybe this way? But I don’t know if it’s a good idea…

    First we can create a constant with a value that indicates the end of the check:
    null (chr(0)+chr(0))

    And then, at the beginning of every script that requires argument_count, we put this:
    var argument_count, v, c;
    c = 0;
    repeat (16) {
    v = argument[c];
    if ( string(v) != null ) { c += 1; }
    else
    { break; }
    }
    argument_count = c;

    The tedious thing is that we should place our constant at the end of the script that requires it:
    a = script…(34,67,0,”Felicia”,noone,null) //return 5
    b = script…(chr(127),0,”Cat”,null) //return 3
    c = script…(chr(0),chr(32),2,3,4,5,6,7,8,9,10,11,12,13,14,15) //return 16
    d = script…(null) //return 0

    • That would maybe work, much like passing the argument count number manually

      I think at this time the real question would be whether you would really need to support a 10-year-old version of GM for your scripts.

      • It’s nothing serious, it’s a way to kill time and remember or (exhume) old times. Haha! Thank you for answering!

  2. To differentiate a zero value from an empty argument, you can replace this line: if (v! = 0) break, for this one: if (frac (v)) break. I think…

    • I’m not sure if that would have the desirable effect – frac(x) returns the fractional part of x, and GM evaluates number truth-ness as (x > 0.5) so that condition would yield false for values such as 1.1 (and true for 1.6)

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.