nakedmudv3.0/
nakedmudv3.0/lib/
nakedmudv3.0/lib/logs/
nakedmudv3.0/lib/misc/
nakedmudv3.0/lib/players/
nakedmudv3.0/lib/pymodules/
nakedmudv3.0/lib/txt/
nakedmudv3.0/lib/world/
nakedmudv3.0/lib/world/examples/
nakedmudv3.0/lib/world/examples/mproto/
nakedmudv3.0/lib/world/examples/oproto/
nakedmudv3.0/lib/world/examples/reset/
nakedmudv3.0/lib/world/examples/rproto/
nakedmudv3.0/lib/world/examples/trigger/
nakedmudv3.0/lib/world/limbo/
nakedmudv3.0/lib/world/limbo/rproto/
nakedmudv3.0/src/alias/
nakedmudv3.0/src/char_vars/
nakedmudv3.0/src/editor/
nakedmudv3.0/src/example_module/
nakedmudv3.0/src/help/
nakedmudv3.0/src/set_val/
nakedmudv3.0/src/socials/
nakedmudv3.0/src/time/
//*****************************************************************************
//
// inform.c
//
// These are all of the functions that are used for listing off processed
// information about things (e.g. room descriptions + contents, shopping
// lists, etc...)
//
//*****************************************************************************

#include "mud.h"
#include "utils.h"
#include "character.h"
#include "object.h"
#include "world.h"
#include "room.h"
#include "exit.h"
#include "extra_descs.h"
#include "body.h"
#include "races.h"
#include "handler.h"
#include "socket.h"
#include "log.h"
#include "inform.h"
#include "hooks.h"



//*****************************************************************************
// mandatory modules
//*****************************************************************************
#include "items/items.h"
#include "items/portal.h"
#include "items/container.h"
#include "items/furniture.h"



//*****************************************************************************
// local functions
//*****************************************************************************

//
// Show a character who is all sitting at one piece of furniture
//
void list_one_furniture(CHAR_DATA *ch, OBJ_DATA *furniture) {
  LIST *can_see = find_all_chars(ch,objGetUsers(furniture), "", NULL, TRUE);
  listRemove(can_see, ch);

  char *chars = print_list(can_see, charGetName, charGetMultiName);
  if(*chars) send_to_char(ch, "{g%s %s %s %s%s.\r\n",
			  chars, (listSize(can_see) == 1 ? "is" : "are"),
			  (furnitureGetType(furniture)==FURNITURE_AT?"at":"on"),
			  objGetName(furniture),
			  (charGetFurniture(ch) == furniture ?" with you": ""));
  // everyone was invisible to us... we should still show the furniture though
  else
    send_to_char(ch, "{g%s\r\n", objGetRdesc(furniture));
  deleteList(can_see);
  free(chars);
}


//
// Lists furniture that is assumed to be used. 
//
void list_used_furniture(CHAR_DATA *ch, LIST *furniture) {
  OBJ_DATA *obj;
  LIST_ITERATOR *obj_i = newListIterator(furniture);

  ITERATE_LIST(obj, obj_i)
    // hmmm... how should we handle invisible furniture?
    list_one_furniture(ch, obj);
  deleteListIterator(obj_i);
}


//
// Get a sublist of characters not using furniture. The returned list must
// be deleted after use.
//
LIST *get_nofurniture_chars(CHAR_DATA *ch, LIST *list, 
			    bool invis_ok, bool include_self) {
  LIST *newlist = newList();
  LIST_ITERATOR *char_i = newListIterator(list);
  CHAR_DATA *i = NULL;

  ITERATE_LIST(i, char_i) {
    // don't show ourself
    if(i == ch && !include_self) continue;
    // check for invis and hidden ...
    if(!(invis_ok || can_see_char(ch, i)))
      continue;
    // make sure they're not on furniture
    if(charGetFurniture(i))
      continue;
    listPut(newlist, i);
  };
  deleteListIterator(char_i);
  return newlist;
}


