btmux/autom4te.cache/
btmux/doc/.svn/
btmux/event/.svn/
btmux/game/.svn/
btmux/game/bin/.svn/
btmux/game/data/.svn/
btmux/game/logs/.svn/
btmux/game/maps/
btmux/game/maps/.svn/
btmux/game/maps/.svn/prop-base/
btmux/game/maps/.svn/props/
btmux/game/maps/.svn/text-base/
btmux/game/maps/.svn/wcprops/
btmux/game/mechs/
btmux/game/mechs/.svn/
btmux/game/mechs/.svn/prop-base/
btmux/game/mechs/.svn/props/
btmux/game/mechs/.svn/text-base/
btmux/game/mechs/.svn/wcprops/
btmux/game/text/.svn/
btmux/include/.svn/
btmux/misc/
btmux/misc/.svn/
btmux/misc/.svn/prop-base/
btmux/misc/.svn/props/
btmux/misc/.svn/text-base/
btmux/misc/.svn/wcprops/
btmux/python/
btmux/python/.svn/
btmux/python/.svn/prop-base/
btmux/python/.svn/props/
btmux/python/.svn/text-base/
btmux/python/.svn/wcprops/
btmux/src/.svn/prop-base/
btmux/src/.svn/props/
btmux/src/.svn/text-base/
btmux/src/.svn/wcprops/
btmux/src/hcode/.svn/
btmux/src/hcode/btech/
btmux/src/hcode/btech/.svn/
btmux/src/hcode/btech/.svn/prop-base/
btmux/src/hcode/btech/.svn/props/
btmux/src/hcode/btech/.svn/text-base/
btmux/src/hcode/btech/.svn/wcprops/
btmux/src/hcode/include/.svn/
/*
 * $Id: mech.ammodump.c,v 1.1.1.1 2005/01/11 21:18:10 kstevens Exp $
 *
 * Author: Cord Awtry <kipsta@mediaone.net>
 * Author: Cord Awtry <kipsta@mediaone.net>
 *  Copyright (c) 2000-2002 Cord Awtry
 *       All rights reserved
 *
 * Based on work that was:
 *  Copyright (c) 1997 Markus Stenberg
 *  Copyright (c) 1998-2000 Thomas Wouters
 */

#include "mech.h"
#include "mech.events.h"
#include "p.mech.ammodump.h"
#include "p.mech.build.h"
#include "p.mech.combat.misc.h"
#include "p.mech.damage.h"
#include "p.mech.partnames.h"
#include "p.mech.utils.h"

