Problem with arrays and structs - copying to a shared array

Started by bspeers, Sun 31/07/2005 22:15:43

Previous topic - Next topic

bspeers

Okay, I'm working on this project right now where I have a bunch of stats recorded in a struct/array and I want to copy them all instantly to an array that uses the same stats, but I don't know how.

Although my knowledge of the terms is not exactly ideal, I can give a general idea.  Basically, I have a struct MyStatsStruct and arrays mychar[30] and battchar[10].

In a battle, the battchar stats act as dummies, allowing the characters to be in a different order and allowing some automation of functions.

So, let's say MyStatsStruct includes the properties hp, hpmax, spdmax, spd, sp, spmax, etc.  I first check which characters are first, second, third and fourth in the roster, and then set the stats of each dummy to that of the corresponding character using aditional "id" property.

So, for example, if battchar[1].id = 4, then I set battchar's hp hpmax, and so on to be equal to mychar[4].

Well, I can do this manually so that each of the 40 stats or so is copied from mychar to battchar accordingly, but this is going to be very unweildy very quickly.  Both arrays already share the same struct.  battchar has properties .hp, .hpmax, .sp, .spmax etc, as does mychar.

What I am looking for is a way to copy all of the stats from one array to another that shares the same properties.  I can only see it in dos language, but there it would look like:

battchar[1].* = mychar[4].*;

Is this possible?  How can I accomplish this, and am I even going about it in a way that AGS will interpret correctly?

Thanks :)
I also really liked my old signature.

monkey0506

Short answer:  No (not directly).


Long answer:

You could create a function to the effect of:

