CODE: Secret doors, hidden objects and search.

From: Homer Simpson (fcolvin@metz.une.edu.au)
Date: 09/24/96


Hiya all,
         as quite a few people wanted this I'll just post it to the list.
I think I have made it quite clear as to what, and where, needs to be
added. One little problem you may come across is that I have changed my
auto_exits command to show closed doors with a # after them. It shouldn't
be that much work however to add the code with stock code however.
  Also I might have missed something as there are a lot of little things
which need to be changed for the effect to work. I'd suggest therefore
that you backup all the files you are going to change before adding the
code. Also I dont really want to support the code as I am busy adding new
stuff to my own mud. So sorry, add and use at your own risk.

Homer :)


If all this adds and works correctly then the following are used in wld
and zon and obj files to signify hidden objects and doors.


For objects:
------------

Extra (Effects) Bitvector

131072 r  HIDDEN         The item is hidden.


For worlds:
-----------

door flags

0   No door.
1   Normal door.
2   Pickproof door.
3   Secret no-door.
4   Secret normal door.
5   Secret Pickproof door.


For zones:
----------

NOTE: Make sure you add these for each secret door, otherwise the door
won't reset each time the door repops. Even if the is no door to open,
close etc.

for the D command

state can be

0   Open door.
1   Door closed.
2   Door locked.
3   Secret door/no door.
4   Secret closed door.
5   Secret locked door.



Now to the code.

Add those lines which have ++ before them.

Add the following in structs.h
------------------------------

#define EX_LOCKED		(1 << 2)   /* The door is locked	*/
#define EX_PICKPROOF	(1 << 3)   /* Lock can't be picked	*/
++#define EX_SECRET       (1 << 4)   /* Secret exit           */


#define ITEM_ANTI_WARRIOR  (1 << 15)    /* Not usable by warriors     */
#define ITEM_NOSELL	   (1 << 16)    /* Shopkeepers won't touch it */
++#define ITEM_HIDDEN        (1 << 17)    /* Item is hidden             */


Add the following to utils.h
----------------------------

/* End of CAN_SEE */

++#define HIDDEN_OK_OBJ(obj)  (!IS_OBJ_STAT((obj), ITEM_HIDDEN))

#define INVIS_OK_OBJ(sub, obj) \
  (!IS_OBJ_STAT((obj), ITEM_INVISIBLE) || IS_AFFECTED((sub), AFF_DETECT_INVIS))

++#define MORT_CAN_SEE_OBJ(sub, obj) (LIGHT_OK(sub) && INVIS_OK_OBJ(sub, obj) && HIDDEN_OK_OBJ(obj))


Add the following to act.informative.c
--------------------------------------

**In do_auto_exits**

  for (door = 0; door < NUM_OF_DIRS; door++) {
++    if (EXIT(ch, door) && EXIT(ch, door)->to_room != NOWHERE && !IS_SET(EXIT(ch, door)->exit_info, EX_SECRET)) {
      if ((IS_SET(EXIT(ch, door)->exit_info, EX_CLOSED)) || (IS_SET(EXIT(ch, door)->exit_info, EX_LOCKED)))
        sprintf(buf, "%s%c# ", buf, LOWER(*dirs[door]));
      else
        sprintf(buf, "%s%c ", buf, LOWER(*dirs[door]));
    }
  }