static void mech_dump_event(MUXEVENT * ev)
{
    MECH *mech = (MECH *) ev->data;
    int arg = (int) ev->data2;
    int loc;
    int i, l;
    int d, e = 0;
    char buf[SBUF_SIZE];
    int weapindx;

    if (!Started(mech))
	return;
    i = MechType(mech) == CLASS_MECH ? 7 : 5;
    /* Global ammo droppage */
    if (!arg) {
	for (; i >= 0; i--)
	    for (l = CritsInLoc(mech, i) - 1; l >= 0; l--)
		if (IsAmmo(GetPartType(mech, i, l)))
		    if (GetPartData(mech, i, l))
			Dump_Decrease(mech, i, l, &e);
	if (e > 1)
	    MECHEVENT(mech, EVENT_DUMP, mech_dump_event, DUMP_GRAD_TICK,
		arg);
	else {
	    mech_notify(mech, MECHALL, "All ammunition dumped.");
	    MechLOSBroadcast(mech,
		"no longer has ammo dumping from hatches on its back.");
	}
	return;
    }
    if (arg < 256) {
	loc = arg - 1;
	l = CritsInLoc(mech, loc);
	for (i = 0; i < l; i++)
	    if (IsAmmo(GetPartType(mech, loc, i)))
		if (!PartIsNonfunctional(mech, loc, i))
		    if ((d = GetPartData(mech, loc, i)))
			Dump_Decrease(mech, loc, i, &e);
	if (e > 1)
	    MECHEVENT(mech, EVENT_DUMP, mech_dump_event, DUMP_GRAD_TICK,
		arg);
	else if (e == 1 && Started(mech)) {
	    ArmorStringFromIndex(loc, buf, MechType(mech), MechMove(mech));
	    mech_notify(mech, MECHALL,
		tprintf("All ammunition in %s dumped.", buf));
	    MechLOSBroadcast(mech,
		"no longer has ammo dumping from hatches on its back.");
	}
	return;
    }
    if (arg < 65536) {
	weapindx = (arg / 256) - 1;
	for (; i >= 0; i--)
	    for (l = CritsInLoc(mech, i) - 1; l >= 0; l--)
		if (IsAmmo(GetPartType(mech, i, l)))
		    if (Ammo2WeaponI(GetPartType(mech, i, l)) == weapindx)
			if (GetPartData(mech, i, l))
			    Dump_Decrease(mech, i, l, &e);
	if (e > 1)
	    MECHEVENT(mech, EVENT_DUMP, mech_dump_event, DUMP_GRAD_TICK,
		arg);
	else {
	    mech_notify(mech, MECHALL, tprintf("Ammunition for %s dumped!",
		    get_parts_long_name(I2Weapon(weapindx), 0)));
	    MechLOSBroadcast(mech,
		"no longer has ammo dumping from hatches on its back.");
	}
	return;
    }
    l = ((arg >> 16) & 0xFF) - 1;
    i = ((arg >> 24) & 0xFF) - 1;
    e = 0;
    if (GetPartData(mech, l, i))
	Dump_Decrease(mech, l, i, &e);
    if (e > 1) {
	MECHEVENT(mech, EVENT_DUMP, mech_dump_event, DUMP_GRAD_TICK, arg);
    } else {
	ArmorStringFromIndex(l, buf, MechType(mech), MechMove(mech));
	mech_notify(mech, MECHALL,
	    tprintf("Ammunition in %s crit %i dumped!", buf, i + 1));
	MechLOSBroadcast(mech,
	    "no longer has ammo dumping from hatches on its back.");
    }
}

