Facebook Twitter YouTube Frictional Games | Forum | Newsletter | Dev Blog | Dev Wiki | Support | Gametee


Post Reply 
 
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Fancy door + quest scripting.
Author Message
Streetboat Offline
Posting Freak

Posts: 1,098
Joined: Mar 2011
Reputation: 56
Post: #1
Fancy door + quest scripting.

Hi all, I'm trying to make a little puzzle involving lighting a fireplace, a door, and a key. What I want to happen is the player needs to get through a door, but needs a key to do so. This I have all figured out in the script, works like a charm. There's an interim step in there, too. The player starts the level out freezing his buns off, and needs to get warm. I made this work as well, creating a quest as soon as the level starts and having it complete when a fireplace is lit. Now, the problem is, I want to tie the fireplace quest to being able to progress. I want to make it so the player can acquire the key, but not be able to use it on the door until he activates the fireplace. It should flash a message when he tries to use the key prematurely, saying "My hands are too frozen to do that."

I feel like this is a fairly complex if...then script, and I have no idea where to even start. On the plus side, I do have working scripts for the key working and the fireplace completing the quest, separately. Take a gander:
void OnStart()
    {
    AddUseItemCallback("", "shop_key", "cellar_wood01", "UsedKeyOnDoor", true);
    AddQuest("questtext1","questtext1");
    GiveSanityDamage(25.0f,true);
    }
void getwarm(string &in EntityName, string &in Type)
    {
         if(Type == "OnIgnite")
         {
           CompleteQuest("questtext1","questtext1");
           GiveSanityBoost();
         }
    }
void UsedKeyOnDoor(string &in asItem, string &in asEntity)
    {
    SetSwingDoorLocked("cellar_wood01", false, true);
    PlaySoundAtEntity("", "unlock_door", "cellar_wood01", 0, false);
    RemoveItem("shop_key");
    }

This is paraphrased, btw. There are other scripts in there, but I only copy-pasted the ones that are pertinent to this question.

Thank you for your time! Smile

[Image: signature-2.png]
(This post was last modified: 03-18-2011 09:08 PM by Streetboat.)
03-18-2011 07:47 PM
Find all posts by this user Quote this message in a reply
Nye Offline
Senior Member

Posts: 250
Joined: Jan 2011
Reputation: 2
Post: #2
RE: Fancy door + quest scripting.

You'll need to make use of the local variant function.

SetLocalVarInt("CUSTOM NAME HERE", INTEGER HERE);

Set an if statement, so that

if(GetLocalVarInt("CUSTOM NAME") == CUSTOM INTEGER)
{
     STUFF HERE
}

So, when the player lights the fireplace, add the line

SetLocalVarInt("CUSTOM NAME HERE", INTEGER HERE);

Then, the player wont be able to do anything until the integer of the variant matches the required value to run "STUFF HERE".

You can be really fancy too, and add a
if(GetLocalVarInt("CUSTOM NAME") != CUSTOM INTEGER)

The != meaning, 'NOT Equal to'.

03-18-2011 09:09 PM
Find all posts by this user Quote this message in a reply
Streetboat Offline
Posting Freak

Posts: 1,098
Joined: Mar 2011
Reputation: 56
Post: #3
RE: Fancy door + quest scripting.

All right, thank you, that's definitely a start. I want to do more than just copy and paste that, though, I want to understand what to do.

So, I set a variant in order to tell the game that the game can't unlock the door unless I have the key AND the fire is lit? What do I put for that integer? Also, where can I tell it to say "Your fingers are too frozen for that" when I try to use the key without the fire? Without that text, the player won't have any clue why he can't use it.

Thank you very much for your help!

[Image: signature-2.png]
03-18-2011 09:45 PM
Find all posts by this user Quote this message in a reply
Nye Offline
Senior Member

Posts: 250
Joined: Jan 2011
Reputation: 2
Post: #4
RE: Fancy door + quest scripting.

(03-18-2011 09:45 PM)Streetboat Wrote:  All right, thank you, that's definitely a start. I want to do more than just copy and paste that, though, I want to understand what to do.

So, I set a variant in order to tell the game that the game can't unlock the door unless I have the key AND the fire is lit? What do I put for that integer? Also, where can I tell it to say "Your fingers are too frozen for that" when I try to use the key without the fire? Without that text, the player won't have any clue why he can't use it.

Thank you very much for your help!

Eugh, I was in a hurry to go to dinner when I posted that reply, so I didn't give it enough detail Tongue

Okay, here goes:

The integer which you set for the local variant, can take any value. For example, 0, 1, 2 , 3, 5, 10, 100.

When you set the local variant, to for example, 1, when the game calls that variable, it will see that it holds the value, "1".

We can manipulate this system. So, when the player interacts with the door, WITHOUT lighting the fire, the first thing you want to put inside the function is:
if(GetLocalVarInt("FireLit") != 1)
{
    SetMessage("CATEGORY NAME", "ENTRY NAME", TIME DISPLAYED);
}

