BUG 2168: call sink_ship for ships that take too much damage.

This commit is contained in:
Enno Rehling 2018-08-01 10:04:12 +02:00
parent 7eb951544a
commit ad0464ab50
12 changed files with 61 additions and 33 deletions

2
clibs

@ -1 +1 @@
Subproject commit 9b6e34959f77d7ca3a4ce3826cb487487f557441 Subproject commit d86c8525489d7f11b7ba13e101bb59ecf160b871

View file

@ -517,3 +517,16 @@ function test_buy_sell()
assert_equal(4, u:get_item(item)) assert_equal(4, u:get_item(item))
assert_not_equal(0, u:get_item('money')) assert_not_equal(0, u:get_item('money'))
end end
function test_seaserpent_attack()
local r = region.create(0, 0, 'ocean')
local sh = ship.create(r, 'boat')
local us = unit.create(get_monsters(), r, 1, 'seaserpent')
local u = unit.create(faction.create('human'), r, 20, 'human')
u.ship = sh
us:clear_orders()
us:add_order('ATTACKIERE ' .. itoa36(u.id))
us:set_skill('unarmed', 10)
process_orders()
write_reports()
end

View file

@ -26,6 +26,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "move.h" #include "move.h"
#include "skill.h" #include "skill.h"
#include "study.h" #include "study.h"
#include "spy.h"
#include <spells/buildingcurse.h> #include <spells/buildingcurse.h>
#include <spells/regioncurse.h> #include <spells/regioncurse.h>
@ -2787,10 +2788,12 @@ static void aftermath(battle * b)
ship *sh = *sp; ship *sh = *sp;
freset(sh, SF_DAMAGED); freset(sh, SF_DAMAGED);
if (sh->damage >= sh->size * DAMAGE_SCALE) { if (sh->damage >= sh->size * DAMAGE_SCALE) {
sink_ship(sh);
remove_ship(sp, sh); remove_ship(sp, sh);
} }
if (*sp == sh) else {
sp = &sh->next; sp = &sh->next;
}
} }
} }

View file

@ -909,8 +909,8 @@ static int tolua_unit_create(lua_State * L)
faction *f = (faction *)tolua_tousertype(L, 1, 0); faction *f = (faction *)tolua_tousertype(L, 1, 0);
region *r = (region *)tolua_tousertype(L, 2, 0); region *r = (region *)tolua_tousertype(L, 2, 0);
unit *u; unit *u;
const char *rcname = tolua_tostring(L, 4, NULL);
int num = (int)tolua_tonumber(L, 3, 1); int num = (int)tolua_tonumber(L, 3, 1);
const char *rcname = tolua_tostring(L, 4, NULL);
const race *rc; const race *rc;
assert(f && r); assert(f && r);

View file

