/* * $Id: mech.hitloc.c,v 1.1.1.1 2005/01/11 21:18:17 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: Fri Sep 20 19:54:48 1996 fingon * Last modified: Tue Jun 16 18:23:58 1998 fingon * */ #include "mech.h" #include "mech.events.h" #include "p.mech.utils.h" #include "p.mech.combat.h" #include "p.mech.damage.h" #include "p.aero.bomb.h" #include "p.mech.update.h" #include "p.crit.h" #define CHECK_ZERO_LOC(mech,a,b) ( GetSectInt(mech, a) > 0 ? a : b ) int FindPunchLocation(int hitGroup) { int roll = Number(1, 6); switch (hitGroup) { case LEFTSIDE: switch (roll) { case 1: case 2: return LTORSO; case 3: return CTORSO; case 4: case 5: return LARM; case 6: return HEAD; } case BACK: case FRONT: switch (roll) { case 1: return LARM; case 2: return LTORSO; case 3: return CTORSO; case 4: return RTORSO; case 5: return RARM; case 6: return HEAD; } break; case RIGHTSIDE: switch (roll) { case 1: case 2: return RTORSO; case 3: return CTORSO; case 4: case 5: return RARM; case 6: return HEAD; } } return CTORSO; } int FindKickLocation(int hitGroup) { int roll = Number(1, 6); switch (hitGroup) { case LEFTSIDE: return LLEG; case BACK: case FRONT: switch (roll) { case 1: case 2: case 3: return RLEG; case 4: case 5: case 6: return LLEG; } case RIGHTSIDE: return RLEG; } return RLEG; } /* * Exile stun code - Used when a mech takes a hit to the head * instead of doing damage to the head it stuns the pilot * and re-rolls the location */ int ModifyHeadHit(int hitGroup, MECH * mech) { int newloc = FindPunchLocation(hitGroup); if (MechType(mech) != CLASS_MECH) return newloc; if (newloc != HEAD) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); mech_notify(mech, MECHALL, "The cockpit violently shakes from a grazing blow! " "You are momentarily stunned!"); if (CrewStunning(mech)) StopCrewStunning(mech); MechLOSBroadcast(mech, "significantly slows down and starts wobbling!"); MechCritStatus(mech) |= MECH_STUNNED; if (MechSpeed(mech) > WalkingSpeed(MechMaxSpeed(mech))) MechDesiredSpeed(mech) = WalkingSpeed(MechMaxSpeed(mech)); MECHEVENT(mech, EVENT_CREWSTUN, mech_crewstun_event, MECHSTUN_TICK, 0); } return newloc; } int get_bsuit_hitloc(MECH * mech) { int i; int table[NUM_BSUIT_MEMBERS]; int last = 0; for (i = 0; i < NUM_BSUIT_MEMBERS; i++) if (GetSectInt(mech, i)) table[last++] = i; if (!last) return -1; return table[Number(0, last - 1)]; } int TransferTarget(MECH * mech, int hitloc) { switch (MechType(mech)) { case CLASS_BSUIT: return get_bsuit_hitloc(mech); case CLASS_AERO: switch (hitloc) { case AERO_NOSE: case AERO_LWING: case AERO_RWING: case AERO_ENGINE: case AERO_COCKPIT: return AERO_FUSEL; } break; case CLASS_MECH: case CLASS_MW: switch (hitloc) { case RARM: case RLEG: return RTORSO; break; case LARM: case LLEG: return LTORSO; break; case RTORSO: case LTORSO: return CTORSO; break; } break; } return -1; } int FindSwarmHitLocation(int *iscritical, int *isrear) { *isrear = 0; *iscritical = 1; switch (Roll()) { case 12: case 2: return HEAD; case 3: case 11: *isrear = 1; return CTORSO; case 4: *isrear = 1; case 5: return RTORSO; case 10: *isrear = 1; case 9: return LTORSO; case 6: return RARM; case 8: return LARM; case 7: return CTORSO; } return HEAD; } /* * Determines whether a section is crittable. * tres = armor percentage threshhold */ int crittable(MECH * mech, int loc, int tres) { int d; if (MechSpecials(mech) & CRITPROOF_TECH) return 0; /* Towers and Stationary Objectives should not crit */ if (MechMove(mech) == MOVE_NONE) return 0; if (!GetSectOArmor(mech, loc)) return 1; if (MechType(mech) != CLASS_MECH && mudconf.btech_vcrit <= 1) return 0; /* Calculate percentage of armor remaining */ d = (100 * GetSectArmor(mech, loc)) / GetSectOArmor(mech, loc); /* Are we below the threshold? */ if (d < tres) return 1; if (d == 100) { if (Number(1, 71) == 23) return 1; return 0; } if (d < (100 - ((100 - tres) / 2))) if (Number(1, 11) == 6) return 1; return 0; } /* end crittable() */ int FindFasaHitLocation(MECH * mech, int hitGroup, int *iscritical, int *isrear) { int roll, hitloc = 0; int side; *iscritical = 0; roll = Roll(); if (MechStatus(mech) & COMBAT_SAFE) return 0; if (MechDugIn(mech) && GetSectOInt(mech, TURRET) && Number(1, 100) >= 42) return TURRET; rollstat.hitrolls[roll - 2]++; rollstat.tothrolls++; switch (MechType(mech)) { case CLASS_BSUIT: if ((hitloc = get_bsuit_hitloc(mech)) < 0) return Number(0, NUM_BSUIT_MEMBERS - 1); case CLASS_MW: case CLASS_MECH: switch (hitGroup) { case LEFTSIDE: switch (roll) { case 2: *iscritical = 1; return LTORSO; case 3: return LLEG; case 4: case 5: return LARM; case 6: return LLEG; case 7: return LTORSO; case 8: return CTORSO; case 9: return RTORSO; case 10: return RARM; case 11: return RLEG; case 12: if (mudconf.btech_exile_stun_code) return ModifyHeadHit(hitGroup, mech); return HEAD; } case RIGHTSIDE: switch (roll) { case 2: *iscritical = 1; return RTORSO; case 3: return RLEG; case 4: case 5: return RARM; case 6: return RLEG; case 7: return RTORSO; case 8: return CTORSO; case 9: return LTORSO; case 10: return LARM; case 11: return LLEG; case 12: if (mudconf.btech_exile_stun_code) return ModifyHeadHit(hitGroup, mech); return HEAD; } case FRONT: case BACK: switch (roll) { case 2: *iscritical = 1; return CTORSO; case 3: case 4: return RARM; case 5: return RLEG; case 6: return RTORSO; case 7: return CTORSO; case 8: return LTORSO; case 9: return LLEG; case 10: case 11: return LARM; case 12: if (mudconf.btech_exile_stun_code) return ModifyHeadHit(hitGroup, mech); return HEAD; } } break; case CLASS_VEH_GROUND: switch (hitGroup) { case LEFTSIDE: switch (roll) { case 2: /* A Roll on Determining Critical Hits Table */ *iscritical = 1; return LSIDE; case 3: if (mudconf.btech_tankfriendly) { if (!Fallen(mech)) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); switch (MechMove(mech)) { case MOVE_TRACK: mech_notify(mech, MECHALL, "One of your tracks is seriously damaged!!"); break; case MOVE_WHEEL: mech_notify(mech, MECHALL, "One of your wheels is seriously damaged!!"); break; case MOVE_HOVER: mech_notify(mech, MECHALL, "Your air skirt is seriously damaged!!"); break; case MOVE_HULL: case MOVE_SUB: case MOVE_FOIL: mech_notify(mech, MECHALL, "Your speed slows down a lot.."); break; } LowerMaxSpeed(mech, MP2); } return LSIDE; } /* Cripple tank */ if (!Fallen(mech)) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); switch (MechMove(mech)) { case MOVE_TRACK: mech_notify(mech, MECHALL, "One of your tracks is destroyed, imobilizing your vehicle!!"); break; case MOVE_WHEEL: mech_notify(mech, MECHALL, "One of your wheels is destroyed, imobilizing your vehicle!!"); break; case MOVE_HOVER: mech_notify(mech, MECHALL, "Your lift fan is destroyed, imobilizing your vehicle!!"); break; case MOVE_HULL: case MOVE_SUB: case MOVE_FOIL: mech_notify(mech, MECHALL, "You are halted in your tracks - literally."); } SetMaxSpeed(mech, 0.0); MakeMechFall(mech); } return LSIDE; case 4: case 5: /* MP -1 */ if (!Fallen(mech)) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); switch (MechMove(mech)) { case MOVE_TRACK: mech_notify(mech, MECHALL, "One of your tracks is damaged!!"); break; case MOVE_WHEEL: mech_notify(mech, MECHALL, "One of your wheels is damaged!!"); break; case MOVE_HOVER: mech_notify(mech, MECHALL, "Your air skirt is damaged!!"); break; case MOVE_HULL: case MOVE_SUB: case MOVE_FOIL: mech_notify(mech, MECHALL, "Your speed slows down.."); break; } LowerMaxSpeed(mech, MP1); } return LSIDE; break; case 6: case 7: case 8: case 9: /* MP -1 if hover */ return LSIDE; case 10: return (GetSectInt(mech, TURRET)) ? TURRET : LSIDE; case 11: if (GetSectInt(mech, TURRET)) { if (!(MechTankCritStatus(mech) & TURRET_LOCKED)) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); MechTankCritStatus(mech) |= TURRET_LOCKED; mech_notify(mech, MECHALL, "Your turret takes a direct hit and immobilizes!"); } return TURRET; } else return LSIDE; case 12: /* A Roll on Determining Critical Hits Table */ *iscritical = 1; return LSIDE; } break; case RIGHTSIDE: switch (roll) { case 2: *iscritical = 1; return RSIDE; case 3: if (mudconf.btech_tankfriendly) { if (!Fallen(mech)) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); switch (MechMove(mech)) { case MOVE_TRACK: mech_notify(mech, MECHALL, "One of your tracks is seriously damaged!!"); break; case MOVE_WHEEL: mech_notify(mech, MECHALL, "One of your wheels is seriously damaged!!"); break; case MOVE_HOVER: mech_notify(mech, MECHALL, "Your air skirt is seriously damaged!!"); break; case MOVE_HULL: case MOVE_SUB: case MOVE_FOIL: mech_notify(mech, MECHALL, "Your speed slows down a lot.."); break; } LowerMaxSpeed(mech, MP2); } return RSIDE; } /* Cripple Tank */ if (!Fallen(mech)) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); switch (MechMove(mech)) { case MOVE_TRACK: mech_notify(mech, MECHALL, "One of your tracks is destroyed, imobilizing your vehicle!!"); break; case MOVE_WHEEL: mech_notify(mech, MECHALL, "One of your wheels is destroyed, imobilizing your vehicle!!"); break; case MOVE_HOVER: mech_notify(mech, MECHALL, "Your lift fan is destroyed, imobilizing your vehicle!!"); break; case MOVE_HULL: case MOVE_SUB: case MOVE_FOIL: mech_notify(mech, MECHALL, "You are halted in your tracks - literally."); } SetMaxSpeed(mech, 0.0); MakeMechFall(mech); } return RSIDE; case 4: case 5: /* MP -1 */ if (!Fallen(mech)) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); switch (MechMove(mech)) { case MOVE_TRACK: mech_notify(mech, MECHALL, "One of your tracks is damaged!!"); break; case MOVE_WHEEL: mech_notify(mech, MECHALL, "One of your wheels is damaged!!"); break; case MOVE_HOVER: mech_notify(mech, MECHALL, "Your air skirt is damaged!!"); break; case MOVE_HULL: case MOVE_SUB: case MOVE_FOIL: mech_notify(mech, MECHALL, "Your speed slows down.."); break; } LowerMaxSpeed(mech, MP1); } return RSIDE; case 6: case 7: case 8: return RSIDE; case 9: /* MP -1 if hover */ if (!Fallen(mech)) { if (MechMove(mech) == MOVE_HOVER) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); mech_notify(mech, MECHALL, "Your air skirt is damaged!!"); LowerMaxSpeed(mech, MP1); } } return RSIDE; case 10: return (GetSectInt(mech, TURRET)) ? TURRET : RSIDE; case 11: if (GetSectInt(mech, TURRET)) { if (!(MechTankCritStatus(mech) & TURRET_LOCKED)) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); MechTankCritStatus(mech) |= TURRET_LOCKED; mech_notify(mech, MECHALL, "Your turret takes a direct hit and immobilizes!"); } return TURRET; } else return RSIDE; case 12: /* A Roll on Determining Critical Hits Table */ *iscritical = 1; return RSIDE; } break; case FRONT: case BACK: side = (hitGroup == FRONT ? FSIDE : BSIDE); switch (roll) { case 2: /* A Roll on Determining Critical Hits Table */ *iscritical = 1; return side; case 3: if (mudconf.btech_tankshield) { if (mudconf.btech_tankfriendly) { if (!Fallen(mech)) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); switch (MechMove(mech)) { case MOVE_TRACK: mech_notify(mech, MECHALL, "One of your tracks is seriously damaged!!"); break; case MOVE_WHEEL: mech_notify(mech, MECHALL, "One of your wheels is seriously damaged!!"); break; case MOVE_HOVER: mech_notify(mech, MECHALL, "Your air skirt is seriously damaged!!"); break; case MOVE_HULL: case MOVE_SUB: case MOVE_FOIL: mech_notify(mech, MECHALL, "Your speed slows down a lot.."); break; } LowerMaxSpeed(mech, MP2); } return side; } /* Cripple tank */ if (!Fallen(mech)) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); switch (MechMove(mech)) { case MOVE_TRACK: mech_notify(mech, MECHALL, "One of your tracks is destroyed, imobilizing your vehicle!!"); break; case MOVE_WHEEL: mech_notify(mech, MECHALL, "One of your wheels is destroyed, imobilizing your vehicle!!"); break; case MOVE_HOVER: mech_notify(mech, MECHALL, "Your lift fan is destroyed, imobilizing your vehicle!!"); break; case MOVE_HULL: case MOVE_SUB: case MOVE_FOIL: mech_notify(mech, MECHALL, "You are halted in your tracks - literally."); } SetMaxSpeed(mech, 0.0); MakeMechFall(mech); } } return side; case 4: /* MP -1 */ if (mudconf.btech_tankshield) { if (!Fallen(mech)) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); switch (MechMove(mech)) { case MOVE_TRACK: mech_notify(mech, MECHALL, "One of your tracks is damaged!!"); break; case MOVE_WHEEL: mech_notify(mech, MECHALL, "One of your wheels is damaged!!"); break; case MOVE_HOVER: mech_notify(mech, MECHALL, "Your air skirt is damaged!!"); break; case MOVE_HULL: case MOVE_SUB: case MOVE_FOIL: mech_notify(mech, MECHALL, "Your speed slows down.."); break; } LowerMaxSpeed(mech, MP1); } } return side; case 5: /* MP -1 if Hovercraft */ if (!Fallen(mech)) { if (MechMove(mech) == MOVE_HOVER) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); mech_notify(mech, MECHALL, "Your air skirt is damaged!!"); LowerMaxSpeed(mech, MP1); } } return side; case 6: case 7: case 8: case 9: return side; case 10: return (GetSectInt(mech, TURRET)) ? TURRET : side; case 11: *iscritical = 1; /* Lock turret into place */ if (GetSectInt(mech, TURRET)) { if (!(MechTankCritStatus(mech) & TURRET_LOCKED)) { mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); MechTankCritStatus(mech) |= TURRET_LOCKED; mech_notify(mech, MECHALL, "Your turret takes a direct hit and immobilizes!"); } return TURRET; } else return side; case 12: /* A Roll on Determining Critical Hits Table */ if (crittable(mech, (GetSectInt(mech, TURRET)) ? TURRET : side, mudconf.btech_critlevel)) *iscritical = 1; return (GetSectInt(mech, TURRET)) ? TURRET : side; } } break; case CLASS_AERO: switch (hitGroup) { case FRONT: switch (roll) { case 2: case 12: return AERO_COCKPIT; case 3: case 11: if (crittable(mech, AERO_NOSE, 90)) LoseWeapon(mech, AERO_NOSE); return AERO_NOSE; case 4: case 10: if (roll == 10) DestroyBomb(mech, AERO_FUSEL); return AERO_FUSEL; case 5: return AERO_RWING; case 9: return AERO_LWING; case 6: case 7: case 8: return AERO_NOSE; } break; case LEFTSIDE: case RIGHTSIDE: side = ((hitGroup == LEFTSIDE) ? AERO_LWING : AERO_RWING); switch (roll) { case 2: return AERO_COCKPIT; case 12: if (crittable(mech, AERO_ENGINE, 99)) *iscritical = 1; return AERO_ENGINE; case 3: case 11: if (crittable(mech, side, 99)) LoseWeapon(mech, side); return side; case 4: case 10: if (crittable(mech, AERO_ENGINE, 90)) DestroyHeatSink(mech, AERO_ENGINE); return AERO_ENGINE; case 5: DestroyBomb(mech, AERO_FUSEL); return AERO_FUSEL; case 9: return AERO_NOSE; case 6: case 8: return side; case 7: return AERO_FUSEL; } break; case BACK: switch (roll) { case 2: case 12: if (crittable(mech, AERO_ENGINE, 90)) *iscritical = 1; return AERO_ENGINE; case 3: case 11: aero_ControlEffect(mech); return AERO_FUSEL; case 4: case 7: case 10: if (crittable(mech, AERO_FUSEL, 90)) DestroyHeatSink(mech, AERO_FUSEL); return AERO_FUSEL; case 5: return AERO_RWING; case 9: return AERO_LWING; case 6: case 8: return AERO_ENGINE; } } break; case CLASS_DS: case CLASS_SPHEROID_DS: switch (hitGroup) { case FRONT: switch (roll) { case 2: case 12: if (crittable(mech, DS_NOSE, 30)) ds_BridgeHit(mech); return DS_NOSE; case 3: case 11: if (crittable(mech, DS_NOSE, 50)) LoseWeapon(mech, DS_NOSE); return DS_NOSE; case 5: return DS_RWING; case 6: case 7: case 8: return DS_NOSE; case 9: return DS_LWING; case 4: case 10: return (Number(1, 2)) == 1 ? DS_LWING : DS_RWING; } case LEFTSIDE: case RIGHTSIDE: side = (hitGroup == LEFTSIDE) ? DS_LWING : DS_RWING; if (Number(1, 2) == 2) SpheroidToRear(mech, side); switch (roll) { case 2: if (crittable(mech, DS_NOSE, 30)) ds_BridgeHit(mech); return DS_NOSE; case 3: case 11: if (crittable(mech, side, 60)) LoseWeapon(mech, side); return side; case 4: case 5: case 6: case 7: case 8: case 10: return side; case 9: return DS_NOSE; case 12: if (crittable(mech, side, 60)) *iscritical = 1; return side; } case BACK: switch (roll) { case 2: case 12: if (crittable(mech, DS_AFT, 60)) *iscritical = 1; return DS_AFT; case 3: case 11: return DS_AFT; case 4: case 7: case 10: if (crittable(mech, DS_AFT, 60)) DestroyHeatSink(mech, DS_AFT); return DS_AFT; case 5: hitloc = DS_RWING; SpheroidToRear(mech, hitloc); return hitloc; case 6: case 8: return DS_AFT; case 9: hitloc = DS_LWING; SpheroidToRear(mech, hitloc); return hitloc; } } break; case CLASS_VTOL: switch (hitGroup) { case LEFTSIDE: switch (roll) { case 2: hitloc = ROTOR; *iscritical = 1; DoVTOLRotorDestroyedCrit(mech, NULL, 1); break; case 3: *iscritical = 1; break; case 4: case 5: hitloc = ROTOR; DoVTOLRotorDamagedCrit(mech); break; case 6: case 7: case 8: hitloc = LSIDE; break; case 9: /* Destroy Main Weapon but do not destroy armor */ DestroyMainWeapon(mech); hitloc = 0; break; case 10: case 11: hitloc = ROTOR; DoVTOLRotorDamagedCrit(mech); break; case 12: hitloc = ROTOR; *iscritical = 1; DoVTOLRotorDamagedCrit(mech); break; } break; case RIGHTSIDE: switch (roll) { case 2: hitloc = ROTOR; *iscritical = 1; DoVTOLRotorDestroyedCrit(mech, NULL, 1); break; case 3: *iscritical = 1; break; case 4: case 5: hitloc = ROTOR; DoVTOLRotorDamagedCrit(mech); break; case 6: case 7: case 8: hitloc = RSIDE; break; case 9: /* Destroy Main Weapon but do not destroy armor */ DestroyMainWeapon(mech); break; case 10: case 11: hitloc = ROTOR; DoVTOLRotorDamagedCrit(mech); break; case 12: hitloc = ROTOR; *iscritical = 1; DoVTOLRotorDamagedCrit(mech); break; } break; case FRONT: case BACK: side = (hitGroup == FRONT ? FSIDE : BSIDE); switch (roll) { case 2: hitloc = ROTOR; *iscritical = 1; DoVTOLRotorDestroyedCrit(mech, NULL, 1); break; case 3: hitloc = ROTOR; DoVTOLRotorDestroyedCrit(mech, NULL, 1); break; case 4: case 5: hitloc = ROTOR; DoVTOLRotorDamagedCrit(mech); break; case 6: case 7: case 8: case 9: hitloc = side; break; case 10: case 11: hitloc = ROTOR; DoVTOLRotorDamagedCrit(mech); break; case 12: hitloc = ROTOR; *iscritical = 1; DoVTOLRotorDamagedCrit(mech); break; } break; } break; case CLASS_VEH_NAVAL: switch (hitGroup) { case LEFTSIDE: switch (roll) { case 2: hitloc = LSIDE; if (crittable(mech, hitloc, 40)) *iscritical = 1; break; case 3: case 4: case 5: hitloc = LSIDE; break; case 9: hitloc = LSIDE; break; case 10: if (GetSectInt(mech, TURRET)) hitloc = TURRET; else hitloc = LSIDE; break; case 11: if (GetSectInt(mech, TURRET)) { hitloc = TURRET; if (crittable(mech, hitloc, 40)) *iscritical = 1; } else hitloc = LSIDE; break; case 12: hitloc = LSIDE; *iscritical = 1; break; } break; case RIGHTSIDE: switch (roll) { case 2: case 12: hitloc = RSIDE; if (crittable(mech, hitloc, 40)) *iscritical = 1; break; case 3: case 4: case 5: case 6: case 7: case 8: hitloc = RSIDE; break; case 10: if (GetSectInt(mech, TURRET)) hitloc = TURRET; else hitloc = RSIDE; break; case 11: if (GetSectInt(mech, TURRET)) { hitloc = TURRET; if (crittable(mech, hitloc, 40)) *iscritical = 1; } else hitloc = RSIDE; break; } break; case FRONT: case BACK: side = (hitGroup == FRONT ? FSIDE : BSIDE); switch (roll) { case 2: case 12: hitloc = side; if (crittable(mech, hitloc, 40)) *iscritical = 1; break; case 3: hitloc = side; break; case 4: hitloc = side; break; case 5: hitloc = side; break; case 6: case 7: case 8: case 9: hitloc = side; break; case 10: if (GetSectInt(mech, TURRET)) hitloc = TURRET; else hitloc = side; break; case 11: if (GetSectInt(mech, TURRET)) { hitloc = TURRET; *iscritical = 1; } else hitloc = side; break; } break; } break; } return (hitloc); } /* Do L3 FASA motive system crits */ void DoMotiveSystemHit(MECH * mech, int wRollMod) { int wRoll; char strVhlTypeName[30]; wRoll = Roll() + wRollMod; switch (MechMove(mech)) { case MOVE_TRACK: strcpy(strVhlTypeName, "tank"); break; case MOVE_WHEEL: strcpy(strVhlTypeName, "vehicle"); wRoll += 2; break; case MOVE_HOVER: strcpy(strVhlTypeName, "hovercraft"); wRoll += 4; break; case MOVE_HULL: strcpy(strVhlTypeName, "ship"); break; case MOVE_FOIL: strcpy(strVhlTypeName, "hydrofoil"); wRoll += 4; break; case MOVE_SUB: strcpy(strVhlTypeName, "submarine"); break; default: strcpy(strVhlTypeName, "weird unidentifiable toy (warn a wizard!)"); break; } if (wRoll < 8) /* no effect */ return; mech_notify(mech, MECHALL, "%ch%cyCRITICAL HIT!!%c"); if (wRoll < 10) { /* minor effect */ MechPilotSkillBase(mech) += 1; if (Fallen(mech)) mech_notify(mech, MECHALL, "%cr%chYour destroyed motive system takes another hit!%cn"); else mech_notify(mech, MECHALL, tprintf ("%%cr%%chYour motive system takes a minor hit, making it harder to control your %s!%%cn", strVhlTypeName)); if (MechSpeed(mech) != 0.0) MechLOSBroadcast(mech, "wobbles slightly."); } else if (wRoll < 12) { /* moderate effect */ MechPilotSkillBase(mech) += 2; if (Fallen(mech)) mech_notify(mech, MECHALL, "%cr%chYour destroyed motive system takes another hit!%cn"); else mech_notify(mech, MECHALL, tprintf ("%%cr%%chYour motive system takes a moderate hit, slowing you down and making it harder to control your %s!%%cn", strVhlTypeName)); if (MechSpeed(mech) != 0.0) MechLOSBroadcast(mech, "wobbles violently."); LowerMaxSpeed(mech, MP1); correct_speed(mech); } else { if (Fallen(mech)) mech_notify(mech, MECHALL, "%cr%chYour destroyed motive system takes another hit!%cn"); else mech_notify(mech, MECHALL, tprintf ("%%cr%%chYour motive system is destroyed! Your %s can no longer move!%%cn", strVhlTypeName)); if (MechSpeed(mech) > 0) MechLOSBroadcast(mech, "shakes violently then begins to slow down."); SetMaxSpeed(mech, 0.0); MakeMechFall(mech); correct_speed(mech); } } int FindAdvFasaVehicleHitLocation(MECH * mech, int hitGroup, int *iscritical, int *isrear) { int roll, hitloc = 0; int side; *iscritical = 0; roll = Roll(); if (MechStatus(mech) & COMBAT_SAFE) return 0; if (MechDugIn(mech) && GetSectInt(mech, TURRET) && Number(1, 100) >= 42) return TURRET; rollstat.hitrolls[roll - 2]++; rollstat.tothrolls++; switch (MechType(mech)) { case CLASS_VEH_GROUND: switch (hitGroup) { case LEFTSIDE: case RIGHTSIDE: side = (hitGroup == LEFTSIDE ? LSIDE : RSIDE); switch (roll) { case 2: hitloc = side; *iscritical = 1; break; case 3: hitloc = side; if (crittable(mech, hitloc, mudconf.btech_critlevel)) DoMotiveSystemHit(mech, 0); break; case 4: hitloc = side; break; case 5: hitloc = FSIDE; break; case 6: case 7: case 8: hitloc = side; break; case 9: hitloc = BSIDE; break; case 10: case 11: hitloc = CHECK_ZERO_LOC(mech, TURRET, side); break; case 12: hitloc = CHECK_ZERO_LOC(mech, TURRET, side); *iscritical = 1; break; } break; case FRONT: case BACK: side = (hitGroup == FRONT ? FSIDE : BSIDE); switch (roll) { case 2: hitloc = side; *iscritical = 1; break; case 3: hitloc = side; if (crittable(mech, hitloc, mudconf.btech_critlevel)) DoMotiveSystemHit(mech, 0); break; case 4: hitloc = side; break; case 5: hitloc = (hitGroup == FRONT ? RSIDE : LSIDE); break; case 6: case 7: case 8: hitloc = side; break; case 9: hitloc = (hitGroup == FRONT ? LSIDE : RSIDE); break; case 10: case 11: hitloc = CHECK_ZERO_LOC(mech, TURRET, (hitGroup == FRONT ? LSIDE : RSIDE)); break; case 12: hitloc = CHECK_ZERO_LOC(mech, TURRET, (hitGroup == FRONT ? LSIDE : RSIDE)); *iscritical = 1; break; } break; } break; case CLASS_VTOL: switch (hitGroup) { case LEFTSIDE: case RIGHTSIDE: side = (hitGroup == LEFTSIDE ? LSIDE : RSIDE); switch (roll) { case 2: hitloc = side; *iscritical = 1; break; case 3: case 4: hitloc = side; break; case 5: hitloc = FSIDE; break; case 6: case 7: case 8: hitloc = side; break; case 9: hitloc = BSIDE; break; case 10: case 11: hitloc = ROTOR; break; case 12: hitloc = ROTOR; *iscritical = 1; break; } break; case FRONT: case BACK: side = (hitGroup == FRONT ? FSIDE : BSIDE); switch (roll) { case 2: hitloc = side; *iscritical = 1; break; case 3: hitloc = side; break; case 4: hitloc = side; break; case 5: hitloc = (hitGroup == FRONT ? RSIDE : LSIDE); break; case 6: case 7: case 8: hitloc = side; break; case 9: hitloc = (hitGroup == FRONT ? LSIDE : RSIDE); break; case 10: case 11: hitloc = ROTOR; break; case 12: hitloc = ROTOR; *iscritical = 1; break; } break; } break; } if (!crittable(mech, hitloc, mudconf.btech_critlevel)) *iscritical = 0; return hitloc; } /* Use this when the unit is CRITPROOF because the other * hitlocation functions are screwy */ int FindHitLocation_CritProof(MECH * mech, int hitGroup, int *iscritical, int *isrear) { int roll, hitloc = 0; int side; roll = Roll(); /* Since we're crit proof set this to 0 */ *iscritical = 0; if (MechStatus(mech) & COMBAT_SAFE) return 0; if (MechDugIn(mech) && GetSectOInt(mech, TURRET) && Number(1, 100) >= 42) return TURRET; rollstat.hitrolls[roll - 2]++; rollstat.tothrolls++; switch (MechType(mech)) { case CLASS_BSUIT: if ((hitloc = get_bsuit_hitloc(mech)) < 0) return Number(0, NUM_BSUIT_MEMBERS - 1); case CLASS_MW: case CLASS_MECH: switch (hitGroup) { case LEFTSIDE: switch (roll) { case 2: return LTORSO; case 3: return LLEG; case 4: case 5: return LARM; case 6: return LLEG; case 7: return LTORSO; case 8: return CTORSO; case 9: return RTORSO; case 10: return RARM; case 11: return RLEG; case 12: if (mudconf.btech_exile_stun_code) return ModifyHeadHit(hitGroup, mech); return HEAD; } case RIGHTSIDE: switch (roll) { case 2: return RTORSO; case 3: return RLEG; case 4: case 5: return RARM; case 6: return RLEG; case 7: return RTORSO; case 8: return CTORSO; case 9: return LTORSO; case 10: return LARM; case 11: return LLEG; case 12: if (mudconf.btech_exile_stun_code) return ModifyHeadHit(hitGroup, mech); return HEAD; } case FRONT: case BACK: switch (roll) { case 2: return CTORSO; case 3: case 4: return RARM; case 5: return RLEG; case 6: return RTORSO; case 7: return CTORSO; case 8: return LTORSO; case 9: return LLEG; case 10: case 11: return LARM; case 12: if (mudconf.btech_exile_stun_code) return ModifyHeadHit(hitGroup, mech); return HEAD; } } break; case CLASS_VEH_GROUND: switch (hitGroup) { case LEFTSIDE: switch (roll) { case 2: case 12: return LSIDE; case 3: case 4: case 5: case 6: case 7: case 8: case 9: return LSIDE; case 10: return (GetSectInt(mech, TURRET)) ? TURRET : LSIDE; case 11: if (GetSectInt(mech, TURRET)) { return TURRET; } else return LSIDE; } break; case RIGHTSIDE: switch (roll) { case 2: case 12: return RSIDE; case 3: case 4: case 5: case 6: case 7: case 8: case 9: return RSIDE; case 10: return (GetSectInt(mech, TURRET)) ? TURRET : RSIDE; case 11: if (GetSectInt(mech, TURRET)) { return TURRET; } else return RSIDE; break; } break; case FRONT: case BACK: side = (hitGroup == FRONT ? FSIDE : BSIDE); switch (roll) { case 2: case 12: return side; case 3: case 4: case 5: case 6: case 7: case 8: case 9: return side; case 10: return (GetSectInt(mech, TURRET)) ? TURRET : side; case 11: if (GetSectInt(mech, TURRET)) { return TURRET; } else return side; } } break; case CLASS_AERO: switch (hitGroup) { case FRONT: switch (roll) { case 2: case 12: return AERO_COCKPIT; case 3: case 11: return AERO_NOSE; case 4: case 10: return AERO_FUSEL; case 5: return AERO_RWING; case 9: return AERO_LWING; case 6: case 7: case 8: return AERO_NOSE; } break; case LEFTSIDE: case RIGHTSIDE: side = ((hitGroup == LEFTSIDE) ? AERO_LWING : AERO_RWING); switch (roll) { case 2: return AERO_COCKPIT; case 12: return AERO_ENGINE; case 3: case 11: return side; case 4: case 10: return AERO_ENGINE; case 5: return AERO_FUSEL; case 9: return AERO_NOSE; case 6: case 8: return side; case 7: return AERO_FUSEL; } break; case BACK: switch (roll) { case 2: case 12: return AERO_ENGINE; case 3: case 11: return AERO_FUSEL; case 4: case 7: case 10: return AERO_FUSEL; case 5: return AERO_RWING; case 9: return AERO_LWING; case 6: case 8: return AERO_ENGINE; } } break; case CLASS_DS: case CLASS_SPHEROID_DS: switch (hitGroup) { case FRONT: switch (roll) { case 2: case 12: return DS_NOSE; case 3: case 11: return DS_NOSE; case 5: return DS_RWING; case 6: case 7: case 8: return DS_NOSE; case 9: return DS_LWING; case 4: case 10: return (Number(1, 2)) == 1 ? DS_LWING : DS_RWING; } case LEFTSIDE: case RIGHTSIDE: side = (hitGroup == LEFTSIDE) ? DS_LWING : DS_RWING; if (Number(1, 2) == 2) SpheroidToRear(mech, side); switch (roll) { case 2: return DS_NOSE; case 3: case 11: return side; case 4: case 5: case 6: case 7: case 8: case 10: return side; case 9: return DS_NOSE; case 12: return side; } case BACK: switch (roll) { case 2: case 12: return DS_AFT; case 3: case 11: return DS_AFT; case 4: case 7: case 10: return DS_AFT; case 5: hitloc = DS_RWING; SpheroidToRear(mech, hitloc); return hitloc; case 6: case 8: return DS_AFT; case 9: hitloc = DS_LWING; SpheroidToRear(mech, hitloc); return hitloc; } } break; case CLASS_VTOL: switch (hitGroup) { case LEFTSIDE: switch (roll) { case 2: hitloc = ROTOR; break; case 3: case 4: hitloc = ROTOR; break; case 5: case 6: case 7: case 8: case 9: hitloc = LSIDE; break; case 10: case 11: hitloc = ROTOR; break; case 12: hitloc = ROTOR; break; } break; case RIGHTSIDE: switch (roll) { case 2: hitloc = ROTOR; break; case 3: case 4: hitloc = ROTOR; break; case 5: case 6: case 7: case 8: case 9: hitloc = RSIDE; break; case 10: case 11: hitloc = ROTOR; break; case 12: hitloc = ROTOR; break; } break; case FRONT: case BACK: side = (hitGroup == FRONT ? FSIDE : BSIDE); switch (roll) { case 2: hitloc = ROTOR; break; case 3: case 4: hitloc = ROTOR; break; case 5: case 6: case 7: case 8: case 9: hitloc = side; break; case 10: case 11: hitloc = ROTOR; break; case 12: hitloc = ROTOR; break; } break; } break; case CLASS_VEH_NAVAL: switch (hitGroup) { case LEFTSIDE: switch (roll) { case 2: hitloc = LSIDE; break; case 3: case 4: case 5: hitloc = LSIDE; break; case 9: hitloc = LSIDE; break; case 10: if (GetSectInt(mech, TURRET)) hitloc = TURRET; else hitloc = LSIDE; break; case 11: if (GetSectInt(mech, TURRET)) { hitloc = TURRET; } else hitloc = LSIDE; break; case 12: hitloc = LSIDE; break; } break; case RIGHTSIDE: switch (roll) { case 2: case 12: hitloc = RSIDE; break; case 3: case 4: case 5: case 6: case 7: case 8: hitloc = RSIDE; break; case 10: if (GetSectInt(mech, TURRET)) hitloc = TURRET; else hitloc = RSIDE; break; case 11: if (GetSectInt(mech, TURRET)) { hitloc = TURRET; } else hitloc = RSIDE; break; } break; case FRONT: case BACK: switch (roll) { case 2: case 12: hitloc = FSIDE; break; case 3: hitloc = FSIDE; break; case 4: hitloc = FSIDE; break; case 5: hitloc = FSIDE; break; case 6: case 7: case 8: case 9: hitloc = FSIDE; break; case 10: if (GetSectInt(mech, TURRET)) hitloc = TURRET; else hitloc = FSIDE; break; case 11: if (GetSectInt(mech, TURRET)) { hitloc = TURRET; } else hitloc = FSIDE; break; } break; } break; } return (hitloc); } int FindHitLocation(MECH * mech, int hitGroup, int *iscritical, int *isrear) { int roll, hitloc = 0; int side; roll = Roll(); /* We have a varying set of crit charts we can use, so let's see what's been config'd */ /* We call the FindHitLocation_CritProof after the adv fasa hit loc function because * it already has a check built in for critproof (lookup crittable), the others don't */ switch (MechType(mech)) { case CLASS_VTOL: if (mudconf.btech_fasaadvvtolcrit) return FindAdvFasaVehicleHitLocation(mech, hitGroup, iscritical, isrear); else if (MechSpecials(mech) & CRITPROOF_TECH) return FindHitLocation_CritProof(mech, hitGroup, iscritical, isrear); else if (mudconf.btech_fasacrit) return FindFasaHitLocation(mech, hitGroup, iscritical, isrear); break; case CLASS_VEH_GROUND: if (mudconf.btech_fasaadvvhlcrit) return FindAdvFasaVehicleHitLocation(mech, hitGroup, iscritical, isrear); else if (MechSpecials(mech) & CRITPROOF_TECH) return FindHitLocation_CritProof(mech, hitGroup, iscritical, isrear); else if (mudconf.btech_fasacrit) return FindFasaHitLocation(mech, hitGroup, iscritical, isrear); break; default: if (MechSpecials(mech) & CRITPROOF_TECH) return FindHitLocation_CritProof(mech, hitGroup, iscritical, isrear); else if (mudconf.btech_fasacrit) return FindFasaHitLocation(mech, hitGroup, iscritical, isrear); break; } if (MechStatus(mech) & COMBAT_SAFE) return 0; if (MechDugIn(mech) && GetSectOInt(mech, TURRET) && Number(1, 100) >= 42) return TURRET; rollstat.hitrolls[roll - 2]++; rollstat.tothrolls++; switch (MechType(mech)) { case CLASS_BSUIT: if ((hitloc = get_bsuit_hitloc(mech)) < 0) return Number(0, NUM_BSUIT_MEMBERS - 1); case CLASS_MW: case CLASS_MECH: switch (hitGroup) { case LEFTSIDE: switch (roll) { case 2: if (crittable(mech, LTORSO, 60)) *iscritical = 1; return LTORSO; case 3: return LLEG; case 4: case 5: return LARM; case 6: return LLEG; case 7: return LTORSO; case 8: return CTORSO; case 9: return RTORSO; case 10: return RARM; case 11: return RLEG; case 12: if (mudconf.btech_exile_stun_code) return ModifyHeadHit(hitGroup, mech); return HEAD; } case RIGHTSIDE: switch (roll) { case 2: if (crittable(mech, RTORSO, 60)) *iscritical = 1; return RTORSO; case 3: return RLEG; case 4: case 5: return RARM; case 6: return RLEG; case 7: return RTORSO; case 8: return CTORSO; case 9: return LTORSO; case 10: return LARM; case 11: return LLEG; case 12: if (mudconf.btech_exile_stun_code) return ModifyHeadHit(hitGroup, mech); return HEAD; } case FRONT: case BACK: switch (roll) { case 2: if (crittable(mech, CTORSO, 60)) *iscritical = 1; return CTORSO; case 3: case 4: return RARM; case 5: return RLEG; case 6: return RTORSO; case 7: return CTORSO; case 8: return LTORSO; case 9: return LLEG; case 10: case 11: return LARM; case 12: if (mudconf.btech_exile_stun_code) return ModifyHeadHit(hitGroup, mech); return HEAD; } } break; case CLASS_VEH_GROUND: switch (hitGroup) { case LEFTSIDE: switch (roll) { case 2: case 12: if (crittable(mech, LSIDE, 40)) *iscritical = 1; return LSIDE; case 3: case 4: case 5: case 6: case 7: case 8: case 9: return LSIDE; case 10: return (GetSectInt(mech, TURRET)) ? TURRET : LSIDE; case 11: if (GetSectInt(mech, TURRET)) { if (crittable(mech, TURRET, 50)) *iscritical = 1; return TURRET; } else return LSIDE; } break; case RIGHTSIDE: switch (roll) { case 2: case 12: if (crittable(mech, RSIDE, 40)) *iscritical = 1; return RSIDE; case 3: case 4: case 5: case 6: case 7: case 8: case 9: return RSIDE; case 10: return (GetSectInt(mech, TURRET)) ? TURRET : RSIDE; case 11: if (GetSectInt(mech, TURRET)) { if (crittable(mech, TURRET, 50)) *iscritical = 1; return TURRET; } else return RSIDE; break; } break; case FRONT: case BACK: side = (hitGroup == FRONT ? FSIDE : BSIDE); switch (roll) { case 2: case 12: if (crittable(mech, FSIDE, 40)) *iscritical = 1; return side; case 3: case 4: case 5: case 6: case 7: case 8: case 9: return side; case 10: return (GetSectInt(mech, TURRET)) ? TURRET : side; case 11: if (GetSectInt(mech, TURRET)) { if (crittable(mech, TURRET, 50)) *iscritical = 1; return TURRET; } else return side; } } break; case CLASS_AERO: switch (hitGroup) { case FRONT: switch (roll) { case 2: case 12: return AERO_COCKPIT; case 3: case 11: if (crittable(mech, AERO_NOSE, 90)) LoseWeapon(mech, AERO_NOSE); return AERO_NOSE; case 4: case 10: if (roll == 10) DestroyBomb(mech, AERO_FUSEL); return AERO_FUSEL; case 5: return AERO_RWING; case 9: return AERO_LWING; case 6: case 7: case 8: return AERO_NOSE; } break; case LEFTSIDE: case RIGHTSIDE: side = ((hitGroup == LEFTSIDE) ? AERO_LWING : AERO_RWING); switch (roll) { case 2: return AERO_COCKPIT; case 12: if (crittable(mech, AERO_ENGINE, 99)) *iscritical = 1; return AERO_ENGINE; case 3: case 11: if (crittable(mech, side, 99)) LoseWeapon(mech, side); return side; case 4: case 10: if (crittable(mech, AERO_ENGINE, 90)) DestroyHeatSink(mech, AERO_ENGINE); return AERO_ENGINE; case 5: DestroyBomb(mech, AERO_FUSEL); return AERO_FUSEL; case 9: return AERO_NOSE; case 6: case 8: return side; case 7: return AERO_FUSEL; } break; case BACK: switch (roll) { case 2: case 12: if (crittable(mech, AERO_ENGINE, 90)) *iscritical = 1; return AERO_ENGINE; case 3: case 11: aero_ControlEffect(mech); return AERO_FUSEL; case 4: case 7: case 10: if (crittable(mech, AERO_FUSEL, 90)) DestroyHeatSink(mech, AERO_FUSEL); return AERO_FUSEL; case 5: return AERO_RWING; case 9: return AERO_LWING; case 6: case 8: return AERO_ENGINE; } } break; case CLASS_DS: case CLASS_SPHEROID_DS: switch (hitGroup) { case FRONT: switch (roll) { case 2: case 12: if (crittable(mech, DS_NOSE, 30)) ds_BridgeHit(mech); return DS_NOSE; case 3: case 11: if (crittable(mech, DS_NOSE, 50)) LoseWeapon(mech, DS_NOSE); return DS_NOSE; case 5: return DS_RWING; case 6: case 7: case 8: return DS_NOSE; case 9: return DS_LWING; case 4: case 10: return (Number(1, 2)) == 1 ? DS_LWING : DS_RWING; } case LEFTSIDE: case RIGHTSIDE: side = (hitGroup == LEFTSIDE) ? DS_LWING : DS_RWING; if (Number(1, 2) == 2) SpheroidToRear(mech, side); switch (roll) { case 2: if (crittable(mech, DS_NOSE, 30)) ds_BridgeHit(mech); return DS_NOSE; case 3: case 11: if (crittable(mech, side, 60)) LoseWeapon(mech, side); return side; case 4: case 5: case 6: case 7: case 8: case 10: return side; case 9: return DS_NOSE; case 12: if (crittable(mech, side, 60)) *iscritical = 1; return side; } case BACK: switch (roll) { case 2: case 12: if (crittable(mech, DS_AFT, 60)) *iscritical = 1; return DS_AFT; case 3: case 11: return DS_AFT; case 4: case 7: case 10: if (crittable(mech, DS_AFT, 60)) DestroyHeatSink(mech, DS_AFT); return DS_AFT; case 5: hitloc = DS_RWING; SpheroidToRear(mech, hitloc); return hitloc; case 6: case 8: return DS_AFT; case 9: hitloc = DS_LWING; SpheroidToRear(mech, hitloc); return hitloc; } } break; case CLASS_VTOL: switch (hitGroup) { case LEFTSIDE: switch (roll) { case 2: hitloc = ROTOR; *iscritical = 1; DoVTOLRotorDestroyedCrit(mech, NULL, 1); break; case 3: case 4: hitloc = ROTOR; DoVTOLRotorDamagedCrit(mech); break; case 5: case 6: case 7: case 8: case 9: hitloc = LSIDE; break; case 10: case 11: hitloc = ROTOR; DoVTOLRotorDamagedCrit(mech); break; case 12: hitloc = ROTOR; *iscritical = 1; DoVTOLRotorDamagedCrit(mech); break; } break; case RIGHTSIDE: switch (roll) { case 2: hitloc = ROTOR; *iscritical = 1; DoVTOLRotorDestroyedCrit(mech, NULL, 1); break; case 3: case 4: hitloc = ROTOR; DoVTOLRotorDamagedCrit(mech); break; case 5: case 6: case 7: case 8: case 9: hitloc = RSIDE; break; case 10: case 11: hitloc = ROTOR; DoVTOLRotorDamagedCrit(mech); break; case 12: hitloc = ROTOR; *iscritical = 1; DoVTOLRotorDamagedCrit(mech); break; } break; case FRONT: case BACK: side = (hitGroup == FRONT ? FSIDE : BSIDE); switch (roll) { case 2: hitloc = ROTOR; *iscritical = 1; DoVTOLRotorDestroyedCrit(mech, NULL, 1); break; case 3: case 4: hitloc = ROTOR; DoVTOLRotorDamagedCrit(mech); break; case 5: case 6: case 7: case 8: case 9: hitloc = side; break; case 10: case 11: hitloc = ROTOR; DoVTOLRotorDamagedCrit(mech); break; case 12: hitloc = ROTOR; *iscritical = 1; DoVTOLRotorDamagedCrit(mech); break; } break; } break; case CLASS_VEH_NAVAL: switch (hitGroup) { case LEFTSIDE: switch (roll) { case 2: hitloc = LSIDE; if (crittable(mech, hitloc, 40)) *iscritical = 1; break; case 3: case 4: case 5: hitloc = LSIDE; break; case 9: hitloc = LSIDE; break; case 10: if (GetSectInt(mech, TURRET)) hitloc = TURRET; else hitloc = LSIDE; break; case 11: if (GetSectInt(mech, TURRET)) { hitloc = TURRET; if (crittable(mech, hitloc, 40)) *iscritical = 1; } else hitloc = LSIDE; break; case 12: hitloc = LSIDE; *iscritical = 1; break; } break; case RIGHTSIDE: switch (roll) { case 2: case 12: hitloc = RSIDE; if (crittable(mech, hitloc, 40)) *iscritical = 1; break; case 3: case 4: case 5: case 6: case 7: case 8: hitloc = RSIDE; break; case 10: if (GetSectInt(mech, TURRET)) hitloc = TURRET; else hitloc = RSIDE; break; case 11: if (GetSectInt(mech, TURRET)) { hitloc = TURRET; if (crittable(mech, hitloc, 40)) *iscritical = 1; } else hitloc = RSIDE; break; } break; case FRONT: case BACK: switch (roll) { case 2: case 12: hitloc = FSIDE; if (crittable(mech, hitloc, 40)) *iscritical = 1; break; case 3: hitloc = FSIDE; break; case 4: hitloc = FSIDE; break; case 5: hitloc = FSIDE; break; case 6: case 7: case 8: case 9: hitloc = FSIDE; break; case 10: if (GetSectInt(mech, TURRET)) hitloc = TURRET; else hitloc = FSIDE; break; case 11: if (GetSectInt(mech, TURRET)) { hitloc = TURRET; *iscritical = 1; } else hitloc = FSIDE; break; } break; } break; } return (hitloc); } int FindAreaHitGroup(MECH * mech, MECH * target) { int quadr; quadr = AcceptableDegree(FindBearing(MechFX(mech), MechFY(mech), MechFX(target), MechFY(target)) - MechFacing(target)); #if 1 if ((quadr >= 135) && (quadr <= 225)) return FRONT; if ((quadr < 45) || (quadr > 315)) return BACK; if ((quadr >= 45) && (quadr < 135)) return LEFTSIDE; return RIGHTSIDE; #else /* These are 'official' BT arcs */ if (quadr >= 120 && quadr <= 240) return FRONT; if (quadr < 30 || quadr > 330) return BACK; if (quadr >= 30 && quadr < 120) return LEFTSIDE; return RIGHTSIDE; #endif } int FindTargetHitLoc(MECH * mech, MECH * target, int *isrear, int *iscritical) { int hitGroup; /* *isrear = 0; */ *iscritical = 0; hitGroup = FindAreaHitGroup(mech, target); if (hitGroup == BACK) *isrear = 1; if (MechType(target) == CLASS_MECH && (MechStatus(target) & PARTIAL_COVER)) return FindPunchLocation(hitGroup); if (MechType(mech) == CLASS_MW && MechType(target) == CLASS_MECH && MechZ(mech) <= MechZ(target)) return FindKickLocation(hitGroup); if (MechType(target) == CLASS_MECH && ((MechType(mech) == CLASS_BSUIT && MechSwarmTarget(mech) == target->mynum))) return FindSwarmHitLocation(iscritical, isrear); return FindHitLocation(target, hitGroup, iscritical, isrear); } int findNARCHitLoc(MECH * mech, MECH * hitMech, int *tIsRearHit) { int tIsRear = 0; int tIsCritical = 0; int wHitLoc = FindTargetHitLoc(mech, hitMech, &tIsRear, &tIsCritical); while (GetSectInt(hitMech, wHitLoc) <= 0) { wHitLoc = TransferTarget(hitMech, wHitLoc); if (wHitLoc < 0) return -1; } *tIsRearHit = 0; if (tIsRear) { if (MechType(hitMech) == CLASS_MECH) *tIsRearHit = 1; else if (wHitLoc == FSIDE) wHitLoc = BSIDE; } return wHitLoc; } int FindTCHitLoc(MECH * mech, MECH * target, int *isrear, int *iscritical) { int hitGroup; *isrear = 0; *iscritical = 0; hitGroup = FindAreaHitGroup(mech, target); if (hitGroup == BACK) *isrear = 1; if (MechAimType(mech) == MechType(target) && Number(1, 6) >= 3) switch (MechType(target)) { case CLASS_MECH: case CLASS_MW: switch (MechAim(mech)) { case RARM: if (hitGroup != LEFTSIDE) return RARM; break; case LARM: if (hitGroup != RIGHTSIDE) return LARM; break; case RLEG: if (hitGroup != LEFTSIDE && !(MechStatus(target) & PARTIAL_COVER)) return RLEG; break; case LLEG: if (hitGroup != RIGHTSIDE && !(MechStatus(target) & PARTIAL_COVER)) return LLEG; break; case RTORSO: if (hitGroup != LEFTSIDE) return RTORSO; break; case LTORSO: if (hitGroup != RIGHTSIDE) return LTORSO; break; case CTORSO: /* if (hitGroup != LEFTSIDE && hitGroup != RIGHTSIDE) */ return CTORSO; case HEAD: if (Immobile(target)) return HEAD; } break; case CLASS_AERO: case CLASS_DS: switch (MechAim(mech)) { case AERO_NOSE: if (hitGroup != BACK) return AERO_NOSE; break; case AERO_LWING: if (hitGroup != RIGHTSIDE) return AERO_LWING; break; case AERO_RWING: if (hitGroup != LEFTSIDE) return AERO_RWING; break; case AERO_COCKPIT: if (hitGroup != BACK) return AERO_COCKPIT; break; case AERO_FUSEL: if (hitGroup != FRONT) return AERO_FUSEL; break; case AERO_ENGINE: if (hitGroup != FRONT) return AERO_ENGINE; break; } case CLASS_VEH_GROUND: case CLASS_VEH_NAVAL: case CLASS_VTOL: switch (MechAim(mech)) { case RSIDE: if (hitGroup != LEFTSIDE) return (RSIDE); break; case LSIDE: if (hitGroup != RIGHTSIDE) return (LSIDE); break; case FSIDE: if (hitGroup != BACK) return (FSIDE); break; case BSIDE: if (hitGroup != FRONT) return (BSIDE); break; case TURRET: return (TURRET); break; } break; } if (MechType(target) == CLASS_MECH && (MechStatus(target) & PARTIAL_COVER)) return FindPunchLocation(hitGroup); return FindHitLocation(target, hitGroup, iscritical, isrear); } int FindAimHitLoc(MECH * mech, MECH * target, int *isrear, int *iscritical) { int hitGroup; *isrear = 0; *iscritical = 0; hitGroup = FindAreaHitGroup(mech, target); if (hitGroup == BACK) *isrear = 1; if (MechType(target) == CLASS_MECH || MechType(target) == CLASS_MW) switch (MechAim(mech)) { case RARM: if (hitGroup != LEFTSIDE) return (RARM); break; case LARM: if (hitGroup != RIGHTSIDE) return (LARM); break; case RLEG: if (hitGroup != LEFTSIDE && !(MechStatus(target) & PARTIAL_COVER)) return (RLEG); break; case LLEG: if (hitGroup != RIGHTSIDE && !(MechStatus(target) & PARTIAL_COVER)) return (LLEG); break; case RTORSO: if (hitGroup != LEFTSIDE) return (RTORSO); break; case LTORSO: if (hitGroup != RIGHTSIDE) return (LTORSO); break; case CTORSO: return (CTORSO); case HEAD: return (HEAD); } else if (is_aero(target)) return MechAim(mech); else switch (MechAim(mech)) { case RSIDE: if (hitGroup != LEFTSIDE) return (RSIDE); break; case LSIDE: if (hitGroup != RIGHTSIDE) return (LSIDE); break; case FSIDE: if (hitGroup != BACK) return (FSIDE); break; case BSIDE: if (hitGroup != FRONT) return (BSIDE); break; case TURRET: return (TURRET); break; } if (MechType(target) == CLASS_MECH && (MechStatus(target) & PARTIAL_COVER)) return FindPunchLocation(hitGroup); return FindHitLocation(target, hitGroup, iscritical, isrear); }