Problem with activating multiple hotspots to reveal secret door

Started by Zephyr, Thu 24/10/2019 11:36:15

Previous topic - Next topic

Zephyr

Hi Everyone,
                I'm trying to script a scenario where a secret door will be revealed only when a total of 4 hotspots have been activated.  I've tried a number of different things with no success.  After trawling through the forum, I thought I'd found the answer as someone else had the same problem but using objects rather than hotspots.  I therefore copied the instructions carefully, having already scripted the trigger enabled/disabled on interact bits :-

Code: ags
function room_RepExec()
{
      if (hTrigger1 == false && hTrigger2 == false && hTrigger3 == false && hTrigger4 == false){
      if (Game.DoOnceOnly ("A secret door opens!")){
         oSecretDoor.Visible = false;
      }
   }
}


That's when I found out that this doesn't work with hotspots!

Can anyone please help me to solve this problem?

- Zephyr   (wtf)
<3 Zephyr <3

Khris

Based on your last question and this one, let me start by saying that AGSScript, like other programming languages, has essentially very simple syntax that follows some strict rules. One of these is that when you're comparing things, they need to be of the same data type.

hTrigger1 == false  makes no sense as an expression; you're comparing an object* (hTrigger1) to a boolean value. Hotspots have a boolean property called  .Enabled, so still assuming that hTrigger1 is a hotspot, you could in theory do this instead:

Code: ags
  if (hTrigger1.Enabled == false) ...


Further assuming that the four hotspots get disabled when the player interacts with them, this would work for your code. However putting it in rep_exe is bad practice, since AGS will not check the condition of the hotspots 40 times per second.

If the secret door is in the same room, use something like this in the room script:

Code: ags
bool triggered1, triggered2, triggered3, triggered4;

function TriggerCheck() {
  if (triggered1 && triggered2 && triggered3 && triggered4) {
    if (Game.DoOnceOnly("four triggers")) {
      Display("A secret door opens!");
      oSecretDoor.Visible = true;  // false?
    }
  }
}

// this  has to be linked to the hotspot event, not just copy-pasted!
function hTrigger1_Interact() {
  triggered1 = true;  // turn variable to true
  Display("You trigger the first trigger.");
  TriggerCheck(); // check other triggers now, as opposed to 40 times per second
}


Same for the other three.
(I used this approach because making interactive areas disappear is lazy game design imo and should be avoided unless they actually disappear in-game)


* a script object, not an AGS Room Object

Zephyr

Hi Khris,
           Thank you so much for your help!  I just implemented your advice and it works just fine.

I'm learning so much from you when I consult the forum (though some of it is a bit beyond me - but I'm getting there slowly!) so thanks again.

- Zephyr   :-D (nod)
<3 Zephyr <3

Zephyr

Hi again, Khris (or anyone else out there),

                 I'm now working on a part of my game where I've had the player collect 5 separate clues (each one a separate inventory item) and I'd like to put in some code which, upon finding the final clue, all 5 items will be replaced by just one.  You see, each clue is part of a short poem and is just a little wordy so the plan is, if I can replace them with just one, I can create a new room which will display the entire poem each time this new item is viewed, if that makes sense.

I don't speak "computer" too well and have trouble finding the correct wording, etc., but I thought that maybe I could put something in Global Script saying something like:

Code: ags
if cChristian.ActiveInventory == (iClue1 && iClue2 && iClue3 && iClue4 && iClue5)
cChristian.LoseInventory (iClue1 && iClue2 && iClue3 && iClue4 && iClue5);
cChristian.AddInventory(iWholeClue);


Is this the correct wording or am I barking up the wrong tree again? Is there maybe a simpler option?
Thanks again in advance for any advice. I really am trying to learn.

- Zephyr
<3 Zephyr <3

Cassiebsg

It's close, but not quiet there.

ActiveInventory is the inventory the player currently has in hand to use. Thus you can only ever have 1 active inventory item.
What you want to check for is: .HasInventory

I don't think you can batch lose inventory items like that. I believe you need one line for each (correct me if I'm wrong).

You are missing the curly brackets to make all inside the if clause.

Also, you don't mention where you are planning to add this code to, but you can add it right after you give an iClue, so no need to place it in a rep_exe. :)

So code wise it would look something like this:
Code: ags

if cChristian.HasInventory(iClue1 && iClue2 && iClue3 && iClue4 && iClue5)
{
    cChristian.LoseInventory(iClue1); 
    cChristian.LoseInventory(iClue2); 
    cChristian.LoseInventory(iClue3); 
    cChristian.LoseInventory(iClue4); 
    cChristian.LoseInventory(iClue5); 
    cChristian.AddInventory(iWholeClue);
}
There are those who believe that life here began out there...

Matti

If you don't want to copy-paste those lines for every clue you can create a function in the global script instead:

Edit: I think you can't batch HasInventory either..

Code: ags

function CombineClues()
{
  if (cChristian.HasInventory(iClue1) && cChristian.HasInventory(iClue2) && cChristian.HasInventory(iClue3) && cChristian.HasInventory(iClue4) && cChristian.HasInventory(iClue5))
  {
    cChristian.LoseInventory(iClue1); 
    cChristian.LoseInventory(iClue2); 
    cChristian.LoseInventory(iClue3); 
    cChristian.LoseInventory(iClue4); 
    cChristian.LoseInventory(iClue5); 
    cChristian.AddInventory(iWholeClue);
  }
}


And then you just need to put this line everywhere you get a new clue:
Code: ags

CombineClues();

Zephyr

Hi Matti and Cassiebsg,

            Thank you so much,both of you!  Why oh why does "computer speak" have to be so complicated?  It's time someone taught them plain English!!! lol
Anyway, I'll try your suggestions out right now. Thanks again.

- Zephyr.
:-*
<3 Zephyr <3

Zephyr

Hi All,

            Sorry to bug you again, but I just can't figure this out!

Matti, I decided to try your solution first as I thought it would be a simpler/easier way. I followed your example exactly but on trying to test run the game, it's telling me that there's no such token as "combine clues",even though I put that in Global Script AND in the room script each time a clue was found!

So next I went with Cassiebsg's suggestion, but it keeps telling me there's a ( missing in the "if" line.  I copy/pasted it just as you had it, so I have no idea what I've gone and done now!

can anyone help me please (again!);  :( ???

- Zephyr
<3 Zephyr <3

eri0o

If you have a function in a script you need to import it in it's header to make it available elsewhere.

If you want to call a function in the same script it's written, you need to call it after the function is defined - not "above" it.

If you are placing a function in the global script I think you need to export it.

Matti

You only need to put the function once in the global script. I forgot to mention though that you need to put
Code: ags
import function CombineClues();
at the top of the global script's header.

Quote from: Zephyr on Wed 04/12/2019 12:12:21
So next I went with Cassiebsg's suggestion, but it keeps telling me there's a ( missing in the "if" line.  I copy/pasted it just as you had it, so I have no idea what I've gone and done now!

Yes, everything after the IF should be enclosed by (). But that line wouldn't work anyway because you can only have one item after .HasInventory. It should look like in my code above.

Zephyr

 :-D
Hi Again,

           Thanks, Matti! I'll try that again.

- Zephyr.

:-*
<3 Zephyr <3

SMF spam blocked by CleanTalk