@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "chaos.h" #include "chaos.h"
#include "monsters.h" #include "monsters.h"
#include "move.h" #include "move.h"
#include "spy.h"
#include <kernel/building.h> #include <kernel/building.h>
#include <kernel/faction.h> #include <kernel/faction.h>
@ -144,19 +145,20 @@ static void chaos(region * r)
break; break;
} }
if (dir != MAXDIRECTIONS) { if (dir != MAXDIRECTIONS) {
ship *sh = r->ships; ship **slist = &r->ships;
unit **up; unit **up;
while (sh) { while (*slist) {
ship *nsh = sh->next; ship *sh = *slist;
double dmg =
config_get_flt("rules.ship.damage.atlantis", damage_ship(sh, 0.5);
0.50);
damage_ship(sh, dmg);
if (sh->damage >= sh->size * DAMAGE_SCALE) { if (sh->damage >= sh->size * DAMAGE_SCALE) {
remove_ship(&sh->region->ships, sh); sink_ship(sh);
remove_ship(slist, sh);
}
else {
slist = &sh->next;
} }
sh = nsh;
} }
for (up = &r->units; *up;) { for (up = &r->units; *up;) {

View file

@ -22,8 +22,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
extern "C" { extern "C" {
#endif #endif
struct region;
void chaos_update(void); void chaos_update(void);
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -124,9 +124,9 @@ extern "C" {
extern void write_ship_reference(const struct ship *sh, extern void write_ship_reference(const struct ship *sh,
struct storage *store); struct storage *store);
extern void remove_ship(struct ship **slist, struct ship *s); void remove_ship(struct ship **slist, struct ship *s);
extern void free_ship(struct ship *s); void free_ship(struct ship *s);
extern void free_ships(void); void free_ships(void);
const char *ship_getname(const struct ship *sh); const char *ship_getname(const struct ship *sh);
void ship_setname(struct ship *self, const char *name); void ship_setname(struct ship *self, const char *name);

View file

@ -2590,6 +2590,7 @@ void sinkships(struct region * r)
} }
} }
if (sh->damage >= sh->size * DAMAGE_SCALE) { if (sh->damage >= sh->size * DAMAGE_SCALE) {
sink_ship(sh);
remove_ship(shp, sh); remove_ship(shp, sh);
} }
if (*shp == sh) if (*shp == sh)

View file

@ -47,6 +47,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "laws.h" #include "laws.h"
#include "reports.h" #include "reports.h"
#include "study.h" #include "study.h"
#include "spy.h"
#include "alchemy.h" #include "alchemy.h"
#include "travelthru.h" #include "travelthru.h"
#include "vortex.h" #include "vortex.h"
@ -541,6 +542,7 @@ static ship *do_maelstrom(region * r, unit * u)
if (sh->damage >= sh->size * DAMAGE_SCALE) { if (sh->damage >= sh->size * DAMAGE_SCALE) {
ADDMSG(&u->faction->msgs, msg_message("entermaelstrom", ADDMSG(&u->faction->msgs, msg_message("entermaelstrom",
"region ship damage sink", r, sh, damage, 1)); "region ship damage sink", r, sh, damage, 1));
sink_ship(sh);
remove_ship(&sh->region->ships, sh); remove_ship(&sh->region->ships, sh);
return NULL; return NULL;
} }
@ -882,12 +884,14 @@ static void drifting_ships(region * r)
} }
if (sh->damage >= sh->size * DAMAGE_SCALE) { if (sh->damage >= sh->size * DAMAGE_SCALE) {
msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("shipsink", "ship", sh)); msg_to_ship_inmates(sh, &firstu, &lastu, msg_message("shipsink", "ship", sh));
remove_ship(&sh->region->ships, sh); sink_ship(sh);
remove_ship(shp, sh);
} }
} }
if (*shp == sh) if (*shp == sh) {
shp = &sh->next; shp = &sh->next;
}
} }
} }
} }
@ -1926,6 +1930,7 @@ static void sail(unit * u, order * ord, region_list ** routep, bool drifting)
if (sh->damage >= sh->size * DAMAGE_SCALE) { if (sh->damage >= sh->size * DAMAGE_SCALE) {
if (sh->region) { if (sh->region) {
ADDMSG(&f->msgs, msg_message("shipsink", "ship", sh)); ADDMSG(&f->msgs, msg_message("shipsink", "ship", sh));
sink_ship(sh);
remove_ship(&sh->region->ships, sh); remove_ship(&sh->region->ships, sh);
} }
sh = NULL; sh = NULL;

View file

@ -26,6 +26,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "economy.h" #include "economy.h"
#include "monsters.h" #include "monsters.h"
#include "move.h" #include "move.h"
#include "spy.h"
#include "study.h" #include "study.h"
#include "volcano.h" #include "volcano.h"
@ -295,6 +296,7 @@ static void move_iceberg(region * r)
ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des", ADDMSG(&u->faction->msgs, msg_message("overrun_by_iceberg_des",
"ship", sh)); "ship", sh));
} }
sink_ship(sh);
remove_ship(&sh->region->ships, sh); remove_ship(&sh->region->ships, sh);
} }
else if (u != NULL) { else if (u != NULL) {
@ -421,6 +423,7 @@ static void godcurse(void)
ADDMSG(&uo->faction->msgs, ADDMSG(&uo->faction->msgs,
msg_message("godcurse_destroy_ship", "ship", sh)); msg_message("godcurse_destroy_ship", "ship", sh));
} }
sink_ship(sh);
remove_ship(&sh->region->ships, sh); remove_ship(&sh->region->ships, sh);
} }
sh = shn; sh = shn;

