/* $Header: look.c,v 2.0 90/05/05 12:45:36 lachesis Exp $
 * $Log:	look.c,v $
 * Revision 2.0  90/05/05  12:45:36  lachesis
 * Incorporated ABODE and HAVEN flags (remembering to convert FireFoot's
 * usage of those flags to ours).
 * Added Examine of objects that don't belong to you, added GOD_PRIV.
 * 
 * Revision 1.3  90/04/21  17:20:46  lachesis
 * Added property lists.
 * 
 * Revision 1.2  90/04/20  14:06:44  lachesis
 * Added @odrop && @drop.
 * 
 * Revision 1.1  90/04/14  14:56:46  lachesis
 * Initial revision
 * 
 */
#include "copyright.h"

/* commands which look at things */

#include "db.h"
#include "config.h"
#include "interface.h"
#include "match.h"
#include "externs.h"

char buf[BUFFER_LEN];

/* prints owner of something */
static void
print_owner(dbref player, dbref thing)
{
  char buf[BUFFER_LEN];

  switch(Typeof(thing))
    {
    case TYPE_ROOM:
      sprintf(buf, "Owner: %s", db[db[thing].sp.room.owner].name);
      break;
    case TYPE_THING:
      sprintf(buf, "Owner: %s", db[db[thing].sp.thing.owner].name);
      break;
    case TYPE_PLAYER:
      sprintf(buf, "%s is a player", db[thing].name);
      break;
    case TYPE_EXIT:
      sprintf(buf, "Owner: %s", db[db[thing].sp.exit.owner].name);
      break;
#ifdef RECYCLE
    case TYPE_GARBAGE:
      sprintf(buf, "%s is garbage", db[thing].name);
      break;
#endif      
    }

  notify(player, buf);
}  

static void look_contents(dbref player, dbref loc, const char *contents_name)
{
    dbref thing;
    dbref can_see_loc;

    /* check to see if he can see the location */
    can_see_loc = (!Dark(loc) || controls(player, loc));

    /* check to see if there is anything there */
    DOLIST(thing, db[loc].contents) {
	if(can_see(player, thing, can_see_loc)) {
	    /* something exists!  show him everything */
	    notify(player, contents_name);
	    DOLIST(thing, db[loc].contents) {
		if(can_see(player, thing, can_see_loc)) {
		    notify(player, unparse_object(player, thing));
		}
	    }
	    break;		/* we're done */
	}
    }
}

static void look_simple(dbref player, dbref thing)
{
    if(db[thing].description) {
	notify(player, db[thing].description);
    } else {
	notify(player, "You see nothing special.");
    }
}

void look_room(dbref player, dbref loc)
{
    /* tell him the name, and the number if he can link to it */
    notify(player, unparse_object(player, loc));

    /* tell him the description */
    if(db[loc].description) {
	notify(player, db[loc].description);
    }

    /* tell him the appropriate messages if he has the key */
    can_doit(player, loc, 0);

    /* tell him the contents */
    look_contents(player, loc, "Contents:");
}

void do_look_around(dbref player)
{
    dbref loc;

    if((loc = getloc(player)) == NOTHING) return;
    look_room(player, loc);
}

void do_look_at(dbref player, const char *name)
{
    dbref thing;

    if(*name == '\0') {
	if((thing = getloc(player)) != NOTHING) {
	    look_room(player, thing);
	}
    } else {
	/* look at a thing here */
	init_match(player, name, NOTYPE);
	match_all_exits();
	match_neighbor();
	match_possession();
	if(Wizard(player)) {
	    match_absolute();
	    match_player();
	}
	match_here();
	match_me();

	if((thing = noisy_match_result()) != NOTHING) {
	    switch(Typeof(thing)) {
	      case TYPE_ROOM:
		look_room(player, thing);
		break;
	      case TYPE_PLAYER:
		look_simple(player, thing);
		look_contents(player, thing, "Carrying:");
		break;
	      default:
		look_simple(player, thing);
		break;
	    }
	}
    }
}

