/* $Header: /belch_a/users/rearl/tinymuck/src/RCS/look.c,v 1.17 90/10/06 19:04:30 rearl Exp $ */
/*
* $Log: look.c,v $
* Revision 1.17 90/10/06 19:04:30 rearl
* Fixed a typo in @# handling.
*
* Revision 1.16 90/10/06 16:32:49 rearl
* Fixes for 2.2 distribution.
*
* Revision 1.15 90/09/28 12:24:13 rearl
* Fixed small bug with disappearing descriptions...
*
* Revision 1.14 90/09/18 08:00:02 rearl
* Took out FILTER. Fixed @find.
*
* Revision 1.13 90/09/16 04:42:25 rearl
* Preparation code added for disk-based MUCK.
*
* Revision 1.12 90/09/15 22:25:59 rearl
* Added argument passing to MUF from @#. COMPRESS fix for this as well.
*
* Revision 1.11 90/09/13 06:27:38 rearl
* Argument passing with @# added.
*
* Revision 1.10 90/08/27 03:29:34 rearl
* Added environment support.
*
* Revision 1.9 90/08/11 04:05:21 rearl
* *** empty log message ***
*
* Revision 1.8 90/08/06 02:35:27 rearl
* Oopsie, changed controls() back to can_link().
*
* Revision 1.7 90/08/05 03:19:33 rearl
* Redid matching routines.
*
* Revision 1.6 90/08/02 18:53:09 rearl
* Changed can_link() to controls(). Everyone controls an unlinked exit.
*
* Revision 1.5 90/07/30 00:09:55 rearl
* Added @owned command, lists everything you own, or for wizards,
* everything owned by the specified player (including exits)
*
* Revision 1.4 90/07/29 21:19:17 rearl
* Fixed examine-description brain damage.
*
* Revision 1.3 90/07/29 17:39:30 rearl
* Fixed various things such as ROOM programs, examine bug, examine
* of programs now shows location, etc.
*
* Revision 1.2 90/07/23 03:12:10 casie
* Cleaned up various gcc warnings.
*
* Revision 1.1 90/07/19 23:03:52 casie
* Initial revision
*
*
*/
#include "copyright.h"
#include "config.h"
/* commands which look at things */
#include <ctype.h>
#include "db.h"
#include "params.h"
#include "interface.h"
#include "match.h"
#include "externs.h"
#include "strings.h"
#define EXEC_SIGNAL '@' /* Symbol which tells us what we're looking at
* is an execution order and not a message. */
/* prints owner of something */
static void
print_owner(dbref player, dbref thing)
{
char buf[BUFFER_LEN];
switch(Typeof(thing))
{
case TYPE_PLAYER:
sprintf(buf, "%s is a player.", NAME(thing));
break;
case TYPE_ROOM:
case TYPE_THING:
case TYPE_EXIT:
case TYPE_PROGRAM:
sprintf(buf, "Owner: %s", NAME(OWNER(thing)));
break;
#ifdef RECYCLE
case TYPE_GARBAGE:
sprintf(buf, "%s is garbage.", NAME(thing));
break;
#endif
}
notify(player, buf);
}
void exec_or_notify(dbref player, dbref thing, const char *message)
{
const char *p;
p = get_uncompress(message);
if (*p == EXEC_SIGNAL) {
int i;
i = atoi(++p);
for (; *p && !isspace(*p); p++)
;
if (*p) p++;
if ((Typeof(i) != TYPE_PROGRAM) || DBFETCH(player)->run) {
if (*p) {
if(index(p, '\\')) {
char buff[BUFFER_LEN];
strcpy(buff, p);
p = buff;
while(index(p, '\\') && (*(1 + index(p, '\\')) == 'n')) {
*index(p, '\\') = '\0';
notify(player, p);
p += strlen(p);
p += 2;
};
if(*p)
notify (player, p);
} else
notify(player, p);
} else notify(player, "You see nothing special.");
} else {
strcpy(match_args, p);
(void) interp(player, i, thing);
if (!(DBFETCH(player)->run -> pc)) {
free((void *) DBFETCH(player)->run);
DBSTORE(player, run, 0);
}
}
} else {
if(index(p, '\\')) {
char buff[BUFFER_LEN];
strcpy(buff, p);
p = buff;
while(index(p, '\\') && (*(1 + index(p, '\\')) == 'n')) {
*index(p,'\\') = '\0';
notify(player,p);
p += strlen(p);
p += 2;
};
if(*p)
notify(player, p);
} else
notify(player, p);
}
}
static void look_exits(dbref player, dbref loc, const char *exits_name)
{
dbref thing;
int flag = 1;
char buf[BUFFER_LEN];
strcpy(buf, exits_name);
DOLIST(thing, DBFETCH(loc)->exits) {
if(!(FLAGS(thing)&DARK)) {
if (flag == 0)
strcat(buf, ", "); /* don't put a comma before the first exit */
strcat(buf, NAME(thing));
flag = 0;
if(index(buf, ';'))
*index(buf, ';') ='\0';
}
}
if(strcmp(buf, exits_name))
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) || Murky(loc)) || controls(player, loc));
/* check to see if there is anything there */
DOLIST(thing, DBFETCH(loc)->contents) {
if(can_see(player, thing, can_see_loc)) {
/* something exists! show him everything */
notify(player, contents_name);
DOLIST(thing, DBFETCH(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(get_attr(thing, "Desc")) {
exec_or_notify(player, thing, get_attr(thing, "Desc"));
} else {
notify(player, "You see nothing special.");
}
if(get_attr(thing, "Odesc")) {
sprintf(buf,"%s %s", NAME(player), get_attr(thing, "Odesc"));
notify_except(DBFETCH(getloc(player))->contents,
player, pronoun_substitute(player, buf, thing));
}
if(get_attr(thing, "Adesc")) {
trigobj(thing, get_attr(thing, "Adesc"), player);
}
look_contents(player, thing, "Contents:");
}
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(get_attr(loc, "Idesc")) {
exec_or_notify(player, loc, get_attr(loc,"idesc"));
} else
if(get_attr(loc, "Desc")) {
exec_or_notify(player, loc, get_attr(loc, "Desc"));
}
if(get_attr(loc, "Odesc")) {
sprintf(buf,"%s %s", NAME(player), get_attr(loc, "Odesc"));
notify_except(DBFETCH(getloc(player))->contents, player,
pronoun_substitute(player, buf, loc));
}
if(get_attr(loc, "Adesc")) {
trigobj(loc, get_attr(loc, "Adesc"), player);
}
/* tell him the appropriate messages if he has the key */
if(Typeof(loc) == TYPE_ROOM) { /* we don't wanna see the osucc on an object. */
can_doit(player, loc, 0);
if (!(FLAGS(loc)&DARK))
look_exits(player,loc,"Obvious exits: ");
}
/* 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;
struct match_data md;
if(*name == '\0') {
if((thing = getloc(player)) != NOTHING) {
look_room(player, thing);
}
} else {
/* look at a thing here */
init_match(player, name, NOTYPE, &md);
match_all_exits(&md);
match_neighbor(&md);
match_possession(&md);
if(Arch(player)) {
match_absolute(&md);
match_player(&md);
}
match_here(&md);
match_me(&md);
if((thing = noisy_match_result(&md)) != NOTHING) {
switch(Typeof(thing)) {
case TYPE_ROOM:
if (getloc(player) != thing
&& !can_link_to(player, TYPE_ROOM, thing)) {
notify(player, "Permission denied.");
} else {
look_room(player, thing);
}
break;
default:
look_simple(player, thing);
break;
}
}
}
}
void do_examine(dbref player, const char *name)
{
dbref thing;
char buf[BUFFER_LEN];
dbref content;
dbref exit;
int i;
struct match_data md;
if(*name == '\0') {
if((thing = getloc(player)) == NOTHING) return;
} else {
/* look it up */
init_match(player, name, NOTYPE, &md);
match_all_exits(&md);
match_neighbor(&md);
match_possession(&md);
match_absolute(&md);
match_player(&md);
match_here(&md);
match_me(&md);
/* get result */
if((thing = noisy_match_result(&md)) == NOTHING) return;
}
if(!can_link(player, thing) && !(FLAGS(thing)&VISIBLE) && !Arch(player)) {
print_owner(player, thing);
return;
}
switch(Typeof(thing)) {
case TYPE_ROOM:
sprintf(buf, "%s Owner: %s Parent: ", unparse_object(player, thing),
NAME(OWNER(thing)));
strcat(buf, unparse_object(player, DBFETCH(thing)->location));
break;
case TYPE_THING:
sprintf(buf, "%s Owner: %s Value: %d", unparse_object(player, thing),
NAME(OWNER(thing)), DBFETCH(thing)->sp.thing.value);
break;
case TYPE_PLAYER:
sprintf(buf, "%s Owner: %s Pennies: %d ", unparse_object(player, thing),
NAME(OWNER(thing)), DBFETCH(thing)->sp.player.pennies);
break;
case TYPE_EXIT:
case TYPE_PROGRAM:
#ifdef RECYCLE
case TYPE_GARBAGE:
#endif
sprintf(buf, "%s Owner: %s", unparse_object(player, thing),
NAME(OWNER(thing)));
break;
}
notify(player, buf);
#ifdef VERBOSE_EXAMINE
sprintf(buf,"Flags: %s",unparse_flag(FLAGS(thing)));
notify(player, buf);
#endif /* VERBOSE_EXAMINE */
sprintf(buf, "Key: %s", unparse_boolexp(player, DBFETCH(thing)->key));
notify(player, buf);
/* show him the attributes */
if (DBFETCH(thing)->attributes)
{
struct plist *a;
char buf[BUFFER_LEN];
sprintf(buf, "Attributes('%c'):", PROP_WIZARD);
notify(player, buf);
for (a = DBFETCH(thing) -> attributes; a; a = a -> next)
{
strncpy(buf, (a -> type) + 1, BUFFER_LEN - 1);
strncat(buf, ": ", BUFFER_LEN - 1);
strncat(buf, get_uncompress(a -> class), BUFFER_LEN - 1);
notify(player, buf);
}
}
/* show him the properties */
if (DBFETCH(thing)->properties)
{
struct plist *p;
char buf[BUFFER_LEN];
notify(player, "Properties:");
for (p = DBFETCH(thing) -> properties; p; p = p -> next)
{
strncpy(buf, p -> type, BUFFER_LEN - 1);
strncat(buf, ": ", BUFFER_LEN - 1);
strncat(buf, get_uncompress(p -> class), BUFFER_LEN - 1);
notify(player, buf);
}
}
/* show him the contents */
if(DBFETCH(thing)->contents != NOTHING) {
notify(player, "Contents:");
DOLIST(content, DBFETCH(thing)->contents) {
notify(player, unparse_object(player, content));
}
}
switch(Typeof(thing)) {
case TYPE_ROOM:
/* tell him about exits */
if(DBFETCH(thing)->exits != NOTHING) {
notify(player, "Exits:");
DOLIST(exit, DBFETCH(thing)->exits) {
notify(player, unparse_object(player, exit));
}
} else {
notify(player, "No exits.");
}
/* print dropto if present */
if(DBFETCH(thing)->link != NOTHING) {
sprintf(buf, "Dropped objects go to: %s",
unparse_object(player, DBFETCH(thing)->link));
notify(player, buf);
}
break;
case TYPE_THING:
/* print home */
sprintf(buf, "Home: %s",
unparse_object(player, DBFETCH(thing)->link)); /* home */
notify(player, buf);
/* print location if player can link to it */
if(DBFETCH(thing)->location != NOTHING
&& (controls(player, DBFETCH(thing)->location)
|| can_link_to(player, NOTYPE, DBFETCH(thing)->location))) {
sprintf(buf, "Location: %s",
unparse_object(player, DBFETCH(thing)->location));
notify(player, buf);
}
/* print thing's actions, if any */
if(DBFETCH(thing)->exits != NOTHING) {
notify(player, "Actions/exits:");
DOLIST(exit, DBFETCH(thing)->exits) {
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, DBFETCH(thing)->link)); /* home */
notify(player, buf);
/* print location if player can link to it */
if(DBFETCH(thing)->location != NOTHING
&& (controls(player, DBFETCH(thing)->location)
|| can_link_to(player, NOTYPE, DBFETCH(thing)->location))) {
sprintf(buf, "Location: %s",
unparse_object(player, DBFETCH(thing)->location));
notify(player, buf);
}
/* print player's actions, if any */
if(DBFETCH(thing)->exits != NOTHING) {
notify(player, "Actions/exits:");
DOLIST(exit, DBFETCH(thing)->exits) {
notify(player, unparse_object(player, exit));
}
} else {
notify(player, "No actions attached.");
}
break;
case TYPE_EXIT:
if (DBFETCH(thing)->location != NOTHING) {
sprintf(buf, "Source: %s",
unparse_object(player, DBFETCH(thing)->location));
notify(player, buf);
}
/* print destinations */
if (DBFETCH(thing)->sp.exit.ndest == 0) break;
for (i = 0; i < DBFETCH(thing)->sp.exit.ndest; i++) {
switch( (DBFETCH(thing)->sp.exit.dest)[i]) {
case NOTHING:
break;
case HOME:
notify(player, "Destination: *HOME*");
break;
default:
sprintf(buf, "Destination: %s",
unparse_object(player, (DBFETCH(thing)->sp.exit.dest)[i]));
notify(player, buf);
break;
}
}
break;
case TYPE_PROGRAM:
if (DBFETCH(thing)->sp.program.siz)
sprintf(buf, "Program compiled size: %d",
DBFETCH(thing)->sp.program.siz);
else
sprintf(buf, "Program not compiled.");
notify(player, buf);
/* print location if player can link to it */
if(DBFETCH(thing)->location != NOTHING
&& (controls(player, DBFETCH(thing)->location)
|| can_link_to(player, NOTYPE, DBFETCH(thing)->location))) {
sprintf(buf, "Location: %s",
unparse_object(player, DBFETCH(thing)->location));
notify(player, buf);
}
break;
default:
/* do nothing */
break;
}
}
void do_score(dbref player)
{
char buf[BUFFER_LEN];
sprintf(buf, "You have %d %s.", DBFETCH(player)->sp.player.pennies,
DBFETCH(player)->sp.player.pennies == 1 ? "penny" : "pennies");
notify(player, buf);
}
void do_inventory(dbref player)
{
dbref thing;
if((thing = DBFETCH(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_owned(dbref player, const char *name, const char *filter)
{
dbref i, victim = 0;
object_flag_type type_check = 0;
object_flag_type flags_check = 0;
int x, y, flag;
struct match_data md;
const char *type_codes = "R-EPF";
char temp[2];
if(!payfor(player, LOOKUP_COST)) {
notify(player, "You don't have enough pennies.");
return;
}
if(*name)
if((victim = lookup_player(name)) == NOTHING) {
init_match(player, name, NOTYPE, &md);
match_me(&md);
match_absolute(&md);
match_player(&md);
if((victim = match_result(&md)) == NOTHING) {
notify(player, "I can't find that player.");
return;
}
}
if(victim && !controls(player, victim)) {
notify(player, "Permission denied.");
return;
}
for(x = 0; x < strlen(filter); x++) {
flag = 0;
for(y = 0; y < 5 && !flag; y++)
if(filter[x] == type_codes[y]) {
type_check |= filter_type(y);
flag++;
}
if(!flag) {
sprintf(temp, "%c", filter[x]);
flags_check |= lookup_flag(temp);
}
}
for(i = 0; i < db_top; i++)
if(controls(player, i)) {
flag = 1;
if(victim)
if(OWNER(i) != victim)
flag = 0;
if(flags_check && flag)
if((FLAGS(i)&flags_check) != flags_check)
flag = 0;
if(type_check && flag)
if(!(filter_type(Typeof(i))&type_check))
flag = 0;
if(flag)
notify(player, unparse_object(player, i));
}
notify(player, "***End of List***");
}
void do_find(dbref player, const char *name, const char *who)
{
dbref i, victim = 0;
int flag;
struct match_data md;
if(!payfor(player, LOOKUP_COST)) {
notify(player, "You don't have enough pennies.");
return;
}
if(*who)
if((victim = lookup_player(who)) == NOTHING) {
init_match(player, who, NOTYPE, &md);
match_me(&md);
match_absolute(&md);
match_player(&md);
if((victim = match_result(&md)) == NOTHING) {
notify(player, "I can't find that player.");
return;
}
}
if(victim && !controls(player, victim)) {
notify(player, "Permission denied.");
return;
}
for(i = 0; i < db_top; i++)
if(controls(player, i))
{
flag = 1;
if (victim)
if(OWNER(i) != victim)
flag = 0;
if (flag && *name)
if(!string_match(NAME(i), name))
flag = 0;
if(flag)
notify(player, unparse_object(player, i));
}
notify(player, "***End of List***");
}
void do_trace(dbref player, const char *name, int depth)
{
dbref thing;
int i;
struct match_data md;
init_match(player, name, NOTYPE, &md);
match_absolute(&md);
match_here(&md);
match_me(&md);
match_neighbor(&md);
match_possession(&md);
if ((thing = noisy_match_result(&md)) == NOTHING
|| thing == AMBIGUOUS) return;
if(!depth) depth=30; /* Otherwise this'd crash the game */
for (i = 0; (!depth || i < depth) && thing != NOTHING; i++) {
if (controls(player, thing) || can_link_to(player, NOTYPE, thing))
notify(player, unparse_object(player, thing));
else
notify(player, "**Missing**");
thing = DBFETCH(thing)->location;
}
notify(player, "***End of List***");
}