mux/src/look.cpp

Go to the documentation of this file.
00001 // look.cpp -- Commands which look at things.
00002 //
00003 // $Id: look.cpp,v 1.47 2007/04/14 04:57:05 sdennis Exp $
00004 //
00005 // MUX 2.4
00006 // Copyright (C) 1998 through 2004 Solid Vertical Domains, Ltd. All
00007 // rights not explicitly given are reserved.
00008 //
00009 #include "copyright.h"
00010 #include "autoconf.h"
00011 #include "config.h"
00012 #include "externs.h"
00013 
00014 #include "ansi.h"
00015 #include "attrs.h"
00016 #include "command.h"
00017 #include "interface.h"
00018 #include "powers.h"
00019 
00020 #ifdef REALITY_LVLS
00021 #include "levels.h"
00022 #endif /* REALITY_LVLS */
00023 
00024 #if defined(WOD_REALMS) || defined(REALITY_LVLS)
00025 #define NORMAL_REALM  0
00026 #define UMBRA_REALM   1
00027 #define SHROUD_REALM  2
00028 #define MATRIX_REALM  3
00029 #define FAE_REALM     4
00030 #define CHIMERA_REALM 5
00031 #define BLIND_REALM   6
00032 #define STAFF_REALM   7
00033 #define NUMBER_OF_REALMS 8
00034 
00035 static int RealmActions[NUMBER_OF_REALMS] =
00036 {
00037     REALM_DO_NORMALLY_SEEN,
00038     REALM_DO_SHOW_UMBRADESC,
00039     REALM_DO_SHOW_WRAITHDESC,
00040     REALM_DO_SHOW_MATRIXDESC,
00041     REALM_DO_SHOW_FAEDESC,
00042     REALM_DO_SHOW_FAEDESC,
00043     REALM_DO_HIDDEN_FROM_YOU,
00044     REALM_DO_NORMALLY_SEEN
00045 };
00046 
00047 // Umbra and Matrix are realms unto themselves, so if you aren't in the same
00048 // realm as what you're looking at, you can't see it.
00049 //
00050 // Normal things can't see shroud things, but shroud things can see normal things.
00051 //
00052 // Only Fae and Chimera can see Chimera.
00053 //
00054 #define MAP_SEEN     0 // Show this to that.
00055 #define MAP_HIDE     1 // Always hide this from that.
00056 #define MAP_NO_ADESC 2 // Don't trigger DESC actions on that.
00057 #define MAP_MEDIUM   4 // Hide this from that unless that is a medium and this is moving or talking.
00058 
00059 static int RealmHiddenMap[NUMBER_OF_REALMS][NUMBER_OF_REALMS] =
00060 {
00061     /* NORMAL  LOOKER */ {     MAP_SEEN, MAP_HIDE, MAP_MEDIUM, MAP_HIDE,     MAP_SEEN, MAP_HIDE, MAP_NO_ADESC, MAP_SEEN},
00062     /* UMBRA   LOOKER */ {     MAP_HIDE, MAP_SEEN, MAP_MEDIUM, MAP_HIDE,     MAP_HIDE, MAP_HIDE,     MAP_HIDE, MAP_SEEN},
00063     /* SHROUD  LOOKER */ { MAP_NO_ADESC, MAP_HIDE,   MAP_SEEN, MAP_HIDE, MAP_NO_ADESC, MAP_HIDE, MAP_NO_ADESC, MAP_SEEN},
00064     /* MATRIX  LOOKER */ {     MAP_HIDE, MAP_HIDE, MAP_MEDIUM, MAP_SEEN,     MAP_HIDE, MAP_HIDE,     MAP_HIDE, MAP_SEEN},
00065     /* FAE     LOOKER */ {     MAP_SEEN, MAP_HIDE, MAP_MEDIUM, MAP_HIDE,     MAP_SEEN, MAP_SEEN, MAP_NO_ADESC, MAP_SEEN},
00066     /* CHIMERA LOOKER */ { MAP_NO_ADESC, MAP_HIDE, MAP_MEDIUM, MAP_HIDE,     MAP_SEEN, MAP_SEEN, MAP_NO_ADESC, MAP_SEEN},
00067     /* BLIND   LOOKER */ {     MAP_HIDE, MAP_HIDE,   MAP_HIDE, MAP_HIDE,     MAP_HIDE, MAP_HIDE,     MAP_HIDE, MAP_SEEN},
00068     /* STAFF   LOOKER */ {     MAP_SEEN, MAP_SEEN,   MAP_SEEN, MAP_SEEN,     MAP_SEEN, MAP_SEEN,     MAP_SEEN, MAP_SEEN}
00069 };
00070 
00071 static int RealmExitsMap[NUMBER_OF_REALMS][NUMBER_OF_REALMS] =
00072 {
00073     /* NORMAL  LOOKER */ { MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE},
00074     /* UMBRA   LOOKER */ { MAP_SEEN, MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE},
00075     /* SHROUD  LOOKER */ { MAP_SEEN, MAP_HIDE, MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE},
00076     /* MATRIX  LOOKER */ { MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE},
00077     /* FAE     LOOKER */ { MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_SEEN, MAP_SEEN, MAP_HIDE, MAP_HIDE},
00078     /* CHIMERA LOOKER */ { MAP_SEEN, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_SEEN, MAP_SEEN, MAP_HIDE, MAP_HIDE},
00079     /* BLIND   LOOKER */ { MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE, MAP_HIDE},
00080     /* STAFF   LOOKER */ { MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN, MAP_SEEN}
00081 };
00082 
00083 static int WhichRealm(dbref what, bool bPeering)
00084 {
00085     int realm = NORMAL_REALM;
00086     if (isMatrix(what))       realm = MATRIX_REALM;
00087     else if (isUmbra(what))   realm = UMBRA_REALM;
00088     else if (isShroud(what))  realm = SHROUD_REALM;
00089     else if (isChimera(what)) realm = CHIMERA_REALM;
00090     else if (isFae(what))     realm = FAE_REALM;
00091 
00092     if (bPeering)
00093     {
00094         char *buff;
00095         dbref owner;
00096         int flags;
00097         int iPeeringRealm = get_atr("PEERING_REALM");
00098         if (0 < iPeeringRealm)
00099         {
00100             buff = atr_get(what, iPeeringRealm, &owner, &flags);
00101             if (*buff)
00102             {
00103                 if      (mux_stricmp(buff, "FAE") == 0)     realm = FAE_REALM;
00104                 else if (mux_stricmp(buff, "CHIMERA") == 0) realm = CHIMERA_REALM;
00105                 else if (mux_stricmp(buff, "SHROUD") == 0)  realm = SHROUD_REALM;
00106                 else if (mux_stricmp(buff, "UMBRA") == 0)   realm = UMBRA_REALM;
00107                 else if (mux_stricmp(buff, "MATRIX") == 0)  realm = MATRIX_REALM;
00108                 else if (mux_stricmp(buff, "NORMAL") == 0)  realm = NORMAL_REALM;
00109                 else if (mux_stricmp(buff, "BLIND") == 0)   realm = BLIND_REALM;
00110                 else if (mux_stricmp(buff, "STAFF") == 0)   realm = STAFF_REALM;
00111             }
00112             free_lbuf(buff);
00113         }
00114     }
00115     return realm;
00116 }
00117 
00118 static int HandleObfuscation(dbref looker, dbref lookee, int threshhold)
00119 {
00120     int iReturn = REALM_DO_NORMALLY_SEEN;
00121     if (isObfuscate(lookee))
00122     {
00123         char *buff;
00124         int iObfuscateLevel = 0;
00125         dbref owner;
00126         int flags;
00127         buff = atr_get(lookee, get_atr("OBF_LEVEL"), &owner, &flags);
00128         if (*buff)
00129         {
00130             iObfuscateLevel = mux_atol(buff);
00131         }
00132         free_lbuf(buff);
00133 
00134         // For OBF_LEVELS of 0, 1, and 2, we show the regular description.
00135         // 3 and above start showing a different OBFDESC.
00136         //
00137         if (3 <= iObfuscateLevel)
00138         {
00139             iReturn = REALM_DO_SHOW_OBFDESC;
00140         }
00141         if (threshhold < iObfuscateLevel)
00142         {
00143             int iHeightenSensesLevel = 0;
00144             if (isHeightenedSenses(looker))
00145             {
00146                 buff = atr_get(looker, get_atr("HSS_LEVEL"), &owner, &flags);
00147                 if (*buff)
00148                 {
00149                     iHeightenSensesLevel = mux_atol(buff);
00150                 }
00151                 free_lbuf(buff);
00152             }
00153 
00154             if (iHeightenSensesLevel < iObfuscateLevel)
00155             {
00156                 iReturn = REALM_DO_HIDDEN_FROM_YOU;
00157             }
00158             else if (iObfuscateLevel == iHeightenSensesLevel)
00159             {
00160                 if (RandomINT32(0,1))
00161                 {
00162                     iReturn = REALM_DO_HIDDEN_FROM_YOU;
00163                 }
00164             }
00165         }
00166     }
00167     return iReturn;
00168 }
00169 int DoThingToThingVisibility(dbref looker, dbref lookee, int action_state)
00170 {
00171     // If the looker is a room, then there is some contents/recursion stuff
00172     // that happens in the rest of the game code. We'll be called later for
00173     // each item in the room, things that are nearby the room, etc.
00174     //
00175     if (isRoom(looker))
00176     {
00177         return REALM_DO_NORMALLY_SEEN;
00178     }
00179 
00180     if (Staff(looker))
00181     {
00182         if (Connected(looker))
00183         {
00184             // Staff players can see everything
00185             //
00186             return REALM_DO_NORMALLY_SEEN;
00187         }
00188 
00189         if (isThing(looker))
00190         {
00191             // Wizard things in the master room can see everything.
00192             //
00193             if (Location(looker) == mudconf.master_room)
00194             {
00195                 return REALM_DO_NORMALLY_SEEN;
00196             }
00197         }
00198     }
00199     int realmLooker = WhichRealm(looker, isPeering(looker));
00200     int realmLookee = WhichRealm(lookee, false);
00201 
00202     // You can always see yourself.
00203     //
00204     if (looker == lookee)
00205     {
00206         return RealmActions[realmLooker];
00207     }
00208 
00209     bool bDisableADESC = false;
00210     if (isRoom(lookee) || isExit(lookee))
00211     {
00212         // All realms see normal rooms and exits, however, if a realm
00213         // specific description exists, they use that one. If a room or exit
00214         // is flagged with a specific realm, then -only- players and things of
00215         // that realm can see it.
00216         //
00217         // Fae and Chimera are treated as the same realm for this purpose.
00218         //
00219         if (RealmExitsMap[realmLooker][realmLookee] == MAP_HIDE)
00220         {
00221             return REALM_DO_HIDDEN_FROM_YOU;
00222         }
00223     }
00224     else
00225     {
00226         if (Staff(lookee))
00227         {
00228             // Staff players are seen in every realm.
00229             //
00230             if (Connected(lookee))
00231             {
00232                 return REALM_DO_NORMALLY_SEEN;
00233             }
00234 
00235             if (isThing(lookee))
00236             {
00237                 // Everyone can use wizard things in the master room.
00238                 //
00239                 // Wizard things that aren't in the master room follow the same
00240                 // realm-rules as everything else.
00241                 //
00242                 if (Location(lookee) == mudconf.master_room)
00243                 {
00244                     return REALM_DO_NORMALLY_SEEN;
00245                 }
00246             }
00247         }
00248 
00249         int iMap = RealmHiddenMap[realmLooker][realmLookee];
00250         if (iMap & MAP_HIDE)
00251         {
00252             return REALM_DO_HIDDEN_FROM_YOU;
00253         }
00254         if (iMap & MAP_MEDIUM)
00255         {
00256             if (isMedium(looker))
00257             {
00258                 if (action_state == ACTION_IS_STATIONARY)
00259                 {
00260                     // Even Mediums can't hear it if the Wraith is just standing still.
00261                     //
00262                     return REALM_DO_HIDDEN_FROM_YOU;
00263                 }
00264             }
00265             else
00266             {
00267                 return REALM_DO_HIDDEN_FROM_YOU;
00268             }
00269         }
00270         if (iMap & MAP_NO_ADESC)
00271         {
00272             bDisableADESC = true;
00273         }
00274     }
00275 
00276     // Do default see rules.
00277     //
00278     int iReturn = RealmActions[realmLooker];
00279     if (iReturn == REALM_DO_HIDDEN_FROM_YOU)
00280     {
00281         return iReturn;
00282     }
00283 
00284     // Do Obfuscate/Heighten Senses rules.
00285     //
00286     int threshhold = 0;
00287     switch (action_state)
00288     {
00289     case ACTION_IS_STATIONARY:
00290         threshhold = 0;
00291         break;
00292 
00293     case ACTION_IS_MOVING:
00294         threshhold = 1;
00295         break;
00296 
00297     case ACTION_IS_TALKING:
00298         if (bDisableADESC)
00299         {
00300             iReturn |= REALM_DISABLE_ADESC;
00301         }
00302         return iReturn;
00303     }
00304     int iObfReturn = HandleObfuscation(looker, lookee, threshhold);
00305     switch (iObfReturn)
00306     {
00307     case REALM_DO_SHOW_OBFDESC:
00308     case REALM_DO_HIDDEN_FROM_YOU:
00309         iReturn = iObfReturn;
00310         break;
00311     }
00312 
00313     // Decide whether to disable ADESC or not. If we can look at them,
00314     // and ADESC isn't -already- disabled via SHROUD looking at NORMAL (see above).
00315     // then, ADESC may be disabled here if the looker is Obfuscated to the lookee.
00316     //
00317     if (iReturn != REALM_DO_HIDDEN_FROM_YOU && !bDisableADESC)
00318     {
00319         if (REALM_DO_HIDDEN_FROM_YOU == HandleObfuscation(lookee, looker, 0))
00320         {
00321             bDisableADESC = true;
00322         }
00323     }
00324     if (bDisableADESC)
00325     {
00326         iReturn |= REALM_DISABLE_ADESC;
00327     }
00328     return iReturn;
00329 }
00330 
00331 static void LetDescriptionsDefault(dbref thing, int *piDESC, int *piADESC, int RealmDirective)
00332 {
00333     int   iDesc = 0;
00334     dbref owner;
00335     int   flags;
00336 
00337     *piDESC = A_DESC;
00338     *piADESC = A_ADESC;
00339 
00340     if (RealmDirective & REALM_DISABLE_ADESC)
00341     {
00342         *piADESC = 0;
00343     }
00344     switch (RealmDirective & REALM_DO_MASK)
00345     {
00346     case REALM_DO_SHOW_OBFDESC:
00347         iDesc = get_atr("OBFDESC");
00348         break;
00349 
00350     case REALM_DO_SHOW_WRAITHDESC:
00351         iDesc = get_atr("WRAITHDESC");
00352         *piADESC = 0;
00353         break;
00354 
00355     case REALM_DO_SHOW_UMBRADESC:
00356         iDesc = get_atr("UMBRADESC");
00357         break;
00358 
00359     case REALM_DO_SHOW_MATRIXDESC:
00360         iDesc = get_atr("MATRIXDESC");
00361         break;
00362 
00363     case REALM_DO_SHOW_FAEDESC:
00364         iDesc = get_atr("FAEDESC");
00365         break;
00366     }
00367 
00368     if (iDesc > 0)
00369     {
00370         char *buff = atr_pget(thing, iDesc, &owner, &flags);
00371         if (buff)
00372         {
00373             if (*buff)
00374             {
00375                 *piDESC = iDesc;
00376             }
00377             free_lbuf(buff);
00378         }
00379     }
00380 }
00381 #endif
00382 
00383 static void look_exits(dbref player, dbref loc, const char *exit_name)
00384 {
00385     // Make sure location has exits.
00386     //
00387     if (  !Good_obj(loc)
00388        || !Has_exits(loc))
00389     {
00390         return;
00391     }
00392 
00393     dbref thing, parent;
00394     char *buff, *e, *buff1, *e1;
00395     const char *s;
00396 
00397     // make sure there is at least one visible exit.
00398     //
00399     bool bFoundAnyDisplayable = false;
00400     bool bFoundAny = false;
00401     int key = 0;
00402     int lev;
00403 #ifdef REALITY_LVLS
00404     if (Dark(loc) || !IsReal(player, loc))
00405 #else
00406     if (Dark(loc))
00407 #endif /* REALITY_LVLS */
00408     {
00409         key |= VE_BASE_DARK;
00410     }
00411     ITER_PARENTS(loc, parent, lev)
00412     {
00413         key &= ~VE_LOC_DARK;
00414         if (Dark(parent))
00415         {
00416             key |= VE_LOC_DARK;
00417         }
00418         DOLIST(thing, Exits(parent))
00419         {
00420             bFoundAny = true;
00421             if (exit_displayable(thing, player, key))
00422             {
00423                 bFoundAnyDisplayable = true;
00424                 break;
00425             }
00426         }
00427         if (bFoundAnyDisplayable)
00428         {
00429             break;
00430         }
00431     }
00432 
00433     if (!bFoundAny)
00434     {
00435         return;
00436     }
00437 
00438     // Retrieve the ExitFormat attribute from the location, evaluate and display
00439     // the results in lieu of the traditional exits list if it exists.
00440     //
00441     dbref aowner;
00442     int aflags;
00443     char *ExitFormatBuffer = atr_pget(loc, A_EXITFORMAT, &aowner, &aflags);
00444     char *ExitFormat = ExitFormatBuffer;
00445 
00446     bool bDisplayExits = bFoundAnyDisplayable;
00447     if (*ExitFormat)
00448     {
00449         char *VisibleObjectList = alloc_lbuf("look_exits.VOL");
00450         char *tPtr = VisibleObjectList;
00451 
00452         ITL pContext;
00453         ItemToList_Init(&pContext, VisibleObjectList, &tPtr, '#');
00454 
00455         ITER_PARENTS(loc, parent, lev)
00456         {
00457             key &= ~VE_LOC_DARK;
00458             if (Dark(parent))
00459             {
00460                 key |= VE_LOC_DARK;
00461             }
00462 
00463             bool bShortCircuit = false;
00464             DOLIST(thing, Exits(parent))
00465             {
00466                 if (  exit_displayable(thing, player, key)
00467                    && !ItemToList_AddInteger(&pContext, thing))
00468                 {
00469                     bShortCircuit = true;
00470                     break;
00471                 }
00472             }
00473             if (bShortCircuit) break;
00474         }
00475         ItemToList_Final(&pContext);
00476 
00477         char *FormatOutput = alloc_lbuf("look_exits.FO");
00478         tPtr = FormatOutput;
00479 
00480         char *preserve[MAX_GLOBAL_REGS];
00481         int preserve_len[MAX_GLOBAL_REGS];
00482         save_and_clear_global_regs("look_exits_save", preserve, preserve_len);
00483 
00484         mux_exec(FormatOutput, &tPtr, loc, player, player,
00485                 EV_FCHECK | EV_EVAL | EV_TOP,
00486                 &ExitFormat, &VisibleObjectList, 1);
00487         *tPtr = '\0';
00488 
00489         restore_global_regs("look_exits_restore", preserve, preserve_len);
00490         notify(player, FormatOutput);
00491 
00492         free_lbuf(FormatOutput);
00493         free_lbuf(VisibleObjectList);
00494 
00495         bDisplayExits = 0;
00496     }
00497     free_lbuf(ExitFormatBuffer);
00498 
00499     if (!bDisplayExits)
00500     {
00501         return;
00502     }
00503 
00504     // Display the list of exit names
00505     //
00506     notify(player, exit_name);
00507     e = buff = alloc_lbuf("look_exits");
00508     e1 = buff1 = alloc_lbuf("look_exits2");
00509     ITER_PARENTS(loc, parent, lev)
00510     {
00511         key &= ~VE_LOC_DARK;
00512         if (Dark(parent))
00513         {
00514             key |= VE_LOC_DARK;
00515         }
00516         if (Transparent(loc))
00517         {
00518             DOLIST(thing, Exits(parent))
00519             {
00520                 if (exit_displayable(thing, player, key))
00521                 {
00522                     strcpy(buff, Name(thing));
00523                     for (e = buff; *e && *e != ';'; e++)
00524                     {
00525                         ; // Nothing.
00526                     }
00527                     *e = '\0';
00528                     notify(player, tprintf("%s leads to %s.", buff, Name(Location(thing))));
00529                 }
00530             }
00531         }
00532         else
00533         {
00534             DOLIST(thing, Exits(parent))
00535             {
00536                 if (exit_displayable(thing, player, key))
00537                 {
00538                     e1 = buff1;
00539 
00540                     // Put the exit name in buff1.
00541                     //
00542                     // chop off first exit alias to display
00543                     //
00544                     if (buff != e)
00545                     {
00546                         safe_str("  ", buff, &e);
00547                     }
00548 
00549                     for (s = Name(thing); *s && (*s != ';'); s++)
00550                     {
00551                         safe_chr(*s, buff1, &e1);
00552                     }
00553 
00554                     *e1 = 0;
00555                     /* Copy the exit name into 'buff' */
00556                     if (Html(player))
00557                     {
00558                         /* XXX The exit name needs to be HTML escaped. */
00559                         safe_str("<a xch_cmd=\"", buff, &e);
00560                         safe_str(buff1, buff, &e);
00561                         safe_str("\"> ", buff, &e);
00562                         html_escape(buff1, buff, &e);
00563                         safe_str(" </a>", buff, &e);
00564                     }
00565                     else
00566                     {
00567                         /* Append this exit to the list */
00568                         safe_str(buff1, buff, &e);
00569                     }
00570                 }
00571             }
00572         }
00573     }
00574 
00575     if (!Transparent(loc))
00576     {
00577         if (Html(player))
00578         {
00579             safe_str("\r\n", buff, &e);
00580             *e = 0;
00581             notify_html(player, buff);
00582         }
00583         else
00584         {
00585             *e = 0;
00586             notify(player, buff);
00587         }
00588     }
00589     free_lbuf(buff);
00590     free_lbuf(buff1);
00591 }
00592 
00593 #define CONTENTS_LOCAL  0
00594 #define CONTENTS_NESTED 1
00595 #define CONTENTS_REMOTE 2
00596 
00597 static void look_contents(dbref player, dbref loc, const char *contents_name, int style)
00598 {
00599     dbref thing;
00600     char *buff;
00601     char *html_buff, *html_cp;
00602     char remote_num[32];
00603 
00604     // Check to see if he can see the location.
00605     //
00606 #ifdef REALITY_LVLS
00607      bool can_see_loc = ( !Dark(loc) && IsReal(player, loc)
00608 #else
00609      bool can_see_loc = (  !Dark(loc)
00610 #endif /* REALITY_LVLS */
00611                        || (mudconf.see_own_dark && Examinable(player, loc)));
00612 
00613     dbref aowner;
00614     int aflags;
00615     char *ContentsFormatBuffer = atr_pget(loc, A_CONFORMAT, &aowner, &aflags);
00616     char *ContentsFormat = ContentsFormatBuffer;
00617 
00618     bool bDisplayContents = true;
00619     if (*ContentsFormat)
00620     {
00621         char *VisibleObjectList = alloc_lbuf("look_contents.VOL");
00622         char *tPtr = VisibleObjectList;
00623 
00624         ITL pContext;
00625         ItemToList_Init(&pContext, VisibleObjectList, &tPtr, '#');
00626 
00627         DOLIST(thing, Contents(loc))
00628         {
00629 #if defined(WOD_REALMS) || defined(REALITY_LVLS)
00630             if (  can_see(player, thing, can_see_loc)
00631                && (REALM_DO_HIDDEN_FROM_YOU != DoThingToThingVisibility(player,
00632                                                 thing, ACTION_IS_STATIONARY)) )
00633 #else
00634             if (can_see(player, thing, can_see_loc))
00635 #endif
00636             {
00637                 if (!ItemToList_AddInteger(&pContext, thing))
00638                 {
00639                     break;
00640                 }
00641             }
00642         }
00643         ItemToList_Final(&pContext);
00644 
00645         char *ContentsNameScratch = alloc_lbuf("look_contents.CNS");
00646         tPtr = ContentsNameScratch;
00647 
00648         safe_str(contents_name, ContentsNameScratch, &tPtr);
00649         *tPtr = '\0';
00650 
00651         char *FormatOutput = alloc_lbuf("look_contents.FO");
00652         tPtr = FormatOutput;
00653 
00654         char* ParameterList[] =
00655             { VisibleObjectList, ContentsNameScratch };
00656 
00657         char *preserve[MAX_GLOBAL_REGS];
00658         int preserve_len[MAX_GLOBAL_REGS];
00659         save_and_clear_global_regs("look_contents_save", preserve, preserve_len);
00660 
00661         mux_exec(FormatOutput, &tPtr, loc, player, player,
00662                 EV_FCHECK | EV_EVAL | EV_TOP,
00663                 &ContentsFormat, ParameterList, 2);
00664         *tPtr = '\0';
00665 
00666         restore_global_regs("look_contents_restore", preserve, preserve_len);
00667         notify(player, FormatOutput);
00668 
00669         free_lbuf(FormatOutput);
00670         free_lbuf(ContentsNameScratch);
00671         free_lbuf(VisibleObjectList);
00672 
00673         bDisplayContents = false;
00674     }
00675     free_lbuf(ContentsFormatBuffer);
00676 
00677     if (!bDisplayContents)
00678     {
00679         return;
00680     }
00681 
00682     html_buff = html_cp = alloc_lbuf("look_contents");
00683 
00684     // Check to see if there is anything there.
00685     //
00686     DOLIST(thing, Contents(loc))
00687     {
00688 #if defined(WOD_REALMS) || defined(REALITY_LVLS)
00689         if (  can_see(player, thing, can_see_loc)
00690            && (REALM_DO_HIDDEN_FROM_YOU != DoThingToThingVisibility(player, thing, ACTION_IS_STATIONARY)))
00691 #else
00692         if (can_see(player, thing, can_see_loc))
00693 #endif
00694         {
00695             // Something exists! Show him everything.
00696             //
00697             notify(player, contents_name);
00698             DOLIST(thing, Contents(loc))
00699             {
00700 #if defined(WOD_REALMS) || defined(REALITY_LVLS)
00701                 if (  can_see(player, thing, can_see_loc)
00702                    && (REALM_DO_HIDDEN_FROM_YOU != DoThingToThingVisibility(player, thing, ACTION_IS_STATIONARY)))
00703 #else
00704                 if (can_see(player, thing, can_see_loc))
00705 #endif
00706                 {
00707                     buff = unparse_object(player, thing, true);
00708                     html_cp = html_buff;
00709                     if (Html(player))
00710                     {
00711                         safe_str("<a xch_cmd=\"look ", html_buff, &html_cp);
00712                         switch (style)
00713                         {
00714                         case CONTENTS_LOCAL:
00715                             safe_str(Name(thing), html_buff, &html_cp);
00716                             break;
00717                         case CONTENTS_NESTED:
00718                             safe_str(Name(Location(thing)), html_buff, &html_cp);
00719                             safe_str("'s ", html_buff, &html_cp);
00720                             safe_str(Name(thing), html_buff, &html_cp);
00721                             break;
00722 
00723                         case CONTENTS_REMOTE:
00724 
00725                             remote_num[0] = '#';
00726                             mux_ltoa(thing, remote_num+1);
00727                             safe_str(remote_num, html_buff, &html_cp);
00728                             break;
00729 
00730                         default:
00731 
00732                             break;
00733                         }
00734                         safe_str("\">", html_buff, &html_cp);
00735                         html_escape(buff, html_buff, &html_cp);
00736                         safe_str("</a>\r\n", html_buff, &html_cp);
00737                         *html_cp = 0;
00738                         notify_html(player, html_buff);
00739                     }
00740                     else
00741                     {
00742                         notify(player, buff);
00743                     }
00744                     free_lbuf(buff);
00745                 }
00746             }
00747             break;  // we're done.
00748         }
00749     }
00750     free_lbuf(html_buff);
00751 }
00752 
00753 typedef struct
00754 {
00755     int mask;
00756     char letter;
00757 } ATTR_DECODE_ENTRY, *PATTR_DECODE_ENTRY;
00758 
00759 static ATTR_DECODE_ENTRY attr_decode_table[] =
00760 {
00761     { AF_LOCK,    '+' },
00762     { AF_NOPROG,  '$' },
00763     { AF_CASE,    'C' },
00764     { AF_HTML,    'H' },
00765     { AF_PRIVATE, 'I' },
00766     { AF_NOPARSE, 'P' },
00767     { AF_REGEXP,  'R' },
00768     { AF_VISUAL,  'V' },
00769     { AF_MDARK,   'M' },
00770     { AF_WIZARD,  'W' },
00771     { 0, 0 }
00772 };
00773 
00774 size_t decode_attr_flags(int aflags, char *buff)
00775 {
00776     char *p = buff;
00777     PATTR_DECODE_ENTRY pEntry;
00778     for (pEntry = attr_decode_table; pEntry->mask; pEntry++)
00779     {
00780         if (aflags & pEntry->mask)
00781         {
00782             *p++ = pEntry->letter;
00783         }
00784     }
00785     *p = '\0';
00786     return p - buff;
00787 }
00788 
00789 static void view_atr
00790 (
00791     dbref player,
00792     dbref thing,
00793     ATTR *ap,
00794     char *text,
00795     dbref aowner,
00796     int aflags,
00797     bool skip_tag
00798 )
00799 {
00800     char *buf;
00801 
00802     if (ap->flags & AF_IS_LOCK)
00803     {
00804         BOOLEXP *pBoolExp = parse_boolexp(player, text, true);
00805         text = unparse_boolexp(player, pBoolExp);
00806         free_boolexp(pBoolExp);
00807     }
00808 
00809     // If we don't control the object or own the attribute, hide the
00810     // attr owner and flag info.
00811     //
00812     if (  !Controls(player, thing)
00813        && Owner(player) != aowner)
00814     {
00815         if (  skip_tag
00816            && ap->number == A_DESC)
00817         {
00818             buf = text;
00819         }
00820         else
00821         {
00822             buf = tprintf("%s%s:%s %s", ANSI_HILITE, ap->name, ANSI_NORMAL, text);
00823         }
00824         notify(player, buf);
00825         return;
00826     }
00827 
00828     // Generate flags.
00829     //
00830     char xbuf[11];
00831     decode_attr_flags(aflags, xbuf);
00832 
00833     if (  aowner != Owner(thing)
00834        && aowner != NOTHING)
00835     {
00836         buf = tprintf("%s%s [#%d%s]:%s %s", ANSI_HILITE,
00837             ap->name, aowner, xbuf, ANSI_NORMAL, text);
00838     }
00839     else if (*xbuf)
00840     {
00841         buf = tprintf("%s%s [%s]:%s %s", ANSI_HILITE, ap->name,
00842             xbuf, ANSI_NORMAL, text);
00843     }
00844     else if (  !skip_tag
00845             || ap->number != A_DESC)
00846     {
00847         buf = tprintf("%s%s:%s %s", ANSI_HILITE, ap->name, ANSI_NORMAL, text);
00848     }
00849     else
00850     {
00851         buf = text;
00852     }
00853     notify(player, buf);
00854 }
00855 
00856 static void look_atrs1
00857 (
00858     dbref player,
00859     dbref thing,
00860     dbref othing,
00861     bool  check_exclude,
00862     bool  hash_insert
00863 )
00864 {
00865     bool bFoundCommands = false;
00866     bool bFoundListens  = false;
00867 
00868     char *as;
00869     for (int ca = atr_head(thing, &as); ca; ca = atr_next(&as))
00870     {
00871         if (  ca == A_DESC
00872            || ca == A_LOCK)
00873         {
00874             continue;
00875         }
00876 
00877         ATTR *pattr = atr_num(ca);
00878         if (!pattr)
00879         {
00880             continue;
00881         }
00882 
00883         ATTR cattr;
00884         memcpy(&cattr, pattr, sizeof(ATTR));
00885 
00886         // Should we exclude this attr?
00887         //
00888         if (  check_exclude
00889            && (  (pattr->flags & AF_PRIVATE)
00890               || hashfindLEN(&ca, sizeof(ca), &mudstate.parent_htab)))
00891         {
00892             continue;
00893         }
00894 
00895         int   aflags;
00896         dbref aowner;
00897         char *buf = atr_get(thing, ca, &aowner, &aflags);
00898 
00899         if (!(aflags & AF_NOPROG))
00900         {
00901             if (  AMATCH_CMD    == buf[0]
00902                || AMATCH_LISTEN == buf[0])
00903             {
00904                 char *s = strchr(buf+1, ':');
00905                 if (s)
00906                 {
00907                     if (AMATCH_CMD == buf[0])
00908                     {
00909                         bFoundCommands = true;
00910                     }
00911                     else
00912                     {
00913                         bFoundListens = true;
00914                     }
00915                 }
00916             }
00917         }
00918 
00919         if (bCanReadAttr(player, othing, &cattr, false))
00920         {
00921             if (!(check_exclude && (aflags & AF_PRIVATE)))
00922             {
00923                 if (hash_insert)
00924                 {
00925                     hashaddLEN(&ca, sizeof(ca), pattr, &mudstate.parent_htab);
00926                 }
00927                 view_atr(player, thing, &cattr, buf, aowner, aflags, false);
00928             }
00929         }
00930         free_lbuf(buf);
00931     }
00932 
00933     if (bFoundCommands)
00934     {
00935         mudstate.bfNoCommands.Clear(thing);
00936         mudstate.bfCommands.Set(thing);
00937     }
00938     else
00939     {
00940         mudstate.bfCommands.Clear(thing);
00941         mudstate.bfNoCommands.Set(thing);
00942     }
00943 
00944     if (bFoundListens)
00945     {
00946         mudstate.bfNoListens.Clear(thing);
00947         mudstate.bfListens.Set(thing);
00948     }
00949     else
00950     {
00951         mudstate.bfListens.Clear(thing);
00952         mudstate.bfNoListens.Set(thing);
00953     }
00954 }
00955 
00956 static void look_atrs(dbref player, dbref thing, bool check_parents)
00957 {
00958     dbref parent;
00959     int lev;
00960     bool check_exclude, hash_insert;
00961 
00962     if (!check_parents)
00963     {
00964         look_atrs1(player, thing, thing, false, false);
00965     }
00966     else
00967     {
00968         hash_insert = true;
00969         check_exclude = false;
00970         hashflush(&mudstate.parent_htab);
00971         ITER_PARENTS(thing, parent, lev)
00972         {
00973             if (!Good_obj(Parent(parent)))
00974             {
00975                 hash_insert = false;
00976             }
00977             look_atrs1(player, parent, thing, check_exclude, hash_insert);
00978             check_exclude = true;
00979         }
00980     }
00981 }
00982 
00983 static bool show_a_desc(dbref player, dbref loc)
00984 {
00985     int iDescDefault = A_DESC;
00986     int iADescDefault = A_ADESC;
00987 #if defined(WOD_REALMS) || defined(REALITY_LVLS)
00988     int iRealmDirective = DoThingToThingVisibility(player, loc, ACTION_IS_STATIONARY);
00989     if (REALM_DO_HIDDEN_FROM_YOU == iRealmDirective)
00990     {
00991         return true;
00992     }
00993     LetDescriptionsDefault(loc, &iDescDefault, &iADescDefault, iRealmDirective);
00994 #endif
00995 
00996     bool ret = false;
00997 
00998     dbref aowner;
00999     int aflags;
01000     bool indent = (isRoom(loc) && mudconf.indent_desc && atr_get_raw(loc, A_DESC));
01001 
01002     char *DescFormatBuffer = atr_pget(loc, A_DESCFORMAT, &aowner, &aflags);
01003     char *DescFormat = DescFormatBuffer;
01004     if (*DescFormat)
01005     {
01006         char *FormatOutput = alloc_lbuf("look_description.FO");
01007         char *tPtr = FormatOutput;
01008 
01009         ATTR *cattr = atr_num(iDescDefault);
01010 
01011         char *tbuf1 = atr_pget(loc, iDescDefault, &aowner, &aflags);
01012         char *str = tbuf1;
01013         char *temp = alloc_lbuf("look_description.ET");
01014         char *bp = temp;
01015         mux_exec(temp, &bp, loc, player, player,
01016                EV_FCHECK | EV_EVAL | EV_TOP,
01017                &str, (char **)NULL, 0);
01018         *bp = '\0';
01019 
01020         char *attrname = alloc_lbuf("look_description.AN");
01021         char *cp = attrname;
01022 
01023         safe_str(cattr->name, attrname, &cp);
01024         *cp = '\0';
01025         char* ParameterList[] =
01026             { temp, attrname };
01027 
01028         mux_exec(FormatOutput, &tPtr, loc, player, player,
01029                 EV_FCHECK | EV_EVAL | EV_TOP,
01030                 &DescFormat, ParameterList, 2);
01031         *tPtr = '\0';
01032 
01033         notify(player, FormatOutput);
01034 #ifdef REALITY_LVLS
01035         did_it_rlevel(player, loc, 0, NULL, A_ODESC, NULL, iADescDefault, (char **) NULL, 0);
01036 #else
01037         did_it(player, loc, 0, NULL, A_ODESC, NULL, iADescDefault, (char **) NULL, 0);
01038 #endif /* REALITY_LVLS */
01039 
01040         free_lbuf(tbuf1);
01041         free_lbuf(attrname);
01042         free_lbuf(FormatOutput);
01043         free_lbuf(temp);
01044 
01045         ret = true;
01046     }
01047     else
01048     {
01049         char *got;
01050         if (Html(player))
01051         {
01052             got = atr_pget(loc, A_HTDESC, &aowner, &aflags);
01053             if (*got)
01054             {
01055 #ifdef REALITY_LVLS
01056                 did_it_rlevel(player, loc, A_HTDESC, NULL, A_ODESC, NULL, A_ADESC, (char **) NULL, 0);
01057 #else
01058                 did_it(player, loc, A_HTDESC, NULL, A_ODESC, NULL, A_ADESC, (char **) NULL, 0);
01059 #endif /* REALITY_LVLS */
01060                 ret = true;
01061             }
01062             else
01063             {
01064                 free_lbuf(got);
01065                 got = atr_pget(loc, iDescDefault, &aowner, &aflags);
01066                 if (*got)
01067                 {
01068                     if (indent)
01069                     {
01070                         raw_notify_newline(player);
01071                     }
01072 #ifdef REALITY_LVLS
01073                     did_it_rlevel(player, loc, iDescDefault, NULL, A_ODESC, NULL, iADescDefault, (char **) NULL, 0);
01074 #else
01075                     did_it(player, loc, iDescDefault, NULL, A_ODESC, NULL, iADescDefault, (char **) NULL, 0);
01076 #endif /* REALITY_LVLS */
01077                     if (indent)
01078                     {
01079                         raw_notify_newline(player);
01080                     }
01081                     ret = true;
01082                 }
01083             }
01084         }
01085         else if (*(got = atr_pget(loc, iDescDefault, &aowner, &aflags)))
01086         {
01087             if (indent)
01088             {
01089                 raw_notify_newline(player);
01090             }
01091 #ifdef REALITY_LVLS
01092             did_it_rlevel(player, loc, iDescDefault, NULL, A_ODESC, NULL, iADescDefault, (char **) NULL, 0);
01093 #else
01094             did_it(player, loc, iDescDefault, NULL, A_ODESC, NULL, iADescDefault, (char **) NULL, 0);
01095 #endif /* REALITY_LVLS */
01096             if (indent)
01097             {
01098                 raw_notify_newline(player);
01099             }
01100             ret = true;
01101         }
01102         free_lbuf(got);
01103     }
01104     free_lbuf(DescFormatBuffer);
01105     return ret;
01106 }
01107 
01108 static void look_simple(dbref player, dbref thing, bool obey_terse)
01109 {
01110     // Only makes sense for things that can hear.
01111     //
01112     if (!Hearer(player))
01113     {
01114         return;
01115     }
01116 
01117 #if defined(WOD_REALMS) || defined(REALITY_LVLS)
01118     int iRealmDirective = DoThingToThingVisibility(player, thing, ACTION_IS_STATIONARY);
01119     if (REALM_DO_HIDDEN_FROM_YOU == iRealmDirective)
01120     {
01121         notify(player, NOMATCH_MESSAGE);
01122         return;
01123     }
01124 #endif
01125 
01126     // Get the name and db-number if we can examine it.
01127     //
01128     int can_see_thing = Examinable(player, thing);
01129     if (can_see_thing)
01130     {
01131         char *buff = unparse_object(player, thing, true);
01132         notify(player, buff);
01133         free_lbuf(buff);
01134     }
01135     int iDescDefault = A_DESC;
01136     int iADescDefault = A_ADESC;
01137 
01138 #if defined(WOD_REALMS) || defined(REALITY_LVLS)
01139     LetDescriptionsDefault(thing, &iDescDefault, &iADescDefault, iRealmDirective);
01140 #endif
01141 
01142     int pattr = (obey_terse && Terse(player)) ? 0 : iDescDefault;
01143     if (!show_a_desc(player, thing))
01144     {
01145         notify(player, "You see nothing special.");
01146 #ifdef REALITY_LVLS
01147         did_it_rlevel(player, thing, 0, NULL, A_ODESC, NULL, iADescDefault,
01148             (char **)NULL, 0);
01149 #else
01150         did_it(player, thing, pattr, NULL, A_ODESC, NULL, iADescDefault,
01151             (char **)NULL, 0);
01152 #endif /* REALITY_LVLS */
01153     }
01154 
01155     if (  !mudconf.quiet_look
01156        && (  !Terse(player)
01157           || mudconf.terse_look))
01158     {
01159         look_atrs(player, thing, false);
01160     }
01161 }
01162 
01163 static void show_desc(dbref player, dbref loc, int key)
01164 {
01165     char *got;
01166     dbref aowner;
01167     int aflags;
01168 
01169     if (  (key & LK_OBEYTERSE)
01170        && Terse(player))
01171     {
01172 #ifdef REALITY_LVLS
01173         did_it_rlevel(player, loc, 0, NULL, A_ODESC, NULL, A_ADESC, (char **)NULL, 0);
01174 #else
01175         did_it(player, loc, 0, NULL, A_ODESC, NULL, A_ADESC, (char **)NULL, 0);
01176 #endif /* REALITY_LVLS */
01177     }
01178     else if (  !isRoom(loc)
01179             && (key & LK_IDESC))
01180     {
01181         if (*(got = atr_pget(loc, A_IDESC, &aowner, &aflags)))
01182         {
01183 #ifdef REALITY_LVLS
01184            did_it_rlevel(player, loc, A_IDESC, NULL, A_ODESC, NULL, A_ADESC, (char **)NULL, 0);
01185 #else
01186             did_it(player, loc, A_IDESC, NULL, A_ODESC, NULL, A_ADESC, (char **)NULL, 0);
01187 #endif /* REALITY_LVLS */
01188         }
01189         else
01190         {
01191             show_a_desc(player, loc);
01192         }
01193         free_lbuf(got);
01194     }
01195     else
01196     {
01197         show_a_desc(player, loc);
01198     }
01199 }
01200 
01201 void look_in(dbref player, dbref loc, int key)
01202 {
01203     // Only makes sense for things that can hear.
01204     //
01205     if (!Hearer(player))
01206     {
01207         return;
01208     }
01209 
01210     // If he needs the VMRL URL, send it:
01211     //
01212     if (key & LK_SHOWVRML)
01213     {
01214         show_vrml_url(player, loc);
01215     }
01216 
01217     // Use @nameformat (by Marlek) if it's present, otherwise, use the
01218     // name and if the player can link to it, it's dbref as well.
01219     //
01220     dbref aowner;
01221     int aflags;
01222     char *NameFormatBuffer = atr_pget(loc, A_NAMEFORMAT, &aowner, &aflags);
01223     char *NameFormat = NameFormatBuffer;
01224 
01225     if (*NameFormat)
01226     {
01227         char *FormatOutput = alloc_lbuf("look_name.FO");
01228         char *tPtr = FormatOutput;
01229 
01230         char *preserve[MAX_GLOBAL_REGS];
01231         int preserve_len[MAX_GLOBAL_REGS];
01232         save_and_clear_global_regs("look_in_save", preserve, preserve_len);
01233 
01234         mux_exec(FormatOutput, &tPtr, loc, player, player,
01235                 EV_FCHECK | EV_EVAL | EV_TOP,
01236                 &NameFormat, 0, 0);
01237         *tPtr = '\0';
01238 
01239         restore_global_regs(