/*
* $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, §ion, &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;
}