//
// uhhh... "contents" isn't really the right word, since we list both
// objects AND characters. Alas, my lexicon is not as verbose as it
// could be.
//
void list_room_contents(CHAR_DATA *ch, ROOM_DATA *room) {
  LIST *list = NULL;

  list = get_nofurniture_chars(ch, roomGetCharacters(room), FALSE, FALSE);
  show_list(ch, list, charGetRdesc, charGetMultiRdesc);
  deleteList(list);

  // show all of the objects that have people using them
  list = get_used_items(ch, roomGetContents(room), FALSE);
  list_used_furniture(ch, list);
  deleteList(list);

  // show all of the objects that don't have people using them that we can see
  list = get_unused_items(ch, roomGetContents(room), FALSE);
  show_list(ch, list, objGetRdesc, objGetMultiRdesc);
  deleteList(list);
}



//*****************************************************************************
// implementaiton of inform.h
// look_at_xxx and show_xxx functions.
//*****************************************************************************
void look_at_obj(CHAR_DATA *ch, OBJ_DATA *obj) {
  // make our working copy of the description
  BUFFER *new_desc = bufferCopy(objGetDescBuffer(obj));

  // do all of the preprocessing on the new descriptions
  hookRun("preprocess_obj_desc", new_desc, obj, ch);

  // colorize all of the edescs
  edescTagDesc(new_desc, objGetEdescs(obj), "{c", "{g");

  // format the desc, and send it
  bufferFormat(new_desc, SCREEN_WIDTH, PARA_INDENT);
  send_to_char(ch, "{g%s", bufferString(new_desc));

  // free up our mess
  deleteBuffer(new_desc);

  // list container-related stuff
  if(objIsType(obj, "container")) {
    send_to_char(ch, "{g%s is %s%s.\r\n",
		 objGetName(obj), 
		 (containerIsClosed(obj) ? "closed" : "opened"),
		 (containerIsLocked(obj) ? " and locked"  : ""));

    // print all of our contents
    if(listSize(objGetContents(obj)) > 0 && !containerIsClosed(obj)) {
      LIST *vis_contents = find_all_objs(ch, objGetContents(obj), "", 
					 NULL, TRUE);
      // make sure we can still see things
      if(listSize(vis_contents) > 0) {
	send_to_char(ch, "It contains:\r\n");
	show_list(ch, vis_contents, objGetName, objGetMultiName);
      }
      deleteList(vis_contents);
    }
  }

  // list furniture-related stuff
  else if(objIsType(obj, "furniture")) {
    int num_sitters = listSize(objGetUsers(obj));

    send_to_char(ch, "\r\n");

    // print character names
    if(num_sitters > 0) {
      LIST *can_see = find_all_chars(ch, objGetUsers(obj), "", NULL, TRUE);
      listRemove(can_see, ch);

      char *chars = print_list(can_see, charGetName, charGetMultiName);
      if(*chars) send_to_char(ch, "{g%s %s %s %s%s.\r\n",
			      chars, (listSize(can_see) == 1 ? "is" : "are"),
			      (furnitureGetType(obj)==FURNITURE_AT ? "at":"on"),
			      objGetName(obj),
			      (charGetFurniture(ch) == obj ? " with you" : ""));
      deleteList(can_see);
      free(chars);
    }

    // print out how much room there is left on the furniture
    int seats_left = (furnitureGetCapacity(obj) - num_sitters);
    if(seats_left > 0)
      send_to_char(ch, "{g%s looks like it could fit %d more %s.\r\n",
		   objGetName(obj), seats_left, 
		   (seats_left == 1 ? "person" : "people"));
  }
}


void look_at_exit(CHAR_DATA *ch, EXIT_DATA *exit) {
  send_to_char(ch, "{g%s", (*exitGetDesc(exit) ? exitGetDesc(exit) :
			    NOTHING_SPECIAL"\r\n"));
  // we have a door ... gotta print it's status
  if(exitIsClosable(exit)) {
    if(!*exitGetName(exit))
      send_to_char(ch, "It is %s.\r\n", (exitIsClosed(exit) ? "closed":"open"));
    else {
      send_to_char(ch, "You see %s. (%s)\r\n", 
		   exitGetName(exit), (exitIsClosed(exit) ? "closed":"open"));
    }
  }

  // the door is not closed, list off the people we can see as well
  if(!exitIsClosed(exit)) {
    ROOM_DATA *room = worldGetRoom(gameworld, exitGetTo(exit));
    if(room != NULL)
      list_room_contents(ch, room);
  }
}

