Giving an NPC multiple items for one item

Started by PEd1, Mon 21/08/2023 17:24:38

Previous topic - Next topic

PEd1

Hi!

I'm making a game using the Tumbleweed template...

I've got most of it working and I know how to give an NPC a specific item and have them respond and give me a different item in return.
However, I am now stuck, as I don't know how to do this next bit -

I want an NPC to give the player an item but only once they've received four specific items from the player, and the player can give them the items in any order.

So, for example, the player has to give the NPC a cup, a fish, a plate, and a fork, and the NPC will take each of these items one by one, but will only give them an item in return, a key, after they've received all four items.

RootBound

Should be simple enough. Under the function where the NPC receives inventory items, you can put the following:

if (NPCname.HasInventory(iFish) && NPCname.HasInventory(iCup) && NPCname .HasInventory(iPlate) && NPCname.HasInventory(iFork)){
  player.AddInventory(iKey);
  }

A little cumbersome but should only trigger once the NPC has all four items.
J. They/them. Here are my most recent games:

PEd1

Thanks!

Ah, ok, so something I did not realize is that NPCs have their own inventories that AGS keeps track of?

So far, when I give an NPC an item in exchange for another I only refer to the player's inventory -

player.LoseInventory(iItem);
player.AddInventory(iNewitem);

So I guess for cases where I need the the NPC to actually have the item I should also have the following -

cNPCname.AddInventory(iItem);

To add it to their inventory?

RootBound

J. They/them. Here are my most recent games:

Khris

Quote from: PEd1 on Mon 21/08/2023 18:29:42Ah, ok, so something I did not realize is that NPCs have their own inventories that AGS keeps track of?

All characters work the same under the hood. They all have the same properties. You can switch the player to command another character at any point.

In general, whenever you need your game to remember something, the answer is: variables. Here you can use the built-in inventory array of the NPC to store which items they already received from you, but if you want to store other information to look up later, you will need a variable (or many of them). It's never too early to learn this concept.

PEd1

Quote from: Khris on Mon 21/08/2023 19:48:00if you want to store other information to look up later, you will need a variable (or many of them). It's never too early to learn this concept.

Thanks - is there a tutorial somewhere for this, or a specific phrase I should search for on the forums to find out more?

Khris

#6
You can start here:
https://www.adventuregamestudio.co.uk/wiki/Scripting,_Code_%26_Interaction#Working_with_variables:_the_basics

You should also take a look at the Global Variables pane in the editor, there you can create global ones without scripting.
For instance the simplest one is a bool, which can only be true or false.

Say you create a bool called "room2_light" and set its initial value to false. You can now solve a previously impossible problem: changing the state of another room as opposed to the current one.

In you first room, when the player interacts with a light switch, put
Code: ags
  room2_light = true;
inside the function.

In room 2 you can now check this variable when the player enters (before fadein) and preprare the room accordingly:
Code: ags
  if (room2_light == true) {
    // switch background
    // turn on hotspots and objects otherwise in darkness
    // etc.
  }
  else if (room2_light == false) {
    // make room dark again
  }

Note the double == to compare a variable to a value; a single = is used to change the value.


(for the sake of completeness: toggling a bool is done like room2_light = !room2_light; and you can use the shorter if (room2_light) and just an else to check for the two cases)

heltenjon

Another small trick in the same vein is that you may give the npc items that only work as bools, like calling an inventory item nothungry or scared, then check for them in the manner described above. With an if statement you may then use this to trigger an action, make a dialogue line visible or something like that. (This is a more roundabout way of doing what Khris explained.)

Snarky

That's quite clever, @heltenjon. In a game with character stats, you can also use the inventory item count as the stat value.

PEd1

Thanks!

The variables should help me with this other puzzle I have...

The player puts a coin in a drinks machine (I then remove the coin from the inventory).
The main character then says the coin got stuck.
The player has to "push" the machine to get the drink out.


So I assume for this I'd set a bool in the room, as it all takes place in one room...

bool CoininMachine = false;

