Different ways to use an item only once? [SOLVED]

Started by Stranga, Fri 09/02/2018 11:24:57

Previous topic - Next topic

Stranga

Hello everyone, I want to use an item on a hotspot only once to get another item without losing the initial item. So far I've been using
Code: ags
if (Game.DoOnceOnly("GainItem"))


But I'm not sure if this is the best method/way to do this. Anyone have any ideas or experience on how to do this or is this way fine?

P.S wasn't sure If this sort of question should be posted here but any moderators are more than welcome to move it :)

Danvzare

#1
Create a variable in the room script and set it to false, then check if that variable is false when you use the item, and if it is, set the variable to true and gain the other item. That way if you use the item again, the check will fail and you'll get a different response, such as "I've got enough wood, I don't need to chop off any more."

I think something like this code should work:
Code: ags

bool usedAxe = false;

if (!usedAxe)
{
    player.AddInventory(iWood);
    usedAxe = true;
}
else
{
    player.Say("I've got enough wood, I don't need to chop off any more.");
}

dayowlron

the whole purpose for the Game.DoOnceOnly is for this purpose. Even though Danvzare's method will work, the way you had it works also and you don't need to set up the additional variable.
Pro is the opposite of Con                       Kids of today are so much different
This fact can clearly be seen,                  Don't you know?
If progress means to move forward         Just ask them where they are from
Then what does congress mean?             And they tell you where you can go.  --Nipsey Russell

Stranga

I thought it was the best method at the time didn't think it would be the actual way to do it. The bool method would be good if I weren't using the RestartGame() function. One other thing that I wanted to ask about is which way is better or they both do the same thing:

Code: ags

if (player.ActiveInventory==iAxe && Game.DoOnceOnly("CutTree"))

//or

if (Game.DoOnceOnly("CutTree")){
    if (player.ActiveInventory==iAxe){

    }
}


I have used both ways and they both "seem" fine to me but I am unsure if they would conflict with each other some how with the first example.

Crimson Wizard

#4
Quote from: Stranga on Fri 09/02/2018 13:28:37
I thought it was the best method at the time didn't think it would be the actual way to do it. The bool method would be good if I weren't using the RestartGame() function.

Both boolean variables and DoOnceOnly are reset with the RestartGame.
Actually, what RestartGame does is simply loading a save that was made when game is started, or you call SetRestartPoint. So, this is like loading a savegame.


Quote from: Stranga on Fri 09/02/2018 13:28:37
One other thing that I wanted to ask about is which way is better or they both do the same thing:

Code: ags

if (player.ActiveInventory==iAxe && Game.DoOnceOnly("CutTree"))

//or

if (Game.DoOnceOnly("CutTree")){
    if (player.ActiveInventory==iAxe){

    }
}


I have used both ways and they both "seem" fine to me but I am unsure if they would conflict with each other some how with the first example.


There is a difference, and that difference may be important or not important depending on situation.

First of all, the first example will run the block of statements if both conditions are true only.
The second example has TWO blocks of statements, one under "if (Game.DoOnceOnly("CutTree"))" and the second under "if (player.ActiveInventory==iAxe)", which is a "sub-block" of the first one.
If you only have commands under second condition, then there is no difference, but in theory you could also add commands under Game.DoOnceOnly like this:
Code: ags

if (Game.DoOnceOnly("CutTree")){
    /// some commands here
    if (player.ActiveInventory==iAxe){
 
    }
    /// more commands here
}

In such hypothetical case these extra commands would be run if Game.DoOnceOnly returns true, but they won't depend on the second condition.


If you only suppose to have game react to both conditions at once always, I'd recommend to use the first variant, because it makes intentions more clear.
But then again, such things are rather important when you work in team and want other people understand your code. If you are working alone it's all up to you.

Khris

I don't think that's correct, there is indeed a difference.

Code: ags
  if (player.ActiveInventory==iAxe && Game.DoOnceOnly("CutTree"))


Expressions are evaluated from left to right (unless set differently in General Settings -> Backwards Compatibility). Which means if the player has used some other InventoryItem, the left test will fail. At this point AGS doesn't bother evaluating the right side, since "false && x" is always "false" anyway.
The downside of this method is that a subsequent else will catch both "other item was used" and "axe was used a second time", which is usually undesirable.

Here however:
Code: ags
if (Game.DoOnceOnly("CutTree")){
    if (player.ActiveInventory==iAxe){
      //...
    }
}


AGS always runs Game.DoOnceOnly() first, which means the entire outer block is disabled after the first run, regardless of the item that was used.
Which means:
1. Use Spoon on Tree -> (wrong)
2. Use Axe on Tree -> (wrong)

My suggestion would be to always handle the item first (after potentially approaching the hotspot and the like, of course):
Code: ags
  if (player.ActiveInventory == iAxe) {
    if (Game.DoOnceOnly("CutTree")) { ... }
    else ...
  }
  else Unhandled();


In general, always nest from generic to specific. Cutting the tree is part of the axe interaction, and should go inside it.

Stranga

Thank you everyone and especially CW and Khris you both have gave great answers but also solved a few problems that I would of had to post here.

Danvzare

Quote from: dayowlron on Fri 09/02/2018 13:05:06
the whole purpose for the Game.DoOnceOnly is for this purpose. Even though Danvzare's method will work, the way you had it works also and you don't need to set up the additional variable.
Wow, can you believe that I've been using AGS for years, and I never knew that Game.DoOnceOnly worked like that.
I've learnt something new. :-D

SMF spam blocked by CleanTalk