//
// shows a single exit to a character
void list_one_exit(CHAR_DATA *ch, EXIT_DATA *exit, const char *dir) {
  char   buf[100] = "\0"; // for the room class
  ROOM_DATA *dest = worldGetRoom(gameworld, exitGetTo(exit));

  if(bitIsOneSet(charGetUserGroups(ch), "builder"))
    sprintf(buf, "[%s] ", roomGetClass(dest));

  send_to_char(ch, "{g  %-10s :: %s%s\r\n", dir, buf, 
	       (exitIsClosed(exit) ? 
		// if it's closed, print the exit name
		(*exitGetName(exit) ? exitGetName(exit) : "closed" ) :
		// if it's open, print where it leads to
		roomGetName(dest)));
}


void list_room_exits(CHAR_DATA *ch, ROOM_DATA *room) {
  EXIT_DATA     *exit = NULL;
  ROOM_DATA       *to = NULL;
  int               i = 0;
  LIST       *ex_list = roomGetExitNames(room);
  LIST_ITERATOR *ex_i = newListIterator(ex_list);
  char           *dir = NULL;

  // first, we list all of the normal exit
  for(i = 0; i < NUM_DIRS; i++) {
    if( (exit = roomGetExit(room, dirGetName(i))) != NULL) {
      // make sure the destination exists
      if( (to = worldGetRoom(gameworld, exitGetTo(exit))) == NULL)
	log_string("ERROR: room %s heads %s to room %s, which does not exist.",
		   roomGetClass(room), dirGetName(i), exitGetTo(exit));
      else if(can_see_exit(ch, exit))
	list_one_exit(ch, exit, dirGetName(i));
    }
  }

  // next, we list all of the special exits
  ITERATE_LIST(dir, ex_i) {
    if(dirGetNum(dir) == DIR_NONE) {
      exit = roomGetExit(room, dir);
      // make sure the destination exists
      if( (to = worldGetRoom(gameworld, exitGetTo(exit))) == NULL)
	log_string("ERROR: room %s heads %s to room %s, which does not exist.",
		   roomGetClass(room), dir, exitGetTo(exit));
      else if(can_see_exit(ch, exit))
	list_one_exit(ch, exit, dir);
    }
  } deleteListIterator(ex_i);
  deleteListWith(ex_list, free);
}


void show_body(CHAR_DATA *ch, BODY_DATA *body) {
  int i, num_bodyparts;
  const char **bodyparts = bodyGetParts(body, TRUE, &num_bodyparts);
  OBJ_DATA    *equipment = NULL;
  char posbuf[SMALL_BUFFER];
  for(i = 0; i < num_bodyparts; i++) {
    equipment = bodyGetEquipment(body, bodyparts[i]);
    if(!equipment || !can_see_obj(ch, equipment))
      continue;
    sprintf(posbuf, "{c<{C%s{c>{n", bodyparts[i]);
    send_to_char(ch, "%-30s %s\r\n", 
		 posbuf, objGetName(equipment));
  }
  if(bodyparts) 
    free(bodyparts);
}


void look_at_char(CHAR_DATA *ch, CHAR_DATA *vict) {
  // if we're an NPC, do some special work for displaying us. We don't do 
  // dynamic descs for PCs because they will probably be describing themselves,
  // and we don't want to give them access to the scripting language.
  if(!charIsNPC(vict))
    send_to_char(ch, "{g%s{n", (*charGetDesc(vict) ? 
				charGetDesc(vict) : NOTHING_SPECIAL"\r\n"));
  else {
    BUFFER *new_desc = bufferCopy(charGetDescBuffer(vict));

    // preprocess our desc before it it sent to the person
    hookRun("preprocess_char_desc", new_desc, vict, ch);
    
    // format and send it
    bufferFormat(new_desc, SCREEN_WIDTH, PARA_INDENT);
    send_to_char(ch, "{g%s{n", (bufferLength(new_desc) > 0 ?
				bufferString(new_desc): NOTHING_SPECIAL"\r\n"));

    // clean up our mess
    deleteBuffer(new_desc);
  }
  show_body(ch, charGetBody(vict));
}


