Factor out common ship gun fire code into shp_fire()

This takes care of a number of bugs / inconsistencies:

* Ships with zero firing range could return fire and fire support, but
  not fire actively or interdict.  Fix by testing for gun limit
  instead in multifire() and mission().  No ships in the stock game
  are affected.

* Required gun crew was inconsistent: multifire() let N military fire
  max(1,floor(N/2)) guns for active fire.  Ditto perform_mission() for
  interdiction.  quiet_bigdef() let them fire N guns for returning gun
  fire.  Ditto sd() for firing support and firing at boarding parties.
  fire_dchrg() let them fire floor(N/2) for returning fire to
  torpedoes.  Unify to let N military fire floor((N+1)/2) guns.

* Shell use was inconsistent: sd() and perform_mission() used one
  shell per gun, everything else one per two guns.  Unify to one shell
  per two guns.

* Shell resupply bugs: multifire() got two shells regardless of actual
  ammo use.  quiet_bigdef() got one shell (but use_ammo() uses only
  one, which is a bug).  sd() and perform_mission() resupplied before
  checking all other requirements and could thus get more shells than
  actually needed.
This commit is contained in:
Markus Armbruster 2008-03-02 11:59:56 +01:00
parent a3ad623b2a
commit 22c6fd8bf6
7 changed files with 65 additions and 109 deletions

View file

@ -184,5 +184,6 @@ extern int m_frnge(struct mchrstr *, int);
extern int m_glim(struct mchrstr *, int); extern int m_glim(struct mchrstr *, int);
extern int shp_dchrg(struct shpstr *); extern int shp_dchrg(struct shpstr *);
extern int shp_fire(struct shpstr *);
#endif #endif

View file