void mech_dump(dbref player, void *data, char *buffer)
{
    MECH *mech = (MECH *) data;
    int argc;
    char *args[2];
    int weapnum;
    int weapindx;
    int section;
    int critical;
    int ammoLoc;
    int ammoCrit;
    int loc;
    int i, l, count = 0, d;
    char buf[MBUF_SIZE];
    int type = 0;

    cch(MECH_USUAL);
    argc = mech_parseattributes(buffer, args, 2);
    DOCHECK(argc < 1, "Not enough arguments to the function");
    weapnum = atoi(args[0]);

    DOCHECKMA(Jumping(mech), "You can't dump ammo while jumping!");
    DOCHECKMA(IsRunning(MechDesiredSpeed(mech), MMaxSpeed(mech)),
	"You can't dump ammo while running!");

    if (!strcasecmp(args[0], "stop")) {
	DOCHECKMA(!Dumping(mech), "You aren't dumping anything!");
	mech_notify(mech, MECHALL, "Ammo dumping halted.");
	StopDump(mech);
	MechLOSBroadcast(mech,
	    "no longer has ammo dumping from hatches on its back.");
	return;
    } else if (!strcasecmp(args[0], "all")) {
	count = 0;
	i = MechType(mech) == CLASS_MECH ? 7 : 5;
	for (; i >= 0; i--)
	    for (l = CritsInLoc(mech, i) - 1; l >= 0; l--)
		if (IsAmmo(GetPartType(mech, i, l)))
		    if (GetPartData(mech, i, l))
			count++;
	DOCHECKMA(!count, "You have no ammo to dump!");
	DOCHECKMA(Dumping_Type(mech, 0),
	    "You're already dumping your ammo!");
	StopDump(mech);
	mech_notify(mech, MECHALL, "Starting dumping of all ammunition..");
	MechLOSBroadcast(mech,
	    "starts dumping ammo from hatches on its back.");
	MECHEVENT(mech, EVENT_DUMP, mech_dump_event, DUMP_GRAD_TICK, 0);
	return;
    } else if (!weapnum && strcmp(args[0], "0")) {
	/* Try to find hitloc instead */
	DOCHECKMA(Dumping(mech), "You're already dumping some ammo!");
	loc =
	    ArmorSectionFromString(MechType(mech), MechMove(mech),
	    args[0]);
	DOCHECK(loc < 0, "Invalid location or weapon number!");
	ArmorStringFromIndex(loc, buf, MechType(mech), MechMove(mech));
	if (args[1]) {
	    i = atoi(args[1]);
	    i--;
	    if (i >= 0 && i < 12) {
		if (IsAmmo(GetPartType(mech, loc, i)))
		    if (!PartIsNonfunctional(mech, loc, i))
			if ((d = GetPartData(mech, loc, i)))
			    count++;
		DOCHECKMA(!count,
		    tprintf("There is no ammunition in %s crit %i!",
			buf, i + 1));
		type = (((i + 1) << 8) | (loc + 1));
		DOCHECKMA(type & ~0xFFFF,
		    "Internal inconsistency, dump failed!");
		type = type << 16;
		mech_notify(mech, MECHALL,
		    tprintf
		    ("Starting dumping of ammunition in %s crit %i..",
			buf, i + 1));
		MechLOSBroadcast(mech,
		    "starts dumping ammo from hatches on its back.");
		MECHEVENT(mech, EVENT_DUMP, mech_dump_event,
		    DUMP_GRAD_TICK, type);
		return;
	    }
	}
	l = CritsInLoc(mech, loc);
	for (i = 0; i < l; i++)
	    if (IsAmmo(GetPartType(mech, loc, i)))
		if (!PartIsNonfunctional(mech, loc, i))
		    if ((d = GetPartData(mech, loc, i)))
			count++;
	DOCHECKMA(!count, tprintf("There is no ammunition in %s!", buf));
	type = loc + 1;
	mech_notify(mech, MECHALL,
	    tprintf("Starting dumping of ammunition in %s..", buf));
	MechLOSBroadcast(mech,
	    "starts dumping ammo from hatches on its back.");
	MECHEVENT(mech, EVENT_DUMP, mech_dump_event, DUMP_GRAD_TICK, type);
	return;
    }
    weapindx = FindWeaponIndex(mech, weapnum);
    if (weapnum < 0)
	SendError(tprintf
	    ("CHEATER: #%d tried to crash mux with command 'dump %d'!",
		(int) player, weapnum));
    DOCHECKMA(Dumping(mech), "You're already dumping some ammo!");
    DOCHECK(weapindx < 0, "Invalid weapon number!");
    FindWeaponNumberOnMech(mech, weapnum, &section, &critical);
    DOCHECK(MechWeapons[weapindx].type == TBEAM ||
	MechWeapons[weapindx].type == THAND,
	"That weapon doesn't use ammunition!");
    DOCHECK(!FindAmmoForWeapon_sub(mech, -1, -1, weapindx, 0, &ammoLoc,
	    &ammoCrit, 0, 0),
	"You don't have any ammunition for that weapon stored on this mech!");
    DOCHECK(GetPartData(mech, ammoLoc, ammoCrit) == 0,
	"You are out of ammunition for that weapon already!");
    type = 256 * (weapindx + 1);
    mech_notify(mech, MECHALL, tprintf("Starting dumping %s ammunition..",
	    get_parts_long_name(I2Weapon(weapindx), 0)));
    MechLOSBroadcast(mech,
	"starts dumping ammo from hatches on its back.");
    MECHEVENT(mech, EVENT_DUMP, mech_dump_event, DUMP_GRAD_TICK, type);
#if 0
    while (FindAmmoForWeapon(mech, weapindx, 0, &ammoLoc, &ammoCrit))
	GetPartData(mech, ammoLoc, ammoCrit) = 0;
    mech_notify(mech, MECHALL, tprintf("Ammunition for %s dumped!",
	    get_parts_long_name(I2Weapon(weapindx), 0)));
#endif
}

