/* * $Id: mech.tech.do.c,v 1.4 2005/06/24 04:39:08 av1-op 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: Sun Sep 1 16:21:57 1996 fingon * Last modified: Thu Jul 9 20:39:04 1998 fingon * */ /* All the *_{succ|fail|econ} functions belong here */ #include "config.h" #include "mech.h" #include "muxevent.h" #include "mech.events.h" #include "mech.tech.h" #include "p.econ.h" #include "p.mech.tech.h" #include "p.mech.status.h" #include "p.mech.utils.h" #define PARTCHECK_SUB(m,a,b,c) \ AVCHECKM(m,a,b,c); \ GrabPartsM(m,a,b,c); #ifndef BT_COMPLEXREPAIRS #define PARTCHECK(m,a,b,c) \ { PARTCHECK_SUB(m, alias_part(m, a), b, c); } #else #define PARTCHECK(m,a,b,c) \ { PARTCHECK_SUB(m, alias_part(m, a, loc), b, c); } #endif #define PARTCHECKTWO(m,a,b,c,d,e,f) \ AVCHECKM(m,a,b,c); \ AVCHECKM(m,d,e,f); \ GrabPartsM(m,a,b,c); \ GrabPartsM(m,d,e,f); #define PARTCHECKTHREE(m,a,b,c,d,e,f,g,h,i) \ AVCHECKM(m,a,b,c); \ AVCHECKM(m,d,e,f); \ AVCHECKM(m,g,h,i); \ GrabPartsM(m,a,b,c); \ GrabPartsM(m,d,e,f); \ GrabPartsM(m,g,h,i); #define PARTCHECKFOUR(m,a,b,c,d,e,f,g,h,i,j,k,l) \ AVCHECKM(m,a,b,c); \ AVCHECKM(m,d,e,f); \ AVCHECKM(m,g,h,i); \ AVCHECKM(m,j,k,l); \ GrabPartsM(m,a,b,c); \ GrabPartsM(m,d,e,f); \ GrabPartsM(m,g,h,i); \ GrabPartsM(m,j,k,l); static struct { char name; /* Letter identifying the ammo in 'reload' */ char *lname; /* Long name (for printing) */ int aflag; /* Flag to set on the crittype */ int rtype; /* required type flag: if non-negative, weapon has to be this type to allow this ammo */ int ntype; /* disallowed type flag: if non-negative, weapon cannot be this type to allow this ammo */ int rspec; /* required 'special' flags: if non-zero, weapon has to have at least one of these bits in the 'special' flag for it to allow this ammo */ int nspec; /* disallowes 'special' flags: if non-zero, weapon cannot have any of these bits set, in the special flag, to allow this ammo */ } ammo_types[] = { { '-', "normal", 0, -1, -1, 0, 0}, { 'L', "cluster", LBX_MODE, -1, -1, LBX, 0}, { 'A', "artemis", ARTEMIS_MODE, TMISSILE, -1, 0, DAR | NARC | INARC}, { 'N', "narc", NARC_MODE, TMISSILE, -1, 0, DAR | NARC | INARC}, { 'S', "swarm", SWARM_MODE, TMISSILE, -1, IDF, DAR | NARC | INARC}, { '1', "swarm-1", SWARM1_MODE, TMISSILE, -1, IDF, DAR | NARC | INARC}, { 'I', "inferno", INFERNO_MODE, TMISSILE, -1, 0, IDF | DAR | NARC | INARC}, { 'X', "explosive", INARC_EXPLO_MODE, TMISSILE, -1, INARC, 0}, { 'Y', "haywire", INARC_HAYWIRE_MODE, TMISSILE, -1, INARC, 0}, { 'E', "ecm", INARC_ECM_MODE, TMISSILE, -1, INARC, 0}, { 'Z', "nemesis", INARC_NEMESIS_MODE, TMISSILE, -1, INARC, 0}, { 'R', "ap", AC_AP_MODE, TAMMO, -1, RFAC, 0}, { 'F', "flechette", AC_FLECHETTE_MODE, TAMMO, -1, RFAC, 0}, { 'D', "incendiary", AC_INCENDIARY_MODE, TAMMO, -1, RFAC, 0}, { 'P', "precision", AC_PRECISION_MODE, TAMMO, -1, RFAC, 0}, { 'T', "stinger", STINGER_MODE, TMISSILE, -1, IDF, DAR}, { 0, NULL, 0, 0, 0, 0, 0} }; int valid_ammo_mode(MECH * mech, int loc, int part, int let) { int w, i; if (!IsAmmo(GetPartType(mech, loc, part)) || !let) return -1; let = toupper(let); w = Ammo2I(GetPartType(mech, loc, part)); if (MechWeapons[w].special & NOSPA) return -1; for (i = 0; ammo_types[i].name; i++) { if (ammo_types[i].name != let) continue; if (ammo_types[i].rtype >= 0 && MechWeapons[w].type != ammo_types[i].rtype) continue; if (ammo_types[i].rspec && !(MechWeapons[w].special & ammo_types[i].rspec)) continue; if (ammo_types[i].ntype >= 0 && MechWeapons[w].type == ammo_types[i].ntype) continue; if (ammo_types[i].nspec && (MechWeapons[w].special & ammo_types[i].nspec)) continue; return ammo_types[i].aflag; } return -1; } int FindAmmoType(MECH * mech, int loc, int part) { int t = GetPartType(mech, loc, part); int m = GetPartAmmoMode(mech, loc, part); int base = -1; if (!IsAmmo(t)) return t; t = Ammo2I(t); if (strstr(MechWeapons[t].name, "StreakSRM")) base = SSRM_AMMO; else if (strstr(MechWeapons[t].name, "StreakLRM")) base = SLRM_AMMO; else if (strstr(MechWeapons[t].name, "ELRM")) base = ELRM_AMMO; else if (strstr(MechWeapons[t].name, "LR_DFM")) base = LR_DFM_AMMO; else if (strstr(MechWeapons[t].name, "SR_DFM")) base = SR_DFM_AMMO; else if (strstr(MechWeapons[t].name, "LRM")) base = LRM_AMMO; else if (strstr(MechWeapons[t].name, "SRM")) base = SRM_AMMO; else if (strstr(MechWeapons[t].name, "MRM")) base = MRM_AMMO; if (!(m & AMMO_MODES)) { if (base < 0) return I2Ammo(t); else return Cargo(base); } if (m & LBX_MODE) { if (strstr(MechWeapons[t].name, "LB20")) base = LBX20_AMMO; else if (strstr(MechWeapons[t].name, "LB10")) base = LBX10_AMMO; else if (strstr(MechWeapons[t].name, "LB5")) base = LBX5_AMMO; else if (strstr(MechWeapons[t].name, "LB2")) base = LBX2_AMMO; if (base < 0) return I2Ammo(t); return Cargo(base); } if (m & AC_MODES) { if (m & AC_AP_MODE) { if (strstr(MechWeapons[t].name, "AC/2")) base = AC2_AP_AMMO; if (strstr(MechWeapons[t].name, "AC/5")) base = AC5_AP_AMMO; if (strstr(MechWeapons[t].name, "AC/10")) base = AC10_AP_AMMO; if (strstr(MechWeapons[t].name, "AC/20")) base = AC20_AP_AMMO; if (strstr(MechWeapons[t].name, "LightAC/2")) base = LAC2_AP_AMMO; if (strstr(MechWeapons[t].name, "LightAC/5")) base = LAC5_AP_AMMO; } if (m & AC_FLECHETTE_MODE) { if (strstr(MechWeapons[t].name, "AC/2")) base = AC2_FLECHETTE_AMMO; if (strstr(MechWeapons[t].name, "AC/5")) base = AC5_FLECHETTE_AMMO; if (strstr(MechWeapons[t].name, "AC/10")) base = AC10_FLECHETTE_AMMO; if (strstr(MechWeapons[t].name, "AC/20")) base = AC20_FLECHETTE_AMMO; if (strstr(MechWeapons[t].name, "LightAC/2")) base = LAC2_FLECHETTE_AMMO; if (strstr(MechWeapons[t].name, "LightAC/5")) base = LAC5_FLECHETTE_AMMO; } if (m & AC_INCENDIARY_MODE) { if (strstr(MechWeapons[t].name, "AC/2")) base = AC2_INCENDIARY_AMMO; if (strstr(MechWeapons[t].name, "AC/5")) base = AC5_INCENDIARY_AMMO; if (strstr(MechWeapons[t].name, "AC/10")) base = AC10_INCENDIARY_AMMO; if (strstr(MechWeapons[t].name, "AC/20")) base = AC20_INCENDIARY_AMMO; if (strstr(MechWeapons[t].name, "LightAC/2")) base = LAC2_INCENDIARY_AMMO; if (strstr(MechWeapons[t].name, "LightAC/5")) base = LAC5_INCENDIARY_AMMO; } if (m & AC_PRECISION_MODE) { if (strstr(MechWeapons[t].name, "AC/2")) base = AC2_PRECISION_AMMO; if (strstr(MechWeapons[t].name, "AC/5")) base = AC5_PRECISION_AMMO; if (strstr(MechWeapons[t].name, "AC/10")) base = AC10_PRECISION_AMMO; if (strstr(MechWeapons[t].name, "AC/20")) base = AC20_PRECISION_AMMO; if (strstr(MechWeapons[t].name, "LightAC/2")) base = LAC2_PRECISION_AMMO; if (strstr(MechWeapons[t].name, "LightAC/5")) base = LAC5_PRECISION_AMMO; } if (base < 0) return I2Ammo(t); return Cargo(base); } if (m & INARC_EXPLO_MODE) return Cargo(INARC_EXPLO_AMMO); else if (m & INARC_HAYWIRE_MODE) return Cargo(INARC_HAYWIRE_AMMO); else if (m & INARC_ECM_MODE) return Cargo(INARC_ECM_AMMO); else if (m & INARC_NEMESIS_MODE) return Cargo(INARC_NEMESIS_AMMO); if (base < 0) return I2Ammo(t); if (m & NARC_MODE) return Cargo(base) + NARC_LRM_AMMO - LRM_AMMO; if (m & ARTEMIS_MODE) return Cargo(base) + ARTEMIS_LRM_AMMO - LRM_AMMO; if (m & SWARM_MODE) return Cargo(base) + SWARM_LRM_AMMO - LRM_AMMO; if (m & SWARM1_MODE) return Cargo(base) + SWARM1_LRM_AMMO - LRM_AMMO; if (m & INFERNO_MODE) return Cargo(base) + INFERNO_SRM_AMMO - SRM_AMMO; if (m & STINGER_MODE) return Cargo(base) + AMMO_LRM_STINGER - LRM_AMMO; return Cargo(base); } TFUNC_LOCPOS(replace_econ) { if (IsAmmo(GetPartType(mech, loc, part))) return 0; PARTCHECK(mech, GetPartType(mech, loc, part), GetPartBrand(mech, loc, part), 1); return 0; } TFUNC_LOCPOS_VAL(reload_econ) { int ammotype = FindAmmoType(mech, loc, part); PARTCHECK(mech, ammotype, GetPartBrand(mech, loc, part), 1); return 0; } TFUNC_LOC_VAL(fixarmor_econ) { PARTCHECK(mech, ProperArmor(mech), 0, *val); return 0; } TFUNC_LOC_VAL(fixinternal_econ) { PARTCHECK(mech, ProperInternal(mech), 0, *val); return 0; } TFUNC_LOCPOS(repair_econ) { if (IsAmmo(GetPartType(mech, loc, part))) return 0; PARTCHECKTWO(mech, Cargo(S_ELECTRONIC), 0, PartIsDestroyed(mech, loc, part) ? 3 : 1, ProperInternal(mech), 0, PartIsDestroyed(mech, loc, part) ? 3 : 1); return 0; } TFUNC_LOCPOS(repairenhcrit_econ) { PARTCHECK(mech, Cargo(S_ELECTRONIC), 0, 1); return 0; } TFUNC_LOC(reattach_econ) { #ifndef BT_COMPLEXREPAIRS PARTCHECKTWO(mech, ProperInternal(mech), 0, GetSectOInt(mech, loc), Cargo(S_ELECTRONIC), 0, GetSectOInt(mech, loc)); #else if (mudconf.btech_complexrepair) { if (MechType(mech) == CLASS_MECH) { PARTCHECKTWO(mech, ProperInternal(mech), 0, GetSectOInt(mech, loc), ProperMyomer(mech), 0, 1); } else { PARTCHECK(mech, ProperInternal(mech), 0, GetSectOInt(mech, loc)); } } else { PARTCHECKTWO(mech, ProperInternal(mech), 0, GetSectOInt(mech, loc), Cargo(S_ELECTRONIC), 0, GetSectOInt(mech, loc)); } #endif return 0; } #define BSUIT_REPAIR_INTERNAL_NEEDED 10 #define BSUIT_REPAIR_SENSORS_NEEDED 2 #define BSUIT_REPAIR_LIFESUPPORT_NEEDED 2 #define BSUIT_REPAIR_ELECTRONICS_NEEDED 10 TFUNC_LOC(replacesuit_econ) { PARTCHECKFOUR(mech, ProperInternal(mech), 0, BSUIT_REPAIR_INTERNAL_NEEDED, Cargo(BSUIT_SENSOR), 0, BSUIT_REPAIR_SENSORS_NEEDED, Cargo(BSUIT_LIFESUPPORT), 0, BSUIT_REPAIR_LIFESUPPORT_NEEDED, Cargo(BSUIT_ELECTRONIC), 0, BSUIT_REPAIR_ELECTRONICS_NEEDED); return 0; } /* * Added for new flood code by Kipsta * 8/4/99 */ TFUNC_LOC(reseal_econ) { PARTCHECKTWO(mech, ProperInternal(mech), 0, GetSectOInt(mech, loc), Cargo(S_ELECTRONIC), 0, GetSectOInt(mech, loc)); return 0; } /* -------------------------------------------- Successes */ /* Replace success is just that ; success, therefore the fake functions here */ NFUNC(TFUNC_LOCPOS(replacep_succ)); NFUNC(TFUNC_LOCPOS(replaceg_succ)); NFUNC(TFUNC_LOCPOS_VAL(reload_succ)); NFUNC(TFUNC_LOC_VAL(fixinternal_succ)); NFUNC(TFUNC_LOC_VAL(fixarmor_succ)); NFUNC(TFUNC_LOC(reattach_succ)); NFUNC(TFUNC_LOC_RESEAL(reseal_succ)); NFUNC(TFUNC_LOC(replacesuit_succ)); /* Repairs _Should_ have some averse effects */ NFUNC(TFUNC_LOCPOS(repairg_succ)); NFUNC(TFUNC_LOCPOS(repairenhcrit_succ)); NFUNC(TFUNC_LOCPOS(repairp_succ)); /* -------------------------------------------- Failures */ /* Replace failures give you one chance to roll for object recovery, otherwise it's irretrieavbly lost */ TFUNC_LOCPOS(replaceg_fail) { int w = (IsWeapon(GetPartType(mech, loc, part))); if (tech_roll(player, mech, REPLACE_DIFFICULTY) < 0) { notify(player, tprintf("You muck around, wasting the %s in the progress.", w ? "weapon" : "part")); return -1; } notify(player, tprintf ("Despite messing the repair, you manage not to waste the %s.", w ? "weapon" : "part")); #ifndef BT_COMPLEXREPAIRS AddPartsM(mech, FindAmmoType(mech, loc, part), GetPartBrand(mech, loc, part), 1); #else AddPartsM(mech, loc, FindAmmoType(mech, loc, part), GetPartBrand(mech, loc, part), 1); #endif return -1; } TFUNC_LOCPOS(repairg_fail) { if (PartIsDestroyed(mech, loc, part)) /* If we are calling repairgun on a thing that is actually destroyed * the following check *should not* be necessary. Nevertheless... */ if (GetWeaponCrits(mech, Weapon2I(GetPartType(mech, loc, part))) > 4) { DestroyPart(mech, loc, part + 1); notify(player, "You muck around, trashing the gun in the process."); return -1; } notify(player, "Your repair fails.. all the parts are wasted for good."); return -1; } TFUNC_LOCPOS(repairenhcrit_fail) { notify(player, "You don't manage to repair the damage."); return -1; } /* Replacepart = Replacegun, for now */ TFUNC_LOCPOS(replacep_fail) { notify(player, "Your repair fails.. all the parts are wasted for good."); return -1; } /* Repairpart = Repairgun, for now */ TFUNC_LOCPOS(repairp_fail) { return repairg_fail(player, mech, loc, part); } /* Reload fail = ammo is wasted and some time, but no averse effects (yet) */ TFUNC_LOCPOS_VAL(reload_fail) { notify(player, "You fumble around, wasting the ammo in the progress."); return -1; } /* Fixarmor/fixinternal failure means that at least 1, or at worst _all_, points are wasted */ TFUNC_LOC_VAL(fixarmor_fail) { int tot = 0; int should = *val; if (tech_roll(player, mech, FIXARMOR_DIFFICULTY) >= 0) tot += 50; tot += random() % 40 + 5; tot = (tot * should) / 100; if (tot == 0) tot = 1; if (tot == should) tot = should - 1; notify(player, tprintf("Your armor patching isn't exactly perfect.. " "You managed to fix %d out of %d.", tot, should)); *val = tot; return 0; } TFUNC_LOC_VAL(fixinternal_fail) { int tot = 0; int should = *val; if (tech_roll(player, mech, FIXARMOR_DIFFICULTY) >= 0) tot += 50; tot += random() % 40 + 5; tot = (tot * should) / 100; if (tot == 0) tot = 1; if (tot == should) tot = should - 1; notify(player, tprintf ("Your internal patching isn't exactly perfect.. You managed to fix %d out of %d.", tot, should)); *val = tot; return 0; } /* Reattach has 2 failures: - if you succeed in second roll, it takes just 1.5x time - if you don't, some (random %) of stuff is wasted and nothing is done (yet some techtime goes nonetheless */ TFUNC_LOC(reattach_fail) { int tot; if (tech_roll(player, mech, REATTACH_DIFFICULTY) >= 0) return 0; tot = random() % 90 + 5; notify(player, tprintf ("Despite your disastrous failure, you recover %d%% of the materials.", tot)); tot = (tot * GetSectOInt(mech, loc)) / 100; if (tot == 0) tot = 1; if (tot == GetSectOInt(mech, loc)) tot = GetSectOInt(mech, loc) - 1; #ifndef BT_COMPLEXREPAIRS AddPartsM(mech, Cargo(S_ELECTRONIC), 0, tot); AddPartsM(mech, ProperInternal(mech), 0, tot); #else AddPartsM(mech, loc, Cargo(S_ELECTRONIC), 0, tot); AddPartsM(mech, loc, ProperInternal(mech), 0, tot); if (mudconf.btech_complexrepair && MechType(mech) == CLASS_MECH) AddPartsM(mech, loc, ProperMyomer(mech), 0, 1); #endif return -1; } TFUNC_LOC(replacesuit_fail) { int wRand = 0; if (tech_roll(player, mech, REATTACH_DIFFICULTY) >= 0) return 0; wRand = random() % 90 + 5; notify(player, tprintf ("Despite your disastrous failure, you recover %d%% of the materials.", wRand)); #ifndef BT_COMPLEXREPAIRS AddPartsM(mech, Cargo(BSUIT_SENSOR), 0, MAX(((BSUIT_REPAIR_SENSORS_NEEDED * wRand) / 100), 1)); AddPartsM(mech, Cargo(BSUIT_LIFESUPPORT), 0, ((BSUIT_REPAIR_LIFESUPPORT_NEEDED * wRand) / 100)); AddPartsM(mech, Cargo(BSUIT_ELECTRONIC), 0, ((BSUIT_REPAIR_ELECTRONICS_NEEDED * wRand) / 100)); AddPartsM(mech, ProperInternal(mech), 0, MAX(((BSUIT_REPAIR_INTERNAL_NEEDED * wRand) / 100), 1)); #else AddPartsM(mech, loc, Cargo(BSUIT_SENSOR), 0, MAX(((BSUIT_REPAIR_SENSORS_NEEDED * wRand) / 100), 1)); AddPartsM(mech, loc, Cargo(BSUIT_LIFESUPPORT), 0, ((BSUIT_REPAIR_LIFESUPPORT_NEEDED * wRand) / 100)); AddPartsM(mech, loc, Cargo(BSUIT_ELECTRONIC), 0, ((BSUIT_REPAIR_ELECTRONICS_NEEDED * wRand) / 100)); AddPartsM(mech, loc, ProperInternal(mech), 0, MAX(((BSUIT_REPAIR_INTERNAL_NEEDED * wRand) / 100), 1)); #endif return -1; } /* * Added by Kipsta for flooding code * 8/4/99 */ TFUNC_LOC_RESEAL(reseal_fail) { int tot; if (tech_roll(player, mech, RESEAL_DIFFICULTY) >= 0) return 0; tot = random() % 90 + 5; notify(player, tprintf ("You don't manage to get all the water out and seal the section, though you recover %d%% of the materials.", tot)); tot = (tot * GetSectOInt(mech, loc)) / 100; if (tot == 0) tot = 1; if (tot == GetSectOInt(mech, loc)) tot = GetSectOInt(mech, loc) - 1; #ifndef BT_COMPLEXREPAIRS AddPartsM(mech, Cargo(S_ELECTRONIC), 0, tot); AddPartsM(mech, ProperInternal(mech), 0, tot); #else AddPartsM(mech, loc, Cargo(S_ELECTRONIC), 0, tot); AddPartsM(mech, loc, ProperInternal(mech), 0, tot); #endif return -1; }