/*
* $Id: mech.enhanced.criticals.c,v 1.1.1.1 2005/01/11 21:18:15 kstevens Exp $
*
* 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.enhanced.criticals.h"
#include "p.mech.utils.h"
#include "p.mech.combat.h"
#include "p.mech.damage.h"
#include "p.mech.bth.h"
#include "failures.h"
void getWeapData(MECH * mech, int section, int critical, int *wWeapIndex,
int *wWeapSize, int *wFirstCrit)
{
int wCritType = 0;
/* Get the crit type */
wCritType = GetPartType(mech, section, critical);
/* Get the weapon index */
*wWeapIndex = Weapon2I(wCritType);
/* Get the max number of crits for this weapon */
*wWeapSize = GetWeaponCrits(mech, *wWeapIndex);
/* Find the first crit */
*wFirstCrit =
FindFirstWeaponCrit(mech, section, critical, 0, wCritType,
*wWeapSize);
}
int getCritAddedBTH(MECH * mech, int section, int critical,
int rangeBracket)
{
int wWeapSize = 0;
int wFirstCrit = 0;
int wWeapIndex = 0;
int i;
int wRetMod = 0;
if (MechType(mech) != CLASS_MECH)
return 0;
getWeapData(mech, section, critical, &wWeapIndex, &wWeapSize,
&wFirstCrit);
/* Iterate over the crits and see if we have any enhanced damage */
for (i = wFirstCrit; i < (wFirstCrit + wWeapSize); i++) {
if (GetPartDamageFlags(mech, section, i) & WEAP_DAM_MODERATE)
wRetMod++;
if (((GetPartDamageFlags(mech, section, i) & WEAP_DAM_EN_FOCUS) ||
(GetPartDamageFlags(mech, section,
i) & WEAP_DAM_MSL_RANGING)) &&
(rangeBracket != RANGE_SHORT))
wRetMod++;
}
return wRetMod;
}
int getCritAddedHeat(MECH * mech, int section, int critical)
{
int wWeapSize = 0;
int wFirstCrit = 0;
int wWeapIndex = 0;
int i;
int wRetMod = 0;
getWeapData(mech, section, critical, &wWeapIndex, &wWeapSize,
&wFirstCrit);
if (!IsEnergy(wWeapIndex))
return 0;
/* Iterate over the crits and see if we have any enhanced damage */
for (i = wFirstCrit; i < (wFirstCrit + wWeapSize); i++) {
if (GetPartDamageFlags(mech, section, i) & WEAP_DAM_EN_CRYSTAL)
wRetMod++;
}
return wRetMod;
}
int getCritSubDamage(MECH * mech, int section, int critical)
{
int wWeapSize = 0;
int wFirstCrit = 0;
int wWeapIndex = 0;
int i;
int wRetMod = 0;
if (MechType(mech) != CLASS_MECH)
return 0;
getWeapData(mech, section, critical, &wWeapIndex, &wWeapSize,
&wFirstCrit);
if (!IsEnergy(wWeapIndex))
return 0;
/* Iterate over the crits and see if we have any enhanced damage */
for (i = wFirstCrit; i < (wFirstCrit + wWeapSize); i++) {
if (GetPartDamageFlags(mech, section, i) & WEAP_DAM_EN_FOCUS)
wRetMod++;
}
return wRetMod;
}
int canWeapExplodeFromDamage(MECH * mech, int section, int critical,
int roll)
{
int wWeapSize = 0;
int wFirstCrit = 0;
int wWeapIndex = 0;
int i;
int wExplosionCheck = 0;
if (MechType(mech) != CLASS_MECH)
return 0;
getWeapData(mech, section, critical, &wWeapIndex, &wWeapSize,
&wFirstCrit);
/* Iterate over the crits and see if we have any enhanced damage */
for (i = wFirstCrit; i < (wFirstCrit + wWeapSize); i++) {
if ((GetPartDamageFlags(mech, section, i) & WEAP_DAM_EN_CRYSTAL) ||
(GetPartDamageFlags(mech, section, i) & WEAP_DAM_BALL_AMMO) ||
(GetPartDamageFlags(mech, section, i) & WEAP_DAM_MSL_AMMO))
wExplosionCheck++;
}
if (wExplosionCheck > 0)
wExplosionCheck += 1;
return wExplosionCheck >= roll;
}
int canWeapJamFromDamage(MECH * mech, int section, int critical, int roll)
{
int wWeapSize = 0;
int wFirstCrit = 0;
int wWeapIndex = 0;
int i;
int wJamCheck = 0;
if (MechType(mech) != CLASS_MECH)
return 0;
getWeapData(mech, section, critical, &wWeapIndex, &wWeapSize,
&wFirstCrit);
/* Iterate over the crits and see if we have any enhanced damage */
for (i = wFirstCrit; i < (wFirstCrit + wWeapSize); i++) {
if (GetPartDamageFlags(mech, section, i) & WEAP_DAM_BALL_BARREL)
wJamCheck++;
}
if (wJamCheck > 0)
wJamCheck += 1;
return wJamCheck >= roll;
}
int isWeapAmmoFeedLocked(MECH * mech, int section, int critical)
{
int wWeapSize = 0;
int wFirstCrit = 0;
int wWeapIndex = 0;
int i;
if (MechType(mech) != CLASS_MECH)
return 0;
getWeapData(mech, section, critical, &wWeapIndex, &wWeapSize,
&wFirstCrit);
/* Iterate over the crits and see if we have any enhanced damage */
for (i = wFirstCrit; i < (wFirstCrit + wWeapSize); i++) {
if ((GetPartDamageFlags(mech, section, i) & WEAP_DAM_BALL_AMMO) ||
(GetPartDamageFlags(mech, section, i) & WEAP_DAM_MSL_AMMO))
return 1;
}
return 0;
}
int countDamagedSlotsFromCrit(MECH * mech, int section, int critical)
{
int wWeapSize = 0;
int wFirstCrit = 0;
int wWeapIndex = 0;
getWeapData(mech, section, critical, &wWeapIndex, &wWeapSize,
&wFirstCrit);
return countDamagedSlots(mech, section, wFirstCrit, wWeapSize);
}
int countDamagedSlots(MECH * mech, int section, int wFirstCrit,
int wWeapSize)
{
int wCritsDamaged = 0;
int i;
for (i = wFirstCrit; i < (wFirstCrit + wWeapSize); i++) {
if (PartIsDamaged(mech, section, i))
wCritsDamaged++;
}
return wCritsDamaged;
}
int shouldDestroyWeapon(MECH * mech, int section, int critical,
int incrementCount)
{
int wCritsDamaged = 0;
int wWeapSize = 0;
int wFirstCrit = 0;
int wWeapIndex = 0;
if (MechType(mech) != CLASS_MECH)
return 1;
getWeapData(mech, section, critical, &wWeapIndex, &wWeapSize,
&wFirstCrit);
if (incrementCount)
wCritsDamaged++;
wCritsDamaged +=
countDamagedSlots(mech, section, wFirstCrit, wWeapSize);
if ((wCritsDamaged * 2) > wWeapSize)
return 1;
return 0;
}
void scoreEnhancedWeaponCriticalHit(MECH * mech, MECH * attacker, int LOS,
int section, int critical)
{
int wWeapSize = 0;
int wFirstCrit = 0;
int wWeapIndex = 0;
int wCritRoll = Roll();
int tDestroyWeapon = 0;
int tNoCrit = 0;
int tModerateCrit = 0;
getWeapData(mech, section, critical, &wWeapIndex, &wWeapSize,
&wFirstCrit);
/* See if we should just destroy the sucker outright */
if (shouldDestroyWeapon(mech, section, critical, 1))
tDestroyWeapon = 1;
else {
/* Add the total number of damaged slots */
wCritRoll +=
countDamagedSlots(mech, section, wFirstCrit, wWeapSize);
wCritRoll++;
}
if (!tDestroyWeapon) {
/* See what damage we do */
if (IsEnergy(wWeapIndex)) {
if (wCritRoll <= 3) {
tNoCrit = 1;
} else if (wCritRoll <= 5) {
tModerateCrit = 1;
} else if (wCritRoll <= 7) {
mech_notify(mech, MECHALL,
tprintf
("Your %s's focusing mechanism gets knocked out of alignment!!",
&MechWeapons[wWeapIndex].name[3]));
GetPartDamageFlags(mech, section, critical) |=
WEAP_DAM_EN_FOCUS;
} else if (wCritRoll <= 9) {
mech_notify(mech, MECHALL,
tprintf
("Your %s's charging crystal takes a direct hit!!",
&MechWeapons[wWeapIndex].name[3]));
GetPartDamageFlags(mech, section, critical) |=
WEAP_DAM_EN_CRYSTAL;
} else {
tDestroyWeapon = 1;
}
} else if (IsMissile(wWeapIndex)) {
if (wCritRoll <= 3) {
tNoCrit = 1;
} else if (wCritRoll <= 5) {
tModerateCrit = 1;
} else if (wCritRoll <= 7) {
mech_notify(mech, MECHALL,
tprintf("Your %s's ranging system takes a hit!!",
&MechWeapons[wWeapIndex].name[3]));
GetPartDamageFlags(mech, section, critical) |=
WEAP_DAM_MSL_RANGING;
} else if (wCritRoll <= 9) {
mech_notify(mech, MECHALL,
tprintf("Your %s's ammo feed is damaged!!",
&MechWeapons[wWeapIndex].name[3]));
GetPartDamageFlags(mech, section, critical) |=
WEAP_DAM_MSL_AMMO;
} else {
tDestroyWeapon = 1;
}
} else if (IsBallistic(wWeapIndex) || IsArtillery(wWeapIndex)) {
if (wCritRoll <= 3) {
tNoCrit = 1;
} else if (wCritRoll <= 5) {
tModerateCrit = 1;
} else if (wCritRoll <= 7) {
mech_notify(mech, MECHALL,
tprintf("Your %s's barrel warps from the damage!!",
&MechWeapons[wWeapIndex].name[3]));
GetPartDamageFlags(mech, section, critical) |=
WEAP_DAM_BALL_BARREL;
} else if (wCritRoll <= 9) {
mech_notify(mech, MECHALL,
tprintf("Your %s's ammo feed is damaged!!",
&MechWeapons[wWeapIndex].name[3]));
GetPartDamageFlags(mech, section, critical) |=
WEAP_DAM_BALL_AMMO;
} else {
tDestroyWeapon = 1;
}
} else {
tDestroyWeapon = 1;
}
}
if (tDestroyWeapon) {
mech_notify(mech, MECHALL, tprintf("Your %s has been destroyed!!",
&MechWeapons[wWeapIndex].name[3]));
DestroyWeapon(mech, section, GetPartType(mech, section, critical),
wFirstCrit, 1, wWeapSize);
} else {
DamagePart(mech, section, critical);
if (tNoCrit)
mech_notify(mech, MECHALL,
tprintf
("Your %s takes a hit but suffers no noticeable damage!!",
&MechWeapons[wWeapIndex].name[3]));
else if (tModerateCrit) {
mech_notify(mech, MECHALL,
tprintf("Your %s takes a hit but continues working!!",
&MechWeapons[wWeapIndex].name[3]));
GetPartDamageFlags(mech, section, critical) |=
WEAP_DAM_MODERATE;
}
}
}
void mech_weaponstatus(dbref player, MECH * mech, char *buffer)
{
int secIter = 0;
int weapIter = 0;
int wWeapsInSec = 0;
int wcWeaps = 0;
int wDamagedSlots = 0;
unsigned char weaparray[MAX_WEAPS_SECTION];
unsigned char weapdata[MAX_WEAPS_SECTION];
int critical[MAX_WEAPS_SECTION];
char tempbuff[160];
char strLocation[80];
char weapbuff[120];
cch(MECH_USUALSP);
notify(player,
"=========================WEAPON SYSTEMS STATUS=========================");
notify(player,
"[##] -------- Weapon Name -------- || Location -------- || Status -----");
for (secIter = 0; secIter < NUM_SECTIONS; secIter++) {
wWeapsInSec =
FindWeapons(mech, secIter, weaparray, weapdata, critical);
if (wWeapsInSec <= 0)
continue;
ArmorStringFromIndex(secIter, tempbuff, MechType(mech),
MechMove(mech));
sprintf(strLocation, "%-18.18s", tempbuff);
for (weapIter = 0; weapIter < wWeapsInSec; weapIter++) {
sprintf(weapbuff, "[%2d] %-29.29s || ", wcWeaps++,
&MechWeapons[weaparray[weapIter]].name[3]);
strcat(weapbuff, strLocation);
wDamagedSlots = 0;
if (PartIsBroken(mech, secIter, critical[weapIter]) ||
PartTempNuke(mech, secIter,
critical[weapIter]) == FAIL_DESTROYED)
strcat(weapbuff, "|| %ch%cxDESTROYED%c");
else {
if (MechType(mech) == CLASS_MECH)
wDamagedSlots =
countDamagedSlotsFromCrit(mech, secIter,
critical[weapIter]);
if (PartIsDisabled(mech, secIter, critical[weapIter]))
strcat(weapbuff, "|| %crDISABLED%c");
else if (PartTempNuke(mech, secIter, critical[weapIter])) {
switch (PartTempNuke(mech, secIter,
critical[weapIter])) {
case FAIL_JAMMED:
strcat(weapbuff, "|| %crJAMMED%c");
break;
case FAIL_SHORTED:
strcat(weapbuff, "|| %crSHORTED%c");
break;
case FAIL_EMPTY:
strcat(weapbuff, "|| %crEMPTY%c");
break;
case FAIL_DUD:
strcat(weapbuff, "|| %crDUD%c");
break;
case FAIL_AMMOJAMMED:
strcat(weapbuff, "|| %crAMMOJAM%c");
break;
}
} else if (wDamagedSlots > 0)
strcat(weapbuff, "|| %cr%chDAMAGED%c");
else
strcat(weapbuff, "|| %cg%chOPERATIONAL%cn");
}
notify(player, weapbuff);
showWeaponDamageAndInfo(player, mech, secIter,
critical[weapIter]);
}
}
}
void showWeaponDamageAndInfo(dbref player, MECH * mech, int section,
int critical)
{
int wWeapSize = 0;
int wFirstCrit = 0;
int wWeapIndex = 0;
int awDamage[3];
int i;
int tHasDamagedPart = 0;
int tPrintSpace = 0;
int wAmmoLoc = GetPartDesiredAmmoLoc(mech, section, critical);
char strLocation[80];
int awNonOpCrits[3];
getWeapData(mech, section, critical, &wWeapIndex, &wWeapSize,
&wFirstCrit);
for (i = 0; i < 3; i++) {
awDamage[i] = 0;
awNonOpCrits[i] = 0;
}
for (i = wFirstCrit; i < (wFirstCrit + wWeapSize); i++) {
if (PartIsDamaged(mech, section, i)) {
tHasDamagedPart = 1;
awDamage[0] +=
GetPartDamageFlags(mech, section, i) & WEAP_DAM_MODERATE;
awDamage[1] +=
((GetPartDamageFlags(mech, section, i) & WEAP_DAM_EN_FOCUS)
|| (GetPartDamageFlags(mech, section,
i) & WEAP_DAM_BALL_BARREL) ||
(GetPartDamageFlags(mech, section,
i) & WEAP_DAM_MSL_RANGING));
awDamage[2] +=
((GetPartDamageFlags(mech, section,
i) & WEAP_DAM_EN_CRYSTAL) ||
(GetPartDamageFlags(mech, section, i) & WEAP_DAM_BALL_AMMO)
|| (GetPartDamageFlags(mech, section,
i) & WEAP_DAM_MSL_AMMO));
awNonOpCrits[0]++;
} else if (PartIsDestroyed(mech, section, i)) {
awNonOpCrits[1]++;
} else if (PartIsDisabled(mech, section, i)) {
awNonOpCrits[2]++;
}
}
if (tHasDamagedPart) {
tPrintSpace = 1;
if (awDamage[0] > 0)
notify(player,
tprintf
(" %%cr%%chGeneral damage (%d hit%s): +%d to hit.",
awDamage[0], awDamage[0] > 1 ? "s" : "", awDamage[0]));
if (IsEnergy(wWeapIndex)) {
if (awDamage[1] > 0)
notify(player,
tprintf
(" %%cr%%chFocus misalignment (%d hit%s): -%d damage. +%d to hit at >%d hexes.%%c",
awDamage[1], awDamage[1] > 1 ? "s" : "",
awDamage[1], awDamage[1],
MechWeapons[wWeapIndex].shortrange));
if (awDamage[2] > 0)
notify(player,
tprintf
(" %%cr%%chCharging crystal damage (%d hit%s): +%d heat. Explodes on %d or less.%%c",
awDamage[2], awDamage[2] > 1 ? "s" : "",
awDamage[2], awDamage[2] + 1));
} else if (IsMissile(wWeapIndex)) {
if (awDamage[1] > 0)
notify(player,
tprintf
(" %%cr%%chRanging system damage (%d hit%s): +%d to hit at >%d hexes.%%c",
awDamage[1], awDamage[1] > 1 ? "s" : "",
awDamage[1], MechWeapons[wWeapIndex].shortrange));
if (awDamage[2] > 0)
notify(player,
tprintf
(" %%cr%%chAmmo feed damage (%d hit%s): Can't switch ammo. Explodes on %d or less.%%c",
awDamage[2], awDamage[2] > 1 ? "s" : "",
awDamage[2] + 1));
} else if (IsBallistic(wWeapIndex) || IsArtillery(wWeapIndex)) {
if (awDamage[1] > 0)
notify(player,
tprintf
(" %%cr%%chBarrel damage (%d hit%s): Jams on a %d or less.%%c",
awDamage[1], awDamage[1] > 1 ? "s" : "",
awDamage[1] + 1));
if (awDamage[2] > 0)
notify(player,
tprintf
(" %%cr%%chAmmo feed damage (%d hit%s): Can't switch ammo. Explodes on %d or less.%%c",
awDamage[2], awDamage[2] > 1 ? "s" : "",
awDamage[2] + 1));
}
if ((awDamage[0] == 0) && (awDamage[1] == 0) && (awDamage[2] == 0))
notify(player,
" %cr%chDamaged, but fully operational.%cn");
tPrintSpace = 1;
}
if (wAmmoLoc >= 0) {
ArmorStringFromIndex(wAmmoLoc, strLocation, MechType(mech),
MechMove(mech));
notify(player, tprintf(" %%cg%%chPrefered ammo source: %s%%c",
strLocation));
tPrintSpace = 1;
}
if ((awNonOpCrits[0] > 0) || (awNonOpCrits[1] > 0) ||
(awNonOpCrits[2] > 0)) {
notify(player,
tprintf
(" %%cr%%chSlot status: Damaged: %d. Destroyed: %d. Disabled: %d%%c",
awNonOpCrits[0], awNonOpCrits[1], awNonOpCrits[2]));
tPrintSpace = 1;
}
if (tPrintSpace)
notify(player, " ");
}