musicmud-2.1.6/data/
musicmud-2.1.6/data/help/
musicmud-2.1.6/data/policy/
musicmud-2.1.6/data/wild/
musicmud-2.1.6/data/world/
musicmud-2.1.6/doc/
musicmud-2.1.6/src/ident/
musicmud-2.1.6/src/lua/
musicmud-2.1.6/src/lua/include/
musicmud-2.1.6/src/lua/src/lib/
musicmud-2.1.6/src/lua/src/lua/
musicmud-2.1.6/src/lua/src/luac/
/*
 * MusicMUD Daemon, version 1.0
 * Copyright (C) 1998-2003 Abigail Brady
 * 
 * This program 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.
 * 
 * This program 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; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <ctype.h>

#include "Mission.h"
#include "musicmud.h"
#include "util.h"
#include "pflags.h"
#include "death.h"
#include "misc.h"
#include "msi.h"
#include "hooks.h"
#include "events.h"
#include "trap.h"
#include "verbs.h"

#include "units.h"
#include "match.h"

#include "nations.h"

//! recursively find the value of everything carried by /what/. if /insured/ is true, vanish anything with a value.
int value_of(MudObject *what, int insured)
{
  MudObject *o;
  int i;

  int v;
  if (is_player(what) || is_mobile(what)) 
    v = 0;
  else {
    v = object_value(what);
  }

  foreach(what->children, o, i) if (!is_player(o) && !is_mobile(o)) {
    int v2 = value_of(o, insured);
    v += v2;
    if (insured && v2) {
      vanish(o);
      i--;
    }
  }

  return v;
}

MudObject *do_die(MudObject *what, int charge, const char *why, int uncovered) {

  int killcorpse = !what->nuke_me;
  dotrap(E_BEFOREDIED, what, what);
  /* ::: before_died o1== victim; */
  if (killcorpse && what->nuke_me)
    killcorpse = 1;
  else
    killcorpse = 0;

    if (is_player(what)) {
      string a = "@auto_";
      a += what->id;
      MudObject *body = planet->get(a.c_str());
      if (body) {
	restore_stuff(what);
	what->oprintf(cansee, "%#M wakes up with a start.\n", what);
	what->printf("You wake up with a start.\n");
	what->interpret("look");
	return 0;
      }
    }

    MudObject *corpse=0;

    bool insured = what->get_int("insurance") > now;

    if (uncovered) insured = 0;

    if (what->get_priv(PFL_IMMORTAL)) {
	what->printf("If you were mortal, you would die.\n");
	return 0;
    }

    if (what->get("tourn") || (is_mobile(what) && mud->get_int("tournament",0))) {
      if (why && why[0]!='|')
	broadcast(!getflag(FL_NOSLAIN) && maxlev(LEV_CAPTAIN),
	    "^Y[^Rdeath^Y] ^n%s died (%s^n)\n", name(what),
	    why);
    }
    
    if (why && why[0]!='|')
      broadcast(!getflag(FL_NOSLAIN) && minlev(LEV_CAPTAIN),
	  "^Y[^Rdeath^Y] ^n%s died (%s^n) %s (%s^n)\n", name(what),
	  why, format_roomname(what->owner, what).c_str(), what->owner->id);
    
    {
      extern MudObject *qui;
      MudObject *who2 = qui;
      qui = what;
      if (why)
	log(PFL_NONE, LEV_INTERNAL, "death", "%s in %s", lose_colour(why).c_str(), what->owner->id);
      qui = who2;
    }

    int valstuff = value_of(what, insured);
    if (is_player(what)) {
      valstuff += (int)(totalcash(what)*0.9);
      wipe_cash(what);
    }
    if (!insured)
      valstuff = 0;

    if (is_mobile(what) && !killcorpse) {
        corpse = make_corpse(what, what->owner);
	
	if (corpse) {
	  
	  if (what->id[0]!='@') {
	    corpse->set("corpseof", what->id);
	  }
  	}

    }

    //    if (!is_mobile(what)) {
      if (!what->owner->get_flag(FL_DEATH))
	dumpstuff(what, what->owner);
      else
	dumpstuff(what, planet->get("empty"));
      //    }

      if (streq(what->get("body"), "droid")) {
	what->oprintf(cansee, "%#M %[terminates/terminate].\n", what);
	what->printf("^RYOU HAVE TERMINATED^n.\n");
      } else {
	what->oprintf(cansee, "%#M %[dies/die].\n", what);
	what->printf("^RYOU HAVE DIED^n.\n");
      }

    if (is_player(what)) {
      if (what->get("tourn")) {
	set_owner(what, MUD_TOURNAMENTHEAVEN);
      } else {

	MudObject *hosp = get_zonepropobj(what->owner, "hospital");
	if (!hosp)
	  hosp = MUD_DEFHOSPITAL;

	if (hosp) {
	  set_owner(what, hosp);
	  what->set_flag(FL_SLEEPING, 1);
	  what->oprintf(cansee, "%#M's body is dragged in.\n");
	}
      }
    }

    if (is_mobile(what)) {
	set_owner(what, MUD_MOBILEHEAVEN);
    }

    what->unset("!plan");
    what->unset("!what");
    what->unset("!when");

    what->set_flag(FL_RANTER, 0);
    what->set_flag(FL_TIMER, 0);

    if (what->get_int(KEY_STRENGTH)<40)
	what->set(KEY_STRENGTH, 40);
    what->unset(KEY_PISSED);

    MudObject *cur = currency(what);

    if (!is_player(what)) {
      if (what->get_object("cloneof") && !what->mission)
	what->nuke_me = 1;
      /* ::: after_died o1==victim; after corpse created; mobile is now in 'dead'; etc */
      dotrap(E_AFTERDIED, what, what);
      return corpse;
    }

    if (is_player(what)) {
      MudObject *miss = what->get_object("mission");
      if (miss) {
	if (miss->get_int("m_id")==-1) {
	} else {
	  what->printf("Your mission is still uncompleted.\n");
	}
      } 
      
      if (insured) {
	valstuff = convertcash(valstuff, NULL, cur);
	if (valstuff) {

	  what->printf("Your bank account has been credited with %s to cover items lost.\n",
		       formatcash(valstuff, cur, 1));
	  bank_credit(what, cur, valstuff);
	}
      }
      
      charge = convertcash(charge, NULL, cur);

      if (insured && charge) {
	what->printf("Your insurance covers your medical costs.\n");
      } else {
	if (is_player(what) && charge) {
	  bank_debit(what, cur, charge);
	  what->printf("The hospital charges you %s in costs.\n", formatcash(charge, cur, 1));
	}
      }
    }

    dotrap(E_AFTERDIED, what, what);
      
    mount(what);
    // remove $mount property.

    if (is_player(what) && !what->get("tourn")) {
      MudObject *blank = clone_object(MUD_BLANKET, what, NULL);
      if (blank) {
	blank->set("$wornby", what->id);
	blank->set("$wornon", blank->get("wornon"));
      }
    }

    return corpse;
}

