Fix return fire ammunition use in fire command

The old code let each defender fire on each target separately.  To
avoid charging ammo multiple times, it didn't update the defenders
after fire; it charged them in use_ammo() instead.  Bugs: not updating
the defender lost any shells fetched by automatic resupply, and
use_ammo() always charged one shell for gun fire, which was wrong for
most ships and land units.

Rewrite to let each defender fire once, updating it normally.  Reuse
the damage for the other targets.  This also yields the proper
probability distribution for damage.
This commit is contained in:
Markus Armbruster 2008-03-14 20:00:48 +01:00
parent 942eddf533
commit f89edc7ae6

View file

@ -45,19 +45,20 @@ enum targ_type {
struct flist { struct flist {
struct emp_qelem queue; /* list of fired things */ struct emp_qelem queue; /* list of fired things */
short type; /* EF_SECTOR, EF_SHIP or EF_LAND */ short type; /* EF_SECTOR, EF_SHIP or EF_LAND */
short uid; /* ship or land unit uid */ short uid;
coord x, y; /* sector coords */ coord x, y;
int defdam; /* damage defenders did */ int defdam; /* damage defenders did */
natid victim; natid victim;
}; };
static void add_to_fired_queue(struct emp_qelem *, struct emp_qelem *);
static int defend(struct emp_qelem *, struct emp_qelem *, static int defend(struct emp_qelem *, struct emp_qelem *,
struct empobj *, natid, int *); struct empobj *, natid, int *);
static void do_defdam(struct emp_qelem *, double); static void do_defdam(struct emp_qelem *, double);
static int quiet_bigdef(int, struct emp_qelem *, natid, natid, coord, static int quiet_bigdef(int, struct emp_qelem *, natid, natid, coord,
coord, int *); 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 int
multifire(void) multifire(void)
@ -578,7 +579,7 @@ multifire(void)
} }
} }
use_ammo(&defended); free_flist(&defended);
if (nfiring) if (nfiring)
odds = ((double)ndefending) / ((double)nfiring); odds = ((double)ndefending) / ((double)nfiring);
else else
@ -591,25 +592,15 @@ static int
defend(struct emp_qelem *al, struct emp_qelem *dl, defend(struct emp_qelem *al, struct emp_qelem *dl,
struct empobj *attgp, natid vict, int *nd) struct empobj *attgp, natid vict, int *nd)
{ {
int dam; int dam;
int nfiring = 0; int nfiring = 0;
struct flist *fp;
dam = quiet_bigdef(attgp->ef_type, dl, vict, dam = quiet_bigdef(attgp->ef_type, dl, vict,
attgp->own, attgp->x, attgp->y, &nfiring); attgp->own, attgp->x, attgp->y, &nfiring);
if (dam) { if (dam) {
if (nfiring > *nd) if (nfiring > *nd)
*nd = nfiring; *nd = nfiring;
fp = malloc(sizeof(struct flist)); add_to_flist(al, attgp, dam, vict);
memset(fp, 0, sizeof(struct flist));
fp->defdam = dam;
fp->victim = vict;
fp->type = attgp->ef_type;
fp->uid = attgp->uid;
fp->x = attgp->x;
fp->y = attgp->y;
emp_insque(&fp->queue, al);
} }
return dam; return dam;
@ -705,8 +696,13 @@ quiet_bigdef(int type, struct emp_qelem *list, natid own, natid aown,
continue; continue;
if (!line_of_sight(NULL, ship.shp_x, ship.shp_y, ax, ay)) if (!line_of_sight(NULL, ship.shp_x, ship.shp_y, ax, ay))
continue; continue;
dam2 = shp_torp(&ship, 0); fp = search_flist(list, (struct empobj *)&ship);
/* no putship(&ship) because ammo is charged in use_ammo() */ if (fp)
dam2 = fp->defdam;
else {
dam2 = shp_torp(&ship, 0);
putship(ship.shp_uid, &ship);
}
if (dam2 < 0) if (dam2 < 0)
continue; continue;
if (!chance(shp_torp_hitchance(&ship, ni.curdist))) if (!chance(shp_torp_hitchance(&ship, ni.curdist)))
@ -715,18 +711,20 @@ quiet_bigdef(int type, struct emp_qelem *list, natid own, natid aown,
erange = shp_fire_range(&ship); erange = shp_fire_range(&ship);
if (roundrange(erange) < ni.curdist) if (roundrange(erange) < ni.curdist)
continue; continue;
dam2 = shp_fire(&ship); fp = search_flist(list, (struct empobj *)&ship);
/* no putship(&ship) because ammo is charged in use_ammo() */ if (fp)
dam2 = fp->defdam;
else {
dam2 = shp_fire(&ship);
putship(ship.shp_uid, &ship);
}
if (dam2 < 0) if (dam2 < 0)
continue; continue;
nreport(ship.shp_own, N_FIRE_BACK, player->cnum, 1); nreport(ship.shp_own, N_FIRE_BACK, player->cnum, 1);
} }
(*nfiring)++; (*nfiring)++;
fp = malloc(sizeof(struct flist)); if (!fp)
memset(fp, 0, sizeof(struct flist)); add_to_flist(list, (struct empobj *)&ship, dam2, 0);
fp->type = EF_SHIP;
fp->uid = ship.shp_uid;
add_to_fired_queue(&fp->queue, list);
dam += dam2; dam += dam2;
} }
snxtitem_dist(&ni, EF_LAND, ax, ay, 8); snxtitem_dist(&ni, EF_LAND, ax, ay, 8);
@ -747,17 +745,19 @@ quiet_bigdef(int type, struct emp_qelem *list, natid own, natid aown,
if (roundrange(erange) < ni.curdist) if (roundrange(erange) < ni.curdist)
continue; continue;
dam2 = lnd_fire(&land); fp = search_flist(list, (struct empobj *)&land);
/* no putland(&land) because ammo is charged in use_ammo() */ if (fp)
dam2 = fp->defdam;
else {
dam2 = lnd_fire(&land);
putland(land.lnd_uid, &land);
}
if (dam2 < 0) if (dam2 < 0)
continue; continue;
(*nfiring)++; (*nfiring)++;
fp = malloc(sizeof(struct flist)); if (!fp)
memset(fp, 0, sizeof(struct flist)); add_to_flist(list, (struct empobj *)&land, dam2, 0);
fp->type = EF_LAND;
fp->uid = land.lnd_uid;
add_to_fired_queue(&fp->queue, list);
nreport(land.lnd_own, N_FIRE_BACK, player->cnum, 1); nreport(land.lnd_own, N_FIRE_BACK, player->cnum, 1);
dam += dam2; dam += dam2;
} }
@ -787,17 +787,18 @@ quiet_bigdef(int type, struct emp_qelem *list, natid own, natid aown,
if (roundrange(erange) < ns.curdist) if (roundrange(erange) < ns.curdist)
continue; continue;
dam2 = fort_fire(&firing); fp = search_flist(list, (struct empobj *)&firing);
/* no putsect(&firing) because ammo is charged in use_ammo() */ if (fp)
dam2 = fp->defdam;
else {
dam2 = fort_fire(&firing);
putsect(&firing);
}
if (dam2 < 0) if (dam2 < 0)
continue; continue;
(*nfiring)++; (*nfiring)++;
fp = malloc(sizeof(struct flist)); if (!fp)
memset(fp, 0, sizeof(struct flist)); add_to_flist(list, (struct empobj *)&firing, dam2, 0);
fp->x = firing.sct_x;
fp->y = firing.sct_y;
fp->type = EF_SECTOR;
add_to_fired_queue(&fp->queue, list);
nreport(firing.sct_own, N_FIRE_BACK, player->cnum, 1); nreport(firing.sct_own, N_FIRE_BACK, player->cnum, 1);
dam += dam2; dam += dam2;
} }
@ -807,74 +808,43 @@ quiet_bigdef(int type, struct emp_qelem *list, natid own, natid aown,
} }
static void static void
use_ammo(struct emp_qelem *list) add_to_flist(struct emp_qelem *list,
struct empobj *gp, int dam, natid victim)
{ {
struct emp_qelem *qp, *next;
struct flist *fp; struct flist *fp;
struct shpstr ship;
struct lndstr land;
struct sctstr sect;
int shell;
short *item;
/* 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 == EF_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);
/* mob cost = 1/2 a sect's mob */
ship.shp_mobil -= shp_mobcost(&ship) / 2.0;
}
} else if (fp->type == EF_SECTOR) {
getsect(fp->x, fp->y, &sect);
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 == EF_SHIP)
putship(ship.shp_uid, &ship);
else if (fp->type == EF_SECTOR)
putsect(&sect);
else
putland(land.lnd_uid, &land);
emp_remque(&fp->queue);
free(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 static void
add_to_fired_queue(struct emp_qelem *elem, struct emp_qelem *list) free_flist(struct emp_qelem *list)
{ {
struct emp_qelem *qp; struct emp_qelem *qp, *next;
struct flist *fp; struct flist *fp;
struct flist *ep = (struct flist *)elem;
/* Don't put them on the list if they're already there */ for (qp = list->q_forw; qp != list; qp = next) {
for (qp = list->q_forw; qp != list; qp = qp->q_forw) { next = qp->q_forw;
fp = (struct flist *)qp; fp = (struct flist *)qp;
if (fp->type == EF_SECTOR emp_remque(&fp->queue);
? fp->x == ep->x && fp->y == ep->y free(fp);
: fp->uid == ep->uid) {
free(ep);
return;
}
} }
emp_insque(elem, list); }
static int
uid_eq(struct emp_qelem *elem, void *key)
{
return ((struct flist *)elem)->uid == ((struct empobj *)key)->uid;
}
static struct flist *
search_flist(struct emp_qelem *list, struct empobj *gp)
{
return (struct flist *)emp_searchque(list, gp, uid_eq);
} }