Function help - Converting string variable to character name [SOLVED]

Started by WHAM, Sun 17/01/2010 13:56:50

Previous topic - Next topic

WHAM

It's me again!

I want to do something like the following:

Code: ags

// This code is in the global script file

function Shootcharacter (string charname) {
  charname.FaceCharacter(cEgo); 
  // What I want AGS to see in this example is: "cStrangeman.FaceCharacter(cEgo);"
  // What AGS sees, is a string variable being ordered to FaceCharacter, which is just impossible.
  charname.Say("No, don't shoot me!");
  cEgo.Animate(8, 3, eNoBlock);
  charname.Animate(8, 3, eBlock);
}


Code: ags

// This code can be called on any character in the game
Shootcharacter(cStrangeman);


However: I cannot use the value of the string as the character's script name when running the script and get the error "Animate is not a public member of string". How do I convert the string so that the script recognizes it? Or can I just bring the character's name into the function somehow?

Thanks in advance!
Wrongthinker and anticitizen one. Utterly untrustworthy. Pending removal to memory hole.

Dualnames

Solution 1
Code: ags

// This code is in the global script file

function Shootcharacter (this Character*) {//See extender functions 

  this.Say("No, don't shoot me!");
  cEgo.Animate(8, 3, eNoBlock);
 this.Animate(8, 3, eBlock);
}


Code: ags

// This code can be called on any character in the game
cStrangeman.Shootcharacter();





Solution 2

Code: ags

// This code is in the global script file

function Shootcharacter (Character *chartobeshot) {//See extender functions 

  chartobeshot.Say("No, don't shoot me!");
  cEgo.Animate(8, 3, eNoBlock);
 chartobeshot.Animate(8, 3, eBlock);
}


Code: ags

// This code can be called on any character in the game
Shootcharacter(cStrangeman);


Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

WHAM

Solution 2 gives me a "Cannot declare pointer to non-managed type" error.
Wrongthinker and anticitizen one. Utterly untrustworthy. Pending removal to memory hole.

Dualnames

Quote from: WHAM on Sun 17/01/2010 14:57:42
Solution 2 gives me a "Cannot declare pointer to non-managed type" error.

It should work fine. On which line do you get the error?
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

WHAM

Oh, drat! It works now, I just had a typo in the line!

Now that I have this:

Code: ags

