/* This software is Copyright 1989, 1990, 1992, 1993 by various individuals. Please see the accompanying file COPYRIGHT for details. */ /* commands which look at things */ #include #include "db.h" #include "defs.h" #include "prims.h" #include "ctype.h" #include "match.h" #include "money.h" #include "config.h" #include "params.h" #include "externs.h" #include "property.h" #include "interface.h" #include "unused-arg.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_DAEMON: case TYPE_PROGRAM: sprintf(buf, "Owner: %s", NAME(OWNER(thing))); break; case TYPE_GARBAGE: sprintf(buf, "%s is garbage.", NAME(thing)); break; } notify(player, buf); } void exec_or_notify(dbref player, dbref thing, const char *p) { if (p[0] == EXEC_SIGNAL) { int i; i = atoi(++p); for (;*p&&!Cisspace(*p);p++); if (*p) p++; if ((i < 0) || (i >= db_top) || (Typeof(i) != TYPE_PROGRAM)) { if (*p) { notify(player,p); } } else { interp(player,i,thing,p,makearray(1,makeinst(PROG_STRING,dup_string("@msg")))); } } else { notify(player,p); } } void exec_or_notify_str(dbref player, dbref thing, STR s) { char *t; t = fetch_str(s); exec_or_notify(player,thing,t); free(t); } 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) #ifdef SILENT_PLAYERS && !(FLAGS(player) & SILENT) #endif ); /* check to see if there is anything there */ DOLIST(thing, DBFETCH(loc)->contents) { if (can_see(player,thing,can_see_loc) && !(FLAGS(loc)&NOINVENTORY)) { /* 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) { #ifdef TIMESTAMPS DBFETCH(thing)->time_used = curtm(); #endif if (DBFETCH(thing)->description != NOSTR) { exec_or_notify_str(player,thing,DBFETCH(thing)->description); } else { notify(player,"You see nothing special."); } } void look_room(dbref player, dbref loc) { static int iamrecursive = 0; SERIAL playser; SERIAL locser; if ((iamrecursive < 10) && can_move(player,"look")) { iamrecursive ++; do_move(player,"look"); iamrecursive --; return; } locser = DBFETCH(loc)->serial; playser = DBFETCH(player)->serial; /* tell him the name, and the number if he can link to it */ notify(player,unparse_object(player,loc)); /* tell him the description */ if (DBFETCH(loc)->description != NOSTR) { exec_or_notify_str(player,loc,DBFETCH(loc)->description); if ( (DBFETCH(loc)->serial != locser) || (DBFETCH(player)->serial != playser) ) return; #ifdef TIMESTAMPS DBFETCH(loc)->time_used = curtm(); #endif } /* tell him the appropriate messages if he has the key */ can_doit(player,loc,0); if ( (DBFETCH(loc)->serial != locser) || (DBFETCH(player)->serial != playser) ) return; /* tell him the contents */ look_contents(player,loc,"Contents:"); } void do_look_around(dbref player) { dbref loc; loc = getloc(player); if ((loc != NOTHING) && !no_autolook(loc,player)) look_room(player,loc); } void do_look_at(dbref player, const char *name) { dbref thing; struct match_data md; if (*name == '\0') { thing = getloc(player); if (thing != 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 (Royalty(player)) /* Royalty is far-sighted! */ { match_absolute(&md); match_player(&md); } match_here(&md); match_me(&md); thing = noisy_match_result(&md); if (thing != NOTHING) { SERIAL thingser; SERIAL playser; thingser = DBFETCH(thing)->serial; playser = DBFETCH(player)->serial; 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; case TYPE_PLAYER: look_simple(player,thing); if ( (DBFETCH(thing)->serial == thingser) && (DBFETCH(player)->serial == playser) ) { look_contents(player,thing,"Carrying:"); } break; default: look_simple(player,thing); break; } } } } #ifdef VERBOSE_EXAMINE /*static*/ const char *flag_description(dbref thing) { char *bp; int i; object_flag_type f; static char buf[BUFFER_LEN]; bp = &buf[0]; strcpy(bp,"Type: "); bp += strlen(bp); switch (Typeof(thing)) { case TYPE_ROOM: strcpy(bp,"ROOM"); break; case TYPE_EXIT: strcpy(bp,"EXIT/ACTION"); break; case TYPE_THING: strcpy(bp,"THING"); break; case TYPE_PLAYER: strcpy(bp,"PLAYER"); break; case TYPE_PROGRAM: strcpy(bp,"PROGRAM"); break; case TYPE_DAEMON: strcpy(bp,"DAEMON"); break; case TYPE_GARBAGE: strcpy(bp,"GARBAGE"); break; default: sprintf(bp,"***UNKNOWN TYPE %d***",Typeof(thing)); break; } bp += strlen(bp); f = FLAGS(thing) & ~TYPE_MASK; if (f) { strcpy(bp," Flags:"); bp += strlen(bp); } for (i=0;f&&flagnames[i].flag;i++) { if (! (f & flagnames[i].flag)) continue; if ((FLAGS(thing) & flagnames[i].othermask) != flagnames[i].otherval) continue; f &= ~flagnames[i].flag; *bp++ = ' '; strcpy(bp,flagnames[i].name); bp += strlen(bp); } /* in case there are any other bits set... */ if (f) { sprintf(bp," 0x%lx",(unsigned long int)f); bp += strlen(bp); } return(&buf[0]); } #endif /* VERBOSE_EXAMINE */ static int showprops_walk(struct propref *pr, void *vvp) #define any (*(int *)((void **)vvp)[0]) #define pat (*(const char **)((void **)vvp)[1]) #define player (*(dbref *)((void **)vvp)[2]) #define bits (*(PROPATTR *)((void **)vvp)[3]) { char buf[BUFFER_LEN]; char *name; if (! (propref_get_attr(pr) & bits & PPERM_BIT_F)) return(0); name = propref_get_name(pr); if (!pat || !strlen(pat) || string_match(name,pat)) { int nlen; int vlen; int nc; char *bp; char *be; char *value; int vfree; bp = &buf[0]; be = &buf[BUFFER_LEN-2]; nlen = strlen(name); if (propref_get_attr(pr) & bits & PPERM_BIT_R) { switch (propref_get_attr(pr) & PATTR_TYPE) { case PTYPE_NIL: strcpy(bp,"(nil) "); value = 0; vfree = 0; break; case PTYPE_DBREF: { static char valbuf[64]; strcpy(bp,"(dbref) "); sprintf(&valbuf[0],"#%d",(int)propref_get_dbref(pr)); value = &valbuf[0]; vfree = 0; } break; case PTYPE_STRING: *bp = '\0'; value = propref_get_string(pr); vfree = 1; break; case PTYPE_ANYVAL: { struct inst i; strcpy(bp,"(anyval) "); i = propref_get_anyval(pr); value = insttotext(&i); CLEAR(&i); vfree = 0; } break; default: panic("showprops_walk: impossible type"); break; } } else { strcpy(bp,"(unreadable) "); value = 0; vfree = 0; } bp += strlen(bp); nc = (be - bp) / 2; if (nc > nlen) nc = nlen; bcopy(name,bp,nc); bp += nc; if (nc < nlen) { bp[-3] = '.'; bp[-2] = '.'; bp[-1] = '.'; } *bp++ = ':'; *bp++ = ' '; nc = be - bp; if (value) { vlen = strlen(value); if (nc > vlen) nc = vlen; bcopy(value,bp,nc); } else { vlen = 0; nc = 0; } bp += nc; if (vfree) free(value); if (nc < vlen) { bp[-3] = '.'; bp[-2] = '.'; bp[-1] = '.'; } *bp = '\0'; if (! any) notify(player,"Properties:"); notify(player,&buf[0]); any ++; } return(0); } #undef any #undef pat #undef player #undef bits static void showprops(dbref player, dbref thing, const char *pat) { int any; void *vv[4]; PROPATTR bits; bits = PPERM_PICKWHO(God(player),Wizard(player),Royalty(player),player==OWNER(thing)) & PPERM_HOW_C; any = 0; vv[0] = &any; vv[1] = &pat; vv[2] = &player; vv[3] = &bits; walk_plist(DBFETCH(thing)->properties,0,showprops_walk,&vv[0]); } void do_properties(dbref player, const char *name, const char *pat) { dbref thing; struct match_data md; if (*name == '\0') { thing = getloc(player); if (thing == 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); if (Royalty(player)) match_player(&md); match_here(&md); match_me(&md); /* get result */ thing = noisy_match_result(&md); if (thing == NOTHING) return; } if (!can_link(player,thing)) { notify(player,"Permission denied."); return; } showprops(player,thing,pat); } void do_contents(dbref player, const char *name, const char *match) { dbref thing; dbref content; struct match_data md; if(*name == '\0') { if((thing = getloc(player)) == NOTHING) return; } else { init_match(player, name, NOTYPE, &md); match_all_exits(&md); match_neighbor(&md); match_possession(&md); match_absolute(&md); if(Royalty(player)) match_player(&md); match_here(&md); match_me(&md); /* get result */ if((thing = noisy_match_result(&md)) == NOTHING) return; } if(!can_link(player, thing)) { notify(player, "Permission denied."); return; } notify(player, "Contents:"); if(DBFETCH(thing)->contents != NOTHING) { DOLIST(content, DBFETCH(thing)->contents) { if (!strlen(match) || string_match(DBFETCH(content)->name, match)) notify(player, unparse_object(player, content)); } } } void do_exits(dbref player, const char *name, const char *match) { dbref thing; dbref xit; struct match_data md; if(*name == '\0') { if((thing = getloc(player)) == NOTHING) return; } else { init_match(player, name, NOTYPE, &md); match_all_exits(&md); match_neighbor(&md); match_possession(&md); match_absolute(&md); if(Royalty(player)) match_player(&md); match_here(&md); match_me(&md); if((thing = noisy_match_result(&md)) == NOTHING) return; } if(!can_link(player, thing)) { print_owner(player, thing); return; } notify (player, "Actions/exits:"); switch(Typeof(thing)) { case TYPE_ROOM: if(DBFETCH(thing)->sp.room.exits != NOTHING) { DOLIST(xit, DBFETCH(thing)->sp.room.exits) { if (!strlen(match) || string_match(DBFETCH(xit)->name, match)) notify(player, unparse_object(player, xit)); } } break; case TYPE_THING: if(DBFETCH(thing)->sp.thing.actions != NOTHING) { DOLIST(xit, DBFETCH(thing)->sp.thing.actions) { if (!strlen(match) || string_match(DBFETCH(xit)->name, match)) notify(player, unparse_object(player, xit)); } } break; case TYPE_PLAYER: if(DBFETCH(thing)->sp.player.actions != NOTHING) { DOLIST(xit, DBFETCH(thing)->sp.player.actions) { if (!strlen(match) || string_match(DBFETCH(xit)->name, match)) notify(player, unparse_object(player, xit)); } } break; } } static void examine_str(dbref player, STR msg, const char *tag) { char *t; char buf[BUFFER_LEN]; if (msg == NOSTR) return; t = fetch_str(msg); sprintf(buf,"%s: %s",tag,t); free(t); notify(player,buf); } static void maybe_print_location(dbref player, dbref thing) { char buf[BUFFER_LEN]; 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); } } static void print_atexam_info(dbref player, dbref thing) { char buf[BUFFER_LEN]; int i; 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 %s: %d",unparse_object(player,thing),PL_MONEY_CAP,DBFETCH(thing)->sp.player.pennies); break; case TYPE_EXIT: case TYPE_PROGRAM: sprintf(buf,"%s Owner: %s",unparse_object(player,thing),NAME(OWNER(thing))); break; case TYPE_DAEMON: sprintf(buf, "%s Owner: %s",unparse_object(player,thing),NAME(OWNER(thing))); break; case TYPE_GARBAGE: strcpy(buf,unparse_object(player,thing)); break; } notify(player,buf); #ifdef VERBOSE_EXAMINE notify(player,flag_description(thing)); #endif /* VERBOSE_EXAMINE */ if (DBFETCH(thing)->description != NOSTR) { notify_str(player,DBFETCH(thing)->description); } sprintf(buf,"Key: %s",unparse_boolexp(player,DBFETCH(thing)->key)); notify(player,buf); examine_str(player,DBFETCH(thing)->fail_message,"Fail"); examine_str(player,DBFETCH(thing)->succ_message,"Success"); examine_str(player,DBFETCH(thing)->drop_message,"Drop"); examine_str(player,DBFETCH(thing)->ofail,"Ofail"); examine_str(player,DBFETCH(thing)->osuccess,"Osuccess"); examine_str(player,DBFETCH(thing)->odrop,"Odrop"); switch (Typeof(thing)) { case TYPE_ROOM: /* print dropto if present */ if (DBFETCH(thing)->sp.room.dropto != NOTHING) { sprintf(buf,"Dropped objects go to: %s",unparse_object(player,DBFETCH(thing)->sp.room.dropto)); notify(player,buf); } break; case TYPE_THING: /* print home */ sprintf(buf,"Home: %s",unparse_object(player,DBFETCH(thing)->sp.thing.home)); notify(player,buf); maybe_print_location(player,thing); break; case TYPE_PLAYER: /* print home, maybe print password */ sprintf(buf,"Home: %s",unparse_object(player,DBFETCH(thing)->sp.player.home)); notify(player,buf); if (Wizard(player)) { sprintf(buf,"Password: %s",DBFETCH(thing)->sp.player.password); notify(player,buf); } maybe_print_location(player,thing); break; case TYPE_EXIT: if (DBFETCH(thing)->location != NOTHING) { sprintf(buf,"Source: %s",unparse_object(player,DBFETCH(thing)->location)); notify(player,buf); } for (i=0;isp.exit.ndest;i++) { switch (DBFETCH(thing)->sp.exit.dest[i]) { case NOTHING: break; case HOME: notify(player,"Destination: *HOME*"); break; case BUILTIN: notify(player,"Destination: *BUILTIN*"); 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.codesiz) { sprintf(buf,"Program compiled size: %d",DBFETCH(thing)->sp.program.codesiz); notify(player,buf); sprintf(buf,"Program symbol table size: %d",DBFETCH(thing)->sp.program.stabsiz); notify(player,buf); } else { notify(player,"Program not compiled"); } maybe_print_location(player,thing); break; case TYPE_DAEMON: sprintf(buf,"Next: #%d",DBFETCH(thing)->next); notify(player,buf); break; } } static void showcontents(dbref player, dbref thing) { dbref content; if (DBFETCH(thing)->contents != NOTHING) { notify(player,"Contents:"); DOLIST(content,DBFETCH(thing)->contents) { notify(player,unparse_object(player,content)); } } } static void showexits(dbref player, dbref thing) { dbref xit; switch (Typeof(thing)) { case TYPE_ROOM: if (DBFETCH(thing)->sp.room.exits != NOTHING) { notify(player,"Actions/exits:"); DOLIST(xit,DBFETCH(thing)->sp.room.exits) { notify(player,unparse_object(player,xit)); } } break; case TYPE_THING: if (DBFETCH(thing)->sp.thing.actions != NOTHING) { notify(player,"Actions/exits:"); DOLIST(xit,DBFETCH(thing)->sp.thing.actions) { notify(player,unparse_object(player,xit)); } } break; case TYPE_PLAYER: if (DBFETCH(thing)->sp.player.actions != NOTHING) { notify(player,"Actions/exits:"); DOLIST(xit,DBFETCH(thing)->sp.player.actions) { notify(player,unparse_object(player,xit)); } } break; } } static void do_examine_(dbref player, const char *name, UNUSED_ARG(const char *match), int all) { dbref thing; struct match_data md; if (*name == '\0') { thing = getloc(player); if (thing == 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_here(&md); match_me(&md); match_player(&md); /* get result */ thing = noisy_match_result(&md); if (thing == NOTHING) return; } if (! PERMIT_EXAMINE(player,thing)) { print_owner(player,thing); return; } print_atexam_info(player,thing); if (all) { showprops(player,thing,0); showcontents(player,thing); showexits(player,thing); } } void do_examine(dbref player, const char *name, const char *match) { do_examine_(player,name,match,1); } void do_at_examine(dbref player, const char *name, const char *match) { do_examine_(player,name,match,0); } 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 ? PLUR_TRI ); /* money.h */ 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_find(dbref player, const char *name) { dbref i; object_flag_type current_flags; current_flags = FLAGS(player); FLAGS(player) &= ~SILENT; if(!payfor(player,LOOKUP_COST,"@find")) notify(player, OUT_ERR ); /* defined in money.h */ else { if (Royalty(player)) { for(i = 0; i < db_top; i++) { if(!*name || (NAME(i) && string_match(NAME(i),name))) notify(player, unparse_object(player, i)); } } else { for (i = player; i != NOTHING; i = DBFETCH(i)->nextowned) { if(!*name || (NAME(i) && string_match(NAME(i),name))) notify(player, unparse_object(player, i)); } } notify(player, "***End of List***"); } FLAGS(player) = current_flags; } void do_owned(dbref player, const char *name, const char *match) { dbref obj, i; struct match_data md; if (strlen(name)) { init_match(player, name, NOTYPE, &md); match_all_exits(&md); match_neighbor(&md); match_possession(&md); if(Royalty(player)) { match_absolute(&md); match_player(&md); } match_here(&md); match_me(&md); if(((obj = noisy_match_result(&md)) == AMBIGUOUS) || (obj == NOTHING)) return; } else obj = player; if (!Royalty(player) && (player != OWNER(obj))) { notify (player, "Permission denied."); return; } if (Typeof(obj) == TYPE_PLAYER) { dbref count; count = db_top + 5; for(i = obj; i != NOTHING; i = DBFETCH(i)->nextowned) { if (!strlen(match) || string_match(DBFETCH(i)->name, match)) notify(player, unparse_object(player, i)); if (count-- < 1) { notify(player,"***INTERNAL ERROR: Circular owned list***"); log_status("CIRCULAR OWNERSHIP LIST FOR #%d, RESETTING LISTS",(int)obj); reset_lists(); break; } } notify(player, "***End of List***"); } else notify(player, "Object not a player."); } 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 (Royalty(player)) match_player(&md); thing = noisy_match_result(&md); if ((thing == NOTHING) || (thing == AMBIGUOUS)) return; for (i=0;(!depth||(ilocation; } notify(player,"***End of List***"); }