void look_at_room(CHAR_DATA *ch, ROOM_DATA *room) {
  if(bitIsOneSet(charGetUserGroups(ch), "builder"))
    send_to_char(ch, "{c[%s] [%s] ", roomGetClass(room), 
		 terrainGetName(roomGetTerrain(room)));

  send_to_char(ch, "{c%s\r\n", roomGetName(room));

  // make the working copy of the description, and fill it up with info
  BUFFER *desc = bufferCopy(roomGetDescBuffer(room));

  // do all of our preprocessing of the description before we show it
  hookRun("preprocess_room_desc", desc, room, ch);

  // colorize all of the edescs
  edescTagDesc(desc, roomGetEdescs(room), "{c", "{g");

  // format our description
  bufferFormat(desc, SCREEN_WIDTH, PARA_INDENT);

  send_to_char(ch, "{g%s", bufferString(desc));
  list_room_exits(ch, room);
  list_room_contents(ch, room);

  send_to_char(ch, "{n");
  deleteBuffer(desc);
};



//*****************************************************************************
//
// implementaiton of inform.h
// send_to_xxx functions
//
//*****************************************************************************
void send_outdoors(const char *format, ...) {
  if(format && *format) {
    // form the message
    static char buf[MAX_BUFFER];
    va_list args;
    va_start(args, format);
    vsprintf(buf, format, args);
    va_end(args);

    // send it out to everyone
    LIST_ITERATOR *list_i = newListIterator(mobile_list);
    CHAR_DATA *ch = NULL;
    ITERATE_LIST(ch, list_i)
      if(roomGetTerrain(charGetRoom(ch)) != TERRAIN_INDOORS &&
	 roomGetTerrain(charGetRoom(ch)) != TERRAIN_CAVERN)
	text_to_char(ch, buf);
    deleteListIterator(list_i);
  }
}


void text_to_char(CHAR_DATA *ch, const char *txt) {
  //  if (txt && *txt && charGetSocket(ch) && 
  //      socketGetState(charGetSocket(ch)) == STATE_PLAYING) {
  if(txt && *txt && charGetSocket(ch)) {
    text_to_buffer(charGetSocket(ch), txt);
    socketBustPrompt(charGetSocket(ch));
  }

  // if it's a PC or we are not in game, then
  // don't send the mesage to us
  if(!charIsNPC(ch))
    try_log(charGetName(ch), txt);
}


void send_to_char(CHAR_DATA *ch, const char *format, ...) {
  if(charGetSocket(ch) && format && *format) {
    static char buf[MAX_BUFFER];
    va_list args;
    va_start(args, format);
    vsprintf(buf, format, args);
    va_end(args);
    text_to_char(ch, buf);
    return;
  }
}


void send_around_char(CHAR_DATA *ch, bool hide_nosee, const char *format, ...) {
  static char buf[MAX_BUFFER];
  va_list args;
  va_start(args, format);
  vsprintf(buf, format, args);
  va_end(args);

  LIST_ITERATOR *room_i = newListIterator(roomGetCharacters(charGetRoom(ch)));
  CHAR_DATA       *vict = NULL;

  ITERATE_LIST(vict, room_i) {
    if(ch == vict)
      continue;
    if(hide_nosee && !can_see_char(vict, ch))
      continue;
    text_to_char(vict, buf);
  }
  deleteListIterator(room_i);
  return;
}


void send_to_groups(const char *groups, const char *format, ...) {
  static char buf[MAX_BUFFER];
  va_list args;
  va_start(args, format);
  vsprintf(buf, format, args);
  va_end(args);

  LIST_ITERATOR *ch_i = newListIterator(mobile_list);
  CHAR_DATA       *ch = NULL;

  ITERATE_LIST(ch, ch_i) {
    if(!charGetSocket(ch) || !bitIsSet(charGetUserGroups(ch), groups))
      continue;
    text_to_char(ch, buf);
  }
  deleteListIterator(ch_i);
}


void send_to_list(LIST *list, const char *format, ...) {
  if(format && *format) {
    // form the message
    static char buf[MAX_BUFFER];
    va_list args;
    va_start(args, format);
    vsprintf(buf, format, args);
    va_end(args);

    // send it out to everyone
    LIST_ITERATOR *list_i = newListIterator(list);
    CHAR_DATA *ch = NULL;
    ITERATE_LIST(ch, list_i)
      text_to_char(ch, buf);
    deleteListIterator(list_i);
  }
};