@ -82,7 +82,6 @@ multifire(void)
int gun; int gun;
int shell; int shell;
int shots; int shots;
double guneff;
int dam; int dam;
int totaldefdam = 0; int totaldefdam = 0;
int fshipno; int fshipno;
@ -189,13 +188,11 @@ multifire(void)
pr("Not enough mil on ship #%d\n", item.ship.shp_uid); pr("Not enough mil on ship #%d\n", item.ship.shp_uid);
continue; continue;
} }
gun = item.ship.shp_item[I_GUN]; if (item.ship.shp_glim == 0) {
gun = MIN(gun, item.ship.shp_glim);
if (item.ship.shp_frnge == 0) {
pr("Ships %d cannot fire guns!\n", item.ship.shp_uid); pr("Ships %d cannot fire guns!\n", item.ship.shp_uid);
continue; continue;
} }
if (gun == 0) { if (item.ship.shp_item[I_GUN] == 0) {
pr("Not enough guns on ship #%d\n", item.ship.shp_uid); pr("Not enough guns on ship #%d\n", item.ship.shp_uid);
continue; continue;
} }
@ -328,29 +325,16 @@ multifire(void)
if (target == targ_sub) if (target == targ_sub)
/* Don't tell it's a sub */ /* Don't tell it's a sub */
range2 = -1; range2 = -1;
gun = fship.shp_item[I_GUN]; if (fship.shp_item[I_GUN] == 0) {
gun = MIN(gun, fship.shp_glim);
if (fship.shp_frnge == 0 || gun == 0) {
pr("Insufficient arms.\n"); pr("Insufficient arms.\n");
continue; continue;
} }
shell = fship.shp_item[I_SHELL]; dam = shp_fire(&fship);
shell += supply_commod(fship.shp_own, putship(fship.shp_uid, &fship);
fship.shp_x, fship.shp_y, if (dam <= 0) {
I_SHELL, 2 - shell);
if (shell <= 0) {
pr("Klick! ...\n"); pr("Klick! ...\n");
continue; continue;
} }
gun = MIN(gun, shell * 2);
gun = MIN(gun, mil / 2);
gun = MAX(gun, 1);
shots = gun;
guneff = seagun(fship.shp_effic, shots);
dam = (int)guneff;
shell -= ldround(shots / 2.0, 1);
fship.shp_item[I_SHELL] = shell;
putship(fship.shp_uid, &fship);
} }
if (opt_NOMOBCOST == 0) { if (opt_NOMOBCOST == 0) {
fship.shp_mobil = MAX(fship.shp_mobil - 15, -100); fship.shp_mobil = MAX(fship.shp_mobil - 15, -100);
@ -723,7 +707,7 @@ static int
quiet_bigdef(int attacker, struct emp_qelem *list, natid own, natid aown, quiet_bigdef(int attacker, struct emp_qelem *list, natid own, natid aown,
coord ax, coord ay, int *nfiring) coord ax, coord ay, int *nfiring)
{ {
int nshot, range; int range;
double erange, hitchance; double erange, hitchance;
struct shpstr ship; struct shpstr ship;
struct lndstr land; struct lndstr land;
@ -753,16 +737,13 @@ quiet_bigdef(int attacker, struct emp_qelem *list, natid own, natid aown,
/* Don't shoot yourself */ /* Don't shoot yourself */
if (ship.shp_own == aown) if (ship.shp_own == aown)
continue; 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)
continue;
if (mchr[(int)ship.shp_type].m_flags & M_SUB) { if (mchr[(int)ship.shp_type].m_flags & M_SUB) {
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)
continue;
if (shell < SHP_TORP_SHELLS) if (shell < SHP_TORP_SHELLS)
shell += supply_commod(ship.shp_own, shell += supply_commod(ship.shp_own,
ship.shp_x, ship.shp_y, ship.shp_x, ship.shp_y,
@ -800,16 +781,9 @@ quiet_bigdef(int attacker, struct emp_qelem *list, natid own, natid aown,
erange = effrange(ship.shp_frnge, ship.shp_tech); erange = effrange(ship.shp_frnge, ship.shp_tech);
if (roundrange(erange) < ni.curdist) if (roundrange(erange) < ni.curdist)
continue; continue;
/* must have gun, shell, and milit to fire */ dam2 = shp_fire(&ship);
if (shell < 1) /* no putship(&ship) because ammo is charged in use_ammo() */
shell += supply_commod(ship.shp_own, if (dam2 < 0)
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)
continue; continue;
(*nfiring)++; (*nfiring)++;
fp = malloc(sizeof(struct flist)); fp = malloc(sizeof(struct flist));
@ -818,7 +792,7 @@ quiet_bigdef(int attacker, struct emp_qelem *list, natid own, natid aown,
fp->uid = ship.shp_uid; fp->uid = ship.shp_uid;
add_to_fired_queue(&fp->queue, list); add_to_fired_queue(&fp->queue, list);
nreport(ship.shp_own, N_FIRE_BACK, player->cnum, 1); nreport(ship.shp_own, N_FIRE_BACK, player->cnum, 1);
dam += seagun(ship.shp_effic, nshot); dam += dam2;
} }
} }
snxtitem_dist(&ni, EF_LAND, ax, ay, 8); snxtitem_dist(&ni, EF_LAND, ax, ay, 8);

View file

@ -221,7 +221,7 @@ mission(void)
radius = desired_radius; radius = desired_radius;
if ((mission == MI_INTERDICT) && (type == EF_SHIP)) if ((mission == MI_INTERDICT) && (type == EF_SHIP))
if (mchr[(int)gp->type].m_frnge < 1) { if (mchr[(int)gp->type].m_glim == 0) {
pr("%s: cannot fire at range!\n", obj_nameof(gp)); pr("%s: cannot fire at range!\n", obj_nameof(gp));
continue; continue;
} }

View file

@ -319,30 +319,12 @@ static void
fire_dchrg(struct shpstr *sp, struct shpstr *targ, int ntargets) fire_dchrg(struct shpstr *sp, struct shpstr *targ, int ntargets)
{ {
int dam; int dam;
int shells;
int gun;
double guneff;
if ((mchr[(int)targ->shp_type].m_flags & M_SUB) == 0) { if ((mchr[(int)targ->shp_type].m_flags & M_SUB) == 0) {
shells = sp->shp_item[I_SHELL]; dam = shp_fire(sp);
gun = sp->shp_item[I_GUN];
gun = MIN(gun, sp->shp_glim);
gun = MIN(gun, sp->shp_item[I_MILIT] / 2);
shells += supply_commod(sp->shp_own, sp->shp_x, sp->shp_y,
I_SHELL, (gun + 1) / 2 - shells);
gun = MIN(gun, shells * 2);
if (gun == 0)
return;
/* ok, all set.. now, we shoot */
shells -= ldround(gun / 2.0, 1);
sp->shp_item[I_SHELL] = shells;
putship(sp->shp_uid, sp); putship(sp->shp_uid, sp);
if (dam < 0)
guneff = seagun(sp->shp_effic, gun); return;
dam = (int)guneff;
if (ntargets > 2) if (ntargets > 2)
dam /= ntargets / 2; dam /= ntargets / 2;

View file

@ -67,12 +67,10 @@ int
sd(natid att, natid own, coord x, coord y, int noisy, int defending, sd(natid att, natid own, coord x, coord y, int noisy, int defending,
int usesubs) int usesubs)
{ {
int nshot;
int range; int range;
double eff; double eff;
struct shpstr ship; struct shpstr ship;
struct nstr_item ni; struct nstr_item ni;
int shell;
int dam, rel, rel2; int dam, rel, rel2;
if (own == 0) if (own == 0)
@ -91,34 +89,23 @@ sd(natid att, natid own, coord x, coord y, int noisy, int defending,
rel2 = getrel(getnatp(ship.shp_own), att); rel2 = getrel(getnatp(ship.shp_own), att);
if ((ship.shp_own != own) && ((rel != ALLIED) || (rel2 != AT_WAR))) if ((ship.shp_own != own) && ((rel != ALLIED) || (rel2 != AT_WAR)))
continue; continue;
if (ship.shp_effic < 60)
continue;
if ((mchr[(int)ship.shp_type].m_flags & M_SUB) && !usesubs) if ((mchr[(int)ship.shp_type].m_flags & M_SUB) && !usesubs)
continue; continue;
range = roundrange(effrange(ship.shp_frnge, ship.shp_tech)); range = roundrange(effrange(ship.shp_frnge, ship.shp_tech));
if (range < ni.curdist) if (range < ni.curdist)
continue; continue;
/* must have gun, shell, and milit to fire */ dam = shp_fire(&ship);
shell = ship.shp_item[I_SHELL];
if (shell < ship.shp_glim)
shell += supply_commod(ship.shp_own, ship.shp_x, ship.shp_y,
I_SHELL, shell - ship.shp_glim);
nshot = MIN(MIN(ship.shp_item[I_GUN], shell), ship.shp_item[I_MILIT]);
nshot = MIN(nshot, ship.shp_glim);
if (nshot <= 0)
continue;
ship.shp_item[I_SHELL] = shell - nshot;
putship(ship.shp_uid, &ship); putship(ship.shp_uid, &ship);
if (dam < 0)
continue;
if (defending) if (defending)
nreport(ship.shp_own, N_FIRE_BACK, att, 1); nreport(ship.shp_own, N_FIRE_BACK, att, 1);
else else
nreport(ship.shp_own, N_FIRE_S_ATTACK, att, 1); nreport(ship.shp_own, N_FIRE_S_ATTACK, att, 1);
dam = seagun(ship.shp_effic, nshot);
eff *= (1.0 - (0.01 * dam)); eff *= (1.0 - (0.01 * dam));
if (noisy) { if (noisy) {
pr_beep(); pr_beep();
pr("Incoming shell%s %d damage!\n", pr("Incoming shells do %d damage!\n", dam);
nshot == 1 ? " does" : "s do", dam);
} }
if (noisy || (ship.shp_own != own)) { if (noisy || (ship.shp_own != own)) {
if (ship.shp_own == own) if (ship.shp_own == own)

View file

@ -101,6 +101,33 @@ fort_fire(struct sctstr *sp)
return (int)fortgun(sp->sct_effic, guns); return (int)fortgun(sp->sct_effic, guns);
} }
/*
* Fire from ship SP.
* Use ammo, resupply if necessary.
* Return damage if the ship fires, else -1.
*/
int
shp_fire(struct shpstr *sp)
{
int guns, shells;
if (sp->shp_effic < 60)
return -1;
guns = sp->shp_glim;
guns = MIN(guns, sp->shp_item[I_GUN]);
guns = MIN(guns, (sp->shp_item[I_MILIT] + 1) / 2);
if (guns == 0)
return -1;
shells = sp->shp_item[I_SHELL];
shells += supply_commod(sp->shp_own, sp->shp_x, sp->shp_y,
I_SHELL, (guns + 1) / 2 - shells);
guns = MIN(guns, shells * 2);
if (guns == 0)
return -1;
sp->shp_item[I_SHELL] = shells - (guns + 1) / 2;
return (int)seagun(sp->shp_effic, guns);
}
/* /*
* Drop depth-charges from ship SP. * Drop depth-charges from ship SP.
* Use ammo, resupply if necessary. * Use ammo, resupply if necessary.

View file

@ -480,16 +480,10 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
sp = (struct shpstr *)glp->thing; sp = (struct shpstr *)glp->thing;
mcp = glp->cp; mcp = glp->cp;
if (sp->shp_effic < 60)
continue;
if (sp->shp_frnge == 0)
continue;
if (((mission == MI_INTERDICT) || if (((mission == MI_INTERDICT) ||
(mission == MI_SINTERDICT)) && (mission == MI_SINTERDICT)) &&
(md > ship_max_interdiction_range)) (md > ship_max_interdiction_range))
continue; continue;
if (sp->shp_item[I_MILIT] < 1)
continue;
/* /*
if ((mcp->m_flags & M_SUB) && if ((mcp->m_flags & M_SUB) &&
(sect.sct_type != SCT_WATER)) (sect.sct_type != SCT_WATER))
@ -513,6 +507,12 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
a sub. */ a sub. */
if (*s != 's') if (*s != 's')
continue; continue;
if (sp->shp_effic < 60)
continue;
if (sp->shp_frnge == 0)
continue;
if (sp->shp_item[I_MILIT] < 1)
continue;
if (sp->shp_mobil < 0) if (sp->shp_mobil < 0)
continue; continue;
gun = sp->shp_item[I_GUN]; gun = sp->shp_item[I_GUN];
@ -569,28 +569,13 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
range = roundrange(effrange(sp->shp_frnge, sp->shp_tech)); range = roundrange(effrange(sp->shp_frnge, sp->shp_tech));
if (md > range) if (md > range)
continue; continue;
if (mission == MI_SINTERDICT) { if (mission == MI_SINTERDICT)
dam2 = shp_dchrg(sp); dam2 = shp_dchrg(sp);
putship(sp->shp_uid, sp); else
if (dam2 < 0) dam2 = shp_fire(sp);
continue; putship(sp->shp_uid, sp);
} else { if (dam2 < 0)
gun = sp->shp_item[I_GUN]; continue;
gun = MIN(gun, sp->shp_glim);
shell = sp->shp_item[I_SHELL];
if (shell < gun)
shell += supply_commod(sp->shp_own,
sp->shp_x, sp->shp_y, I_SHELL,
gun - shell);
gun = MIN(gun, shell);
gun = MIN(gun, sp->shp_item[I_MILIT] / 2.0);
if (gun == 0)
continue;
gun = MAX(gun, 1);
dam2 = seagun(sp->shp_effic, gun);
sp->shp_item[I_SHELL] = shell - gun;
putship(sp->shp_uid, sp);
}
if (range == 0.0) if (range == 0.0)
prb = 1.0; prb = 1.0;
else else