View file

@ -392,19 +392,22 @@ static int try_destruction(unit * u, unit * u2, const ship * sh, int skilldiff)
return 1; /* success */ return 1; /* success */
} }
static void sink_ship(region * r, ship * sh, unit * saboteur) #define OCEAN_SWIMMER_CHANCE 0.1
#define COAST_SWIMMER_CHANCE 0.9
void sink_ship(ship * sh)
{ {
unit **ui, *u; unit **ui, *u;
region *safety = r; region *r, *safety;
int i; int i;
direction_t d; direction_t d;
double probability = 0.0; double probability = 0.0;
message *sink_msg = NULL; message *sink_msg = NULL;
faction *f; faction *f;
assert(r); assert(sh && sh->region);
assert(sh); r = sh->region;
assert(saboteur);
for (f = NULL, u = r->units; u; u = u->next) { for (f = NULL, u = r->units; u; u = u->next) {
/* slight optimization to avoid dereferencing u->faction each time */ /* slight optimization to avoid dereferencing u->faction each time */
if (f != u->faction) { if (f != u->faction) {
@ -414,8 +417,9 @@ static void sink_ship(region * r, ship * sh, unit * saboteur)
} }
/* figure out what a unit's chances of survival are: */ /* figure out what a unit's chances of survival are: */
safety = r;
if (!(r->terrain->flags & SEA_REGION)) { if (!(r->terrain->flags & SEA_REGION)) {
probability = CANAL_SWIMMER_CHANCE; probability = COAST_SWIMMER_CHANCE;
} }
else { else {
for (d = 0; d != MAXDIRECTIONS; ++d) { for (d = 0; d != MAXDIRECTIONS; ++d) {
@ -479,10 +483,9 @@ static void sink_ship(region * r, ship * sh, unit * saboteur)
} }
ui = &u->next; ui = &u->next;
} }
if (sink_msg) if (sink_msg) {
msg_release(sink_msg); msg_release(sink_msg);
/* finally, get rid of the ship */ }
remove_ship(&sh->region->ships, sh);
} }
int sabotage_cmd(unit * u, struct order *ord) int sabotage_cmd(unit * u, struct order *ord)
@ -514,7 +517,9 @@ int sabotage_cmd(unit * u, struct order *ord)
effskill(u, SK_SPY, 0) - top_skill(u->region, u2->faction, sh, SK_PERCEPTION); effskill(u, SK_SPY, 0) - top_skill(u->region, u2->faction, sh, SK_PERCEPTION);
} }
if (try_destruction(u, u2, sh, skdiff)) { if (try_destruction(u, u2, sh, skdiff)) {
sink_ship(u->region, sh, u); sink_ship(sh);
/* finally, get rid of the ship */
remove_ship(&sh->region->ships, sh);
} }
break; break;
default: default:

View file

@ -27,6 +27,7 @@ extern "C" {
struct strlist; struct strlist;
struct order; struct order;
struct faction; struct faction;
struct ship;
int setstealth_cmd(struct unit *u, struct order *ord); int setstealth_cmd(struct unit *u, struct order *ord);
int spy_cmd(struct unit *u, struct order *ord); int spy_cmd(struct unit *u, struct order *ord);
@ -34,10 +35,7 @@ extern "C" {
void spy_message(int spy, const struct unit *u, void spy_message(int spy, const struct unit *u,
const struct unit *target); const struct unit *target);
void set_factionstealth(struct unit * u, struct faction * f); void set_factionstealth(struct unit * u, struct faction * f);
void sink_ship(struct ship * sh);
#define OCEAN_SWIMMER_CHANCE 0.1
#define CANAL_SWIMMER_CHANCE 0.9
#ifdef __cplusplus #ifdef __cplusplus
} }