//*****************************************************************************
//
// implementation of inform.h
// game commands
//
//*****************************************************************************

//
// cmd_more skips onto the next page in the socket's read buffer
//
COMMAND(cmd_more) {
  if(charGetSocket(ch))
    page_continue(charGetSocket(ch));
}


//
// cmd_back goes back to the previous page in the socket's read buffer
//
COMMAND(cmd_back) {
  if(charGetSocket(ch))
    page_back(charGetSocket(ch));
}


//
// lists all of the commands available to a character via some group. If the
// character is not part of the group, s/he cannot see the commands
COMMAND(cmd_groupcmds) {
  if(!*arg)
    send_to_char(ch, "Which group did you want to commands for: %s\r\n",
		 bitvectorGetBits(charGetUserGroups(ch)));
  else if(!bitIsOneSet(charGetUserGroups(ch), arg))
    send_to_char(ch, "You are not a member of user group, %s.\r\n", arg);
  else
    show_commands(ch, arg);
}


//
// cmd_look lets a character get information about a specific thing. Objects,
// characters, extra descriptions, and just about anything else that can exist
// in the MUD can be looked at.
//   usage: look [at] <target> [[<on> <thing>] [<in> <thing>]]
//
//   examples:
//     look bob                      look at bob
//     look at 2.woman               look at the 2nd woman
//     look at sword in sheath       look at the sword in the sheath
//     look at earrings on sue       look at the earrings sue is wearing
COMMAND(cmd_look) {
  if(!arg || !*arg)
    look_at_room(ch, charGetRoom(ch));
  else {
    int found_type = FOUND_NONE;
    void *found = generic_find(ch, arg, FIND_TYPE_ALL, FIND_SCOPE_IMMEDIATE,
			       FALSE, &found_type);

    // nothing!
    if(found == NULL)
      send_to_char(ch, "What did you want to look at?\r\n");

    // is it an extra description?
    else if(found_type == FOUND_EDESC) {
      EDESC_SET *set = edescGetSet(found);
      BUFFER  *edesc = bufferCopy(edescGetDescBuffer(found));
      edescTagDesc(edesc, set, "{c", "{g");
      bufferFormat(edesc, SCREEN_WIDTH, PARA_INDENT);
      send_to_char(ch, "{g%s", bufferString(edesc));
      deleteBuffer(edesc);
    }

    // is it an item?
    else if(found_type == FOUND_OBJ)
      look_at_obj(ch, found);

    // is it something inside of an object?
    else if(found_type == FOUND_IN_OBJ) {
      // show the destination we're peering at
      if(objIsType(found, "portal")) {
	ROOM_DATA *dest = worldGetRoom(gameworld, portalGetDest(found));
	if(dest) {
	  send_to_char(ch, "You peer inside %s.\r\n", see_obj_as(ch, found));
	  look_at_room(ch, dest);
	}
	else
	  send_to_char(ch, 
		       "%s is murky, and you cannot "
		       "make out anything on the other side.\r\n",
		       see_obj_as(ch, found));
      }
      else if(!objIsType(found, "container"))
	send_to_char(ch, "%s is not a container or portal.\r\n",
		     objGetName(found));
      else if(containerIsClosed(found))
	send_to_char(ch, "%s is closed.\r\n", objGetName(found));
      else if(listSize(objGetContents(found)) == 0)
	send_to_char(ch, "There is nothing inside of %s.\r\n", 
		     objGetName(found));
      else {
	send_to_char(ch, "You peer inside of %s:\r\n", objGetName(found));
	LIST *vis_objs = find_all_objs(ch, objGetContents(found), "", NULL,
				       TRUE);
	show_list(ch, vis_objs, objGetName, objGetMultiName);
	deleteList(vis_objs);
      }
    }

    // is it another character?
    else if(found_type == FOUND_CHAR)
      look_at_char(ch, found);

    // is it an exit?
    else if(found_type == FOUND_EXIT)
      look_at_exit(ch, found);

    // couldn't find anything. too bad!
    else
      send_to_char(ch, "What did you want to at?\r\n");
  }
}


