/* rob.c -- Commands dealing with giving/taking/killing things or money */

#include "autoconf.h"
#include "copyright.h"
#ifndef	lint
static char *RCSid = "$Id: rob.c,v 1.8 1995/03/21 00:01:07 ambar Exp $";
USE(RCSid);
#endif

#include "interface.h"
#include "match.h"
#include "attrs.h"

void 
do_kill(player, cause, key, what, costchar)
    dbref player, cause;
    int key;
    char *what, *costchar;
{
    dbref victim;
    char *buf1, *buf2;
    int cost;

    init_match(player, what, TYPE_PLAYER);
    match_neighbor();
    match_me();
    match_here();
    if (Wizard(player)) {
	match_player();
	match_absolute();
    }
    victim = match_result();

    switch (victim) {
    case NOTHING:
	notify(player, "I don't see that player here.");
	break;
    case AMBIGUOUS:
	notify(player, "I don't know who you mean!");
	break;
    default:
	if (!isPlayer(victim) && !isThing(victim)) {
	    notify(player, "Sorry, you can only kill players and things.");
	    break;
	}
	if ((Haven(Location(victim)) && !Wizard(player)) ||
	    (controls(victim, Location(victim)) &&
	     !controls(player, Location(victim))) ||
	    Immortal(victim)) {
	    notify(player, "Sorry.");
	    break;
	}
	/* go for it */

	cost = atoi(costchar);
	if (key == KILL_KILL) {
	    if (cost < mudconf.killmin)
		cost = mudconf.killmin;
	    if (cost > mudconf.killmax)
		cost = mudconf.killmax;

	    /* see if it works */

	    if (!payfor(player, cost)) {
		notify(player,
		       tprintf("You don't have enough %s.",
			       mudconf.many_coins));
		return;
	    }
	} else {
	    cost = 0;
	}

	if (!(((random() % mudconf.killguarantee) < cost) ||
	      (key == KILL_SLAY)) ||
	    Wizard(victim)) {

	    /* Failure: notify player and victim only */

	    notify(player, "Your murder attempt failed.");
	    buf1 = alloc_lbuf("do_kill.failed");
	    sprintf(buf1, "%s tried to kill you!", Name(player));
	    notify_with_cause(victim, player, buf1);
	    if (Suspect(player)) {
		strcpy(buf1, Name(player));
		if (player == Owner(player)) {
		    raw_broadcast(WIZARD,
				  "[Suspect] %s tried to kill %s(#%d).",
				  buf1, Name(victim), victim);
		} else {
		    buf2 = alloc_lbuf("do_kill.SUSP.failed");
		    strcpy(buf2, Name(Owner(player)));
		    raw_broadcast(WIZARD,
			"[Suspect] %s <via %s(#%d)> tried to kill %s(#%d).",
				  buf2, buf1, player,
				  Name(victim), victim);
		    free_lbuf(buf2);
		}
	    }
	    free_lbuf(buf1);
	    break;
	}
	/* Success!  You killed him */

	buf1 = alloc_lbuf("do_kill.succ.1");
	buf2 = alloc_lbuf("do_kill.succ.2");
	if (Suspect(player)) {
	    strcpy(buf1, Name(player));
	    if (player == Owner(player)) {
		raw_broadcast(WIZARD,
			      "[Suspect] %s killed %s(#%d).",
			      buf1, Name(victim), victim);
	    } else {
		strcpy(buf2, Name(Owner(player)));
		raw_broadcast(WIZARD,
			      "[Suspect] %s <via %s(#%d)> killed %s(#%d).",
			      buf2, buf1, player, Name(victim),
			      victim);
	    }
	}
	sprintf(buf1, "You killed %s!", Name(victim));
	sprintf(buf2, "killed %s!", Name(victim));
	if (!isPlayer(victim))
	    if (halt_que(NOTHING, victim) > 0)
		if (!Quiet(victim))
		    notify(Owner(victim), "Halted.");
	did_it(player, victim, A_KILL, buf1, A_OKILL, buf2, A_AKILL,
	       (char **) NULL, 0);

	/* notify victim */

	sprintf(buf1, "%s killed you!", Name(player));
	notify_with_cause(victim, player, buf1);

	/* Pay off the bonus */

	if (key == KILL_KILL) {
	    cost /= 2;		/* victim gets half */
	    if (Pennies(Owner(victim)) < mudconf.paylimit) {
		sprintf(buf1,
			"Your insurance policy pays %d %s.",
			cost, mudconf.many_coins);
		notify(victim, buf1);
		giveto(Owner(victim), cost);
	    } else {
		notify(victim,
		       "Your insurance policy has been revoked.");
	    }
	}
	free_lbuf(buf1);
	free_lbuf(buf2);

	/* send him home */

	move_via_generic(victim, HOME, NOTHING, 0);
	divest_object(victim);
	break;
    }
}

/* ---------------------------------------------------------------------------
 * give_thing, give_money, do_give: Give away money or things.
 */

