/*
* $Id: mech.damage.c,v 1.4 2005/08/10 14:09:34 av1-op Exp $
*
* Author: Cord Awtry <kipsta@mediaone.net>
* Copyright (c) 2000-2002 Cord Awtry
* Copyright (c) 1999-2005 Kevin Stevens
* All rights reserved
*
* Based on work that was:
* Copyright (c) 1997 Markus Stenberg
* Copyright (c) 1998-2000 Thomas Wouters
*
*/
#include "mech.h"
#include "btmacros.h"
#include "mech.events.h"
#include "p.bsuit.h"
#include "p.btechstats.h"
#include "p.crit.h"
#include "p.eject.h"
#include "p.map.conditions.h"
#include "p.mech.ammodump.h"
#include "p.mech.build.h"
#include "p.mech.combat.misc.h"
#include "p.mech.combat.missile.h"
#include "p.mech.damage.h"
#include "p.mech.ecm.h"
#include "p.mech.hitloc.h"
#include "p.mech.move.h"
#include "p.mech.ood.h"
#include "p.mech.utils.h"
#include "p.mech.pickup.h"
#include "p.pcombat.h"
static char *MyColorStrings[] = {
"", "%ch%cg", "%ch%cy", "%cr"
};
static char *MyMessageStrings[] = {
"ERROR%c",
"low.%c",
"critical!%c",
"BREACHED!%c"
};
static inline char *MySeriousColorStr(MECH * mech, int index)
{
return MyColorStrings[index % 4];
}
static inline char *MySeriousStr(MECH * mech, int index)
{
return MyMessageStrings[index % 4];
}
static inline int MySeriousnessCheck(MECH * mech, int hitloc)
{
int orig, new;
if (!(orig = GetSectOArmor(mech, hitloc)))
return 0;
if (!(new = GetSectArmor(mech, hitloc)))
return 3;
if (new < orig / 4)
return 2;
if (new < orig / 2)
return 1;
return 0;
}
static inline int MySeriousnessCheckR(MECH * mech, int hitloc)
{
int orig, new;
if (!(orig = GetSectORArmor(mech, hitloc)))
return 0;
if (!(new = GetSectRArmor(mech, hitloc)))
return 3;
if (new < orig / 4)
return 2;
if (new < orig / 2)
return 1;
return 0;
}
int cause_armordamage(MECH * wounded,
MECH * attacker,
int LOS,
int attackPilot,
int isrear,
int iscritical,
int hitloc, int damage, int *crits, int wWeapIndx, int wAmmoMode)
{
int intDamage = 0, r;
int seriousness = 0;
int tAPCritical = 0;
int wPercentLeft = 0;
if (MechType(wounded) == CLASS_MW)
return (damage > 0) ? damage : 0;
if ((MechSpecials(wounded) & HARDA_TECH) && damage > 0)
damage = (damage + 1) / 2;
/* Now decrement armor, and if neccessary, handle criticals... */
if (MechType(wounded) == CLASS_MECH && isrear && (hitloc == CTORSO
|| hitloc == RTORSO || hitloc == LTORSO)) {
if ((GetSectRArmor(wounded, hitloc) - damage) >= 0) {
wPercentLeft = (((GetSectRArmor(wounded, hitloc) -
damage) * 100) / GetSectORArmor(wounded, hitloc));
}
intDamage = damage - GetSectRArmor(wounded, hitloc);
if (intDamage > 0) {
SetSectRArmor(wounded, hitloc, 0);
if (intDamage != damage)
seriousness = 3;
} else {
seriousness = MySeriousnessCheckR(wounded, hitloc);
SetSectRArmor(wounded, hitloc, GetSectRArmor(wounded,
hitloc) - damage);
seriousness = (seriousness == MySeriousnessCheckR(wounded,
hitloc)) ? 0 : MySeriousnessCheckR(wounded, hitloc);
}
} else {
/* Silly stuff */
/*
SetSectArmor(wounded, hitloc, MAX(0, intDamage =
GetSectArmor(wounded, hitloc) - damage));
intDamage = abs(intDamage);
*/
if (GetSectOArmor(wounded, hitloc) &&
((GetSectArmor(wounded, hitloc) - damage) >= 0)) {
wPercentLeft = (((GetSectArmor(wounded, hitloc) -
damage) * 100) / GetSectOArmor(wounded, hitloc));
}
intDamage = damage - GetSectArmor(wounded, hitloc);
if (intDamage > 0) {
SetSectArmor(wounded, hitloc, 0);
if (intDamage != damage)
seriousness = 3;
} else {
seriousness = MySeriousnessCheck(wounded, hitloc);
SetSectArmor(wounded, hitloc, GetSectArmor(wounded,
hitloc) - damage);
seriousness = (seriousness == MySeriousnessCheck(wounded,
hitloc)) ? 0 : MySeriousnessCheck(wounded, hitloc);
}
if (!GetSectArmor(wounded, hitloc))
MechFloodsLoc(wounded, hitloc, MechZ(wounded));
}
if (!iscritical && (wAmmoMode & AC_AP_MODE) && (intDamage <= 0) &&
(wPercentLeft < 50))
tAPCritical = 1;
if (iscritical || tAPCritical) {
r = Roll();
rollstat.critrolls[r - 2]++;
rollstat.totcrolls++;
/* Do the AP ammo thang */
if (tAPCritical) {
if (!strcmp(&MechWeapons[wWeapIndx].name[3], "AC/2"))
r -= 4;
else if (!strcmp(&MechWeapons[wWeapIndx].name[3], "LightAC/2"))
r -= 4;
else if (!strcmp(&MechWeapons[wWeapIndx].name[3], "AC/5"))
r -= 3;
else if (!strcmp(&MechWeapons[wWeapIndx].name[3], "LightAC/5"))
r -= 3;
else if (!strcmp(&MechWeapons[wWeapIndx].name[3], "AC/10"))
r -= 2;
else if (!strcmp(&MechWeapons[wWeapIndx].name[3], "AC/20"))
r -= 1;
else
r -= 10;
}
switch (r) {
case 8:
case 9:
HandleCritical(wounded, attacker, LOS, hitloc, 1);
(*crits) += 1;
break;
case 10:
case 11:
HandleCritical(wounded, attacker, LOS, hitloc, 2);
(*crits) += 2;
break;
case 12:
HandleCritical(wounded, attacker, LOS, hitloc, 3);
(*crits) += 3;
break;
default:
break;
}
iscritical = 0;
}
if (MechType(wounded) == CLASS_AERO && intDamage >= 0) {
DestroySection(wounded, attacker, LOS, hitloc);
if (Destroyed(wounded)) {
intDamage = 0;
return 0;
}
switch (hitloc) {
case AERO_COCKPIT:
DestroyMech(wounded, attacker, 1);
return 0;
case AERO_ENGINE:
MakeMechFall(wounded);
MechSpeed(wounded) = 0;
SetMaxSpeed(wounded, 0);
MechVerticalSpeed(wounded) = 0;
if (!(MechStatus(wounded) & LANDED))
mech_notify(wounded, MECHALL, "You feel the thrust die..");
else
mech_notify(wounded, MECHALL,
"The computer reports engine destroyed!");
if (!Landed(wounded))
MECHEVENT(wounded, EVENT_FALL, mech_fall_event, FALL_TICK,
-1);
break;
}
}
if (seriousness > 0 && MechArmorWarn(wounded))
mech_notify(wounded, MECHALL, tprintf("%sWARNING: %s%s Armor %s",
MySeriousColorStr(wounded, seriousness),
ShortArmorSectionString(MechType(wounded),
MechMove(wounded), hitloc),
isrear ? " (Rear)" : "", MySeriousStr(wounded, seriousness)));
return intDamage > 0 ? intDamage : 0;
}
int cause_internaldamage(MECH * wounded,
MECH * attacker,
int LOS,
int attackPilot,
int isrear, int hitloc, int intDamage, int weapindx, int *crits)
{
int r = Roll();
char locname[30];
char msgbuf[MBUF_SIZE];
ArmorStringFromIndex(hitloc, locname, MechType(wounded),
MechMove(wounded));
if ((MechSpecials(wounded) & REINFI_TECH) && intDamage > 0)
intDamage = (intDamage + 1) / 2;
else if (MechSpecials(wounded) & COMPI_TECH)
intDamage = intDamage * 2;
/* Critical hits? */
rollstat.critrolls[r - 2]++;
rollstat.totcrolls++;
if (!(*crits))
switch (r) {
case 8:
case 9:
HandleCritical(wounded, attacker, LOS, hitloc, 1);
break;
case 10:
case 11:
HandleCritical(wounded, attacker, LOS, hitloc, 2);
break;
case 12:
if ((MechType(wounded) == CLASS_MECH) ||
(MechType(wounded) == CLASS_MW)) {
switch (hitloc) {
case RARM:
case LARM:
case RLEG:
case LLEG:
case HEAD:
/* Limb blown off */
mech_notify(wounded, MECHALL,
"%ch%cyCRITICAL HIT!!%c");
if (!Destroyed(wounded)) {
sprintf(msgbuf,
"'s %s is blown off in a shower of sparks and smoke!",
locname);
MechLOSBroadcast(wounded, msgbuf);
}
DestroySection(wounded, attacker, LOS, hitloc);
if (MechType(wounded) != CLASS_MW)
intDamage = 0;
break;
default:
/* Ouch */
HandleCritical(wounded, attacker, LOS, hitloc, 3);
break;
}
} else {
HandleCritical(wounded, attacker, LOS, hitloc, 3);
}
break;
default:
break;
/* No critical hit */
}
/* Hmm.. This should be interesting */
if (MechType(wounded) == CLASS_MECH && intDamage && (hitloc == CTORSO)
&& GetSectInt(wounded, hitloc) == GetSectOInt(wounded, hitloc))
MechBoomStart(wounded) = muxevent_tick;
if (GetSectInt(wounded, hitloc) <= intDamage) {
intDamage -= GetSectInt(wounded, hitloc);
DestroySection(wounded, attacker, LOS, hitloc);
/* if (Destroyed(wounded)) */
/* intDamage = 0; */
} else {
SetSectInt(wounded, hitloc, GetSectInt(wounded,
hitloc) - intDamage);
intDamage = 0;
}
return intDamage;
}
int global_physical_flag = 0;
void DamageMech(MECH * wounded,
MECH * attacker,
int LOS,
int attackPilot,
int hitloc,
int isrear,
int iscritical,
int damage,
int intDamage, int cause, int bth, int wWeapIndx, int wAmmoMode,
int tIgnoreSwarmers)
{
char locationBuff[20];
char notificationBuff[80];
char rearMessage[10];
int transfer = 0;
int was_transfer = 0;
int kill = 0;
MAP *map;
int crits = 0;
int tBlowDumpingAmmo = 0;
int wSwarmerHitChance = 0;
int wRoll = Roll();
MECH *mechSwarmer;
int tSnapTowLines = 0;
MECH *towTarget;
/* if:
damage = -1 && intDamage>0
- ammo expl
damage = -2 && intDamage>0
- transferred ammo expl
damage = n && intDamage = 0
- usual damage
damage = n && intDamage = -1/-2
- usual damage + transfer/+red enable */
/* if damage>0 && !intDamage usual dam. */
map = getMap(attacker->mapindex);
if ((map && MapIsCS(map)) || (MechStatus(wounded) & COMBAT_SAFE)) {
if (wounded != attacker)
mech_notify(attacker, MECHALL,
"Your efforts only scratch the paint!");
return;
}
/* See if we have suits on us. If we get hit in any rear torso or the left/right front
* torsos, there's a chance the bsuits on us will suck up the damage. In fasa rules, there's
* no roll, but that's foolish if there's only one suits. 3030 rules are there's a 20 percent
* chance per suit on you that the suits will eat up the damage.
*/
if ((CountSwarmers(wounded) > 0) && (!tIgnoreSwarmers)) {
if ((mechSwarmer = findSwarmers(wounded))) {
if (!attacker || (attacker->mynum != mechSwarmer->mynum)) {
wSwarmerHitChance = 20 * CountBSuitMembers(mechSwarmer);
if (isrear) {
if ((hitloc != CTORSO) && (hitloc != RTORSO) &&
(hitloc != LTORSO))
wSwarmerHitChance = 0;
} else {
if ((hitloc != RTORSO) && (hitloc != LTORSO))
wSwarmerHitChance = 0;
}
if ((wSwarmerHitChance >= wRoll) &&
(GetSectArmor(wounded, hitloc))) {
if (attacker && (attacker->mynum != wounded->mynum)) {
mech_notify(attacker, MECHALL,
"The battlesuits crawling all over your target absorb the damage!");
}
mech_notify(wounded, MECHALL,
"The battlesuits crawling all over you absorb the damage!");
mech_notify(mechSwarmer, MECHALL,
"You absorb the damage!");
hitloc =
FindHitLocation(mechSwarmer, 0, &iscritical,
&isrear);
DamageMech(mechSwarmer, attacker, LOS,
attackPilot, hitloc, 0, 0, damage, 0,
cause, bth, wWeapIndx, wAmmoMode, 0);
return;
}
}
}
}
if (MechType(wounded) == CLASS_MW || MechType(wounded) == CLASS_MECH)
transfer = 1;
#ifdef BT_MOVEMENT_MODES
if ((damage > 0 || intDamage > 0) && MechStatus2(wounded) & SPRINTING) {
MechStatus2(wounded) &= ~SPRINTING;
MechLOSBroadcast(wounded, "breaks out of its sprint as it takes damage!");
mech_notify(wounded, MECHALL, "You lose your sprinting momentum as you take damage!");
if (!MoveModeChange(wounded))
MECHEVENT(wounded, EVENT_MOVEMODE, mech_movemode_event, TURN, MODE_OFF|MODE_SPRINT);
}
if ((damage > 0 || intDamage > 0) && MechStatus2(wounded) & HIDDEN) {
MechStatus2(wounded) &= ~HIDDEN;
MechLOSBroadcast(wounded, "loses it's cover as it takes damage!");
mech_notify(wounded, MECHALL, "Your cover is ruined you take damage!");
if (!MoveModeChange(wounded))
MechCritStatus(wounded) &= ~HIDDEN;
}
if ((damage > 0 || intDamage > 0) && (MoveModeLock(wounded) && !(MoveModeData(wounded) & (MODE_EVADE|MODE_DODGE|MODE_OFF)))) {
StopMoveMode(wounded);
mech_notify(wounded, MECHALL, "Your movement mode changes are cancelled as you take damage!");
}
#endif
if (damage > 0 && intDamage == 0) {
/* If we're a VTOL and the hitloc is the rotor,
we'll cut the damage by some value */
if ((MechType(wounded) == CLASS_VTOL) && (hitloc == ROTOR)) {
if (mudconf.btech_divrotordamage > 0)
damage = damage / mudconf.btech_divrotordamage;
if (damage < 1)
damage = 1;
}
if (MechCritStatus(wounded) & HIDDEN) {
mech_notify(wounded, MECHALL, "Your cover is ruined as you take damage!");
MechLOSBroadcast(wounded, "loses it's cover as it takes damage.");
MechCritStatus(wounded) &= ~HIDDEN;
}
if (!global_physical_flag)
AccumulateGunXP(attackPilot, attacker, wounded, damage, 1,
cause, bth);
else if (global_physical_flag == 1)
if (!Destroyed(wounded) && In_Character(wounded->mynum) &&
MechTeam(wounded) != MechTeam(attacker))
if (MechType(wounded) != CLASS_MW ||
MechType(attacker) == CLASS_MW)
AccumulatePilXP(attackPilot, attacker, damage / 3, 1);
damage = dam_to_pc_conversion(wounded, cause, damage);
}
if (isrear) {
if (!(MechSpecials(wounded) & SALVAGE_TECH) && (Roll() <= 5) &&
(hitloc == CTORSO || hitloc == LTORSO || hitloc == RTORSO))
tSnapTowLines = 1;
if (MechType(wounded) == CLASS_MECH) {
strcpy(rearMessage, "(Rear)");
if (Dumping(wounded) && ((hitloc == CTORSO) ||
(hitloc == LTORSO) ||
(hitloc == RTORSO)) && (cause >= 0))
if (Roll() <= 7)
tBlowDumpingAmmo = 1;
} else {
if (hitloc == FSIDE)
hitloc = BSIDE;
*rearMessage = '\0';
isrear = 0;
}
} else
*rearMessage = '\0';
/* Damage something else, ok? */
if (damage < 0) {
switch (damage) {
case -2:
was_transfer = 1;
case -1:
transfer = 1;
break;
}
damage = 0;
} else if (intDamage < 0) {
switch (intDamage) {
case -2:
was_transfer = 1;
case -1:
transfer = 1;
break;
}
intDamage = 0;
}
/* while (SectIsDestroyed(wounded, hitloc) && !kill) */
while (((!is_aero(wounded) && !GetSectInt(wounded, hitloc)) ||
(is_aero(wounded) && !GetSectArmor(wounded, hitloc))) &&
!kill) {
if (transfer && (hitloc = TransferTarget(wounded, hitloc)) >= 0
&& (MechType(wounded) == CLASS_MECH ||
MechType(wounded) == CLASS_MW ||
MechType(wounded) == CLASS_BSUIT || is_aero(wounded))) {
DamageMech(wounded, attacker, LOS, attackPilot, hitloc,
isrear, iscritical, damage == -1 ? -2 : damage,
transfer == 1 ? -2 : damage, cause, bth, wWeapIndx,
wAmmoMode, tIgnoreSwarmers);
return;
} else {
if (!((MechType(wounded) == CLASS_MECH ||
MechType(wounded) == CLASS_MW ||
MechType(wounded) == CLASS_BSUIT ||
is_aero(wounded)) &&
(hitloc = TransferTarget(wounded, hitloc)) >= 0)) {
if (is_aero(wounded) && !Destroyed(wounded)) {
/* Hurt SI instead. */
if (AeroSI(wounded) <= damage)
kill = 1;
else {
AeroSI(wounded) -= damage;
kill = -1;
}
} else
return;
}
/* Nyah. Damage transferred to waste, shooting a dead mech? */
}
}
if (C_OODing(wounded) && Roll() > 8) {
mech_ood_damage(wounded, attacker,
damage + (intDamage < 0 ? 0 : intDamage));
return;
}
if (hitloc != -1) {
ArmorStringFromIndex(hitloc, locationBuff, MechType(wounded),
MechMove(wounded));
sprintf(notificationBuff,
"for %d points of damage in the %s %s",
damage + (intDamage < 0 ? 0 : intDamage), locationBuff,
rearMessage);
} else
sprintf(notificationBuff,
"for %d points of damage in the structure.",
damage + (intDamage < 0 ? 0 : intDamage));
/* if (LOS && attackPilot != -1) */
if (LOS) {
if (!was_transfer)
mech_notify(attacker, MECHALL, tprintf("%%cgYou hit %s%%c",
notificationBuff));
else
mech_notify(attacker, MECHALL,
tprintf("%%cgDamage transfer.. %s%%c", notificationBuff));
}
if (MechType(wounded) == CLASS_MW && !was_transfer)
if (damage > 0)
if (!(damage =
armor_effect(wounded, cause, hitloc, damage,
intDamage)))
return;
mech_notify(wounded, MECHALL,
tprintf("%%ch%%cyYou have been hit %s%s%%c",
notificationBuff, was_transfer ? "(transfer)" : ""));
/* Always a good policy :-> */
if (damage > 0 && intDamage <= 0 && !was_transfer && !Fallen(wounded)) {
if (mudconf.btech_newstagger) {
StaggerDamage(wounded) += damage;
} else {
MechTurnDamage(wounded) += damage;
}
}
if ((hitloc == HEAD && MechType(wounded) == CLASS_MECH)
|| (hitloc == AERO_COCKPIT && MechType(wounded) == CLASS_AERO)) {
/* mech_notify (wounded, MECHALL,
"You take 10 points of Lethal damage!!"); */
headhitmwdamage(wounded, 1);
}
if (kill) {
if (kill == 1) {
mech_notify(wounded, MECHALL,
"The blast causes last of your craft's structural integrity disappear, blowing");
mech_notify(wounded, MECHALL, "it's pieces all over the sky!");
if (!Landed(wounded) && Started(wounded)) {
mech_notify(attacker, MECHALL,
"You shoot the craft from the sky!");
MechLOSBroadcasti(attacker, wounded,
"shoots %s from the sky!");
}
DestroyMech(wounded, attacker, !(!Landed(wounded) &&
Started(wounded)));
}
return;
}
if (damage > 0) {
if (MechType(wounded) == CLASS_MECH) {
if (!isrear && (MechSpecials(wounded) & SLITE_TECH) &&
!(MechCritStatus(wounded) & SLITE_DEST) &&
(hitloc == LTORSO || hitloc == CTORSO ||
hitloc == RTORSO)) {
/* Possibly destroy the light */
if (Roll() > 6) {
if ((MechStatus2(wounded) & SLITE_ON) ||
(Roll() > 5)) {
MechCritStatus(wounded) |= SLITE_DEST;
MechStatus2(wounded) &= ~SLITE_ON;
MechLOSBroadcast(wounded,
"'s searchlight is blown apart!");
mech_notify(wounded, MECHALL,
"%ch%cyYour searchlight is destroyed!%cn");
}
}
}
}
if (MechType(wounded) == CLASS_VEH_GROUND) {
if (!isrear && (MechSpecials(wounded) & SLITE_TECH) &&
!(MechCritStatus(wounded) & SLITE_DEST) &&
(hitloc == FSIDE)) {
/* Possibly destroy the light */
if (Roll() > 6) {
if ((MechStatus2(wounded) & SLITE_ON) ||
(Roll() > 5)) {
MechCritStatus(wounded) |= SLITE_DEST;
MechStatus2(wounded) &= ~SLITE_ON;
MechLOSBroadcast(wounded,
"'s searchlight is blown apart!");
mech_notify(wounded, MECHALL,
"%ch%cyYour searchlight is destroyed!%cn");
}
}
}
}
intDamage +=
cause_armordamage(wounded, attacker, LOS, attackPilot, isrear,
iscritical, hitloc, damage, &crits, wWeapIndx, wAmmoMode);
if (intDamage >= 0)
MechFloodsLoc(wounded, hitloc, MechZ(wounded));
if (intDamage > 0 && !is_aero(wounded)) {
intDamage =
cause_internaldamage(wounded, attacker, LOS, attackPilot,
isrear, hitloc, intDamage, cause, &crits);
if (!intDamage && !SectIsDestroyed(wounded, hitloc))
BreachLoc(attacker, wounded, hitloc);
} else
PossiblyBreach(attacker, wounded, hitloc);
if (intDamage > 0 && transfer &&
(MechType(wounded) != CLASS_BSUIT)) {
if ((hitloc = TransferTarget(wounded, hitloc)) >= 0)
DamageMech(wounded, attacker, LOS, attackPilot, hitloc,
isrear, iscritical, intDamage, -2, cause, bth,
wWeapIndx, wAmmoMode, tIgnoreSwarmers);
else {
DestroyMech(wounded, attacker, 1);
return;
}
}
} else
/* Cause _INTERNAL_ HAVOC! :-) */
/* Non-CASE things get _really_ hurt */
{
if (intDamage > 0) {
if (is_aero(wounded))
intDamage =
cause_armordamage(wounded, attacker, LOS, attackPilot,
isrear, iscritical, hitloc,
intDamage, &crits, wWeapIndx, wAmmoMode);
else
intDamage =
cause_internaldamage(wounded, attacker, LOS,
attackPilot, isrear, hitloc, intDamage, cause, &crits);
if (!SectIsDestroyed(wounded, hitloc))
PossiblyBreach(attacker, wounded, hitloc);
if (intDamage > 0 && transfer &&
!((MechSections(wounded)[hitloc].config & CASE_TECH) ||
(MechSpecials(wounded) & CLAN_TECH))) {
if ((hitloc = TransferTarget(wounded, hitloc)) >= 0) {
if (!is_aero(wounded))
DamageMech(wounded, attacker, LOS, attackPilot,
hitloc, isrear, iscritical, -2,
intDamage, cause, bth, wWeapIndx, wAmmoMode,
tIgnoreSwarmers);
else
DamageMech(wounded, attacker, LOS, attackPilot,
hitloc, isrear, iscritical, intDamage,
-2, cause, bth, wWeapIndx, wAmmoMode,
tIgnoreSwarmers);
} else {
DestroyMech(wounded, attacker, 1);
return;
}
}
}
}
/* Check to see if the tow lines should snap */
if (tSnapTowLines && (MechCarrying(wounded) > 0)) {
if ((towTarget = getMech(MechCarrying(wounded)))) {
mech_notify(wounded, MECHALL,
"The hit causes your tow line to let go!");
mech_notify(towTarget, MECHALL,
"Your tow lines go suddenly slack!");
MechLOSBroadcast(wounded,
"'s tow lines release and flap freely behind it!");
mech_dropoff(GOD, wounded, "");
}
}
/* Check to see if we blow up ammo that's dumping. */
if (tBlowDumpingAmmo) {
BlowDumpingAmmo(wounded, attacker, hitloc);
}
}
/* this takes care of setting all the criticals to CRIT_DESTROYED */
void DestroyWeapon(MECH * wounded, int hitloc, int type, int startCrit,
int numcrits, int totalcrits)
{
int i;
char sum = 0;
char destroyed = 0;
for (i = startCrit; i < NUM_CRITICALS; i++) {
if (GetPartType(wounded, hitloc, i) == type) {
if (PartIsDamaged(wounded, hitloc, i)) {
DestroyPart(wounded, hitloc, i);
} else if (destroyed < numcrits) {
DestroyPart(wounded, hitloc, i);
destroyed++;
} else {
BreakPart(wounded, hitloc, i);
}
sum++;
if (sum == totalcrits)
return;
}
}
}
int CountWeaponsInLoc(MECH * mech, int loc)
{
int i;
int j, sec, cri;
int count = 0;
j = FindWeaponNumberOnMech(mech, 1, &sec, &cri);
for (i = 2; j != -1; i++) {
if (sec == loc)
count++;
j = FindWeaponNumberOnMech(mech, i, &sec, &cri);
}
return count;
}
int FindWeaponTypeNumInLoc(MECH * mech, int loc, int num)
{
int i;
int j, sec, cri;
int count = 0;
j = FindWeaponNumberOnMech(mech, 1, &sec, &cri);
for (i = 2; j != -1; i++) {
if (sec == loc) {
count++;
if (count == num)
return j;
}
j = FindWeaponNumberOnMech(mech, i, &sec, &cri);
}
return -1;
}
void LoseWeapon(MECH * mech, int hitloc)
{
/* Look for hit locations.. */
int i = CountWeaponsInLoc(mech, hitloc);
int a, b;
int firstCrit;
if (!i)
return;
a = random() % i + 1;
b = FindWeaponTypeNumInLoc(mech, hitloc, a);
if (b < 0)
return;
firstCrit =
FindFirstWeaponCrit(mech, hitloc, -1, 0, I2Weapon(b),
GetWeaponCrits(mech, b));
DestroyWeapon(mech, hitloc, I2Weapon(b), firstCrit, 1,
GetWeaponCrits(mech, b));
mech_notify(mech, MECHALL, tprintf("%%ch%%crYour %s is destroyed!%%c",
&MechWeapons[b].name[3]));
}
void DestroyHeatSink(MECH * mech, int hitloc)
{
/* This can be done easily, or this can be done painfully. */
/* Let's try the painful way, it's more fun that way. */
int num;
int i = I2Special(HEAT_SINK);
if (FindObj(mech, hitloc, i)) {
num = HS_Size(mech);
DestroyWeapon(mech, hitloc, i, 0, 1, num);
MechRealNumsinks(mech) -= MAX(num, 2);
mech_notify(mech, MECHALL,
"The computer shows a heatsink died due to the impact.");
}
}
void DestroySection(MECH * wounded, MECH * attacker, int LOS, int hitloc)
{
char locname[30];
char msgbuf[MBUF_SIZE];
int i, j;
int tKillMech;
int tIsLeg = ((hitloc == RLEG || hitloc == LLEG) ||
((hitloc == RARM || hitloc == LARM)
&& (MechIsQuad(wounded))));
dbref wounded_pilot = MechPilot(wounded);
/* Prevent the rare occurance of a section getting destroyed twice */
if (SectIsDestroyed(wounded, hitloc)) {
fprintf(stderr, "Double-desting section %d on mech #%d\n",
hitloc, wounded->mynum);
if (IsDS(wounded))
return;
for (i = 0; i < NUM_SECTIONS; i++)
if (GetSectOInt(wounded, i) && GetSectInt(wounded, i))
return;
if (muxevent_count_type_data(EVENT_NUKEMECH, (void *) wounded)) {
fprintf(stderr, "And nuke event already existed.\n");
return;
}
discard_mw(wounded);
}
/* Ouch. They got toasted */
SetSectArmor(wounded, hitloc, 0);
SetSectInt(wounded, hitloc, 0);
SetSectRArmor(wounded, hitloc, 0);
SetSectDestroyed(wounded, hitloc);
MechSections(wounded)[hitloc].specials = 0;
/* Tell the attacker about it... */
if (attacker) {
ArmorStringFromIndex(hitloc, locname, MechType(wounded),
MechMove(wounded));
if (LOS >= 0)
mech_notify(wounded, MECHALL,
tprintf("Your %s has been destroyed!", locname));
sprintf(msgbuf, "'s %s has been destroyed!", locname);
MechLOSBroadcast(wounded, msgbuf);
}
/* Destroy everything in the loc */
DestroyParts(attacker, wounded, hitloc, 0, 0);
checkECM(wounded);
/* Stop lateral if we're a quad */
if ((MechType(wounded) == CLASS_MECH) && MechIsQuad(wounded))
if (MechLateral(wounded) && tIsLeg)
MechLateral(wounded) = 0;
/* Check to see if we should destroy the unit */
if (MechType(wounded) == CLASS_BSUIT) {
if (CountBSuitMembers(wounded) > 0)
goto skip_nuke;
else if (!Destroyed(wounded))
DestroyMech(wounded, attacker, 1);
} else {
for (i = 0; i < NUM_SECTIONS; i++)
if (GetSectOInt(wounded, i) && GetSectInt(wounded, i))
goto skip_nuke;
}
/* Ensure the template's timely demise */
if (In_Character(wounded->mynum)) {
/* Clear the freqs on the unit... */
for (j = 0; j < FREQS; j++) {
wounded->freq[j] = 0;
wounded->freqmodes[j] = 0;
wounded->chantitle[j][0] = 0;
}
/* There's a 25% chance of bsuit pilots living through it */
if ((MechType(wounded) == CLASS_BSUIT) &&
(Number(1, 100) <= 25) && wounded_pilot)
autoeject(wounded_pilot, wounded, 1);
else
KillMechContentsIfIC(wounded->mynum);
/* Schedule removal of the template */
if (!IsDS(wounded))
discard_mw(wounded);
}
/* We've done everything we should do... */
return;
skip_nuke:
/* Add 4 MW damage if it's a MW loosing a location */
if (MechType(wounded) == CLASS_MW) {
mwlethaldam(wounded, 4);
}
/* If it's a MW or a mech, let's see if there's additional stuff we need to do */
if (MechType(wounded) == CLASS_MW || MechType(wounded) == CLASS_MECH) {
if (hitloc == LTORSO)
DestroySection(wounded, attacker, LOS, LARM);
else if (hitloc == RTORSO)
DestroySection(wounded, attacker, LOS, RARM);
else if (hitloc == CTORSO || hitloc == HEAD) {
if (!Destroyed(wounded))
DestroyMech(wounded, attacker, 1);
/* If it's the head or a MW's CT, kill the contents if IC */
if (hitloc == HEAD || ((MechType(wounded) == CLASS_MW) &&
(hitloc == CTORSO))) {
if (In_Character(wounded->mynum)) {
for (j = 0; j < FREQS; j++) {
wounded->freq[j] = 0;
wounded->freqmodes[j] = 0;
wounded->chantitle[j][0] = 0;
}
KillMechContentsIfIC(wounded->mynum);
}
}
if (MechType(wounded) == CLASS_MW)
discard_mw(wounded);
}
return;
}
/* If we're an aero... */
if (is_aero(wounded)) {
/* Aero handling is trivial ; No destruction whatsoever, for now. */
/* With one exception.. */
if (hitloc == COCKPIT && MechType(wounded) == CLASS_AERO) {
if (!Destroyed(wounded))
DestroyMech(wounded, attacker, 1);
for (j = 0; j < FREQS; j++) {
wounded->freq[j] = 0;
wounded->freqmodes[j] = 0;
wounded->chantitle[j][0] = 0;
}
KillMechContentsIfIC(wounded->mynum);
}
return;
}
/* Last check to see if we destroy the unit... vehicle stuff */
if (TransferTarget(wounded, 0) < 0)
tKillMech = 1;
else
tKillMech = 0;
switch (MechType(wounded)) {
case CLASS_BSUIT:
tKillMech = 0;
break;
case CLASS_VEH_GROUND:
if (hitloc == TURRET) {
tKillMech = 0;
MechStatus2(wounded) &= ~AUTOTURN_TURRET;
} else
tKillMech = 1;
break;
case CLASS_VTOL:
if (hitloc == ROTOR) {
tKillMech = 0;
StartVTOLCrash(wounded);
} else
tKillMech = 1;
break;
}
if (tKillMech) {
if (!Destroyed(wounded))
DestroyMech(wounded, attacker, 1);
}
}
char *setarmorstatus_func(MECH * mech,
char *sectstr, char *typestr, char *valuestr)
{
int index, type, value;
if (!sectstr || !*sectstr)
return "#-1 INVALID SECTION";
index =
ArmorSectionFromString(MechType(mech), MechMove(mech), sectstr);
if (index == -1 || !GetSectOInt(mech, index))
return "#-1 INVALID SECTION";
if ((value = atoi(valuestr)) < 0 || value > 255)
return "#-1 INVALID ARMORVALUE";
switch (type = atoi(typestr)) {
case 0:
SetSectArmor(mech, index, value);
break;
case 1:
SetSectInt(mech, index, value);
break;
case 2:
SetSectRArmor(mech, index, value);
break;
default:
return "#-1 INVALID ARMORTYPE";
}
return "1";
}
int dodamage_func(dbref player,
MECH * mech,
int totaldam,
int clustersize,
int direction, int iscritical, char *mechmsg, char *mechbroadcast)
{
int hitloc = 1, this_time, isrear = 0, dummy = 0;
int *dummy1 = &dummy, *dummy2 = &dummy;
if (direction < 8) {
hitloc = direction;
} else if (direction < 16) {
hitloc = direction - 8;
isrear = 1;
} else if (direction > 21) {
return 0;
}
if (mechmsg && *mechmsg)
mech_notify(mech, MECHALL, mechmsg);
if (mechbroadcast && *mechbroadcast)
MechLOSBroadcast(mech, mechbroadcast);
while (totaldam) {
if (direction > 18)
isrear = 1;
if (direction > 15)
hitloc =
FindHitLocation(mech, ((direction - 1) & 3) + 1, dummy1,
dummy2);
this_time = MIN(clustersize, totaldam);
DamageMech(mech, mech, 0, -1, hitloc, isrear, iscritical,
this_time, 0, 0, 0, -1, 0, 1);
totaldam -= this_time;
}
return 1;
}
void mech_damage(dbref player, MECH * mech, char *buffer)
{
char *args[5];
int damage, clustersize;
int isrear, iscritical;
DOCHECK(mech_parseattributes(buffer, args, 5) != 4,
"Invalid arguments!");
DOCHECK(Readnum(damage, args[0]), "Invalid damage!");
DOCHECK(Readnum(clustersize, args[1]), "Invalid cluster size!");
DOCHECK(Readnum(isrear, args[2]), "Invalid isrear flag!");
DOCHECK(Readnum(iscritical, args[3]), "Invalid iscritical flag!");
DOCHECK(damage <= 0 || damage > 1000, "Invalid damage!");
DOCHECK(clustersize <= 0, "Invalid cluster size!");
DOCHECK(MechType(mech) == CLASS_MW, "No MW killings!");
Missile_Hit(mech, mech, -1, -1, isrear, iscritical, 0, -1, -1,
clustersize, damage / clustersize, 1, 0, 0, 0);
}