/* Version 2: This is very similar to the first, but allows multiple people
 * to sit in the same chair, using a linked list to track who is in the chair.
 * I've also added a few things that were not included in the first, such as 
 * the ability to see what you're sitting on in your score, stating a chair 
 * showing the specific info on the chair, including the list of who is sitting
 * in it, etc.
 *
 * Updated : July 7, 2000, Dana Luther
 */
/* This patch is for bpl17, I don't know why it wouldn't work for others, 
 * but since I haven't tried them, I couldn't say for sure.
 * 
 * Purpose: To enable characters to SIT in/on things.
 *
 * This patch will make it so that if the character is sitting in a chair, they
 * will be seen to sit in the chair when you look at the room, you can't take
 * a chair out from under a sitting player, etc.
 * I'm no expert, but I'll be happy to answer any questions that come up.
 * Just drop me a line at dtluther@mindspring.com
 *
 * I'd like to thank Andy Hubbard for the second opinion on this ;) and for
 * being willing to try it out on DreamScapes (www.dreamscapesmud.com)
 *
 */
/* Please note, that if you've used the original chair.patch, I changed the name
 * of the struct pointers in the char_special_data and obj_data structs, simply
 * to make them a little clearer in my mind. If you don't want to change them, 
 * just make sure your references use the proper name. 
 */

In structs.h
************
#define ITEM_CHAIR          26   /* Item is umm... a chair ;) */