function Shooty (Character*chartobeshot) {


How do I bring, say, another boolean variable into the the same function?
Or if I need to bring several different variables from the execute command to the function? (Like: target character, target ammo and a few others)
Wrongthinker and anticitizen one. Utterly untrustworthy. Pending removal to memory hole.

Dualnames

Code: ags

function Shooty (Character*chartobeshot, bool var, int ammo, Character*target){
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Lufia

You put commas between the different arguments.

function myFunction(int a, bool b, Character* c) {
blah blah blah
}

That makes me wonder how you'd do optional arguments.

Dualnames

Quote from: Lufia on Sun 17/01/2010 15:55:55
You put commas between the different arguments.

function myFunction(int a, bool b, Character* c) {
blah blah blah
}

That makes me wonder how you'd do optional arguments.

When you declare the function:

import function myFunction(int a=1, bool b=true, Character* c);
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Lufia

That's specifying default values, not making the arguments optional. I know in Ruby I can make a function take a pointer to an array as an argument, without said array having a fixed size. Then my function can take a variable number of arguments without having to specify any default values. I wondered if there was an equivalent in AGS scripting.

Khris

Quote from: Lufia on Sun 17/01/2010 16:06:46
That's specifying default values, not making the arguments optional.

Yes it is. The optional arguments have to be the last ones in the declaration though.

Dualnames

Quote from: Khris on Sun 17/01/2010 16:11:23
Quote from: Lufia on Sun 17/01/2010 16:06:46
That's specifying default values, not making the arguments optional.

Yes it is. The optional arguments have to be the last ones in the declaration though.
Quote from: Dualnames on Sun 17/01/2010 15:59:28
Quote from: Lufia on Sun 17/01/2010 15:55:55
You put commas between the different arguments.

function myFunction(Character* c,int a, bool b) {
blah blah blah
}

That makes me wonder how you'd do optional arguments.

When you declare the function:

import function myFunction(int a=1, bool b=true, Character* c);

-Right, Khris is absolutely correct. Supplying a default value, means you don't have to set the value of the integer (therefore optional).
Worked on Strangeland, Primordia, Hob's Barrow, The Cat Lady, Mage's Initiation, Until I Have You, Downfall, Hunie Pop, and every game in the Wadjet Eye Games catalogue (porting)

Khris

Thus the import line is supposed to look like this:
import function myFunction(Character*c, int a=1, bool b=true)
This can now be called thusly:

- myFunction(player);
- myFunction(player, 2);
- myFunction(player, 5, false);

WHAM

Wrongthinker and anticitizen one. Utterly untrustworthy. Pending removal to memory hole.

monkey0506

#13
It's presently possible in AGS to make a parameter of any type optional by specifying a default value except float. For bool, char, short, int, or enumerated type parameters you can specify the literal value such as:

Code: ags
import function my_func(int param=127);
import function other_func(bool something=false);


In order to make a parameter optional you must provide a default value and you must place all required parameters first.

If you were to take the example Dualnames gave:

Code: ags
import function myFunction(int a=1, bool b=true, Character* c);


Despite there being 2 parameters with default values given, since they are followed by a parameter that does not have a default value this function has no optional parameters. In order to call this function you would have to provide a value for every single parameter.

As Khris showed this can be resolved by placing the required parameters first, which makes the parameters with a default value optional.

As for String and pointer-type parameters in this instance you can substitute the literal value of 0 (zero) in place of null. This is the only default value that can be given to a pointer. For example:

Code: ags
import function myFunction(int a=1, bool b=true, Character* c=0);

function myFunction(int a, bool b, Character* c) {
  if (c == null) { // the player did not specify a character
    c = player; // default to the player character
  }
}

myFunction(); // this is the same as calling myFunction(1, true, null);
// which in turn is treated the same as myFunction(1, true, player);


Strings work the same way:

Code: ags
import function my_func(String optionalString=0);

function my_func(String optionalString) {
  if (optionalString == null) optionalString = "";
}

my_func(); // is the same as my_func(null);
// which is treated the same as my_func("");


Using 0 in place of null is a workaround and isn't technically considered "officially supported". No such workaround presently exists for floating-point parameters which must always be passed as required parameters.

Oh, and one last note. It's possible to define an optional parameter for a local function by putting the import in the same script as the function definition (above the function definition). The import does not have to be in a header, but if it's not then it won't be globally accessible. So:

Code: ags
// GlobalScript.asc

import function my_local_func(int someVal=0); // NOTE: Still within GlobalScript.asc!! not the header ASH file

function my_local_func(int someVal) {
  // ...
}

my_local_func();


All within the same script provides optional parameters (with default value) without making the function globally accessible. :)

Edit: Also, in response to the original post...there's actually a fun little undocumented Character.scrname property which will return the script name (such as "cEgo"). So you could do something like:

Code: ags
Character* GetCharacterByName(String name) {
  if (String.IsNullOrEmpty(name)) return null;
  if (name == "player") return player; // if looking for the player character
  if (name.Chars[0] != 'c') name = String.Format("c%s", name); // if the given NAME does not start with 'c', add it
  int i = 0;
  while (i < Game.CharacterCount) {
    String cname = String.Format("%s", character[i].scrname); // we MUST use formatting to get this in String format, it's actually stored in a char*
    // which is actually fun considering you CANNOT create a char* in AGS :D
    if (name == cname) return character[i]; // consider using String.CompareTo if you want to make it case-insensitive
    i++;
  }
  return null;
}

function Shootcharacter(String charname) {
  Character *thechar = GetCharacterByName(charname);
  if (thechar == null) return; // abort if character not found or invalid name given
  thechar.FaceCharacter(cEgo); 
  thechar.Say("No, don't shoot me!");
  cEgo.Animate(8, 3, eNoBlock);
  thechar.Animate(8, 3, eBlock);
}

ShootCharacter("Ego"); // commit suicide? :D


So the original request wasn't as impossible as you thought. :)

Lufia

I don't think I was explaining myself very clearly, so I'll give a concrete example in Ruby.
There is a Bitmap class which can either load an image from the cache or draw a box in which to draw text or images, and stuff. To create a new bitmap object, you do it like that :
@mysprite = Bitmap.new
with @mysprite being an instance of the Bitmap class.

Now, the new funtion of the bitmap class either takes one or two arguments :
Code: ags
@mysprite = Bitmap.new(filename) # Load an image from the cache
@mysprite = Bitmap.new(width, height) # Draw an empty box

width and height are integers, filename is a filename. new isn't defined by putting default values in a list of arguments. It's defined something like that :

Code: ags
class Bitmap # start class definition
  def new(*args) # start method definition
    if args.size == 1 # If there is only one argument
      # Go get image
    elsif args.size == 2 # If there are two arguments
      # Draw box
    end
  end
end


That's useful to create stuff dynamically without having to specify a fixed number of elements, for example.
Come on, that's stuff used in RPG Maker, there has to be an equivalent here. :p

Oh, thanks for the tip about using 0 as a replacement for null, monkey.

Khris

I know, being able to do that is common for pretty much every o-o language, not for AGS though.
One can work around that of course using e.g.

Code: ags
import function CreateBitmap(String filename, int width = 0, int height = 0);

function CreateBitmap(String filename, int width, int height) {
  if (filename.Length) {
    // load file
  }
  else {
    use width & height parameters instead
  }
}


One reason is probably that with AGS, one practically never creates something dynamically.
So including this would be for cosmetic reasons only and I don't think that justifies the huge amount of compiler-related work that would have to go into that.

Lufia

QuoteOne reason is probably that with AGS, one practically never creates something dynamically.
Eh. Fair enough. I was jusk asking out of curiosity.

Well, thanks.

monkey0506

What you're referring to Lufia is technically what's called overloading which AGS only supports in a very limited number of cases.

To be precise you can overload functions (in AGS) only:

1. When using an extender method, AND

2a. Defining a function for a managed or user-defined type that does not already exist (for that type), or
2b. Defining a function for a managed or user-defined type that inherits a function with the same name from a base class.

So it's a pretty limited set, but you could create functions for Character, GUI, and Object all named FadeIn and FadeOut.

Option 2b is what's called polymorphism and it would allow you to define a function for the GUIControl class and then overload it for each of the derived classes. The derived overloads would be optional as the derived classes would inherit the function from the GUIControl class. However, the derived classes could also have their own parameter lists, completely differentiating them from the base class method.

Wikipedia has more on all this stuff, but those are the terms under which you can overload functions in AGS. ;)

SMF spam blocked by CleanTalk