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

Items that the player can pick up


This tutorial shows you how to place items on the screen, and allow the player to pick them up.

Step 1: Draw the item

You need to draw two views. One is the item as shown on the screen, and the other is a close-up view used for when the player has it in their inventory and examines it. The latter should also have a description.

Step 2: Adding the item to the OBJECT file.

Because this is an item that the player will be able to carry around in their inventory, it must be added to the OBJECT file. The name of the file is a little confusing - it actually has nothing to do with what we normally refer to as objects (screen objects), but it contains the list of names of inventory objects (which I always refer to as inventory items). The name of item 1 should be set to "portable radio". This is the name that will be displayed in the inventory screen when the player has the radio.

The room number for this item should also be set to 2. This is the room number the item is to be found in, and will be used later to determine if the radio is in the room or not (if set to 255, then the item is put in the player's inventory).

Step 2: Placing the item in the room

To put the item in the room, we will use an object. For this example I will use object 1, but I want to refer to it as "radio", so I will define "radio" as o1 at the top of the logic:

#define radio o1

The object is set up by putting the following code in the initialization section of the room's logic:

animate.obj(radio);
load.view(2);
set.view(radio,2);
set.loop(radio,0);
set.cel(radio,0);
position(radio,43,104);
set.priority(radio,11);
ignore.objs(radio);
stop.cycling(radio);
draw(radio);

The first 8 lines basically say the following: I want to use the radio object. Load view 2 into memory and assign it to the radio. I initially want to display cel 0 of loop 0, and position it at 43,104 with a priority of 11. And I don't want it to obstruct or be obstructed by other objects (such as ego).

The priority is set to 11 because that is the same priority as the bench (as you'll see in the picture included with the tutorial game). This means that when ego is behind the bench, it will also be behind the radio and when it is in front of the bench it will also be in front of the radio.

The stop.cycling command is used to stop it from cycling through the cels in the loop. There is only 1 cel in the loop for this object, so the command isn't really necessary, but it is a good idea to do so in case you add some more cels later or something. The set.loop and set.cel commands aren't absolutely necessary either, but it'is also a good idea to use them so you know for sure which loop and which cel is being used.

The draw command makes the object visible on screen.

Step 3: Modifying logic 90 to handle the new item

Logic 90 in the template game (and hence games that are based on the template game) handles non-room specific game functions - things like the player asking to examine items that they have in their inventory (e.g. typing "look keycard" and being shown a close-up view of the keycard along with a description). There are also responses to inputs like "get <something>" and "look <something>" that haven't yet been parsed by other logics (in each interpreter cycle, logic 90 is always called AFTER the room's logic), so for example if the player is in a forest and types "get remote control" they'll get a response like "You can't get that here!" because there is no remote control in the forest, and hence that input hasn't been parsed (responded to) by the room's logic.

So for every inventory item in the game, there should be some code to handle player inputs regarding those items. I always put responses to the inputs "look <item>" and "get <item>".

If the player types "look <item>" and they have the item in their inventory, the show.obj command is used to show them a close-up of the inventory item along with a description. If they don't have the item in their inventory, the flag input_parsed is reset so that the if (said("look","anyword")) command will pick it up afterwards and say "What? Where?".

if (said("look","radio")) {
  if (has("portable radio")) {
    show.obj(220);  // 220 is the number of the view with the
                    // close-up and description of the radio.
  }
  else {
    reset(input_parsed);
  }
}

Here is the code that responds to the player's "look" input if it hasn't been parsed yet:

if ((said("look", "anyword") ||
  said("look", "anyword", "anyword"))) {
  print("What? Where?");
}

Remember, the said test command always returns false if the input_parsed flag is set (so the player doesn't get multiple responses), and always sets the input_parsed flag when it returns true. So when the player types "look radio", and they don't have the radio, input_parsed is reset so the second bit of code will give the response instead of the first.

In the room that the object is to be found, there should be a test to see if the player has types "look <item>". If the item is in that room (which can be tested for using the obj.in.room test command), then it should give a brief description of the item. Otherwise, it should reset the input_parsed so that logic 90 will take care of it. Logic 90 will test for the player typing "look <item>", and if they have the item it will show the close-up. But if they don't have the item, it will reset input_parsed so that the bit down the bottom will give the response "What? Where?".

I know this technique wasn't used in the template game, but I came up with it after that was written.

The other response I put in is to the input "get <item>". This is done in basically the same way as the response to "look <item>":

if (said("get","radio")) {
  if (has("portable radio")) {
    print("You already have it.");
  }
  else {
    reset(input_parsed);
  }
}

The modified logic 90 should look like this:

// ****************************************************************************
//
// Logic 90: Game-specific functions
//
// You should use this logic to perform any game specific functions, such as
// counting down timers, etc and processing player input related to the game
// (such as examining/using inventory items) and any other things that are
// required in several rooms that you don't want to duplicate in each room.
//
// This logic is called from logic 0, on every cycle.
// If you like, you could only make it called only when disable_game_functions
// is not set.
//
// Sierra did not use a separate logic for all this - they just did it all
// from logic 0. I find it is neater this way, as you can keep your game
// specific processing separate from other system-related things (although
// these may require some modification for your game). Also, this makes logic 0
// easier to manage.
//
// ****************************************************************************

#include "defines.txt"

// put all non-input-reponse game functions here

if (input_recieved &&
    unknown_word_no == 0 &&
    !input_parsed) {

// put various input responses here
  
  if (said("die")) {     // this one should not be in your game - it is
    load.view(1);        // only to demostrate the death handler (logic 94)
    set.view(ego,1);
    program.control();
    stop.motion(ego);
    death_type = 1;
  }

  if (said("look","radio")) {
    if (has("portable radio")) {
      show.obj(220);  // 220 is the number of the view with the
                      // close-up and description of the radio.
    }
    else {
      reset(input_parsed);
    }
  }
  
  if (said("get","radio")) {
    if (has("portable radio")) {
      print("You already have it.");
    }
    else {
      reset(input_parsed);
    }
  }

  if ((said("look", "anyword") ||
       said("look", "anyword", "anyword"))) {
    print("What? Where?");
  }
  
  if ((said("get", "anyword") ||
       said("get", "anyword", "anyword"))) {
    print("You can't get that here!");
  }
  
  if ((said("use", "anyword") ||
       said("use", "anyword", "anyword"))) {
    print("What do you want me to do with it?");
  }
}

return();

Step 4: Allowing the player to get the item

For the player to pick up the radio, they must walk near it and type "get radio". When they do this, we first check if the item is in the current room. Remember how we set the room number of the item back in step 2? This is where it comes in handy. If the player has the item in their inventory, it's room number will be 255, or if they have used it somewhere else then then it's room number will probably be 0 or the number of that room. So we test to see if it is in room 2. If it isn't, we reset input_parsed and let logic 90 give the response - if it's in the player's inventory they will be shown a close-up of it, otherwise they will be told it's not there (see step 3).

Next we test the ego's position on screen. If they're in the right position, we erase the radio object from screen and place the "portable radio" item in their inventory (the get command basically sets the item's room number to 255). Otherwise, they're told they are not close enough.

Note: The obj.in.room command only accepts a variable as the second parameter, so we must temporarily set the value of some variable (I'll use v255) to the room we want and then give that as the parameter.

This is done with the following code:

if (said("get","radio")) {
  v255 = 2;
  if (obj.in.room("portable radio",v255)) {
    if (posn(ego,37,111,51,124)) {
      print("Ok.");
      erase(radio);
      get("portable radio");
    }
    else {
      print("You're not close enough.");
    }
  }
  else {
    reset(input_parsed);    // let logic 90 take care of it
  }
}

Of course, the words "get" and "radio" must be present in the WORDS.TOK file.

Step 5: Responding to the player typing "look radio"

As mentioned in step 3, the room's logic should test for the player typing "look <item>" and if the item is in the current room, providing a brief description, or if it isn't, resetting input_parsed so logic 90 will give the response.

if (said("look","radio")) {
  v255 = 2;
  if (obj.in.room("portable radio",v255)) {
    print("There is a portable radio sitting on the bench.");
  }
  else {
    reset(input_parsed);    // let logic 90 take care of it
  }
}

Step 6: Only showing the item if it is in the room

In the initialization section, you'll notice that the item is always drawn on screen even if it is not supposed to be there. There is an easy way around this - and that is to test if the item is in the room before drawing it. Just replace this line from the initialization section:

draw(radio);

with this:

v255 = 2;
if (obj.in.room("portable radio",v255)) { draw(radio); }

The finished room with the radio in it should look something like this:

// ****************************************************************************
//
// Logic 2: Item tutorial room
//
// ****************************************************************************

#include "defines.txt"
#define radio o1

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

  animate.obj(radio);
  load.view(2);
  set.view(radio,2);
  set.loop(radio,0);
  set.cel(radio,0);
  position(radio,43,104);
  set.priority(radio,11);
  ignore.objs(radio);
  stop.cycling(radio);
  v255 = 2;
  if (obj.in.room("portable radio",v255)) { draw(radio); }

  // The next 6 lines need only be in the first room of the game
  if ((prev_room_no == 1 ||    // just come from intro screen
      prev_room_no == 0)) {    // or just started game
    position(ego,120,140);
    status.line.on();
    accept.input();
  }

  if (prev_room_no == 3) {
    position(ego,150,114);
  }

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

if (said("look")) {
  print("This is the room for the item tutorial.");
}

if (said("get","radio")) {
  v255 = 2;
  if (obj.in.room("portable radio",v255)) {
    if (posn(ego,37,111,51,124)) {
      print("Ok.");
      erase(radio);
      get("portable radio");
    }
    else {
      print("You're not close enough.");
    }
  }
  else {
    reset(input_parsed);    // let logic 90 take care of it
  }
}

if (said("look","radio")) {
  v255 = 2;
  if (obj.in.room("portable radio",v255)) {
    print("There is a portable radio sitting on the bench.");
  }
  else {
    reset(input_parsed);    // let logic 90 take care of it
  }
}

if (ego_edge_code == right_edge) {    // ego touching right edge of screen
  new.room(3);
}

return();