Jibble

Author Topic: Lost in a maze of nested functions!  (Read 207 times)

Lost in a maze of nested functions!
« on: 22 Jan 2020, 11:20 »
Hi again Everyone,

         OK, so I'm building my first "shop" in my game, but it's a little complex in that 2 separate transactions can take place by interaction with only 1 hotspot.  This is further complicated by the fact that each transaction involves having:
a). the correct amount of cash
b). the correct inventory item.

I've messed around for hours trying to sort out the necessary nested functions and my brain is about to explode!
Here's what my last attempt was:-
Code: Adventure Game Studio
  1. function hFont_UseInv()
  2. {      
  3.       if (cChristian.ActiveInventory == (iEmptyBottle))
  4. {
  5.          cChristian.Walk (225, 168, eNoBlock, eWalkableAreas);
  6. }
  7.       if (Money >= 5)
  8. {
  9.          cChristian.LoseInventory (iEmptyBottle);
  10.          cChristian.AddInventory (iHolyWater);
  11.          Money -= 5;
  12.          Display ("You have a bottle of Holy Water.");
  13. }
  14.     else
  15. {
  16.          Display ("Not enough money.");
  17. }
  18.       if (cChristian.ActiveInventory == (iStMichael))
  19. {
  20.          cChristian.Walk (225, 168, eNoBlock, eWalkableAreas);
  21. }
  22.       if ((Money >= 5)  // error msg reads "end of input reached in middle of expression"
  23. {
  24.           cChristian.LoseInventory (iStMichael);
  25.           cChristian.AddInventory (iBlessedStMichael);
  26.           Money -= 5;
  27.           Display ("Your medallion has been blessed.");
  28. }
  29.      else
  30. {
  31.           Display ("Not enough money.");
  32. }
  33. }

Can anyone please tell me where I've gone wrong and (in simple terms) WHY it's wrong?
Thanks again,
- Zephyr   :confused:

Re: Lost in a maze of nested functions!
« Reply #1 on: 22 Jan 2020, 11:25 »
On my phone so can't see it all that well atm but in the "if money" line you have an extra "(" which isn't going to help.

Slasher

  • slasher
    • I can help with AGS tutoring
    • Lifetime Achievement Award Winner
    • I can help with scripting
    • I can help with story design
    • Slasher worked on one or more games that won an AGS Award!
    •  
    • Slasher worked on one or more games that was nominated for an AGS Award!
Re: Lost in a maze of nested functions!
« Reply #2 on: 22 Jan 2020, 11:38 »
Not exactly the same but it may shed some usefulness

From a Dialog option.

Code: Adventure Game Studio
  1.    cTurner.SayBubble("1 thimble of ale, 1 bitters, 1 teaspoon of sherbert,");
  2.    cTurner.SayBubble("...1 small sweet sherry, 1 shot of pineapple juice, 1 shot of lime cordial,");
  3.    cTurner.SayBubble("...and a banana slice.");
  4.    cTurner.SayBubble("Stirred not Shaken.");
  5.    cChang.SayBubble("&6 That will be Â¥139 Yuans.");
  6.    if(Money <=138.00){
  7.    cTurner.SayBubble("Seems like I don't have enough money.");
  8.    cTurner.SayBubble("I'll have to leave it for now.");
  9.    cChang.SayBubble("OK, sir.");
  10.    }
  11.      else {
  12.    cTurner.SayBubble("Here you are.");
  13.    Money -=100.39;
  14.    object[16].Graphic=2380;
  15.    Wait(40);
  16.    object[16].Visible=true;
  17.    cChang.SayBubble("&7 Here you go, sir.");
  18.    cTurner.SayBubble("Agh!");
  19.    cTurner.SayBubble("This tastes disgusting!");
  20.    cChang.SayBubble("&8 Maybe you got the recipe wrong, sir.");
  21.    cTurner.SayBubble("You are probably right!");
  22.    object[16].Visible=false;
  23.    DRINKA=true;
  24.      }
  25.  


Re: Lost in a maze of nested functions!
« Reply #3 on: 22 Jan 2020, 11:42 »
When dealing with lots of conditions, the proper code indentation saves lifes!

Original code with correct indentation
Code: Adventure Game Studio
  1. function hFont_UseInv()
  2. {      
  3.     if (cChristian.ActiveInventory == (iEmptyBottle))
  4.     {
  5.         cChristian.Walk (225, 168, eNoBlock, eWalkableAreas);
  6.     }
  7.     if (Money >= 5)
  8.     {
  9.         cChristian.LoseInventory (iEmptyBottle);
  10.         cChristian.AddInventory (iHolyWater);
  11.         Money -= 5;
  12.         Display ("You have a bottle of Holy Water.");
  13.     }
  14.     else
  15.     {
  16.         Display ("Not enough money.");
  17.     }
  18.     if (cChristian.ActiveInventory == (iStMichael))
  19.     {
  20.         cChristian.Walk (225, 168, eNoBlock, eWalkableAreas);
  21.     }
  22.     if (Money >= 5)  // error msg reads "end of input reached in middle of expression"
  23.     {
  24.         cChristian.LoseInventory (iStMichael);
  25.         cChristian.AddInventory (iBlessedStMichael);
  26.         Money -= 5;
  27.         Display ("Your medallion has been blessed.");
  28.     }
  29.     else
  30.     {
  31.         Display ("Not enough money.");
  32.     }
  33. } // ?
  34.  


From the above code we can see that all the actions are performed in a straight sequence:
1. Check if active inventory is iEmptyBottle, and if yes then walk.
2. Check if has money, and if yes, then exchange iEmptyBottle for iHolyWater.
3. Check if active inventory is iStMichael, and if yes then walk.
4. Check if has money, and if yes, then exchange iStMichael for iBlessedStMichael.

Because they are performed in one sequence, there's no interconnection between them, in other words, money check will be done even if you don't have an item.

To get it proper you need to nest condition 2 inside condition 1, and nest condition 4 inside condition 3.

Code: Adventure Game Studio
  1. function hFont_UseInv()
  2. {      
  3.     if (cChristian.ActiveInventory == (iEmptyBottle))
  4.     {
  5.         cChristian.Walk (225, 168, eNoBlock, eWalkableAreas);
  6.         if (Money >= 5)
  7.         {
  8.             cChristian.LoseInventory (iEmptyBottle);
  9.             cChristian.AddInventory (iHolyWater);
  10.             Money -= 5;
  11.             Display ("You have a bottle of Holy Water.");
  12.         }
  13.         else
  14.         {
  15.             Display ("Not enough money.");
  16.         }
  17.     }
  18.     if (cChristian.ActiveInventory == (iStMichael))
  19.     {
  20.         cChristian.Walk (225, 168, eNoBlock, eWalkableAreas);
  21.         if ((Money >= 5)  // error msg reads "end of input reached in middle of expression"
  22.         {
  23.             cChristian.LoseInventory (iStMichael);
  24.             cChristian.AddInventory (iBlessedStMichael);
  25.             Money -= 5;
  26.             Display ("Your medallion has been blessed.");
  27.         }
  28.         else
  29.         {
  30.             Display ("Not enough money.");
  31.         }
  32.     }
  33. }
  34.  


The "end of input reached in middle of expression" error is because you have two opening brackets and 1 closing one. "if ((Money >= 5)" should be "if (Money >= 5).

Re: Lost in a maze of nested functions!
« Reply #4 on: 22 Jan 2020, 11:43 »
Things I've noticed:

- Extra bracket in line 22, like CaptainD said.

- Money checks need to go inside each inventory item check.

- Your indentation (or more like, lack thereof) also makes things hard to read. When you have conditions nested inside of conditions, this doesn't help figure out what's going on.

Here's the corrected code:


Code: Adventure Game Studio
  1.    
  2. function hFont_UseInv()
  3. {      
  4.        if (cChristian.ActiveInventory == (iEmptyBottle))
  5.         {
  6.           cChristian.Walk (225, 168, eNoBlock, eWalkableAreas);
  7.  
  8.           if (Money >= 5)
  9.             {
  10.               cChristian.LoseInventory (iEmptyBottle);
  11.               cChristian.AddInventory (iHolyWater);
  12.               Money -= 5;
  13.               Display ("You have a bottle of Holy Water.");
  14.              }
  15.           else
  16.             {
  17.               Display ("Not enough money.");
  18.              }
  19.          }  // this closes the first "if" condition (for iEmptyBottle)
  20.  
  21.        if (cChristian.ActiveInventory == (iStMichael))
  22.         {
  23.           cChristian.Walk (225, 168, eNoBlock, eWalkableAreas);
  24.  
  25.           if (Money >= 5)  // removed the extra parenthesis that was causing an error
  26.             {
  27.               cChristian.LoseInventory (iStMichael);
  28.               cChristian.AddInventory (iBlessedStMichael);
  29.               Money -= 5;
  30.               Display ("Your medallion has been blessed.");
  31.              }
  32.           else
  33.             {
  34.                Display ("Not enough money.");
  35.              }
  36.       } // this closes the second "if" (for iStMichael)
  37.  }

Also, for one-line commands, you don't have to use curly brackets, which might add to your confusion. So instead of:

Code: Adventure Game Studio
  1. else
  2. {
  3. Display("Blah blah blah");
  4. }

Just do
Code: Adventure Game Studio
  1. else Display("Blah blah blah");
« Last Edit: 22 Jan 2020, 11:49 by Laura Hunt »

Lost in a maze of nested functions! - SOLVED!!
« Reply #5 on: 22 Jan 2020, 13:46 »
 :-D
Thanks so much everyone!  And a special thanks to Crimson Wizard and Laura Hunt for your straightforward, simple explanations and guidance. 
They do say that the older you get, the harder it is to learn a new language - and THIS old lady can confirm that!   (laugh)
I'm learning so much from you all though, so thanks again - I really appreciate it!

- Zephyr   :-* :-*

Re: Lost in a maze of nested functions! - SOLVED!!
« Reply #6 on: 22 Jan 2020, 14:01 »
:-D
Thanks so much everyone!  And a special thanks to Crimson Wizard and Laura Hunt for your straightforward, simple explanations and guidance. 
They do say that the older you get, the harder it is to learn a new language - and THIS old lady can confirm that!   (laugh)

I think quite a few of us can confirm that it's never too late ;)

btw, another possible issue you might run into, is that cChristian never gets to the shopkeeper, or wherever his "walk" command is supposed to take him. This is because you've made it non-blocking, which means that the next lines in the script will be executed immediately, which in turn means that your message of "Success" or "You don't have enough money" will pop up before he's even had the chance to walk up to his destination. If this is not what you want, and you want him to walk all the way up to (225, 168) before the shop message pops up, you should make the Walk command eBlock rather than eNoBlock.


Re: Lost in a maze of nested functions!
« Reply #7 on: 23 Jan 2020, 10:21 »
Hi Laura,

Thanks again for that.  I'm also getting confused with the block/no-block thing.  The thing is, I also have an object animation running in the background and I wasn't sure if  the block command would interfere with that.  Could you maybe explain a little please?

Thanks again!
- Zephyr   :-\

CrashPL

  • The dinosaur guy
    • I can help with AGS tutoring
    • I can help with animation
    • I can help with characters
    • I can help with play testing
    • I can help with scripting
    • I can help with translating
    • CrashPL worked on one or more games that was nominated for an AGS Award!
Re: Lost in a maze of nested functions!
« Reply #8 on: 23 Jan 2020, 10:59 »
One thing I found incredibly useful is the code reidentation in Notepad++ - AGScript files can be easily beautified and reidented as C code via the TextFX plugin!

Khris

  • partook in silencing a crtitc despite facts
    • Lifetime Achievement Award Winner
    • I can help with play testing
    • I can help with scripting
    • I can help with translating
    • Khris worked on one or more games that was nominated for an AGS Award!
Re: Lost in a maze of nested functions!
« Reply #9 on: 23 Jan 2020, 11:02 »
I'm also getting confused with the block/no-block thing.  The thing is, I also have an object animation running in the background and I wasn't sure if  the block command would interfere with that.  Could you maybe explain a little please?

I'll give it a try:

Any non-blocking thing keeps running in the background, even when blocking things start to happen. Calling the same non-blocking command twice in quick succession (for instance  player.Walk()) will lead to the first command being "overwritten" / discarded because the second command will run in the very next microsecond.

A blocking thing halts the current function until it completes (for instance .Animate-ing something using both eRepeat and eBlock will make the game permanently unresponsive since the blocking thing never finishes).

Say you want three characters to walk across the screen, blocking. You'd tell #1 & #2 to walk using eNoBlock, then tell #3 to walk using eBlock. That way they will all walk at the same time, and the game will be unresponsive until the 3rd one has reached her goal.

Another common situation is where you want multiple things to happen in sequence, like a character walking somewhere, then animating, then saying something.
If this is part of a cutscene and can be blocking, you can simply use the blocking versions of the three according commands and it'll work fine.
However if this is supposed to happen without the game getting unresponsive, you need to "wait" until the character has reached their goal first before you call the Animate command. Then you need to wait until the animation is complete before calling SayBackground(). The only way to do that currently is to use a state variable and repeatedly_execute to a) keep track of what the character is currently doing and b) check if they have finished yet.

