00001
00002
00003
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
00027
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
00099
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
00179
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
00315
00316 if ((player != NOTHING) && !canpayfees(player, player, cost, quota))
00317 {
00318 return NOTHING;
00319 }
00320
00321
00322
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);
00345
00346
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
00401
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
00445
00446 dbref owner = Owner(obj);
00447 bool good_owner = Good_owner(owner);
00448
00449
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
00463
00464 fwdlist_clr(obj);
00465 stack_clr(obj);
00466 }
00467
00468
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
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
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
00600
00601
00602 void empty_obj(dbref obj)
00603 {
00604 dbref targ, next;
00605
00606
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
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
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
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
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
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
00759
00760 Log_simple_err(i, NOTHING,
00761 "GOING object with unexpected type. Destroyed.");
00762 destroy_obj(i);
00763 }
00764 }
00765 }
00766
00767
00768
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
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
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
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
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
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
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
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
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
01026
01027 targ = mudconf.paylimit;
01028 check_pennies(i, targ, "Wealth");
01029 }
01030 break;
01031
01032 case TYPE_THING:
01033
01034
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
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
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
01079
01080 targ = OBJECT_ENDOWMENT(mudconf.createmax);
01081 check_pennies(i, targ, "Value");
01082 }
01083 break;
01084
01085 case TYPE_ROOM:
01086
01087
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
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
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
01139
01140 check_pennies(i, 1, "Value");
01141 }
01142 break;
01143
01144 case TYPE_EXIT:
01145
01146
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
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
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
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
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
01206
01207 check_pennies(i, 1, "Value");
01208 }
01209 break;
01210
01211 case TYPE_GARBAGE:
01212 break;
01213
01214 default:
01215
01216
01217
01218 Log_simple_err(i, NOTHING, "Funny object type. Destroyed.");
01219 destroy_obj(i);
01220 }
01221 }
01222 }
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241 static void check_loc_exits(dbref loc)
01242 {
01243 if (!Good_obj(loc))
01244 {
01245 return;
01246 }
01247
01248
01249
01250 if ( isExit(loc)
01251 || Going(loc))
01252 {
01253 return;
01254 }
01255
01256
01257
01258 if (Marked(loc))
01259 {
01260 return;
01261 }
01262 Mark(loc);
01263
01264
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
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
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
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
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
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
01357
01358
01359
01360
01361 check_loc_exits(exitloc);
01362 if (Marked(exit))
01363 {
01364
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
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
01390
01391 if (check_type & DBCK_FULL)
01392 {
01393
01394
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
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449 static void check_loc_contents(dbref);
01450
01451 static void check_misplaced_obj(dbref *obj, dbref back, dbref loc)
01452 {
01453
01454
01455
01456
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
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
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
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
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
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
01549
01550 if (Location(obj) != loc)
01551 {
01552
01553
01554 check_misplaced_obj(&obj, back, loc);
01555 }
01556 else
01557 {
01558
01559
01560 }
01561 }
01562 else if (Location(obj) != loc)
01563 {
01564
01565
01566 check_misplaced_obj(&obj, back, loc);
01567 }
01568 if (obj != NOTHING)
01569 {
01570
01571
01572 if (check_type & DBCK_FULL)
01573 {
01574
01575
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
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
01633
01634
01635 static void mark_place(dbref loc)
01636 {
01637 dbref exit;
01638
01639
01640
01641 if (!Good_obj(loc))
01642 {
01643 return;
01644 }
01645 if (Marked(loc))
01646 {
01647 return;
01648 }
01649 Mark(loc);
01650
01651
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
01667
01668 Unmark_all(i);
01669 mark_place(mudconf.start_room);
01670
01671
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
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
01721
01722 local_dbck();
01723
01724 if ( !mudstate.bStandAlone
01725 && executor != NOTHING
01726 && !Quiet(executor))
01727 {
01728 notify(executor, "Done.");
01729 }
01730 }