/*
 * corpse rottings
 *
 *   1. cloned droids don't leave corpses.
 *   2. zoned mobiles leave corpses that never decay.
 *
 *   3. cloned mobiles leave corpses that
 *         a. are fine
 *         b. rotted
 *         c. skeleton
 *         d. vanish
 */

MudObject *make_corpse(MudObject *mob, MudObject *loc) 
//! create a corpse for /mob/, and place it in /loc/
{
  Mission *mission = mob->mission;

  MudObject *tc = MUD_CORPSE;
  int droid = 0;
  if (streq(mob->get("body"), "droid")) {
    tc = MUD_DROID;
    droid = 1;
  }

  MudObject *corpse = clone_object(tc, loc, NULL);
  if (!corpse)
    return 0;
  
  corpse->set("altshort", mob->get("short"));
  
  if (!droid) {
    corpse->setf("short_desc", "The disfigured ^ocorpse^n of %M", mob);
    corpse->setf("mobname", "%M", mob);
  }
  else
    corpse->setf("short_desc", "The broken form of %M", mob);
  
  corpse->set("zone", mob->get("zone"));

  if (!droid && (!corpse->get("zone") || streq(corpse->get("zone"),"@auto"))) { 
    corpse->set("plan.decay", "60 trap decay;1200 trap decay;600 trap decay");
    corpse->set_flag(FL_TIMER, 1);
    corpse->interpret("file_plan decay");
  } else {
    if (mission)
      corpse->set_mission(mission);
  }

  if (mob->get_int("size")>=0) {
    corpse->set("size", mob->get_int("size"));
  }
  if (mob->get_int("mass")>=0) {
    corpse->set("mass", mob->get_int("mass"));
  }
  corpse->setf("desc", "%#M is dead.", mob);
  if (const char *a=mob->get("corpsedisc")) {
    corpse->set("disc.0", a);
    corpse->set("disc.count", 1);
  }
  corpse->set_flag(FL_NOSAVE, 1);
  
  MudObject *wpn = mob->get_object(KEY_WIELD);
  if (wpn && wpn->owner != mob)
    wpn = 0;
  
  MudObject *wornfrom = archetype(mob);
  if (mob->get("wornfrom"))
    wornfrom = mob->get_object("wornfrom");

  MudObject *orwep = 0;

  if (!mob->get_object(KEY_WIELD) && wornfrom && 
      wornfrom->get_object(KEY_WIELD)) {
    MudObject *o = orwep = wornfrom->get_object(KEY_WIELD);
    MudObject *c = clone_object(o, mob, NULL);
    if (c) {
      c->set("zone", corpse->get("zone"));
      c->set("$lootfrom", mob->id);
      if (droid && mission)
	c->set_mission(mission);
    }
    wpn = c;
  }
  
  if (wornfrom) {
    MudObject *o;
    int i;
    foreach(wornfrom->children, o, i) 
      if (iswornby(o, wornfrom) && !worn_on(mob, wornon(o), o->get_int("wornlevel", 0))) {

	MudObject *c = orwep ==o ? wpn : clone_object(o, corpse, NULL);
	if (c) {
	  c->set("zone", corpse->get("zone"));
	  c->set("$wornby", corpse->id);
	  c->set("$wornon", o->get("$wornon"));
	  c->set("$lootfrom", mob->id);
	  if (droid && mission)
	    c->set_mission(mission);
	}
      }
  }

  MudObject *o;
  int i;
  
  World<MudObject> on = *mob->children;
  foreach(&on, o, i) {
    if (iswornby(o, mob)) {
      set_owner(o, corpse);
      o->set("$wornby", corpse->id);
      o->set("$wornon", o->get("$wornon"));
    }
  }
  if (wpn) {
    set_owner(wpn, corpse);
    corpse->set(KEY_WIELD, wpn->id);
  }
  if (anycash(mob)) {
    MudObject *t = clone_object(MUD_CASH, corpse, NULL);
    if (t) {
      moveallcash(mob, t);
      describe_pot(t);
      if (mission)
	t->set_mission(mission);
    }
  }
  
  /* So we reset with the zone properly */
  return corpse;
}