00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <stdio.h>
00012 #include <stdlib.h>
00013
00014 #include "mech.h"
00015 #include "btmacros.h"
00016 #include "mech.combat.h"
00017 #include "mech.events.h"
00018 #include "p.pcombat.h"
00019 #include "p.mech.combat.h"
00020 #include "p.mech.combat.misc.h"
00021 #include "p.mech.combat.missile.h"
00022 #include "p.mech.damage.h"
00023 #include "p.mech.ecm.h"
00024 #include "p.mech.hitloc.h"
00025 #include "p.mech.los.h"
00026 #include "p.mech.utils.h"
00027
00028 int pilot_override;
00029
00030 void Missile_Hit(MECH * mech,
00031 MECH * target,
00032 int hitX,
00033 int hitY,
00034 int isrear,
00035 int iscritical,
00036 int weapindx,
00037 int fireMode,
00038 int ammoMode,
00039 int num_missiles_hit, int damage, int salvo_size, int LOS,
00040 int bth, int tIsSwarmAttack)
00041 {
00042 int orig_num_missiles = num_missiles_hit;
00043 int this_time;
00044 int this_damage;
00045 int total_damage = 0;
00046 int clear_damage = 0;
00047 int hitloc;
00048 int tCheckWoodsDamageDecrement = 0;
00049 MAP *mech_map = getMap(mech->mapindex);
00050 char buf[SBUF_SIZE];
00051
00052 total_damage = num_missiles_hit * damage;
00053
00054 if(target && mudconf.btech_moddamagewithwoods &&
00055 IsForestHex(mech_map, MechX(target), MechY(target)) &&
00056 (fireMode > -1) && (ammoMode > -1) &&
00057 ((MechZ(target) - 2) <= Elevation(mech_map, MechX(target),
00058 MechY(target)))) {
00059 tCheckWoodsDamageDecrement = 1;
00060 clear_damage = total_damage;
00061
00062 if(GetRTerrain(mech_map, MechX(target),
00063 MechY(target)) == LIGHT_FOREST)
00064 total_damage -= 2;
00065 else if(GetRTerrain(mech_map, MechX(target),
00066 MechY(target)) == HEAVY_FOREST)
00067 total_damage -= 4;
00068
00069 if(total_damage <= 0)
00070 num_missiles_hit = 0;
00071 else
00072 num_missiles_hit = total_damage / damage;
00073
00074 possibly_ignite_or_clear(mech, weapindx, ammoMode, clear_damage,
00075 MechX(target), MechY(target), 1);
00076
00077 strcpy(buf, "");
00078
00079 if(IsMissile(weapindx))
00080 sprintf(buf, "%s%s", "missile", orig_num_missiles > 1 ? "s" : "");
00081 else if(ammoMode & LBX_MODE)
00082 sprintf(buf, "%s%s", "pellet", orig_num_missiles > 1 ? "s" : "");
00083 else if((fireMode && ULTRA_MODE) || (fireMode && RFAC_MODE) ||
00084 (fireMode && RAC_MODES))
00085 sprintf(buf, "%s%s", "slug", orig_num_missiles > 1 ? "s" : "");
00086 else
00087 sprintf(buf, "%s", "damage");
00088
00089 mech_printf(mech, MECHALL,
00090 "%s %s %s absorbed by the trees!",
00091 (orig_num_missiles == 1 ? "The" : num_missiles_hit ==
00092 0 ? "All of the" : "Some of the"), buf,
00093 (orig_num_missiles == 1 ? "is" : "are"));
00094 mech_printf(target, MECHALL, "The trees absorb %s %s",
00095 ((orig_num_missiles == 1) ||
00096 (num_missiles_hit == 0) ? "the" : "some of the"), buf);
00097 }
00098
00099 while (num_missiles_hit) {
00100 this_time = MIN(salvo_size, num_missiles_hit);
00101 this_damage = this_time * damage;
00102
00103 if(target) {
00104 hitloc = FindTargetHitLoc(mech, target, &isrear, &iscritical);
00105
00106 DamageMech(target, mech, LOS, GunPilot(mech), hitloc, isrear,
00107 iscritical, pc_to_dam_conversion(target, weapindx,
00108 this_damage), 0,
00109 weapindx, bth, -1, 0, tIsSwarmAttack);
00110 } else {
00111 hex_hit(mech, hitX, hitY, weapindx, ammoMode, this_damage, 1);
00112 }
00113
00114 num_missiles_hit -= this_time;
00115 }
00116 }
00117
00118 int MissileHitIndex(MECH * mech,
00119 MECH * hitMech, int weapindx, int wSection, int wCritSlot, int glance)
00120 {
00121 int hit_roll;
00122 int r1, r2, r3, rtmp;
00123 int tHotloading =
00124 HotLoading(weapindx, GetPartFireMode(mech, wSection, wCritSlot));
00125 int wRollInc = 0;
00126 int wFinalRoll = 0;
00127 int tUseArtemisBonus =
00128 GetPartAmmoMode(mech, wSection, wCritSlot) & ARTEMIS_MODE;
00129 int tUseNARCBonus = 0;
00130
00131 if(hitMech) {
00132 if(ECMProtected(hitMech) || AngelECMProtected(hitMech)) {
00133 tUseArtemisBonus = 0;
00134 tUseNARCBonus = 0;
00135 } else {
00136 tUseNARCBonus =
00137 (GetPartAmmoMode(mech, wSection, wCritSlot) & NARC_MODE) &&
00138 (checkAllSections(hitMech, NARC_ATTACHED) ||
00139 checkAllSections(hitMech, INARC_HOMING_ATTACHED));
00140 }
00141 }
00142
00143 if(AnyECMDisturbed(mech)) {
00144 tUseArtemisBonus = 0;
00145 tUseNARCBonus = 0;
00146 }
00147
00148
00149
00150
00151 if(IsMissile(weapindx) && (tUseArtemisBonus || tUseNARCBonus))
00152 wRollInc = 2;
00153
00154
00155 r1 = Number(1, 6);
00156 r2 = Number(1, 6);
00157 r3 = Number(1, 6);
00158
00159 if(r1 > r2)
00160 Swap(r1, r2);
00161 if(r2 > r3)
00162 Swap(r2, r3);
00163
00164 if(tHotloading)
00165 hit_roll = r1 + r2 - 2;
00166 else
00167 hit_roll = Roll() - 2;
00168
00169 if((!hitMech || (hitMech && !AngelECMProtected(hitMech))) &&
00170 !AngelECMDisturbed(mech) && (MechWeapons[weapindx].special & STREAK)) {
00171 return 10;
00172 }
00173
00174
00175 if(glance)
00176 wRollInc += -4;
00177 if(wRollInc)
00178 hit_roll = hit_roll + wRollInc;
00179
00180
00181
00182 if(glance && (hit_roll < 0))
00183 return -1;
00184
00185 wFinalRoll = MAX(MIN(hit_roll, 10), 0);
00186
00187 return wFinalRoll;
00188 }
00189
00190 int MissileHitTarget(MECH * mech,
00191 int weapindx,
00192 int wSection,
00193 int wCritSlot,
00194 MECH * hitMech, int hitX, int hitY, int LOS,
00195 int baseToHit, int roll, int incoming,
00196 int tIsSwarmAttack, int player_roll)
00197 {
00198 int isrear = 0, iscritical = 0;
00199 int AMStype, ammoLoc, ammoCrit;
00200 int AMSShotdown = 0;
00201 int hit;
00202 int i, j = -1, k, l = 0;
00203 int wNARCType = 0;
00204 int ammoMode = GetPartAmmoMode(mech, wSection, wCritSlot);
00205 int tIsInferno = (ammoMode & INFERNO_MODE);
00206 int wNARCHitLoc = 0;
00207 int tIsRear = 0;
00208 char strLocName[30];
00209 int missileindex = 0;
00210
00211
00212 if(IsMissile(weapindx)) {
00213 if((MechWeapons[weapindx].special & NARC) &&
00214 !(GetPartAmmoMode(mech, wSection, wCritSlot) & NARC_MODE))
00215 wNARCType = 1;
00216 else if((MechWeapons[weapindx].special & INARC) &&
00217 !(GetPartAmmoMode(mech, wSection,
00218 wCritSlot) & INARC_EXPLO_MODE)) {
00219
00220 if(GetPartAmmoMode(mech, wSection,
00221 wCritSlot) & INARC_HAYWIRE_MODE)
00222 wNARCType = 3;
00223 else if(GetPartAmmoMode(mech, wSection,
00224 wCritSlot) & INARC_ECM_MODE)
00225 wNARCType = 4;
00226 else
00227 wNARCType = 2;
00228 }
00229
00230
00231 if(hitMech && (!((ammoMode & SWARM_MODE) ||
00232 (ammoMode & SWARM1_MODE)
00233 || (ammoMode & MINE_MODE)))) {
00234 if(LocateAMSDefenses(hitMech, &AMStype, &ammoLoc, &ammoCrit))
00235 AMSShotdown =
00236 AMSMissiles(mech, hitMech, wNARCType ? 1 : incoming,
00237 AMStype, ammoLoc, ammoCrit, LOS,
00238 roll >= baseToHit);
00239 }
00240
00241 if(wNARCType) {
00242 if(roll >= baseToHit) {
00243 if(hitMech) {
00244 if(AMSShotdown > 0) {
00245 if(LOS)
00246 mech_notify(mech, MECHALL,
00247 "The pod is shot down by the target!");
00248
00249 mech_notify(hitMech, MECHALL,
00250 "Your Anti-Missile System activates and shoots down the incoming pod!");
00251
00252 return 0;
00253 }
00254
00255 wNARCHitLoc = findNARCHitLoc(mech, hitMech, &tIsRear);
00256
00257
00258 if(wNARCHitLoc < 0) {
00259 mech_notify(mech, MECHALL,
00260 "Your NARC Beacon attaches to the target!");
00261
00262 return 0;
00263 }
00264
00265 ArmorStringFromIndex(wNARCHitLoc, strLocName,
00266 MechType(hitMech),
00267 MechMove(hitMech));
00268
00269 if(wNARCType == 1)
00270 MechSections(hitMech)[wNARCHitLoc].specials |=
00271 NARC_ATTACHED;
00272 else if(wNARCType == 2)
00273 MechSections(hitMech)[wNARCHitLoc].specials |=
00274 INARC_HOMING_ATTACHED;
00275 else if(wNARCType == 3) {
00276 MechSections(hitMech)[wNARCHitLoc].specials |=
00277 INARC_HAYWIRE_ATTACHED;
00278
00279 mech_notify(hitMech, MECHALL,
00280 "Your targetting system goes a bit haywire!");
00281 } else if(wNARCType == 4) {
00282 MechSections(hitMech)[wNARCHitLoc].specials |=
00283 INARC_ECM_ATTACHED;
00284
00285 checkECM(hitMech);
00286 }
00287
00288 mech_printf(hitMech, MECHALL,
00289 "A NARC Beacon has been attached to your %s%s!",
00290 strLocName, tIsRear == 1 ? " (Rear)" : "");
00291 mech_printf(mech, MECHALL,
00292 "Your NARC Beacon attaches to the target's %s%s!",
00293 strLocName, tIsRear == 1 ? " (Rear)" : "");
00294 }
00295 } else
00296 mech_notify(mech, MECHALL,
00297 "Your NARC Beacon flies off into the distance.");
00298
00299 return 0;
00300 }
00301 }
00302
00303 if(roll < baseToHit)
00304 return incoming;
00305
00306 for(i = 0; MissileHitTable[i].key >= 0; i++)
00307 if((k = MissileHitTable[i].num_missiles[10]) <= incoming &&
00308 ((MechWeapons[MissileHitTable[i].key].special & STREAK) ==
00309 (MechWeapons[weapindx].special & STREAK)))
00310 if(k >= l && (j < 0 || MissileHitTable[i].key != weapindx ||
00311 k > l)) {
00312 j = i;
00313 l = k;
00314 }
00315
00316 if(j < 0)
00317 return 0;
00318
00319 missileindex = MissileHitIndex(mech,hitMech,weapindx,wSection,wCritSlot,(mudconf.btech_glancing_blows) && (player_roll == baseToHit) ? 1 : 0);
00320 if (missileindex < 0 )
00321 hit = MIN(incoming, 1);
00322 else
00323 hit = MIN(incoming, MissileHitTable[j].num_missiles[missileindex]);
00324
00325
00326 if(LOS) {
00327 mech_printf(mech, MECHALL, "%%cg%s with %d missile%s!%%c",
00328 LOS == 1 ? "You hit" : "The swarm hits", hit,
00329 hit > 1 ? "s" : "");
00330 }
00331
00332 if(AMSShotdown > 0) {
00333 if(AMSShotdown >= hit) {
00334 if(LOS)
00335 mech_notify(mech, MECHALL,
00336 "All of your missiles are shot down by the target!");
00337
00338 mech_notify(hitMech, MECHALL,
00339 "Your Anti-Missile System activates and shoots all the incoming missiles!");
00340 } else {
00341 mech_printf(mech, MECHALL,
00342 "The target shoots down %d of your missiles!",
00343 AMSShotdown);
00344
00345 mech_printf(hitMech, MECHALL,
00346 "Your Anti-Missile System activates and shoots down %d incoming missiles!",
00347 AMSShotdown);
00348 }
00349 }
00350
00351 hit = MAX(0, hit - AMSShotdown);
00352
00353 if(hit <= 0)
00354 return 0;
00355
00356 if(tIsInferno) {
00357 if(hitMech)
00358 Inferno_Hit(mech, hitMech, hit, LOS);
00359 else
00360 hex_hit(mech, hitX, hitY, weapindx, GetPartAmmoMode(mech,
00361 wSection,
00362 wCritSlot), 0,
00363 0);
00364 } else {
00365 if(mudconf.btech_glancing_blows &&
00366 (player_roll == baseToHit) && hitMech ) {
00367 if(!(MechWeapons[weapindx].special & STREAK)) {
00368 MechLOSBroadcast(hitMech, "is nicked by a glancing blow!");
00369 mech_notify(hitMech, MECHALL,
00370 "You are nicked by a glancing blow!");
00371 }
00372 }
00373 Missile_Hit(mech, hitMech, hitX, hitY, isrear, iscritical,
00374 weapindx, GetPartFireMode(mech, wSection, wCritSlot),
00375 GetPartAmmoMode(mech, wSection, wCritSlot), hit,
00376 MechWeapons[weapindx].damage, Clustersize(weapindx),
00377 LOS, baseToHit, tIsSwarmAttack);
00378 }
00379
00380 return incoming - hit;
00381 }
00382
00383 void SwarmHitTarget(MECH * mech,
00384 int weapindx,
00385 int wSection,
00386 int wCritSlot,
00387 MECH * hitMech,
00388 int LOS, int baseToHit, int roll, int incoming, int fof,
00389 int tIsSwarmAttack, int player_roll)
00390 {
00391 #define MAX_STAR 10
00392
00393 MECH *star[MAX_STAR];
00394 int present_target = 0;
00395 int missiles;
00396 int loop;
00397 MAP *map = FindObjectsData(mech->mapindex);
00398 float r = 0.0, ran = 0, flrange = 0.0;
00399 MECH *source = mech, *tempMech;
00400 int i, j;
00401
00402 for(loop = 0; MissileHitTable[loop].key != -1; loop++)
00403 if(MissileHitTable[loop].key == weapindx)
00404 break;
00405
00406 if(!(MissileHitTable[loop].key == weapindx))
00407 return;
00408
00409 missiles = MissileHitTable[loop].num_missiles[10];
00410 while (missiles > 0) {
00411 flrange = flrange + FaMechRange(source, hitMech);
00412 ran = FaMechRange(mech, hitMech);
00413 if(flrange > EGunRange(weapindx)) {
00414 mech_notify(hitMech, MECHALL,
00415 "Luckily, the missiles fall short of you!");
00416 return;
00417 }
00418 if(!(missiles =
00419 MissileHitTarget(mech, weapindx, wSection, wCritSlot,
00420 hitMech, -1, -1, InLineOfSight_NB(mech, hitMech,
00421 MechX(mech),
00422 MechY(mech),
00423 ran) ?
00424 present_target == 0 ? 1 : 2 : 0, baseToHit,
00425 present_target == 0 ? roll : Roll(), missiles,
00426 tIsSwarmAttack, player_roll)))
00427 return;
00428
00429 if(present_target == MAX_STAR)
00430 return;
00431 star[present_target++] = hitMech;
00432 source = hitMech;
00433 hitMech = NULL;
00434 for(i = 0; i < map->first_free; i++)
00435 if((tempMech = FindObjectsData(map->mechsOnMap[i])))
00436 if(!fof || (MechTeam(tempMech) != MechTeam(mech))) {
00437 for(j = 0; j < present_target; j++)
00438 if(tempMech == star[j])
00439 break;
00440 if(MechStatus(tempMech) & COMBAT_SAFE)
00441 continue;
00442 if(j != present_target)
00443 continue;
00444 if(!hitMech && (r = FaMechRange(source, tempMech)) < 1.9)
00445 if(InLineOfSight_NB(source, tempMech,
00446 MechX(source), MechY(source),
00447 r)) {
00448 hitMech = tempMech;
00449 ran = r;
00450 }
00451 }
00452 if(!hitMech)
00453 return;
00454 if(mech != hitMech)
00455 mech_notify(hitMech, MECHALL,
00456 "The missile-swarm turns towards you!");
00457 if(InLineOfSight_NB(mech, source, MechX(mech), MechY(mech),
00458 FaMechRange(mech, source)))
00459 mech_printf(mech, MECHALL,
00460 "Your missile-swarm of %d missile%s targets %s!",
00461 missiles, missiles > 1 ? "s" : "",
00462 mech == hitMech ? "YOU!!" : GetMechToMechID(mech,
00463 hitMech));
00464 MechLOSBroadcasti(mech, hitMech, "'s missile-swarm targets %s!");
00465 }
00466 }
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480 int AMSMissiles(MECH * mech,
00481 MECH * hitMech,
00482 int incoming, int type,
00483 int ammoLoc, int ammoCrit, int LOS, int missilesDidHit)
00484 {
00485 int num_missiles_shotdown;
00486
00487 if(MechWeapons[type].special & CLAT)
00488 num_missiles_shotdown = Roll();
00489 else
00490 num_missiles_shotdown = Number(1, 6);
00491
00492 if(num_missiles_shotdown > incoming)
00493 num_missiles_shotdown = incoming;
00494
00495 if(num_missiles_shotdown >= GetPartData(hitMech, ammoLoc, ammoCrit))
00496 GetPartData(hitMech, ammoLoc, ammoCrit) = 0;
00497 else
00498 GetPartData(hitMech, ammoLoc, ammoCrit) -= num_missiles_shotdown;
00499
00500 if(!missilesDidHit) {
00501 mech_notify(hitMech, MECHALL,
00502 "Your Anti-Missile System activates and shoots at the incoming missiles!");
00503 return 0;
00504 }
00505
00506 return num_missiles_shotdown;
00507 }
00508
00509 int LocateAMSDefenses(MECH * target,
00510 int *AMStype, int *ammoLoc, int *ammoCrit)
00511 {
00512 int AMSsect, AMScrit;
00513 int i, j = 0, w, t = 0;
00514
00515 if(!(MechSpecials(target) & (IS_ANTI_MISSILE_TECH |
00516 CL_ANTI_MISSILE_TECH)) ||
00517 !Started(target) || !(MechStatus(target) & AMS_ENABLED))
00518 return 0;
00519
00520 for(i = 0; i < NUM_SECTIONS; i++) {
00521 for(j = 0; j < NUM_CRITICALS; j++)
00522 if(IsWeapon((t = GetPartType(target, i, j))))
00523 if(IsAMS(Weapon2I(t)))
00524 if(!(PartIsNonfunctional(target, i, j) ||
00525 WpnIsRecycling(target, i, j)))
00526 break;
00527 if(j < NUM_CRITICALS)
00528 break;
00529 }
00530
00531 if(i == NUM_SECTIONS)
00532 return 0;
00533
00534 w = Weapon2I(t);
00535 AMSsect = i;
00536 AMScrit = j;
00537 *AMStype = w;
00538
00539 if(!(FindAmmoForWeapon(target, w, AMSsect, ammoLoc, ammoCrit)))
00540 return 0;
00541
00542 if(!(GetPartData(target, *ammoLoc, *ammoCrit)))
00543 return 0;
00544
00545 SetRecyclePart(target, AMSsect, AMScrit, MechWeapons[w].vrt);
00546 MechWeapHeat(target) += (float) MechWeapons[w].heat;
00547 return 1;
00548 }
00549
00550
00551
00552