TinyMAZE/
TinyMAZE/config/
TinyMAZE/doc/
TinyMAZE/run/msgs/
TinyMAZE/src/
TinyMAZE/src/db/
TinyMAZE/src/ident/
TinyMAZE/src/io/
TinyMAZE/src/prog/
TinyMAZE/src/softcode/
TinyMAZE/src/util/
#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;
  }
}