#ifdef VERBOSE_EXAMINE
static const char *flag_description(dbref thing)
{
    static char buf[BUFFER_LEN];

    strcpy(buf, "Type: ");
    switch(Typeof(thing)) {
      case TYPE_ROOM:
	strcat(buf, "ROOM");
	break;
      case TYPE_EXIT:
	strcat(buf, "EXIT/ACTION");
	break;
      case TYPE_THING:
	strcat(buf, "THING");
	break;
      case TYPE_PLAYER:
	strcat(buf, "PLAYER");
	break;
#ifdef RECYCLE	
      case TYPE_GARBAGE:
        strcat(buf, "GARBAGE");
	break;
#endif	
      default:
	strcat(buf, "***UNKNOWN TYPE***");
	break;
    }

    if(db[thing].flags & ~TYPE_MASK) {
	/* print flags */
	strcat(buf, "  Flags:");
	if(db[thing].flags & WIZARD) strcat(buf, " WIZARD");
	if(db[thing].flags & STICKY) strcat(buf, " STICKY");
	if(db[thing].flags & DARK) strcat(buf, " DARK");
	if(db[thing].flags & LINK_OK) strcat(buf, " LINK_OK");
	if(db[thing].flags & TEMPLE) strcat(buf, " TEMPLE");
#ifdef RESTRICTED_BUILDING
	if(db[thing].flags & BUILDER) strcat(buf, " BUILDER");
#endif /* RESTRICTED_BUILDING */
#ifdef PLAYER_CHOWN
	if(db[thing].flags & CHOWN_OK) strcat(buf, " CHOWN_OK");
#endif /* PLAYER_CHOWN */
	if(db[thing].flags & JUMP_OK) strcat(buf, " JUMP_OK");
#ifdef HAVEN
	if (db[thing].flags & HAVEN) strcat(buf, " HAVEN");
#endif /* HAVEN */
#ifdef ABODE
	if (db[thing].flags & ABODE) strcat(buf, " ABODE");
#endif /* ABODE */
    }

    return buf;
}
#endif /* VERBOSE_EXAMINE */

