00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <config.h>
00036
00037 #include <stdlib.h>
00038 #include "damage.h"
00039 #include "empobj.h"
00040 #include "file.h"
00041 #include "item.h"
00042 #include "misc.h"
00043 #include "mission.h"
00044 #include "nsc.h"
00045 #include "optlist.h"
00046 #include "path.h"
00047 #include "player.h"
00048 #include "prototypes.h"
00049 #include "queue.h"
00050 #include "xy.h"
00051
00052 struct genlist {
00053 struct emp_qelem queue;
00054 void *cp;
00055 struct empobj *thing;
00056 };
00057
00058 struct airport {
00059 struct emp_qelem queue;
00060 coord x, y;
00061 natid own;
00062 };
00063
00064 static void add_airport(struct emp_qelem *, coord, coord);
00065 static int air_damage(struct emp_qelem *, coord, coord, int, natid,
00066 char *, int);
00067 static void build_mission_list(struct genlist *, coord, coord, int, natid);
00068 static void build_mission_list_type(struct genlist *, coord, coord, int,
00069 int, natid);
00070 static void divide(struct emp_qelem *, struct emp_qelem *, coord, coord);
00071 static int dosupport(struct genlist *, coord, coord, natid, natid);
00072 static int find_airport(struct emp_qelem *, coord, coord);
00073 static int mission_pln_arm(struct emp_qelem *, coord, coord, int,
00074 int, struct ichrstr *, int, int, int *);
00075 static void mission_pln_sel(struct emp_qelem *, int, int, int);
00076 static int perform_mission(coord, coord, natid, struct emp_qelem *, int,
00077 char *, int);
00078
00079
00080
00081
00082 int
00083 ground_interdict(coord x, coord y, natid victim, char *s)
00084 {
00085 int cn;
00086 int dam = 0, newdam, rel;
00087 struct genlist mi[MAXNOC];
00088 int z;
00089
00090 memset(mi, 0, sizeof(mi));
00091 for (z = 1; z < MAXNOC; z++)
00092 emp_initque((struct emp_qelem *)&mi[z]);
00093
00094 build_mission_list(mi, x, y, MI_INTERDICT, victim);
00095
00096 for (cn = 1; cn < MAXNOC; cn++) {
00097 rel = getrel(getnatp(cn), victim);
00098 if (rel > HOSTILE)
00099 continue;
00100
00101 if (QEMPTY(&mi[cn].queue))
00102 continue;
00103
00104 newdam = perform_mission(x, y, victim, &mi[cn].queue,
00105 MI_INTERDICT, s, SECT_HARDTARGET);
00106 dam += newdam;
00107 if (newdam)
00108 mpr(victim, "%s interdiction mission does %d damage!\n",
00109 cname(cn), newdam);
00110 }
00111 if (dam) {
00112 collateral_damage(x, y, dam, 0);
00113 }
00114 return dam;
00115 }
00116
00117 int
00118 collateral_damage(coord x, coord y, int dam, struct emp_qelem *list)
00119 {
00120 int coll;
00121 struct sctstr sect;
00122
00123 if (!dam)
00124 return 0;
00125
00126 getsect(x, y, §);
00127 if (sect.sct_own) {
00128 coll = ldround((double)dam * collateral_dam, 1);
00129 if (coll == 0)
00130 return 0;
00131 mpr(sect.sct_own, "%s takes %d%% collateral damage\n",
00132 xyas(x, y, sect.sct_own), coll);
00133 sectdamage(§, coll, list);
00134 putsect(§);
00135 return coll;
00136 }
00137 return 0;
00138 }
00139
00140 static int
00141 only_subs(struct emp_qelem *list)
00142 {
00143 struct emp_qelem *qp;
00144 struct genlist *glp;
00145 struct mchrstr *mcp;
00146
00147 for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
00148 glp = (struct genlist *)qp;
00149
00150 if (glp->thing->ef_type != EF_SHIP)
00151 return 0;
00152 mcp = glp->cp;
00153 if (!(mcp->m_flags & M_SUB))
00154 return 0;
00155
00156 }
00157
00158 return 1;
00159 }
00160
00161
00162
00163
00164
00165 int
00166 unit_interdict(coord x, coord y, natid victim, char *s, int hardtarget,
00167 int mission)
00168 {
00169 int cn;
00170 int dam = 0, newdam;
00171 struct genlist mi[MAXNOC];
00172 int z;
00173 int osubs;
00174
00175 memset(mi, 0, sizeof(mi));
00176 for (z = 1; z < MAXNOC; z++)
00177 emp_initque((struct emp_qelem *)&mi[z]);
00178
00179 build_mission_list(mi, x, y, mission, victim);
00180
00181 for (cn = 1; cn < MAXNOC; cn++) {
00182 if (cn == victim)
00183 continue;
00184 if (mission == MI_SINTERDICT) {
00185 if (getrel(getnatp(cn), victim) >= FRIENDLY)
00186 continue;
00187 } else if (getrel(getnatp(cn), victim) > HOSTILE)
00188 continue;
00189
00190 if (QEMPTY(&mi[cn].queue))
00191 continue;
00192
00193 osubs = only_subs(&mi[cn].queue);
00194 newdam = perform_mission(x, y, victim, &mi[cn].queue,
00195 mission, s, hardtarget);
00196 dam += newdam;
00197 if (newdam) {
00198
00199
00200 mpr(victim, "%s interdiction mission does %d damage!\n",
00201 osubs ? "Enemy" : cname(cn), newdam);
00202 }
00203 }
00204 if (dam) {
00205 collateral_damage(x, y, dam, 0);
00206 }
00207 return dam;
00208 }
00209
00210
00211
00212
00213 int
00214 off_support(coord x, coord y, natid victim, natid actee)
00215 {
00216 int dam = 0;
00217 struct genlist mi[MAXNOC];
00218 int z;
00219
00220 memset(mi, 0, sizeof(mi));
00221 for (z = 1; z < MAXNOC; z++)
00222 emp_initque((struct emp_qelem *)&mi[z]);
00223
00224 build_mission_list(mi, x, y, MI_SUPPORT, victim);
00225 build_mission_list(mi, x, y, MI_OSUPPORT, victim);
00226
00227 dam = dosupport(mi, x, y, victim, actee);
00228 return dam;
00229 }
00230
00231
00232
00233
00234 int
00235 def_support(coord x, coord y, natid victim, natid actee)
00236 {
00237 int dam = 0;
00238 struct genlist mi[MAXNOC];
00239 int z;
00240
00241 memset(mi, 0, sizeof(mi));
00242 for (z = 1; z < MAXNOC; z++)
00243 emp_initque((struct emp_qelem *)&mi[z]);
00244
00245 build_mission_list(mi, x, y, MI_SUPPORT, victim);
00246 build_mission_list(mi, x, y, MI_DSUPPORT, victim);
00247
00248 dam = dosupport(mi, x, y, victim, actee);
00249 return dam;
00250 }
00251
00252 static int
00253 dosupport(struct genlist *mi, coord x, coord y, natid victim, natid actee)
00254 {
00255 int cn;
00256 int rel;
00257 int dam = 0;
00258
00259 for (cn = 1; cn < MAXNOC; cn++) {
00260 rel = getrel(getnatp(cn), actee);
00261 if ((cn != actee) && (rel != ALLIED))
00262 continue;
00263 rel = getrel(getnatp(cn), victim);
00264 if ((cn != actee) && (rel != AT_WAR))
00265 continue;
00266
00267 if (QEMPTY(&mi[cn].queue))
00268 continue;
00269
00270 dam += perform_mission(x, y, victim, &mi[cn].queue, MI_SUPPORT,
00271 "", SECT_HARDTARGET);
00272 }
00273 return dam;
00274 }
00275
00276 static void
00277 build_mission_list(struct genlist *mi, coord x, coord y, int mission,
00278 natid victim)
00279 {
00280 build_mission_list_type(mi, x, y, mission, EF_LAND, victim);
00281 build_mission_list_type(mi, x, y, mission, EF_SHIP, victim);
00282 build_mission_list_type(mi, x, y, mission, EF_PLANE, victim);
00283 }
00284
00285 static void
00286 build_mission_list_type(struct genlist *mi, coord x, coord y, int mission,
00287 int type, natid victim)
00288 {
00289 struct nstr_item ni;
00290 struct genlist *glp;
00291 struct empobj *gp;
00292 union empobj_storage item;
00293 int dist;
00294 int radius;
00295 int relat;
00296 struct sctstr sect;
00297
00298 snxtitem_all(&ni, type);
00299 while (nxtitem(&ni, &item)) {
00300 gp = (struct empobj *)&item;
00301
00302 if (gp->own == 0)
00303 continue;
00304
00305 if (gp->mobil < 1)
00306 continue;
00307
00308 if ((gp->mission != mission) && (mission != MI_SINTERDICT))
00309 continue;
00310
00311 if ((gp->mission != mission) && (mission == MI_SINTERDICT) &&
00312 (gp->mission != MI_INTERDICT))
00313 continue;
00314
00315 relat = getrel(getnatp(gp->own), victim);
00316 if (mission == MI_SINTERDICT) {
00317 if (relat >= FRIENDLY)
00318 continue;
00319 else if (type != EF_PLANE && relat > HOSTILE)
00320 continue;
00321 } else if (relat > HOSTILE)
00322 continue;
00323
00324 dist = mapdist(x, y, gp->opx, gp->opy);
00325
00326 radius = gp->radius;
00327 if (mission != MI_RESERVE)
00328 oprange(gp, &radius);
00329
00330 if (dist > radius)
00331 continue;
00332
00333
00334
00335 dist = mapdist(x, y, gp->x, gp->y);
00336 radius = 999;
00337 oprange(gp, &radius);
00338 if (dist > radius)
00339 continue;
00340
00341
00342 if (opt_SLOW_WAR) {
00343 if (mission != MI_AIR_DEFENSE) {
00344 getsect(x, y, §);
00345 if (getrel(getnatp(gp->own), sect.sct_own) > AT_WAR) {
00346
00347
00348
00349
00350
00351
00352
00353 if (sect.sct_type != SCT_WATER &&
00354 sect.sct_own != gp->own &&
00355 sect.sct_oldown != gp->own)
00356 continue;
00357 }
00358 }
00359 }
00360
00361 glp = malloc(sizeof(struct genlist));
00362 memset(glp, 0, sizeof(struct genlist));
00363 glp->cp = get_empobj_chr(gp);
00364 glp->thing = malloc(sizeof(item));
00365 memcpy(glp->thing, &item, sizeof(item));
00366 emp_insque(&glp->queue, &mi[gp->own].queue);
00367 }
00368 }
00369
00370 static void
00371 find_escorts(coord x, coord y, natid cn, struct emp_qelem *escorts)
00372 {
00373 struct nstr_item ni;
00374 struct plist *plp;
00375 struct plnstr plane;
00376 int dist;
00377
00378 snxtitem_all(&ni, EF_PLANE);
00379 while (nxtitem(&ni, &plane)) {
00380 if (plane.pln_own != cn)
00381 continue;
00382
00383 if (plane.pln_mission != MI_ESCORT)
00384 continue;
00385
00386 dist = mapdist(x, y, plane.pln_x, plane.pln_y);
00387 if (dist > plane.pln_range / 2)
00388 continue;
00389
00390 plp = malloc(sizeof(struct plist));
00391 memset(plp, 0, sizeof(struct plist));
00392 plp->pcp = &plchr[(int)plane.pln_type];
00393 plp->plane = plane;
00394 emp_insque(&plp->queue, escorts);
00395 }
00396 }
00397
00398 static int
00399 perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
00400 int mission, char *s, int hardtarget)
00401 {
00402 struct emp_qelem *qp, missiles, bombers, escorts, airp, b, e;
00403 struct emp_qelem *newqp;
00404 struct genlist *glp;
00405 struct plist *plp;
00406 struct empobj *gp;
00407 struct lndstr *lp;
00408 struct shpstr *sp;
00409 struct sctstr sect;
00410 struct mchrstr *mcp;
00411 struct plchrstr *pcp;
00412 int dam = 0, dam2, mission_flags, tech;
00413 natid plane_owner = 0;
00414 int gun, shell, md, range, air_dam = 0;
00415 double prb, hitchance, vrange;
00416
00417 getsect(x, y, §);
00418
00419 emp_initque(&missiles);
00420 emp_initque(&bombers);
00421 emp_initque(&escorts);
00422 emp_initque(&airp);
00423
00424 for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
00425 glp = (struct genlist *)qp;
00426 gp = glp->thing;
00427
00428 md = mapdist(x, y, gp->x, gp->y);
00429
00430 if (glp->thing->ef_type == EF_LAND) {
00431 lp = (struct lndstr *)glp->thing;
00432
00433 if (lp->lnd_effic < LAND_MINFIREEFF)
00434 continue;
00435
00436 if (mission == MI_SINTERDICT)
00437 continue;
00438
00439 if ((mission == MI_INTERDICT) &&
00440 (md > land_max_interdiction_range))
00441 continue;
00442
00443 if ((lp->lnd_ship != -1) || (lp->lnd_land != -1))
00444 continue;
00445
00446 if (lp->lnd_item[I_MILIT] < 1)
00447 continue;
00448
00449 range = roundrange(effrange(lp->lnd_frg, lp->lnd_tech));
00450 if (md > range)
00451 continue;
00452
00453 shell = lp->lnd_item[I_SHELL];
00454 gun = lp->lnd_item[I_GUN];
00455 if (shell == 0 || gun == 0)
00456 continue;
00457
00458 if (has_supply(lp)) {
00459 use_supply(lp);
00460 putland(lp->lnd_uid, lp);
00461 dam2 = ldround(landunitgun(lp->lnd_effic, lp->lnd_dam, gun,
00462 lp->lnd_ammo, shell), 1);
00463 if (sect.sct_type == SCT_WATER) {
00464 if (chance(lp->lnd_acc / 100.0))
00465 dam2 = ldround(dam2 / 2.0, 1);
00466 }
00467 dam += dam2;
00468 if (sect.sct_type == SCT_WATER)
00469 nreport(lp->lnd_own, N_SHP_SHELL, victim, 1);
00470 else
00471 nreport(lp->lnd_own, N_SCT_SHELL, victim, 1);
00472 wu(0, lp->lnd_own,
00473 "%s fires at %s %s at %s\n",
00474 prland(lp), cname(victim), s, xyas(x, y, lp->lnd_own));
00475
00476 mpr(victim, "%s %s fires at you at %s\n",
00477 cname(lp->lnd_own), prland(lp), xyas(x, y, victim));
00478 }
00479 } else if (glp->thing->ef_type == EF_SHIP) {
00480 sp = (struct shpstr *)glp->thing;
00481 mcp = glp->cp;
00482
00483 if (sp->shp_effic < 60)
00484 continue;
00485 if (sp->shp_frnge == 0)
00486 continue;
00487 if (((mission == MI_INTERDICT) ||
00488 (mission == MI_SINTERDICT)) &&
00489 (md > ship_max_interdiction_range))
00490 continue;
00491 if (sp->shp_item[I_MILIT] < 1)
00492 continue;
00493
00494
00495
00496
00497
00498 if (mission == MI_SINTERDICT) {
00499 if (!(mcp->m_flags & M_SONAR))
00500 continue;
00501 if (!(mcp->m_flags & M_DCH) && !(mcp->m_flags & M_SUBT))
00502 continue;
00503 vrange = techfact(sp->shp_tech, mcp->m_vrnge);
00504 vrange *= sp->shp_effic / 200.0;
00505 if (md > vrange)
00506 continue;
00507
00508 if (chance(0.5))
00509 continue;
00510 }
00511 if (mcp->m_flags & M_SUB) {
00512
00513
00514 if (*s != 's')
00515 continue;
00516 if (sp->shp_mobil < 0)
00517 continue;
00518 gun = sp->shp_item[I_GUN];
00519 if (gun < 1)
00520 continue;
00521 shell = sp->shp_item[I_SHELL];
00522 if (shell < SHP_TORP_SHELLS)
00523 shell += supply_commod(sp->shp_own,
00524 sp->shp_x, sp->shp_y, I_SHELL,
00525 SHP_TORP_SHELLS - shell);
00526 if (shell < SHP_TORP_SHELLS)
00527 continue;
00528
00529 range = roundrange(torprange(sp));
00530 if (md > range)
00531 continue;
00532
00533 if (!line_of_sight(NULL, x, y, gp->x, gp->y))
00534 continue;
00535 sp->shp_item[I_SHELL] = shell - SHP_TORP_SHELLS;
00536 sp->shp_mobil -= shp_mobcost(sp) / 2.0;
00537 putship(sp->shp_uid, sp);
00538 hitchance = DTORP_HITCHANCE(md, sp->shp_visib);
00539
00540 wu(0, sp->shp_own,
00541 "%s locking on %s %s in %s\n",
00542 prship(sp), cname(victim), s, xyas(x, y, sp->shp_own));
00543 wu(0, sp->shp_own,
00544 "\tEffective torpedo range is %d.0\n", range);
00545 wu(0, sp->shp_own,
00546 "\tWhooosh... Hitchance = %d%%\n",
00547 (int)(hitchance * 100));
00548
00549 if (hitchance < 1.0 && !chance(hitchance)) {
00550 wu(0, sp->shp_own, "\tMissed\n");
00551 mpr(victim,
00552 "Incoming torpedo sighted @ %s missed (whew)!\n",
00553 xyas(x, y, victim));
00554 continue;
00555 }
00556 wu(0, sp->shp_own, "\tBOOM!...\n");
00557 dam2 = TORP_DAMAGE();
00558
00559 dam += dam2;
00560 nreport(victim, N_TORP_SHIP, 0, 1);
00561 wu(0, sp->shp_own,
00562 "\tTorpedo hit %s %s for %d damage\n",
00563 cname(victim), s, dam2);
00564
00565 mpr(victim,
00566 "Incoming torpedo sighted @ %s hits and does %d damage!\n",
00567 xyas(x, y, victim), dam2);
00568 } else {
00569 range = roundrange(effrange(sp->shp_frnge, sp->shp_tech));
00570 if (md > range)
00571 continue;
00572 gun = sp->shp_item[I_GUN];
00573 gun = MIN(gun, sp->shp_glim);
00574 shell = sp->shp_item[I_SHELL];
00575 if (shell < gun)
00576 shell += supply_commod(sp->shp_own,
00577 sp->shp_x, sp->shp_y, I_SHELL,
00578 gun - shell);
00579 gun = MIN(gun, shell);
00580 gun = MIN(gun, sp->shp_item[I_MILIT] / 2.0);
00581 if (gun == 0)
00582 continue;
00583 gun = MAX(gun, 1);
00584 dam2 = seagun(sp->shp_effic, gun);
00585 if (range == 0.0)
00586 prb = 1.0;
00587 else
00588 prb = (double)md / range;
00589 prb *= prb;
00590 if (chance(prb))
00591 dam2 /= 2;
00592 dam += dam2;
00593 if (sect.sct_type == SCT_WATER)
00594 nreport(sp->shp_own, N_SHP_SHELL, victim, 1);
00595 else
00596 nreport(sp->shp_own, N_SCT_SHELL, victim, 1);
00597 wu(0, sp->shp_own,
00598 "%s fires at %s %s at %s\n",
00599 prship(sp), cname(victim), s, xyas(x, y, sp->shp_own));
00600
00601 mpr(victim, "%s %s fires at you at %s\n",
00602 cname(sp->shp_own), prship(sp), xyas(x, y, victim));
00603
00604 sp->shp_item[I_SHELL] = shell - gun;
00605 putship(sp->shp_uid, sp);
00606 }
00607 } else if (glp->thing->ef_type == EF_PLANE) {
00608 pcp = glp->cp;
00609 if (pcp->pl_flags & P_M)
00610
00611 if (hardtarget != SECT_HARDTARGET || pcp->pl_flags & P_MAR)
00612 continue;
00613
00614
00615 plp = malloc(sizeof(struct plist));
00616
00617 memset(plp, 0, sizeof(struct plist));
00618 plp->pcp = pcp;
00619 memcpy(&plp->plane, glp->thing, sizeof(struct plnstr));
00620 if (plp->pcp->pl_flags & P_M)
00621 emp_insque(&plp->queue, &missiles);
00622 else
00623 emp_insque(&plp->queue, &bombers);
00624 plane_owner = plp->plane.pln_own;
00625 }
00626 }
00627 if (!QEMPTY(&missiles)) {
00628
00629 dam +=
00630 msl_launch_mindam(&missiles, x, y, hardtarget, EF_SECTOR, 100,
00631 "sector", victim, mission);
00632 qp = missiles.q_forw;
00633 while (qp != (&missiles)) {
00634 newqp = qp->q_forw;
00635 emp_remque(qp);
00636 free(qp);
00637 qp = newqp;
00638 }
00639 }
00640
00641 if (QEMPTY(&bombers)) {
00642 qp = list->q_forw;
00643 while (qp != list) {
00644 glp = (struct genlist *)qp;
00645 qp = qp->q_forw;
00646
00647 free(glp->thing);
00648 free(glp);
00649 }
00650 return dam;
00651 }
00652
00653
00654
00655
00656
00657
00658 find_escorts(x, y, plane_owner, &escorts);
00659
00660 if (mission == MI_SINTERDICT)
00661 mission_pln_sel(&bombers, P_T | P_A, 0, hardtarget);
00662 else
00663 mission_pln_sel(&bombers, P_T, P_A, SECT_HARDTARGET);
00664
00665 mission_pln_sel(&escorts, P_ESC | P_F, 0, SECT_HARDTARGET);
00666
00667 for (qp = bombers.q_forw; qp != (&bombers); qp = qp->q_forw) {
00668 plp = (struct plist *)qp;
00669 if (!find_airport(&airp, plp->plane.pln_x, plp->plane.pln_y))
00670 add_airport(&airp, plp->plane.pln_x, plp->plane.pln_y);
00671 }
00672
00673 for (qp = airp.q_forw; qp != (&airp); qp = qp->q_forw) {
00674 struct airport *air;
00675 char buf[512];
00676 char *pp;
00677
00678 air = (struct airport *)qp;
00679 md = mapdist(x, y, air->x, air->y);
00680
00681 emp_initque(&b);
00682 emp_initque(&e);
00683
00684
00685 divide(&bombers, &b, air->x, air->y);
00686
00687
00688 divide(&escorts, &e, air->x, air->y);
00689
00690 tech = 0;
00691 mission_flags = 0;
00692 mission_flags |= P_X;
00693 mission_flags |= P_H;
00694
00695 mission_flags = mission_pln_arm(&b, air->x, air->y, 2 * md, 'p', 0,
00696 0, mission_flags, &tech);
00697
00698 if (QEMPTY(&b))
00699 continue;
00700
00701 mission_flags = mission_pln_arm(&e, air->x, air->y, 2 * md, 'p', 0,
00702 P_F | P_ESC, mission_flags, &tech);
00703
00704 pp = BestAirPath(buf, air->x, air->y, x, y);
00705 if (CANT_HAPPEN(!pp))
00706 continue;
00707 wu(0, plane_owner, "Flying %s mission from %s\n",
00708 mission_name(mission), xyas(air->x, air->y, plane_owner));
00709 if (air->own && (air->own != plane_owner)) {
00710 wu(0, air->own, "%s is flying %s mission from %s\n",
00711 cname(plane_owner), mission_name(mission),
00712 xyas(air->x, air->y, air->own));
00713 }
00714
00715 ac_encounter(&b, &e, air->x, air->y, pp, mission_flags, 0, 0, 0);
00716
00717 if (!QEMPTY(&b))
00718 air_dam +=
00719 air_damage(&b, x, y, mission, victim, s, hardtarget);
00720
00721 pln_put(&b);
00722 pln_put(&e);
00723 }
00724
00725 if (air_dam > 0) {
00726 dam += air_dam;
00727 if (sect.sct_type == SCT_WATER)
00728 nreport(plane_owner, N_SHP_BOMB, victim, 1);
00729 else
00730 nreport(plane_owner, N_SCT_BOMB, victim, 1);
00731 }
00732
00733
00734 qp = list->q_forw;
00735 while (qp != list) {
00736 glp = (struct genlist *)qp;
00737 qp = qp->q_forw;
00738
00739 free(glp->thing);
00740 free(glp);
00741 }
00742
00743 qp = escorts.q_forw;
00744 while (qp != (&escorts)) {
00745 newqp = qp->q_forw;
00746 emp_remque(qp);
00747 free(qp);
00748 qp = newqp;
00749 }
00750
00751 qp = bombers.q_forw;
00752 while (qp != (&bombers)) {
00753 newqp = qp->q_forw;
00754 emp_remque(qp);
00755 free(qp);
00756 qp = newqp;
00757 }
00758
00759 return dam;
00760 }
00761
00762 int
00763 cando(int mission, int type)
00764 {
00765 switch (mission) {
00766 case MI_ESCORT:
00767 if (type == EF_PLANE)
00768 return 1;
00769 return 0;
00770 case MI_AIR_DEFENSE:
00771 if (type == EF_PLANE)
00772 return 1;
00773 return 0;
00774 case MI_SINTERDICT:
00775 if ((type == EF_PLANE) || (type == EF_SHIP))
00776 return 1;
00777 return 0;
00778 case MI_INTERDICT:
00779 return 1;
00780 case MI_SUPPORT:
00781 case MI_OSUPPORT:
00782 case MI_DSUPPORT:
00783 if (type == EF_PLANE)
00784 return 1;
00785 return 0;
00786 case MI_RESERVE:
00787 if (type == EF_LAND)
00788 return 1;
00789 return 0;
00790 }
00791
00792 return 0;
00793 }
00794
00795 char *
00796 mission_name(short mission)
00797 {
00798 switch (mission) {
00799 case MI_INTERDICT:
00800 return "an interdiction";
00801 case MI_SUPPORT:
00802 return "a support";
00803 case MI_OSUPPORT:
00804 return "a offensive support";
00805 case MI_DSUPPORT:
00806 return "a defensive support";
00807 case MI_RESERVE:
00808 return "a reserve";
00809 case MI_ESCORT:
00810 return "an escort";
00811 case MI_SINTERDICT:
00812 return "a sub interdiction";
00813 case MI_AIR_DEFENSE:
00814 return "an air defense";
00815 }
00816 return "a mysterious";
00817 }
00818
00819 void
00820 show_mission(int type, struct nstr_item *np)
00821 {
00822 int first = 1, radius;
00823 union empobj_storage item;
00824 struct empobj *gp;
00825
00826 while (nxtitem(np, &item)) {
00827 gp = (struct empobj *)&item;
00828 if (!player->owner || gp->own == 0)
00829 continue;
00830
00831 if (first) {
00832 pr("Thing x,y op-sect rad mission\n");
00833 first = 0;
00834 }
00835 pr("%-25s", obj_nameof(gp));
00836 prxy(" %3d,%-3d", gp->x, gp->y, player->cnum);
00837 if (gp->mission == MI_INTERDICT || gp->mission == MI_SUPPORT ||
00838 gp->mission == MI_OSUPPORT ||
00839 gp->mission == MI_DSUPPORT || gp->mission == MI_AIR_DEFENSE) {
00840 radius = 999;
00841 oprange(gp, &radius);
00842 prxy(" %3d,%-3d", gp->opx, gp->opy, player->cnum);
00843 if (radius < gp->radius)
00844 pr(" %4d", radius);
00845 else
00846 pr(" %4d", gp->radius);
00847 } else if (gp->mission == MI_RESERVE) {
00848 struct sctstr sect;
00849 int plus = 2;
00850
00851 getsect(gp->x, gp->y, §);
00852 if ((sect.sct_type == SCT_HEADQ) && (sect.sct_effic >= 60))
00853 plus++;
00854
00855 if (item.land.lnd_rad_max == 0)
00856 plus = 0;
00857 else
00858 plus += item.land.lnd_rad_max;
00859 prxy(" %3d,%-3d", gp->x, gp->y, player->cnum);
00860 pr(" %4d", plus);
00861 } else if (gp->mission == MI_ESCORT) {
00862 pr(" ");
00863 pr(" %4d", item.plane.pln_range / 2);
00864 } else
00865 pr(" ");
00866 if (gp->mission)
00867 pr(" is on %s mission\n", mission_name(gp->mission));
00868 else
00869 pr(" has no mission.\n");
00870 }
00871 }
00872
00873 int
00874 oprange(struct empobj *gp, int *radius)
00875 {
00876 int range;
00877
00878 switch (gp->ef_type) {
00879 case EF_SHIP:
00880 range = ldround(effrange(((struct shpstr *)gp)->shp_frnge,
00881 ((struct shpstr *)gp)->shp_tech), 1);
00882 break;
00883 case EF_LAND:
00884 range = ldround(effrange(((struct lndstr *)gp)->lnd_frg,
00885 ((struct lndstr *)gp)->lnd_tech), 1);
00886 break;
00887 case EF_PLANE:
00888
00889 if (plchr[(int)gp->type].pl_flags & P_M)
00890 range = ((struct plnstr *)gp)->pln_range;
00891 else
00892 range = ((struct plnstr *)gp)->pln_range / 2;
00893 break;
00894 default:
00895 CANT_HAPPEN("bad TYPE");
00896 range = -1;
00897 }
00898
00899 if (*radius > range)
00900 *radius = range;
00901
00902 return range;
00903 }
00904
00905
00906
00907
00908
00909 static void
00910 mission_pln_sel(struct emp_qelem *list, int wantflags, int nowantflags,
00911 int hardtarget)
00912 {
00913 struct emp_qelem *qp, *next;
00914 struct plnstr *pp;
00915 struct plchrstr *pcp;
00916 struct plist *plp;
00917 int y, bad, bad1;
00918 unsigned x;
00919
00920 for (qp = list->q_forw; qp != list; qp = next) {
00921 next = qp->q_forw;
00922 plp = (struct plist *)qp;
00923 pp = &plp->plane;
00924 pcp = plp->pcp;
00925
00926 if (pp->pln_effic < 40) {
00927 emp_remque(qp);
00928 free(qp);
00929 continue;
00930 }
00931
00932 if (pp->pln_mobil < 1) {
00933 emp_remque(qp);
00934 free(qp);
00935 continue;
00936 }
00937
00938 if (opt_MARKET) {
00939 if (ontradingblock(EF_PLANE, pp)) {
00940 emp_remque(qp);
00941 free(qp);
00942 continue;
00943 }
00944 }
00945
00946 if (!pln_capable(pp, wantflags, nowantflags)) {
00947 emp_remque(qp);
00948 free(qp);
00949 continue;
00950 }
00951
00952 if (!pln_airbase_ok(pp, 0, 0)) {
00953 emp_remque(qp);
00954 free(qp);
00955 continue;
00956 }
00957
00958 if (pcp->pl_flags & P_A) {
00959 if (roll(100) > pln_identchance(pp, hardtarget, EF_SHIP)) {
00960 emp_remque(qp);
00961 free(qp);
00962 continue;
00963 }
00964 }
00965
00966 putplane(pp->pln_uid, pp);
00967 }
00968 }
00969
00970
00971
00972
00973 static int
00974 mission_pln_arm(struct emp_qelem *list, coord x, coord y, int dist,
00975 int mission, struct ichrstr *ip, int flags,
00976 int mission_flags, int *tech)
00977 {
00978 struct emp_qelem *qp;
00979 struct emp_qelem *next;
00980 struct plist *plp;
00981
00982 if (*tech == 0)
00983 *tech = 9999;
00984 for (qp = list->q_forw; qp != list; qp = next) {
00985 next = qp->q_forw;
00986 plp = (struct plist *)qp;
00987
00988 if (plp->plane.pln_x != x)
00989 continue;
00990 if (plp->plane.pln_y != y)
00991 continue;
00992
00993 if (mission_pln_equip(plp, ip, flags, mission) < 0) {
00994 emp_remque(qp);
00995 free(qp);
00996 continue;
00997 }
00998 if (flags & (P_S | P_I)) {
00999 if (plp->pcp->pl_flags & P_S)
01000 mission_flags |= P_S;
01001 if (plp->pcp->pl_flags & P_I)
01002 mission_flags |= P_I;
01003 }
01004 if (*tech > plp->plane.pln_tech)
01005 *tech = plp->plane.pln_tech;
01006 if (!(plp->pcp->pl_flags & P_H))
01007
01008 mission_flags &= ~P_H;
01009 if (!(plp->pcp->pl_flags & P_X))
01010
01011 mission_flags &= ~P_X;
01012 if (!(plp->pcp->pl_flags & P_A)) {
01013
01014 mission_flags &= ~P_A;
01015 }
01016 if (!(plp->pcp->pl_flags & P_MINE)) {
01017
01018 mission_flags &= ~P_MINE;
01019 }
01020
01021
01022
01023
01024
01025
01026 plp->plane.pln_mobil -= pln_mobcost(dist, &plp->plane, flags);
01027
01028 }
01029 return mission_flags;
01030 }
01031
01032 int
01033 mission_pln_equip(struct plist *plp, struct ichrstr *ip, int flags,
01034 char mission)
01035 {
01036 struct plchrstr *pcp;
01037 struct plnstr *pp;
01038 int needed;
01039 struct lndstr land;
01040 struct shpstr ship;
01041 struct sctstr sect;
01042 i_type itype;
01043 int rval;
01044 short *item;
01045
01046 pp = &plp->plane;
01047 pcp = plp->pcp;
01048 if (pp->pln_ship >= 0) {
01049 getship(pp->pln_ship, &ship);
01050 item = ship.shp_item;
01051 } else if (pp->pln_land >= 0) {
01052 getland(pp->pln_land, &land);
01053 item = land.lnd_item;
01054 } else {
01055 getsect(pp->pln_x, pp->pln_y, §);
01056 item = sect.sct_item;
01057 }
01058 if (pcp->pl_fuel > item[I_PETROL]) {
01059 return -1;
01060 }
01061 item[I_PETROL] -= pcp->pl_fuel;
01062 rval = 0;
01063 if (!(flags & P_F)) {
01064 itype = I_NONE;
01065 needed = 0;
01066 switch (mission) {
01067 case 's':
01068 case 'p':
01069 if (pp->pln_nuketype == -1) {
01070 itype = I_SHELL;
01071 needed = pp->pln_load;
01072 }
01073 break;
01074 case 't':
01075 if ((pcp->pl_flags & P_C) == 0 || ip == 0)
01076 break;
01077 itype = ip->i_uid;
01078 needed = (pp->pln_load * 2) / ip->i_lbs;
01079 break;
01080 case 'd':
01081 if ((pcp->pl_flags & P_C) == 0 || ip == 0)
01082 break;
01083 itype = ip->i_uid;
01084 needed = (pp->pln_load * 2) / ip->i_lbs;
01085 break;
01086 case 'a':
01087 if ((pcp->pl_flags & (P_V | P_C)) == 0)
01088 break;
01089 itype = I_MILIT;
01090 needed = pp->pln_load / ip->i_lbs;
01091 break;
01092 case 'n':
01093 if (pp->pln_nuketype == -1)
01094 rval = -1;
01095 break;
01096 case 'i':
01097 if (pp->pln_load) {
01098 itype = I_SHELL;
01099 needed = pp->pln_load;
01100 }
01101 break;
01102 default:
01103 break;
01104 }
01105 if (rval < 0 || (itype != I_NONE && needed <= 0)) {
01106 return -1;
01107 }
01108 if (itype != I_NONE) {
01109 if (itype == I_SHELL && item[itype] < needed)
01110 item[itype] += supply_commod(plp->plane.pln_own,
01111 plp->plane.pln_x,
01112 plp->plane.pln_y,
01113 I_SHELL, needed);
01114 if (item[itype] < needed)
01115 return -1;
01116 item[itype] -= needed;
01117 }
01118 if (itype == I_SHELL && (mission == 's' || mission == 'p'))
01119 plp->bombs = needed;
01120 else
01121 plp->misc = needed;
01122 }
01123 if (pp->pln_ship >= 0)
01124 putship(ship.shp_uid, &ship);
01125 else if (pp->pln_land >= 0)
01126 putland(land.lnd_uid, &land);
01127 else
01128 putsect(§);
01129 return rval;
01130 }
01131
01132
01133
01134
01135 static int
01136 find_airport(struct emp_qelem *airp, coord x, coord y)
01137 {
01138 struct emp_qelem *qp;
01139 struct airport *a;
01140
01141 for (qp = airp->q_forw; qp != airp; qp = qp->q_forw) {
01142 a = (struct airport *)qp;
01143 if ((a->x == x) && (a->y == y))
01144 return 1;
01145 }
01146
01147 return 0;
01148 }
01149
01150
01151 static void
01152 add_airport(struct emp_qelem *airp, coord x, coord y)
01153 {
01154 struct airport *a;
01155 struct sctstr sect;
01156
01157 a = malloc(sizeof(struct airport));
01158
01159 a->x = x;
01160 a->y = y;
01161 getsect(x, y, §);
01162 a->own = sect.sct_own;
01163
01164 emp_insque((struct emp_qelem *)a, airp);
01165 }
01166
01167
01168
01169
01170
01171 static void
01172 divide(struct emp_qelem *l1, struct emp_qelem *l2, coord x, coord y)
01173 {
01174 struct emp_qelem *qp, *next;
01175 struct plist *plp;
01176
01177 for (qp = l1->q_forw; qp != l1; qp = next) {
01178 next = qp->q_forw;
01179 plp = (struct plist *)qp;
01180
01181 if (plp->plane.pln_x != x)
01182 continue;
01183 if (plp->plane.pln_y != y)
01184 continue;
01185
01186 emp_remque(qp);
01187 emp_insque(qp, l2);
01188 }
01189 }
01190
01191 static int
01192 air_damage(struct emp_qelem *bombers, coord x, coord y, int mission,
01193 natid victim, char *s, int hardtarget)
01194 {
01195 struct emp_qelem *qp;
01196 struct plist *plp;
01197 struct plnstr *pp;
01198 int newdam, dam = 0;
01199 int hitchance;
01200 int nukedam;
01201
01202 for (qp = bombers->q_forw; qp != bombers; qp = qp->q_forw) {
01203 plp = (struct plist *)qp;
01204 pp = &plp->plane;
01205
01206 if ((mission == MI_SINTERDICT) && !(plp->pcp->pl_flags & P_A))
01207 continue;
01208
01209 if (!plp->bombs)
01210 continue;
01211
01212 newdam = 0;
01213 if (plp->pcp->pl_flags & P_A) {
01214 if (roll(100) > pln_identchance(pp, hardtarget, EF_SHIP)) {
01215 wu(0, pp->pln_own,
01216 "\t%s detects sub movement in %s\n",
01217 prplane(pp), xyas(x, y, pp->pln_own));
01218 continue;
01219 }
01220 if (getrel(getnatp(pp->pln_own), victim) > HOSTILE) {
01221 wu(0, pp->pln_own,
01222 "\t%s tracks %s %s at %s\n",
01223 prplane(pp), cname(victim), s, xyas(x, y, pp->pln_own));
01224 continue;
01225 }
01226 wu(0, pp->pln_own,
01227 "\t%s depth-charging %s %s in %s\n",
01228 prplane(pp), cname(victim), s, xyas(x, y, pp->pln_own));
01229 } else {
01230 wu(0, pp->pln_own,
01231 "\t%s pinbombing %s %s in %s\n",
01232 prplane(pp), cname(victim), s, xyas(x, y, pp->pln_own));
01233 }
01234 hitchance = pln_hitchance(pp, hardtarget, EF_SHIP);
01235 if (plp->plane.pln_nuketype != -1)
01236 hitchance = 100;
01237 else if (hardtarget != SECT_HARDTARGET)
01238 wu(0, pp->pln_own, "\t\t%d%% hitchance...", hitchance);
01239
01240 if (roll(100) <= hitchance) {
01241 newdam = pln_damage(&plp->plane, x, y, 'p', &nukedam, 1);
01242 if (nukedam) {
01243 if (mission == MI_INTERDICT) {
01244 wu(0, pp->pln_own,
01245 "\t\tnuclear warhead on plane %s does %d damage to %s %s\n",
01246 prplane(pp), nukedam, cname(victim), s);
01247 dam += nukedam;
01248 }
01249 } else {
01250 wu(0, pp->pln_own,
01251 "\t\thit %s %s for %d damage\n",
01252 cname(victim), s, newdam);
01253 dam += newdam;
01254 }
01255 } else {
01256 newdam = pln_damage(&plp->plane, x, y, 'p', &nukedam, 0);
01257 wu(0, pp->pln_own, "missed\n");
01258 if (mission == MI_SINTERDICT) {
01259 mpr(victim,
01260 "RUMBLE... your sub in %s hears a depth-charge explode nearby\n",
01261 xyas(x, y, victim));
01262 } else if (*s == 's') {
01263 mpr(victim, "SPLASH! Bombs miss your %s in %s\n",
01264 s, xyas(x, y, victim));
01265 } else {
01266 mpr(victim, "SPLAT! Bombs miss your %s in %s\n",
01267 s, xyas(x, y, victim));
01268 }
01269
01270
01271 collateral_damage(x, y, newdam, bombers);
01272 }
01273
01274
01275 if (plp->pcp->pl_flags & P_M)
01276 pp->pln_effic = 0;
01277 }
01278
01279 return dam;
01280 }
01281
01282
01283
01284
01285
01286
01287 int
01288 air_defense(coord x, coord y, natid victim, struct emp_qelem *bomb_list,
01289 struct emp_qelem *esc_list)
01290 {
01291 int dam = 0, cn;
01292 int mission_flags, tech, combat = 0, rel, dist, z;
01293 struct emp_qelem *qp, interceptors, airp, i, empty, *next;
01294 struct plist *plp;
01295 struct genlist *glp;
01296 struct empobj *gp;
01297 struct genlist mi[MAXNOC];
01298 char buf[512];
01299 char *path;
01300 int count;
01301 int tcount;
01302
01303 count = 0;
01304 for (qp = bomb_list->q_forw; qp != bomb_list; qp = qp->q_forw)
01305 count++;
01306 for (qp = esc_list->q_forw; qp != esc_list; qp = qp->q_forw)
01307 count++;
01308
01309 memset(mi, 0, sizeof(mi));
01310 for (z = 1; z < MAXNOC; z++)
01311 emp_initque((struct emp_qelem *)&mi[z]);
01312
01313 build_mission_list_type(mi, x, y, MI_AIR_DEFENSE, EF_PLANE, victim);
01314
01315 for (cn = 1; cn < MAXNOC; cn++) {
01316
01317 rel = getrel(getnatp(cn), victim);
01318
01319 if (rel > HOSTILE)
01320 continue;
01321
01322 if (QEMPTY(&mi[cn].queue))
01323 continue;
01324
01325
01326
01327 emp_initque(&interceptors);
01328 for (qp = mi[cn].queue.q_forw; qp != (&mi[cn].queue); qp = next) {
01329 next = qp->q_forw;
01330 glp = (struct genlist *)qp;
01331 gp = glp->thing;
01332
01333 dist = mapdist(x, y, gp->x, gp->y);
01334
01335 plp = malloc(sizeof(struct plist));
01336 memset(plp, 0, sizeof(struct plist));
01337 plp->pcp = glp->cp;
01338 memcpy(&plp->plane, glp->thing, sizeof(struct plnstr));
01339
01340
01341 if (!(plp->pcp->pl_flags & P_M))
01342 dist *= 2;
01343
01344 if (dist > plp->plane.pln_range) {
01345 free(plp);
01346 continue;
01347 }
01348 emp_insque(&plp->queue, &interceptors);
01349 }
01350
01351
01352 mission_pln_sel(&interceptors, P_F, 0, SECT_HARDTARGET);
01353
01354 if (QEMPTY(&interceptors))
01355 continue;
01356
01357
01358
01359
01360 tcount = 0;
01361 for (qp = interceptors.q_forw; qp != (&interceptors);
01362 qp = qp->q_forw)
01363 tcount++;
01364 tcount -= count * 2;
01365
01366 if (tcount < 0)
01367 tcount = 0;
01368 for (qp = interceptors.q_forw; qp != (&interceptors); qp = next) {
01369 next = qp->q_forw;
01370 if (tcount) {
01371 tcount--;
01372
01373 emp_remque(qp);
01374 glp = (struct genlist *)qp;
01375 free(glp);
01376 }
01377 }
01378
01379
01380 emp_initque(&airp);
01381 for (qp = interceptors.q_forw; qp != (&interceptors);
01382 qp = qp->q_forw) {
01383 plp = (struct plist *)qp;
01384 if (!find_airport(&airp, plp->plane.pln_x, plp->plane.pln_y))
01385 add_airport(&airp, plp->plane.pln_x, plp->plane.pln_y);
01386 }
01387
01388
01389 for (qp = airp.q_forw; qp != (&airp); qp = qp->q_forw) {
01390 struct airport *air;
01391
01392 air = (struct airport *)qp;
01393 dist = mapdist(x, y, air->x, air->y);
01394
01395 emp_initque(&i);
01396
01397
01398 divide(&interceptors, &i, air->x, air->y);
01399
01400 tech = 0;
01401 mission_flags = 0;
01402 mission_flags |= P_X;
01403
01404 mission_flags |= P_H;
01405 sam_intercept(bomb_list, &i, cn, victim, x, y, 0);
01406 sam_intercept(esc_list, &i, cn, victim, x, y, 1);
01407
01408
01409 if (QEMPTY(&i))
01410 continue;
01411
01412 if (QEMPTY(bomb_list)) {
01413
01414
01415 pln_put(&i);
01416 continue;
01417 }
01418 mission_flags =
01419 mission_pln_arm(&i, air->x, air->y, 2 * dist, 'r', 0, P_F,
01420 mission_flags, &tech);
01421
01422
01423 if (QEMPTY(&i))
01424 continue;
01425
01426 if (QEMPTY(bomb_list)) {
01427
01428
01429 pln_put(&i);
01430 continue;
01431 }
01432
01433 path = BestAirPath(buf, air->x, air->y, x, y);
01434 if (CANT_HAPPEN(!path))
01435 continue;
01436 wu(0, cn, "Flying %s mission from %s\n",
01437 mission_name(MI_AIR_DEFENSE), xyas(air->x, air->y, cn));
01438 if (air->own && (air->own != cn)) {
01439 wu(0, air->own, "%s is flying %s mission from %s\n",
01440 cname(cn), mission_name(MI_AIR_DEFENSE),
01441 xyas(air->x, air->y, air->own));
01442 }
01443
01444
01445 emp_initque(&empty);
01446 ac_encounter(&i, &empty, air->x, air->y,
01447 path, mission_flags, 1, bomb_list, esc_list);
01448
01449
01450 if (QEMPTY(&i))
01451 continue;
01452
01453
01454
01455 combat = 0;
01456 if (!QEMPTY(esc_list)) {
01457 mpr(victim, "%s air defense planes intercept!\n",
01458 cname(cn));
01459 ac_combat_headers(victim, cn);
01460 ac_airtoair(esc_list, &i);
01461 combat = 1;
01462 }
01463
01464 if (!QEMPTY(bomb_list)) {
01465 if (!combat) {
01466 mpr(victim, "%s air defense planes intercept!\n",
01467 cname(cn));
01468 ac_combat_headers(victim, cn);
01469 }
01470 ac_airtoair(bomb_list, &i);
01471 PR(cn, "\n");
01472 PR(victim, "\n");
01473 }
01474
01475 pln_put(&i);
01476 }
01477 }
01478
01479
01480
01481 for (cn = 1; cn < MAXNOC; cn++) {
01482
01483 for (qp = mi[cn].queue.q_forw; qp != (&mi[cn].queue); qp = next) {
01484 next = qp->q_forw;
01485 glp = (struct genlist *)qp;
01486 free(glp->thing);
01487 free(glp);
01488 }
01489 }
01490
01491 return dam;
01492 }