Creating a Struct [SOLVED]

Started by Atelier, Fri 29/05/2009 10:18:36

Previous topic - Next topic

Atelier

Hullo.

I'm using a list box GUI at the bottom to display everything the player looks at. It works fine, but the code that you have to write for it is long and will slow up the game if I have to do it for every hotspot. Here's the code I use at the moment:

Code: ags
function hHotspotX_Look ()
{
   int ran=Random(4);
   if (ran==0) {
      DisplayBox.ScrollDown();
      DisplayBox.AddItem ("You got the first phrase.");
}
   else if (ran==1){
      DisplayBox.ScrollDown();
      DisplayBox.AddItem ("You got the second phrase.");
}
   else if (ran==2){
      DisplayBox.ScrollDown();
      DisplayBox.AddItem ("You got the third phrase.");
}
   else if (ran==3){
      DisplayBox.ScrollDown();
      DisplayBox.AddItem ("You got the fourth phrase.");
}
   else if (ran==4){
      DisplayBox.ScrollDown();
      DisplayBox.AddItem ("You got the fifth phrase.");
   }
}


Like so. Now if I had to do this I'd need to enter all this (or copy and paste) for every single hotspot. Is there a way I can simplify it by making my own custom code? I've looked into structs but I don't know where to start.

Thanks.



Khris

It wouldn't slow down the game, only developing it, but nevermind that ;)

What you do is use a custom function. It doesn't need to return anything hence the "void".

Code: ags
//  directly above on_mouse_click

void hs_look() {
  int ran = Random(4);
  String s;
  if (ran == 0) s = "first";
  ...
  if (ran == 4) s = "fifth";
  DisplayBox.ScrollDown();
  DisplayBox.AddItem(String.Format("You got the %s phrase.", s));
}

Note how I considerably shortened your code by taking out duplicate lines.

Call this in the global script / on_mouse_click:

Code: ags
 // eMouseLeft
  if (button == eMouseLeft) {
    if (mouse.Mode == eModeLookat && GetLocationType(mouse.x, mouse.y) == eLocationHotspot)) hs_look();
    ProcessClick(...); as before
  }
  ...


Note that this can and will add identical items to your list box.
If you want each of the five items to be added only once, you need additional checks.

Atelier

I've added in both of the codes into the global script, but I'm a little confused. Is the 'hs' just used as an example, or does it have an important function to it? I'm guessing I enter the first block into the global script, under repeatedly execute or something. Sorry about this, but I need just a little more explanation for it to register with me. Thanks for helping me.

Trent R

The first block is above the on_mouse_click, the second is inside of it. It is called for every single hotspot you click on.


~Trent
To give back to the AGS community, I can get you free, full versions of commercial software. Recently, Paint Shop Pro X, and eXPert PDF Pro 6. Please PM me for details.


Current Project: The Wanderer
On Hold: Hero of the Rune

Atelier

Success!

I entered the first block into my room script, changed the hs for the hotspot name, and it worked perfectly. This meant I could take out the coding from the global script. The script may be longer in the room script, but it frees up space in the global script and it's not too complicated for me.  :)

Thank you Khris, thank you Trent; that seems to be the only problem left for the basis of my game.

Khris

I called it hs_look, short for hotspot_look.

You're not supposed to use its contents as a hotspot's look function because that destroys the whole of purpose of having it made a function and you'll end up with lots and lots of duplicate code again...

Leave the first block as it is, inside the global script, above on_mouse_click, then add this line to the global header:

Code: ags
import void hs_look();


Now you could use a look function like this:

Code: ags
function hTree_Look() {
  hs_look();
}


Calling hs_look() will in effect call all the code inside the function's body. Still, using this method, you'd have to put that line into every single hotspot's look function.
Thus I suggested calling it whenever the player looks at a hotspot by adding the second piece of code to the on_mouse_click.

On a side note, "freeing up space" in the global script is completely pointless (and not necessary anyway) if it leads you to having long room scripts with lots of duplicate code.

Atelier

Ahh, that makes sense now. Admittedly, I only did what I said in the last post because I didn't understand and didn't want to be a further pain, but I ended up being more of a pain. :) I've done what you said and it works nicely. The 21 lines of code I used to have are now 1. Hopefully the last question on this though: How would I change the value of 's' for each hotspot? At the moment every hotspot either says first, second etc, so how is it done?

Thanks for your help.

Khris

If you want a specific value for each hotspot, you can use a parameter.

Code: ags
void hs_look(int ran) {
  String s;
  if (ran == 0) s = "first";
  ...
  if (ran == 4) s = "fifth";
  DisplayBox.ScrollDown();
  DisplayBox.AddItem(String.Format("You got the %s phrase.", s));
}


Now you call it like this:
Code: ags
  hs_look(3);   // adds "You got the fourth phrase."


I'm still not sure which line is supposed to get added when though. Do you want looking at the first five hotspots to add the five lines in order?

Atelier

