/
2.0.4beta/doc/
2.0.4beta/gnu/
2.0.4beta/sha/
/* recycle.c */

#include "config.h"

/*
 *		       This file is part of TeenyMUD II.
 *		 Copyright(C) 1993, 1994, 1995 by Jason Downs.
 *                           All rights reserved.
 * 
 * TeenyMUD II is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * TeenyMUD II is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see the file 'COPYING'); if not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 *
 */

#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif			/* HAVE_UNISTD_H */

#include "conf.h"
#include "teeny.h"
#include "commands.h"
#include "externs.h"

#ifndef F_OK
#define F_OK	0
#endif

/* object recycling system */

static int recycle_clean _ANSI_ARGS_((int, int, int, int *));

VOID do_recycle(player, cause, switches, argone)
    int player, cause, switches;
    char *argone;
{
  int obj, ret;
  char buff[BUFFSIZ];

  if((argone == (char *)NULL) || (argone[0] == '\0')) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "Recycle what?", NOT_QUIET);
    return;
  }

  obj = resolve_object(player, cause, argone,
  		       (!(switches & CMD_QUIET) ? RSLV_EXITS|RSLV_NOISY
		       				: RSLV_EXITS));
  if(obj == -1)
    return;

  if(!isDESTROY_OK(obj)) {
    if(!(switches & RECYCLE_OVERRIDE)) {
      int plown, objown;
      char fbuf[152];

      if((get_int_elt(player, OWNER, &plown) == -1)
         || (get_int_elt(obj, OWNER, &objown) == -1)) {
        notify_bad(player);
        return;
      }
      if(objown != plown) {
        if(!(switches & CMD_QUIET))
          notify_player(player, cause, player, "You can't recycle that!",
	  		NOT_QUIET);
        return;
      }

      /* Very rudimentary protection. */
      snprintf(fbuf, sizeof(fbuf), "%s#%d", mudconf.files_path, obj);
      if(access(fbuf, F_OK) == 0) {
        if(!(switches & CMD_QUIET))
          notify_player(player, cause, player, "You can't recycle that!",
	  		NOT_QUIET);
	return;
      }
    } else {
      if(isEXIT(obj)) {
        int loc;

        if(get_int_elt(obj, LOC, &loc) == -1) {
	  notify_bad(player);
	  return;
        }
        if(!controls(player, cause, obj)
	   && !controls(player, cause, loc)) {
	  if(!(switches & CMD_QUIET))
	    notify_player(player, cause, player, "You can't recycle that!",
	    		  NOT_QUIET);
	  return;
        }
      } else {
        if(!controls(player, cause, obj)) {
	  if(!(switches & CMD_QUIET))
            notify_player(player, cause, player, "You can't recycle that!",
	    		  NOT_QUIET);
          return;
        }
      }
    }
  }

  if((obj == mudconf.starting_loc) || (obj == mudconf.root_location)) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "You may not recycle that.",
      		    NOT_QUIET);
    return;
  }
  if(isPLAYER(obj)) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "You may not recycle players.",
      		    NOT_QUIET);
    return;
  }

  ret = recycle_obj(player, cause, obj);
  switch(ret) {
  case -1:
    notify_bad(player);
    break;
  case 0:
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "Nothing to recycle?!", NOT_QUIET);
    break;
  case 1:
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "Thank you for recycling.",
      		    NOT_QUIET);
    break;
  default:
    if(!(switches & CMD_QUIET)) {
      snprintf(buff, sizeof(buff), "Thank you for recycling %d objects.", ret);
      notify_player(player, cause, player, buff, NOT_QUIET);
    }
  }
}

int recycle_owned(player, cause, object)
    int player, cause, object;
{
  register int index, ret;
  int owner, total = 0;

  for(index = 0; index < mudstat.total_objects; index++) {
    if(!exists_object(index) || (index == object))
      continue;
    if(get_int_elt(index, OWNER, &owner) == -1) {
      logfile(LOG_ERROR, "recycle_owned: bad owner reference on object #%d\n",
	      index);
      return(-1);
    }
    if(owner == object) {
      ret = recycle_obj(player, cause, index);
      if(ret == -1)
	return(-1);
      total += ret;
    }
  }
  return(total);
}

int recycle_obj(player, cause, object)
    int player, cause, object;
{
  int loc, owner;
  int total = 0;

  /* some sanity checking. */
  if(!exists_object(object)
     || (get_int_elt(object, LOC, &loc) == -1)
     || (get_int_elt(object, OWNER, &owner) == -1)) {
    logfile(LOG_ERROR, "recycle_obj: bad reference to object #%d\n", object);
    return(-1);
  }

  switch(Typeof(object)) {
  case TYP_PLAYER:
    notify_player(object, cause, object,
		  "You feel the universe collapsing around you...", 0);
    if(isALIVE(object))
      tcp_logoff(object);
    ptable_delete(object);
  case TYP_THING:
    move_player_leave(object, cause, loc, 0, "You've been recycled!");

    if(recycle_clean(player, cause, object, &total) == -1)
      return(-1);

    if(isTHING(object))
      reward_money(owner, mudconf.thing_cost);

    destroy_obj(object);
    total++;
    break;
  case TYP_EXIT:
    list_drop(object, loc, EXITS);

    reward_money(owner, mudconf.exit_cost);

    destroy_obj(object);
    total++;
    break;
  case TYP_ROOM:
    notify_contents(object, cause, object,
		    "The room shakes and begins to crumble...", 0);

    list_drop(object, loc, ROOMS);

    if(recycle_clean(player, cause, object, &total) == -1)
      return(-1);

    reward_money(owner, mudconf.room_cost);

    destroy_obj(object);
    total++;
  }

  return(total);
}