static void 
give_thing(giver, recipient, key, what)
    dbref giver, recipient;
    int key;
    char *what;
{
    dbref thing;
    char *str, *sp;

    init_match(giver, what, TYPE_THING);
    match_possession();
    match_me();
    thing = match_result();

    switch (thing) {
    case NOTHING:
	notify(giver, "You don't have that!");
	return;
    case AMBIGUOUS:
	notify(giver, "I don't know which you mean!");
	return;
    }

    if (thing == giver) {
	notify(giver, "You can't give yourself away!");
	return;
    }
    if ((!isThing(thing) && !isPlayer(thing)) ||
	!(Enter_ok(recipient) || controls(giver, recipient))) {
	notify(giver, "Permission denied.");
	return;
    }
    if (!could_doit(giver, thing, A_LGIVE)) {
	sp = str = alloc_lbuf("do_give.gfail");
	safe_str((char *) "You can't give ", str, &sp);
	safe_str(Name(thing), str, &sp);
	safe_str((char *) " away.", str, &sp);

	did_it(giver, thing, A_GFAIL, str, A_OGFAIL, NULL,
	       A_AGFAIL, (char **) NULL, 0);
	free_lbuf(str);
	return;
    }
    if (!could_doit(thing, recipient, A_LRECEIVE)) {
	sp = str = alloc_lbuf("do_give.rfail");
	safe_str(Name(recipient), str, &sp);
	safe_str((char *) " doesn't want ", str, &sp);
	safe_str(Name(thing), str, &sp);
	safe_chr('.', str, &sp);

	did_it(giver, recipient, A_RFAIL, str, A_ORFAIL, NULL,
	       A_ARFAIL, (char **) NULL, 0);
	free_lbuf(str);
	return;
    }
    move_via_generic(thing, recipient, giver, 0);
    divest_object(thing);
    if (!(key & GIVE_QUIET)) {
	str = alloc_lbuf("do_give.thing.ok");
	strcpy(str, Name(giver));
	notify_with_cause(recipient, giver,
			  tprintf("%s gave you %s.", str, Name(thing)));
	notify(giver, "Given.");
	notify_with_cause(thing, giver,
		       tprintf("%s gave you to %s.", str, Name(recipient)));
	free_lbuf(str);
    }
    did_it(giver, thing, A_DROP, NULL, A_ODROP, NULL, A_ADROP,
	   (char **) NULL, 0);
    did_it(recipient, thing, A_SUCC, NULL, A_OSUCC, NULL, A_ASUCC,
	   (char **) NULL, 0);
}

static void 
give_money(giver, recipient, key, amount)
    dbref giver, recipient;
    int key;
    int amount;
{
    dbref aowner;
    int cost, aflags;
    char *str;

    /* do amount consistency check */

    if (amount < 0 && !Wizard(giver)) {
	notify(giver,
	     tprintf("You look through your pockets. Nope, no negative %s.",
		     mudconf.many_coins));
	return;
    }
    if (!amount) {
	notify(giver, tprintf("You must specify a positive number of %s.",
			      mudconf.many_coins));
	return;
    }
    if (!Wizard(giver)) {
	if ((isPlayer(recipient)) &&
	    (Pennies(recipient) + amount > mudconf.paylimit)) {
	    notify(giver, tprintf("That player doesn't need that many %s!",
				  mudconf.many_coins));
	    return;
	}
	if (!could_doit(giver, recipient, A_LUSE)) {
	    notify(giver, tprintf("%s won't take your money.",
				  Name(recipient)));
	    return;
	}
    }
    /* try to do the give */

    if (!payfor(giver, amount)) {
	notify(giver,
	       tprintf("You don't have that many %s to give!",
		       mudconf.many_coins));
	return;
    }
    /* Find out cost if an object */

    if (isThing(recipient)) {
	str = atr_pget(recipient, A_COST, &aowner, &aflags);
	cost = atoi(str);
	free_lbuf(str);

	/* Can't afford it? */

	if (amount < cost) {
	    notify(giver, "Feeling poor today?");
	    giveto(giver, amount);
	    return;
	}
	/* Negative cost */

	if (cost < 0) {
	    return;
	}
    } else {
	cost = amount;
    }

    if (!(key & GIVE_QUIET)) {
	if (amount == 1) {
	    notify(giver,
		   tprintf("You give a %s to %s.",
			   mudconf.one_coin, Name(recipient)));
	    notify_with_cause(recipient, giver,
			      tprintf("%s gives you a %s.", Name(giver),
				      mudconf.one_coin));
	} else {
	    notify(giver,
		   tprintf("You give %d %s to %s.", amount,
			   mudconf.many_coins, Name(recipient)));
	    notify_with_cause(recipient, giver,
			      tprintf("%s gives you %d %s.", Name(giver),
				      amount, mudconf.many_coins));
	}
    }
    /* Report change given */

    if ((amount - cost) == 1) {
	notify(giver,
	       tprintf("You get 1 %s in change.", mudconf.one_coin));
	giveto(giver, 1);
    } else if (amount != cost) {
	notify(giver,
	       tprintf("You get %d %s in change.",
		       (amount - cost), mudconf.many_coins));
	giveto(giver, (amount - cost));
    }
    /* Transfer the money and run PAY attributes */

    giveto(recipient, cost);
    did_it(giver, recipient, A_PAY, NULL, A_OPAY, NULL, A_APAY,
	   (char **) NULL, 0);
    return;
}

void 
do_give(player, cause, key, who, amnt)
    dbref player, cause;
    int key;
    char *who, *amnt;
{
    dbref recipient;

    /* check recipient */

    init_match(player, who, TYPE_PLAYER);
    match_neighbor();
    match_possession();
    match_me();
    if (Wizard(player)) {
	match_player();
	match_absolute();
    }
    recipient = match_result();
    switch (recipient) {
    case NOTHING:
	notify(player, "Give to whom?");
	return;
    case AMBIGUOUS:
	notify(player, "I don't know who you mean!");
	return;
    }

    if (Guest(recipient)) {
	notify(player, "Guest really doesn't need money or anything.");
	return;
    }
    if (is_number(amnt)) {
	give_money(player, recipient, key, atoi(amnt));
    } else {
	give_thing(player, recipient, key, amnt);
    }
}