**In ACMD(do_exits)**

  for (door = 0; door < NUM_OF_DIRS; door++)
    if (EXIT(ch, door) && EXIT(ch, door)->to_room != NOWHERE &&
++        !IS_SET(EXIT(ch, door)->exit_info, EX_SECRET)) {
      if (GET_LEVEL(ch) >= LVL_IMMORT)


**In look_in_direction**

void look_in_direction(struct char_data * ch, int dir)
{
++  if (EXIT(ch, dir) && !IS_SET(EXIT(ch, dir)->exit_info, EX_SECRET)) {
    if (EXIT(ch, dir)->general_description)
      send_to_char(EXIT(ch, dir)->general_description, ch);
    else
      send_to_char("You see nothing special.\r\n", ch);



Add the following in act.other.c
--------------------------------

At the top in the extern declerations

extern char *class_abbrevs[];
++extern struct obj_data *obj_list;
++extern int rev_dir[];


Add the all the following. I added it just above do_hide.
NOTE: In the function get_roll, I have just put any numbers into the
if statements. I would strongly suggest changing them to reflect prices
and object weights in your mud.


int get_roll(struct obj_data *obj)
{
  int roll = 20;

  if (GET_OBJ_COST(obj) > 100)
    roll -= 15;
  else if (GET_OBJ_COST(obj) > 50)
    roll -= 10;
  else if (GET_OBJ_COST(obj) > 10)
    roll -= 5;
  else
    roll = roll;
        
  if (GET_OBJ_WEIGHT(obj) > 20)
    roll += 10;
  else if (GET_OBJ_WEIGHT(obj) > 10)
    roll += 5;
  else if (GET_OBJ_WEIGHT(obj) > 5)
    roll += 2;
  else
    roll = roll;
        
  if (roll < 1)
    roll = 2;

  return (roll);
}


ACMD(do_search)
{
  byte percent;
  struct obj_data *obj = NULL;
  struct char_data *person = NULL;
  int roll;
  int temp = 0;
  int door;
  int other_room;

  one_argument(argument, arg);

  if (IS_AFFECTED(ch, AFF_BLIND))
    send_to_char("You're blind! How can you search for anything?\r\n", ch);
  else if ((IS_DARK(ch->in_room)) && (!CAN_SEE_IN_DARK(ch)))
    send_to_char("It's too dark to search for anything!\r\n", ch);
  else {
    if (!*arg) {
      for (obj = world[ch->in_room].contents; obj; obj = obj->next_content) {
        if (IS_OBJ_STAT(obj, ITEM_HIDDEN)) {
          roll = get_roll(obj);
          percent = number(1, 101);
          if (percent <= roll) {
            REMOVE_BIT(obj->obj_flags.extra_flags, ITEM_HIDDEN);
            sprintf(buf, "You found %s.\r\n", obj->short_description);
            send_to_char(buf, ch);
            WAIT_STATE(ch, PULSE_VIOLENCE * 4);
            return;
          }
        }
      }
      for (person = world[ch->in_room].people; person; person = person->next_in_room) {
        if ((ch != person) && (IS_AFFECTED(person, AFF_HIDE))) {
          temp = MAX((GET_SKILL(person, SKILL_HIDE) / 4), (GET_LEVEL(person) / 2));
          roll = 35 - MIN(25, temp);
          percent = number(1, 101);
          if (percent <= roll) {
            REMOVE_BIT(AFF_FLAGS(person), AFF_HIDE);
            sprintf(buf, "You point out %s cowering in the shadows.\r\n", person->player.short_descr);
            send_to_char(buf, ch);
            act("$n points out $N cowering in the shadows.", TRUE, ch, 0, person, TO_ROOM);
            WAIT_STATE(ch, PULSE_VIOLENCE * 4);
            return;
          }
        }
      }
      for (door = 0; door < NUM_OF_DIRS; door++) {
        if (EXIT(ch, door)) {
	  if (IS_SET(EXIT(ch, door)->exit_info, EX_SECRET)) {
            other_room = (EXIT(ch, door)->to_room);
            roll = 20 + ((GET_DEX(ch) + GET_INT(ch)) / 2);
            percent = number(1, 101);
            if ((percent <= roll) && (other_room != NOWHERE)) {
              TOGGLE_BIT(world[ch->in_room].dir_option[door]->exit_info, EX_SECRET);
              TOGGLE_BIT(world[other_room].dir_option[rev_dir[door]]->exit_info, EX_SECRET);
              send_to_char("You found a secret door.\r\n", ch);
              act("$n found a secret door.", TRUE, ch, 0, 0, TO_ROOM);
              WAIT_STATE(ch, PULSE_VIOLENCE * 4);
              return;
            }
          }
        }
      }
    }
    else {
      if (!generic_find(arg, FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP, ch, &person, &obj)) {
        sprintf(buf, "There doesn't seem to be %s %s here.\r\n", AN(arg), arg);
        send_to_char(buf, ch);
        return;
      }
      else if (GET_OBJ_TYPE(obj) != ITEM_CONTAINER) {
        send_to_char("You can't search that!\r\n", ch);
        return;
      }
      else {
        if (IS_SET(GET_OBJ_VAL(obj, 1), CONT_CLOSED)) {
          send_to_char("Maybe you should try opening it first.\r\n", ch);
          return;
        }
        else {
          for (obj = obj->contains; obj; obj = obj->next_content) {
            if (IS_OBJ_STAT(obj, ITEM_HIDDEN)) {
              roll = get_roll(obj);
              percent = number(1, 101);
              if (percent <= roll) {
                REMOVE_BIT(obj->obj_flags.extra_flags, ITEM_HIDDEN);
                sprintf(buf, "You found %s.\r\n", obj->short_description);
                send_to_char(buf, ch);
                WAIT_STATE(ch, PULSE_VIOLENCE * 4);
                return;
              }
            }
          }
        }
      }
    }
  }
  send_to_char("You didn't find anything you didn't see before.\r\n", ch);
  WAIT_STATE(ch, PULSE_VIOLENCE * 4);
}



Add the following in act.movement.c
-----------------------------------

**In perform_move**

  struct follow_type *k, *next;

  if (ch == NULL || dir < 0 || dir >= NUM_OF_DIRS)
    return 0;
++  else if (!EXIT(ch, dir) || EXIT(ch, dir)->to_room == NOWHERE || IS_SET(EXIT(ch, dir)->exit_info, EX_SECRET))
    send_to_char("Alas, you cannot go that way...\r\n", ch);
  else if (IS_SET(EXIT(ch, dir)->exit_info, EX_CLOSED)) {


Change the define for DOOR_IS_OPENABLE to

#define DOOR_IS_OPENABLE(ch, obj, door)	((obj) ? \
			((GET_OBJ_TYPE(obj) == ITEM_CONTAINER) && \
			(IS_SET(GET_OBJ_VAL(obj, 1), CONT_CLOSEABLE))) :\
			((IS_SET(EXIT(ch, door)->exit_info, EX_ISDOOR)) && \
			(!IS_SET(EXIT(ch, door)->exit_info, EX_SECRET))))


Add the following in interpreter.c
----------------------------------

ACMD(do_score);
++ACMD(do_search);
ACMD(do_send);


  { "sell"     , POS_STANDING, do_not_here , 0, 0 },
++  { "search"   , POS_STANDING, do_search   , 0, 0 },
  { "send"     , POS_SLEEPING, do_send     , LVL_GOD, 0 },


Add the following in db.c
-------------------------

**In setup_dir**

  if (t[0] == 1)
    world[room].dir_option[dir]->exit_info = EX_ISDOOR;
  else if (t[0] == 2)
    world[room].dir_option[dir]->exit_info = EX_ISDOOR | EX_PICKPROOF;
++  else if (t[0] == 3)
++    world[room].dir_option[dir]->exit_info = EX_SECRET;
++  else if (t[0] == 4)
++    world[room].dir_option[dir]->exit_info = EX_ISDOOR | EX_SECRET;
++  else if (t[0] == 5)
++    world[room].dir_option[dir]->exit_info = EX_ISDOOR | EX_PICKPROOF | EX_SECRET;
  else
    world[room].dir_option[dir]->exit_info = 0;


**In reset_zone**
Add case 3: to case 5: below case 2: :)


	case 2:
	  SET_BIT(world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
		  EX_LOCKED);
	  SET_BIT(world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
		  EX_CLOSED);
	  break;
      case 3:
	  REMOVE_BIT(world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
		     EX_LOCKED);
	  REMOVE_BIT(world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
		     EX_CLOSED);
	  SET_BIT(world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
		  EX_SECRET);
	  break;
      case 4:
	  REMOVE_BIT(world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
		     EX_LOCKED);
	  SET_BIT(world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
		  EX_CLOSED);
	  SET_BIT(world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
		  EX_SECRET);
	  break;
      case 5:
	  SET_BIT(world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
		  EX_LOCKED);
	  SET_BIT(world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
		  EX_CLOSED);
	  SET_BIT(world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
		  EX_SECRET);
	  break;
+-----------------------------------------------------------+
| Ensure that you have read the CircleMUD Mailing List FAQ: |
|   http://cspo.queensu.ca/~fletcher/Circle/list_faq.html   |
+-----------------------------------------------------------+



This archive was generated by hypermail 2b30 : 12/18/00 PST