X-Git-Url: http://git.pond.sub.org/?p=empserver;a=blobdiff_plain;f=src%2Flib%2Fsubs%2Fmslsub.c;h=a25f28f68e44e83e5a4af4e94b50c17a83f99f21;hp=1f8a5ac2b004f7e1a363a52fcd8384b71ec921ee;hb=0b46e31d60f5b60f4dfca7df60574264f6713a3b;hpb=91c316afaa5a359740faada29d121200a5fd8f6e diff --git a/src/lib/subs/mslsub.c b/src/lib/subs/mslsub.c index 1f8a5ac2b..a25f28f68 100644 --- a/src/lib/subs/mslsub.c +++ b/src/lib/subs/mslsub.c @@ -1,11 +1,11 @@ /* * Empire - A multi-player, client/server Internet based war game. - * Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak, - * Ken Stevens, Steve McClure + * Copyright (C) 1986-2021, Dave Pare, Jeff Bailey, Thomas Ruschak, + * Ken Stevens, Steve McClure, Markus Armbruster * - * This program is free software; you can redistribute it and/or modify + * Empire is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -14,154 +14,162 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program. If not, see . * * --- * - * See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the - * related information and legal notices. It is expected that any future - * projects/authors will amend these files as needed. + * See files README, COPYING and CREDITS in the root of the source + * tree for related information and legal notices. It is expected + * that future projects/authors will amend these files as needed. * * --- * * mslsub.c: Missile subroutine stuff - * + * * Known contributors to this file: * Ken Stevens, 1995 * Steve McClure, 1996-2000 + * Markus Armbruster, 2004-2021 */ +#include + +#include +#include "chance.h" #include "misc.h" +#include "nat.h" +#include "news.h" +#include "nsc.h" +#include "nuke.h" +#include "optlist.h" +#include "plague.h" +#include "plane.h" +#include "prototypes.h" #include "queue.h" -#include "player.h" -#include "var.h" #include "sect.h" #include "ship.h" -#include "optlist.h" -#include "nuke.h" -#include "plane.h" -#include "land.h" -#include "news.h" -#include "item.h" #include "xy.h" -#include "nsc.h" -#include "file.h" -#include "nat.h" -#include "path.h" -#include "mission.h" -#include "prototypes.h" int -msl_equip(struct plnstr *pp) +msl_launch(struct plnstr *pp, int type, char *what, coord x, coord y, + natid victim, int *sublaunchp) { - struct plist pl; - - memset(&pl, 0, sizeof(struct plist)); - pl.pcp = plchr + pp->pln_type; - pl.plane = *pp; - return mission_pln_equip(&pl, 0, 0, 'p'); -} - -int -msl_hit(struct plnstr *pp, int hardtarget, int type, int news_item, - int snews_item, s_char *what, coord x, coord y, int victim) -{ - int hit; struct shpstr ship; - struct sctstr sect; + struct nukstr nuke; int sublaunch = 0; - struct plchrstr *pcp = plchr + pp->pln_type; - int hitchance = pln_hitchance(pp, hardtarget, type); - s_char *from; - int dam, dummyi; + char *base, *in_or_at, *from; mpr(pp->pln_own, "Preparing to launch %s at %s %s %s%s\n", prplane(pp), cname(victim), what, - (type == EF_SHIP || type == EF_PLANE) ? "in " : "", + type != EF_SECTOR ? "in " : "", xyas(x, y, pp->pln_own)); - mpr(pp->pln_own, "\tLaunching from "); if (pp->pln_ship >= 0) { getship(pp->pln_ship, &ship); - mpr(pp->pln_own, "%s in ", prship(&ship)); + base = prship(&ship); + in_or_at = " in "; if (mchr[(int)ship.shp_type].m_flags & M_SUB) { sublaunch = 1; from = "in hatch"; } else from = "on deck"; - mpr(pp->pln_own, "%s\n", - xyas(ship.shp_x, ship.shp_y, pp->pln_own)); } else { if (pp->pln_harden > 0) { - mpr(pp->pln_own, "missile silo at "); + base = "missile silo"; + in_or_at = " at "; from = "in silo"; - } else + } else { + base = in_or_at = ""; from = "on launch pad"; - mpr(pp->pln_own, "%s\n", xyas(pp->pln_x, pp->pln_y, pp->pln_own)); + } } + mpr(pp->pln_own, "\tLaunching from %s%s%s\n", + base, in_or_at, xyas(pp->pln_x, pp->pln_y, pp->pln_own)); + + CANT_HAPPEN(pp->pln_flags & PLN_LAUNCHED); + pp->pln_flags |= PLN_LAUNCHED; + putplane(pp->pln_uid, pp); if (chance((0.05 + (100 - pp->pln_effic) / 100.0) * (1 - techfact(pp->pln_tech, 1.0)))) { mpr(pp->pln_own, "KABOOOOM! Missile explodes %s!\n", from); + if (getnuke(nuk_on_plane(pp), &nuke)) { + mpr(pp->pln_own, "%s lost!\n", prnuke(&nuke)); + nuke.nuk_effic = 0; + putnuke(nuke.nuk_uid, &nuke); + } +#if 0 + /* + * Disabled for now, because it breaks callers that call + * msl_launch() for each member of a list of planes, created + * by msl_sel() or perform_mission(). Damage to the base can + * damage other planes. Any copies of them in the list become + * stale. When msl_launch() modifies and writes back such a + * stale copy, the damage gets wiped out, triggering a seqno + * oops. + */ if (chance(0.33)) { - if (pp->pln_nuketype != (s_char)-1 && opt_NUKEFAILDETONATE) { - pp->pln_flags &= ~PLN_AIRBURST; - detonate(pp, pp->pln_x, pp->pln_y); + struct sctstr sect; + int dam; + + dam = pln_damage(pp, 'p', NULL) / 2; + if (pp->pln_ship >= 0) { + shipdamage(&ship, dam); + putship(ship.shp_uid, &ship); } else { - dam = pln_damage(pp, pp->pln_x, pp->pln_y, - 'p', &dummyi, 1) / 2; - if (dam) { - if (pp->pln_ship >= 0) { - shipdamage(&ship, dam); - putship(ship.shp_uid, &ship); - } else { - pr("Explosion damages %s %d%%", - xyas(pp->pln_x, pp->pln_y, pp->pln_own), dam); - getsect(pp->pln_x, pp->pln_y, §); - sectdamage(§, dam, 0); - putsect(§); - } - } + mpr(pp->pln_own, "Explosion damages %s %d%%\n", + xyas(pp->pln_x, pp->pln_y, pp->pln_own), dam); + getsect(pp->pln_x, pp->pln_y, §); + sectdamage(§, dam); + putsect(§); } } - return 0; +#endif + return -1; } mpr(pp->pln_own, "\tSHWOOOOOSH! Missile launched!\n"); - if (pp->pln_nuketype != (s_char)-1) - mpr(pp->pln_own, "\tArming nuclear warheads...\n"); - - if (pcp->pl_flags & P_T) + if (type != EF_PLANE) mpr(victim, "Incoming %s missile sighted at %s...\n", sublaunch ? "sub-launched" : cname(pp->pln_own), xyas(x, y, victim)); - if (opt_PINPOINTMISSILE == 0 || - (pcp->pl_flags & P_T && !(pcp->pl_flags & P_MAR))) { - if (msl_intercept(x, y, pp->pln_own, pcp->pl_def, - sublaunch, P_N, P_O)) { - return 0; - } + if (type == EF_SECTOR || type == EF_LAND) { + if (msl_abm_intercept(pp, x, y, sublaunch)) + return -1; } - if (pcp->pl_flags & P_MAR) { - if (shp_missile_defense(x, y, pp->pln_own, pcp->pl_def)) { - return 0; + if (type == EF_SHIP) { + if (shp_missile_defense(x, y, pp->pln_own, pln_def(pp))) { + return -1; } } - if (pp->pln_nuketype != (s_char)-1) - hitchance = 100; + if (sublaunchp) + *sublaunchp = sublaunch; + return 0; +} - mpr(pp->pln_own, "\t%d%% hitchance...", hitchance); - hit = (roll(100) <= hitchance); +int +msl_hit(struct plnstr *pp, int hardtarget, int type, + int news_item, int snews_item, int sublaunch, natid victim) +{ + int hitchance, hit; - mpr(pp->pln_own, hit ? "HIT!\n" : "miss\n"); - if (pcp->pl_flags & P_T) + if (nuk_on_plane(pp) >= 0) { + mpr(pp->pln_own, "\tArming nuclear warheads...\n"); + hit = 1; + } else { + hitchance = pln_hitchance(pp, hardtarget, type); + hit = pct_chance(hitchance); + mpr(pp->pln_own, "\t%d%% hit chance...%s\n", hitchance, + hit ? "HIT!" : "miss"); + } + + if (type != EF_PLANE) mpr(victim, "...Incoming %s missile %s\n", - sublaunch ? (s_char *)"" : cname(pp->pln_own), + sublaunch ? "" : cname(pp->pln_own), hit ? "HIT!\n" : "missed\n"); if (hit && news_item) { if (sublaunch) @@ -176,14 +184,14 @@ void msl_sel(struct emp_qelem *list, coord x, coord y, natid victim, int wantflags, int nowantflags, int mission) { - register struct plchrstr *pcp; + struct plchrstr *pcp; struct plnstr plane; struct plist *irv; struct nstr_item ni; emp_initque(list); snxtitem_all(&ni, EF_PLANE); - while (nxtitem(&ni, (s_char *)&plane)) { + while (nxtitem(&ni, &plane)) { if (!plane.pln_own) continue; @@ -196,72 +204,49 @@ msl_sel(struct emp_qelem *list, coord x, coord y, natid victim, continue; if (mission && plane.pln_mission != mission) continue; - if (getrel(getnatp(plane.pln_own), victim) >= NEUTRAL) + if (mission && + plane.pln_radius < mapdist(x, y, plane.pln_opx, plane.pln_opy)) + continue; + if (relations_with(plane.pln_own, victim) >= NEUTRAL) continue; /* missiles go one way, so we can use all the range */ if (plane.pln_range < mapdist(x, y, plane.pln_x, plane.pln_y)) continue; - if (plane.pln_mobil <= (s_char)0) + if (plane.pln_mobil <= 0) continue; if (plane.pln_effic < 100) continue; + if (opt_MARKET) { + if (ontradingblock(EF_PLANE, &plane)) + continue; + } + if (!pln_airbase_ok(&plane, 1, 0)) + continue; /* got a valid interceptor */ - irv = (struct plist *)malloc(sizeof(*irv)); - irv->state = P_OK; - irv->bombs = 0; - irv->misc = 0; + irv = malloc(sizeof(*irv)); + irv->load = 0; + irv->pstage = PLG_HEALTHY; irv->pcp = &plchr[(int)plane.pln_type]; irv->plane = plane; emp_insque(&irv->queue, list); } } -int -msl_intercept(coord x, coord y, natid bombown, int hardtarget, - int sublaunch, int wantflags, int nowantflags) +static int +msl_intercept(struct plnstr *msl, struct sctstr *sp, int sublaunch, + struct emp_qelem *irvlist, char *att_name, char *def_name, + int news_item) { - register struct plnstr *pp; - register struct plchrstr *pcp; - struct sctstr sect; - struct emp_qelem *irvlist; - struct emp_qelem foo; + struct plnstr *pp; struct emp_qelem *intlist; struct emp_qelem intfoo; struct emp_qelem *qp; struct emp_qelem *next; struct plist *ip; int icount = 0; - short destroyed = 0; - s_char *att_name; - s_char *def_name; - int news_item; - s_char *who = sublaunch ? (s_char *)"" : cname(bombown); + short destroyed; + char *who = sublaunch ? "" : cname(msl->pln_own); - getsect(x, y, §); - if (wantflags == P_O && !nowantflags) { - att_name = "satellite"; - def_name = "a-sat missile"; - news_item = N_SAT_KILL; - if (sect.sct_own) { - mpr(sect.sct_own, "%s has positioned a satellite over %s\n", - sublaunch ? (s_char *)"someone" : cname(bombown), xyas(x, - y, - sect. - sct_own)); - } - } else if (wantflags == P_N && nowantflags == P_O) { - att_name = "warhead"; - def_name = "abm"; - news_item = sublaunch ? N_NUKE_SSTOP : N_NUKE_STOP; - } else { - att_name = "elephant"; - def_name = "tomato"; /* heh -KHS */ - news_item = N_NUKE_STOP; - } - irvlist = &foo; - - /* get all hostile abms in range */ - msl_sel(irvlist, x, y, bombown, wantflags, nowantflags, 0); intlist = &intfoo; emp_initque(intlist); /* First choose interceptors belonging to the target sector */ @@ -270,12 +255,11 @@ msl_intercept(coord x, coord y, natid bombown, int hardtarget, next = qp->q_forw; ip = (struct plist *)qp; pp = &ip->plane; - if (pp->pln_own != sect.sct_own) + if (pp->pln_own != sp->sct_own) continue; - pcp = ip->pcp; - if (mission_pln_equip(ip, 0, 0, 'i') < 0) { + if (mission_pln_equip(ip, NULL, 0) < 0) { emp_remque(qp); - free((s_char *)qp); + free(qp); continue; } /* got one interceptor, delete from irv_list and @@ -291,10 +275,9 @@ msl_intercept(coord x, coord y, natid bombown, int hardtarget, next = qp->q_forw; ip = (struct plist *)qp; pp = &ip->plane; - pcp = ip->pcp; - if (mission_pln_equip(ip, 0, 0, 'i') < 0) { + if (mission_pln_equip(ip, NULL, 0) < 0) { emp_remque(qp); - free((s_char *)qp); + free(qp); continue; } /* got one interceptor, delete from irv_list and @@ -309,127 +292,96 @@ msl_intercept(coord x, coord y, natid bombown, int hardtarget, while (!QEMPTY(irvlist)) { qp = irvlist->q_forw; emp_remque(qp); - free((s_char *)qp); + free(qp); } if (icount == 0) { - if (sect.sct_own != 0) - mpr(sect.sct_own, "No %ss launched to intercept.\n", def_name); - return (destroyed); + mpr(sp->sct_own, "No %ss launched to intercept.\n", def_name); + return 0; } /* attempt to destroy incoming missile */ - while (!QEMPTY(intlist)) { + destroyed = 0; + while (!destroyed && !QEMPTY(intlist)) { qp = intlist->q_forw; ip = (struct plist *)qp; pp = &ip->plane; - pcp = ip->pcp; - mpr(bombown, "%s %s launched in defense!\n", + mpr(msl->pln_own, "%s %s launched in defense!\n", cname(pp->pln_own), def_name); - if (sect.sct_own == pp->pln_own) { - mpr(sect.sct_own, "%s launched to intercept %s %s!\n", + if (sp->sct_own == pp->pln_own) { + mpr(sp->sct_own, "%s launched to intercept %s %s!\n", def_name, who, att_name); } else { - if (sect.sct_own) - mpr(sect.sct_own, - "%s launched an %s to intercept the %s %s!\n", - cname(pp->pln_own), def_name, who, att_name); + mpr(sp->sct_own, + "%s launched an %s to intercept the %s %s!\n", + cname(pp->pln_own), def_name, who, att_name); mpr(pp->pln_own, "%s launched to intercept %s %s arcing towards %s territory!\n", - def_name, who, att_name, cname(sect.sct_own)); + def_name, who, att_name, cname(sp->sct_own)); } - if (!destroyed && - msl_hit(pp, hardtarget, EF_PLANE, news_item, news_item, - att_name, x, y, bombown)) { - mpr(bombown, "%s destroyed by %s %s!\n", att_name, - cname(pp->pln_own), def_name); - if (sect.sct_own) - mpr(sect.sct_own, "%s %s intercepted!\n", who, att_name); - if (sect.sct_own != pp->pln_own) + if (msl_launch(pp, EF_PLANE, att_name, sp->sct_x, sp->sct_y, + msl->pln_own, NULL) >= 0 + && msl_hit(pp, pln_def(msl), EF_PLANE, 0, 0, 0, msl->pln_own)) { + mpr(msl->pln_own, "%s destroyed by %s %s!\n", + att_name, cname(pp->pln_own), def_name); + mpr(sp->sct_own, "%s %s intercepted!\n", who, att_name); + if (sp->sct_own != pp->pln_own) mpr(pp->pln_own, "%s %s intercepted!\n", who, att_name); + if (sublaunch) + nreport(pp->pln_own, news_item, 0, 1); + else + nreport(pp->pln_own, news_item, msl->pln_own, 1); destroyed = 1; } /* zap the missile */ - makelost(EF_PLANE, pp->pln_own, pp->pln_uid, pp->pln_x, pp->pln_y); - pp->pln_own = 0; + pp->pln_effic = 0; putplane(pp->pln_uid, pp); emp_remque(qp); - free((s_char *)qp); - if (destroyed) - break; + free(qp); } /* Clean out what is left in the list */ while (!QEMPTY(intlist)) { qp = intlist->q_forw; emp_remque(qp); - free((s_char *)qp); + free(qp); } if (destroyed) - return (destroyed); + return 1; if (icount) { - mpr(bombown, "%s made it through %s defenses!\n", att_name, - def_name); - if (sect.sct_own) - mpr(sect.sct_own, "%s made it through %s defenses!\n", - att_name, def_name); + mpr(msl->pln_own, "%s made it through %s defenses!\n", + att_name, def_name); + mpr(sp->sct_own, "%s made it through %s defenses!\n", + att_name, def_name); } - return (destroyed); + return 0; } -/* Keep launching missiles on list until mindam damage has been done */ int -msl_launch_mindam(struct emp_qelem *list, coord x, coord y, int hardtarget, - int type, int mindam, s_char *whatp, int victim, - int mission) +msl_abm_intercept(struct plnstr *msl, coord x, coord y, int sublaunch) { - struct emp_qelem *qp; - struct emp_qelem *next; - struct plist *plp; - int newdam, dam = 0; - int nukedam = 0; - int news_item; - int snews_item; + struct sctstr sect; + struct emp_qelem irvlist; - if (type == EF_SHIP) { - news_item = N_SHP_MISS; - snews_item = N_SHP_SMISS; - } else if (type == EF_LAND) { - news_item = N_LND_MISS; - snews_item = N_LND_SMISS; - } else { - news_item = N_SCT_MISS; - snews_item = N_SCT_SMISS; - } + getsect(x, y, §); + msl_sel(&irvlist, x, y, msl->pln_own, P_N, 0, 0); + return msl_intercept(msl, §, sublaunch, + &irvlist, "warhead", "abm", + sublaunch ? N_NUKE_SSTOP : N_NUKE_STOP); +} - for (qp = list->q_back; qp != list && dam < mindam && !nukedam; - qp = next) { - next = qp->q_back; - plp = (struct plist *)qp; +int +msl_asat_intercept(struct plnstr *msl, coord x, coord y) +{ + struct sctstr sect; + struct emp_qelem irvlist; - if (mission_pln_equip(plp, 0, 0, 'p') >= 0) { - if (msl_hit(&plp->plane, - hardtarget, type, news_item, snews_item, - whatp, x, y, victim)) { - newdam = pln_damage(&plp->plane, x, y, 'p', &nukedam, 1); - if (nukedam) { - if (mission == MI_INTERDICT && type == EF_SECTOR) - dam += nukedam; - } else - dam += newdam; - } else { - /* Missiles that miss have to hit somewhere! */ - newdam = pln_damage(&plp->plane, x, y, 'p', &nukedam, 0); - collateral_damage(x, y, newdam, 0); - } - makelost(EF_PLANE, plp->plane.pln_own, plp->plane.pln_uid, - plp->plane.pln_x, plp->plane.pln_y); - plp->plane.pln_own = 0; - putplane(plp->plane.pln_uid, &plp->plane); - emp_remque(qp); - free(qp); - } - } - return dam; + getsect(x, y, §); + mpr(sect.sct_own, "%s has positioned a satellite over %s\n", + cname(msl->pln_own), xyas(x, y, sect.sct_own)); + msl_sel(&irvlist, x, y, msl->pln_own, P_O, 0, 0); + return msl_intercept(msl, §, 0, + &irvlist, "satellite", "a-sat missile", + N_SAT_KILL); }