/*
* 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-2014, 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,
* 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 <http://www.gnu.org/licenses/>.
*
* ---
*
- * 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.
*
* ---
*
* multifire.c: Fire at other sectors/ships
- *
+ *
* Known contributors to this file:
* Steve McClure, 2000
- *
+ * Markus Armbruster, 2004-2014
*/
-#include "misc.h"
-#include "player.h"
-#include "var.h"
-#include "xy.h"
-#include "treaty.h"
-#include "nat.h"
-#include "ship.h"
-#include "land.h"
-#include "sect.h"
-#include "retreat.h"
+#include <config.h>
+
+#include "chance.h"
+#include "commands.h"
+#include "empobj.h"
#include "news.h"
-#include "nsc.h"
-#include "file.h"
-#include "queue.h"
-#include <ctype.h>
-#include "options.h"
#include "optlist.h"
-#include "damage.h"
-#include "commands.h"
+#include "retreat.h"
enum targ_type {
- targ_land, targ_ship, targ_sub, targ_unit, targ_bogus
+ targ_land, targ_ship, targ_sub, targ_bogus
};
struct flist {
struct emp_qelem queue; /* list of fired things */
- int type; /* ship? otherwise sector */
- int uid; /* ship uid */
- coord x, y; /* sector coords */
+ short type; /* EF_SECTOR, EF_SHIP or EF_LAND */
+ int uid;
+ coord x, y;
int defdam; /* damage defenders did */
- int victim; /* who I was shooting at */
-};
-
-union item_u {
- struct shpstr ship;
- struct sctstr sect;
- struct lndstr land;
+ natid victim;
};
-static void add_to_fired_queue(struct emp_qelem *, struct emp_qelem *);
-static int defend(struct emp_qelem *al,
- struct emp_qelem *dl,
- enum targ_type target,
- enum targ_type attacker,
- struct sctstr *vsect,
- struct sctstr *fsect,
- struct shpstr *vship,
- struct shpstr *fship, int fx, int fy, int *nd);
+static int defend(struct emp_qelem *, struct emp_qelem *,
+ struct empobj *, natid, int *);
static void do_defdam(struct emp_qelem *, double);
static int quiet_bigdef(int, struct emp_qelem *, natid, natid, coord,
coord, int *);
-static void use_ammo(struct emp_qelem *);
+static void add_to_flist(struct emp_qelem *, struct empobj *, int, natid);
+static void free_flist(struct emp_qelem *);
+static struct flist *search_flist(struct emp_qelem *, struct empobj *);
int
multifire(void)
{
- s_char vbuf[20];
- s_char *ptr;
- double range2, range;
- int trange;
+ static int ef_with_guns[] = { EF_SECTOR, EF_SHIP, EF_LAND, EF_BAD };
+ char *ptr;
+ double range;
+ int trange, range2;
coord fx;
coord fy;
coord x;
coord y;
- int mil;
- int gun;
- int shell;
- int shots;
- double guneff;
int dam;
int totaldefdam = 0;
- int fshipno;
int vshipno;
- double prb;
natid vict;
struct shpstr fship;
struct lndstr fland;
struct sctstr fsect;
+ char *sep = "";
struct shpstr vship;
struct sctstr vsect;
- enum targ_type target, attacker, orig_attacker;
- int rel;
- struct natstr *natp;
+ enum targ_type target;
struct nstr_item nbst;
int type;
- s_char *p;
+ struct empobj *attgp;
+ char *p;
int nfiring = 0;
int ndefending = 0;
- union item_u item;
+ union empobj_storage item;
struct emp_qelem fired, defended;
double odds;
- s_char buf[1024];
-#if defined(_WIN32)
- time_t now;
-#endif
+ char buf[1024];
emp_initque(&fired);
emp_initque(&defended);
- type = (-1);
- while ((type != EF_SECTOR) && (type != EF_SHIP) && (type != EF_LAND)) {
- if (!(p = getstarg(player->argp[1],
- "Firing from ship(s), sect(s), or land unit(s)? ",
- buf)))
- return RET_SYN;
- player->argp[1] = 0;
- type = ef_byname(p);
- if (type == EF_SECTOR) {
- if (opt_NO_FORT_FIRE) {
- pr("Fort firing is disabled.\n");
- return RET_FAIL;
- }
- orig_attacker = attacker = targ_land;
- shots = 1;
- } else if (type == EF_SHIP) {
- orig_attacker = attacker = targ_ship;
- } else if (type == EF_LAND) {
- orig_attacker = attacker = targ_unit;
- } else
- pr("Please type 'sh', 'l', or 'se'!\n");
+ p = getstarg(player->argp[1],
+ "Firing from ship(s), sect(s), or land unit(s)? ", buf);
+ if (!p)
+ return RET_SYN;
+ type = ef_byname_from(p, ef_with_guns);
+ if (opt_NO_FORT_FIRE && type == EF_SECTOR) {
+ pr("Fort firing is disabled.\n");
+ return RET_FAIL;
}
- if ((ptr = getstarg(player->argp[2], "Firing from? ", buf)) == 0
- || *ptr == '\0')
+ if (type < 0) {
+ pr("Ships, land units or sectors only!\n");
return RET_SYN;
-
- if (!snxtitem(&nbst, type, ptr))
+ }
+ if (!snxtitem(&nbst, type, player->argp[2], "Firing from? "))
return RET_SYN;
- if (player->aborted) {
- pr("Fire aborted.\n");
- return RET_OK;
- }
- while (nxtitem(&nbst, (s_char *)&item)) {
- attacker = orig_attacker;
- if (attacker == targ_unit) {
+ while (nxtitem(&nbst, &item)) {
+ if (type == EF_LAND) {
if (!getland(item.land.lnd_uid, &fland))
continue;
if (!getsect(item.land.lnd_x, item.land.lnd_y, &fsect))
if (item.land.lnd_own != player->cnum)
continue;
- if (fland.lnd_frg == 0) {
+ if (lchr[fland.lnd_type].l_dam == 0) {
pr("Unit %d cannot fire!\n", fland.lnd_uid);
continue;
}
- if (lnd_getmil(&fland) < 1) {
+ if (fland.lnd_item[I_MILIT] < 1) {
pr("Unit %d cannot fire because it has no military!\n",
fland.lnd_uid);
continue;
continue;
}
if (fland.lnd_effic < LAND_MINFIREEFF) {
- pr("Unit %d cannot fire because it is less than %d%% efficient\n", fland.lnd_uid, LAND_MINFIREEFF);
+ pr("Unit %d cannot fire because it is less than %d%% efficient\n",
+ fland.lnd_uid, LAND_MINFIREEFF);
continue;
}
- resupply_commod(&fland, I_SHELL); /* Get more shells */
- putland(fland.lnd_uid, &fland);
+ if (fland.lnd_item[I_GUN] == 0) {
+ pr("%s -- not enough guns\n", prland(&fland));
+ continue;
+ }
+
if (fland.lnd_item[I_SHELL] == 0) {
pr("%s -- not enough shells\n", prland(&fland));
continue;
}
- } else if (attacker == targ_ship) {
+ pr("%s%s ready to fire\n", sep, prland(&fland));
+ fx = fland.lnd_x;
+ fy = fland.lnd_y;
+ } else if (type == EF_SHIP) {
if (!getship(item.ship.shp_uid, &fship))
continue;
if (item.ship.shp_own != player->cnum)
pr("Not enough mil on ship #%d\n", item.ship.shp_uid);
continue;
}
- gun = item.ship.shp_item[I_GUN];
- gun = min(gun, item.ship.shp_glim);
- if (item.ship.shp_frnge == 0) {
+ if (mchr[item.ship.shp_type].m_glim == 0
+ && !(mchr[fship.shp_type].m_flags & M_DCH)) {
pr("Ships %d cannot fire guns!\n", item.ship.shp_uid);
continue;
}
- if (gun == 0) {
+ if (item.ship.shp_item[I_GUN] == 0) {
pr("Not enough guns on ship #%d\n", item.ship.shp_uid);
continue;
}
pr("Ship #%d is crippled!\n", item.ship.shp_uid);
continue;
}
- fshipno = fship.shp_uid;
- } else if (attacker == targ_land) {
+ pr("%s%s ready to fire\n", sep, prship(&fship));
+ fx = fship.shp_x;
+ fy = fship.shp_y;
+ } else {
if (!getsect(item.sect.sct_x, item.sect.sct_y, &fsect))
continue;
if (item.sect.sct_own != player->cnum)
continue;
if (item.sect.sct_type != SCT_FORTR)
continue;
- if (item.sect.sct_effic < ((u_char)FORTEFF)) {
+ if (item.sect.sct_effic < FORTEFF) {
pr("Fort not efficient enough to fire!\n");
continue;
}
xyas(item.sect.sct_x, item.sect.sct_y, player->cnum));
continue;
}
- pr("\nSector %s firing\n",
+ pr("%sSector %s ready to fire\n", sep,
xyas(item.sect.sct_x, item.sect.sct_y, player->cnum));
+ fx = fsect.sct_x;
+ fy = fsect.sct_y;
}
- if ((ptr = getstarg(player->argp[3], "Firing at? ", buf)) == 0
- || *ptr == '\0')
- continue;
- if (player->aborted) {
- pr("Fire aborted.\n");
+ sep = "\n";
+
+ ptr = getstarg(player->argp[3], "Firing at? ", buf);
+ if (!ptr)
+ return RET_FAIL;
+ if (!*ptr)
continue;
- }
- ptr[19] = 0;
- (void)strcpy(vbuf, ptr);
- if (issector(vbuf))
- target = targ_land;
- else
- target = targ_ship;
- if (target == targ_ship) {
- vshipno = atoi(vbuf);
+ if (!issector(ptr)) {
+ vshipno = atoi(ptr);
if (vshipno < 0 || !getship(vshipno, &vship) ||
(!vship.shp_own)) {
pr("No such ship exists!\n");
continue;
}
} else {
- if (!sarg_xy(vbuf, &x, &y) || !getsect(x, y, &vsect)) {
+ if (!sarg_xy(ptr, &x, &y) || !getsect(x, y, &vsect)) {
pr("No such sector exists!\n");
continue;
}
x = vsect.sct_x;
y = vsect.sct_y;
}
- if (attacker == targ_ship) {
- shots = -1; /* convert to max later */
- if (fship.shp_own != player->cnum) {
- pr("Not your ship!\n");
- continue;
- }
+
+ trange = mapdist(x, y, fx, fy);
+
+ if (type == EF_SHIP) {
+ if (!check_ship_ok(&fship))
+ return RET_FAIL;
if (target == targ_sub || target == targ_ship) {
if (fship.shp_uid == vship.shp_uid) {
pr("You can't fire upon yourself!\n");
continue;
}
}
- fx = fship.shp_x;
- fy = fship.shp_y;
-/*
- attacker = (mchr[fship.shp_type].m_flags & M_SUB) ?
- targ_sub : targ_ship;
- if (attacker == targ_sub){
- pr("Subs may not fire normally.. use torpedo.\n");
- continue;
- }
-*/
- attacker = targ_ship;
- if ((mil = fship.shp_item[I_MILIT]) < 1) {
- pr("Not enough military for firing crew.\n");
- continue;
- }
- gun = fship.shp_item[I_GUN];
- gun = min(gun, fship.shp_glim);
- if (fship.shp_frnge == 0 || gun == 0) {
- pr("Insufficient arms.\n");
- continue;
- }
- shell = fship.shp_item[I_SHELL];
- if (shell < 2)
- shell += supply_commod(fship.shp_own, fship.shp_x,
- fship.shp_y, I_SHELL, 2 - shell);
- if (shell <= 0) {
- pr("Klick! ...\n");
- continue;
- }
- if (fship.shp_effic < 60) {
- pr("Ship #%d is crippled (%d%%)\n", fshipno,
- fship.shp_effic);
- continue;
- }
- range = techfact(fship.shp_tech,
- (double)fship.shp_frnge / 2.0);
- range2 = (double)roundrange(range);
- pr("range is %.2f (%.2f)\n", range2, range);
- if (target == targ_sub) {
- if ((mchr[(int)fship.shp_type].m_flags & M_DCH) == 0) {
- pr("A %s can't drop depth charges!\n",
- mchr[(int)fship.shp_type].m_name);
- continue;
- }
- if (shell < 2) {
- pr("Not enough shells for depth charge!\n");
+ range = shp_fire_range(&fship);
+ range2 = roundrange(range);
+ pr("range is %d.00 (%.2f)\n", range2, range);
+ if (target == targ_sub
+ && trange <= range2
+ && (mchr[(int)fship.shp_type].m_flags & M_DCH)) {
+ dam = shp_dchrg(&fship);
+ } else {
+ if (target == targ_sub)
+ /* Don't tell it's a sub */
+ range2 = -1;
+ if (fship.shp_item[I_GUN] == 0) {
+ pr("Insufficient arms.\n");
continue;
}
+ dam = shp_fire(&fship);
}
- gun = min(gun, shell * 2);
- gun = min(gun, mil / 2);
- gun = max(gun, 1);
- if (shots > gun || shots < 0)
- shots = gun;
- else if (shots == 0) {
- pr("No shots fired.\n");
- continue;
- }
- guneff = seagun(fship.shp_effic, shots);
- dam = (int)guneff;
- shell -= ldround(((double)shots) / 2.0, 1);
- fship.shp_item[I_SHELL] = shell;
- if (opt_NOMOBCOST == 0)
- fship.shp_mobil = max(fship.shp_mobil - 15, -100);
putship(fship.shp_uid, &fship);
- } else if (attacker == targ_unit) {
- if (fland.lnd_own != player->cnum) {
- pr("Not your unit!\n");
+ if (CANT_HAPPEN(dam < 0)) {
+ pr("Klick! ...\n");
continue;
}
-
+ if (opt_NOMOBCOST == 0) {
+ fship.shp_mobil = MAX(fship.shp_mobil - 15, -100);
+ putship(fship.shp_uid, &fship);
+ }
+ } else if (type == EF_LAND) {
+ if (!check_land_ok(&fland))
+ return RET_FAIL;
if (target == targ_land) {
if (fland.lnd_x == vsect.sct_x
&& fland.lnd_y == vsect.sct_y) {
}
}
- fx = fland.lnd_x;
- fy = fland.lnd_y;
-
- if (fland.lnd_frg == 0) {
- pr("Unit %d cannot fire!\n", fland.lnd_uid);
- continue;
- }
- if (fland.lnd_item[I_SHELL] == 0) {
- pr("%s -- not enough shells\n", prland(&fland));
- continue;
- }
-
- shell = fland.lnd_item[I_SHELL];
-
- range = techfact((int)fland.lnd_tech,
- (double)fland.lnd_frg / 2.0);
- range2 = (double)roundrange(range);
- pr("range is %.2f (%.2f)\n", range2, range);
+ range = lnd_fire_range(&fland);
+ range2 = roundrange(range);
+ pr("range is %d.00 (%.2f)\n", range2, range);
if (target == targ_sub) {
- pr("A %s can't drop depth charges!\n",
- lchr[(int)fland.lnd_type].l_name);
- continue;
+ /* Don't tell it's a sub */
+ range2 = -1;
}
- gun = fland.lnd_item[I_GUN];
- if (gun <= 0) {
- pr("%s -- not enough guns\n", prland(&fland));
+ dam = lnd_fire(&fland);
+ putland(fland.lnd_uid, &fland);
+ if (CANT_HAPPEN(dam < 0)) {
+ pr("Klick! ...\n");
continue;
}
-
- dam = (int)landunitgun(fland.lnd_effic, fland.lnd_dam, gun,
- fland.lnd_ammo, shell);
if (target == targ_ship) {
- if (chance(((double)fland.lnd_acc) / 100.0))
- dam = ldround(((double)dam / 2.0), 1);
+ if (chance(lnd_acc(&fland) / 100.0))
+ dam = ldround(dam / 2.0, 1);
}
- use_supply(&fland);
- resupply_commod(&fland, I_SHELL); /* Get more shells */
- putland(fland.lnd_uid, &fland);
} else {
- fx = fsect.sct_x;
- fy = fsect.sct_y;
- if (fsect.sct_own != player->cnum ||
- fsect.sct_type != SCT_FORTR) {
- pr("No fortress at %s\n", xyas(fsect.sct_x,
- fsect.sct_y, player->cnum));
- continue;
- }
+ if (!check_sect_ok(&fsect))
+ return RET_FAIL;
if (target == targ_land) {
if (fsect.sct_x == vsect.sct_x
&& fsect.sct_y == vsect.sct_y) {
continue;
}
}
- attacker = targ_land;
- if ((gun = fsect.sct_item[I_GUN]) == 0) {
- pr("Insufficient arms.\n");
- continue;
- }
- shell = fsect.sct_item[I_SHELL];
- if (shell <= 0)
- shell += supply_commod(fsect.sct_own, fsect.sct_x,
- fsect.sct_y, I_SHELL, 1);
- if (shell <= 0) {
+ dam = fort_fire(&fsect);
+ putsect(&fsect);
+ if (CANT_HAPPEN(dam < 0)) {
pr("Klick! ...\n");
continue;
}
- if (fsect.sct_item[I_MILIT] < 5) {
- pr("Not enough military for firing crew.\n");
- continue;
- }
+ range = fortrange(&fsect);
+ range2 = roundrange(range);
+ pr("range is %d.00 (%.2f)\n", range2, range);
if (target == targ_sub) {
- pr("Target ship not sighted!\n");
- continue;
+ /* Don't tell it's a sub */
+ range2 = -1;
}
- if (gun > 7)
- gun = 7;
- range = tfactfire(player->cnum, 7.0);
- if (fsect.sct_effic > 59)
- range++;
- range2 = (double)roundrange(range);
- pr("range is %.2f (%.2f)\n", range2, range);
- guneff = landgun((int)fsect.sct_effic, gun);
- dam = (int)guneff;
- shell--;
- fsect.sct_item[I_SHELL] = shell;
- putsect(&fsect);
}
- trange = mapdist(x, y, fx, fy);
if (trange > range2) {
pr("Target out of range.\n");
-/*
- switch (target) {
- case targ_land:
- case targ_bogus:
- pr("Target out of range. Thud.\n");
- break ;
- default:
- pr("Target ship out of range. Splash.\n");
- break ;
- }
- */
- switch (attacker) {
- case targ_land:
+ switch (type) {
+ case EF_SECTOR:
putsect(&fsect);
break;
- case targ_unit:
+ case EF_LAND:
fland.lnd_mission = 0;
putland(fland.lnd_uid, &fland);
break;
- default:
+ case EF_SHIP:
fship.shp_mission = 0;
putship(fship.shp_uid, &fship);
+ break;
+ default:
+ CANT_REACH();
}
continue;
}
-/*
- if (target == targ_bogus) {
- if (vsect.sct_type == SCT_SANCT) {
- pr("%s is a %s!!\n", vbuf,
- dchr[SCT_SANCT].d_name);
- continue;
- } else if (vsect.sct_type == SCT_WATER) {
- pr("You must specify a ship in sector %s!\n",
- vbuf);
- continue;
- }
- }
-*/
- switch (target) {
- case targ_ship:
- if (!trechk(player->cnum, vict, SEAFIR))
- continue;
- break;
- case targ_sub:
- if (!trechk(player->cnum, vict, SUBFIR))
- continue;
- break;
- case targ_unit:
- case targ_land:
- if (!trechk(player->cnum, vict, LANFIR))
- continue;
- break;
- default:
- break;
- }
- if (opt_SLOW_WAR) {
- if (target == targ_land) {
- natp = getnatp(player->cnum);
- rel = getrel(natp, vict);
- if ((rel != AT_WAR) && (player->cnum != vict) &&
- (vict) && (vsect.sct_oldown != player->cnum)) {
- pr("You're not at war with them!\n");
- continue;
- }
- }
- }
nfiring++;
switch (target) {
case targ_sub:
pr_beep();
pr("Kawhomp!!!\n");
- if (vship.shp_rflags & RET_DCHRGED)
- retreat_ship(&vship, 'd');
break;
default:
pr_beep();
pr("Kaboom!!!\n");
- prb = (double)(range2 ? (trange / range2) : 1.0);
- prb *= prb;
-#if !defined(_WIN32)
- srandom(random());
-#else
- (void)time(&now);
- (void)srand(now);
-#endif
- if (chance(prb)) {
- pr("Wind deflects shell%s.\n", splur(shots));
-/* dam = (int)((double)dam / 2.0);*/
- dam =
- (int)((double)dam *
- (double)((double)(90 - (random() % 11)) /
- 100.0));
- if (dam < 0)
- dam = 0;
- }
break;
}
switch (target) {
wu(0, vict,
"Country #%d shelled sector %s for %d damage.\n",
player->cnum, xyas(x, y, vict), dam);
- pr("Shell%s hit sector %s for %d damage.\n",
- splur(shots), xyas(x, y, player->cnum), dam);
- /* Ok, it wasn't a bogus target, so do damage. */
- if (target != targ_bogus)
- sectdamage(&vsect, dam, 0);
+ pr("Shells hit sector %s for %d damage.\n",
+ xyas(x, y, player->cnum), dam);
break;
case targ_ship:
nreport(player->cnum, N_SHP_SHELL, vict, 1);
/* fall through */
default:
- if ((target != targ_sub) ||
- ((vship.shp_rflags & RET_DCHRGED) == 0))
- check_retreat_and_do_shipdamage(&vship, dam);
- else
- shipdamage(&vship, dam);
- if (vict) {
+ if (vict && vict != player->cnum) {
wu(0, vict,
"Country #%d shelled %s in %s for %d damage.\n",
player->cnum, prship(&vship),
xyas(vship.shp_x, vship.shp_y, vict), dam);
}
- pr("Shell%s hit %s in %s for %d damage.\n",
- splur(shots), prsub(&vship),
+ pr("Shells hit %s in %s for %d damage.\n",
+ prsub(&vship),
xyas(vship.shp_x, vship.shp_y, player->cnum), dam);
-
- if (vship.shp_effic < SHIP_MINEFF)
- pr("%s sunk!\n", prsub(&vship));
-
break;
}
/* Ok, now, check if we had a bogus target. If so,
just continue on, since there is no defender. */
if (target == targ_bogus)
continue;
- if (attacker == targ_unit) {
- attacker = targ_land;
+ attgp = &item.gen;
+ if (type == EF_LAND) {
getsect(fland.lnd_x, fland.lnd_y, &fsect);
+ attgp = (struct empobj *)&fsect;
}
- totaldefdam =
- defend(&fired, &defended, target, attacker, &vsect, &fsect,
- &vship, &fship, fx, fy, &ndefending);
+ totaldefdam = defend(&fired, &defended, attgp, vict, &ndefending);
switch (target) {
case targ_land:
+ getsect(x, y, &vsect);
+ sectdamage(&vsect, dam);
putsect(&vsect);
break;
default:
+ getship(vshipno, &vship);
+ check_retreat_and_do_shipdamage(&vship, dam);
+ if (vship.shp_effic < SHIP_MINEFF)
+ pr("%s sunk!\n", prsub(&vship));
+ else if (target == targ_sub
+ && (vship.shp_rflags & RET_DCHRGED)
+ && !(vship.shp_rflags & RET_INJURED))
+ retreat_ship(&vship, 'd');
+ else if (totaldefdam == 0
+ && (vship.shp_rflags & RET_HELPLESS)
+ && !(vship.shp_rflags & RET_INJURED))
+ retreat_ship(&vship, 'h');
putship(vship.shp_uid, &vship);
break;
}
- if ((totaldefdam == 0) && (target == targ_ship))
- if (vship.shp_rflags & RET_INJURED)
- retreat_ship(&vship, 'h');
- switch (attacker) {
- case targ_land:
+ switch (attgp->ef_type) {
+ case EF_SECTOR:
putsect(&fsect);
break;
- default:
+ case EF_SHIP:
if ((target == targ_ship) || (target == targ_sub)) {
if (fship.shp_effic > SHIP_MINEFF) {
shp_missdef(&fship, vict);
};
putship(fship.shp_uid, &fship);
break;
+ default:
+ CANT_REACH();
}
}
- use_ammo(&defended);
+ free_flist(&defended);
if (nfiring)
odds = ((double)ndefending) / ((double)nfiring);
else
}
static int
-defend(struct emp_qelem *al, struct emp_qelem *dl, enum targ_type target,
- enum targ_type attacker, struct sctstr *vsect, struct sctstr *fsect,
- struct shpstr *vship, struct shpstr *fship, int fx, int fy, int *nd)
+defend(struct emp_qelem *al, struct emp_qelem *dl,
+ struct empobj *attgp, natid vict, int *nd)
{
-
int dam;
- int vict, nfiring = 0;
- struct flist *fp;
- int aown;
-
- if (attacker == targ_land)
- aown = fsect->sct_own;
- else
- aown = fship->shp_own;
-
- if (target == targ_land)
- vict = vsect->sct_own;
- else
- vict = vship->shp_own;
+ int nfiring = 0;
- if (0 !=
- (dam = quiet_bigdef(attacker, dl, vict, aown, fx, fy, &nfiring))) {
+ dam = quiet_bigdef(attgp->ef_type, dl, vict,
+ attgp->own, attgp->x, attgp->y, &nfiring);
+ if (dam) {
if (nfiring > *nd)
*nd = nfiring;
- fp = (struct flist *)malloc(sizeof(struct flist));
- memset(fp, 0, sizeof(struct flist));
- fp->defdam = dam;
- fp->victim = vict;
- switch (attacker) {
- case targ_land:
- fp->x = fsect->sct_x;
- fp->y = fsect->sct_y;
- fp->type = targ_land;
- break;
- default:
- fp->type = targ_ship;
- fp->uid = fship->shp_uid;
- break;
- }
- emp_insque(&fp->queue, al);
+ add_to_flist(al, attgp, dam, vict);
}
- return (dam);
+ return dam;
}
static void
do_defdam(struct emp_qelem *list, double odds)
{
- int dam, vict, first = 1;
+ int dam, first = 1;
+ natid vict;
struct flist *fp;
struct shpstr ship;
struct sctstr sect;
for (qp = list->q_forw; qp != list; qp = next) {
next = qp->q_forw;
fp = (struct flist *)qp;
- if (fp->type == targ_ship) {
+ if (fp->type == EF_SHIP) {
if (!getship(fp->uid, &ship) || !ship.shp_own)
continue;
}
pr("\nDefenders fire back!\n");
first = 0;
}
- dam = (odds * (double)fp->defdam);
+ dam = odds * fp->defdam;
- if (fp->type == targ_ship) {
+ if (fp->type == EF_SHIP) {
vict = fp->victim;
pr("Return fire hit %s in %s for %d damage.\n",
prship(&ship),
shipdamage(&ship, dam);
putship(ship.shp_uid, &ship);
} else {
+ CANT_HAPPEN(fp->type != EF_SECTOR);
getsect(fp->x, fp->y, §);
vict = fp->victim;
pr("Return fire hit sector %s for %d damage.\n",
xyas(fp->x, fp->y, player->cnum), dam);
- sectdamage(§, dam, 0);
+ sectdamage(§, dam);
putsect(§);
if (vict)
wu(0, vict, "Return fire hit sector %s for %d damage.\n",
xyas(fp->x, fp->y, vict), dam);
}
emp_remque(&fp->queue);
- free((s_char *)fp);
+ free(fp);
}
}
static int
-quiet_bigdef(int attacker, struct emp_qelem *list, natid own, natid aown,
+quiet_bigdef(int type, struct emp_qelem *list, natid own, natid aown,
coord ax, coord ay, int *nfiring)
{
- int nshot;
- double range, erange, hitchance;
+ double erange;
struct shpstr ship;
struct lndstr land;
struct nstr_item ni;
- int dam, dam2, rel, rel2;
- double tech;
+ int dam, dam2;
struct sctstr firing;
struct nstr_sect ns;
struct flist *fp;
- int gun, shell;
if (own == 0)
return 0;
dam = 0;
snxtitem_dist(&ni, EF_SHIP, ax, ay, 8);
- while (nxtitem(&ni, (caddr_t)&ship)) {
- if (ship.shp_own == 0)
+ while (nxtitem(&ni, &ship)) {
+ if (!feels_like_helping(ship.shp_own, own, aown))
continue;
- if ((mchr[(int)ship.shp_type].m_flags & M_SUB) &&
- (attacker == targ_land))
- continue;
-
- rel = getrel(getnatp(ship.shp_own), own);
- rel2 = getrel(getnatp(ship.shp_own), aown);
- if ((ship.shp_own != own) && ((rel != ALLIED) || (rel2 != AT_WAR)))
- continue;
- /* Don't shoot yourself */
- if (ship.shp_own == aown)
- continue;
- if (ship.shp_effic < 60)
- continue;
-
- gun = ship.shp_item[I_GUN];
- shell = ship.shp_item[I_SHELL];
-
- if (ship.shp_item[I_MILIT] < 1)
+ if ((mchr[ship.shp_type].m_flags & M_SUB) && type != EF_SHIP)
continue;
if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
- if (shell < SHP_TORP_SHELLS)
- shell += supply_commod(ship.shp_own, ship.shp_x, ship.shp_y,
- I_SHELL, SHP_TORP_SHELLS - shell);
- if (shell < SHP_TORP_SHELLS)
+ erange = torprange(&ship);
+ if (roundrange(erange) < ni.curdist)
continue;
- if (gun < 1)
+ if (!line_of_sight(NULL, ship.shp_x, ship.shp_y, ax, ay))
continue;
-/*
- if (ship.shp_mobil <= 0)
- continue;
-*/
- erange = ship.shp_effic *
- techfact(ship.shp_tech, ((double)ship.shp_frnge))
- / 100.0;
- erange = (double)roundrange(erange);
- range = mapdist(ship.shp_x, ship.shp_y, ax, ay);
- if (range > erange)
- continue;
- if (!line_of_sight((s_char **)0, ship.shp_x, ship.shp_y, ax, ay))
- continue;
-
- (*nfiring)++;
- fp = (struct flist *)malloc(sizeof(struct flist));
- memset(fp, 0, sizeof(struct flist));
- fp->type = targ_ship;
- fp->uid = ship.shp_uid;
- add_to_fired_queue(&fp->queue, list);
-/*
- nreport(ship.shp_own, N_FIRE_BACK, player->cnum, 1);
-*/
- hitchance = DTORP_HITCHANCE(range, ship.shp_visib);
- if (!chance(hitchance))
+ fp = search_flist(list, (struct empobj *)&ship);
+ if (fp)
+ dam2 = fp->defdam;
+ else {
+ dam2 = shp_torp(&ship, 0);
+ putship(ship.shp_uid, &ship);
+ }
+ if (dam2 < 0)
continue;
-
- dam += TORP_DAMAGE();
+ if (!chance(shp_torp_hitchance(&ship, ni.curdist)))
+ dam2 = 0;
} else {
- range = techfact(ship.shp_tech,
- ship.shp_frnge * ship.shp_effic / 200.0);
- range = (double)roundrange(range);
- if (range < ni.curdist)
- continue;
- /* must have gun, shell, and milit to fire */
- if (shell < 1)
- shell += supply_commod(ship.shp_own, ship.shp_x, ship.shp_y,
- I_SHELL, 1);
- /* only need 1 shell, so don't check that */
- if (shell < 1)
- continue;
- nshot = min(gun, ship.shp_item[I_MILIT]);
- nshot = min(nshot, ship.shp_glim);
- if (nshot == 0)
+ erange = shp_fire_range(&ship);
+ if (roundrange(erange) < ni.curdist)
+ continue;
+ fp = search_flist(list, (struct empobj *)&ship);
+ if (fp)
+ dam2 = fp->defdam;
+ else {
+ dam2 = shp_fire(&ship);
+ putship(ship.shp_uid, &ship);
+ }
+ if (dam2 < 0)
continue;
- (*nfiring)++;
- fp = (struct flist *)malloc(sizeof(struct flist));
- memset(fp, 0, sizeof(struct flist));
- fp->type = targ_ship;
- fp->uid = ship.shp_uid;
- add_to_fired_queue(&fp->queue, list);
nreport(ship.shp_own, N_FIRE_BACK, player->cnum, 1);
- dam += seagun(ship.shp_effic, nshot);
}
+ (*nfiring)++;
+ if (!fp)
+ add_to_flist(list, (struct empobj *)&ship, dam2, 0);
+ dam += dam2;
}
snxtitem_dist(&ni, EF_LAND, ax, ay, 8);
- while (nxtitem(&ni, (caddr_t)&land)) {
- if (land.lnd_own == 0)
- continue;
- if (land.lnd_effic < LAND_MINFIREEFF)
- continue;
- /* Can't fire if on a ship */
- if (land.lnd_ship >= 0)
- continue;
- if (land.lnd_land >= 0)
- continue;
- /* Gotta have military */
- if (lnd_getmil(&land) < 1)
- continue;
- /* Don't shoot yourself */
- if (land.lnd_own == aown)
- continue;
-
- rel = getrel(getnatp(land.lnd_own), own);
- rel2 = getrel(getnatp(land.lnd_own), aown);
-
- if ((land.lnd_own != own) && ((rel != ALLIED) || (rel2 != AT_WAR)))
+ while (nxtitem(&ni, &land)) {
+ if (!feels_like_helping(land.lnd_own, own, aown))
continue;
-
- range = techfact((int)land.lnd_tech, (double)land.lnd_frg / 2.0);
- range = (double)roundrange(range);
- if (range < ni.curdist)
- continue;
-
- resupply_all(&land);
- if (!has_supply(&land))
+ erange = lnd_fire_range(&land);
+ if (roundrange(erange) < ni.curdist)
continue;
- gun = land.lnd_item[I_GUN];
- shell = land.lnd_item[I_SHELL];
-
- if (land.lnd_item[I_MILIT] == 0 || shell == 0 || gun == 0)
+ fp = search_flist(list, (struct empobj *)&land);
+ if (fp)
+ dam2 = fp->defdam;
+ else {
+ dam2 = lnd_fire(&land);
+ putland(land.lnd_uid, &land);
+ }
+ if (dam2 < 0)
continue;
- dam2 = (int)landunitgun(land.lnd_effic, land.lnd_dam, gun,
- land.lnd_ammo, shell);
-
(*nfiring)++;
- fp = (struct flist *)malloc(sizeof(struct flist));
- memset(fp, 0, sizeof(struct flist));
- fp->type = targ_unit;
- fp->uid = land.lnd_uid;
- add_to_fired_queue(&fp->queue, list);
- use_supply(&land);
- putland(land.lnd_uid, &land);
+ if (!fp)
+ add_to_flist(list, (struct empobj *)&land, dam2, 0);
nreport(land.lnd_own, N_FIRE_BACK, player->cnum, 1);
+ if (type == EF_SHIP) {
+ if (chance(lnd_acc(&land) / 100.0))
+ dam2 = ldround(dam2 / 2.0, 1);
+ }
dam += dam2;
}
if (!opt_NO_FORT_FIRE) {
snxtsct_dist(&ns, ax, ay, 8);
while (nxtsct(&ns, &firing)) {
-
- if (firing.sct_type != SCT_FORTR)
+ if (!feels_like_helping(firing.sct_own, own, aown))
continue;
- if (firing.sct_own == 0)
- continue;
- rel = getrel(getnatp(firing.sct_own), own);
- rel2 = getrel(getnatp(firing.sct_own), aown);
- if ((firing.sct_own != own) &&
- ((rel != ALLIED) || (rel2 != AT_WAR)))
- continue;
- /* Don't shoot yourself */
- if (firing.sct_own == aown)
+ erange = fortrange(&firing);
+ if (roundrange(erange) < ns.curdist)
continue;
- tech = tfactfire(firing.sct_own, 1.0);
- range = tech * 7.0;
- if (firing.sct_effic > 59) /* fort bonus */
- range++;
- range = (double)roundrange(range);
- if (range < ns.curdist)
- continue;
-
- gun = firing.sct_item[I_GUN];
- shell = firing.sct_item[I_SHELL];
- if (shell < 1)
- shell += supply_commod(firing.sct_own,
- firing.sct_x, firing.sct_y,
- I_SHELL, 1);
- if (gun == 0 || firing.sct_item[I_MILIT] < 5 || shell == 0)
+ fp = search_flist(list, (struct empobj *)&firing);
+ if (fp)
+ dam2 = fp->defdam;
+ else {
+ dam2 = fort_fire(&firing);
+ putsect(&firing);
+ }
+ if (dam2 < 0)
continue;
(*nfiring)++;
- fp = (struct flist *)malloc(sizeof(struct flist));
- memset(fp, 0, sizeof(struct flist));
- fp->x = firing.sct_x;
- fp->y = firing.sct_y;
- fp->type = targ_land;
- add_to_fired_queue(&fp->queue, list);
+ if (!fp)
+ add_to_flist(list, (struct empobj *)&firing, dam2, 0);
nreport(firing.sct_own, N_FIRE_BACK, player->cnum, 1);
- if (gun > 7)
- gun = 7;
- dam += landgun((int)firing.sct_effic, gun);
+ dam += dam2;
}
}
- return ((*nfiring) == 0 ? 0 : (dam / (*nfiring)));
+ return *nfiring == 0 ? 0 : dam / *nfiring;
}
static void
-use_ammo(struct emp_qelem *list)
+add_to_flist(struct emp_qelem *list,
+ struct empobj *gp, int dam, natid victim)
+{
+ struct flist *fp;
+
+ fp = malloc(sizeof(struct flist));
+ fp->type = gp->ef_type;
+ fp->uid = gp->uid;
+ fp->x = gp->x;
+ fp->y = gp->y;
+ fp->defdam = dam;
+ fp->victim = victim;
+ emp_insque(&fp->queue, list);
+}
+
+static void
+free_flist(struct emp_qelem *list)
{
struct emp_qelem *qp, *next;
struct flist *fp;
- struct shpstr ship;
- struct lndstr land;
- struct sctstr sect;
- int shell;
- short *item;
- double mobcost;
- struct mchrstr *mcp;
- /* use 1 shell from everyone */
for (qp = list->q_forw; qp != list; qp = next) {
next = qp->q_forw;
fp = (struct flist *)qp;
- if (fp->type == targ_ship) {
- getship(fp->uid, &ship);
- item = ship.shp_item;
- if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
- shell = item[I_SHELL];
- shell -= SHP_TORP_SHELLS - 1;
- if (shell < 0)
- shell = 0;
- item[I_SHELL] = shell;
- putship(ship.shp_uid, &ship);
- mcp = &mchr[(int)ship.shp_type];
- mobcost = ship.shp_effic * 0.01 * ship.shp_speed;
- mobcost = (480.0 / (mobcost +
- techfact(ship.shp_tech, mobcost)));
- /* mob cost = 1/2 a sect's mob */
- mobcost /= 2.0;
- ship.shp_mobil -= mobcost;
- }
- } else if (fp->type == targ_land) {
- getsect(fp->x, fp->y, §);
- item = sect.sct_item;
- } else {
- getland(fp->uid, &land);
- item = land.lnd_item;
- }
- shell = item[I_SHELL];
- shell--;
- if (shell < 0)
- shell = 0;
- item[I_SHELL] = shell;
- if (fp->type == targ_ship)
- putship(ship.shp_uid, &ship);
- else if (fp->type == targ_land)
- putsect(§);
- else
- putland(land.lnd_uid, &land);
-
emp_remque(&fp->queue);
- free((s_char *)fp);
+ free(fp);
}
-
}
-static void
-add_to_fired_queue(struct emp_qelem *elem, struct emp_qelem *list)
+static int
+uid_eq(struct emp_qelem *elem, void *key)
{
- struct emp_qelem *qp;
- struct flist *fp, *ep;
- int bad = 0;
-
- ep = (struct flist *)elem;
-
- /* Don't put them on the list if they're already there */
- for (qp = list->q_forw; qp != list; qp = qp->q_forw) {
- fp = (struct flist *)qp;
- if ((fp->type == targ_ship) && (fp->uid == ep->uid))
- bad = 1;
- if ((fp->type != targ_ship) && (fp->x == ep->x) &&
- (fp->y == ep->y))
- bad = 1;
- }
+ return ((struct flist *)elem)->uid == ((struct empobj *)key)->uid;
+}
- if (!bad)
- emp_insque(elem, list);
+static struct flist *
+search_flist(struct emp_qelem *list, struct empobj *gp)
+{
+ return (struct flist *)emp_searchque(list, gp, uid_eq);
}