The Wayback Machine - http://web.archive.org/web/20011213032525/http://members.ozemail.com.au:80/~ptrkelly/agi/docs/doors.html

Doors


This tutorial describes how to use a door in a room.

Step 1: Draw the doorway into the picture

Draw the doorway as if there is no door there, and you can see into the room behind the door. Also make sure there is a blue control line in front of the doorway so the player can't walk through it when the door is there. If the door is on the left or right wall (as in this example), the edge of the door closest to the front of the screen should be at the bottom of a priority band, and the wall beside it should be given the appropriate priority. This is so when the player walks through the door, they are hidden behind the wall but they can be seen when they walk in front of the wall.

We will place an object on top of the doorway, which will be used to show the door (either open or closed).

Step 2: Create a view for the door

The next thing to do is to create a view which will represent the door. The first cel in the view (cel 0) should show the door closed. The next few cels should show the door opening, and the last cel should show the door fully opened.

Note that I have only drawn the door itself, not the door frame. This is mainly because the left side of the door frame has a different priority to the rest of the door.

Now we have all the graphics we need. The next thing to do is to program the door into the room.

Step 3: Setting up the door object

We will place an object on screen which will show the door. We will call this object "door", so we have to define "door" as an object. At the top of the logic, put the following line:

#define door o1

I have used object 1 here but you may need to use a different object number of you have another object with that number.

We must now put some code in the initialization section to set up the object:

animate.obj(door);
load.view(3);
set.view(door,3);
set.loop(door,0);
set.cel(door,0);
position(door,24,118);
ignore.blocks(door);
ignore.objs(door);
set.priority(door,4);
stop.cycling(door);
draw(door);

The first 6 lines basically say the following: I want to use the door object. Load view 3 into memory and assign it to the door. I initially want to display cel 0 of loop 0, and position the bottom-left corner of the door at 24,117.

