Factor out common torpedo fire code into shp_torp()

This takes care of a number of bugs / inconsistencies:

* Submarines with zero mobility could interdict.  Change to require
  positive mobility.

* Submarines with zero firing range could not interdict.  Fix by
  dropping the test from perform_mission().  No ships in the stock
  game are affected.

* Submarines without capability torp could fire return torpedoes and
  interdict.  Stock sbc, nm and msb were affected by the return fire
  bug.  Closes bug#950936.

* Shell resupply bugs: quiet_bigdef(), fire_torp() and
  perform_mission() resupplied before checking all other requirements
  and could thus get more shells than actually needed.

torp() no longer resupplies shells.  It's hardly worth the bother, and
fire doesn't do it either.
This commit is contained in:
Markus Armbruster 2008-03-02 15:45:41 +01:00
parent 21733d1473
commit 6d83090aad
5 changed files with 60 additions and 105 deletions

View file

@ -185,5 +185,6 @@ 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 *); extern int shp_fire(struct shpstr *);
extern int shp_torp(struct shpstr *, int);
#endif #endif

View file

@ -708,7 +708,7 @@ 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 range; int range;
double erange, hitchance; double erange;
struct shpstr ship; struct shpstr ship;
struct lndstr land; struct lndstr land;
struct nstr_item ni; struct nstr_item ni;
@ -738,45 +738,25 @@ quiet_bigdef(int attacker, struct emp_qelem *list, natid own, natid aown,
if (ship.shp_own == aown) if (ship.shp_own == aown)
continue; 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)
shell += supply_commod(ship.shp_own,
ship.shp_x, ship.shp_y,
I_SHELL, SHP_TORP_SHELLS - shell);
if (shell < SHP_TORP_SHELLS)
continue;
if (gun < 1)
continue;
/*
if (ship.shp_mobil <= 0)
continue;
*/
erange = torprange(&ship); erange = torprange(&ship);
range = mapdist(ship.shp_x, ship.shp_y, ax, ay); range = mapdist(ship.shp_x, ship.shp_y, ax, ay);
if (range > roundrange(erange)) if (range > roundrange(erange))
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);
/* no putship(&ship) because ammo is charged in use_ammo() */
if (dam2 < 0)
continue;
(*nfiring)++; (*nfiring)++;
fp = malloc(sizeof(struct flist)); fp = malloc(sizeof(struct flist));
memset(fp, 0, sizeof(struct flist)); memset(fp, 0, sizeof(struct flist));
fp->type = targ_ship; fp->type = targ_ship;
fp->uid = ship.shp_uid; fp->uid = ship.shp_uid;
add_to_fired_queue(&fp->queue, list); add_to_fired_queue(&fp->queue, list);
/* if (!chance(DTORP_HITCHANCE(range, ship.shp_visib)))
nreport(ship.shp_own, N_FIRE_BACK, player->cnum, 1);
*/
hitchance = DTORP_HITCHANCE(range, ship.shp_visib);
if (!chance(hitchance))
continue; continue;
dam += dam2;
dam += TORP_DAMAGE();
} else { } else {
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)

View file