struct char_special_data {
  add...
  struct obj_data *chair;          /* Object the char is sitting in */
  struct char_data *next_in_chair; /* The next person in the chair */\


struct obj_data {
  add...
  struct char_data *sitting_here;   /* Who is sitting in it (null if none) */

In oasis.h (or olc.h, depending on what you use)
**********************
Increase the NUM_ITEM_TYPES by one
#define MAX_PEOPLE_IN_CHAIR 10   /* The maximum number of people you want 
                                    to sit in a chair at the same time. */

In utils.h
**********
void char_from_chair(struct char_data *ch);
#define SITTING(ch)          ((ch)->char_specials.chair)
#define NEXT_SITTING(ch)     ((ch)->char_specials.next_in_chair)
#define OBJ_SAT_IN_BY(obj)   ((obj)->sitting_here)

In utils.c
**********
+void char_from_chair(struct char_data *ch)
+{
+  struct obj_data *chair;
+  struct char_data *tempch;
+  int i, found;
+
+  if (!SITTING(ch))
+    return;
+
+  if (!(chair = SITTING(ch))){
+    log("SYSERR: ACK, no chair for char in char from chair");
+    SITTING(ch) = NULL;
+    NEXT_SITTING(ch) = NULL;
+    return;
+  }
+
+  if (!(tempch = OBJ_SAT_IN_BY(chair))){
+    log("SYSERR: Char from chair, but no chair!");
+    SITTING(ch) = NULL;
+    NEXT_SITTING(ch) = NULL;
+    return;
+  }
+
+  if (tempch == ch){
+    if (!NEXT_SITTING(ch))
+			OBJ_SAT_IN_BY(chair) = NULL;
+    else
+  	  OBJ_SAT_IN_BY(chair) = NEXT_SITTING(ch);
+	  GET_OBJ_VAL(chair, 1) -= 1;
+    SITTING(ch) = NULL;
+    NEXT_SITTING(ch) = NULL;
+
+    return;
+  }
+
+  for (i = 0; i < GET_OBJ_VAL(chair, 1) && found == 0; i++){
+    if (NEXT_SITTING(tempch) == ch){
+      NEXT_SITTING(tempch) = NEXT_SITTING(ch);
+      found = 1;
+    }
+  }
+  if (found == 0)
+    log("SYSERR: Char flagged as sitting, but not in chair");
+  else
+	  GET_OBJ_VAL(chair, 1) -= 1;
+ 
+  SITTING(ch) = NULL;
+  NEXT_SITTING(ch) = NULL;
+
+  return;
+}

In constants.c
**************
/* ITEM_x (ordinal object types) */
const char *item_types[] = {
   add ...
  "CHAIR", at the appropriate spot

In act.movement.c
*****************
ACMD(do_stand)
  case POS_SITTING:
    send_to_char("You stand up.\r\n", ch);
    act("$n clambers to $s feet.", TRUE, ch, 0, 0, TO_ROOM);
+   /* Were they sitting in a chair? */
+   char_from_chair(ch); 
    /* Will be sitting after a successful bash and may still be fighting. */
    GET_POS(ch) = FIGHTING(ch) ? POS_FIGHTING : POS_STANDING;
    break;
  case POS_RESTING:
    send_to_char("You stop resting, and stand up.\r\n", ch);
    act("$n stops resting, and clambers on $s feet.", TRUE, ch, 0, 0, TO_ROOM);
    GET_POS(ch) = POS_STANDING;
+   /* Were they sitting in the chair */
+   char_from_chair(ch);
    break;

ACMD(do_sit)
{
+  struct obj_data *chair;
+  struct char_data *tempch;
+  int found;
+
+  one_argument(argument, arg);
+
+  if (!*arg)
+     found = 0;
+  if (!(chair = get_obj_in_list_vis(ch, arg, world[ch->in_room].contents)))
+     found = 0;
+  else {
+     found = 1;
+  }

  switch (GET_POS(ch)) {
  case POS_STANDING:
+    if (found == 0){
      send_to_char("You sit down.\r\n", ch);
      act("$n sits down.", FALSE, ch, 0, 0, TO_ROOM);
      GET_POS(ch) = POS_SITTING;
+    } else {
+      if (GET_OBJ_TYPE(chair) != ITEM_CHAIR){
+        send_to_char("You can't sit in that!\r\n", ch);
+        return;
+      } else if (GET_OBJ_VAL(chair, 1) > GET_OBJ_VAL(chair, 0)){
+        /* val 1 is current number in chair, 0 is max in chair */
+        act("$p looks like it's all full.", TRUE, ch, chair, 0, TO_CHAR);
+        sprintf(buf, "SYSERR: chair %d holding too many people.", GET_OBJ_VNUM(chair));
+        return;
+      } else if (GET_OBJ_VAL(chair, 1) == GET_OBJ_VAL(chair, 0)){
+        act("There is no where left to sit upon $p.", TRUE, ch, chair, 0, TO_CHAR);
+        return;
+      } else {
+        if (OBJ_SAT_IN_BY(chair) == NULL)
+          OBJ_SAT_IN_BY(chair) = ch;
+        for (tempch = OBJ_SAT_IN_BY(chair); tempch != ch ; tempch = NEXT_SITTING(tempch)){
+          if (NEXT_SITTING(tempch))
+             continue;
+          NEXT_SITTING(tempch) = ch;
+        }
+   			act("You sit down upon $p.", TRUE, ch, chair, 0, TO_CHAR);
+	      act("$n sits down upon $p.", TRUE, ch, chair, 0, TO_ROOM);
+        SITTING(ch) = chair;
+        NEXT_SITTING(ch) = NULL;
+	      GET_OBJ_VAL(chair, 1) += 1;
+        GET_POS(ch) = POS_SITTING;
+      }
    }
    break;

---snip---


In db.c
*******

int load_char(char *name, struct char_data *ch)
{
---snip---
    ch->next_in_room = NULL;
+   SITTING(ch) = NULL;
    NEXT_SITTING(ch) = NULL;

/* clear some of the the working variables of a char */
void reset_char(struct char_data * ch)
{
---snip---
  ch->next_in_room = NULL;
  FIGHTING(ch) = NULL;
+ char_from_chair(ch);
---snip---

int check_object(struct obj_data *obj)
{
 add case...
+  case ITEM_CHAIR:
+    if (GET_OBJ_VAL(obj, 1) > GET_OBJ_VAL(obj, 0) && (error = TRUE))
+      log("SYSERR: Object #%d (%s) contains (%d) more than maximum (%d).",
+		GET_OBJ_VNUM(obj), obj->short_description,
+		GET_OBJ_VAL(obj, 1), GET_OBJ_VAL(obj, 0));     
+    break;

char *parse_object(FILE * obj_f, int nr)
{
add...
+ object_proto[i].sitting_here = NULL;

In act.informative.c
********************
void list_one_char(struct char_data * i, struct char_data * ch)
{
---snip---
  if (GET_POS(i) != POS_FIGHTING) {
+    if (!SITTING(i)){
      strcat(buf, positions[(int) GET_POS(i)]);
+		} else {
+      chair = SITTING(i);
+      sprintf(buf2, " is %s upon %s.", 
+             ((GET_POS(i) == POS_SITTING) ? "sitting" : "resting"),
+             (CAN_SEE_OBJ(ch, chair) ? chair->short_description : "something"));
+      strcat(buf, buf2);
+    }
  } else {
---snip---

void show_obj_to_char(struct obj_data * object, struct char_data * ch,
      int mode)
{
+ int found;
+ struct char_data *temp;

  *buf = '\0';

  if ((mode == 0) && object->description){
+    if (GET_OBJ_VAL(object, 1) == 0 || !OBJ_SAT_IN_BY(object))
	    strcpy(buf, object->description);        
+    else {
+      temp = OBJ_SAT_IN_BY(object);
+      for (temp = OBJ_SAT_IN_BY(object); temp; temp = NEXT_SITTING(temp)){
+        if (temp == ch)
+          found = 1;
+      }
+      if (found == 1)
+        sprintf(buf, "You are %s upon %s.", GET_POS(ch) == POS_SITTING ? "sitting" : "resting", object->short_description);
+		 	else
+        strcpy(buf, object->description);      
+    }
  }


ACMD(do_score)
{
---snip---
  case POS_SITTING:
+    if (!SITTING(ch))
	    strcat(buf, "You are sitting.\r\n");
+    else { 
+      struct obj_data *chair = SITTING(ch);
+      sprintf(buf + strlen(buf), "You are sitting upon %s.\r\n", chair->short_description);
+    }
    break;

in handler.c
************

void extract_char(struct char_data * ch)
{
add...
+  char_from_chair(ch);

/* Extract an object from the world */
void extract_obj(struct obj_data * obj)
{
+  struct char_data *ch, *next;
---snip---
+	if (OBJ_SAT_IN_BY(obj)){
+	  for (ch = OBJ_SAT_IN_BY(obj); OBJ_SAT_IN_BY(obj); ch = next){
+			if (!NEXT_SITTING(ch))
+         OBJ_SAT_IN_BY(obj) = NULL;
+			else
+         OBJ_SAT_IN_BY(obj) = (next = NEXT_SITTING(ch));
+      SITTING(ch) = NULL;
+      NEXT_SITTING(ch) = NULL;
+  	}
+  }

  /* Get rid of the contents of the object, as well. */

In act.wizard.c
***************
void do_stat_object(struct char_data * ch, struct obj_data * j)
{
  int i, found;
  obj_vnum vnum;
  struct obj_data *j2;
  struct extra_descr_data *desc;
+  struct char_data *tempch;
  char temp;

---snip---
+  case ITEM_CHAIR:
+   sprintf(buf, "Can hold: [%d] Num. of People in Chair: [%d]\r\n", GET_OBJ_VAL(j, 0), GET_OBJ_VAL(j, 1));
+   sprintf(buf + strlen(buf), "Holding : ");
+   for (tempch = OBJ_SAT_IN_BY(j); tempch; tempch = NEXT_SITTING(tempch)){
+		 sprintf(buf + strlen(buf), "%s ", GET_NAME(tempch));
+   }
+   break;

In oedit.c
***********
void oedit_disp_val1_menu(struct descriptor_data *d)
{
---snip---
+  case ITEM_CHAIR:
+		 SEND_TO_Q("Number of people the chair can hold : ", d);
+     break;

void oedit_parse(struct descriptor_data *d, char *arg)
{
---snip---
case OEDIT_VALUE_1:
    /*
     * Lucky, I don't need to check any of these for out of range values.
     * Hmm, I'm not so sure - Rv  
     * - You do now... DHL 7/7/2000
     */
+    number = atoi(arg);
+    switch (GET_OBJ_TYPE(OLC_OBJ(d))) {
+    case ITEM_CHAIR:
+			if (number < 0 || number > MAX_PEOPLE_IN_CHAIR)
+        oedit_disp_val1_menu(d);
+      else {
+        GET_OBJ_VAL(OLC_OBJ(d), 0) = number;
+        oedit_disp_val2_menu(d);
+      } 
+		break;
+    default:
	    GET_OBJ_VAL(OLC_OBJ(d), 0) = number;
	    oedit_disp_val2_menu(d);
+    break;
+    }
    return;

NOTE - If you use the xap-objs copy_object, after the following add to it:
   returno->in_room = obj->in_room;
+  returno->sitting_here = obj->sitting_here;


In genobj.c
************
int update_objects(struct obj_data *refobj)
{
---snip---
    obj->next_content = swap.next_content;
    obj->next = swap.next;
+   obj->sitting_here = swap.sitting_here;