int Dump_Decrease(MECH * mech, int loc, int pos, int *hm)
{
    int c, index, weapindx, rem;

#define RUP(a) { if (*hm < a) *hm = a; return a; }
    /* It _is_ ammo, and contains something */

    if (IsAmmo((index = GetPartType(mech, loc, pos))))
	if (!PartIsNonfunctional(mech, loc, pos))
	    if ((c = GetPartData(mech, loc, pos))) {
		weapindx = Ammo2WeaponI(index);
		if (MechWeapons[weapindx].ammoperton < DUMP_SPEED) {
		    if ((muxevent_tick % (DUMP_SPEED /
				MechWeapons[weapindx].ammoperton)))
			RUP(2);
		    /* fine, we remove 1 */
		    rem = 1;
		} else
		    rem =
			MIN(c,
			MechWeapons[weapindx].ammoperton / DUMP_SPEED);
		ammo_expedinture_check(mech, weapindx, rem - 1);
		SetPartData(mech, loc, pos, c - rem);
		if (c <= rem)
		    RUP(1);
		RUP(2);
	    }
    return 0;
}

/*
 * The function is for blowing up some of the ammo that's being dumped from
 * a mech when it takes a rear torso shot.
 *
 * FASA rules state that if a mech takes a rear torso shot while dumping ammo,
 * all the dumping ammo explodes and goes to the armor of that location. That's
 * a bit harsh in RS as getting behind someone ain't that hard. So what we do is
 * if you're dumping ammo and take a rear torso shot, we, on a roll of 7 or less, 
 * call this BlowDumpingAmmo function. This function finds all the ammo you're dumping
 * and blows up ONE ROUND of one type, randomly. If you're dumping a lot and get hit
 * a few times (like from an LRM) you could get a bunch of little booms which
 * could really ruin your day.
 */