Code: ags
function MyStatsStruct::SetBattChar(int mychar_index) {
  int temp = 0;
  bool break = false;
  while ((temp < 10) && (!break)) {
    if (this != battchar[temp]) temp++;
    else break = true;
    }
  if (temp == 10) return; /* only call this function on battchar array items! */
  if ((mychar_index < 0) || (mychar_index >= 30)) return; /* mychar_index invalid */
  this.hp = mychar[mychar_index].hp;
  this.hpmax = mychar[mychar_index].hpmax;
  this.sp = mychar[mychar_index].sp;
  this.spmax = mychar[mychar_index].spmax;
  this.spd = mychar[mychar_index.spd;
  this.spdmax = mychar[mychar_index].spdmax;
  /* etc. */
  }


Make sure to place an import into you struct definition:

Code: ags
struct MyStatsStruct {
  /* stuff */
  import function SetBattChar(int mychar_index);
  /* stuff */
  }


And then you can call it like:

Code: ags
battchar[1].SetBattChar(4);


Which will set battchar[1]'s stats to those of mychar[4].  Not as simple as you had hoped, but it should work.  Also, in case you didn't pick up on it, if you try to do something like any of the following, nothing will happen:

Code: ags
/* NOTHING IS DONE BY ANY OF THESE */
mychar[5].SetBattChar(3);
battchar[3].SetBattChar(30);
battchar[5].SetBattChar(-1);
/* NOTHING IS DONE BY ANY OF THESE */


Edit:  Also, you could change "function" to "bool" and then you could test whether or not anything was done by changing the lines:

Code: ags
  if (temp == 10) return; /* only call this function on battchar array items! */
  if ((mychar_index < 0) || (mychar_index >= 30)) return; /* mychar_index invalid */


To:

Code: ags
  if (temp == 10) return false; /* only call this function on battchar array items! */
  if ((mychar_index < 0) || (mychar_index >= 30)) return false; /* mychar_index invalid */


And then at the end of the function put:

Code: ags
return true;


That way you could find out whether it was set with a statement like:

Code: ags
if (battchar[1].SetBattChar(4)) Display("battchar[1] is now set to mychar[4]!");
else Display("battchar[1] not changed!  error in script!");

bspeers

Okay, thank you.  I'm still somewhat ignorant of the terms though, and was wondering if you could clarify.  I think I see how this works, but just need a little hand holding.

What does "bool" refer to here.  I can't find an explanation in the manual.  I assume it stands for "boolean" but don't know if I "have" to use it for any particular reason.

Where does the "break" come from?  I don't know its application here or what it does, and again, can't find it in the manual at all.

Also, what is meant to go in place of the word "this"?

What does the line "if (temp == 10) return;" do? I have never used "return" as a command and there doesn't seem to be any declaration of it -- what does it do?

Otherwise, I think I understand how this function works and can implement it.

Thanks!
I also really liked my old signature.

monkey0506

Edit:  AGS versions 2.7 and higher

"bool" is a built in type of AGS versions 2.7 and higher.  It can contain the following values:

false (or 0)
true (or 1)

Yes, it is a boolean type, but the keyword is "bool".  "break" is not a built-in keyword of AGS, I just used it as a boolean flag to figure out whether the item you called the function from (i.e., battchar[1]) is a member of the battchar array, because if it is not, then the function will not do anything.

"this" is a keyword of AGS versions 2.7 and higher.  It is a readonly pointer (which means that it points to an object of the type of the struct; in this case "this" is the item the function was called upon (i.e., battchar[1]).

[Edit: All versions of AGS]

"return" is a keyword that causes the function to end, returning the value specified.  If no value is specified (i.e., "return;") then nothing is returned.

Also, "function" is defined within AGS as "int".  When you define a function, it is laid out as follows:

func_return_type   func_name([func_parameters [, ...]])

func_return_type is the type that will be returned by the function.  If you use the keyword "function" then the function will be capable of returning integer values.  So:

Code: ags
function myfunc() {
  return 1;
  } /* returns 1 to the script (i.e., int myvar = myfunc(); would set myvar to 1 */


And:

Code: ags
int myfunc() {
  return 1;
  } /* returns 1 to the script (i.e., int myvar = myfunc(); would set myvar to 1 */


Are effectively the same.  I said that you could change the word "function" to "bool", making the return type "bool" (a boolean value) so that you could test if it would affect the item you called it upon.[/Edit back to AGS 2.7 and higher]

  @about "return":  Here I have tested to see that the object you called the function from was a member of the battchar array, so that you can't change the values of mychar items with this function.  If you call it from a mychar item (i.e., mychar[5].SetBattChar(3)) then this test will cause the function to return, not doing anything.

You could use this function in place of the above:

Code: ags
bool MyStatsStruct::SetBattChar(int mychar_index) {
  int temp = 0;
  bool break = false;
  while ((temp < 10) && (!break)) {
    if (this != battchar[temp]) temp++;
    else break = true;
    }
  if (temp == 10) return false; /* only call this function on battchar array items! */
  if ((mychar_index < 0) || (mychar_index >= 30)) return false; /* mychar_index invalid */
  this.hp = mychar[mychar_index].hp;
  this.hpmax = mychar[mychar_index].hpmax;
  this.sp = mychar[mychar_index].sp;
  this.spmax = mychar[mychar_index].spmax;
  this.spd = mychar[mychar_index.spd;
  this.spdmax = mychar[mychar_index].spdmax;
  /* etc. */
  return true;
  }


Then, as I mentioned before, you can do something like:

Code: ags
if (battchar[1].SetBattChar(4)) Display("battchar[1] is now set to mychar[4]!");
else Display("battchar[1] not changed!  error in script!");


Which will test to see if the item was changed and display output accordingly.  You have to replace the above function with this one for this test to work though.

I hope I have explained myself well enough.  And good luck with AGS!


Also, I don't believe I mentioned it (except in explaining some of the keywords), but this code is based on some things only available to AGS 2.7 and higher.  So if you are using an older version of AGS you will have to upgrade to use this function.

Edit:  If you are using AGS version 2.62 or earlier

If using 2.62 or earlier then you could use the following code:

Code: ags
int SetBattChar(int battchar_index, int mychar_index) {
 
  if ((battchar_index < 0) || (battchar_index >= 10)) return 0; /* only call this function on battchar array items! */
  if ((mychar_index < 0) || (mychar_index >= 30)) return 0; /* mychar_index invalid */
  battchar[battchar_index].hp = mychar[mychar_index].hp;
  battchar[battchar_index].hpmax = mychar[mychar_index].hpmax;
  battchar[battchar_index].sp = mychar[mychar_index].sp;
  battchar[battchar_index].spmax = mychar[mychar_index].spmax;
  battchar[battchar_index].spd = mychar[mychar_index.spd;
  battchar[battchar_index].spdmax = mychar[mychar_index].spdmax;
  /* etc. */
  return 1;
  }


In 2.62 and previous you can't have member functions of structs, so it has to be a global function.  Then you can make use of the function like this:

Code: ags
if (SetBattChar(5, 23)) Display("battchar[5] is now set to the values of mychar[23]!");
else Display("battchar[5] unaffected!  error in script!");


But note that this is for AGS 2.62 and previous because it's a lot easier and nicer to have it as a member function (imported into the struct) than to have it cluttering up your global script.

bspeers

Thank you, that should be all I need to solve this particular problem.  Very informative.  I still don't understand a damned word of it, but as usually happens, once I start implementing the code myself, it shoud all make sense :)

Thanks a lot, I'm sure I can build a function that works now :D.
I also really liked my old signature.

monkey0506

You're very much welcome.  I'm sorry if I didn't explain myself well enough...I have a thorough understanding of what these things are and how they work, so I guess I just took it for granted that you would too.  Glad to hear that you should be able to get a working function out of it though.  Let me know if any problems arise. ;)

SMF spam blocked by CleanTalk