@ -56,7 +56,6 @@ torp(void)
natid vshipown; natid vshipown;
int range; int range;
int dam; int dam;
int shells;
int subno; int subno;
int victno; int victno;
int erange; int erange;
@ -79,11 +78,8 @@ torp(void)
continue; continue;
if ((mchr[(int)sub.shp_type].m_flags & M_TORP) == 0) if ((mchr[(int)sub.shp_type].m_flags & M_TORP) == 0)
continue; continue;
shells = sub.shp_item[I_SHELL]; if (sub.shp_item[I_GUN] == 0
if (shells < SHP_TORP_SHELLS) || sub.shp_item[I_SHELL] < SHP_TORP_SHELLS)
shells += supply_commod(sub.shp_own, sub.shp_x, sub.shp_y,
I_SHELL, SHP_TORP_SHELLS - shells);
if (sub.shp_item[I_GUN] == 0 || shells < SHP_TORP_SHELLS)
continue; continue;
if (sub.shp_item[I_MILIT] < 1) if (sub.shp_item[I_MILIT] < 1)
continue; continue;
@ -106,11 +102,8 @@ torp(void)
sub.shp_uid, mchr[(int)sub.shp_type].m_name); sub.shp_uid, mchr[(int)sub.shp_type].m_name);
continue; continue;
} }
shells = sub.shp_item[I_SHELL]; if (sub.shp_item[I_GUN] == 0
if (shells < SHP_TORP_SHELLS) || sub.shp_item[I_SHELL] < SHP_TORP_SHELLS) {
shells += supply_commod(sub.shp_own, sub.shp_x, sub.shp_y,
I_SHELL, SHP_TORP_SHELLS - shells);
if (sub.shp_item[I_GUN] == 0 || shells < SHP_TORP_SHELLS) {
pr("Ship #%d has insufficient armament\n", sub.shp_uid); pr("Ship #%d has insufficient armament\n", sub.shp_uid);
continue; continue;
} }
@ -149,19 +142,22 @@ torp(void)
continue; continue;
} }
} }
dam = shp_torp(&sub, 1);
sub.shp_mission = 0;
putship(sub.shp_uid, &sub);
if (CANT_HAPPEN(dam < 0)) {
pr("Ship #%d has insufficient armament\n", sub.shp_uid);
continue;
}
if ((mchr[(int)sub.shp_type].m_flags & M_SUB) == 0) if ((mchr[(int)sub.shp_type].m_flags & M_SUB) == 0)
anti_torp(sub.shp_uid, ntorping, vshipown); anti_torp(sub.shp_uid, ntorping, vshipown);
getship(sub.shp_uid, &sub); getship(sub.shp_uid, &sub);
if (sub.shp_own == 0) { if (sub.shp_own == 0)
continue; continue;
}
erange = roundrange(torprange(&sub)); erange = roundrange(torprange(&sub));
pr("Effective torpedo range is %d.0\n", erange); pr("Effective torpedo range is %d.0\n", erange);
shells -= SHP_TORP_SHELLS;
sub.shp_item[I_SHELL] = shells;
putship(sub.shp_uid, &sub);
/* Mob cost for a torp is equal to the cost of 1/2 sector of movement */
sub.shp_mobil -= shp_mobcost(&sub) / 2.0;
pr("Whooosh... "); pr("Whooosh... ");
getship(victno, &vship); getship(victno, &vship);
vshipown = vship.shp_own; vshipown = vship.shp_own;
@ -183,9 +179,8 @@ torp(void)
} }
} else if (range > erange) { } else if (range > erange) {
pr("Out of range\n"); pr("Out of range\n");
} else if (hitchance >= 1.0 || chance(hitchance)) { } else if (chance(hitchance)) {
pr("BOOM!...\n"); pr("BOOM!...\n");
dam = TORP_DAMAGE();
if (vshipown != 0) if (vshipown != 0)
wu(0, vshipown, "%s in %s torpedoed %s for %d damage.\n", wu(0, vshipown, "%s in %s torpedoed %s for %d damage.\n",
prsub(&sub), xyas(sub.shp_x, sub.shp_y, vshipown), prsub(&sub), xyas(sub.shp_x, sub.shp_y, vshipown),
@ -210,8 +205,7 @@ torp(void)
wu(0, vshipown, "Torpedo sighted @ %s by %s\n", wu(0, vshipown, "Torpedo sighted @ %s by %s\n",
xyas(sub.shp_x, sub.shp_y, vshipown), prship(&vship)); xyas(sub.shp_x, sub.shp_y, vshipown), prship(&vship));
} }
sub.shp_mission = 0;
putship(sub.shp_uid, &sub);
if (mchr[(int)sub.shp_type].m_flags & M_SUB) if (mchr[(int)sub.shp_type].m_flags & M_SUB)
anti_torp(sub.shp_uid, ntorping, vshipown); anti_torp(sub.shp_uid, ntorping, vshipown);
} }
@ -355,55 +349,28 @@ static int
fire_torp(struct shpstr *sp, struct shpstr *targ, int ntargets) fire_torp(struct shpstr *sp, struct shpstr *targ, int ntargets)
{ {
int range, erange, dam; int range, erange, dam;
int shells;
double hitchance;
erange = roundrange(torprange(sp)); erange = roundrange(torprange(sp));
range = mapdist(sp->shp_x, sp->shp_y, targ->shp_x, targ->shp_y); range = mapdist(sp->shp_x, sp->shp_y, targ->shp_x, targ->shp_y);
if (range > erange) if (range > erange)
return 0; return 0;
shells = sp->shp_item[I_SHELL];
if (shells < SHP_TORP_SHELLS)
shells += supply_commod(sp->shp_own, sp->shp_x, sp->shp_y,
I_SHELL, SHP_TORP_SHELLS - shells);
if (sp->shp_item[I_GUN] == 0 || shells < SHP_TORP_SHELLS)
return 0;
if (sp->shp_item[I_MILIT] < 1)
return 0;
if (sp->shp_effic < 60)
return 0;
if (sp->shp_mobil <= 0)
return 0;
if (!line_of_sight(NULL, sp->shp_x, sp->shp_y, if (!line_of_sight(NULL, sp->shp_x, sp->shp_y,
targ->shp_x, targ->shp_y)) targ->shp_x, targ->shp_y))
return 0; return 0;
dam = shp_torp(sp, 1);
/* All set.. fire! */
shells -= SHP_TORP_SHELLS;
sp->shp_item[I_SHELL] = shells;
putship(sp->shp_uid, sp); putship(sp->shp_uid, sp);
if (dam < 0)
/* Mob cost for a torp is equal to the cost of 1/2 sector of movement */ return 0;
sp->shp_mobil -= shp_mobcost(sp) / 2.0;
hitchance = DTORP_HITCHANCE(range, sp->shp_visib);
pr("Captain! Torpedoes sighted!\n"); pr("Captain! Torpedoes sighted!\n");
if (chance(hitchance)) { if (chance(DTORP_HITCHANCE(range, sp->shp_visib))) {
pr("BOOM!...\n"); pr("BOOM!...\n");
if (sp->shp_own != 0) if (sp->shp_own != 0)
wu(0, sp->shp_own, "%s @ %s torpedoed %s\n", wu(0, sp->shp_own, "%s @ %s torpedoed %s\n",
prship(sp), prship(sp),
xyas(sp->shp_x, sp->shp_y, sp->shp_own), prsub(targ)); xyas(sp->shp_x, sp->shp_y, sp->shp_own), prsub(targ));
dam = TORP_DAMAGE();
if (ntargets > 2) if (ntargets > 2)
dam /= ntargets / 2; dam /= ntargets / 2;

View file

@ -33,6 +33,7 @@
#include <config.h> #include <config.h>
#include "damage.h"
#include "file.h" #include "file.h"
#include "nat.h" #include "nat.h"
#include "optlist.h" #include "optlist.h"
@ -151,6 +152,33 @@ shp_dchrg(struct shpstr *sp)
return (int)seagun(sp->shp_effic, 3); return (int)seagun(sp->shp_effic, 3);
} }
/*
* Fire torpedo from ship SP.
* Use ammo and mobility, resupply if necessary.
* Return damage if the ship fires, else -1.
*/
int
shp_torp(struct shpstr *sp, int usemob)
{
int shells;
if (sp->shp_effic < 60 || (mchr[sp->shp_type].m_flags & M_TORP) == 0)
return -1;
if (sp->shp_item[I_MILIT] == 0 || sp->shp_item[I_GUN] == 0)
return -1;
if (usemob && sp->shp_mobil <= 0)
return -1;
shells = sp->shp_item[I_SHELL];
shells += supply_commod(sp->shp_own, sp->shp_x, sp->shp_y,
I_SHELL, SHP_TORP_SHELLS - shells);
if (shells < SHP_TORP_SHELLS)
return -1;
sp->shp_item[I_SHELL] = shells - SHP_TORP_SHELLS;
if (usemob)
sp->shp_mobil -= (int)shp_mobcost(sp) / 2.0;
return TORP_DAMAGE();
}
/* /*
* Return effective firing range for range factor RNG at tech TLEV. * Return effective firing range for range factor RNG at tech TLEV.
*/ */

View file

@ -507,34 +507,15 @@ 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)
continue;
gun = sp->shp_item[I_GUN];
if (gun < 1)
continue;
shell = sp->shp_item[I_SHELL];
if (shell < SHP_TORP_SHELLS)
shell += supply_commod(sp->shp_own,
sp->shp_x, sp->shp_y, I_SHELL,
SHP_TORP_SHELLS - shell);
if (shell < SHP_TORP_SHELLS)
continue;
range = roundrange(torprange(sp)); range = roundrange(torprange(sp));
if (md > range) if (md > range)
continue; continue;
if (!line_of_sight(NULL, x, y, gp->x, gp->y)) if (!line_of_sight(NULL, x, y, gp->x, gp->y))
continue; continue;
sp->shp_item[I_SHELL] = shell - SHP_TORP_SHELLS; dam2 = shp_torp(sp, 1);
sp->shp_mobil -= shp_mobcost(sp) / 2.0;
putship(sp->shp_uid, sp); putship(sp->shp_uid, sp);
if (dam2 < 0)
continue;
hitchance = DTORP_HITCHANCE(md, sp->shp_visib); hitchance = DTORP_HITCHANCE(md, sp->shp_visib);
wu(0, sp->shp_own, wu(0, sp->shp_own,
@ -546,7 +527,7 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
"\tWhooosh... Hitchance = %d%%\n", "\tWhooosh... Hitchance = %d%%\n",
(int)(hitchance * 100)); (int)(hitchance * 100));
if (hitchance < 1.0 && !chance(hitchance)) { if (!chance(hitchance)) {
wu(0, sp->shp_own, "\tMissed\n"); wu(0, sp->shp_own, "\tMissed\n");
mpr(victim, mpr(victim,
"Incoming torpedo sighted @ %s missed (whew)!\n", "Incoming torpedo sighted @ %s missed (whew)!\n",
@ -554,8 +535,6 @@ perform_mission(coord x, coord y, natid victim, struct emp_qelem *list,
continue; continue;
} }
wu(0, sp->shp_own, "\tBOOM!...\n"); wu(0, sp->shp_own, "\tBOOM!...\n");
dam2 = TORP_DAMAGE();
dam += dam2; dam += dam2;
nreport(victim, N_TORP_SHIP, 0, 1); nreport(victim, N_TORP_SHIP, 0, 1);
wu(0, sp->shp_own, wu(0, sp->shp_own,