And then in the function for when the coin is used on the machine I'd put -

CoininMachine = true;

And then when "push" is used on the machine I'd have -

if (CoininMachine == true) {
// player says the coin has been dislodged
// player gets drink added to their inventory
}
else if (CoininMachine == false) {
// player says nothing happened
}

I guess I'd then have to set CoininMachine back to false somewhere afterwards? So that the player can't repeatedly push the machine and get the drink added again.

Khris

Exactly. If you need to store more complex information, you need to carefully think about the kind of information and which variable type is needed.

For instance if you have three lockers and one of them contains an object at random, using one bool for each locker is a bad idea because not only do you need to handle three variables, but at least in theory more than one can be true, which clashes with the concept of only one of them containing the object.
In this case you would use an integer variable, where a value of 1 means the object is in the first locker, and so on. After the player removes the object, you simply change the value to 0. This greatly reduces the possibility for logic errors in your game.

heltenjon

QuoteI guess I'd then have to set CoininMachine back to false somewhere afterwards? So that the player can't repeatedly push the machine and get the drink added again.
You could add another if statement to the top of your code to check if the player already has the drink. Then make the reply "I already got a drink". Check for the drink before you check for the coin. (You can solve this in multiple ways, depending on what player response you want.)

Crimson Wizard

Quote from: PEd1 on Tue 22/08/2023 14:16:20if (CoininMachine == true) {
// player says the coin has been dislodged
// player gets drink added to their inventory
}
else if (CoininMachine == false) {
// player says nothing happened
}

Please note that this code may be simplified for two reasons: 1) checking boolean variable may be done directly without comparing with true/false; and 2) if you have only 2 possible variants, then there's no need for the second "if":
Code: ags
if (CoininMachine) {
// player says the coin has been dislodged
// player gets drink added to their inventory
}
else {
// player says nothing happened
}

Khris

#13
Quote from: heltenjon on Tue 22/08/2023 14:37:51You could add another if statement to the top of your code to check if the player already has the drink. Then make the reply "I already got a drink". Check for the drink before you check for the coin. (You can solve this in multiple ways, depending on what player response you want.)

Sorry, but I don't think this is a good approach. First of all, if the player can lose the drink, this check will no longer work as intended. Granted, if they cannot lose the drink before leaving the area with the machine forever, this will work, but this is error prone in general and should be avoided.

I always try to mimic real life: a vending machine IRL has no idea whether you already possess a drink or not, and it shouldn't prevent you from getting another one anyway.
Just simulate an actual vending machine: you insert a coin and you get a drink. If the coin can get stuck, add a variable for this and keep track of that, too.
If you want to limit the player to a single drink, just don't give them more than one coin. If they have more than one coin but getting two drinks would lead to a dead end, consider your approach. Can they maybe get back the coin(s) somehow? (This has the added benefit of making the player feel less like being guided along a narrow path towards the "correct" solution.)

I'm also not too fond of using the inventory as a substitute for variables, tbh. My rule of thumb is always: implement everything in a future-proof way. Any future change to the game design, UI, etc. should require as little changes as possible to existing code.

heltenjon

Quote from: Khris on Tue 22/08/2023 15:03:59Sorry, but I don't think this is a good approach. First of all, if the player can lose the drink, this check will no longer work as intended. Granted, if they cannot lose the drink before leaving the area with the machine forever, this will work, but this is error prone in general and should be avoided.

I thought more in the vein of making sure that the player had only one drink at a time, which could open up for using the drink in multiple ways: drinking it, spilling it, giving it to the wrong person, etc. But  I think I didn't consider the stuck coin in all that, so I agree.

QuoteI always try to mimic real life:
(snip)
QuoteI'm also not too fond of using the inventory as a substitute for variables, tbh.

I think the logic of a npc having iKnowledge in their inventory is flawless.  (laugh) It's certainly easier for some beginners (like myself) than integers. But anyone more serious about learning coding is better off by taking Khris' advice than my own.

SMF spam blocked by CleanTalk