mux/src/object.cpp

Go to the documentation of this file.
00001 // object.cpp -- Low-level object manipulation routines.
00002 //
00003 // $Id: object.cpp,v 1.17 2006/01/07 17:36:11 sdennis Exp $
00004 //
00005 
00006 #include "copyright.h"
00007 #include "autoconf.h"
00008 #include "config.h"
00009 #include "externs.h"
00010 
00011 #include "attrs.h"
00012 #include "command.h"
00013 #include "mguests.h"
00014 #include "powers.h"
00015 
00016 #define IS_CLEAN(i) (isGarbage(i) && Going(i) && \
00017              ((i) >= 0) && ((i) < mudstate.db_top) && \
00018              (Location(i) == NOTHING) && \
00019              (Contents(i) == NOTHING) && (Exits(i) == NOTHING) && \
00020              (Next(i) == NOTHING) && (Owner(i) == GOD))
00021 
00022 static int check_type;
00023 
00024 /*
00025  * ---------------------------------------------------------------------------
00026  * * Log_pointer_err, Log_header_err, Log_simple_damage: Write errors to the
00027  * * log file.
00028  */
00029 
00030 static void Log_pointer_err(dbref prior, dbref obj, dbref loc, dbref ref,
00031     const char *reftype, const char *errtype)
00032 {
00033     STARTLOG(LOG_PROBLEMS, "OBJ", "DAMAG");
00034     log_type_and_name(obj);
00035     if (loc != NOTHING)
00036     {
00037         log_text(" in ");
00038         log_type_and_name(loc);
00039     }
00040     log_text(": ");
00041     if (prior == NOTHING)
00042     {
00043         log_text(reftype);
00044     }
00045     else
00046     {
00047         log_text("Next pointer");
00048     }
00049     log_text(" ");
00050     log_type_and_name(ref);
00051     log_text(" ");
00052     log_text(errtype);
00053     ENDLOG;
00054 }
00055 
00056 static void Log_header_err(dbref obj, dbref loc, dbref val, bool is_object,
00057     const char *valtype, const char *errtype)
00058 {
00059     STARTLOG(LOG_PROBLEMS, "OBJ", "DAMAG");
00060     log_type_and_name(obj);
00061     if (loc != NOTHING)
00062     {
00063         log_text(" in ");
00064         log_type_and_name(loc);
00065     }
00066     log_text(": ");
00067     log_text(valtype);
00068     log_text(" ");
00069     if (is_object)
00070     {
00071         log_type_and_name(val);
00072     }
00073     else
00074     {
00075         log_number(val);
00076     }
00077     log_text(" ");
00078     log_text(errtype);
00079     ENDLOG;
00080 }
00081 
00082 static void Log_simple_err(dbref obj, dbref loc, const char *errtype)
00083 {
00084     STARTLOG(LOG_PROBLEMS, "OBJ", "DAMAG");
00085     log_type_and_name(obj);
00086     if (loc != NOTHING)
00087     {
00088         log_text(" in ");
00089         log_type_and_name(loc);
00090     }
00091     log_text(": ");
00092     log_text(errtype);
00093     ENDLOG;
00094 }
00095 
00096 /*
00097  * ---------------------------------------------------------------------------
00098  * * start_home, default_home, can_set_home, new_home, clone_home:
00099  * * Routines for validating and determining homes.
00100  */
00101 
00102 dbref start_home(void)
00103 {
00104     if (mudconf.start_home != NOTHING)
00105     {
00106         return mudconf.start_home;
00107     }
00108     return mudconf.start_room;
00109 }
00110 
00111 dbref default_home(void)
00112 {
00113     if (mudconf.default_home != NOTHING)
00114     {
00115         return mudconf.default_home;
00116     }
00117     if (mudconf.start_home != NOTHING)
00118     {
00119         return mudconf.start_home;
00120     }
00121     return mudconf.start_room;
00122 }
00123 
00124 bool can_set_home(dbref player, dbref thing, dbref home)
00125 {
00126     if (  !Good_obj(player)
00127        || !Good_obj(home)
00128        || thing == home)
00129     {
00130         return false;
00131     }
00132 
00133     switch (Typeof(home))
00134     {
00135     case TYPE_PLAYER:
00136     case TYPE_ROOM:
00137     case TYPE_THING:
00138         if (Going(home))
00139         {
00140             return false;
00141         }
00142         if (  Controls(player, home)
00143            || Abode(home))
00144         {
00145             return true;
00146         }
00147     }
00148     return false;
00149 }
00150 
00151 dbref new_home(dbref player)
00152 {
00153     dbref loc = Location(player);
00154     if (can_set_home(Owner(player), player, loc))
00155     {
00156         return loc;
00157     }
00158     loc = Home(Owner(player));
00159     if (can_set_home(Owner(player), player, loc))
00160     {
00161         return loc;
00162     }
00163     return default_home();
00164 }
00165 
00166 dbref clone_home(dbref player, dbref thing)
00167 {
00168     dbref loc = Home(thing);
00169     if (can_set_home(Owner(player), player, loc))
00170     {
00171         return loc;
00172     }
00173     return new_home(player);
00174 }
00175 
00176 /*
00177  * ---------------------------------------------------------------------------
00178  * * create_obj: Create an object of the indicated type IF the player can
00179  * * afford it.
00180  */
00181 
00182 dbref create_obj(dbref player, int objtype, const char *name, int cost)
00183 {
00184     dbref obj, owner;
00185     int quota = 0, value = 0, nValidName;
00186     FLAGSET f;
00187     char *buff;
00188     const char *pValidName;
00189     const char *tname;
00190     bool okname = false, self_owned = false, require_inherit = false;
00191 
00192     switch (objtype)
00193     {
00194     case TYPE_ROOM:
00195 
00196         cost = mudconf.digcost;
00197         quota = mudconf.room_quota;
00198         f = mudconf.room_flags;
00199         pValidName = MakeCanonicalObjectName(name, &nValidName, &okname);
00200         tname = "a room";
00201         break;
00202 
00203     case TYPE_THING:
00204 
00205         if (cost < mudconf.createmin)
00206             cost = mudconf.createmin;
00207         if (cost > mudconf.createmax)
00208             cost = mudconf.createmax;
00209         quota = mudconf.thing_quota;
00210         f = mudconf.thing_flags;
00211         value = OBJECT_ENDOWMENT(cost);
00212         pValidName = MakeCanonicalObjectName(name, &nValidName, &okname);
00213         tname = "a thing";
00214         break;
00215 
00216     case TYPE_EXIT:
00217 
00218         cost = mudconf.opencost;
00219         quota = mudconf.exit_quota;
00220         f = mudconf.exit_flags;
00221         pValidName = MakeCanonicalExitName(name, &nValidName, &okname);
00222         tname = "an exit";
00223         break;
00224 
00225     case TYPE_PLAYER:
00226 
00227         if (cost)
00228         {
00229             cost = mudconf.robotcost;
00230             quota = mudconf.player_quota;
00231             f = mudconf.robot_flags;
00232             value = 0;
00233             tname = "a robot";
00234             require_inherit = true;
00235         }
00236         else
00237         {
00238             cost = 0;
00239             quota = 0;
00240             f = mudconf.player_flags;
00241             value = mudconf.paystart;
00242             quota = mudconf.start_quota;
00243             self_owned = true;
00244             tname = "a player";
00245         }
00246         buff = munge_space(name);
00247         pValidName = name;
00248         if (!badname_check(buff))
00249         {
00250             notify(player, "That name is not allowed.");
00251             free_lbuf(buff);
00252             return NOTHING;
00253         }
00254         if (*buff)
00255         {
00256             okname = ValidatePlayerName(buff);
00257             if (!okname)
00258             {
00259                 notify(player, "That's a silly name for a player.");
00260                 free_lbuf(buff);
00261                 return NOTHING;
00262             }
00263         }
00264         if (okname)
00265         {
00266             okname = (lookup_player(NOTHING, buff, false) == NOTHING);
00267             if (!okname)
00268             {
00269                 notify(player, tprintf("The name %s is already taken.", name));
00270                 free_lbuf(buff);
00271                 return NOTHING;
00272             }
00273         }
00274         free_lbuf(buff);
00275         break;
00276 
00277     default:
00278         LOG_SIMPLE(LOG_BUGS, "BUG", "OTYPE", tprintf("Bad object type in create_obj: %d.", objtype));
00279         return NOTHING;
00280     }
00281 
00282     if (!okname)
00283     {
00284         notify(player, tprintf("That's a silly name for %s!", tname));
00285         return NOTHING;
00286     }
00287 
00288     if (!self_owned)
00289     {
00290         if (!Good_obj(player))
00291         {
00292             return NOTHING;
00293         }
00294         owner = Owner(player);
00295         if (!Good_obj(owner))
00296         {
00297             return NOTHING;
00298         }
00299     }
00300     else
00301     {
00302         owner = NOTHING;
00303     }
00304 
00305     if (require_inherit)
00306     {
00307         if (!Inherits(player))
00308         {
00309             notify(player, NOPERM_MESSAGE);
00310             return NOTHING;
00311         }
00312     }
00313 
00314     // Make sure the creator can pay for the object.
00315     //
00316     if ((player != NOTHING) && !canpayfees(player, player, cost, quota))
00317     {
00318         return NOTHING;
00319     }
00320 
00321     // Get the first object from the freelist.  If the object is not clean,
00322     // discard the remainder of the freelist and go get a completely new object.
00323     //
00324     obj = NOTHING;
00325     if (mudstate.freelist != NOTHING)
00326     {
00327         obj = mudstate.freelist;
00328         if (IS_CLEAN(obj))
00329         {
00330             mudstate.freelist = Link(obj);
00331         }
00332         else
00333         {
00334             LOG_SIMPLE(LOG_PROBLEMS, "FRL", "DAMAG", tprintf("Freelist damaged, bad object #%d.", obj));
00335             obj = NOTHING;
00336             mudstate.freelist = NOTHING;
00337         }
00338     }
00339     if (obj == NOTHING)
00340     {
00341         obj = mudstate.db_top;
00342         db_grow(mudstate.db_top + 1);
00343     }
00344     atr_free(obj);  // just in case.
00345 
00346     // Set things up according to the object type.
00347     //
00348     s_Location(obj, NOTHING);
00349     s_Contents(obj, NOTHING);
00350     s_Exits(obj, NOTHING);
00351     s_Next(obj, NOTHING);
00352     s_Link(obj, NOTHING);
00353     s_Parent(obj, NOTHING);
00354 
00355     if (mudconf.autozone && player != NOTHING)
00356     {
00357         s_Zone(obj, Zone(player));
00358     }
00359     else
00360     {
00361         s_Zone(obj, NOTHING);
00362     }
00363     f.word[FLAG_WORD1] |= objtype;
00364     db[obj].fs = f;
00365     s_Owner(obj, (self_owned ? obj : owner));
00366     s_Pennies(obj, value);
00367     Unmark(obj);
00368     pValidName = munge_space(pValidName);
00369     s_Name(obj, pValidName);
00370     free_lbuf(pValidName);
00371     db[obj].cpu_time_used.Set100ns(0);
00372 
00373     db[obj].tThrottleExpired.Set100ns(0);
00374     s_ThAttrib(obj, 0);
00375     s_ThMail(obj, 0);
00376 
00377     CLinearTimeAbsolute ltaNow;
00378     ltaNow.GetLocal();
00379     buff = ltaNow.ReturnDateString(7);
00380     atr_add_raw(obj, A_CREATED, buff);
00381     atr_add_raw(obj, A_MODIFIED, buff);
00382 
00383     if (objtype == TYPE_PLAYER)
00384     {
00385         atr_add_raw(obj, A_LAST, buff);
00386 
00387         buff = alloc_sbuf("create_obj.quota");
00388         mux_ltoa(quota, buff);
00389         atr_add_raw(obj, A_QUOTA, buff);
00390         atr_add_raw(obj, A_RQUOTA, buff);
00391         add_player_name(obj, Name(obj));
00392         free_sbuf(buff);
00393         s_Zone(obj, NOTHING);
00394     }
00395     return obj;
00396 }
00397 
00398 /*
00399  * ---------------------------------------------------------------------------
00400  * * destroy_obj: Destroy an object.  Assumes it has already been removed from
00401  * * all lists and has no contents or exits.
00402  */
00403 
00404 static void destroy_bad_obj(dbref obj)
00405 {
00406     if (!mudstate.bStandAlone)
00407     {
00408         halt_que(NOTHING, obj);
00409         nfy_que(obj, A_SEMAPHORE, NFY_DRAIN, 0);
00410         fwdlist_clr(obj);
00411         stack_clr(obj);
00412         ReleaseAllResources(obj);
00413     }
00414     atr_free(obj);
00415     s_Name(obj, NULL);
00416     s_Flags(obj, FLAG_WORD1, (TYPE_GARBAGE | GOING));
00417     s_Flags(obj, FLAG_WORD2, 0);
00418     s_Flags(obj, FLAG_WORD3, 0);
00419     s_Powers(obj, 0);
00420     s_Powers2(obj, 0);
00421     s_Location(obj, NOTHING);
00422     s_Contents(obj, NOTHING);
00423     s_Exits(obj, NOTHING);
00424     s_Next(obj, NOTHING);
00425     s_Link(obj, NOTHING);
00426     s_Owner(obj, GOD);
00427     s_Pennies(obj, 0);
00428     s_Parent(obj, NOTHING);
00429     s_Zone(obj, NOTHING);
00430 }
00431 
00432 void destroy_obj(dbref obj)
00433 {
00434     if (!Good_obj(obj))
00435     {
00436         if (  (obj >= 0)
00437            && (obj < mudstate.db_top))
00438         {
00439             destroy_bad_obj(obj);
00440         }
00441         return;
00442     }
00443 
00444     // Validate the owner.
00445     //
00446     dbref owner = Owner(obj);
00447     bool good_owner = Good_owner(owner);
00448 
00449     // Halt any pending commands (waiting or semaphore).
00450     //
00451     if (!mudstate.bStandAlone)
00452     {
00453         if (  halt_que(NOTHING, obj) > 0
00454            && good_owner
00455            && !Quiet(obj)
00456            && !Quiet(owner))
00457         {
00458             notify(owner, "Halted.");
00459         }
00460         nfy_que(obj, A_SEMAPHORE, NFY_DRAIN, 0);
00461 
00462         // Remove forwardlists and stacks.
00463         //
00464         fwdlist_clr(obj);
00465         stack_clr(obj);
00466     }
00467 
00468     // Compensate the owner for the object.
00469     //
00470     if (  good_owner
00471        && owner != obj)
00472     {
00473         int val = 0;
00474         int quota = 0;
00475         switch (Typeof(obj))
00476         {
00477         case TYPE_ROOM:
00478             val = mudconf.digcost;
00479             quota = mudconf.room_quota;
00480             break;
00481 
00482         case TYPE_THING:
00483             val = OBJECT_DEPOSIT(Pennies(obj));
00484             quota = mudconf.thing_quota;
00485             break;
00486 
00487         case TYPE_EXIT:
00488             if (Location(obj) == NOTHING)
00489             {
00490                 val = mudconf.opencost;
00491             }
00492             else
00493             {
00494                 val = mudconf.opencost + mudconf.linkcost;
00495             }
00496             quota = mudconf.exit_quota;
00497             break;
00498 
00499         case TYPE_PLAYER:
00500             if (Robot(obj))
00501             {
00502                 val = mudconf.robotcost;
00503             }
00504             else
00505             {
00506                 val = 0;
00507             }
00508             quota = mudconf.player_quota;
00509             break;
00510         }
00511         if (val)
00512         {
00513             giveto(owner, val);
00514             if (  !Quiet(owner)
00515                && !Quiet(obj))
00516             {
00517                 notify(owner, tprintf(
00518                        "You get back your %d %s deposit for %s(#%d).",
00519                         val, mudconf.one_coin, Name(obj), obj));
00520             }
00521         }
00522         if (  mudconf.quotas
00523            && quota)
00524         {
00525             add_quota(owner, quota);
00526         }
00527     }
00528     if (!mudstate.bStandAlone)
00529     {
00530         ReleaseAllResources(obj);
00531     }
00532     atr_free(obj);
00533     s_Name(obj, NULL);
00534     s_Flags(obj, FLAG_WORD1, (TYPE_GARBAGE | GOING));
00535     s_Flags(obj, FLAG_WORD2, 0);
00536     s_Flags(obj, FLAG_WORD3, 0);
00537     s_Powers(obj, 0);
00538     s_Powers2(obj, 0);
00539     s_Location(obj, NOTHING);
00540     s_Contents(obj, NOTHING);
00541     s_Exits(obj, NOTHING);
00542     s_Next(obj, NOTHING);
00543     s_Link(obj, NOTHING);
00544     s_Owner(obj, GOD);
00545     s_Pennies(obj, 0);
00546     s_Parent(obj, NOTHING);
00547     s_Zone(obj, NOTHING);
00548 
00549     local_data_free(obj);
00550 }
00551 
00552 /*
00553  * ---------------------------------------------------------------------------
00554  * * make_freelist: Build a freelist
00555  */
00556 
00557 static void make_freelist(void)
00558 {
00559     dbref i;
00560 
00561     mudstate.freelist = NOTHING;
00562     DO_WHOLE_DB_BACKWARDS(i)
00563     {
00564         if (IS_CLEAN(i))
00565         {
00566             s_Link(i, mudstate.freelist);
00567             mudstate.freelist = i;
00568         }
00569     }
00570 }
00571 
00572 /*
00573  * ---------------------------------------------------------------------------
00574  * * divest_object: Get rid of KEY contents of object.
00575  */
00576 
00577 void divest_object(dbref thing)
00578 {
00579     dbref curr, temp;
00580 
00581     SAFE_DOLIST(curr, temp, Contents(thing))
00582     {
00583         if (  !Controls(thing, curr)
00584            && Has_location(curr)
00585            && Key(curr))
00586         {
00587             if (  !Good_obj(Home(curr))
00588                || Going(Home(curr)))
00589             {
00590                 s_Home(curr, new_home(curr));
00591             }
00592             move_via_generic(curr, HOME, NOTHING, 0);
00593         }
00594     }
00595 }
00596 
00597 /*
00598  * ---------------------------------------------------------------------------
00599  * * empty_obj, purge_going: Get rid of GOING objects in the db.
00600  */
00601 
00602 void empty_obj(dbref obj)
00603 {
00604     dbref targ, next;
00605 
00606     // Send the contents home
00607     //
00608     SAFE_DOLIST(targ, next, Contents(obj))
00609     {
00610         if (!Has_location(targ))
00611         {
00612             Log_simple_err(targ, obj,
00613                    "Funny object type in contents list of GOING location. Flush terminated.");
00614             break;
00615         }
00616         else if (Location(targ) != obj)
00617         {
00618             Log_header_err(targ, obj, Location(targ), true,
00619                    "Location",
00620                    "indicates object really in another location during cleanup of GOING location.  Flush terminated.");
00621             break;
00622         }
00623         else
00624         {
00625             s_Location(targ, NOTHING);
00626             s_Next(targ, NOTHING);
00627             if (  !Good_obj(Home(targ))
00628                || Going(Home(targ))
00629                || Home(targ) == obj)
00630             {
00631                 s_Home(targ, new_home(targ));
00632             }
00633             move_via_generic(targ, HOME, NOTHING, 0);
00634             divest_object(targ);
00635         }
00636     }
00637 
00638     // Destroy the exits.
00639     //
00640     SAFE_DOLIST(targ, next, Exits(obj))
00641     {
00642         if (!isExit(targ) && !isGarbage(targ))
00643         {
00644             Log_simple_err(targ, obj, "Funny object type in exit list of GOING location. Flush terminated.");
00645             break;
00646         }
00647         else if (Exits(targ) != obj)
00648         {
00649             Log_header_err(targ, obj, Exits(targ), true, "Location",
00650                    "indicates exit really in another location during cleanup of GOING location.  Flush terminated.");
00651             break;
00652         }
00653         else
00654         {
00655             destroy_obj(targ);
00656         }
00657     }
00658 }
00659 
00660 /*
00661  * ---------------------------------------------------------------------------
00662  * * destroy_exit, destroy_thing, destroy_player
00663  */
00664 
00665 void destroy_exit(dbref exit)
00666 {
00667     dbref loc = Exits(exit);
00668     s_Exits(loc, remove_first(Exits(loc), exit));
00669     destroy_obj(exit);
00670 }
00671 
00672 void destroy_thing(dbref thing)
00673 {
00674     move_via_generic(thing, NOTHING, Owner(thing), 0);
00675     empty_obj(thing);
00676     destroy_obj(thing);
00677 }
00678 
00679 void destroy_player(dbref player, dbref victim)
00680 {
00681     // Bye bye...
00682     //
00683     boot_off(victim, "You have been destroyed!");
00684     halt_que(victim, NOTHING);
00685     int count = chown_all(victim, player, player, CHOWN_NOZONE);
00686 
00687     // Remove the name from the name hash table.
00688     //
00689     delete_player_name(victim, Name(victim));
00690     dbref aowner;
00691     int aflags;
00692     char *buf = atr_pget(victim, A_ALIAS, &aowner, &aflags);
00693     delete_player_name(victim, buf);
00694     free_lbuf(buf);
00695 
00696     move_via_generic(victim, NOTHING, player, 0);
00697     destroy_obj(victim);
00698     notify_quiet(player, tprintf("(%d objects @chowned to you)", count));
00699 }
00700 
00701 static void purge_going(void)
00702 {
00703     dbref i;
00704     DO_WHOLE_DB(i)
00705     {
00706         if (!Going(i))
00707         {
00708             continue;
00709         }
00710 
00711         const char *p;
00712         switch (Typeof(i))
00713         {
00714         case TYPE_PLAYER:
00715             p = atr_get_raw(i, A_DESTROYER);
00716             if (!p)
00717             {
00718                 STARTLOG(LOG_PROBLEMS, "OBJ", "DAMAG");
00719                 log_type_and_name(i);
00720                 dbref loc = Location(i);
00721                 if (loc != NOTHING)
00722                 {
00723                     log_text(" in ");
00724                     log_type_and_name(loc);
00725                 }
00726                 log_text("GOING object doesn't remember it's destroyer. GOING reset.");
00727                 ENDLOG;
00728                 db[i].fs.word[FLAG_WORD1] &= ~GOING;
00729             }
00730             else
00731             {
00732                 dbref player = (dbref) mux_atol(p);
00733                 destroy_player(player, i);
00734             }
00735             break;
00736 
00737         case TYPE_ROOM:
00738 
00739             // Room scheduled for destruction... do it.
00740             //
00741             empty_obj(i);
00742             destroy_obj(i);
00743             break;
00744 
00745         case TYPE_THING:
00746             destroy_thing(i);
00747             break;
00748 
00749         case TYPE_EXIT:
00750             destroy_exit(i);
00751             break;
00752 
00753         case TYPE_GARBAGE:
00754             break;
00755 
00756         default:
00757 
00758             // Something else... How did this happen?
00759             //
00760             Log_simple_err(i, NOTHING,
00761               "GOING object with unexpected type.  Destroyed.");
00762             destroy_obj(i);
00763         }
00764     }
00765 }
00766 
00767 // ---------------------------------------------------------------------------
00768 // check_dead_refs: Look for references to GOING or illegal objects.
00769 //
00770 static void check_pennies(dbref thing, int limit, const char *qual)
00771 {
00772     if (Going(thing))
00773     {
00774         return;
00775     }
00776     int j = Pennies(thing);
00777     if (j)
00778     {
00779         if (isRoom(thing) || isExit(thing))
00780         {
00781             Log_header_err(thing, NOTHING, j, false, qual, "is strange.  Reset.");
00782             s_Pennies(thing, 0);
00783         }
00784         else if (j < 0)
00785         {
00786             Log_header_err(thing, NOTHING, j, false, qual, "is negative.");
00787         }
00788         else if (limit < j)
00789         {
00790             Log_header_err(thing, NOTHING, j, false, qual, "is excessive.");
00791         }
00792     }
00793     else
00794     {
00795         if(isPlayer(thing) || isThing(thing))
00796         {
00797             Log_header_err(thing, NOTHING, j, false, qual, "is zero.");
00798         }
00799     }
00800 }
00801 
00802 static void check_dead_refs(void)
00803 {
00804     dbref targ, owner, i, j;
00805     int aflags;
00806     char *str;
00807     FWDLIST *fp;
00808     bool dirty;
00809 
00810     DO_WHOLE_DB(i)
00811     {
00812         // Check the owner.
00813         //
00814         owner = Owner(i);
00815         if (!Good_obj(owner))
00816         {
00817             if (isPlayer(i))
00818             {
00819                 Log_header_err(i, NOTHING, owner, true, "Owner",
00820                     "is invalid.  Set to player.");
00821                 owner = i;
00822             }
00823             else
00824             {
00825                 Log_header_err(i, NOTHING, owner, true, "Owner",
00826                     "is invalid.  Set to GOD.");
00827                 owner = GOD;
00828             }
00829             s_Owner(i, owner);
00830             if (!mudstate.bStandAlone)
00831             {
00832                 halt_que(NOTHING, i);
00833             }
00834             s_Halted(i);
00835         }
00836         else if (check_type & DBCK_FULL)
00837         {
00838             if (Going(owner))
00839             {
00840                 if (isPlayer(i))
00841                 {
00842                     Log_header_err(i, NOTHING, owner, true,
00843                        "Owner", "is set GOING.  Set to player.");
00844                     owner = i;
00845                 }
00846                 else
00847                 {
00848                     Log_header_err(i, NOTHING, owner, true,
00849                        "Owner", "is set GOING.  Set to GOD.");
00850                     owner = GOD;
00851                 }
00852                 s_Owner(i, owner);
00853                 if (!mudstate.bStandAlone)
00854                 {
00855                     halt_que(NOTHING, i);
00856                 }
00857                 s_Halted(i);
00858             }
00859             else if (!OwnsOthers(owner))
00860             {
00861                 if (isPlayer(i))
00862                 {
00863                     Log_header_err(i, NOTHING, owner, true,
00864                        "Owner", "is not a valid owner type.  Set to player.");
00865                     owner = i;
00866                 }
00867                 else
00868                 {
00869                     Log_header_err(i, NOTHING, owner, true,
00870                        "Owner", "is not a valid owner type.  Set to GOD.");
00871                     owner = GOD;
00872                 }
00873                 s_Owner(i, owner);
00874             }
00875         }
00876 
00877         // Check the parent
00878         //
00879         targ = Parent(i);
00880         if (Good_obj(targ))
00881         {
00882             if (Going(targ))
00883             {
00884                 s_Parent(i, NOTHING);
00885                 if (!mudstate.bStandAlone)
00886                 {
00887                     if (  !Quiet(i)
00888                        && !Quiet(owner))
00889                     {
00890                         notify(owner, tprintf("Parent cleared on %s(#%d)",
00891                             Name(i), i));
00892                     }
00893                 }
00894                 else
00895                 {
00896                     Log_header_err(i, Location(i), targ, true, "Parent",
00897                         "is invalid.  Cleared.");
00898                 }
00899             }
00900         }
00901         else if (targ != NOTHING)
00902         {
00903             Log_header_err(i, Location(i), targ, true,
00904                 "Parent", "is invalid.  Cleared.");
00905             s_Parent(i, NOTHING);
00906         }
00907 
00908         // Check the zone.
00909         //
00910         targ = Zone(i);
00911         if (Good_obj(targ))
00912         {
00913             if (Going(targ))
00914             {
00915                 s_Zone(i, NOTHING);
00916                 if (!mudstate.bStandAlone)
00917                 {
00918                     owner = Owner(i);
00919                     if (  !Quiet(i)
00920                        && !Quiet(owner))
00921                     {
00922                         notify(owner, tprintf("Zone cleared on %s(#%d)",
00923                             Name(i), i));
00924                     }
00925                 }
00926                 else
00927                 {
00928                     Log_header_err(i, Location(i), targ, true, "Zone",
00929                         "is invalid.  Cleared.");
00930                 }
00931             }
00932         }
00933         else if (targ != NOTHING)
00934         {
00935             Log_header_err(i, Location(i), targ, true, "Zone",
00936                 "is invalid.  Cleared.");
00937             s_Zone(i, NOTHING);
00938         }
00939 
00940         // Check forwardlist
00941         //
00942         fp = fwdlist_get(i);
00943         dirty = false;
00944         if (fp)
00945         {
00946             for (j = 0; j < fp->count; j++)
00947             {
00948                 targ = fp->data[j];
00949                 if (  Good_obj(targ)
00950                    && Going(targ))
00951                 {
00952                     fp->data[j] = NOTHING;
00953                     dirty = true;
00954                 }
00955                 else if (  !Good_obj(targ)
00956                         && targ != NOTHING)
00957                 {
00958                     fp->data[j] = NOTHING;
00959                     dirty = true;
00960                 }
00961             }
00962         }
00963         if (dirty)
00964         {
00965             str = alloc_lbuf("purge_going");
00966             (void)fwdlist_rewrite(fp, str);
00967             atr_get_info(i, A_FORWARDLIST, &owner, &aflags);
00968             atr_add(i, A_FORWARDLIST, str, owner, aflags);
00969             free_lbuf(str);
00970         }
00971 
00972         if (check_type & DBCK_FULL)
00973         {
00974             // Check for wizards
00975             //
00976             if (Wizard(i))
00977             {
00978                 if (isPlayer(i))
00979                 {
00980                     Log_simple_err(i, NOTHING, "Player is a WIZARD.");
00981                 }
00982                 if (!Wizard(Owner(i)))
00983                 {
00984                     Log_header_err(i, NOTHING, Owner(i), true,
00985                                "Owner", "of a WIZARD object is not a wizard");
00986                 }
00987             }
00988         }
00989 
00990         switch (Typeof(i))
00991         {
00992         case TYPE_PLAYER:
00993             // Check home.
00994             //
00995             targ = Home(i);
00996             if (  !Good_obj(targ)
00997                || !Has_contents(targ))
00998             {
00999                 Log_simple_err(i, Location(i), "Bad home. Reset.");
01000                 s_Home(i, default_home());
01001             }
01002 
01003             // Check the location.
01004             //
01005             targ = Location(i);
01006             if (  !Good_obj(targ)
01007                || !Has_contents(targ))
01008             {
01009                 Log_pointer_err(NOTHING, i, NOTHING, targ, "Location",
01010                     "is invalid.  Moved to home.");
01011                 move_object(i, Home(i));
01012             }
01013 
01014             // Check for self-referential Next().
01015             //
01016             if (Next(i) == i)
01017             {
01018                 Log_simple_err(i, NOTHING,
01019                      "Next points to self.  Next cleared.");
01020                 s_Next(i, NOTHING);
01021             }
01022 
01023             if (check_type & DBCK_FULL)
01024             {
01025                 // Check wealth.
01026                 //
01027                 targ = mudconf.paylimit;
01028                 check_pennies(i, targ, "Wealth");
01029             }
01030             break;
01031 
01032         case TYPE_THING:
01033 
01034             // Check home.
01035             //
01036             targ = Home(i);
01037             if (  !Good_obj(targ)
01038                || !Has_contents(targ))
01039             {
01040                 if (!mudstate.bStandAlone)
01041                 {
01042                     if (  !Quiet(i)
01043                        && !Quiet(owner))
01044                     {
01045                         notify(owner, tprintf("Home reset on %s(#%d)",
01046                             Name(i), i));
01047                     }
01048                     else
01049                     {
01050                         Log_header_err(i, Location(i), targ, true, "Home",
01051                             "is invalid.  Cleared.");
01052                     }
01053                 }
01054                 s_Home(i, new_home(i));
01055             }
01056 
01057             // Check the location.
01058             //
01059             targ = Location(i);
01060             if (  !Good_obj(targ)
01061                || !Has_contents(targ))
01062             {
01063                 Log_pointer_err(NOTHING, i, NOTHING, targ, "Location",
01064                     "is invalid.  Moved to home.");
01065                 move_object(i, HOME);
01066             }
01067 
01068             // Check for self-referential Next().
01069             //
01070             if (Next(i) == i)
01071             {
01072                 Log_simple_err(i, NOTHING,
01073                     "Next points to self.  Next cleared.");
01074                 s_Next(i, NOTHING);
01075             }
01076             if (check_type & DBCK_FULL)
01077             {
01078                 // Check value.
01079                 //
01080                 targ = OBJECT_ENDOWMENT(mudconf.createmax);
01081                 check_pennies(i, targ, "Value");
01082             }
01083             break;
01084 
01085         case TYPE_ROOM:
01086 
01087             // Check the dropto.
01088             //
01089             targ = Dropto(i);
01090             if (Good_obj(targ))
01091             {
01092                 if (Going(targ))
01093                 {
01094                     s_Dropto(i, NOTHING);
01095                     if (!mudstate.bStandAlone)
01096                     {
01097                         if (  !Quiet(i)
01098                            && !Quiet(owner))
01099                         {
01100                             notify(owner, tprintf("Dropto removed from %s(#%d)",
01101                                 Name(i), i));
01102                         }
01103                     }
01104                     else
01105                     {
01106                         Log_header_err(i, NOTHING, targ, true, "Dropto",
01107                             "is invalid.  Removed.");
01108                     }
01109                 }
01110             }
01111             else if (  targ != NOTHING
01112                     && targ != HOME)
01113             {
01114                 Log_header_err(i, NOTHING, targ, true, "Dropto",
01115                     "is invalid.  Cleared.");
01116                 s_Dropto(i, NOTHING);
01117             }
01118             if (check_type & DBCK_FULL)
01119             {
01120                 // NEXT should be null.
01121                 //
01122                 if (Next(i) != NOTHING)
01123                 {
01124                     Log_header_err(i, NOTHING, Next(i), true, "Next pointer",
01125                         "should be NOTHING.  Reset.");
01126                     s_Next(i, NOTHING);
01127                 }
01128 
01129                 // LINK should be null.
01130                 //
01131                 if (Link(i) != NOTHING)
01132                 {
01133                     Log_header_err(i, NOTHING, Link(i), true, "Link pointer ",
01134                         "should be NOTHING.  Reset.");
01135                     s_Link(i, NOTHING);
01136                 }
01137 
01138                 // Check value.
01139                 //
01140                 check_pennies(i, 1, "Value");
01141             }
01142             break;
01143 
01144         case TYPE_EXIT:
01145 
01146             // If it points to something GOING, set it going.
01147             //
01148             targ = Location(i);
01149             if (Good_obj(targ))
01150             {
01151                 if (Going(targ))
01152                 {
01153                     s_Going(i);
01154                 }
01155             }
01156             else if (targ == HOME)
01157             {
01158                 // null case, HOME is always valid.
01159                 //
01160             }
01161             else if (targ != NOTHING)
01162             {
01163                 Log_header_err(i, Exits(i), targ, true, "Destination",
01164                     "is invalid.  Exit destroyed.");
01165                 s_Going(i);
01166             }
01167             else
01168             {
01169                 if (!Has_contents(targ))
01170                 {
01171                     Log_header_err(i, Exits(i), targ, true, "Destination",
01172                         "is not a valid type.  Exit destroyed.");
01173                     s_Going(i);
01174                 }
01175             }
01176 
01177             // Check for self-referential Next().
01178             //
01179             if (Next(i) == i)
01180             {
01181                 Log_simple_err(i, NOTHING,
01182                     "Next points to self.  Next cleared.");
01183                 s_Next(i, NOTHING);
01184             }
01185             if (check_type & DBCK_FULL)
01186             {
01187                 // CONTENTS should be null.
01188                 //
01189                 if (Contents(i) != NOTHING)
01190                 {
01191                     Log_header_err(i, Exits(i), Contents(i), true, "Contents",
01192                         "should be NOTHING.  Reset.");
01193                     s_Contents(i, NOTHING);
01194                 }
01195 
01196                 // LINK should be null.
01197                 //
01198                 if (Link(i) != NOTHING)
01199                 {
01200                     Log_header_err(i, Exits(i), Link(i), true, "Link",
01201                         "should be NOTHING.  Reset.");
01202                     s_Link(i, NOTHING);
01203                 }
01204 
01205                 // Check value.
01206                 //
01207                 check_pennies(i, 1, "Value");
01208             }
01209             break;
01210 
01211         case TYPE_GARBAGE:
01212             break;
01213 
01214         default:
01215 
01216             // Funny object type, destroy it.
01217             //
01218             Log_simple_err(i, NOTHING, "Funny object type.  Destroyed.");
01219             destroy_obj(i);
01220         }
01221     }
01222 }
01223 
01224 /*
01225  * ---------------------------------------------------------------------------
01226  * * check_loc_exits, check_exit_chains: Validate the exits chains
01227  * * of objects and attempt to correct problems.  The following errors are
01228  * * found and corrected:
01229  * *      Location not in database                        - skip it.
01230  * *      Location GOING                                  - skip it.
01231  * *      Location not a PLAYER, ROOM, or THING           - skip it.
01232  * *      Location already visited                        - skip it.
01233  * *      Exit/next pointer not in database               - NULL it.
01234  * *      Member is not an EXIT                           - terminate chain.
01235  * *      Member is GOING                                 - destroy exit.
01236  * *      Member already checked (is in another list)     - terminate chain.
01237  * *      Member in another chain (recursive check)       - terminate chain.
01238  * *      Location of member is not specified location    - reset it.
01239  */
01240 
01241 static void check_loc_exits(dbref loc)
01242 {
01243     if (!Good_obj(loc))
01244     {
01245         return;
01246     }
01247 
01248     // Only check players, rooms, and things that aren't GOING.
01249     //
01250     if (  isExit(loc)
01251        || Going(loc))
01252     {
01253         return;
01254     }
01255 
01256     // If marked, we've checked here already.
01257     //
01258     if (Marked(loc))
01259     {
01260         return;
01261     }
01262     Mark(loc);
01263 
01264     // Check all the exits.
01265     //
01266     dbref temp, exitloc, dest;
01267     dbref back = NOTHING;
01268     dbref exit = Exits(loc);
01269     while (exit != NOTHING)
01270     {
01271         exitloc = NOTHING;
01272         dest = NOTHING;
01273 
01274         if (Good_obj(exit))
01275         {
01276             exitloc = Exits(exit);
01277             dest = Location(exit);
01278         }
01279         if (!Good_obj(exit))
01280         {
01281             // A bad pointer - terminate chain.
01282             //
01283             Log_pointer_err(back, loc, NOTHING, exit, "Exit list",
01284                 "is invalid.  List nulled.");
01285             if (back != NOTHING)
01286             {
01287                 s_Next(back, NOTHING);
01288             }
01289             else
01290             {
01291                 s_Exits(loc, NOTHING);
01292             }
01293             exit = NOTHING;
01294         }
01295         else if (!isExit(exit))
01296         {
01297             // Not an exit - terminate chain.
01298             //
01299             Log_pointer_err(back, loc, NOTHING, exit, "Exitlist member",
01300                 "is not an exit.  List terminated.");
01301             if (back != NOTHING)
01302             {
01303                 s_Next(back, NOTHING);
01304             }
01305             else
01306             {
01307                 s_Exits(loc, NOTHING);
01308             }
01309             exit = NOTHING;
01310         }
01311         else if (Going(exit))
01312         {
01313             // Going - silently filter out.
01314             //
01315             temp = Next(exit);
01316             if (back != NOTHING)
01317             {
01318                 s_Next(back, temp);
01319             }
01320             else
01321             {
01322                 s_Exits(loc, temp);
01323             }
01324             destroy_obj(exit);
01325             exit = temp;
01326             continue;
01327         }
01328         else if (Marked(exit))
01329         {
01330             // Already in another list - terminate chain.
01331             //
01332             Log_pointer_err(back, loc, NOTHING, exit, "Exitlist member",
01333                 "is in another exitlist.  Cleared.");
01334             if (back != NOTHING)
01335             {
01336                 s_Next(back, NOTHING);
01337             }
01338             else
01339             {
01340                 s_Exits(loc, NOTHING);
01341             }
01342             exit = NOTHING;
01343         }
01344         else if (  !Good_obj(dest)
01345                 && dest != HOME
01346                 && dest != NOTHING)
01347         {
01348             // Destination is not in the db.  Null it.
01349             //
01350             Log_pointer_err(back, loc, NOTHING, exit, "Destination",
01351                 "is invalid.  Cleared.");
01352             s_Location(exit, NOTHING);
01353         }
01354         else if (exitloc != loc)
01355         {
01356             // Exit thinks it's in another place.  Check the exitlist there
01357             // and see if it contains this exit. If it does, then our exitlist
01358             // somehow pointed into the middle of their exitlist. If not,
01359             // assume we own the exit.'
01360             //
01361             check_loc_exits(exitloc);
01362             if (Marked(exit))
01363             {
01364                 // It's in the other list, give it up.
01365                 //
01366                 Log_pointer_err(back, loc, NOTHING, exit, "",
01367                     "is in another exitlist.  List terminated.");
01368                 if (back != NOTHING)
01369                 {
01370                     s_Next(back, NOTHING);
01371                 }
01372                 else
01373                 {
01374                     s_Exits(loc, NOTHING);
01375                 }
01376                 exit = NOTHING;
01377             }
01378             else
01379             {
01380                 // Not in the other list, assume in ours.
01381                 //
01382                 Log_header_err(exit, loc, exitloc, true,
01383                     "Not on chain for location", "Reset.");
01384                 s_Exits(exit, loc);
01385             }
01386         }
01387         if (exit != NOTHING)
01388         {
01389             // All OK (or all was made OK).
01390             //
01391             if (check_type & DBCK_FULL)
01392             {
01393                 // Make sure exit owner owns at least one of the source or
01394                 // destination.  Just warn if he doesn't.
01395                 //
01396                 temp = Owner(exit);
01397                 if (  temp != Owner(loc)
01398                    && temp != Owner(Location(exit)))
01399                 {
01400                     Log_header_err(exit, loc, temp, true, "Owner",
01401                         "does not own either the source or destination.");
01402                 }
01403             }
01404             Mark(exit);
01405             back = exit;
01406             exit = Next(exit);
01407         }
01408     }
01409     return;
01410 }
01411 
01412 static void check_exit_chains(void)
01413 {
01414     dbref i;
01415 
01416     Unmark_all(i);
01417     DO_WHOLE_DB(i)
01418     {
01419         check_loc_exits(i);
01420     }
01421     DO_WHOLE_DB(i)
01422     {
01423         if (  isExit(i)
01424            && !Marked(i))
01425         {
01426             Log_simple_err(i, NOTHING, "Disconnected exit.  Destroyed.");
01427             destroy_obj(i);
01428         }
01429     }
01430 }
01431 
01432 /*
01433  * ---------------------------------------------------------------------------
01434  * * check_misplaced_obj, check_loc_contents, check_contents_chains: Validate
01435  * * the contents chains of objects and attempt to correct problems.  The
01436  * * following errors are found and corrected:
01437  * *      Location not in database                        - skip it.
01438  * *      Location GOING                                  - skip it.
01439  * *      Location not a PLAYER, ROOM, or THING           - skip it.
01440  * *      Location already visited                        - skip it.
01441  * *      Contents/next pointer not in database           - NULL it.
01442  * *      Member is not an PLAYER or THING                - terminate chain.
01443  * *      Member is GOING                                 - destroy exit.
01444  * *      Member already checked (is in another list)     - terminate chain.
01445  * *      Member in another chain (recursive check)       - terminate chain.
01446  * *      Location of member is not specified location    - reset it.
01447  */
01448 
01449 static void check_loc_contents(dbref);
01450 
01451 static void check_misplaced_obj(dbref *obj, dbref back, dbref loc)
01452 {
01453     // Object thinks it's in another place.  Check the contents list there
01454     // and see if it contains this object.  If it does, then our contents
01455     // list somehow pointed into the middle of their contents list and we
01456     // should truncate our list. If not, assume we own the object.
01457     //
01458     if (!Good_obj(*obj))
01459     {
01460         return;
01461     }
01462     loc = Location(*obj);
01463     Unmark(*obj);
01464     if (Good_obj(loc))
01465     {
01466         check_loc_contents(loc);
01467     }
01468     if (Marked(*obj))
01469     {
01470         // It's in the other list, give it up.
01471         //
01472         Log_pointer_err(back, loc, NOTHING, *obj, "",
01473             "is in another contents list.  Cleared.");
01474         if (back != NOTHING)
01475         {
01476             s_Next(back, NOTHING);
01477         }
01478         else
01479         {
01480             s_Contents(loc, NOTHING);
01481         }
01482         *obj = NOTHING;
01483     }
01484     else
01485     {
01486         // Not in the other list, assume in ours.
01487         //
01488         Log_header_err(*obj, loc, Contents(*obj), true, "Location",
01489             "is invalid.  Reset.");
01490         s_Contents(*obj, loc);
01491     }
01492     return;
01493 }
01494 
01495 static void check_loc_contents(dbref loc)
01496 {
01497     if (!Good_obj(loc))
01498     {
01499         return;
01500     }
01501 
01502     // Only check players, rooms, and things that aren't GOING.
01503     //
01504     if (  isExit(loc)
01505        || Going(loc))
01506     {
01507         return;
01508     }
01509 
01510     dbref back = NOTHING;
01511     dbref obj = Contents(loc);
01512     while (obj != NOTHING)
01513     {
01514         if (!Good_obj(obj))
01515         {
01516             // A bad pointer - terminate chain.
01517             //
01518             Log_pointer_err(back, loc, NOTHING, obj, "Contents list",
01519                 "is invalid.  Cleared.");
01520             if (back != NOTHING)
01521             {
01522                 s_Next(back, NOTHING);
01523             }
01524             else
01525             {
01526                 s_Contents(loc, NOTHING);
01527             }
01528             obj = NOTHING;
01529         }
01530         else if (!Has_location(obj))
01531         {
01532             // Not a player or thing - terminate chain.
01533             //
01534             Log_pointer_err(back, loc, NOTHING, obj, "",
01535                 "is not a player or thing.  Cleared.");
01536             if (back != NOTHING)
01537             {
01538                 s_Next(back, NOTHING);
01539             }
01540             else
01541             {
01542                 s_Contents(loc, NOTHING);
01543             }
01544             obj = NOTHING;
01545         }
01546         else if (Marked(obj))
01547         {
01548             // Already visited - either truncate or ignore.
01549             //
01550             if (Location(obj) != loc)
01551             {
01552                 // Location wrong - either truncate or fix.
01553                 //
01554                 check_misplaced_obj(&obj, back, loc);
01555             }
01556             else
01557             {
01558                 // Location right - recursive contents.
01559                 //
01560             }
01561         }
01562         else if (Location(obj) != loc)
01563         {
01564             // Location wrong - either truncate or fix.
01565             //
01566             check_misplaced_obj(&obj, back, loc);
01567         }
01568         if (obj != NOTHING)
01569         {
01570             // All OK (or all was made OK).
01571             //
01572             if (check_type & DBCK_FULL)
01573             {
01574                 // Check for wizard command-handlers inside nonwiz. Just warn
01575                 // if we find one.
01576                 //
01577                 if (Wizard(obj) && !Wizard(loc))
01578                 {
01579                     if (Commer(obj))
01580                     {
01581                         Log_simple_err(obj, loc,
01582                             "Wizard command handling object inside nonwizard.");
01583                     }
01584                 }
01585 
01586                 // Check for nonwizard objects inside wizard objects.
01587                 //
01588                 if (  Wizard(loc)
01589                    && !Wizard(obj)
01590                    && !Wizard(Owner(obj)))
01591                 {
01592                     Log_simple_err(obj, loc, "Nonwizard object inside wizard.");
01593                 }
01594             }
01595             Mark(obj);
01596             back = obj;
01597             obj = Next(obj);
01598         }
01599     }
01600 }
01601 
01602 static void check_contents_chains(void)
01603 {
01604     dbref i;
01605 
01606     Unmark_all(i);
01607     DO_WHOLE_DB(i)
01608     {
01609         check_loc_contents(i);
01610     }
01611     DO_WHOLE_DB(i)
01612     {
01613         if (  !Going(i)
01614            && !Marked(i)
01615            && Has_location(i))
01616         {
01617             Log_simple_err(i, Location(i), "Orphaned object, moved home.");
01618             s_Location(i, NOTHING);
01619             s_Next(i, NOTHING);
01620             if (  !Good_obj(Home(i))
01621                || Going(Home(i)))
01622             {
01623                 s_Home(i, new_home(i));
01624             }
01625             move_via_generic(i, HOME, NOTHING, 0);
01626         }
01627     }
01628 }
01629 
01630 /*
01631  * ---------------------------------------------------------------------------
01632  * * mark_place, check_floating: Look for floating rooms not set FLOATING.
01633  */
01634 
01635 static void mark_place(dbref loc)
01636 {
01637     dbref exit;
01638 
01639     // If already marked, exit.  Otherwise set marked.
01640     //
01641     if (!Good_obj(loc))
01642     {
01643         return;
01644     }
01645     if (Marked(loc))
01646     {
01647         return;
01648     }
01649     Mark(loc);
01650 
01651     // Visit all places you can get to via exits from here.
01652     //
01653     for (exit = Exits(loc); exit != NOTHING; exit = Next(exit))
01654     {
01655         if (Good_obj(Location(exit)))
01656         {
01657             mark_place(Location(exit));
01658         }
01659     }
01660 }
01661 
01662 static void check_floating(void)
01663 {
01664     dbref owner, i;
01665 
01666     // Mark everyplace you can get to via exits from the starting room.
01667     //
01668     Unmark_all(i);
01669     mark_place(mudconf.start_room);
01670 
01671     // Look for rooms not marked and not set FLOATING.
01672     //
01673     DO_WHOLE_DB(i)
01674     {
01675         if (  isRoom(i)
01676            && !Floating(i)
01677            && !Going(i)
01678            && !Marked(i))
01679         {
01680             owner = Owner(i);
01681             if (!mudstate.bStandAlone)
01682             {
01683                 if (Good_owner(owner))
01684                 {
01685                     notify(owner, tprintf( "You own a floating room: %s(#%d)",
01686                         Name(i), i));
01687                 }
01688             }
01689             else
01690             {
01691                 Log_simple_err(i, NOTHING, "Disconnected room.");
01692             }
01693         }
01694     }
01695 }
01696 
01697 /*
01698  * ---------------------------------------------------------------------------
01699  * * do_dbck: Perform a database consistency check and clean up damage.
01700  */
01701 
01702 void do_dbck(dbref executor, dbref caller, dbref enactor, int key)
01703 {
01704     UNUSED_PARAMETER(caller);
01705     UNUSED_PARAMETER(enactor);
01706 
01707     check_type = key;
01708     check_dead_refs();
01709     check_exit_chains();
01710     check_contents_chains();
01711     check_floating();
01712     if (  !mudstate.bStandAlone
01713        && executor != NOTHING)
01714     {
01715         Guest.CleanUp();
01716     }
01717     purge_going();
01718     make_freelist();
01719 
01720     // Allow the local extensions to do data checks.
01721     //
01722     local_dbck();
01723 
01724     if (  !mudstate.bStandAlone
01725        && executor != NOTHING
01726        && !Quiet(executor))
01727     {
01728         notify(executor, "Done.");
01729     }
01730 }

Generated on Mon May 28 04:40:10 2007 for MUX by  doxygen 1.4.7