Edit: actually, you could also use SetTimer() to schedule the 2nd and 3rd command, in case the number of frames for the walking and animating is constant
« Last Edit: 23 Jan 2020, 11:06 by Khris »
Fail at Floaty Rog' now!  still having to deal with what games are going through

Re: Lost in a maze of nested functions!
« Reply #10 on: 23 Jan 2020, 11:04 »
Hi Laura,

Thanks again for that.  I'm also getting confused with the block/no-block thing.  The thing is, I also have an object animation running in the background and I wasn't sure if  the block command would interfere with that.  Could you maybe explain a little please?

Thanks again!
- Zephyr   :-\

Blocking commands simply pause the script and wait until the blocking action is finished in order to execute the next line, but they won't interfere with animations that you have already going on in the background.

You would usually use blocking actions when you need an action to be completed before something else starts. For example, say you have a radio playing music and you want your character to walk up to it and turn it off:

- If you don't use blocking, the commands "walk to radio" and "turn radio off" will be executed immediately one after the other, so the radio will get turned off before the character even takes a single step.
- If you use blocking, then the character will start walking, the script will wait patiently until the walk command is finished, and then resume executing the next line in the script, which in this example would be turning the radio off.

Hope this clears things up a bit!

Edit: Khris' explanation is a bit more comprehensive than mine, but since I already wrote this, might as well click "publish" anyway :)
« Last Edit: 23 Jan 2020, 11:16 by Laura Hunt »

Re: Lost in a maze of nested functions!
« Reply #11 on: 23 Jan 2020, 12:48 »
Thanks again, Everyone!

      You really are very patient teachers! I'm going to play about with block/no-block for a while now - seeing it "in action" will make it clearer, I think.
You've been amazing, all of you.

- Zephyr   (nod) :)