By default, the game will run the procedure and unless you have already specified the value of your local variant, it will default to 0. In this case, it will run all the functions you have put inside the curly braces, as 0 is not 1, so it will show the message (until "FireLit" takes the value 1)

In the above case, the player will see the message stored in your extra_english.hps file, under the category and entry name you have chosen and display for the custom time you choose.

Now, second. We want to add a second 'IF' statement within our function that is called when we interact with the door.
if(GetLocalVarInt("FireLit") == 1)
{
    INSERT STUFF FOR WHEN THE THE FIRE IS LIT AND THE DOOR OPENS ETC.
}

Now, only when the FireLit local variant takes the value 1, will the game run the stuff located in-between the curly braces.

However, in order for the game to recognise when the player has lit the fire, upon running the function called when the player LIGHTS the fire, you need to add the line
SetLocalVarInt("FireLit", 1);
Reading this out loud is: "Set the local variant, "FireLit" to take the value 1."

And as an example for the if statements above, "If the local variant "FireLit" does NOT equal 1, then...INSERT STUFF in-between the curly bracket/braces."

(!= means NOT equal is not assigned to...) and (== means equal/IS assigned to...).

I hope this helped a little better, local variants are MASSIVELY useful for lots of things, especially when making larger, more complex custom stories Smile

If you get stuck, copy and paste your script and I will show you what you need to do Smile

(This post was last modified: 03-18-2011 10:03 PM by Nye.)
03-18-2011 10:00 PM
Find all posts by this user Quote this message in a reply
Streetboat Offline
Posting Freak

Posts: 1,098
Joined: Mar 2011
Reputation: 56
Post: #5
RE: Fancy door + quest scripting.

All right, so here's the order of things I want:

Interact with door:
If key != in inventory, display message "I need a key."
If key == in inventory, keep key and display message "My hands are too cold, I need to warm them up."

Light fire:
If key != in inventory, nothing happens.
If key == in inventory, it will now work on door.

I need to do some inventory things to make this work, it seems.

Here's my code, anyways
void UsedKeyOnDoor(string &in asItem, string &in asEntity)
    {
    if(GetLocalVarInt("FireLit") == 1)
        {
        SetSwingDoorLocked("cellar_wood01", false, true);
        PlaySoundAtEntity("", "unlock_door", "cellar_wood01", 0, false);
        RemoveItem("shop_key");
        }
    if(GetLocalVarInt("FireLit") != 1)
        {
        SetMessage("00_woodshop", "LockedDoorNoFire", 0);
        }
    }
void getwarm(string &in EntityName, string &in Type)
    {
        if(Type == "OnIgnite")
        {
        CompleteQuest("questtext1","questtext1");
        GiveSanityBoost();
        SetLocalVarInt("firelit", 1);
        }
    }

It looks good to me, but it's missing parts, such as checking the inventory for the key when the door is used.
This is really complicated considering I just started working with this code two days ago, but if it works this is gonna be great. Big Grin
Okay, so the code I just pasted above works almost perfectly. The only problem is that once the fire is lit, the key doesn't work on the door. It says "Can't use item this way!". However, the key does give the message that your hands are too cold if you use it without the fire. HOWEVER, if you light the fire before you pick the key up, the key works.

[Image: signature-2.png]
(This post was last modified: 03-18-2011 10:53 PM by Streetboat.)
03-18-2011 10:27 PM
Find all posts by this user Quote this message in a reply
Nye Offline
Senior Member

Posts: 250
Joined: Jan 2011
Reputation: 2
Post: #6
RE: Fancy door + quest scripting.

I would rethink your logic slightly. There is no such thing as an 'inventory search'. You need to add a collide callback for when the player picks up the key.

Here is the structure I suggest you use:
0 Player INTERACTS with door // note: NOT using the key on door
   0.1 If local variant "DoorUnlocked" != 1 then
        0.1.1 Display the message, "The door is locked!"

1 Player USES KEY on door (UseItem Callback)
  1.1 If local variant "FireLit" != 1 then
        1.1.1 Display message "My hands are too cold to do that!"
  1.2 If local variant "FireLit" == 1 then
        1.2.2 Unlock the door.
        1.2.3 Set local variant "DoorUnlocked" to 1.
        1.2.4 Remove key from inventory.

Your next question will probably be about callbacks, but it is late now, so ask any questions and I will check this thread again tomorrow morning Smile

(This post was last modified: 03-19-2011 12:26 AM by Nye.)
03-19-2011 12:21 AM
Find all posts by this user Quote this message in a reply
Pandemoneus Offline
Senior Member

Posts: 328
Joined: Sep 2010
Reputation: 0
Post: #7
RE: Fancy door + quest scripting.

Btw,

if(GetLocalVarInt("FireLit") == 1) {
...
}
else
{
...
}

would do the same.

03-19-2011 02:02 AM
Find all posts by this user Quote this message in a reply
Streetboat Offline
Posting Freak

Posts: 1,098
Joined: Mar 2011
Reputation: 56
Post: #8
RE: Fancy door + quest scripting.

