/* This is the code that runs the parts failures. Written by: Nim 9-28-96 Parts copyright (c) 2000-2002 Thomas Wouters */ /* * $Id: failures.c,v 1.1.1.1 2005/01/11 21:18:07 kstevens Exp $ * Last modified: Sat Jun 6 21:43:52 1998 fingon */ #include <ctype.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #define _FAILURES_C #include "mech.h" #include "failures.h" #include "mech.events.h" #include "p.mech.startup.h" extern int num_def_weapons; int GetBrandIndex(int type) { if (type == -1) return COMPUTER_INDEX; if (type == -2) return RADIO_INDEX; if (IsWeapon(type)) if (type < I2Weapon(num_def_weapons)) { type = Weapon2I(type); if (MechWeapons[type].special & PCOMBAT) return -1; if (IsFlamer(type)) return FLAMMER_INDEX; if (IsEnergy(type)) return ENERGY_INDEX; if (IsAutocannon(type)) return AC_INDEX; if (IsMissile(type)) return MISSILE_INDEX; return -1; } return -1; } char *GetPartBrandName(int type, int level) { int i; if (!level) return NULL; i = GetBrandIndex(type); if (i < 0) return NULL; return brands[i * 5 / 6 + level - 1].name; } #define Conv(mech,section,critical) \ (GetBrandIndex(GetPartType(mech, section, critical)) - 1) void FailureRadioStatic(MECH * mech, int weapnum, int weaptype, int section, int critical, int roll, int *modifier, int *type) { int mod = failures[GetBrandIndex(-2) + roll - 1].data; *modifier = mod; *type = FAIL_STATIC; } static void mech_rrec_event(MUXEVENT * e) { MECH *mech = (MECH *) e->data; int val = (int) e->data2; MechRadioRange(mech) += val; if (!Destroyed(mech) && val == MechRadioRange(mech)) mech_notify(mech, MECHALL, "Your radio is now operational again."); } static void mech_srec_event(MUXEVENT * e) { MECH *mech = (MECH *) e->data; int val = (int) e->data2; int vt = val / 256; switch (vt) { case 0: MechTacRange(mech) = val; if (!Destroyed(mech)) mech_notify(mech, MECHALL, "Your tactical scanners are operational again."); break; case 1: MechLRSRange(mech) = val; if (!Destroyed(mech)) mech_notify(mech, MECHALL, "Your long-range scanners are operational again."); break; case 2: MechScanRange(mech) = val; if (!Destroyed(mech)) mech_notify(mech, MECHALL, "Your scanners are operational again."); break; } } void FailureRadioShort(MECH * mech, int weapnum, int weaptype, int section, int critical, int roll, int *modifier, int *type) { MECHEVENT(mech, EVENT_MRECOVERY, mech_rrec_event, Number(30, Number(40, 200)), (int) MechRadioRange(mech)); MechRadioRange(mech) = 0; } void FailureRadioRange(MECH * mech, int weapnum, int weaptype, int section, int critical, int roll, int *modifier, int *type) { int mod = failures[GetBrandIndex(-2) + roll - 1].data; mod = MIN(MechRadioRange(mech) - 1, mod); MECHEVENT(mech, EVENT_MRECOVERY, mech_rrec_event, Number(30, Number(40, 200)), (int) mod); MechRadioRange(mech) -= mod; } void FailureComputerShutdown(MECH * mech, int weapnum, int weaptype, int section, int critical, int roll, int *modifier, int *type) { if (Started(mech)) mech_shutdown(mech->mynum, mech, ""); } void FailureComputerScanner(MECH * mech, int weapnum, int weaptype, int section, int critical, int roll, int *modifier, int *type) { int tmp = failures[GetBrandIndex(-1) + roll - 1].data; switch (tmp) { case 1: MECHEVENT(mech, EVENT_MRECOVERY, mech_srec_event, Number(30, Number(40, 200)), (int) MechTacRange(mech)); MechTacRange(mech) = 0; break; case 2: MECHEVENT(mech, EVENT_MRECOVERY, mech_srec_event, Number(30, Number(40, 200)), MechLRSRange(mech) + 256); MechLRSRange(mech) = 0; break; case 4: MECHEVENT(mech, EVENT_MRECOVERY, mech_srec_event, Number(30, Number(40, 200)), MechScanRange(mech) + 512); MechScanRange(mech) = 0; break; case 7: MECHEVENT(mech, EVENT_MRECOVERY, mech_srec_event, Number(30, Number(40, 200)), (int) MechTacRange(mech)); MECHEVENT(mech, EVENT_MRECOVERY, mech_srec_event, Number(30, Number(40, 200)), MechLRSRange(mech) + 256); MECHEVENT(mech, EVENT_MRECOVERY, mech_srec_event, Number(30, Number(40, 200)), MechScanRange(mech) + 512); MechTacRange(mech) = 0; MechLRSRange(mech) = 0; MechScanRange(mech) = 0; break; } } void FailureComputerTarget(MECH * mech, int weapnum, int weaptype, int section, int critical, int roll, int *modifier, int *type) { MechTarget(mech) = -1; } void FailureWeaponMissiles(MECH * mech, int weapnum, int weaptype, int section, int critical, int roll, int *modifier, int *type) { SetPartTempNuke(mech, section, critical, failures[Conv(mech, section, critical) + roll].type); *type = CRAZY_MISSILES; *modifier = failures[Conv(mech, section, critical) + roll].data; } void FailureWeaponDud(MECH * mech, int weapnum, int weaptype, int section, int critical, int roll, int *modifier, int *type) { if (failures[Conv(mech, section, critical) + roll].type == FAIL_NONE) { SetRecyclePart(mech, section, critical, MechWeapons[weaptype].vrt); return; } SetPartTempNuke(mech, section, critical, failures[Conv(mech, section, critical) + roll].type); *type = WEAPON_DUD; if (roll == 6) { SetPartTempNuke(mech, section, critical, FAIL_DESTROYED); } SetRecyclePart(mech, section, critical, 30 + Number(1, 60)); } void FailureWeaponJammed(MECH * mech, int weapnum, int weaptype, int section, int critical, int roll, int *modifier, int *type) { SetPartTempNuke(mech, section, critical, failures[Conv(mech, section, critical) + roll].type); *type = WEAPON_JAMMED; SetRecyclePart(mech, section, critical, Number(20, 40)); } void FailureWeaponRange(MECH * mech, int weapnum, int weaptype, int section, int critical, int roll, int *modifier, int *type) { *modifier = (int) (EGunRangeWithCheck(mech, section, weaptype) * (failures[Conv(mech, section, critical) + roll].data / 100.0)); *type = RANGE; } void FailureWeaponDamage(MECH * mech, int weapnum, int weaptype, int section, int critical, int roll, int *modifier, int *type) { *modifier = (int) (MechWeapons[weaptype].damage * (failures[Conv(mech, section, critical) + roll].data / 100.0)); *type = DAMAGE; } void FailureWeaponHeat(MECH * mech, int weapnum, int weaptype, int section, int critical, int roll, int *modifier, int *type) { *modifier = (int) MechWeapons[weaptype].heat * (failures[Conv(mech, section, critical) + roll].data / 100.0); *type = HEAT; } void FailureWeaponSpike(MECH * mech, int weapnum, int weaptype, int section, int critical, int roll, int *modifier, int *type) { SetPartTempNuke(mech, section, critical, failures[Conv(mech, section, critical) + roll].type); *type = POWER_SPIKE; if (roll == 6) { SetPartTempNuke(mech, section, critical, FAIL_DESTROYED); return; } SetRecyclePart(mech, section, critical, Number(20, 40)); } void CheckGenericFail(MECH * mech, int type, int *result, int *mod) { int i = GetBrandIndex(type); int l = type == -1 ? MechComputer(mech) : MechRadio(mech); int roll, in; if (result) *result = FAIL_NONE; if (i < 0) return; if (mudconf.btech_parts) { if (!l) l = 5; } else return; if (Number(1, 5000) != 42) return; /* ~1/5000 chance */ if (Number(1, 100) <= brands[(i + l - 1) * 5 / 6].success) return; roll = Number(1, 6); if (roll == 6) roll = Number(1, 6); in = i + roll - 1; switch (failures[in].flag) { case REQ_TARGET: if (MechTarget(mech) <= 0) return; break; case REQ_TAC: if (MechTacRange(mech) == 0) return; break; case REQ_LRS: if (MechLRSRange(mech) == 0) return; break; case REQ_SCANNERS: if (MechTacRange(mech) == 0 || MechLRSRange(mech) == 0 || MechScanRange(mech) == 0) return; break; case REQ_COMPUTER: /* */ break; case REQ_RADIO: if (MechRadioRange(mech) == 0) return; break; } if (failures[in].message && strcmp(failures[in].message, "none")) mech_notify(mech, MECHALL, failures[in].message); failures[in].func(mech, -1, -1, -1, -1, roll, mod, result); } void CheckWeaponFailed(MECH * mech, int weapnum, int weaptype, int section, int critical, int *modifier, int *type) { short roll; int l = GetPartBrand(mech, section, critical); int t = GetPartType(mech, section, critical); int i = GetBrandIndex(t), in; *type = FAIL_NONE; if (i < 0) return; if (mudconf.btech_parts) { if (!l) l = 5; if (MechWeapons[Weapon2I(t)].special & PCOMBAT) return; } else return; if (Number(1, 10) < 9) return; if (Number(1, 100) <= brands[(i + l - 1) * 5 / 6].success) return; roll = Number(1, 6); if (roll == 6) roll = Number(1, 6); in = i + roll - 1; if (failures[in].flag & REQ_HEAT) if (!MechWeapons[weaptype].heat) return; if (failures[in].message && strcmp(failures[in].message, "none")) mech_notify(mech, MECHALL, failures[in].message); failures[in].func(mech, weapnum, weaptype, section, critical, roll, modifier, type); }