void BlowDumpingAmmo(MECH * mech, MECH * attacker, int wHitLoc)
{
    struct objDumpingAmmo aobjAmmoItems[MAX_WEAPONS_PER_MECH];
    int wEventData = -1;
    int wSecIter, wSlotIter;
    int wcAmmoItems = 0;
    int wPartType = 0, wPartData = 0;
    int wLoc = 0;
    int wWeapIdx = 0;
    int wRndIdx = 0;
    int wBlowDamage = 0;

    DumpingData(mech, &wEventData);
    if (wEventData < 0)
	return;
    if (!wEventData) {		/* Global ammo dump */
	for (wSecIter = 7; wSecIter >= 0; wSecIter--)
	    for (wSlotIter = CritsInLoc(mech, wSecIter) - 1;
		wSlotIter >= 0; wSlotIter--) {
		wPartType = GetPartType(mech, wSecIter, wSlotIter);
		if (IsAmmo(wPartType))
		    if (GetPartData(mech, wSecIter, wSlotIter)) {
			aobjAmmoItems[wcAmmoItems].wDamage =
			    FindMaxAmmoDamage(Ammo2WeaponI(wPartType));
			aobjAmmoItems[wcAmmoItems].wLocation = wSecIter;
			aobjAmmoItems[wcAmmoItems].wSlot = wSlotIter;
			aobjAmmoItems[wcAmmoItems].wWeapIdx =
			    Ammo2WeaponI(wPartType);
			aobjAmmoItems[wcAmmoItems].wPartType = wPartType;
			wcAmmoItems++;
		    }
	    }
    } else if (wEventData < 256) {	/* Location specific ammo dump */
	wLoc = wEventData - 1;
	for (wSlotIter = 0; wSlotIter < CritsInLoc(mech, wLoc);
	    wSlotIter++) {
	    wPartType = GetPartType(mech, wLoc, wSlotIter);

/*     wPartType = GetPartType(mech, wSecIter, wSlotIter); */
	    if (IsAmmo(wPartType))
		if (!PartIsNonfunctional(mech, wLoc, wSlotIter) &&
		    GetPartData(mech, wLoc, wSlotIter)) {
		    aobjAmmoItems[wcAmmoItems].wDamage =
			FindMaxAmmoDamage(Ammo2WeaponI(wPartType));
		    aobjAmmoItems[wcAmmoItems].wLocation = wLoc;
		    aobjAmmoItems[wcAmmoItems].wSlot = wSlotIter;
		    aobjAmmoItems[wcAmmoItems].wWeapIdx =
			Ammo2WeaponI(wPartType);
		    aobjAmmoItems[wcAmmoItems].wPartType = wPartType;
		    wcAmmoItems++;
		}
	}
    } else if (wEventData < 65536) {	/* Weapon specific ammo dump */
	wWeapIdx = (wEventData / 256) - 1;
	for (wSecIter = 7; wSecIter >= 0; wSecIter--)
	    for (wSlotIter = CritsInLoc(mech, wSecIter) - 1;
		wSlotIter >= 0; wSlotIter--) {
		wPartType = GetPartType(mech, wSecIter, wSlotIter);
		if (IsAmmo(wPartType) &&
		    (Ammo2WeaponI(wPartType) == wWeapIdx)) {
		    aobjAmmoItems[wcAmmoItems].wDamage =
			FindMaxAmmoDamage(Ammo2WeaponI(wPartType));
		    aobjAmmoItems[wcAmmoItems].wLocation = wSecIter;
		    aobjAmmoItems[wcAmmoItems].wSlot = wSlotIter;
		    aobjAmmoItems[wcAmmoItems].wWeapIdx =
			Ammo2WeaponI(wPartType);
		    aobjAmmoItems[wcAmmoItems].wPartType = wPartType;
		    wcAmmoItems++;
		}
	    }
    } else {			/* crit specific dump */
	wSecIter = ((wEventData >> 16) & 0xFF) - 1;
	wSlotIter = ((wEventData >> 24) & 0xFF) - 1;
	wPartType = GetPartType(mech, wSecIter, wSlotIter);
	aobjAmmoItems[wcAmmoItems].wDamage =
	    FindMaxAmmoDamage(Ammo2WeaponI(wPartType));
	aobjAmmoItems[wcAmmoItems].wLocation = wSecIter;
	aobjAmmoItems[wcAmmoItems].wSlot = wSlotIter;
	aobjAmmoItems[wcAmmoItems].wWeapIdx = Ammo2WeaponI(wPartType);
	aobjAmmoItems[wcAmmoItems].wPartType = wPartType;
	wcAmmoItems++;
    }

    if (wcAmmoItems > 0) {
	wRndIdx = Number(0, wcAmmoItems - 1);
	wBlowDamage = aobjAmmoItems[wRndIdx].wDamage;
	wSecIter = aobjAmmoItems[wRndIdx].wLocation;
	wSlotIter = aobjAmmoItems[wRndIdx].wSlot;
	wWeapIdx = aobjAmmoItems[wRndIdx].wWeapIdx;
	if (wBlowDamage > 0) {
	    MechLOSBroadcast(mech,
		"'s rear armor lights up as ammo being dumped ignites!");
	    mech_notify(mech, MECHALL,
		tprintf
		("%%ch%%crSome of the %s ammo dumping out of your mech ignites!%%cn",
		    get_parts_long_name(I2Weapon(wWeapIdx), 0)));
	    DamageMech(mech, attacker, 0, -1, wHitLoc, 1, 0,
		wBlowDamage, -1, -1, 0, -1, 0, 1);
	    /*
	     * Decrement the ammo one round
	     */
	    wPartData = GetPartData(mech, wSecIter, wSlotIter);
	    if (wPartData > 0)
		SetPartData(mech, wSecIter, wSlotIter, wPartData - 1);
	    mech_notify(mech, MECHALL,
		"%ch%crAll ammo dumping operations have stopped!%cn");
	    StopDump(mech);
	}
    }
}

int FindMaxAmmoDamage(int wWeapIdx)
{
    int wDamage = MechWeapons[wWeapIdx].damage;
    int wIter = 0;

    if (IsMissile(wWeapIdx) || IsArtillery(wWeapIdx)) {
	for (wIter = 0; MissileHitTable[wIter].key != -1; wIter++)
	    if (MissileHitTable[wIter].key == wWeapIdx)
		wDamage *= MissileHitTable[wIter].num_missiles[10];
    }

    return wDamage;
}