void do_examine(dbref player, const char *name)
{
    dbref thing;
    char buf[BUFFER_LEN];
    dbref content;
    dbref exit;
    int  i;

    if(*name == '\0') {
	if((thing = getloc(player)) == NOTHING) return;
    } else {
	/* look it up */
	init_match(player, name, NOTYPE);
	match_all_exits();
	match_neighbor();
	match_possession();
	match_absolute();
	/* only Wizards can examine other players */
	if(Wizard(player)) match_player();
	match_here();
	match_me();

	/* get result */
	if((thing = noisy_match_result()) == NOTHING) return;
    }

    if(!can_link(player, thing)) {
      print_owner(player, thing);
      do_look_at(player, name);
	return;
    }

    switch(Typeof(thing)) {
      case TYPE_ROOM:
	sprintf(buf, "%s  Owner: %s",
		unparse_object(player, thing),
		db[db[thing].sp.room.owner].name);
	break;
      case TYPE_THING:
	sprintf(buf, "%s  Owner: %s  Value: %d",
		unparse_object(player, thing),
		db[db[thing].sp.thing.owner].name,
		db[thing].sp.thing.value);
	break;
      case TYPE_PLAYER:
	sprintf(buf, "%s  Cookies: %d  ",
		unparse_object(player, thing),
		db[thing].sp.player.pennies);
	break;
      case TYPE_EXIT:
	sprintf(buf, "%s  Owner: %s",
		unparse_object(player, thing),
		db[db[thing].sp.exit.owner].name);
	break;
#ifdef RECYCLE
      case TYPE_GARBAGE:
        strcpy(buf, unparse_object(player, thing));
	break;
#endif	
    }
    notify(player, buf);
#ifdef VERBOSE_EXAMINE
    notify(player, flag_description(thing));
#endif /* VERBOSE_EXAMINE */
    if(db[thing].description) notify(player, db[thing].description);
    sprintf(buf, "Key: %s", unparse_boolexp(player, db[thing].key));
    notify(player, buf);

    if(db[thing].fail_message) {
	sprintf(buf, "Fail: %s", db[thing].fail_message);
	notify(player, buf);
    }
    if(db[thing].succ_message) {
	sprintf(buf, "Success: %s", db[thing].succ_message);
	notify(player, buf);
    }
    if (db[thing].drop_message)
      {
	sprintf(buf, "Drop: %s", db[thing].drop_message);
	notify(player, buf);
      }
    if(db[thing].ofail) {
	sprintf(buf, "Ofail: %s", db[thing].ofail);
	notify(player, buf);
    }
    if(db[thing].osuccess) {
	sprintf(buf, "Osuccess: %s", db[thing].osuccess);
	notify(player, buf);
    }
    if (db[thing].odrop)
      {
	sprintf(buf, "Odrop: %s", db[thing].odrop);
	notify(player, buf);
      }

    /* show him the properties */
    if (db[thing].properties)
      {
	struct plist *p;
	char   buf[BUFFER_LEN];

	notify(player, "Properties:");
	for (p = db[thing].properties; p; p = p -> next)
	  {
	    strncpy(buf, p -> type, BUFFER_LEN - 1);
	    strncat(buf, ": ", BUFFER_LEN - 1);
	    strncat(buf, p -> class, BUFFER_LEN - 1);
	    notify(player, buf);
	  }
      }

    /* show him the contents */
    if(db[thing].contents != NOTHING) {
	if (Typeof(thing) == TYPE_PLAYER)
	    notify(player, "Carrying:");
	else
	    notify(player, "Contents:");
	DOLIST(content, db[thing].contents) {
	    notify(player, unparse_object(player, content));
	}
    }

    switch(Typeof(thing)) {
      case TYPE_ROOM:
	/* tell him about exits */
	if(db[thing].sp.room.exits != NOTHING) {
	    notify(player, "Exits:");
	    DOLIST(exit, db[thing].sp.room.exits) {
		notify(player, unparse_object(player, exit));
	    }
	} else {
	    notify(player, "No exits.");
	}

	/* print dropto if present */
	if(db[thing].sp.room.dropto != NOTHING) {
	    sprintf(buf, "Dropped objects go to: %s",
		    unparse_object(player, db[thing].sp.room.dropto));
	    notify(player, buf);
	}
	break;
      case TYPE_THING:
	/* print home */
	sprintf(buf, "Home: %s",
		unparse_object(player, db[thing].sp.thing.home)); /* home */
	notify(player, buf);
	/* print location if player can link to it */
	if(db[thing].location != NOTHING
	   && (controls(player, db[thing].location)
	       || can_link_to(player, db[thing].location))) {
	    sprintf(buf, "Location: %s",
		    unparse_object(player, db[thing].location));
	    notify(player, buf);
	}
	/* print thing's actions, if any */
	if(db[thing].sp.thing.actions != NOTHING) {
	    notify(player, "Actions/exits:");
	    DOLIST(exit, db[thing].sp.thing.actions) {
		notify(player, unparse_object(player, exit));
	    }
	} else {
	    notify(player, "No actions attached.");
	}
	break;
      case TYPE_PLAYER:

	/* print home */
	sprintf(buf, "Home: %s",
		unparse_object(player, db[thing].sp.player.home)); /* home */
	notify(player, buf);

	/* print location if player can link to it */
	if(db[thing].location != NOTHING
	   && (controls(player, db[thing].location)
	       || can_link_to(player, db[thing].location))) {
	    sprintf(buf, "Location: %s",
		    unparse_object(player, db[thing].location));
	    notify(player, buf);
	}
	
	/* print player's actions, if any */
	if(db[thing].sp.player.actions != NOTHING) {
	    notify(player, "Actions/exits:");
	    DOLIST(exit, db[thing].sp.player.actions) {
		notify(player, unparse_object(player, exit));
	    }
	} else {
	    notify(player, "No actions attached.");
	}
	break;
      case TYPE_EXIT:
	if (db[thing].location != NOTHING) {
	    sprintf(buf, "Source: %s",
	    	unparse_object(player, db[thing].location));
	    notify(player, buf);
	}
	/* print destinations */
	if (db[thing].sp.exit.ndest == 0) break;
	for (i = 0; i < db[thing].sp.exit.ndest; i++) {
	    switch( (db[thing].sp.exit.dest)[i]) {
	      case NOTHING:
		break;
	      case HOME:
		notify(player, "Destination: *HOME*");
		break;
	      default:
		sprintf(buf, "Destination: %s",
			unparse_object(player, (db[thing].sp.exit.dest)[i]));
		notify(player, buf);
		break;
	    }
	}
	break;
      default:
	/* do nothing */
	break;
    }
}

void do_score(dbref player) 
{
    char buf[BUFFER_LEN];

    sprintf(buf, "You have %d %s.",
	    db[player].sp.player.pennies,
	    db[player].sp.player.pennies == 1 ? "cookie" : "cookies");
    notify(player, buf);
}

void do_inventory(dbref player)
{
    dbref thing;

    if((thing = db[player].contents) == NOTHING) {
	notify(player, "You aren't carrying anything.");
    } else {
	notify(player, "You are carrying:");
	DOLIST(thing, thing) {
	    notify(player, unparse_object(player, thing));
	}
    }

    do_score(player);
}

void do_find(dbref player, const char *name)
{
    dbref i;

    if(!payfor(player, LOOKUP_COST)) {
	notify(player, "You don't have enough cookies.");
    } else {
	for(i = 0; i < db_top; i++) {
	    if(Typeof(i) != TYPE_EXIT
	       && controls(player, i)
	       && (!*name || string_match(db[i].name, name))) {
		notify(player, unparse_object(player, i));
	    }
	}
	notify(player, "***End of List***");
    }
}