//
// list all of the equipment a character is wearing to him or herself
COMMAND(cmd_equipment) {
  send_to_char(ch, "You are wearing:\r\n");
  show_body(ch, charGetBody(ch));
}


//
// list a character's inventory to him or herself
COMMAND(cmd_inventory) {
  if(listSize(charGetInventory(ch)) == 0)
    send_to_char(ch, "You aren't carrying anything.\r\n");
  else {
    send_to_char(ch, "{gYou are carrying:\r\n");
    LIST *vis_objs = find_all_objs(ch, charGetInventory(ch), "", NULL, TRUE);
    show_list(ch, vis_objs, objGetName, objGetMultiName);
    deleteList(vis_objs);
  }
}


//
// show a list of all commands available to the character
COMMAND(cmd_commands) {
  show_commands(ch, bitvectorGetBits(charGetUserGroups(ch)));
}


//
// builds a buffer that lists all of the people online. 
// Buffer must be deleted after it is used
BUFFER *build_who(void) {
  CHAR_DATA *plr;
  SOCKET_DATA *dsock;
  BUFFER *buf = newBuffer(MAX_BUFFER);
  LIST_ITERATOR *sock_i = newListIterator(socket_list);
  int socket_count = 0, playing_count = 0;

  bprintf(buf, 
	  "{cPlayers Online:\r\n"
	  "{gStatus   Race )\r\n"
	  );

  // build our list of people online
  ITERATE_LIST(dsock, sock_i) {
    socket_count++;
    if ((plr = socketGetChar(dsock)) == NULL) continue;
    playing_count++;
    bprintf(buf, "{y%-8s %-3s  {g)  {c%-12s {b%26s\r\n",
	    (bitIsSet(charGetUserGroups(plr), "admin") ? "admin" :
	     (bitIsSet(charGetUserGroups(plr), "scripter") ? "scripter" :
	      (bitIsSet(charGetUserGroups(plr), "builder") ? "builder"  :
	       (bitIsSet(charGetUserGroups(plr), "player") ? "player" : 
		"noone!")))),
	    raceGetAbbrev(charGetRace(plr)),
	    charGetName(plr), socketGetHostname(dsock));
  } deleteListIterator(sock_i);

  // send out info about the number of sockets and players logged on
  bprintf(buf, "\r\n{g%d socket%s connected. %d playing.\r\n",
	  socket_count, (socket_count == 1 ? "" : "s"), playing_count);
  return buf;
}


//
// show the player all of the people who are currently playing
COMMAND(cmd_who) {
  BUFFER *buf = build_who();
  page_string(charGetSocket(ch), bufferString(buf));
  deleteBuffer(buf);
}



//*****************************************************************************
// below this line are all of the subfunctions related to the message() 
// function
//*****************************************************************************

