00001
00002
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
00284
00285
00286 if((player != NOTHING) && !canpayfees(player, player, cost, quota))
00287 return NOTHING;
00288
00289
00290
00291
00292
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);
00312
00313
00314
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
00376
00377
00378 owner = Owner(obj);
00379 good_owner = Good_owner(owner);
00380
00381
00382
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
00820
00821
00822 check_pennies(i, 1, "Value");
00823 }
00824 break;
00825 case TYPE_EXIT:
00826
00827
00828
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
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
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
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
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
00883
00884
00885 check_pennies(i, 1, "Value");
00886 }
00887 break;
00888 case TYPE_GARBAGE:
00889 break;
00890 default:
00891
00892
00893
00894
00895
00896 Log_simple_err(i, NOTHING, "Funny object type. Destroyed.");
00897 destroy_obj(NOTHING, i);
00898 }
00899
00900
00901
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
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
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
00995
00996
00997 if(isExit(loc) || Going(loc))
00998 return;
00999
01000
01001
01002
01003
01004 if(Marked(loc))
01005 return;
01006 Mark(loc);
01007
01008
01009
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
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
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
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
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
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
01094
01095
01096
01097
01098
01099
01100 check_loc_exits(exitloc);
01101 if(Marked(exit)) {
01102
01103
01104
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
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
01130
01131
01132 if(check_type & DBCK_FULL) {
01133
01134
01135
01136
01137
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
01191
01192
01193
01194
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
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
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
01239
01240
01241 if(isExit(loc) || Going(loc))
01242 return;
01243
01244
01245
01246
01247
01248 back = NOTHING;
01249 obj = Contents(loc);
01250 while (obj != NOTHING) {
01251 if(!Good_obj(obj)) {
01252
01253
01254
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
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
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
01298
01299
01300 if(Location(obj) != loc) {
01301
01302
01303
01304
01305
01306 check_misplaced_obj(&obj, back, loc);
01307 } else {
01308
01309
01310
01311
01312 }
01313 } else if(Location(obj) != loc) {
01314
01315
01316
01317
01318
01319 check_misplaced_obj(&obj, back, loc);
01320 }
01321 if(obj != NOTHING) {
01322
01323
01324
01325
01326
01327 if(check_type & DBCK_FULL) {
01328
01329
01330
01331
01332
01333
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
01344
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
01384
01385
01386 if(!Good_obj(loc))
01387 return;
01388 if(Marked(loc))
01389 return;
01390 Mark(loc);
01391
01392
01393
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
01408
01409
01410 Unmark_all(i);
01411 mark_place(mudconf.start_room);
01412
01413
01414
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 }