#include <stdio.h> #include <stdlib.h> #include "db.h" #include "externs.h" #include "net.h" #include "config.h" OBJ *root_obj = NULL; OBJ *player_start_obj = NULL; static void ref_descriptors() { DDATA *d, *dnext; for(d = descriptor_list;d;d = dnext) { dnext = d->next; if(!(d->player = find_object(d->player_ref))) { log_error(tprintf("Player %d (descriptor %d) was not found.", d->player_ref, d->descriptor)); log_error(tprintf("Shutting down socket %d.", d->descriptor)); shutdownsock(d); } } } static void ref_location(OBJ *o) { if(!(o->location = find_object(o->loadinfo->location))) { log_error(tprintf("Bad dbref %d on object %d for location.", o->loadinfo->location, o->dbref)); log_error(tprintf("Setting location for %d to %d", o->dbref, config.player_start)); o->location = player_start_obj; } } static void ref_contents(OBJ *o) { OBJ *p; int *i; for(i = o->loadinfo->contents;*i != -1;++i) { if(!(p = find_object(*i))) { log_error(tprintf("Bad object %d in children list for %d.", *i, o->dbref)); continue; } p->next_con = o->contents; o->contents = p; } stack_free(o->loadinfo->contents); } static void ref_exits(OBJ *o) { OBJ *p; int *i; for(i = o->loadinfo->exits;*i != -1;++i) { if(!(p = find_object(*i))) { log_error(tprintf("Bad object %d in exit list for %d.", *i, o->dbref)); continue; } p->next_exit = o->exits; o->exits = p; } stack_free(o->loadinfo->exits); } static void ref_link(OBJ *o) { if(o->loadinfo->link != -1) { if(!(o->link = find_object(o->loadinfo->link))) { log_error(tprintf("Bad object %d on object %d for link.", o->loadinfo->link, o->dbref)); log_error(tprintf("Setting link for %d to %d.", o->dbref, config.player_start)); o->link = player_start_obj; } } } static void ref_owner(OBJ *o) { if(!(o->owner = find_object(o->loadinfo->owner))) { log_error(tprintf("Bad object %d on object %d for owner.", o->loadinfo->owner, o->dbref)); log_error(tprintf("Setting owner for %d to %d.", o->dbref, config.root)); o->link = root_obj; } } static void ref_creator(OBJ *o) { if(!(o->creator = find_object(o->loadinfo->creator))) { log_error(tprintf("Bad object %d on object %d for creator.", o->loadinfo->creator, o->dbref)); log_error(tprintf("Setting creator for %d to %d.", o->dbref, config.root)); o->creator = root_obj; } } static void init_dblist(void) { OBJ *o; db_list = (OBJ **)stack_alloc(sizeof(OBJ *)*db_top, 1, 1); for(o = player_list;o;o = o->next) db_list[o->dbref] = o; for(o = room_list;o;o = o->next) db_list[o->dbref] = o; for(o = thing_list;o;o = o->next) db_list[o->dbref] = o; for(o = exit_list;o;o = o->next) db_list[o->dbref] = o; } void reference_db() { OBJ *o; /* Unallocate the stack to make this process MUCH faster */ stack_unalloc(); init_dblist(); /* Check important objects */ if(!(root_obj = find_object(config.root))) { log_error(tprintf("Couldn't find object %d (root). Check config.c", config.root)); exit_nicely(1); } if(!(player_start_obj = find_object(config.player_start))) { log_error(tprintf("Couldn't find object %d (player_start). Check config.c", config.player_start)); exit_nicely(1); } ref_descriptors(); for(o = player_list;o;o = o->next) { ref_location(o); ref_contents(o); ref_link(o); o->owner = o; /* Players always own themselves */ ref_creator(o); stack_free(o->loadinfo); o->loadinfo = NULL; } for(o = thing_list;o;o = o->next) { ref_location(o); ref_contents(o); ref_link(o); ref_owner(o); ref_creator(o); stack_free(o->loadinfo); o->loadinfo = NULL; } for(o = room_list;o;o = o->next) { o->location = o; /* Room's location is always itself */ ref_contents(o); ref_exits(o); o->link = o; /* Room is always linked to itself */ ref_owner(o); ref_creator(o); stack_free(o->loadinfo); o->loadinfo = NULL; } for(o = exit_list;o;o = o->next) { ref_location(o); ref_link(o); ref_owner(o); ref_creator(o); stack_free(o->loadinfo); o->loadinfo = NULL; } } void add_content(OBJ *thing, OBJ *room) { thing->next_con = room->contents; room->contents = thing; if(!IS(thing, TYPE_PLAYER, PLAYER_INVISIBLE)) notify_in(room, thing, tprintf("%s has arrived.", name(thing))); } void add_exit(OBJ *exit, OBJ *room) { exit->next_exit = room->exits; room->exits = exit; } void remove_content(OBJ *thing, OBJ *room) { OBJ *o, *oprev = NULL; for(o = room->contents;o;o = o->next_con) { if(o == thing) break; oprev = o; } if(!o) return; if(oprev) oprev->next_con = o->next_con; else room->contents = o->next_con; if(!IS(thing, TYPE_PLAYER, PLAYER_INVISIBLE)) notify_in(room, NULL, tprintf("%s has left.", name(thing))); } void remove_exit(OBJ *exit, OBJ *room) { OBJ *o, *oprev = NULL; for(o = room->exits;o;o = o->next_exit) { if(o == exit) break; oprev = o; } if(!o) return; if(oprev) oprev->next_exit = o->next_exit; else room->exits = o->next_exit; } void remove_refs(OBJ *thing) { OBJ *o; switch(Typeof(thing)) { case TYPE_PLAYER: case TYPE_THING: remove_content(thing, thing->location); break; case TYPE_EXIT: remove_exit(thing, thing->location); break; case TYPE_ROOM: for(o = player_list;o;o = o->next) if(o->link == thing) { log_important(tprintf("%s destroyed. Linking %s to #%d (player_start).", unparse_object(thing, thing), unparse_object(o, o), config.player_start)); o->link = player_start_obj; } for(o = thing_list;o;o = o->next) if(o->link == thing) { log_important(tprintf("%s destroyed. Linking %s to #%d (owner)", unparse_object(thing, thing), unparse_object(o, o), o->owner->dbref)); o->link = o->owner; } for(o = exit_list;o;o = o->next) if(o->link == thing) { log_important(tprintf("%s destroyed. Unlinking %s.", unparse_object(thing, thing), unparse_object(o, o))); o->link = NULL; } /* Teleport room contents home. Destroy an exits in the room. */ for(o = player_list;o;o = o->next) if(o->location == thing) { notify(o, "The room you're in was just destroyed. Bye."); safe_tel(o, o->link); } for(o = thing_list;o;o = o->next) if(o->location == thing) safe_tel(o, o->link); for(o = exit_list;o;o = o->next) if(o->location == thing) destroy_obj(o); break; } }