//
// Send a message out
//
// Converts the following symbols:
//  $n = ch name
//  $N = vict name
//  $m = him/her of char
//  $M = him/her of vict
//  $s = his/hers of char
//  $S = his/hers of vict
//  $e = he/she of char
//  $E = he/she of vict
//
//  $o = obj name
//  $O = vobj name
//  $a = a/an of obj
//  $A = a/an of vobj
void send_message(CHAR_DATA *to, 
		  const char *str,
		  CHAR_DATA *ch, CHAR_DATA *vict,
		  OBJ_DATA *obj, OBJ_DATA *vobj) {
  char buf[MAX_BUFFER];
  int i, j;

  // if there's nothing to send the message to, don't go through all
  // the work it takes to parse the string
  if(charGetSocket(to) == NULL)
    return;

  for(i = 0, j = 0; str[i] != '\0'; i++) {
    if(str[i] != '$') {
      buf[j] = str[i];
      j++;
    }
    else {
      i++;

      switch(str[i]) {
      case 'n':
	if(!ch) break;
	sprintf(buf+j, see_char_as(to, ch));
	while(buf[j] != '\0') j++;
	break;
      case 'N':
	if(!vict) break;
	sprintf(buf+j, see_char_as(to, vict));
	while(buf[j] != '\0') j++;
	break;
      case 'm':
	if(!ch) break;
	sprintf(buf+j, (can_see_char(to, ch) ? HIMHER(ch) : SOMEONE));
	while(buf[j] != '\0') j++;
	break;
      case 'M':
	if(!vict) break;
	sprintf(buf+j, (can_see_char(to, vict) ? HIMHER(vict) : SOMEONE));
	while(buf[j] != '\0') j++;
	break;
      case 's':
	if(!ch) break;
	sprintf(buf+j, (can_see_char(to, ch) ? HISHER(ch) :SOMEONE"'s"));
	while(buf[j] != '\0') j++;
	break;
      case 'S':
	if(!vict) break;
	sprintf(buf+j, (can_see_char(to, vict) ? HISHER(vict) :SOMEONE"'s"));
	while(buf[j] != '\0') j++;
	break;
      case 'e':
	if(!ch) break;
	sprintf(buf+j, (can_see_char(to, ch) ? HESHE(ch) : SOMEONE));
	while(buf[j] != '\0') j++;
	break;
      case 'E':
	if(!vict) break;
	sprintf(buf+j, (can_see_char(to, vict) ? HESHE(vict) : SOMEONE));
	while(buf[j] != '\0') j++;
	break;
      case 'o':
	if(!obj) break;
	sprintf(buf+j, see_obj_as(to, obj));
	while(buf[j] != '\0') j++;
	break;
      case 'O':
	if(!vobj) break;
	sprintf(buf+j, see_obj_as(to, vobj));
	while(buf[j] != '\0') j++;
	break;
      case 'a':
	if(!obj) break;
	sprintf(buf+j, AN(see_obj_as(to, obj)));
	while(buf[j] != '\0') j++;
	break;
      case 'A':
	if(!vobj) break;
	sprintf(buf+j, AN(see_obj_as(to, vobj)));
	while(buf[j] != '\0') j++;
	break;
      case '$':
	buf[j] = '$';
	j++;
	break;
      default:
	// do nothing
	break;
      }
    }
  }

  //  buf[0] = toupper(buf[0]);
  sprintf(buf+j, "\r\n");
  text_to_char(to, buf);
}


void message(CHAR_DATA *ch,  CHAR_DATA *vict,
	     OBJ_DATA  *obj, OBJ_DATA  *vobj,
	     int hide_nosee, bitvector_t range, 
	     const char *mssg) {
  if(!mssg || !*mssg)
    return;

  // what's our scope?
  if(IS_SET(range, TO_VICT) &&
     (!hide_nosee ||
      // make sure the vict can the character, or the
      // object if there is no character
      ((!ch || can_see_char(vict, ch)) &&
       (ch  || (!obj || can_see_obj(vict, obj))))))
    send_message(vict, mssg, ch, vict, obj, vobj);

  // characters can always see themselves. No need to do checks here
  if(IS_SET(range, TO_CHAR))
    send_message(ch, mssg, ch, vict, obj, vobj);

  LIST *recipients = NULL;
  // check if the scope of this message is everyone in the world
  if(IS_SET(range, TO_WORLD))
    recipients = mobile_list;
  else if(IS_SET(range, TO_ROOM))
    recipients = roomGetCharacters(charGetRoom(ch));

  // if we have a list to send the message to, do it
  if(recipients != NULL) {
    LIST_ITERATOR *rec_i = newListIterator(recipients);
    CHAR_DATA *rec = NULL;

    // go through everyone in the list
    ITERATE_LIST(rec, rec_i) {
      // if we wanted to send to ch or vict, we would have already...
      if(rec == vict || rec == ch)
	continue;
      if(rec == ch ||
	 (!hide_nosee ||
	  // make sure the vict can see the character, or the
	  // object if there is no character
	  ((!ch || can_see_char(rec, ch)) &&
	   (ch  || (!obj || can_see_obj(rec, obj))))))
      send_message(rec, mssg, ch, vict, obj, vobj);
    } deleteListIterator(rec_i);
  }
}

void mssgprintf(CHAR_DATA *ch, CHAR_DATA *vict, 
		OBJ_DATA *obj, OBJ_DATA  *vobj,
		int hide_nosee, bitvector_t range, const char *fmt, ...) {
  if(fmt && *fmt) {
    // form the message
    static char buf[MAX_BUFFER];
    va_list args;
    va_start(args, fmt);
    vsprintf(buf, fmt, args);
    va_end(args);
    message(ch, vict, obj, vobj, hide_nosee, range, buf);
  }
}