cherry-picking ship tests from range_max code

This commit is contained in:
Enno Rehling 2015-08-07 09:03:19 +02:00
parent da2b116ea9
commit b3a8a95a24
8 changed files with 107 additions and 46 deletions

1
.gitignore vendored
View File

@ -40,3 +40,4 @@ Thumbs.db
.gdb_history .gdb_history
*.cfg *.cfg
*.cmd *.cmd
tmp/

View File

@ -282,6 +282,20 @@ static int ShipSpeedBonus(const unit * u)
return 0; return 0;
} }
int crew_skill(const ship *sh) {
int n = 0;
unit *u;
n = 0;
for (u = sh->region->units; u; u = u->next) {
if (u->ship == sh) {
n += eff_skill(u, SK_SAILING, sh->region) * u->number;
}
}
return n;
}
int shipspeed(const ship * sh, const unit * u) int shipspeed(const ship * sh, const unit * u)
{ {
double k = sh->type->range; double k = sh->type->range;
@ -290,14 +304,19 @@ int shipspeed(const ship * sh, const unit * u)
attrib *a; attrib *a;
struct curse *c; struct curse *c;
assert(sh);
if (!u) u = ship_owner(sh);
if (!u) return 0;
assert(u->ship == sh);
assert(u == ship_owner(sh));
assert(sh->type->construction);
assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */
if (!init) { if (!init) {
init = true; init = true;
stormwind_ct = ct_find("stormwind"); stormwind_ct = ct_find("stormwind");
nodrift_ct = ct_find("nodrift"); nodrift_ct = ct_find("nodrift");
} }
assert(u->ship == sh);
assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */
if (sh->size != sh->type->construction->maxsize) if (sh->size != sh->type->construction->maxsize)
return 0; return 0;
@ -442,18 +461,3 @@ const char *ship_getname(const ship * self)
{ {
return self->name; return self->name;
} }
unit *get_captain(const ship * sh)
{
const region *r = sh->region;
unit *u;
for (u = r->units; u; u = u->next) {
if (u->ship == sh && u->number
&& eff_skill(u, SK_SAILING, r) >= sh->type->cptskill)
return u;
}
return NULL;
}

View File

@ -124,7 +124,7 @@ extern "C" {
const char *ship_getname(const struct ship *self); const char *ship_getname(const struct ship *self);
void ship_setname(struct ship *self, const char *name); void ship_setname(struct ship *self, const char *name);
int shipspeed(const struct ship *sh, const struct unit *u); int shipspeed(const struct ship *sh, const struct unit *u);
struct unit *get_captain(const struct ship *sh); int crew_skill(const struct ship *sh);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -10,6 +10,7 @@
#include <tests.h> #include <tests.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h>
static void test_register_ship(CuTest * tc) static void test_register_ship(CuTest * tc)
{ {
@ -367,6 +368,69 @@ static void test_stype_defaults(CuTest *tc) {
test_cleanup(); test_cleanup();
} }
static void test_crew_skill(CuTest *tc) {
ship *sh;
region *r;
struct faction *f;
int i;
test_cleanup();
test_create_world();
r = findregion(0, 0);
f = test_create_faction(0);
assert(r && f);
sh = test_create_ship(r, st_find("boat"));
for (i = 0; i != 4; ++i) {
unit * u = test_create_unit(f, r);
set_level(u, SK_SAILING, 5);
u->ship = sh;
}
CuAssertIntEquals(tc, 20, crew_skill(sh));
test_cleanup();
}
static void test_shipspeed(CuTest *tc) {
ship *sh;
ship_type *stype;
region *r;
struct faction *f;
unit *cap, *crew;
test_cleanup();
test_create_world();
r = test_create_region(0, 0, test_create_terrain("ocean", 0));
f = test_create_faction(0);
assert(r && f);
stype = test_create_shiptype("longboat");
stype->cptskill = 1;
stype->sumskill = 10;
stype->minskill = 1;
stype->range = 2;
sh = test_create_ship(r, stype);
CuAssertIntEquals_Msg(tc, "ship without a captain cannot move", 0, shipspeed(sh, NULL));
cap = test_create_unit(f, r);
crew = test_create_unit(f, r);
cap->ship = sh;
crew->ship = sh;
CuAssertPtrEquals(tc, cap, ship_owner(sh));
set_level(cap, SK_SAILING, stype->cptskill);
set_level(crew, SK_SAILING, stype->sumskill - stype->cptskill);
CuAssertIntEquals_Msg(tc, "ship with fully skilled crew can sail at max speed", 2, shipspeed(sh, cap));
set_level(cap, SK_SAILING, stype->cptskill + 5);
CuAssertIntEquals_Msg(tc, "higher captain skill should not affect top speed", 2, shipspeed(sh, cap));
set_level(cap, SK_SAILING, stype->cptskill);
CuAssertIntEquals(tc, 2, shipspeed(sh, cap));
set_level(crew, SK_SAILING, (stype->sumskill - stype->cptskill) * 11);
set_level(cap, SK_SAILING, stype->cptskill + 10);
CuAssertIntEquals_Msg(tc, "regular skills should not exceed sh.range", 2, shipspeed(sh, cap));
}
CuSuite *get_ship_suite(void) CuSuite *get_ship_suite(void)
{ {
CuSuite *suite = CuSuiteNew(); CuSuite *suite = CuSuiteNew();
@ -381,5 +445,6 @@ CuSuite *get_ship_suite(void)
SUITE_ADD_TEST(suite, test_shipowner_goes_to_other_after_leave); SUITE_ADD_TEST(suite, test_shipowner_goes_to_other_after_leave);
SUITE_ADD_TEST(suite, test_shipowner_goes_to_same_faction_after_leave); SUITE_ADD_TEST(suite, test_shipowner_goes_to_same_faction_after_leave);
SUITE_ADD_TEST(suite, test_shipowner_goes_to_empty_unit_after_leave); SUITE_ADD_TEST(suite, test_shipowner_goes_to_empty_unit_after_leave);
SUITE_ADD_TEST(suite, test_shipspeed);
return suite; return suite;
} }

View File

@ -2797,17 +2797,17 @@ void sinkships(struct region * r)
ship *sh = *shp; ship *sh = *shp;
if (!sh->type->construction || sh->size >= sh->type->construction->maxsize) { if (!sh->type->construction || sh->size >= sh->type->construction->maxsize) {
if (fval(r->terrain, SEA_REGION) && (!enoughsailors(sh, r) if (fval(r->terrain, SEA_REGION)) {
|| get_captain(sh) == NULL)) { if (!enoughsailors(sh, crew_skill(sh))) {
/* Schiff nicht seetüchtig */ // ship is at sea, but not enough people to control it
float dmg = get_param_flt(global.parameters, float dmg = get_param_flt(global.parameters,
"rules.ship.damage.nocrewocean", "rules.ship.damage.nocrewocean",
0.30F); 0.30F);
damage_ship(sh, dmg); damage_ship(sh, dmg);
} }
if (ship_owner(sh) == NULL) { } else if (!ship_owner(sh)) {
float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrew", // any ship lying around without an owner slowly rots
0.05F); float dmg = get_param_flt(global.parameters, "rules.ship.damage.nocrew", 0.05F);
damage_ship(sh, dmg); damage_ship(sh, dmg);
} }
} }

View File

@ -469,18 +469,9 @@ static bool cansail(const region * r, ship * sh)
return true; return true;
} }
int enoughsailors(const ship * sh, const region * r) int enoughsailors(const ship * sh, int sumskill)
{ {
int n; return sumskill >= sh->type->sumskill;
unit *u;
n = 0;
for (u = r->units; u; u = u->next) {
if (u->ship == sh)
n += eff_skill(u, SK_SAILING, r) * u->number;
}
return n >= sh->type->sumskill;
} }
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
@ -778,7 +769,7 @@ static void drifting_ships(region * r)
assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ assert(sh->type->construction->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */
if (captain && sh->size == sh->type->construction->maxsize if (captain && sh->size == sh->type->construction->maxsize
&& enoughsailors(sh, r) && cansail(r, sh)) { && enoughsailors(sh, crew_skill(sh)) && cansail(r, sh)) {
shp = &sh->next; shp = &sh->next;
continue; continue;
} }
@ -1767,7 +1758,7 @@ static bool ship_ready(const region * r, unit * u)
cmistake(u, u->thisorder, 15, MSG_MOVE); cmistake(u, u->thisorder, 15, MSG_MOVE);
return false; return false;
} }
if (!enoughsailors(u->ship, r)) { if (!enoughsailors(u->ship, crew_skill(u->ship))) {
cmistake(u, u->thisorder, 1, MSG_MOVE); cmistake(u, u->thisorder, 1, MSG_MOVE);
/* mistake(u, u->thisorder, /* mistake(u, u->thisorder,
"Auf dem Schiff befinden sich zuwenig erfahrene Seeleute.", MSG_MOVE); */ "Auf dem Schiff befinden sich zuwenig erfahrene Seeleute.", MSG_MOVE); */

View File

@ -61,7 +61,7 @@ extern "C" {
void run_to(struct unit *u, struct region *to); void run_to(struct unit *u, struct region *to);
struct unit *is_guarded(struct region *r, struct unit *u, unsigned int mask); struct unit *is_guarded(struct region *r, struct unit *u, unsigned int mask);
bool is_guard(const struct unit *u, unsigned int mask); bool is_guard(const struct unit *u, unsigned int mask);
int enoughsailors(const struct ship *sh, const struct region *r); int enoughsailors(const struct ship *sh, int sumskill);
bool canswim(struct unit *u); bool canswim(struct unit *u);
bool canfly(struct unit *u); bool canfly(struct unit *u);
void travelthru(const struct unit *u, struct region *r); void travelthru(const struct unit *u, struct region *r);

View File

@ -342,7 +342,7 @@ int setstealth_cmd(unit * u, struct order *ord)
return 0; return 0;
} }
static int crew_skill(region * r, faction * f, ship * sh, skill_t sk) static int top_skill(region * r, faction * f, ship * sh, skill_t sk)
{ {
int value = 0; int value = 0;
unit *u; unit *u;
@ -517,7 +517,7 @@ int sabotage_cmd(unit * u, struct order *ord)
r = u->region; r = u->region;
if (u2->faction != u->faction) { if (u2->faction != u->faction) {
skdiff = skdiff =
eff_skill(u, SK_SPY, r) - crew_skill(r, u2->faction, sh, SK_PERCEPTION); eff_skill(u, SK_SPY, r) - top_skill(r, u2->faction, sh, SK_PERCEPTION);
} }
if (try_destruction(u, u2, sh, skdiff)) { if (try_destruction(u, u2, sh, skdiff)) {
sink_ship(r, sh, u); sink_ship(r, sh, u);