diff --git a/include/plane.h b/include/plane.h index e392050d..b7b31072 100644 --- a/include/plane.h +++ b/include/plane.h @@ -162,13 +162,9 @@ extern int pln_first_on_land(struct lndstr *); extern int pln_next_on_unit(int); /* src/lib/subs/aircombat.c */ -extern void ac_combat_headers(natid, natid); -extern void ac_airtoair(struct emp_qelem *, struct emp_qelem *); extern int ac_flak_dam(int, int, int); extern void ac_encounter(struct emp_qelem *, struct emp_qelem *, coord, - coord, char *, int, int); -extern void sam_intercept(struct emp_qelem *, struct emp_qelem *, - natid, natid, coord, coord, int); + coord, char *, int); /* src/lib/subs/aswplnsubs.c */ extern int on_shiplist(short, struct shiplist *); diff --git a/include/prototypes.h b/include/prototypes.h index ac112922..5c58835a 100644 --- a/include/prototypes.h +++ b/include/prototypes.h @@ -488,8 +488,6 @@ extern int def_support(coord, coord, natid, natid); extern int oprange(struct empobj *); extern int in_oparea(struct empobj *, coord, coord); extern int cando(int, int); -extern int air_defense(coord, coord, natid, struct emp_qelem *, - struct emp_qelem *); /* move.c */ extern int check_lmines(coord, coord, double); extern int move_ground(struct sctstr *, struct sctstr *, diff --git a/info/mission.t b/info/mission.t index 732fe606..3f8a2443 100644 --- a/info/mission.t +++ b/info/mission.t @@ -36,14 +36,13 @@ or "order"). .s1 Artillery units less than 40% efficient will not fire. .s1 -Planes flying missions will be intercepted normally. (i.e. if you fly -over enemy territory, you'll get intercepted. Any mission except air -missions may also be intercepted by planes on air defense missions) +Planes flying missions other than air defense will be intercepted +normally. (i.e. if you fly over enemy territory, you'll get +intercepted. .s1 -Planes of less than 40% efficiency will not fly missions. -.s1 -Planes assigned to missions are \*QNOT\*U eligible to intercept -normally. For example, if a fighter is assigned to an escort or air-defense +Planes assigned to missions other than air defense are \*QNOT\*U +eligible to intercept normally. For example, if a fighter is assigned +to an escort or interdiction or support mission, it will \*QNOT\*U rise to intercept an intruding enemy plane. (planes on air-defense missions will intercept planes flying in their op-area, in accordance with the air-defense mission, @@ -232,22 +231,11 @@ pays to put your bombing planes and escorting planes together. Only planes with the 'escort' or 'intercept' abilities can fly escort missions. .s1 AIR DEFENSE MISSIONS (planes only) -When given an air defense mission, an intercept capable plane will attempt -to intercept any enemy plane (defined as any plane belonging to a country -you re at war with) flying into its operations area, irregardless -of whether the enemy planes are flying over owned sectors. For example, if -a plane is given an air defense mission with an op area covering some -owned sectors, some sea, some allied sectors, and some enemy sectors, it -would try to intercept over any of them. .s1 -When a plane enters a sector, any planes with air defense missions that are -at war with the owner of the plane will fly there to fight it. -The air defense planes -encounter normal interception along the way (but do \*QNOT\*U trigger -more air defense missions, but \*QMAY\*U be intercepted normally). -Once the air defense planes get to the sector, -they fight the plane. Then, if the owner of the sector -is hostile to the plane, still more planes may intercept it. +Putting a plane on an air defense mission modifies where the plane +intercepts. Without a mission, it intercepts over own sectors, +surface ships and land units. With an air defense mission, it +intercepts over any sector in its op area. .s1 .L Example Groonland wants to run a recon flight over Bannannarama. Joeland has a @@ -275,12 +263,10 @@ This is within the Joeland aircraft's op-area, so it flies to intercept. It takes the shortest path there, and fights the Groonland plane. Let's say that both take 20 points of damage, and neither aborts. .s1 -Next, the Groonland plane overflies a Bannannarama sector. The Joeland -plane flies there, and is intercepted by the Bannannarama plane. Let's -say that it comes through the fight without being aborted. It then fights -the Groonland plane. After this combat, if the Groonland plane is not -aborted, it may be intercepted again by the busy Bannannarama fighter, -assuming that that plane is still efficient enough, has mob enough, etc. +Next, the Groonland plane overflies a Bannannarama sector. It gets +intercepted by Joeland's fighter, because the sector is in its +op-area, and by Bannannarama's fighter, because the sector belongs to +Bannannarama. And so forth. .s1 A good use of this mission is to provide a wider CAP around a carrier, so that enemy planes get intercepted several times on the way to the diff --git a/src/lib/commands/bomb.c b/src/lib/commands/bomb.c index 87c29d46..a0bfe704 100644 --- a/src/lib/commands/bomb.c +++ b/src/lib/commands/bomb.c @@ -140,7 +140,7 @@ bomb(void) return RET_FAIL; } pln_arm(&esc_list, 2 * ap_to_target, mission, ip, P_F | P_ESC); - ac_encounter(&bomb_list, &esc_list, ax, ay, flightpath, 0, 0); + ac_encounter(&bomb_list, &esc_list, ax, ay, flightpath, 0); if (QEMPTY(&bomb_list)) { pr("No planes got through fighter defenses\n"); } else if (target.sct_type == SCT_SANCT) { diff --git a/src/lib/commands/drop.c b/src/lib/commands/drop.c index 2c8806eb..247b4fba 100644 --- a/src/lib/commands/drop.c +++ b/src/lib/commands/drop.c @@ -115,7 +115,7 @@ drop(void) return RET_FAIL; } pln_arm(&esc_list, 2 * ap_to_target, 'd', ip, P_ESC | P_F); - ac_encounter(&bomb_list, &esc_list, ax, ay, flightpath, 0, 0); + ac_encounter(&bomb_list, &esc_list, ax, ay, flightpath, 0); if (QEMPTY(&bomb_list)) { pr("No planes got through fighter defenses\n"); } else { diff --git a/src/lib/commands/fly.c b/src/lib/commands/fly.c index efc60696..130c32b8 100644 --- a/src/lib/commands/fly.c +++ b/src/lib/commands/fly.c @@ -117,8 +117,7 @@ fly(void) return RET_FAIL; } pln_arm(&esc_list, ap_to_target, 't', ip, P_ESC | P_F); - ac_encounter(&bomb_list, &esc_list, ax, ay, - flightpath, 0, 0); + ac_encounter(&bomb_list, &esc_list, ax, ay, flightpath, 0); if (QEMPTY(&bomb_list)) { pr("No planes got through fighter defenses\n"); } else { diff --git a/src/lib/commands/para.c b/src/lib/commands/para.c index 8299f33a..142d02d8 100644 --- a/src/lib/commands/para.c +++ b/src/lib/commands/para.c @@ -96,7 +96,7 @@ para(void) return RET_FAIL; } pln_arm(&esc_list, 2 * ap_to_target, 'a', &ichr[I_MILIT], P_ESC | P_F); - ac_encounter(&bomb_list, &esc_list, ax, ay, flightpath, 0, 0); + ac_encounter(&bomb_list, &esc_list, ax, ay, flightpath, 0); if (QEMPTY(&bomb_list)) { pr("No planes got through fighter defenses\n"); } else { diff --git a/src/lib/commands/reco.c b/src/lib/commands/reco.c index e60b0229..5f89c0b7 100644 --- a/src/lib/commands/reco.c +++ b/src/lib/commands/reco.c @@ -104,8 +104,7 @@ reco(void) } pln_arm(&esc_list, ap_to_target, 'r', 0, P_F | P_ESC); ac_encounter(&bomb_list, &esc_list, ax, ay, flightpath, - *player->argp[0] == 's' ? PM_R | PM_S : PM_R, - 0); + *player->argp[0] == 's' ? PM_R | PM_S : PM_R); if (QEMPTY(&bomb_list)) { pr("No planes got through fighter defenses\n"); } else { diff --git a/src/lib/subs/aircombat.c b/src/lib/subs/aircombat.c index 8413a102..c95e0f0f 100644 --- a/src/lib/subs/aircombat.c +++ b/src/lib/subs/aircombat.c @@ -40,6 +40,7 @@ #include "land.h" #include "map.h" #include "misc.h" +#include "mission.h" #include "nat.h" #include "news.h" #include "nsc.h" @@ -55,8 +56,12 @@ #define FLAK_GUN_MAX 14 static int plane_caps(struct emp_qelem *); +static void sam_intercept(struct emp_qelem *, struct emp_qelem *, + natid, natid, coord, coord, int); static void ac_intercept(struct emp_qelem *, struct emp_qelem *, - struct emp_qelem *, natid, coord, coord); + struct emp_qelem *, natid, coord, coord, int); +static void ac_combat_headers(natid, natid); +static void ac_airtoair(struct emp_qelem *, struct emp_qelem *); static void ac_dog(struct plist *, struct plist *); static void ac_planedamage(struct plist *, natid, int, natid, int, int, char *); @@ -64,19 +69,17 @@ static void ac_doflak(struct emp_qelem *, struct sctstr *); static void ac_landflak(struct emp_qelem *, coord, coord); static void ac_shipflak(struct emp_qelem *, coord, coord); static void ac_fireflak(struct emp_qelem *, natid, int); -static void getilist(struct emp_qelem *, natid); +static void getilists(struct emp_qelem *, unsigned char *, natid); static int do_evade(struct emp_qelem *, struct emp_qelem *); void ac_encounter(struct emp_qelem *bomb_list, struct emp_qelem *esc_list, - coord x, coord y, char *path, int mission_flags, - int no_air_defense) + coord x, coord y, char *path, int mission_flags) { int val; int dir; unsigned char gotships[MAXNOC]; unsigned char gotlands[MAXNOC]; - int gotilist[MAXNOC]; unsigned char rel[MAXNOC]; int overfly[MAXNOC]; int flags; @@ -100,9 +103,7 @@ ac_encounter(struct emp_qelem *bomb_list, struct emp_qelem *esc_list, plane_owner = plp->plane.pln_own; memset(overfly, 0, sizeof(overfly)); - memset(gotilist, 0, sizeof(gotilist)); - for (cn = 0; cn < MAXNOC; cn++) - rel[cn] = getrel(getnatp(cn), plane_owner); + getilists(ilist, rel, plane_owner); if (mission_flags & PM_R) { flags = plane_caps(bomb_list); @@ -228,19 +229,12 @@ ac_encounter(struct emp_qelem *bomb_list, struct emp_qelem *esc_list, if (QEMPTY(bomb_list)) break; - if (!no_air_defense) - air_defense(x, y, plane_owner, bomb_list, esc_list); - for (cn = 1; cn < MAXNOC && !QEMPTY(bomb_list); cn++) { if (rel[cn] > HOSTILE) continue; - if (cn != sect.sct_own && !gotships[cn] && !gotlands[cn]) - continue; - if (!gotilist[cn]) { - getilist(&ilist[cn], cn); - gotilist[cn]++; - } - ac_intercept(bomb_list, esc_list, &ilist[cn], cn, x, y); + ac_intercept(bomb_list, esc_list, &ilist[cn], cn, x, y, + !(cn == sect.sct_own + || gotships[cn] || gotlands[cn])); } } @@ -263,10 +257,8 @@ ac_encounter(struct emp_qelem *bomb_list, struct emp_qelem *esc_list, writemap(player->cnum); free_shiplist(&head); - for (cn = 1; cn < MAXNOC; cn++) { - if (gotilist[cn]) - pln_put(&ilist[cn]); - } + for (cn = 1; cn < MAXNOC; cn++) + pln_put(&ilist[cn]); } static int @@ -285,10 +277,10 @@ plane_caps(struct emp_qelem *list) return fl; } -void +static void sam_intercept(struct emp_qelem *att_list, struct emp_qelem *def_list, natid def_own, natid plane_owner, coord x, coord y, - int delete_missiles) + int only_mission) { struct emp_qelem *aqp; struct emp_qelem *anext; @@ -296,6 +288,7 @@ sam_intercept(struct emp_qelem *att_list, struct emp_qelem *def_list, struct emp_qelem *dnext; struct plist *aplp; struct plist *dplp; + struct plnstr *pp; int first = 1; for (aqp = att_list->q_forw, @@ -308,20 +301,24 @@ sam_intercept(struct emp_qelem *att_list, struct emp_qelem *def_list, for (; dqp != def_list; dqp = dnext) { dnext = dqp->q_forw; dplp = (struct plist *)dqp; + pp = &dplp->plane; if (!(dplp->pcp->pl_flags & P_M)) continue; - - if (dplp->plane.pln_range < - mapdist(x, y, dplp->plane.pln_x, dplp->plane.pln_y)) + if (only_mission && !pp->pln_mission) continue; - if (CANT_HAPPEN(dplp->plane.pln_flags & PLN_LAUNCHED) + if (pp->pln_range < mapdist(x, y, pp->pln_x, pp->pln_y)) + continue; + if (pp->pln_mission + && pp->pln_radius < mapdist(x, y, pp->pln_opx, pp->pln_opy)) + continue; + if (CANT_HAPPEN(pp->pln_flags & PLN_LAUNCHED) || mission_pln_equip(dplp, 0, P_F, 0) < 0) { emp_remque(dqp); free(dqp); continue; } - dplp->plane.pln_flags |= PLN_LAUNCHED; - putplane(dplp->plane.pln_uid, &dplp->plane); + pp->pln_flags |= PLN_LAUNCHED; + putplane(pp->pln_uid, pp); if (first) { first = 0; PR(plane_owner, "%s launches SAMs!\n", cname(def_own)); @@ -338,22 +335,12 @@ sam_intercept(struct emp_qelem *att_list, struct emp_qelem *def_list, PR(plane_owner, "\n"); PR(def_own, "\n"); } - if (delete_missiles) { - for (; dqp != def_list; dqp = dnext) { - dnext = dqp->q_forw; - dplp = (struct plist *)dqp; - if (!(dplp->pcp->pl_flags & P_M)) - continue; - emp_remque(dqp); - free(dqp); - continue; - } - } } static void ac_intercept(struct emp_qelem *bomb_list, struct emp_qelem *esc_list, - struct emp_qelem *def_list, natid def_own, coord x, coord y) + struct emp_qelem *def_list, natid def_own, coord x, coord y, + int only_mission) { struct plnstr *pp; struct plist *plp; @@ -368,8 +355,10 @@ ac_intercept(struct emp_qelem *bomb_list, struct emp_qelem *esc_list, plp = (struct plist *)bomb_list->q_forw; plane_owner = plp->plane.pln_own; - sam_intercept(bomb_list, def_list, def_own, plane_owner, x, y, 0); - sam_intercept(esc_list, def_list, def_own, plane_owner, x, y, 0); + sam_intercept(bomb_list, def_list, def_own, plane_owner, x, y, + only_mission); + sam_intercept(esc_list, def_list, def_own, plane_owner, x, y, + only_mission); att_count = 0; for (qp = bomb_list->q_forw; qp != bomb_list; qp = qp->q_forw) @@ -388,9 +377,14 @@ ac_intercept(struct emp_qelem *bomb_list, struct emp_qelem *esc_list, /* SAMs interdict separately */ if (plp->pcp->pl_flags & P_M) continue; + if (only_mission && !pp->pln_mission) + continue; dist = mapdist(x, y, pp->pln_x, pp->pln_y) * 2; if (pp->pln_range < dist) continue; + if (pp->pln_mission + && pp->pln_radius < mapdist(x, y, pp->pln_opx, pp->pln_opy)) + continue; if (CANT_HAPPEN(pp->pln_flags & PLN_LAUNCHED) || mission_pln_equip(plp, 0, P_F, 0) < 0) { emp_remque(qp); @@ -845,27 +839,33 @@ ac_flak_dam(int guns, int def, int pl_flags) } /* - * Get a list of planes available for interception duties. + * Get planes available for interception duties. */ static void -getilist(struct emp_qelem *list, natid own) +getilists(struct emp_qelem *list, unsigned char *rel, natid intruder) { + natid cn; struct plchrstr *pcp; struct plnstr plane; struct nstr_item ni; struct plist *ip; - emp_initque(list); + rel[0] = NEUTRAL; + for (cn = 1; cn < MAXNOC; cn++) { + rel[cn] = getrel(getnatp(cn), intruder); + emp_initque(&list[cn]); + } + snxtitem_all(&ni, EF_PLANE); while (nxtitem(&ni, &plane)) { - if (plane.pln_own != own) + if (rel[plane.pln_own] > HOSTILE) continue; pcp = &plchr[(int)plane.pln_type]; if ((pcp->pl_flags & P_F) == 0) continue; if (plane.pln_flags & PLN_LAUNCHED) continue; - if (plane.pln_mission != 0) + if (plane.pln_mission && plane.pln_mission != MI_AIR_DEFENSE) continue; if (plane.pln_mobil <= 0) continue; @@ -879,7 +879,7 @@ getilist(struct emp_qelem *list, natid own) ip->misc = 0; ip->pcp = &plchr[(int)plane.pln_type]; ip->plane = plane; - emp_insque(&ip->queue, list); + emp_insque(&ip->queue, &list[plane.pln_own]); } } diff --git a/src/lib/subs/mission.c b/src/lib/subs/mission.c index e3d78f8c..473e012d 100644 --- a/src/lib/subs/mission.c +++ b/src/lib/subs/mission.c @@ -630,7 +630,7 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list, xyas(x, y, air->own)); } - ac_encounter(&b, &e, air->x, air->y, pp, 0, 0); + ac_encounter(&b, &e, air->x, air->y, pp, 0); if (!QEMPTY(&b)) air_dam += @@ -1111,216 +1111,3 @@ air_damage(struct emp_qelem *bombers, coord x, coord y, int mission, return dam; } - -/* - * Check to see if anyone hostile to the victim - * is running an air defense mission on this - * sector. If so, do air combat - */ -int -air_defense(coord x, coord y, natid victim, struct emp_qelem *bomb_list, - struct emp_qelem *esc_list) -{ - int dam = 0, cn; - int combat = 0, rel, dist, z; - struct emp_qelem *qp, interceptors, airp, i, empty, *next; - struct plist *plp; - struct genlist *glp; - struct empobj *gp; - struct genlist mi[MAXNOC]; - char buf[512]; - char *path; - int count; - int tcount; - - count = 0; - for (qp = bomb_list->q_forw; qp != bomb_list; qp = qp->q_forw) - count++; - for (qp = esc_list->q_forw; qp != esc_list; qp = qp->q_forw) - count++; - - memset(mi, 0, sizeof(mi)); - for (z = 1; z < MAXNOC; z++) - emp_initque((struct emp_qelem *)&mi[z]); - - build_mission_list_type(mi, x, y, MI_AIR_DEFENSE, EF_PLANE, victim); - - for (cn = 1; cn < MAXNOC; cn++) { - /* Check our relations */ - rel = getrel(getnatp(cn), victim); - - if (rel > HOSTILE) - continue; - - if (QEMPTY(&mi[cn].queue)) - continue; - - /* Ok, make a list of all the interceptors. Note that this *copies* the - * list from the mission creation. This list must be deleted later. */ - emp_initque(&interceptors); - for (qp = mi[cn].queue.q_forw; qp != (&mi[cn].queue); qp = next) { - next = qp->q_forw; - glp = (struct genlist *)qp; - gp = glp->thing; - if (CANT_HAPPEN(gp->ef_type != EF_PLANE)) - break; - - dist = mapdist(x, y, gp->x, gp->y); - - plp = malloc(sizeof(struct plist)); - memset(plp, 0, sizeof(struct plist)); - plp->pcp = glp->cp; - memcpy(&plp->plane, glp->thing, sizeof(struct plnstr)); - - /* missiles go one way, so we can use all the range */ - if (!(plp->pcp->pl_flags & P_M)) - dist *= 2; - /* If it's out of range, free it and continue on */ - if (dist > plp->plane.pln_range) { - free(plp); - continue; - } - emp_insque(&plp->queue, &interceptors); - } - - /* Remove those who cannot go */ - mission_pln_sel(&interceptors, P_F, 0, SECT_HARDTARGET); - - if (QEMPTY(&interceptors)) - continue; - - /* Now, delete all the extras, but delete the first ones, not the last ones, so - * that the higher numbered planes go into battle (they should be the better ones - * at fighting, if all went well.) */ - tcount = 0; - for (qp = interceptors.q_forw; qp != (&interceptors); - qp = qp->q_forw) - tcount++; - tcount -= count * 2; - /* Just in case there are more incoming than we have */ - if (tcount < 0) - tcount = 0; - for (qp = interceptors.q_forw; qp != (&interceptors); qp = next) { - next = qp->q_forw; - if (tcount) { - tcount--; - /* Free it up and continue */ - emp_remque(qp); - glp = (struct genlist *)qp; - free(glp); - } - } - - /* Now, make a list of all the airports these planes are coming from */ - emp_initque(&airp); - for (qp = interceptors.q_forw; qp != (&interceptors); - qp = qp->q_forw) { - plp = (struct plist *)qp; - if (!find_airport(&airp, plp->plane.pln_x, plp->plane.pln_y)) - add_airport(&airp, plp->plane.pln_x, plp->plane.pln_y); - } - - /* Now, fly them out one airport at a time */ - for (qp = airp.q_forw; qp != (&airp); qp = qp->q_forw) { - struct airport *air; - - air = (struct airport *)qp; - dist = mapdist(x, y, air->x, air->y); - - emp_initque(&i); - - /* Split off the interceptors at this base into i */ - divide(&interceptors, &i, air->x, air->y); - - sam_intercept(bomb_list, &i, cn, victim, x, y, 0); - sam_intercept(esc_list, &i, cn, victim, x, y, 1); - - /* Did we run out of interceptors? */ - if (QEMPTY(&i)) - continue; - /* Did we run out of bombers? */ - if (QEMPTY(bomb_list)) { - /* Yes, so we have to put the rest of the interceptors back, and - then continue, or we leak memory */ - pln_put(&i); - continue; - } - mission_pln_arm(&i, air->x, air->y, 2 * dist, 0, 0, P_F); - - /* Did we run out of interceptors? */ - if (QEMPTY(&i)) - continue; - /* Did we run out of bombers? */ - if (QEMPTY(bomb_list)) { - /* Yes, so we have to put the rest of the interceptors back, and - then continue, or we leak memory */ - pln_put(&i); - continue; - } - - path = BestAirPath(buf, air->x, air->y, x, y); - if (CANT_HAPPEN(!path)) { - pln_put(&i); - continue; - } - wu(0, cn, "Flying %s mission from %s to %s\n", - mission_name(MI_AIR_DEFENSE), - xyas(air->x, air->y, cn), - xyas(x, y, cn)); - if (air->own && (air->own != cn)) { - wu(0, air->own, "%s is flying %s mission from %s to %s\n", - cname(cn), mission_name(MI_AIR_DEFENSE), - xyas(air->x, air->y, air->own), - xyas(x, y, air->own)); - } - - /* Now, fly the planes to the sector */ - emp_initque(&empty); - ac_encounter(&i, &empty, air->x, air->y, path, 0, 1); - - /* If none made it, continue */ - if (QEMPTY(&i)) - continue; - - /* Some made it, so now they get to try to fight. */ - /* Intercept the escorts first */ - combat = 0; - if (!QEMPTY(esc_list)) { - mpr(victim, "%s air defense planes intercept!\n", - cname(cn)); - ac_combat_headers(victim, cn); - ac_airtoair(esc_list, &i); - combat = 1; - } - /* Now intercept the bombers */ - if (!QEMPTY(bomb_list)) { - if (!combat) { - mpr(victim, "%s air defense planes intercept!\n", - cname(cn)); - ac_combat_headers(victim, cn); - } - ac_airtoair(bomb_list, &i); - PR(cn, "\n"); - PR(victim, "\n"); - } - - pln_put(&i); - } - if (CANT_HAPPEN(!QEMPTY(&interceptors))) - pln_put(&interceptors); - } - - /* We have to free all of these, if they are still there, otherwise they get - lost and we leak memory all over the place. */ - for (cn = 1; cn < MAXNOC; cn++) { - /* free up all this memory if it's still there */ - for (qp = mi[cn].queue.q_forw; qp != (&mi[cn].queue); qp = next) { - next = qp->q_forw; - glp = (struct genlist *)qp; - free(glp->thing); - free(glp); - } - } - - return dam; -}