The ignore.blocks command tells the door object to ignore obstacles such as blue control lines. If this is not used, and there is a blue control line in the way of the door, it will move up or down so that it is not touching the line (which wouldn't look right). The ignore.objs command stops other objects (such as ego) from being blocked by the door's baseline (bottom row of pixels). And the set.priority command gives the door a priority of 4 so that the player will always be in drawn in front of it.

When you first set up an object, it cycles continuously through the cels in the current loop. Since we only want it on cel 0 initially, the stop.cycling command is used.

Then finally, we draw the door.

Step 4: Allowing the player to open the door

In order to open the door, the player must walk in front of it and type "open door". When they do this, an animation of the door opening will be played (by cycling the cels until the end of the loop is reached), and then the player will automatically walk through the doorway and into the next room.

The first piece of code we have to write is to detect whether the player has said "open door", and if so, test if they are in the correct position:

if (said("open","door")) {
  if (posn(ego,21,112,32,119)) {
    .........
  }
  else {
    print("You're not close enough.");
  }
}

Of course, the words "open" and "door" must be present in the WORDS.TOK file.

Now in order to play an animation of the door opening, we will use the end.of.loop command. This cycles through all the cels in the current loop until the last one, and then sets a flag. For this example, I'll give the flag the name "door_finished_opening" (the following line should go near the top with the other defines):

#define door_finished_opening f200

(you may have to use a different flag number if f200 is already in use)

Then, the end.of.loop command goes in place of the ....... in the previous section of code:

end.of.loop(door,door_finished_opening);

However, before the door opens, we should stop ego from moving, and prevent the player from controlling it:

stop.motion(ego);
program.control();

So the code for opening the door should look like this:

if (said("open","door")) {
  if (posn(ego,21,112,32,119)) {
    stop.motion(ego);
    program.control();
    end.of.loop(door,door_finished_opening);
  }
  else {
    print("You're not close enough.");
  }
}

Next we write the code which moves the player through the doorway once the door has finished opening. To detect when to do this, we test to see if the flag door_finished_opening is set. When it is, we use the move.obj command to move ego into a certain position on the other side of the door. The flag ego_through_doorway needs to be defined first:

#define ego_through_doorway f201

(This should go up the top with the other defines)

Then, the following code goes in the main part below the previous block of code:

if (door_finished_opening) {
  reset(door_finished_opening);  // If door_finished_opening remains set, the
                                 // following code will be executed on every
                                 // cycle (which we don't want).
  ignore.blocks(ego);        // allow ego to cross the blue control line
  move.obj(ego,21,114,1,ego_through_doorway);
}

The move.obj command moves ego to 21,114 with a step size of 1 (i.e. ego moves 1 pixel every cycle) and when ego reaches this position, the flag ego_through_doorway is set. When this flag is set, we want to take the player to a new room:

if (ego_through_doorway) {
  observe.blocks(ego);
  new.room(2);
}

Once all this code is in the logic, the player will be able to open the door and go through it. There is one final thing we have to do for this, however, and that is to make sure the two flags we are using are not initially set. It is possible that one or both of these was set in the previous room we were in, and if so, ego might start moving back through the door as soon as the player enters the room. This potential problem is solved by resetting both flags in the initialization section:

reset(door_finished_opening);
reset(ego_through_doorway);

At this stage, the room's logic should look something like this:

// ****************************************************************************
//
// Logic 3: Door tutorial room
//
// ****************************************************************************

#include "defines.txt"
#define door o1
#define door_finished_opening f200
#define ego_through_doorway f201

if (new_room) {
  load.pic(room_no);
  draw.pic(room_no);
  discard.pic(room_no);
  set.horizon(50);

  animate.obj(door);
  load.view(3);
  set.view(door,3);
  set.loop(door,0);
  set.cel(door,0);
  position(door,24,118);
  ignore.blocks(door);
  ignore.objs(door);
  set.priority(door,4);
  stop.cycling(door);
  draw(door);

  reset(door_finished_opening);
  reset(ego_through_doorway);

  draw(ego);
  show.pic();
}

if (said("look")) {
  print("You are in the room for the door tutorial.");
}

if (said("open","door")) {
  if (posn(ego,21,112,32,119)) {
    stop.motion(ego);
    program.control();
    end.of.loop(door,door_finished_opening);
  }
  else {
    print("You're not close enough.");
  }
}

if (door_finished_opening) {
  reset(door_finished_opening);  // If door_finished_opening remains set, the
                                 // following code will be executed on every
                                 // cycle (which we don't want).
  ignore.blocks(ego);        // allow ego to cross the blue control line
  move.obj(ego,21,114,1,ego_through_doorway);
}

if (ego_through_doorway) {
  observe.blocks(ego);
  new.room(2);
}

return();

Step 5: Making the player enter the room through the door

If the player is allowed to go through the door to get into the next room, then when they come back from the next room they should be shown coming through the door. For this, we basically do the reverse of what we did for when they exit the room through the door.

In the initialization section, we must determine if they have come from the room that is behind the door (in this example, room 2), and if so, set the door to be initially open, make the player walk through the doorway, then close the door. For this we will use two flags, ego_exited_doorway and door_finished_closing, so these must be defined:

#define ego_exited_doorway f202
#define door_finished_closing f203

They should both be reset in the initialization section:

reset(ego_exited_doorway);
reset(door_finished_opening);

The first bit is done with the following code, placed in the initialization section just before the draw(ego) command:

if (prev_room_no == 2) {
  set.cel(door,4);
  position(ego,21,114);
  ignore.blocks(ego);
  move.obj(ego,31,114,1,ego_exited_doorway);
}

This changes the door to be open, positions ego just behind the door and starts moving it through the doorway into the room.

Then, in the main part of the room, the following code is added, which closes the door when ego has finished exiting the doorway.

if (ego_exited_doorway) {
  reset(ego_exited_doorway);
  observe.blocks(ego);
  reverse.loop(door,door_finished_closing);
}

The door_finished_closing does not actually do anything, but a flag is required by the reverse.loop command (which cycles through the cels in reverse until it gets to cel 0, then sets the flag).

Step 6: Providing a description for the door

The last (and easiest) thing that needs to be done is to provide a description for the door, so when the player types "look door" they will get an appropriate response. This of course is not required, but it makes the game more friendly if the player can "look" at everything that's in the room.

if (said("look","door")) {
  print("There is a red door in the left wall.");
}

The finished room should look something like this:

// ****************************************************************************
//
// Logic 3: Door tutorial room
//
// ****************************************************************************

#include "defines.txt"
#define door o1
#define door_finished_opening f200
#define ego_through_doorway f201
#define ego_exited_doorway f202
#define door_finished_closing f203

if (new_room) {
  load.pic(room_no);
  draw.pic(room_no);
  discard.pic(room_no);
  set.horizon(50);

  animate.obj(door);
  load.view(3);
  set.view(door,3);
  set.loop(door,0);
  set.cel(door,0);
  position(door,24,118);
  ignore.blocks(door);
  ignore.objs(door);
  set.priority(door,4);
  stop.cycling(door);
  draw(door);

  reset(door_finished_opening);
  reset(ego_through_doorway);
  reset(ego_exited_doorway);
  reset(door_finished_opening);

  if (prev_room_no == 2) {
    set.cel(door,4);
    position(ego,21,114);
    ignore.blocks(ego);
    move.obj(ego,31,114,1,ego_exited_doorway);
  }

  draw(ego);
  show.pic();
}

if (said("look")) {
  print("You are in the room for the door tutorial.");
}

if (said("look","door")) {
  print("There is a red door in the left wall.");
}

if (ego_exited_doorway) {
  reset(ego_exited_doorway);
  observe.blocks(ego);
  reverse.loop(door,door_finished_closing);
}

if (said("open","door")) {
  if (posn(ego,21,112,32,119)) {
    stop.motion(ego);
    program.control();
    end.of.loop(door,door_finished_opening);
  }
  else {
    print("You're not close enough.");
  }
}

if (door_finished_opening) {
  reset(door_finished_opening);  // If door_finished_opening remains set, the
                                 // following code will be executed on every
                                 // cycle (which we don't want).
  ignore.blocks(ego);        // allow ego to cross the blue control line
  move.obj(ego,21,114,1,ego_through_doorway);
}

if (ego_through_doorway) {
  observe.blocks(ego);
  new.room(2);
}

return();