Yeah, I'm confused. My problem is, It appears that after the script runs once, it won't run again. If I try the key with frozen hands, it gives the message and all is well. If I then go on to light the fire and try again, it says "Cannot use item this way!"

If I light the fire first and then use the key, it works like a charm. It seems that once I run the script once either way, it won't work again. I don't understand.

Also, I simply cannot get it to display the text when I use the door normally while it is locked. Sad
code:
void locked1(string &in EntityName, string &in Type)
        {
        SetMessage("woodshop", "InteractLockedDoor", 0);
        }

And I have 'locked1' as the PlayerInteractCallBack on the door itself. That same system worked just fine for my lantern script. :/

[Image: signature-2.png]
03-19-2011 02:43 AM
Find all posts by this user Quote this message in a reply
Streetboat Offline
Posting Freak

Posts: 1,098
Joined: Mar 2011
Reputation: 56
Post: #9
RE: Fancy door + quest scripting.

Additional problem: Could anyone possibly tell me what's wrong with this script? It's a different level from the other one. There are 00_woodshop and 01_house in terms of levels. When the player enters an area in 01_house, it's supposed to do what's in this script, but it just crashes instead. Is it not possible to check and see if a VarInt from another level is true? My first attempt was an 'if... else' using "HasItem" and checking for the lantern, but that also crashed. What am I doing wrong?
void OnStart()
    {
    AddEntityCollideCallback("Player", "needlantern", "lantern_warn", true, 1);
    }
void lantern_warn(string &in asParent, string &in asChild, int alState)
    {
    if (GetLocalVarInt("HasLantern") == 1)
        {
        PlaySoundAtEntity("scare_dog", "scare_animal_squeal2.snt", "needlantern", 0, true);
        AddTimer("dogreact", 0.5f, "scaredgasp2");
        }
    else
        {
        PlaySoundAtEntity("scare_dog", "scare_animal_squeal2.snt", "needlantern", 0, true);
        SetPlayerCrouching(true);
        AddTimer("dogreact", 0.5f, "scaredgasp2");
        SetMessage("house", "TooDark", 0);
        AddQuest("questtext2","questtext2");
        }
    }
void scaredgasp2(string &in asTimer)
    {
    PlayMusic("react_scare3",false,100.0f,0.0f,1,false);
    GiveSanityDamage(10.0f,true);
    GiveHint("sanity", "Hints", "Sanity", 0);
    }
I have a callback on the lantern in the other level's script that sets "HasLantern" to 1 when it's picked up.

[Image: signature-2.png]
(This post was last modified: 03-19-2011 08:13 AM by Streetboat.)
03-19-2011 08:05 AM
Find all posts by this user Quote this message in a reply
Nye Offline
Senior Member

Posts: 250
Joined: Jan 2011
Reputation: 2
Post: #10
RE: Fancy door + quest scripting.

As for your first problem, regarding the callback being removed upon being run, when you declare the callback, for example:

AddEntityCollideCallback("Player", "needlantern", "lantern_warn", true, 1);

The boolean expression, 'true' in the above case is the answer to "Delete on collide?". Changing this to false will stop it deleting on collide. So, in your case, to allow the player to use the key more than once. I always find the 'Script Functions' page on the Wiki is handy

http://wiki.frictionalgames.com/hpl2/amn..._functions

So, if we use an entity collide callback, the syntax is
AddEntityCollideCallback(string& asParentName, string& asChildName, string& asFunction, bool abDeleteOnCollide, int alStates);

If we wanted to allow two entities to collide and run the associated procedure more than once, we would change the boolean value 'bool abDeleteOnCollide' to false.

Regarding the key on the door, the syntax and your syntax for the using key on door callback is:
AddUseItemCallback(string& asName, string& asItem, string& asEntity, string& asFunction, bool abAutoDestroy);

Notice the 'boola abAutoDestroy'. We want this to be false, so that it doesn't remove the key each time. It's a little more complicated with items, since, you will then need to add another local variant check, when you run the procedure. For example:

void OnStart()
{
    AddUseItemCallback("", "shop_key", "cellar_wood01", "UsedKeyOnDoor", false);
}

void  UsedKeyOnDoor(string &in asItem, string &in asEntity)
{
    if (GetLocalVarInt("FireLit") != 1)
    {
        SetMessage("woodshop", "HandsTooCold", 0);
    }
      if (GetLocalVarInt("FireLit") == 1)
    {
          RemoveItem("shop_key");
          GiveSanityBoost();
          SetSwingDoorLocked("cellar_wood01", false, true);
          PlaySoundAtEntity.... etc etc
    }
}

Also, you can use an 'else' statement, to make it a bit quicker, as Pandemoneus says, but I find it is easier to understand what you were doing, using just if statements where possible.
--------------------------------------------------------------------
With your second script, try ensuring that you have
void OnLeave()
{

}
AND
void OnEnter()
{


}
in your script file somewhere, else it wont run.

(This post was last modified: 03-19-2011 08:49 AM by Nye.)
03-19-2011 08:47 AM
Find all posts by this user Quote this message in a reply
Post Reply 




User(s) browsing this thread: 1 Guest(s)