I'm using this as a random phrase generator, so looking at an item/hotspot could produce one of five outcomes, in no particular order, making everything much more interesting. My very first post might explain it a little better. I was wondering whether there's a way to change the value of s for each individual outcome for looking at a particular hotspot?

Khris

Quote from: Atelier on Sun 31/05/2009 13:19:58I was wondering whether there's a way to change the value of s for each individual outcome for looking at a particular hotspot?
I'm sorry but I still don't quite get it. Currently, you're using the Random() function to add one of five phrases to the listbox. If you want to add a random line for some hotspots and a specific line for others, you can use this version of the function:

Code: ags
void hs_look(int ran) {
  if (ran == -1) ran = Random(4);
  String s;
  if (ran == 0) s = "first";
  ...
  if (ran == 4) s = "fifth";
  DisplayBox.ScrollDown();
  DisplayBox.AddItem(String.Format("You got the %s phrase.", s));
}


Now call hs_look(-1); to add a random line, or pass a value from 0 to 4 to add a specific one.

Atelier

Maybe this might explain it better:

Code: ags
function hGrass_Look()
{
   int ran = Random(4);
   String s;
   if (ran == 0) s = "A herbacious plant counting for most of the vegatation on the world!";
   if (ran == 1) s = "Flattened by stampeding spectators.";
   if (ran == 2) s = "Trodden, withered, and sad...";
   if (ran == 3) s = "A member of the grass family Poaceae.";
   if (ran == 4) s = "Trampled, yellowed, and dying...";
   DisplayBox.AddItem(String.Format("%s", s));
   DisplayBox.ScrollDown();
}

Rather than having all this for one hotspot, I've used your code in the global script and just imported it instead. BUT the code in the global script has outcomes like "first" "second" etc. So, I was wondering how to change these outcomes to suit the hotspot looked at. I hope that makes it clearer.  :) I admire you perseverance, I have to say. Thanks!

Khris

Right, now it makes sense.

The most straightforward way is to pass the strings as parameters:

Code: ags
// header
import void hs_look(String s0, String s1, String s2, String s3, String s4);

// global script
void hs_look(String s0, String s1, String s2, String s3, String s4) {
  String s[5];
  s[0] = s0; s[1] = s1; s[2] = s2; s[3] = s3; s[4] = s4;  // put strings in an array
  int i, c = 4;
  while (i < 5) {
    if (s[i].Length == 0) c--;  // count strings not == ""
    i++;
  }
  int ran = Random(c);  // select a random string
  DisplayBox.AddItem(s[ran]);
  DisplayBox.ScrollDown();
}

Tested, working.

This will result in pretty long lines, so alternatively you can use a global string array and assign the values beforehand:
Code: ags
// header
import hs_look();
import String s[5];

// global script
String s[5];
export s;

void hs_look() {
  int i, c = 4;
  while (i < 5) {
    if (s[i].Length == 0) c--;
    i++;
  }
  int ran = Random(c);
  DisplayBox.AddItem(s[ran]);
  DisplayBox.ScrollDown();
}


Then do e.g.
Code: ags
function hGrass_Look() {
  s[0] = "A herbacious plant counting for most of the vegatation on the world!";
  s[1] = "Flattened by stampeding spectators.";
  s[2] = "Trodden, withered, and sad...";
  s[3] = "A member of the grass family Poaceae.";
  s[4] = "Trampled, yellowed, and dying...";
  hs_look();
}

Atelier

I've copied the first block of code into the global script, and that seems fine. But when it gets to the room script, it claims that 's' is an undefined token. Does it need a global variable?

Khris

If you use the first method, you have to include the lines in the function call:

Code: ags
...
  hs_look("bla", "bleh", "blih", "", "");


Like I said, this will result in pretty long lines of code.
If you want to set the lines beforehand, like in the example at the bottom of my previous post, you have to use the second way.

Don't just copy and paste, try to understand how the code works and what it does. I also believe you're rushing things; read my posts carefully, I explained all about this already.

Atelier

#14
Good! Now that my brain's in gear today I was able to successfully do it using the second method. It works really well; cuts down on code; and I don't get that annoying thing where it adds two versions of it and does really weird stuff.

Thanks for helping me all the way on this, I really appreciate it - and I've learnt quite a bit too.  :)

monkey0506

Just to clarify one thing that I saw:

Code: ags
DisplayBox.AddItem(String.Format("%s", s));


It is completely unnecessary to use String.Format here because in the code snippet this was taken from you've defined s as:

Code: ags
String s;


So s is already a String. There's no need to format it into a String. If you were perhaps getting null pointer errors, that could be corrected by doing:

Code: ags
String s = "";


Although it doesn't crash, using String.Format with null Strings is still bad practice. I'm not sure if that's why you were doing it this way, but again the line could be simplified as:

Code: ags
DisplayBox.AddItem(s);

Atelier

That probably might explain why it was acting really strangely and adding duplicate items into the display box. If that wasn't the reason then :-\
Thanks, I'll know what to do next time I deal with strings.

SMF spam blocked by CleanTalk