Hey,
So I had one problem and that got solved and now I've run into another. So what I'm trying to do is that classic
puzzle in Point&Click games where you need to create a distraction so that a character will walk away and you can take something without
them looking. So let me lay out what I want to do. The location is a veterinary clinic.
I have a pair of gloves I want to pick up. I can't because of the desk clerk. There is a dog(a character) in a cage, I want to interact with the dog and
make it bark which will make the clerk leave her desk and I can take the gloves. I have a basic idea that involves if i get an item of the dog that lets me pick
up the gloves and I make the clerk walk to the dog but that would be too clunky. Is there a way to interact with the dog, make it bark in the background and allow me
to walk over to the desk, while the clerk goes to the cage and tells the dog to shut up (which stops it barking in the background.), allowing me to get the gloves, but not if the clerk comes back to the desk.
I believe I'd need to use the Set.Timer function but that's all I've got.
Thanks in advance.
Yeah, I had a similar problem a few weeks ago. You are correct the SetTimer-command is the right choice but not (only) in the way of setting a specific time frame where you can grab the gloves. This frame you have to design has to include:
the clerk going away,
looking after the dog for a specific time frame and
coming back until the point where he can see you.
But you need to use it in the repeatedly_execute_always function of your room though, to let the game do something while you can play and to check what you want (that it's save to take the gloves) in every time unit. But then you got a problem:
For your idea you can't use any game-blocking commands like "wait" or "say". Instead you have to use several SetTimers to simulate the "wait" which maybe also have to include for example your guy saying something to the dog with "SayBackground"(not blocking command) and waiting till he calms down.
Here is an idea:
{
//in room script header
bool dogbark = false;
function repeatedly_execute_always()
{
if (dogbark == true)
cDog.SayBackground("bark bark"); // you need another SetTimer there if you want him to do that in a sequence with pauses
// or use the "BackgroundSpeech" module (forum search) if you want him (or any other character ever) to SayBackground
// something with speech animation and "wait"s in beetween
if (IsTimerExpired(t)) // it is important to do SetTimer(t,1) after the (dogbark = true;) for the following actions and can be set optionally in advance,
// if you want to let the character wait before he responds
{
cClerk.UnlockView(); // Always good to do that before NPC actions
if (dogbark == true) // if the dog barks
{
cClerk.Walk(x, y, eNoBlock, eWalkableAreas);
cClerk.AddWaypoint(x, y); // make sure the character stands on the exact spot you want ( AGS is sometimes a bit buggy and not exact there)
SetTimer(t, 200); // The timer for standing by the dog until he says or does something
start=0; //prevents a loop
}
if (cClerk.x == x)
{
cClerk.LockView(view);
cClerk.Animate(loop, delay, eOnce, eNoBlock);
SetTimer(t2, 400); // set this second timer to an amount your NPC needs to do all you want him to do until he walks back
}
}
if (IsTimerExpired(t2))
cClerk.Walk(startx,starty,eNoBlock,eWalkableAreas);
if (cClerk.y <= [the "i see you" limit]) // to let him catch you
{
whatever you want to do
}
}
Not sure if it's all correct but i think this could work :)
First and foremost, since this is a bit more complex: use proper indentation.
Next, stuff like this is best handled using a state variable. If you use an enum, the code will become MUCH more readable.
// top of room script
enum ClerkState {
eStateBored, // at desk
eStateGoingToDog,
eStateTellingDogToShutUp,
eStateReturningToDesk
};
// state variables
ClerkState clerkstate = eStateBored;
int dogbarking = -1; // barking state and timer, -1 = no barking, otherwise countdown to bark
Overlay *shutup;
Next, handle talking to clerk and dog (I'm using the BASS template here):
// GlobalScript.asc
function cClerk_Interact() {
// handle in room script
if (player.Room == 2) CallRoomScript(1);
}
function cDog_Interact() {
if (player.Room == 2) CallRoomScript(2);
}
The actual handler code is in the room script, for tidiness reasons and access to room variables
void on_call(int p) {
// talk to cClerk
if (p == 1) {
if (clerkstate == eStateBored) dClerk1.Start();
else player.Say("She's busy.");
}
// talk to dog
if (p == 2) {
if (clerkstate != eStateBored) {
player.SayBackground("Not now.");
return;
}
// make dog bark, set stuff in motion
player.Walk(cDog.x, cDog.y + 10, eBlock);
player.FaceCharacter(cDog);
player.Say("Hiya, doggie! Want to go for a walk?");
// 20 frames till first bark
dogbarking = 20;
}
}
Finally, handle states in room's rep_ex_always:
Dog:
// handle dog's barking
if (dogbarking != -1) {
dogbarking--; // count down frames to next bark
if (dogbarking == 0) {
cDog.SayBackground("BARK!");
// first bark makes clerk walk over
if (clerkstate == eStateBored) {
clerkstate = eStateGoingToDog;
cClerk.SayBackground("Goddamn dog!");
cClerk.Walk(cDog.x - 5, cDog.y + 15);
}
// next bark two seconds from now
dogbarking = 80;
}
}
And clerk:
// arrived at dog
if (clerkstate == eStateGoingToDog && !cClerk.Moving) {
clerkstate = eStateTellingDogToShutUp;
cClerk.FaceCharacter(cDog, eNoBlock);
shutup = cClerk.SayBackground("Shut up!");
// dog stops barking
dogbarking = -1;
}
// done telling dog to "Shut up"
if (clerkstate == eStateTellingDogToShutUp && !shutup.Valid) {
clerkstate = eStateReturningToDesk;
cClerk.Walk(110, 225);
}
// arrived at desk
if (clerkstate == eStateReturningToDesk && !cClerk.Moving) {
cClerk.FaceLocation(cClerk.x, cClerk.y - 10, eNoBlock);
clerkstate = eStateBored;
}
Finally, getting the object:
function oBook_Interact()
{
if (Region.GetAtRoomXY(player.x, player.y) != region[1]) {
player.Say("I need to get closer.");
return;
}
if (clerkstate == eStateBored || clerkstate == eStateReturningToDesk) {
cClerk.SayBackground("Hey, you can't have that!");
return;
}
player.SayBackground("YOINK");
oBook.Visible = false;
player.AddInventory(iBook);
}
I'm using a region to check if the player is near the book so everything keeps being non-blocking.
Hey guys,
Kumpel I tried to implement yours and when I do, i get an error saying unidentified symbol 't'. Any idea?
Khris, I also tried yours but I don't think I put the scripts in the right place, could you tell me in the simplest way
possible where to place each script and how.
Sorry for the trouble guys.
Thanks.
Where each part goes is mentioned every single time.
Here's the complete room script: http://pastebin.com/EnPusLKa
This will very likely not work as-is, which is why I provided separate snippets so you can add the code to your existing room script.
Note that the snippets that start with "function" need to be linked to the appropriate events and will not work after simply pasting them.
The second and final snippet are example implementations; your characters are most likely named differently, and with your object being gloves, it probably won't make sense to use oBook_Interact().
My post is not intended as a full beginner's step by step tutorial; it requires a basic understanding of how the functions and events of AGS work.
these stuff are just placeholders the t-timer and t2-timer needs a number of course.
Hey,
Kumpel I tried yours again, fixing up the t stuff but it came up with another error, about if.
Khris I tried yours again and I ran into a problem but It was because I didn't change the room number and
when I did it now works perfectly.
Thank you both so much. You've been a big help.
Cool, you're welcome!