src/object.c

Go to the documentation of this file.
00001 /*
00002  * object.c - low-level object manipulation routines 
00003  */
00004 
00005 #include "copyright.h"
00006 #include "config.h"
00007 
00008 #include "db.h"
00009 #include "mudconf.h"
00010 #include "command.h"
00011 #include "externs.h"
00012 #include "flags.h"
00013 #include "powers.h"
00014 #include "attrs.h"
00015 #include "alloc.h"
00016 
00017 #define IS_CLEAN(i)     (IS(i, TYPE_GARBAGE, GOING) && \
00018                          (Location(i) == NOTHING) && \
00019                          (Contents(i) == NOTHING) && (Exits(i) == NOTHING) && \
00020                          (Next(i) == NOTHING) && (Owner(i) == GOD))
00021 
00022 #define ZAP_LOC(i)      { s_Location(i, NOTHING); s_Next(i, NOTHING); }
00023 
00024 static int check_type;
00025 extern int boot_off(dbref player, char *message);
00026 extern void do_mail_clear(dbref player, char *msglist);
00027 
00032 static void Log_pointer_err(dbref prior, dbref obj, dbref loc, dbref ref,
00033                                                         const char *reftype, const char *errtype)
00034 {
00035         STARTLOG(LOG_PROBLEMS, "OBJ", "DAMAG") {
00036                 log_type_and_name(obj);
00037                 if(loc != NOTHING) {
00038                         log_text((char *) " in ");
00039                         log_type_and_name(loc);
00040                 }
00041                 log_text((char *) ": ");
00042                 if(prior == NOTHING) {
00043                         log_text((char *) reftype);
00044                 } else {
00045                         log_text((char *) "Next pointer");
00046                 }
00047                 log_text((char *) " ");
00048                 log_type_and_name(ref);
00049                 log_text((char *) " ");
00050                 log_text((char *) errtype);
00051                 ENDLOG;
00052 }}
00053 
00054 static void Log_header_err(dbref obj, dbref loc, dbref val, int is_object,
00055                                                    const char *valtype, const char *errtype)
00056 {
00057         STARTLOG(LOG_PROBLEMS, "OBJ", "DAMAG") {
00058                 log_type_and_name(obj);
00059                 if(loc != NOTHING) {
00060                         log_text((char *) " in ");
00061                         log_type_and_name(loc);
00062                 }
00063                 log_text((char *) ": ");
00064                 log_text((char *) valtype);
00065                 log_text((char *) " ");
00066                 if(is_object)
00067                         log_type_and_name(val);
00068                 else
00069                         log_number(val);
00070                 log_text((char *) " ");
00071                 log_text((char *) errtype);
00072                 ENDLOG;
00073 }}
00074 
00075 static void Log_simple_err(dbref obj, dbref loc, const char *errtype)
00076 {
00077         STARTLOG(LOG_PROBLEMS, "OBJ", "DAMAG") {
00078                 log_type_and_name(obj);
00079                 if(loc != NOTHING) {
00080                         log_text((char *) " in ");
00081                         log_type_and_name(loc);
00082                 }
00083                 log_text((char *) ": ");
00084                 log_text((char *) errtype);
00085                 ENDLOG;
00086 }}
00087 
00092 dbref start_home(void)
00093 {
00094         if(mudconf.start_home != NOTHING)
00095                 return mudconf.start_home;
00096         return mudconf.start_room;
00097 }
00098 
00099 dbref default_home(void)
00100 {
00101         if(mudconf.default_home != NOTHING)
00102                 return mudconf.default_home;
00103         if(mudconf.start_home != NOTHING)
00104                 return mudconf.start_home;
00105         return mudconf.start_room;
00106 }
00107 
00108 int can_set_home(dbref player, dbref thing, dbref home)
00109 {
00110         if(!Good_obj(player) || !Good_obj(home) || (thing == home))
00111                 return 0;
00112 
00113         switch (Typeof(home)) {
00114         case TYPE_PLAYER:
00115         case TYPE_ROOM:
00116         case TYPE_THING:
00117                 if(Going(home))
00118                         return 0;
00119                 if(Controls(player, home) || Abode(home))
00120                         return 1;
00121         }
00122         return 0;
00123 }
00124 
00125 dbref new_home(dbref player)
00126 {
00127         dbref loc;
00128 
00129         loc = Location(player);
00130         if(can_set_home(Owner(player), player, loc))
00131                 return loc;
00132         loc = Home(Owner(player));
00133         if(can_set_home(Owner(player), player, loc))
00134                 return loc;
00135         return default_home();
00136 }
00137 
00138 dbref clone_home(dbref player, dbref thing)
00139 {
00140         dbref loc;
00141 
00142         loc = Home(thing);
00143         if(can_set_home(Owner(player), player, loc))
00144                 return loc;
00145         return new_home(player);
00146 }
00147 
00151 static void make_freelist(void)
00152 {
00153         dbref i;
00154 
00155         mudstate.freelist = NOTHING;
00156         DO_WHOLE_DB_REV(i) {
00157                 if(IS_CLEAN(i)) {
00158                         s_Link(i, mudstate.freelist);
00159                         mudstate.freelist = i;
00160 
00161                 }
00162         }
00163 }
00164 
00169 dbref create_obj(dbref player, int objtype, char *name, int cost)
00170 {
00171         dbref obj, owner;
00172         int quota, okname = 0, value, self_owned, require_inherit;
00173         FLAG f1, f2, f3;
00174         time_t tt;
00175         char *buff;
00176         const char *tname;
00177 
00178         value = 0;
00179         quota = 0;
00180         self_owned = 0;
00181         require_inherit = 0;
00182 
00183         switch (objtype) {
00184         case TYPE_ROOM:
00185                 cost = mudconf.digcost;
00186                 quota = mudconf.room_quota;
00187                 f1 = mudconf.room_flags.word1;
00188                 f2 = mudconf.room_flags.word2;
00189                 f3 = mudconf.room_flags.word3;
00190                 okname = ok_name(name);
00191                 tname = "a room";
00192                 break;
00193         case TYPE_THING:
00194                 if(cost < mudconf.createmin)
00195                         cost = mudconf.createmin;
00196                 if(cost > mudconf.createmax)
00197                         cost = mudconf.createmax;
00198                 quota = mudconf.thing_quota;
00199                 f1 = mudconf.thing_flags.word1;
00200                 f2 = mudconf.thing_flags.word2;
00201                 f3 = mudconf.thing_flags.word3;
00202                 value = OBJECT_ENDOWMENT(cost);
00203                 okname = ok_name(name);
00204                 tname = "a thing";
00205                 break;
00206         case TYPE_EXIT:
00207                 cost = mudconf.opencost;
00208                 quota = mudconf.exit_quota;
00209                 f1 = mudconf.exit_flags.word1;
00210                 f2 = mudconf.exit_flags.word2;
00211                 f3 = mudconf.exit_flags.word3;
00212                 okname = ok_name(name);
00213                 tname = "an exit";
00214                 break;
00215         case TYPE_PLAYER:
00216                 if(cost) {
00217                         cost = mudconf.robotcost;
00218                         quota = mudconf.player_quota;
00219                         f1 = mudconf.robot_flags.word1;
00220                         f2 = mudconf.robot_flags.word2;
00221                         f3 = mudconf.robot_flags.word3;
00222                         value = 0;
00223                         tname = "a robot";
00224                         require_inherit = 1;
00225                 } else {
00226                         cost = 0;
00227                         quota = 0;
00228                         f1 = mudconf.player_flags.word1;
00229                         f2 = mudconf.player_flags.word2;
00230                         f3 = mudconf.player_flags.word3;
00231                         value = mudconf.paystart;
00232                         quota = mudconf.start_quota;
00233                         self_owned = 1;
00234                         tname = "a player";
00235                 }
00236                 buff = munge_space(name);
00237                 if(!badname_check(buff)) {
00238                         notify(player, "That name is not allowed.");
00239                         free_lbuf(buff);
00240                         return NOTHING;
00241                 }
00242                 if(*buff) {
00243                         okname = ok_player_name(buff);
00244                         if(!okname) {
00245                                 notify(player, "That's a silly name for a player.");
00246                                 free_lbuf(buff);
00247                                 return NOTHING;
00248                         }
00249                 }
00250                 if(okname) {
00251                         okname = (lookup_player(NOTHING, buff, 0) == NOTHING);
00252                         if(!okname) {
00253                                 notify_printf(player, "The name %s is already taken.", name);
00254                                 free_lbuf(buff);
00255                                 return NOTHING;
00256                         }
00257                 }
00258                 free_lbuf(buff);
00259                 break;
00260         default:
00261                 LOG_SIMPLE(LOG_BUGS, "BUG", "OTYPE",
00262                                    tprintf("Bad object type in create_obj: %d.", objtype));
00263                 return NOTHING;
00264         }
00265 
00266         if(!self_owned) {
00267                 if(!Good_obj(player))
00268                         return NOTHING;
00269                 owner = Owner(player);
00270                 if(!Good_obj(owner))
00271                         return NOTHING;
00272         } else {
00273                 owner = NOTHING;
00274         }
00275 
00276         if(require_inherit) {
00277                 if(!Inherits(player)) {
00278                         notify(player, "Permission denied.");
00279                         return NOTHING;
00280                 }
00281         }
00282         /*
00283          * Make sure the creator can pay for the object. 
00284          */
00285 
00286         if((player != NOTHING) && !canpayfees(player, player, cost, quota))
00287                 return NOTHING;
00288 
00289         /*
00290          * Get the first object from the freelist. If the object is not 
00291          * clean, discard the remainder of the freelist and go get a
00292          * completely new object. 
00293          */
00294 
00295         obj = NOTHING;
00296         if(mudstate.freelist != NOTHING) {
00297                 obj = mudstate.freelist;
00298                 if(Good_obj(obj) && IS_CLEAN(obj)) {
00299                         mudstate.freelist = Link(obj);
00300                 } else {
00301                         LOG_SIMPLE(LOG_PROBLEMS, "FRL", "DAMAG",
00302                                            tprintf("Freelist damaged, bad object #%d.", obj));
00303                         obj = NOTHING;
00304                         mudstate.freelist = NOTHING;
00305                 }
00306         }
00307         if(obj == NOTHING) {
00308                 obj = mudstate.db_top;
00309                 db_grow(mudstate.db_top + 1);
00310         }
00311         atr_free(obj);                          // Just in case...
00312 
00313         /*
00314          * Set things up according to the object type 
00315          */
00316 
00317         s_Location(obj, NOTHING);
00318         s_Contents(obj, NOTHING);
00319         s_Exits(obj, NOTHING);
00320         s_Next(obj, NOTHING);
00321         s_Link(obj, NOTHING);
00322 
00323         if(objtype == TYPE_ROOM && mudconf.room_parent > 0)
00324                 s_Parent(obj, mudconf.room_parent);
00325         else if(objtype == TYPE_EXIT && mudconf.exit_parent > 0)
00326                 s_Parent(obj, mudconf.exit_parent);
00327         else
00328                 s_Parent(obj, NOTHING);
00329 
00330         s_Zone(obj, Zone(player));
00331         s_Flags(obj, objtype | f1);
00332         s_Flags2(obj, f2);
00333         s_Flags3(obj, f3);
00334         s_Owner(obj, (self_owned ? obj : owner));
00335         s_Pennies(obj, value);
00336         Unmark(obj);
00337         buff = munge_space((char *) name);
00338         s_Name(obj, buff);
00339         free_lbuf(buff);
00340 
00341         if(objtype == TYPE_PLAYER) {
00342                 time(&tt);
00343                 buff = (char *) ctime(&tt);
00344                 buff[strlen(buff) - 1] = '\0';
00345                 atr_add_raw(obj, A_LAST, buff);
00346 
00347                 buff = alloc_sbuf("create_obj.quota");
00348                 sprintf(buff, "%d", quota);
00349                 atr_add_raw(obj, A_QUOTA, buff);
00350                 atr_add_raw(obj, A_RQUOTA, buff);
00351                 add_player_name(obj, Name(obj));
00352                 free_sbuf(buff);
00353                 s_Zone(obj, NOTHING);
00354         }
00355         make_freelist();
00356         return obj;
00357 }
00358 
00359 
00364 void destroy_obj(dbref player, dbref obj)
00365 {
00366         dbref owner;
00367         int good_owner, val, quota;
00368         STACK *sp, *next;
00369         char *tname;
00370 
00371         if(!Good_obj(obj))
00372                 return;
00373 
00374         /*
00375          * Validate the owner 
00376          */
00377 
00378         owner = Owner(obj);
00379         good_owner = Good_owner(owner);
00380 
00381         /*
00382          * Halt any pending commands (waiting or semaphore) 
00383          */
00384         if(halt_que(NOTHING, obj) > 0) {
00385                 if(good_owner && !Quiet(obj) && !Quiet(owner)) {
00386                         notify(owner, "Halted.");
00387                 }
00388         }
00389         nfy_que(obj, 0, NFY_DRAIN, 0);
00390 
00391         /*
00392          * Compensate the owner for the object 
00393          */
00394 
00395         val = 1;
00396         quota = 1;
00397         if(good_owner && (owner != obj)) {
00398                 switch (Typeof(obj)) {
00399                 case TYPE_ROOM:
00400                         val = mudconf.digcost;
00401                         quota = mudconf.room_quota;
00402                         break;
00403                 case TYPE_THING:
00404                         val = OBJECT_DEPOSIT(Pennies(obj));
00405                         quota = mudconf.thing_quota;
00406                         break;
00407                 case TYPE_EXIT:
00408                         val = mudconf.opencost;
00409                         quota = mudconf.exit_quota;
00410                         break;
00411                 case TYPE_PLAYER:
00412                         if(Robot(obj))
00413                                 val = mudconf.robotcost;
00414                         else
00415                                 val = 0;
00416                         quota = mudconf.player_quota;
00417                 }
00418                 giveto(owner, val);
00419                 if(mudconf.quotas)
00420                         add_quota(owner, quota);
00421 
00422                 if(!Quiet(owner) && !Quiet(obj))
00423                         notify_printf(owner,
00424                                                   "You get back your %d %s deposit for %s(#%d).",
00425                                                   val, mudconf.one_coin, Name(obj), obj);
00426         }
00427 
00428         if((player != NOTHING) && !Quiet(player)) {
00429                 if(good_owner && Owner(player) != owner) {
00430                         if(owner == obj) {
00431                                 notify_printf(player, "Destroyed. %s(#%d)", Name(obj), obj);
00432                         } else {
00433                                 tname = alloc_sbuf("destroy_obj");
00434                                 StringCopy(tname, Name(owner));
00435                                 notify_printf(player, "Destroyed. %s's %s(#%d)", tname,
00436                                                           Name(obj), obj);
00437                                 free_sbuf(tname);
00438                         }
00439                 } else if(!Quiet(obj)) {
00440                         notify(player, "Destroyed.");
00441                 }
00442         }
00443 
00444         atr_free(obj);
00445         s_Name(obj, "Garbage");
00446         s_Flags(obj, (TYPE_GARBAGE | GOING));
00447         s_Flags2(obj, 0);
00448         s_Flags3(obj, 0);
00449         s_Powers(obj, 0);
00450         s_Powers2(obj, 0);
00451         s_Location(obj, NOTHING);
00452         s_Contents(obj, NOTHING);
00453         s_Exits(obj, NOTHING);
00454         s_Next(obj, NOTHING);
00455         s_Link(obj, NOTHING);
00456         s_Owner(obj, GOD);
00457         s_Pennies(obj, 0);
00458         s_Parent(obj, NOTHING);
00459         s_Zone(obj, NOTHING);
00460 
00461         /*
00462          * Clear the stack 
00463          */
00464         for(sp = Stack(obj); sp != NULL; sp = next) {
00465                 next = sp->next;
00466                 free_lbuf(sp->data);
00467                 free(sp);
00468         }
00469 
00470         s_Stack(obj, NULL);
00471 
00472         if(mudconf.have_comsys)
00473                 toast_player(obj);
00474 
00475         make_freelist();
00476         return;
00477 }
00478 
00482 void divest_object(dbref thing)
00483 {
00484         dbref curr, temp;
00485 
00486         SAFE_DOLIST(curr, temp, Contents(thing)) {
00487                 if(!Controls(thing, curr) && Has_location(curr) && Key(curr)) {
00488                         move_via_generic(curr, HOME, NOTHING, 0);
00489                 }
00490         }
00491 }
00492 
00496 void empty_obj(dbref obj)
00497 {
00498         dbref targ, next;
00499 
00500         /*
00501          * Send the contents home 
00502          */
00503 
00504         SAFE_DOLIST(targ, next, Contents(obj)) {
00505                 if(!Has_location(targ)) {
00506                         Log_simple_err(targ, obj,
00507                                                    "Funny object type in contents list of GOING location. Flush terminated.");
00508                         break;
00509                 } else if(Location(targ) != obj) {
00510                         Log_header_err(targ, obj, Location(targ), 1, "Location",
00511                                                    "indicates object really in another location during cleanup of GOING location.  Flush terminated.");
00512                         break;
00513                 } else {
00514                         ZAP_LOC(targ);
00515                         if(Home(targ) == obj) {
00516                                 s_Home(targ, new_home(targ));
00517                         }
00518                         move_via_generic(targ, HOME, NOTHING, 0);
00519                         divest_object(targ);
00520                 }
00521         }
00522 
00523         /*
00524          * Destroy the exits 
00525          */
00526 
00527         SAFE_DOLIST(targ, next, Exits(obj)) {
00528                 if(!isExit(targ)) {
00529                         Log_simple_err(targ, obj,
00530                                                    "Funny object type in exit list of GOING location. Flush terminated.");
00531                         break;
00532                 } else if(Exits(targ) != obj) {
00533                         Log_header_err(targ, obj, Exits(targ), 1, "Location",
00534                                                    "indicates exit really in another location during cleanup of GOING location.  Flush terminated.");
00535                         break;
00536                 } else {
00537                         destroy_obj(NOTHING, targ);
00538                 }
00539         }
00540 }
00541 
00545 void destroy_exit(dbref exit)
00546 {
00547         dbref loc;
00548 
00549         loc = Exits(exit);
00550         s_Exits(loc, remove_first(Exits(loc), exit));
00551         destroy_obj(NOTHING, exit);
00552 }
00553 
00557 void destroy_thing(dbref thing)
00558 {
00559         move_via_generic(thing, NOTHING, Owner(thing), 0);
00560         empty_obj(thing);
00561         destroy_obj(NOTHING, thing);
00562 }
00563 
00567 void destroy_player(dbref victim)
00568 {
00569         dbref aowner, player;
00570         int count, aflags;
00571         char *buf;
00572 
00573         /*
00574          * Bye bye... 
00575          */
00576         player = (dbref) atoi(atr_get_raw(victim, A_DESTROYER));
00577         toast_player(victim);
00578         boot_off(victim, (char *) "You have been destroyed!");
00579         halt_que(victim, NOTHING);
00580         count = chown_all(victim, player);
00581 
00582         /*
00583          * Remove the name from the name hash table 
00584          */
00585 
00586         delete_player_name(victim, Name(victim));
00587         buf = atr_pget(victim, A_ALIAS, &aowner, &aflags);
00588         delete_player_name(victim, buf);
00589         free_lbuf(buf);
00590 
00591         move_via_generic(victim, NOTHING, player, 0);
00592         do_mail_clear(victim, NULL);
00593         do_mail_purge(victim);
00594         destroy_obj(NOTHING, victim);
00595         notify_quiet(player, tprintf("(%d objects @chowned to you)", count));
00596 }
00597 
00601 static void purge_going(void)
00602 {
00603         dbref i;
00604 
00605         DO_WHOLE_DB(i) {
00606                 if(!Going(i))
00607                         continue;
00608 
00609                 switch (Typeof(i)) {
00610                 case TYPE_PLAYER:
00611                         destroy_player(i);
00612                         break;
00613                 case TYPE_ROOM:
00614 
00615                         /*
00616                          * Room scheduled for destruction... do it 
00617                          */
00618 
00619                         empty_obj(i);
00620                         destroy_obj(NOTHING, i);
00621                         break;
00622                 case TYPE_THING:
00623                         destroy_thing(i);
00624                         break;
00625                 case TYPE_EXIT:
00626                         destroy_exit(i);
00627                         break;
00628                 case TYPE_GARBAGE:
00629                         break;
00630                 default:
00631 
00632                         /*
00633                          * Something else... How did this happen? 
00634                          */
00635 
00636                         Log_simple_err(i, NOTHING,
00637                                                    "GOING object with unexpected type.  Destroyed.");
00638                         destroy_obj(NOTHING, i);
00639                 }
00640         }
00641 }
00642 
00646 static void check_pennies(dbref thing, int limit, const char *qual)
00647 {
00648         int j;
00649 
00650         if(Going(thing))
00651                 return;
00652         j = Pennies(thing);
00653         if(isRoom(thing) || isExit(thing)) {
00654                 if(j) {
00655                         Log_header_err(thing, NOTHING, j, 0, qual, "is strange.  Reset.");
00656                         s_Pennies(j, 0);
00657                 }
00658         } else if(j == 0) {
00659                 Log_header_err(thing, NOTHING, j, 0, qual, "is zero.");
00660         } else if(j < 0) {
00661                 Log_header_err(thing, NOTHING, j, 0, qual, "is negative.");
00662         } else if(j > limit) {
00663                 Log_header_err(thing, NOTHING, j, 0, qual, "is excessive.");
00664         }
00665 }
00666 
00667 static void check_dead_refs(void)
00668 {
00669         dbref targ, owner, i, j;
00670         int aflags, dirty;
00671         char *str;
00672         FWDLIST *fp;
00673 
00674         DO_WHOLE_DB(i) {
00675 
00676                 /*
00677                  * Check the parent 
00678                  */
00679 
00680                 targ = Parent(i);
00681                 if(Good_obj(targ)) {
00682                         if(Going(targ)) {
00683                                 s_Parent(i, NOTHING);
00684                                 owner = Owner(i);
00685 
00686                                 if(Good_owner(owner) && !Quiet(i) && !Quiet(owner)) {
00687                                         notify_printf(owner, "Parent cleared on %s(#%d)",
00688                                                                   Name(i), i);
00689                                 }
00690                         }
00691                 } else if(targ != NOTHING) {
00692                         Log_header_err(i, Location(i), targ, 1, "Parent",
00693                                                    "is invalid.  Cleared.");
00694                         s_Parent(i, NOTHING);
00695                 }
00696                 /*
00697                  * Check the zone 
00698                  */
00699 
00700                 targ = Zone(i);
00701                 if(Good_obj(targ)) {
00702                         if(Going(targ)) {
00703                                 s_Zone(i, NOTHING);
00704                                 owner = Owner(i);
00705                                 if(Good_owner(owner) && !Quiet(i) && !Quiet(owner)) {
00706                                         notify_printf(owner, "Zone cleared on %s(#%d)",
00707                                                                   Name(i), i);
00708                                 }
00709                         }
00710                 } else if(targ != NOTHING) {
00711                         Log_header_err(i, Location(i), targ, 1, "Zone",
00712                                                    "is invalid. Cleared.");
00713                         s_Zone(i, NOTHING);
00714                 }
00715                 switch (Typeof(i)) {
00716                 case TYPE_PLAYER:
00717                 case TYPE_THING:
00718 
00719                         if(Going(i))
00720                                 break;
00721 
00722                         /*
00723                          * Check the home 
00724                          */
00725 
00726                         targ = Home(i);
00727                         if(Good_obj(targ)) {
00728                                 if(Going(targ)) {
00729                                         s_Home(i, new_home(i));
00730                                         owner = Owner(i);
00731                                         if(Good_owner(owner) && !Quiet(i) && !Quiet(owner)) {
00732                                                 notify_printf(owner, "Home reset on %s(#%d)",
00733                                                                           Name(i), i);
00734                                         }
00735                                 }
00736                         } else if(targ != NOTHING) {
00737                                 Log_header_err(i, Location(i), targ, 1, "Home",
00738                                                            "is invalid.  Cleared.");
00739                                 s_Home(i, new_home(i));
00740                         }
00741                         /*
00742                          * Check the location 
00743                          */
00744 
00745                         targ = Location(i);
00746                         if(!Good_obj(targ)) {
00747                                 Log_pointer_err(NOTHING, i, NOTHING, targ, "Location",
00748                                                                 "is invalid.  Moved to home.");
00749                                 ZAP_LOC(i);
00750                                 move_object(i, HOME);
00751                         }
00752                         /*
00753                          * Check for self-referential Next() 
00754                          */
00755 
00756                         if(Next(i) == i) {
00757                                 Log_simple_err(i, NOTHING,
00758                                                            "Next points to self.  Next cleared.");
00759                                 s_Next(i, NOTHING);
00760                         }
00761                         if(check_type & DBCK_FULL) {
00762 
00763                                 /*
00764                                  * Check wealth or value 
00765                                  */
00766 
00767                                 targ = OBJECT_ENDOWMENT(mudconf.createmax);
00768                                 if(OwnsOthers(i)) {
00769                                         targ += mudconf.paylimit;
00770                                         check_pennies(i, targ, "Wealth");
00771                                 } else {
00772                                         check_pennies(i, targ, "Value");
00773                                 }
00774                         }
00775                         break;
00776                 case TYPE_ROOM:
00777 
00778                         /*
00779                          * Check the dropto 
00780                          */
00781 
00782                         targ = Dropto(i);
00783                         if(Good_obj(targ)) {
00784                                 if(Going(targ)) {
00785                                         s_Dropto(i, NOTHING);
00786                                         owner = Owner(i);
00787                                         if(Good_owner(owner) && !Quiet(i) && !Quiet(owner)) {
00788                                                 notify_printf(owner,
00789                                                                           "Dropto removed from %s(#%d)", Name(i),
00790                                                                           i);
00791                                         }
00792                                 }
00793                         } else if((targ != NOTHING) && (targ != HOME)) {
00794                                 Log_header_err(i, NOTHING, targ, 1, "Dropto",
00795                                                            "is invalid.  Cleared.");
00796                                 s_Dropto(i, NOTHING);
00797                         }
00798                         if(check_type & DBCK_FULL) {
00799 
00800                                 /*
00801                                  * NEXT should be null 
00802                                  */
00803 
00804                                 if(Next(i) != NOTHING) {
00805                                         Log_header_err(i, NOTHING, Next(i), 1, "Next pointer",
00806                                                                    "should be NOTHING.  Reset.");
00807                                         s_Next(i, NOTHING);
00808                                 }
00809                                 /*
00810                                  * LINK should be null 
00811                                  */
00812 
00813                                 if(Link(i) != NOTHING) {
00814                                         Log_header_err(i, NOTHING, Link(i), 1, "Link pointer ",
00815                                                                    "should be NOTHING.  Reset.");
00816                                         s_Link(i, NOTHING);
00817                                 }
00818                                 /*
00819                                  * Check value 
00820                                  */
00821 
00822                                 check_pennies(i, 1, "Value");
00823                         }
00824                         break;
00825                 case TYPE_EXIT:
00826 
00827                         /*
00828                          * If it points to something GOING, set it going 
00829                          */
00830 
00831                         targ = Location(i);
00832                         if(Good_obj(targ)) {
00833                                 if(Going(targ)) {
00834                                         s_Going(i);
00835                                 }
00836                         } else if(targ == HOME) {
00837                                 /*
00838                                  * null case, HOME is always valid 
00839                                  */
00840                         } else if(targ != NOTHING) {
00841                                 Log_header_err(i, Exits(i), targ, 1, "Destination",
00842                                                            "is invalid.  Exit destroyed.");
00843                                 s_Going(i);
00844                         } else {
00845                                 if(!Has_contents(targ)) {
00846                                         Log_header_err(i, Exits(i), targ, 1, "Destination",
00847                                                                    "is not a valid type.  Exit destroyed.");
00848                                         s_Going(i);
00849                                 }
00850                         }
00851 
00852                         /*
00853                          * Check for self-referential Next() 
00854                          */
00855 
00856                         if(Next(i) == i) {
00857                                 Log_simple_err(i, NOTHING,
00858                                                            "Next points to self.  Next cleared.");
00859                                 s_Next(i, NOTHING);
00860                         }
00861                         if(check_type & DBCK_FULL) {
00862 
00863                                 /*
00864                                  * CONTENTS should be null 
00865                                  */
00866 
00867                                 if(Contents(i) != NOTHING) {
00868                                         Log_header_err(i, Exits(i), Contents(i), 1, "Contents",
00869                                                                    "should be NOTHING.  Reset.");
00870                                         s_Contents(i, NOTHING);
00871                                 }
00872                                 /*
00873                                  * LINK should be null 
00874                                  */
00875 
00876                                 if(Link(i) != NOTHING) {
00877                                         Log_header_err(i, Exits(i), Link(i), 1, "Link",
00878                                                                    "should be NOTHING.  Reset.");
00879                                         s_Link(i, NOTHING);
00880                                 }
00881                                 /*
00882                                  * Check value 
00883                                  */
00884 
00885                                 check_pennies(i, 1, "Value");
00886                         }
00887                         break;
00888                 case TYPE_GARBAGE:
00889                         break;
00890                 default:
00891 
00892                         /*
00893                          * Funny object type, destroy it 
00894                          */
00895 
00896                         Log_simple_err(i, NOTHING, "Funny object type.  Destroyed.");
00897                         destroy_obj(NOTHING, i);
00898                 }
00899 
00900                 /*
00901                  * Check forwardlist 
00902                  */
00903 
00904                 dirty = 0;
00905                 fp = fwdlist_get(i);
00906                 if(fp) {
00907                         for(j = 0; j < fp->count; j++) {
00908                                 targ = fp->data[j];
00909                                 if(Good_obj(targ) && Going(targ)) {
00910                                         fp->data[j] = NOTHING;
00911                                         dirty = 1;
00912                                 } else if(!Good_obj(targ) && (targ != NOTHING)) {
00913                                         fp->data[j] = NOTHING;
00914                                         dirty = 1;
00915                                 }
00916                         }
00917                 }
00918                 if(dirty) {
00919                         str = alloc_lbuf("purge_going");
00920                         (void) fwdlist_rewrite(fp, str);
00921                         atr_get_info(i, A_FORWARDLIST, &owner, &aflags);
00922                         atr_add(i, A_FORWARDLIST, str, owner, aflags);
00923                         free_lbuf(str);
00924                 }
00925                 /*
00926                  * Check owner 
00927                  */
00928 
00929                 owner = Owner(i);
00930                 if(!Good_obj(owner)) {
00931                         Log_header_err(i, NOTHING, owner, 1, "Owner",
00932                                                    "is invalid.  Set to GOD.");
00933                         owner = GOD;
00934                         s_Owner(i, owner);
00935                         halt_que(NOTHING, i);
00936                         s_Halted(i);
00937                 } else if(check_type & DBCK_FULL) {
00938                         if(Going(owner)) {
00939                                 Log_header_err(i, NOTHING, owner, 1, "Owner",
00940                                                            "is set GOING.  Set to GOD.");
00941                                 s_Owner(i, owner);
00942                                 halt_que(NOTHING, i);
00943                                 s_Halted(i);
00944                         } else if(!OwnsOthers(owner)) {
00945                                 Log_header_err(i, NOTHING, owner, 1, "Owner",
00946                                                            "is not a valid owner type.");
00947                         } else if(isPlayer(i) && (owner != i)) {
00948                                 Log_header_err(i, NOTHING, owner, 1, "Player",
00949                                                            "is the owner instead of the player.");
00950                         }
00951                 }
00952                 if(check_type & DBCK_FULL) {
00953 
00954                         /*
00955                          * Check for wizards 
00956                          */
00957 
00958                         if(Wizard(i)) {
00959                                 if(isPlayer(i)) {
00960                                         Log_simple_err(i, NOTHING, "Player is a WIZARD.");
00961                                 }
00962                                 if(!Wizard(Owner(i))) {
00963                                         Log_header_err(i, NOTHING, Owner(i), 1, "Owner",
00964                                                                    "of a WIZARD object is not a wizard");
00965                                 }
00966                         }
00967                 }
00968         }
00969 }
00970 
00986 static void check_loc_exits(dbref loc)
00987 {
00988         dbref exit, back, temp, exitloc, dest;
00989 
00990         if(!Good_obj(loc))
00991                 return;
00992 
00993         /*
00994          * Only check players, rooms, and things that aren't GOING 
00995          */
00996 
00997         if(isExit(loc) || Going(loc))
00998                 return;
00999 
01000         /*
01001          * If marked, we've checked here already 
01002          */
01003 
01004         if(Marked(loc))
01005                 return;
01006         Mark(loc);
01007 
01008         /*
01009          * Check all the exits 
01010          */
01011 
01012         back = NOTHING;
01013         exit = Exits(loc);
01014         while (exit != NOTHING) {
01015 
01016                 exitloc = NOTHING;
01017                 dest = NOTHING;
01018 
01019                 if(Good_obj(exit)) {
01020                         exitloc = Exits(exit);
01021                         dest = Location(exit);
01022                 }
01023                 if(!Good_obj(exit)) {
01024 
01025                         /*
01026                          * A bad pointer - terminate chain 
01027                          */
01028 
01029                         Log_pointer_err(back, loc, NOTHING, exit, "Exit list",
01030                                                         "is invalid.  List nulled.");
01031                         if(back != NOTHING) {
01032                                 s_Next(back, NOTHING);
01033                         } else {
01034                                 s_Exits(loc, NOTHING);
01035                         }
01036                         exit = NOTHING;
01037                 } else if(!isExit(exit)) {
01038 
01039                         /*
01040                          * Not an exit - terminate chain 
01041                          */
01042 
01043                         Log_pointer_err(back, loc, NOTHING, exit, "Exitlist member",
01044                                                         "is not an exit.  List terminated.");
01045                         if(back != NOTHING) {
01046                                 s_Next(back, NOTHING);
01047                         } else {
01048                                 s_Exits(loc, NOTHING);
01049                         }
01050                         exit = NOTHING;
01051                 } else if(Going(exit)) {
01052 
01053                         /*
01054                          * Going - silently filter out 
01055                          */
01056 
01057                         temp = Next(exit);
01058                         if(back != NOTHING) {
01059                                 s_Next(back, temp);
01060                         } else {
01061                                 s_Exits(loc, temp);
01062                         }
01063                         destroy_obj(NOTHING, exit);
01064                         exit = temp;
01065                         continue;
01066                 } else if(Marked(exit)) {
01067 
01068                         /*
01069                          * Already in another list - terminate chain 
01070                          */
01071 
01072                         Log_pointer_err(back, loc, NOTHING, exit, "Exitlist member",
01073                                                         "is in another exitlist.  Cleared.");
01074                         if(back != NOTHING) {
01075                                 s_Next(back, NOTHING);
01076                         } else {
01077                                 s_Exits(loc, NOTHING);
01078                         }
01079                         exit = NOTHING;
01080                 } else if(!Good_obj(dest) && (dest != HOME) && (dest != NOTHING)) {
01081 
01082                         /*
01083                          * Destination is not in the db.  Null it. 
01084                          */
01085 
01086                         Log_pointer_err(back, loc, NOTHING, exit, "Destination",
01087                                                         "is invalid.  Cleared.");
01088                         s_Location(exit, NOTHING);
01089 
01090                 } else if(exitloc != loc) {
01091 
01092                         /*
01093                          * Exit thinks it's in another place. Check the
01094                          * exitlist there and see if it contains this
01095                          * exit. If it does, then our exitlist
01096                          * somehow pointed into the middle of their
01097                          * exitlist. If not, assume we own the exit. 
01098                          */
01099 
01100                         check_loc_exits(exitloc);
01101                         if(Marked(exit)) {
01102 
01103                                 /*
01104                                  * It's in the other list, give it up 
01105                                  */
01106 
01107                                 Log_pointer_err(back, loc, NOTHING, exit, "",
01108                                                                 "is in another exitlist.  List terminated.");
01109                                 if(back != NOTHING) {
01110                                         s_Next(back, NOTHING);
01111                                 } else {
01112                                         s_Exits(loc, NOTHING);
01113                                 }
01114                                 exit = NOTHING;
01115                         } else {
01116 
01117                                 /*
01118                                  * Not in the other list, assume in ours 
01119                                  */
01120 
01121                                 Log_header_err(exit, loc, exitloc, 1,
01122                                                            "Not on chain for location", "Reset.");
01123                                 s_Exits(exit, loc);
01124                         }
01125                 }
01126                 if(exit != NOTHING) {
01127 
01128                         /*
01129                          * All OK (or all was made OK) 
01130                          */
01131 
01132                         if(check_type & DBCK_FULL) {
01133 
01134                                 /*
01135                                  * Make sure exit owner owns at least one of
01136                                  * * * * * the source or destination.  Just * 
01137                                  * warn * if * * he doesn't. 
01138                                  */
01139 
01140                                 temp = Owner(exit);
01141                                 if((temp != Owner(loc)) && (temp != Owner(Location(exit)))) {
01142                                         Log_header_err(exit, loc, temp, 1, "Owner",
01143                                                                    "does not own either the source or destination.");
01144                                 }
01145                         }
01146                         Mark(exit);
01147                         back = exit;
01148                         exit = Next(exit);
01149                 }
01150         }
01151         return;
01152 }
01153 
01154 static void check_exit_chains(void)
01155 {
01156         dbref i;
01157 
01158         Unmark_all(i);
01159         DO_WHOLE_DB(i)
01160                 check_loc_exits(i);
01161         DO_WHOLE_DB(i) {
01162                 if(isExit(i) && !Marked(i)) {
01163                         Log_simple_err(i, NOTHING, "Disconnected exit.  Destroyed.");
01164                         destroy_obj(NOTHING, i);
01165                 }
01166         }
01167 }
01168 
01185 static void check_loc_contents(dbref);
01186 
01187 static void check_misplaced_obj(dbref * obj, dbref back, dbref loc)
01188 {
01189         /*
01190          * Object thinks it's in another place. Check the contents list
01191          * there and see if it contains this object. If it does, then
01192          * our contents list somehow pointed into the middle of their 
01193          * contents list and we should truncate our list. If not,
01194          * assume we own the object. 
01195          */
01196 
01197         if(!Good_obj(*obj))
01198                 return;
01199         loc = Location(*obj);
01200         Unmark(*obj);
01201         if(Good_obj(loc)) {
01202                 check_loc_contents(loc);
01203         }
01204         if(Marked(*obj)) {
01205 
01206                 /*
01207                  * It's in the other list, give it up 
01208                  */
01209 
01210                 Log_pointer_err(back, loc, NOTHING, *obj, "",
01211                                                 "is in another contents list.  Cleared.");
01212                 if(back != NOTHING) {
01213                         s_Next(back, NOTHING);
01214                 } else {
01215                         s_Contents(loc, NOTHING);
01216                 }
01217                 *obj = NOTHING;
01218         } else {
01219                 /*
01220                  * Not in the other list, assume in ours 
01221                  */
01222 
01223                 Log_header_err(*obj, loc, Contents(*obj), 1, "Location",
01224                                            "is invalid.  Reset.");
01225                 s_Contents(*obj, loc);
01226         }
01227         return;
01228 }
01229 
01230 static void check_loc_contents(dbref loc)
01231 {
01232         dbref obj, back, temp;
01233 
01234         if(!Good_obj(loc))
01235                 return;
01236 
01237         /*
01238          * Only check players, rooms, and things that aren't GOING 
01239          */
01240 
01241         if(isExit(loc) || Going(loc))
01242                 return;
01243 
01244         /*
01245          * Check all the exits 
01246          */
01247 
01248         back = NOTHING;
01249         obj = Contents(loc);
01250         while (obj != NOTHING) {
01251                 if(!Good_obj(obj)) {
01252 
01253                         /*
01254                          * A bad pointer - terminate chain 
01255                          */
01256 
01257                         Log_pointer_err(back, loc, NOTHING, obj, "Contents list",
01258                                                         "is invalid.  Cleared.");
01259                         if(back != NOTHING) {
01260                                 s_Next(back, NOTHING);
01261                         } else {
01262                                 s_Contents(loc, NOTHING);
01263                         }
01264                         obj = NOTHING;
01265                 } else if(!Has_location(obj)) {
01266 
01267                         /*
01268                          * Not a player or thing - terminate chain 
01269                          */
01270 
01271                         Log_pointer_err(back, loc, NOTHING, obj, "",
01272                                                         "is not a player or thing.  Cleared.");
01273                         if(back != NOTHING) {
01274                                 s_Next(back, NOTHING);
01275                         } else {
01276                                 s_Contents(loc, NOTHING);
01277                         }
01278                         obj = NOTHING;
01279                 } else if(Going(obj) && (Typeof(obj) == TYPE_GARBAGE)) {
01280 
01281                         /*
01282                          * Going - silently filter out 
01283                          */
01284 
01285                         temp = Next(obj);
01286                         if(back != NOTHING) {
01287                                 s_Next(back, temp);
01288                         } else {
01289                                 s_Contents(loc, temp);
01290                         }
01291                         destroy_obj(NOTHING, obj);
01292                         obj = temp;
01293                         continue;
01294                 } else if(Marked(obj)) {
01295 
01296                         /*
01297                          * Already visited - either truncate or ignore 
01298                          */
01299 
01300                         if(Location(obj) != loc) {
01301 
01302                                 /*
01303                                  * Location wrong - either truncate or fix 
01304                                  */
01305 
01306                                 check_misplaced_obj(&obj, back, loc);
01307                         } else {
01308 
01309                                 /*
01310                                  * Location right - recursive contents 
01311                                  */
01312                         }
01313                 } else if(Location(obj) != loc) {
01314 
01315                         /*
01316                          * Location wrong - either truncate or fix 
01317                          */
01318 
01319                         check_misplaced_obj(&obj, back, loc);
01320                 }
01321                 if(obj != NOTHING) {
01322 
01323                         /*
01324                          * All OK (or all was made OK) 
01325                          */
01326 
01327                         if(check_type & DBCK_FULL) {
01328 
01329                                 /*
01330                                  * Check for wizard command-handlers inside * 
01331                                  * 
01332                                  * *  * *  * * nonwiz. Just warn if we find
01333                                  * one. 
01334                                  */
01335 
01336                                 if(Wizard(obj) && !Wizard(loc)) {
01337                                         if(Commer(obj)) {
01338                                                 Log_simple_err(obj, loc,
01339                                                                            "Wizard command handling object inside nonwizard.");
01340                                         }
01341                                 }
01342                                 /*
01343                                  * Check for nonwizard objects inside wizard
01344                                  * * * * * objects. 
01345                                  */
01346 
01347                                 if(Wizard(loc) && !Wizard(obj) && !Wizard(Owner(obj))) {
01348                                         Log_simple_err(obj, loc,
01349                                                                    "Nonwizard object inside wizard.");
01350                                 }
01351                         }
01352                         Mark(obj);
01353                         back = obj;
01354                         obj = Next(obj);
01355                 }
01356         }
01357         return;
01358 }
01359 
01360 static void check_contents_chains(void)
01361 {
01362         dbref i;
01363 
01364         Unmark_all(i);
01365         DO_WHOLE_DB(i)
01366                 check_loc_contents(i);
01367         DO_WHOLE_DB(i)
01368                 if(!Going(i) && !Marked(i) && Has_location(i)) {
01369                 Log_simple_err(i, Location(i), "Orphaned object, moved home.");
01370                 ZAP_LOC(i);
01371                 move_via_generic(i, HOME, NOTHING, 0);
01372         }
01373 }
01374 
01378 static void mark_place(dbref loc)
01379 {
01380         dbref exit;
01381 
01382         /*
01383          * If already marked, exit.  Otherwise set marked. 
01384          */
01385 
01386         if(!Good_obj(loc))
01387                 return;
01388         if(Marked(loc))
01389                 return;
01390         Mark(loc);
01391 
01392         /*
01393          * Visit all places you can get to via exits from here. 
01394          */
01395 
01396         for(exit = Exits(loc); exit != NOTHING; exit = Next(exit)) {
01397                 if(Good_obj(Location(exit)))
01398                         mark_place(Location(exit));
01399         }
01400 }
01401 
01402 static void check_floating(void)
01403 {
01404         dbref owner, i;
01405 
01406         /*
01407          * Mark everyplace you can get to via exits from the starting room 
01408          */
01409 
01410         Unmark_all(i);
01411         mark_place(mudconf.start_room);
01412 
01413         /*
01414          * Look for rooms not marked and not set FLOATING 
01415          */
01416 
01417         DO_WHOLE_DB(i) {
01418                 if(isRoom(i) && !Floating(i) && !Going(i) && !Marked(i)) {
01419                         owner = Owner(i);
01420                         if(Good_owner(owner)) {
01421                                 notify_printf(owner, "You own a floating room: %s(#%d)",
01422                                                           Name(i), i);
01423                         }
01424                 }
01425         }
01426 }
01427 
01431 void do_dbck(dbref player, dbref cause, int key)
01432 {
01433         check_type = key;
01434         make_freelist();
01435         check_dead_refs();
01436         check_exit_chains();
01437         check_contents_chains();
01438         check_floating();
01439         purge_going();
01440 
01441         if(player != NOTHING) {
01442                 if(!Quiet(player))
01443                         notify(player, "Done.");
01444         }
01445 }

Generated on Mon May 28 04:25:25 2007 for BattletechMUX by  doxygen 1.4.7