static int recycle_clean(player, cause, object, total)
    int player, cause, object, *total;
{
  register int index;
  int home, *dests, parent, list, next;
  static char err[] =
	"recycle_clean: bad element reference on object #%d\n";

  /* fix references to recycled objects */
  for(index = 0; index < mudstat.total_objects; index++) {
    if(!exists_object(index))
      continue;

    if(!isEXIT(index)) {
      if(get_int_elt(index, HOME, &home) == -1) {
	logfile(LOG_ERROR, err, index); 
        return(-1);
      }
    }

    switch(Typeof(index)) {
    case TYP_PLAYER:
      if(home == object) {
	if(set_int_elt(index, HOME, mudconf.starting_loc) == -1) {
	  logfile(LOG_ERROR, err, index);
	  return(-1);
	}
      }
      break;
    case TYP_THING:
      if(home == object) {
	int owner, ownhome;

	if(get_int_elt(index, OWNER, &owner) == -1) {
	  logfile(LOG_ERROR, err, index);
	  return(-1);
	}
	if(get_int_elt(owner, HOME, &ownhome) == -1) {
	  logfile(LOG_ERROR, err, owner);
	  return(-1);
	}

	if(ownhome != object) {
	  if(set_int_elt(index, HOME, ownhome) == -1) {
	    logfile(LOG_ERROR, err, index);
	    return(-1);
	  }
	} else {
	  if(set_int_elt(index, HOME, mudconf.starting_loc) == -1) {
	    logfile(LOG_ERROR, err, index);
	    return(-1);
	  }
	}
      }
      break;
    case TYP_ROOM:
      /* really drop-to */
      if(home == object) {
	if(set_int_elt(index, DROPTO, -1) == -1) {
	  logfile(LOG_ERROR, err, index);
	  return(-1);
	}
      }
      break;
    case TYP_EXIT:
      if(get_array_elt(index, DESTS, &dests) == -1) {
	logfile(LOG_ERROR, err, index);
	return(-1);
      }

      if(dests != (int *)NULL) {
	register int d, t, change = 0;
	int new[MAXLINKS + 1];

	for(d = 1; d <= dests[0]; d++) {
	  if(dests[d] == object)
	    change++;
	}
	if(change) {
	  t = 0;

	  for(d = 1; d <= dests[0]; d++) {
	    if(dests[d] != object)
	      new[++t] = dests[d];
	  }
	  if(t) {
	    new[0] = t;
	    if(set_array_elt(index, DESTS, new) == -1) {
	      logfile(LOG_ERROR, err, index);
	      return(-1);
	    }
	  } else {
	    if(set_array_elt(index, DESTS, (int *)NULL) == -1) {
	      logfile(LOG_ERROR, err, index);
	      return(-1);
	    }
	  }
	}
      }
      break;
    }

    if(get_int_elt(index, PARENT, &parent) == -1) {
      logfile(LOG_ERROR, err, index);
      return(-1);
    }
    if(parent == object) {
      if(set_int_elt(index, PARENT, -1) == -1) {
	logfile(LOG_ERROR, err, index);
	return(-1);
      }
    }
  }

  /* clean out lists and such */
  if(get_int_elt(object, CONTENTS, &list) == -1) {
    logfile(LOG_ERROR, err, object);
    return(-1);
  }

  while(list != -1) {
    if(get_int_elt(list, NEXT, &next) == -1) {
      logfile(LOG_ERROR, err, list);
      return(-1);
    }
    notify_player(list, cause, list, "You feel a wrenching sensation...", 0);
    send_home(list, cause, object);

    list = next;
  }

  if(get_int_elt(object, EXITS, &list) == -1) {
    logfile(LOG_ERROR, err, object);
    return(-1);
  }

  while(list != -1) {
    if(get_int_elt(list, NEXT, &next) == -1) {
      logfile(LOG_ERROR, err, list);
      return(-1);
    }
    (*total) += recycle_obj(player, cause, list);
    list = next;
  }

  if(isROOM(object)) {
    if(get_int_elt(object, ROOMS, &list) == -1) {
      logfile(LOG_ERROR, err, object);
      return(-1);
    }

    while(list != -1) {
      if(get_int_elt(list, NEXT, &next) == -1) {
	logfile(LOG_ERROR, err, list);
	return(-1);
      }
      list_add(list, mudconf.root_location, ROOMS);
      if(set_int_elt(list, LOC, mudconf.root_location) == -1) {
	logfile(LOG_ERROR, err, list);
	return(-1);
      }
      list = next;
    }
  }
  return(0);
}