/*
* $Id: mech.tech.damages.c,v 1.1.1.1 2005/01/11 21:18:25 kstevens Exp $
*
* Author: Markus Stenberg <fingon@iki.fi>
*
* Copyright (c) 1996 Markus Stenberg
* Copyright (c) 1998-2002 Thomas Wouters
* Copyright (c) 2000-2002 Cord Awtry
* All rights reserved
*
* Created: Mon Dec 2 19:00:35 1996 fingon
* Last modified: Thu Sep 10 09:55:13 1998 fingon
*
*/
#include "mech.h"
#include "mech.events.h"
#include "mech.tech.h"
#include "mech.tech.damages.h"
#include "coolmenu.h"
#include "mycool.h"
#include "failures.h"
#include "p.mech.utils.h"
#include "p.mech.tech.commands.h"
#include "p.mech.status.h"
#include "p.mech.build.h"
/* 0 = type, 1 = loc, 2 = (pos/amnt), 3 = (val) */
short damage_table[MAX_DAMAGES][3];
int damage_last;
const char *repair_need_msgs[] = {
"Reattachment",
"Repairs on %s",
"Repairs on %s",
"Repairs on %s",
"Realign focus on %s",
"Charging crystal repairs on %s",
"Barrel repairs on %s",
"Ammo feed repairs on %s",
"Ranging system repairs on %s",
"Ammo feed repairs on %s",
"Replacement of %s",
"Reload of %s (%d rounds)",
"Repairs on armor (%d points)",
"Repairs on rear armor (%d points)",
"Repairs on internals (%d points)",
"Removal of section",
"Removal of %s",
"Removal of %s",
"Unload of %s (%d rounds)",
"Reseal",
"Replace suit",
};
#define CHECK(loc) check_for_damage(mech,loc)
#define DAMAGE2(a,b) do {\
damage_table[damage_last][0]=a;\
damage_table[damage_last++][1]=b;\
} while (0)
#define DAMAGE3(a,b,c) do {\
damage_table[damage_last][0]=a;\
damage_table[damage_last][1]=b;\
damage_table[damage_last++][2]=c;\
} while (0)
static int check_for_damage(MECH * mech, int loc)
{
int a, b, c, d;
if (SectIsDestroyed(mech, loc)) {
if (MechType(mech) != CLASS_BSUIT)
DAMAGE2(REATTACH, loc);
else
DAMAGE2(REPLACESUIT, loc);
return 0;
}
/*
* Added by Kipsta
* 8/4/99
*/
if (SectIsFlooded(mech, loc)) {
DAMAGE2(RESEAL, loc);
return 0;
}
if ((a = GetSectInt(mech, loc)) != (b = GetSectOInt(mech, loc)))
DAMAGE3(FIXINTERNAL, loc, (b - a));
else {
if ((a = GetSectArmor(mech, loc)) != (b =
GetSectOArmor(mech, loc)))
DAMAGE3(FIXARMOR, loc, (b - a));
if ((a = GetSectRArmor(mech, loc)) != (b =
GetSectORArmor(mech, loc)))
DAMAGE3(FIXARMOR_R, loc, (b - a));
}
for (a = 0; a < NUM_CRITICALS; a++) {
if (!(b = GetPartType(mech, loc, a)))
continue;
if (IsAmmo(b) && !PartIsDestroyed(mech, loc, a) &&
(c = GetPartData(mech, loc, a)) != (d =
FullAmmo(mech, loc, a)))
DAMAGE3(RELOAD, loc, a);
if (!PartIsNonfunctional(mech, loc, a) &&
!PartTempNuke(mech, loc, a) && !PartIsDamaged(mech, loc, a))
continue;
if (IsCrap(b))
continue;
/* Destroyed / tempnuke'd part. Either case, it works for us :) */
if (PartIsDamaged(mech, loc, a)) {
if (GetPartDamageFlags(mech, loc, a) & WEAP_DAM_EN_FOCUS)
DAMAGE3(ENHCRIT_FOCUS, loc, a);
else if (GetPartDamageFlags(mech, loc,
a) & WEAP_DAM_EN_CRYSTAL)
DAMAGE3(ENHCRIT_CRYSTAL, loc, a);
else if (GetPartDamageFlags(mech, loc,
a) & WEAP_DAM_BALL_BARREL)
DAMAGE3(ENHCRIT_BARREL, loc, a);
else if (GetPartDamageFlags(mech, loc, a) & WEAP_DAM_BALL_AMMO)
DAMAGE3(ENHCRIT_AMMOB, loc, a);
else if (GetPartDamageFlags(mech, loc,
a) & WEAP_DAM_MSL_RANGING)
DAMAGE3(ENHCRIT_RANGING, loc, a);
else if (GetPartDamageFlags(mech, loc, a) & WEAP_DAM_MSL_AMMO)
DAMAGE3(ENHCRIT_AMMOM, loc, a);
else
DAMAGE3(ENHCRIT_MISC, loc, a);
} else if (IsWeapon(b) && GetWeaponCrits(mech, Weapon2I(b)) > 4 &&
!PartIsDestroyed(mech, loc, a + 1))
DAMAGE3(REPAIRP_T, loc, a);
else
DAMAGE3(IsWeapon(b) ? REPAIRG : REPAIRP, loc, a);
if (IsWeapon(b))
a += GetWeaponCrits(mech, Weapon2I(b)) - 1;
}
return 1;
}
static int check_for_scrappage(MECH * mech, int loc)
{
int a, b;
int ret = 1;
if (SectIsDestroyed(mech, loc))
return 1;
if (SomeoneScrappingLoc(mech, loc)) {
DAMAGE2(DETACH, loc);
return 1;
}
for (a = 0; a < NUM_CRITICALS; a++) {
if (!(b = GetPartType(mech, loc, a)))
continue;
if (PartIsBroken(mech, loc, a))
continue;
if (IsCrap(b))
continue;
if (IsAmmo(b) && GetPartData(mech, loc, a)) {
DAMAGE3(UNLOAD, loc, a);
if (ret && !SomeoneRepairing(mech, loc, a))
ret = 0;
continue;
}
DAMAGE3(IsWeapon(b) ? SCRAPG : SCRAPP, loc, a);
if (ret && !SomeoneScrappingPart(mech, loc, a))
ret = 0;
if (IsWeapon(b))
a += GetWeaponCrits(mech, Weapon2I(b)) - 1;
}
if (ret && !Invalid_Scrap_Path(mech, loc))
DAMAGE2(DETACH, loc);
return 0;
}
void make_scrap_table(MECH * mech)
{
int i = 4;
damage_last = 0;
if (MechType(mech) == CLASS_MECH) {
if (check_for_scrappage(mech, RARM))
i -= check_for_scrappage(mech, RTORSO);
if (check_for_scrappage(mech, LARM))
i -= check_for_scrappage(mech, LTORSO);
i -= check_for_scrappage(mech, RLEG);
i -= check_for_scrappage(mech, LLEG);
if (!i)
check_for_scrappage(mech, CTORSO);
check_for_scrappage(mech, HEAD);
} else
for (i = 0; i < NUM_SECTIONS; i++)
if (GetSectOInt(mech, i))
check_for_scrappage(mech, i);
}
void make_damage_table(MECH * mech)
{
int i;
damage_last = 0;
if (MechType(mech) == CLASS_MECH) {
if (check_for_damage(mech, CTORSO)) {
if (check_for_damage(mech, LTORSO)) {
CHECK(LARM);
}
if (check_for_damage(mech, RTORSO)) {
CHECK(RARM);
}
CHECK(LLEG);
CHECK(RLEG);
CHECK(HEAD);
}
} else
for (i = 0; i < NUM_SECTIONS; i++)
if (GetSectOInt(mech, i))
check_for_damage(mech, i);
}
int is_under_repair(MECH * mech, int i)
{
int v1 = damage_table[i][1];
int v2 = damage_table[i][2];
switch (damage_table[i][0]) {
case RELOAD:
case REPAIRP:
case REPAIRP_T:
case REPAIRG:
case UNLOAD:
case ENHCRIT_MISC:
case ENHCRIT_FOCUS:
case ENHCRIT_CRYSTAL:
case ENHCRIT_BARREL:
case ENHCRIT_AMMOB:
case ENHCRIT_RANGING:
case ENHCRIT_AMMOM:
return SomeoneRepairing(mech, v1, v2);
case REATTACH:
return SomeoneAttaching(mech, v1);
case RESEAL:
return SomeoneResealing(mech, v1);
case FIXARMOR_R:
return SomeoneFixing(mech, v1 + 8);
case FIXARMOR:
case FIXINTERNAL:
return SomeoneFixing(mech, v1);
case DETACH:
return SomeoneScrappingLoc(mech, v1);
case SCRAPP:
case SCRAPG:
return SomeoneScrappingPart(mech, v1, v2);
case REPLACESUIT:
return SomeoneReplacingSuit(mech, v1);
}
return 0;
}
char *damages_func(MECH * mech)
{
static char buffer[MBUF_SIZE];
int i;
if (unit_is_fixable(mech))
make_damage_table(mech);
else
make_scrap_table(mech);
buffer[0] = '\0';
if (!damage_last)
return "";
for (i = 0; i < damage_last; i++) {
/* Ok... i think we want: */
/* repairnum|location|typenum|data|fixing? */
if (i)
sprintf(buffer, "%s,", buffer);
sprintf(buffer, "%s%d|%s|%d|", buffer, i + 1,
ShortArmorSectionString(MechType(mech), MechMove(mech),
damage_table[i][1]), (int) damage_table[i][0]);
switch (damage_table[i][0]) {
case REPAIRP:
case REPAIRP_T:
case REPAIRG:
case ENHCRIT_MISC:
case ENHCRIT_FOCUS:
case ENHCRIT_CRYSTAL:
case ENHCRIT_BARREL:
case ENHCRIT_AMMOB:
case ENHCRIT_RANGING:
case ENHCRIT_AMMOM:
case SCRAPP:
case SCRAPG:
sprintf(buffer, "%s%s", buffer, pos_part_name(mech,
damage_table[i][1], damage_table[i][2]));
break;
case RELOAD:
sprintf(buffer, "%s%s:%d", buffer, pos_part_name(mech,
damage_table[i][1], damage_table[i][2]), FullAmmo(mech,
damage_table[i][1],
damage_table[i][2]) - GetPartData(mech,
damage_table[i][1], damage_table[i][2]));
break;
case UNLOAD:
sprintf(buffer, "%s%s:%d", buffer, pos_part_name(mech,
damage_table[i][1], damage_table[i][2]),
GetPartData(mech, damage_table[i][1], damage_table[i]
[2]));
break;
case FIXARMOR:
case FIXARMOR_R:
case FIXINTERNAL:
sprintf(buffer, "%s%d", buffer, damage_table[i][2]);
break;
default:
sprintf(buffer, "%s-", buffer);
}
sprintf(buffer, "%s|%d", buffer, is_under_repair(mech, i));
}
return buffer;
}
void show_mechs_damage(dbref player, void *data, char *buffer)
{
MECH *mech = data;
coolmenu *c = NULL;
int i, j, v1, v2;
char buf[MBUF_SIZE];
char buf2[MBUF_SIZE];
int isds;
TECHCOMMANDD;
if (unit_is_fixable(mech))
make_damage_table(mech);
else
make_scrap_table(mech);
DOCHECK(!damage_last &&
MechType(mech) == CLASS_MECH,
"The 'mech is in pristine condition!");
DOCHECK(!damage_last, "It's in pristine condition!");
addline();
cent(tprintf("Damage for %s", GetMechID(mech)));
addline();
for (i = 0; i < damage_last; i++) {
v1 = damage_table[i][1];
v2 = damage_table[i][2];
switch (damage_table[i][0]) {
case REATTACH:
case DETACH:
case RESEAL:
case REPLACESUIT:
strcpy(buf, repair_need_msgs[(int) damage_table[i][0]]);
break;
case REPAIRP:
case REPAIRP_T:
case REPAIRG:
case ENHCRIT_MISC:
case ENHCRIT_FOCUS:
case ENHCRIT_CRYSTAL:
case ENHCRIT_BARREL:
case ENHCRIT_AMMOB:
case ENHCRIT_RANGING:
case ENHCRIT_AMMOM:
case SCRAPP:
case SCRAPG:
sprintf(buf, repair_need_msgs[(int) damage_table[i][0]],
pos_part_name(mech, v1, v2));
break;
case RELOAD:
sprintf(buf, repair_need_msgs[(int) damage_table[i][0]],
pos_part_name(mech, v1, v2), FullAmmo(mech, v1,
v2) - GetPartData(mech, v1, v2));
break;
case UNLOAD:
sprintf(buf, repair_need_msgs[(int) damage_table[i][0]],
pos_part_name(mech, v1, v2), GetPartData(mech, v1, v2));
break;
case FIXARMOR:
case FIXARMOR_R:
case FIXINTERNAL:
sprintf(buf, repair_need_msgs[(int) damage_table[i][0]],
damage_table[i][2]);
break;
}
j = is_under_repair(mech, i);
sprintf(buf2, "%%ch%s%-2d:%s %%cn%s%s", j ? "%cg" : "%cy", i + 1,
ShortArmorSectionString(MechType(mech), MechMove(mech), v1),
buf, j ? " (*)" : "");
vsi(buf2);
}
addline();
vsi("(*) / %ch%cgGreen%cn = Job already done. %ch%cyYellow%cn = To be done.");
addline();
ShowCoolMenu(player, c);
KillCoolMenu(c);
}
static void fix_entry(dbref player, MECH * mech, int n)
{
char buf[MBUF_SIZE];
char *c;
/* whee */
n--;
c = ShortArmorSectionString(MechType(mech), MechMove(mech),
damage_table[n][1]);
switch (damage_table[n][0]) {
case REPAIRP_T:
sprintf(buf, "%s %d", c, damage_table[n][2] + 1);
tech_repairgun(player, mech, buf);
break;
case ENHCRIT_MISC:
case ENHCRIT_FOCUS:
case ENHCRIT_CRYSTAL:
case ENHCRIT_BARREL:
case ENHCRIT_AMMOB:
case ENHCRIT_RANGING:
case ENHCRIT_AMMOM:
sprintf(buf, "%s %d", c, damage_table[n][2] + 1);
tech_fixenhcrit(player, mech, buf);
break;
case REPAIRG:
sprintf(buf, "%s %d", c, damage_table[n][2] + 1);
tech_replacegun(player, mech, buf);
break;
case REPAIRP:
sprintf(buf, "%s %d", c, damage_table[n][2] + 1);
tech_replacepart(player, mech, buf);
break;
case RELOAD:
sprintf(buf, "%s %d", c, damage_table[n][2] + 1);
tech_reload(player, mech, buf);
break;
case REATTACH:
sprintf(buf, "%s", c);
tech_reattach(player, mech, buf);
break;
case RESEAL:
sprintf(buf, "%s", c);
tech_reseal(player, mech, buf);
break;
case FIXARMOR:
sprintf(buf, "%s", c);
tech_fixarmor(player, mech, buf);
break;
case FIXARMOR_R:
sprintf(buf, "%s r", c);
tech_fixarmor(player, mech, buf);
break;
case FIXINTERNAL:
sprintf(buf, "%s", c);
tech_fixinternal(player, mech, buf);
break;
case DETACH:
sprintf(buf, "%s", c);
tech_removesection(player, mech, buf);
break;
case SCRAPP:
sprintf(buf, "%s %d", c, damage_table[n][2] + 1);
tech_removepart(player, mech, buf);
break;
case SCRAPG:
sprintf(buf, "%s %d", c, damage_table[n][2] + 1);
tech_removegun(player, mech, buf);
break;
case UNLOAD:
sprintf(buf, "%s %d", c, damage_table[n][2] + 1);
tech_unload(player, mech, buf);
break;
case REPLACESUIT:
sprintf(buf, "%s", c);
tech_replacesuit(player, mech, buf);
break;
}
}
void tech_fix(dbref player, void *data, char *buffer)
{
MECH *mech = data;
int n = atoi(buffer);
int low, high;
int isds;
skipws(buffer);
TECHCOMMANDC;
if (unit_is_fixable(mech))
make_damage_table(mech);
else
make_scrap_table(mech);
DOCHECK(!damage_last &&
MechType(mech) == CLASS_MECH,
"The 'mech is in pristine condition!");
DOCHECK(!damage_last, "It's in pristine condition!");
if (sscanf(buffer, "%d-%d", &low, &high) == 2) {
DOCHECK(low < 1 || low > damage_last, "Invalid low #!");
DOCHECK(high < 1 || high > damage_last, "Invalid high #!");
for (n = low; n <= high; n++)
fix_entry(player, mech, n);
return;
}
DOCHECK(n < 1 || n > damage_last, "Invalid #!");
fix_entry(player, mech, n);
}