From 84633b50e101225d3b02cc741b21ab9450f58fc3 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 5 Oct 2019 20:31:00 +0200 Subject: [PATCH 01/13] gamedata version SHIP_NUMBER_VERSION --- src/kernel/gamedata.h | 3 ++- src/kernel/save.c | 7 +++++++ src/kernel/ship.c | 16 ++++++++-------- src/kernel/ship.h | 1 + 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/kernel/gamedata.h b/src/kernel/gamedata.h index bc1701173..b0fd7762c 100644 --- a/src/kernel/gamedata.h +++ b/src/kernel/gamedata.h @@ -45,8 +45,9 @@ #define FIX_RES_BASE_VERSION 367 /* fixing resource base */ #define FIX_CLONES_VERSION 368 /* dissolve clones */ #define FIX_MIGRANT_AURA_VERSION 369 /* bug 2585, migrants with aura */ +#define SHIP_NUMBER_VERISON 370 /* ships have a number */ -#define RELEASE_VERSION FIX_MIGRANT_AURA_VERSION /* current datafile */ +#define RELEASE_VERSION SHIP_NUMBER_VERISON /* current datafile */ #define MIN_VERSION UIDHASH_VERSION /* minimal datafile we support */ #define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */ diff --git a/src/kernel/save.c b/src/kernel/save.c index 2eb36b134..2774f3401 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1283,6 +1283,7 @@ void write_ship(gamedata *data, const ship *sh) WRITE_STR(store, (const char *)sh->name); WRITE_STR(store, sh->display ? (const char *)sh->display : ""); WRITE_TOK(store, sh->type->_name); + WRITE_INT(store, sh->number); WRITE_INT(store, sh->size); WRITE_INT(store, sh->damage); WRITE_INT(store, sh->flags & SFL_SAVEMASK); @@ -1320,6 +1321,12 @@ ship *read_ship(gamedata *data) } assert(sh->type || !"ship_type not registered!"); + if (data->version < SHIP_NUMBER_VERISON) { + sh->number = 1; + } + else { + READ_INT(store, &sh->number); + } READ_INT(store, &sh->size); READ_INT(store, &sh->damage); if (data->version >= FOSS_VERSION) { diff --git a/src/kernel/ship.c b/src/kernel/ship.c index d1657b926..6d458843e 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -389,7 +389,7 @@ int shipcapacity(const ship * sh) { int i = sh->type->cargo; - if (sh->type->construction && sh->size != sh->type->construction->maxsize) + if (sh->type->construction && sh->size < sh->number * sh->type->construction->maxsize) return 0; if (sh->damage) { @@ -465,17 +465,17 @@ void write_ship_reference(const struct ship *sh, struct storage *store) WRITE_INT(store, (sh && sh->region) ? sh->no : 0); } -void ship_setname(ship * self, const char *name) +void ship_setname(ship * sh, const char *name) { - free(self->name); - self->name = name ? str_strdup(name) : 0; + free(sh->name); + sh->name = name ? str_strdup(name) : 0; } -const char *ship_getname(const ship * self) +const char *ship_getname(const ship * sh) { - return self->name; + return sh->name; } -int ship_damage_percent(const ship *ship) { - return (ship->damage * 100 + DAMAGE_SCALE - 1) / (ship->size * DAMAGE_SCALE); +int ship_damage_percent(const ship *sh) { + return (sh->damage * 100 + DAMAGE_SCALE - 1) / (sh->size * DAMAGE_SCALE); } diff --git a/src/kernel/ship.h b/src/kernel/ship.h index cd6966040..6c4e0bf95 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -73,6 +73,7 @@ extern "C" { struct ship *nexthash; struct unit * _owner; /* never use directly, always use ship_owner() */ int no; + int number; struct region *region; char *name; char *display; From 178f7c2e19f9b8ac642645656f59bdbd37e4c1d7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Oct 2019 18:11:10 +0200 Subject: [PATCH 02/13] add number of ships for convoys. check required crew skills. require number of captains >= ship.number. --- scripts/tests/e2/ships.lua | 89 +++++++++++++++++++++++++++++ src/bind_ship.c | 111 +++++++++++++++++++++---------------- src/bind_unit.c | 14 ++++- src/creport.c | 7 ++- src/kernel/save.c | 1 + src/kernel/ship.c | 96 ++++++++++++++++++++++---------- src/kernel/ship.h | 11 +++- src/kernel/ship.test.c | 14 ++--- src/laws.c | 6 +- src/move.c | 39 +++++-------- src/move.h | 1 - src/report.c | 2 +- 12 files changed, 271 insertions(+), 120 deletions(-) diff --git a/scripts/tests/e2/ships.lua b/scripts/tests/e2/ships.lua index 3208f0a0d..27e4d9b26 100644 --- a/scripts/tests/e2/ships.lua +++ b/scripts/tests/e2/ships.lua @@ -75,3 +75,92 @@ function test_speedy_ship_fast() process_orders() assert_equal(8, u1.region.x) end + +function test_ship_convoy_capacity() + local r1 = region.create(1, 0, 'ocean') + local r2 = region.create(2, 0, 'ocean') + local f = faction.create("human") + local u = unit.create(f, r1, 1) + + u:add_order('NACH O') + u:set_skill('sailing', 2, true) + u:add_item('jewel', 40) + u.ship = ship.create(r1, 'boat') + assert_equal(1, u.ship.number) + process_orders() + u:clear_orders() + assert_equal(r2, u.region) + + u:add_order('NACH W') + u:add_item('jewel', 1) + u:set_skill('sailing', 2, true) + process_orders() + u:clear_orders() + assert_equal(r2, u.region) -- too heavy + + u:add_order('NACH W') + u:add_item('jewel', 39) + u.name = 'Xolgrim' + u.ship.number = 2 + u.number = 2 + u:set_skill('sailing', 2, true) + process_orders() + u:clear_orders() + assert_equal(r1, u.region) -- double capacity + + u:add_order('NACH O') + u.ship.number = 2 + u.name = 'Bolgrim' + u:add_item('jewel', 1) -- too heavy again + u:set_skill('sailing', 2, true) + process_orders() + u:clear_orders() + assert_equal(r1, u.region) +end + +function test_ship_convoy_crew() + local r1 = region.create(1, 0, 'ocean') + local r2 = region.create(2, 0, 'ocean') + local f = faction.create("human") + local u = unit.create(f, r1, 1) + u.ship = ship.create(r1, 'boat') + u.ship.number = 2 + + u:set_skill('sailing', 4, true) + u:add_order('NACH O') + process_orders() + u:clear_orders() + assert_equal(r1, u.region) -- not enough captains + + u.number = 2 + u:set_skill('sailing', 2, true) + u:add_order('NACH O') + process_orders() + u:clear_orders() + assert_equal(r2, u.region) +end + +function test_ship_convoy_skill() + local r1 = region.create(1, 0, 'ocean') + local r2 = region.create(2, 0, 'ocean') + local r3 = region.create(3, 0, 'ocean') + local f = faction.create("human") + local u = unit.create(f, r1, 1) + + u:set_skill('sailing', 2, true) + u.ship = ship.create(r1, 'boat') + assert_equal(1, u.ship.number) + u:add_order('NACH O') + process_orders() + assert_equal(r2, u.region) + + u.ship.number = 2 + u:set_skill('sailing', 2, true) + process_orders() + assert_equal(r2, u.region) + + u.number = 2 + u:set_skill('sailing', 2, true) + process_orders() + assert_equal(r3, u.region) +end diff --git a/src/bind_ship.c b/src/bind_ship.c index d335d996d..6711b0370 100644 --- a/src/bind_ship.c +++ b/src/bind_ship.c @@ -38,39 +38,55 @@ int tolua_shiplist_next(lua_State * L) return 0; /* no more values to return */ } +static int tolua_ship_get_number(lua_State * L) +{ + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + lua_pushinteger(L, sh->number); + return 1; +} + +static int tolua_ship_set_number(lua_State * L) +{ + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + int n = (int)tolua_tonumber(L, 2, 0); + sh->number = n; + sh->size += sh->type->construction->maxsize; + return 0; +} + static int tolua_ship_get_id(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - lua_pushinteger(L, self->no); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + lua_pushinteger(L, sh->no); return 1; } static int tolua_ship_get_name(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - tolua_pushstring(L, ship_getname(self)); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + tolua_pushstring(L, ship_getname(sh)); return 1; } static int tolua_ship_get_size(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - lua_pushinteger(L, self->size); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + lua_pushinteger(L, sh->size); return 1; } static int tolua_ship_get_display(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - tolua_pushstring(L, self->display); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + tolua_pushstring(L, sh->display); return 1; } static int tolua_ship_get_region(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - if (self) { - tolua_pushusertype(L, self->region, TOLUA_CAST "region"); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + if (sh) { + tolua_pushusertype(L, sh->region, TOLUA_CAST "region"); return 1; } return 0; @@ -78,43 +94,43 @@ static int tolua_ship_get_region(lua_State * L) static int tolua_ship_set_region(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); region *r = (region *)tolua_tousertype(L, 2, NULL); - if (self) { - move_ship(self, self->region, r, NULL); + if (sh) { + move_ship(sh, sh->region, r, NULL); } return 0; } static int tolua_ship_set_name(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - ship_setname(self, tolua_tostring(L, 2, NULL)); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + ship_setname(sh, tolua_tostring(L, 2, NULL)); return 0; } static int tolua_ship_set_size(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - self->size = lua_tointeger(L, 2); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + sh->size = lua_tointeger(L, 2); return 0; } static int tolua_ship_set_display(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - free(self->display); - self->display = str_strdup(tolua_tostring(L, 2, NULL)); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + free(sh->display); + sh->display = str_strdup(tolua_tostring(L, 2, NULL)); return 0; } static int tolua_ship_get_units(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); unit **unit_ptr = (unit **)lua_newuserdata(L, sizeof(unit *)); - unit *u = self->region->units; + unit *u = sh->region->units; - while (u && u->ship != self) + while (u && u->ship != sh) u = u->next; luaL_getmetatable(L, TOLUA_CAST "unit"); lua_setmetatable(L, -2); @@ -147,42 +163,42 @@ static int tolua_ship_create(lua_State * L) static int tolua_ship_tostring(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - lua_pushstring(L, shipname(self)); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + lua_pushstring(L, shipname(sh)); return 1; } static int tolua_ship_get_flags(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - lua_pushinteger(L, self->flags); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + lua_pushinteger(L, sh->flags); return 1; } static int tolua_ship_set_flags(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - self->flags = (int)lua_tointeger(L, 2); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + sh->flags = (int)lua_tointeger(L, 2); return 0; } static int tolua_ship_set_coast(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); if (lua_isnil(L, 2)) { - self->coast = NODIRECTION; + sh->coast = NODIRECTION; } else if (lua_isnumber(L, 2)) { - self->coast = (direction_t)lua_tointeger(L, 2); + sh->coast = (direction_t)lua_tointeger(L, 2); } return 0; } static int tolua_ship_get_coast(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - if (self->coast) { - lua_pushinteger(L, self->coast); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + if (sh->coast) { + lua_pushinteger(L, sh->coast); return 1; } return 0; @@ -190,30 +206,30 @@ static int tolua_ship_get_coast(lua_State * L) static int tolua_ship_get_type(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - tolua_pushstring(L, self->type->_name); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + tolua_pushstring(L, sh->type->_name); return 1; } static int tolua_ship_get_damage(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - lua_pushinteger(L, self->damage); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + lua_pushinteger(L, sh->damage); return 1; } static int tolua_ship_set_damage(lua_State * L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); - self->damage = (int)lua_tointeger(L, 2); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); + sh->damage = (int)lua_tointeger(L, 2); return 0; } static int tolua_ship_get_curse(lua_State *L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); const char *name = tolua_tostring(L, 2, NULL); - if (self->attribs) { - curse * c = get_curse(self->attribs, ct_find(name)); + if (sh->attribs) { + curse * c = get_curse(sh->attribs, ct_find(name)); if (c) { lua_pushnumber(L, curse_geteffect(c)); return 1; @@ -223,9 +239,9 @@ static int tolua_ship_get_curse(lua_State *L) { } static int tolua_ship_has_attrib(lua_State *L) { - ship *self = (ship *)tolua_tousertype(L, 1, NULL); + ship *sh = (ship *)tolua_tousertype(L, 1, NULL); const char *name = tolua_tostring(L, 2, NULL); - attrib * a = a_find(self->attribs, at_find(name)); + attrib * a = a_find(sh->attribs, at_find(name)); lua_pushboolean(L, a != NULL); return 1; } @@ -243,6 +259,7 @@ void tolua_ship_open(lua_State * L) { tolua_function(L, TOLUA_CAST "__tostring", tolua_ship_tostring); tolua_variable(L, TOLUA_CAST "id", tolua_ship_get_id, NULL); + tolua_variable(L, TOLUA_CAST "number", tolua_ship_get_number, tolua_ship_set_number); tolua_variable(L, TOLUA_CAST "name", tolua_ship_get_name, tolua_ship_set_name); tolua_variable(L, TOLUA_CAST "size", tolua_ship_get_size, diff --git a/src/bind_unit.c b/src/bind_unit.c index 45b4d7d0a..28e24e85b 100644 --- a/src/bind_unit.c +++ b/src/bind_unit.c @@ -884,9 +884,19 @@ static int tolua_unit_create(lua_State * L) const char *rcname = tolua_tostring(L, 4, NULL); const race *rc; - assert(f && r); + if (!r) { + log_warning("unit.create: arg(2) is not a region"); + return 0; + } + if (!f) { + log_warning("unit.create: arg(1) is not a faction"); + return 0; + } rc = rcname ? rc_find(rcname) : f->race; - assert(rc); + if (!rc) { + log_warning("unit.create: unknown race %s", rcname); + return 0; + } u = create_unit(r, f, num, rc, 0, NULL, NULL); tolua_pushusertype(L, u, TOLUA_CAST "unit"); return 1; diff --git a/src/creport.c b/src/creport.c index 72bca8c70..4a5188108 100644 --- a/src/creport.c +++ b/src/creport.c @@ -515,7 +515,9 @@ static void report_crtypes(FILE * F, const struct locale *lang) fputc('\"', F); fputs(crescape(nrt_string(kmt->mtype, lang), buffer, sizeof(buffer)), F); fputs("\";text\n", F); - fprintf(F, "\"%s\";section\n", kmt->mtype->section); + if (kmt->mtype->section) { + fprintf(F, "\"%s\";section\n", kmt->mtype->section); + } } while (mtypehash[i]) { kmt = mtypehash[i]; @@ -695,6 +697,7 @@ static void cr_output_ship(struct stream *out, const ship *sh, const unit *u, stream_printf(out, "\"%s\";Beschr\n", sh->display); stream_printf(out, "\"%s\";Typ\n", translate(sh->type->_name, LOC(f->locale, sh->type->_name))); + stream_printf(out, "%d;Anzahl\n", sh->number); stream_printf(out, "%d;Groesse\n", sh->size); if (sh->damage) { int percent = @@ -710,7 +713,7 @@ static void cr_output_ship(struct stream *out, const ship *sh, const unit *u, /* calculate cargo */ if (u && (u->faction == f || omniscient(f))) { int n = 0, p = 0; - int mweight = shipcapacity(sh); + int mweight = ship_capacity(sh); getshipweight(sh, &n, &p); stream_printf(out, "%d;capacity\n", mweight); diff --git a/src/kernel/save.c b/src/kernel/save.c index 2774f3401..a65dda7e1 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1283,6 +1283,7 @@ void write_ship(gamedata *data, const ship *sh) WRITE_STR(store, (const char *)sh->name); WRITE_STR(store, sh->display ? (const char *)sh->display : ""); WRITE_TOK(store, sh->type->_name); + assert(sh->number > 0); WRITE_INT(store, sh->number); WRITE_INT(store, sh->size); WRITE_INT(store, sh->damage); diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 6d458843e..67b98d37c 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -181,6 +181,7 @@ ship *new_ship(const ship_type * stype, region * r, const struct locale *lang) sh->coast = NODIRECTION; sh->type = stype; sh->region = r; + sh->number = 1; if (lang) { sname = LOC(lang, stype->_name); @@ -275,13 +276,13 @@ static int ShipSpeedBonus(const unit * u) } if (bonus > 0) { int skl = effskill(u, SK_SAILING, NULL); - int minsk = (sh->type->cptskill + 1) / 2; + int minsk = (ship_captain_minskill(sh) + 1) / 2; return (skl - minsk) / bonus; } else if (sh->type->flags & SFL_SPEEDY) { int base = 3; int speed = 0; - int minsk = sh->type->cptskill * base; + int minsk = ship_captain_minskill(sh) * base; int skl = effskill(u, SK_SAILING, NULL); while (skl >= minsk) { ++speed; @@ -292,21 +293,8 @@ static int ShipSpeedBonus(const unit * u) 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) { - int es = effskill(u, SK_SAILING, NULL); - if (es >= sh->type->minskill) { - n += es * u->number; - } - } - } - return n; +int ship_captain_minskill(const ship *sh) { + return sh->type->cptskill; } int shipspeed(const ship * sh, const unit * u) @@ -323,8 +311,9 @@ int shipspeed(const ship * sh, const unit * u) assert(sh->type->construction); k = sh->type->range; - if (sh->size != sh->type->construction->maxsize) + if (!ship_finished(sh)) { return 0; + } if (sh->attribs) { if (curse_active(get_curse(sh->attribs, &ct_stormwind))) { @@ -343,7 +332,7 @@ int shipspeed(const ship * sh, const unit * u) bonus = ShipSpeedBonus(u); if (bonus > 0 && sh->type->range_max > sh->type->range) { - int crew = crew_skill(sh); + int crew = crew_skill(sh, NULL); int crew_bonus = (crew / sh->type->sumskill / 2) - 1; if (crew_bonus > 0) { int sbonus = sh->type->range_max - sh->type->range; @@ -385,17 +374,68 @@ const char *shipname(const ship * sh) return write_shipname(sh, ibuf, sizeof(idbuf[0])); } -int shipcapacity(const ship * sh) +bool ship_finished(const ship *sh) { - int i = sh->type->cargo; - - if (sh->type->construction && sh->size < sh->number * sh->type->construction->maxsize) - return 0; - - if (sh->damage) { - i = (int)ceil(i * (1.0 - sh->damage / sh->size / (double)DAMAGE_SCALE)); + if (sh->type->construction) { + return (sh->size >= sh->number * sh->type->construction->maxsize); } - return i; + return true; +} + +int enoughsailors(const ship * sh, int crew_skill) +{ + return crew_skill >= sh->type->sumskill * sh->number; +} + +int crew_skill(const ship *sh, int *o_captains) { + int n = 0, captains = 0; + unit *u; + + for (u = sh->region->units; u; u = u->next) { + if (u->ship == sh) { + int es = effskill(u, SK_SAILING, NULL); + if (es >= sh->type->cptskill) { + captains += u->number; + } + if (es >= sh->type->minskill) { + n += es * u->number; + } + } + } + if (o_captains) { + *o_captains = captains; + } + return n; +} + +bool ship_crewed(const ship *sh) +{ + int num_caps, crew = crew_skill(sh, &num_caps); + return num_caps >= sh->number && enoughsailors(sh, crew); +} + +int ship_capacity(const ship * sh) +{ + if (ship_finished(sh)) { + int i = sh->type->cargo * sh->number; + if (sh->damage) { + i = (int)ceil(i * (1.0 - sh->damage / sh->size / (double)DAMAGE_SCALE)); + } + return i; + } + return 0; +} + +int ship_cabins(const ship * sh) +{ + if (ship_finished(sh)) { + int i = sh->type->cabins * sh->number; + if (sh->damage) { + i = (int)ceil(i * (1.0 - sh->damage / sh->size / (double)DAMAGE_SCALE)); + } + return i; + } + return 0; } void getshipweight(const ship * sh, int *sweight, int *scabins) diff --git a/src/kernel/ship.h b/src/kernel/ship.h index 6c4e0bf95..b82a69140 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -90,8 +90,10 @@ extern "C" { struct unit *ship_owner(const struct ship *sh); void ship_update_owner(struct ship * sh); - extern const char *shipname(const struct ship *self); - extern int shipcapacity(const struct ship *sh); + const char *shipname(const struct ship *self); + int ship_capacity(const struct ship *sh); + int ship_cabins(const struct ship *sh); + bool ship_finished(const struct ship *sh); extern void getshipweight(const struct ship *sh, int *weight, int *cabins); extern ship *new_ship(const struct ship_type *stype, struct region *r, @@ -114,7 +116,10 @@ extern "C" { const char *ship_getname(const struct ship *sh); void ship_setname(struct ship *self, const char *name); int shipspeed(const struct ship *sh, const struct unit *u); - int crew_skill(const struct ship *sh); + + bool ship_crewed(const struct ship *sh); + int crew_skill(const struct ship *sh, int *num_captains); + int ship_captain_minskill(const struct ship *sh); int ship_damage_percent(const struct ship *sh); #ifdef __cplusplus diff --git a/src/kernel/ship.test.c b/src/kernel/ship.test.c index 062e7cd20..18d8a1754 100644 --- a/src/kernel/ship.test.c +++ b/src/kernel/ship.test.c @@ -641,21 +641,21 @@ static void test_crew_skill(CuTest *tc) { CuAssertIntEquals(tc, 1, stype->minskill); r = test_create_ocean(0, 0); sh = test_create_ship(r, stype); - CuAssertIntEquals(tc, 0, crew_skill(sh)); + CuAssertIntEquals(tc, 0, crew_skill(sh, NULL)); u = test_create_unit(test_create_faction(NULL), r); set_level(u, SK_SAILING, 1); - CuAssertIntEquals(tc, 0, crew_skill(sh)); + CuAssertIntEquals(tc, 0, crew_skill(sh, NULL)); u_set_ship(u, sh); set_level(u, SK_SAILING, 1); - CuAssertIntEquals(tc, 1, crew_skill(sh)); + CuAssertIntEquals(tc, 1, crew_skill(sh, NULL)); set_number(u, 10); - CuAssertIntEquals(tc, 10, crew_skill(sh)); + CuAssertIntEquals(tc, 10, crew_skill(sh, NULL)); stype->minskill = 2; - CuAssertIntEquals(tc, 0, crew_skill(sh)); + CuAssertIntEquals(tc, 0, crew_skill(sh, NULL)); set_level(u, SK_SAILING, 2); - CuAssertIntEquals(tc, 20, crew_skill(sh)); + CuAssertIntEquals(tc, 20, crew_skill(sh, NULL)); set_level(u, SK_SAILING, 3); - CuAssertIntEquals(tc, 30, crew_skill(sh)); + CuAssertIntEquals(tc, 30, crew_skill(sh, NULL)); test_teardown(); } diff --git a/src/laws.c b/src/laws.c index 50d364660..61262b75d 100644 --- a/src/laws.c +++ b/src/laws.c @@ -1094,8 +1094,8 @@ int enter_ship(unit * u, struct order *ord, int id, bool report) } if (CheckOverload()) { int sweight, scabins; - int mweight = shipcapacity(sh); - int mcabins = sh->type->cabins; + int mweight = ship_capacity(sh); + int mcabins = ship_cabins(sh); if (mweight > 0) { getshipweight(sh, &sweight, &scabins); @@ -2598,7 +2598,7 @@ void sinkships(struct region * r) if (!sh->type->construction || sh->size >= sh->type->construction->maxsize) { if (fval(r->terrain, SEA_REGION)) { - if (!enoughsailors(sh, crew_skill(sh))) { + if (!ship_crewed(sh)) { /* ship is at sea, but not enough people to control it */ double dmg = config_get_flt("rules.ship.damage.nocrewocean", 0.3); damage_ship(sh, dmg); diff --git a/src/move.c b/src/move.c index a5438eb3d..484ee993f 100644 --- a/src/move.c +++ b/src/move.c @@ -470,13 +470,13 @@ static bool cansail(const region * r, ship * sh) { UNUSED_ARG(r); - if (sh->type->construction && sh->size != sh->type->construction->maxsize) { + if (!ship_finished(sh)) { return false; } else { int n = 0, p = 0; - int mweight = shipcapacity(sh); - int mcabins = sh->type->cabins; + int mweight = ship_capacity(sh); + int mcabins = ship_cabins(sh); getshipweight(sh, &n, &p); @@ -492,12 +492,12 @@ static double overload(const region * r, ship * sh) { UNUSED_ARG(r); - if (sh->type->construction && sh->size != sh->type->construction->maxsize) { + if (!ship_finished(sh)) { return DBL_MAX; } else { int n = 0, p = 0; - int mcabins = sh->type->cabins; + int mcabins = sh->type->cabins * sh->number; double ovl; getshipweight(sh, &n, &p); @@ -509,11 +509,6 @@ static double overload(const region * r, ship * sh) } } -int enoughsailors(const ship * sh, int crew_skill) -{ - return crew_skill >= sh->type->sumskill; -} - /* ------------------------------------------------------------- */ static ship *do_maelstrom(region * r, unit * u) @@ -808,7 +803,7 @@ static void drifting_ships(region * r) ship *sh = *shp; region *rnext = NULL; region_list *route = NULL; - unit *firstu = r->units, *lastu = NULL, *captain; + unit *firstu = r->units, *lastu = NULL; direction_t dir = NODIRECTION; double ovl; @@ -822,16 +817,10 @@ static void drifting_ships(region * r) continue; } - /* Kapitaen bestimmen */ - captain = ship_owner(sh); - if (captain && effskill(captain, SK_SAILING, r) < sh->type->cptskill) - captain = NULL; - /* Kapitaen da? Beschaedigt? Genuegend Matrosen? * Genuegend leicht? Dann ist alles OK. */ - if (captain && sh->size == sh->type->construction->maxsize - && enoughsailors(sh, crew_skill(sh)) && cansail(r, sh)) { + if (ship_finished(sh) && ship_crewed(sh) && cansail(r, sh)) { shp = &sh->next; continue; } @@ -1639,19 +1628,17 @@ static bool ship_ready(const region * r, unit * u, order * ord) cmistake(u, ord, 146, MSG_MOVE); return false; } - if (effskill(u, SK_SAILING, r) < u->ship->type->cptskill) { + if (effskill(u, SK_SAILING, r) < ship_captain_minskill(u->ship)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, - "error_captain_skill_low", "value ship", u->ship->type->cptskill, + "error_captain_skill_low", "value ship", ship_captain_minskill(u->ship), u->ship)); return false; } - if (u->ship->type->construction) { - if (u->ship->size != u->ship->type->construction->maxsize) { - cmistake(u, ord, 15, MSG_MOVE); - return false; - } + if (!ship_finished(u->ship)) { + cmistake(u, ord, 15, MSG_MOVE); + return false; } - if (!enoughsailors(u->ship, crew_skill(u->ship))) { + if (!ship_crewed(u->ship)) { cmistake(u, ord, 1, MSG_MOVE); return false; } diff --git a/src/move.h b/src/move.h index cbf154694..4362091b2 100644 --- a/src/move.h +++ b/src/move.h @@ -53,7 +53,6 @@ extern "C" { int personcapacity(const struct unit *u); void movement(void); - void run_to(struct unit *u, struct region *to); int enoughsailors(const struct ship *sh, int sumskill); bool canswim(struct unit *u); bool canfly(struct unit *u); diff --git a/src/report.c b/src/report.c index c69ddcdab..63886096e 100644 --- a/src/report.c +++ b/src/report.c @@ -1728,7 +1728,7 @@ nr_ship(struct stream *out, const region *r, const ship * sh, const faction * f, n = (n + 99) / 100; /* 1 Silber = 1 GE */ sbs_printf(&sbs, "%s, %s, (%d/%d)", shipname(sh), - LOC(f->locale, sh->type->_name), n, shipcapacity(sh) / 100); + LOC(f->locale, sh->type->_name), n, ship_capacity(sh) / 100); } else { sbs_printf(&sbs, "%s, %s", shipname(sh), LOC(f->locale, sh->type->_name)); From 5cf417d16d96e3c15f9f813dcea2ec9293ac59f2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Oct 2019 20:22:19 +0200 Subject: [PATCH 03/13] must have one captain per ship. --- scripts/tests/e2/ships.lua | 7 +++---- src/kernel/ship.c | 36 +++++++++++++++++++++++------------- src/kernel/ship.h | 2 +- src/kernel/ship.test.c | 14 +++++++------- 4 files changed, 34 insertions(+), 25 deletions(-) diff --git a/scripts/tests/e2/ships.lua b/scripts/tests/e2/ships.lua index 27e4d9b26..ad4e3656c 100644 --- a/scripts/tests/e2/ships.lua +++ b/scripts/tests/e2/ships.lua @@ -100,7 +100,6 @@ function test_ship_convoy_capacity() u:add_order('NACH W') u:add_item('jewel', 39) - u.name = 'Xolgrim' u.ship.number = 2 u.number = 2 u:set_skill('sailing', 2, true) @@ -146,7 +145,7 @@ function test_ship_convoy_skill() local r3 = region.create(3, 0, 'ocean') local f = faction.create("human") local u = unit.create(f, r1, 1) - + u:set_skill('sailing', 2, true) u.ship = ship.create(r1, 'boat') assert_equal(1, u.ship.number) @@ -155,9 +154,9 @@ function test_ship_convoy_skill() assert_equal(r2, u.region) u.ship.number = 2 - u:set_skill('sailing', 2, true) + u:set_skill('sailing', 4, true) process_orders() - assert_equal(r2, u.region) + assert_equal(r2, u.region) -- not enough captains u.number = 2 u:set_skill('sailing', 2, true) diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 67b98d37c..ca2da27b9 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -332,7 +332,7 @@ int shipspeed(const ship * sh, const unit * u) bonus = ShipSpeedBonus(u); if (bonus > 0 && sh->type->range_max > sh->type->range) { - int crew = crew_skill(sh, NULL); + int crew = crew_skill(sh); int crew_bonus = (crew / sh->type->sumskill / 2) - 1; if (crew_bonus > 0) { int sbonus = sh->type->range_max - sh->type->range; @@ -387,31 +387,41 @@ int enoughsailors(const ship * sh, int crew_skill) return crew_skill >= sh->type->sumskill * sh->number; } -int crew_skill(const ship *sh, int *o_captains) { - int n = 0, captains = 0; +int crew_skill(const ship *sh) { + int n = 0; unit *u; for (u = sh->region->units; u; u = u->next) { if (u->ship == sh) { int es = effskill(u, SK_SAILING, NULL); - if (es >= sh->type->cptskill) { - captains += u->number; - } if (es >= sh->type->minskill) { n += es * u->number; } } } - if (o_captains) { - *o_captains = captains; - } return n; } -bool ship_crewed(const ship *sh) -{ - int num_caps, crew = crew_skill(sh, &num_caps); - return num_caps >= sh->number && enoughsailors(sh, crew); +bool ship_crewed(const ship *sh) { + unit *u; + int capskill = -1, sumskill = 0; + for (u = sh->region->units; u; u = u->next) { + if (u->ship == sh) { + int es = effskill(u, SK_SAILING, NULL); + if (capskill < 0) { + if (u->number >= sh->number) { + capskill = es; + } + else { + capskill = 0; + } + } + if (es >= sh->type->minskill) { + sumskill += es * u->number; + } + } + } + return (capskill >= ship_captain_minskill(sh)) && (sumskill >= sh->type->sumskill * sh->number); } int ship_capacity(const ship * sh) diff --git a/src/kernel/ship.h b/src/kernel/ship.h index b82a69140..34230f55b 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -118,7 +118,7 @@ extern "C" { int shipspeed(const struct ship *sh, const struct unit *u); bool ship_crewed(const struct ship *sh); - int crew_skill(const struct ship *sh, int *num_captains); + int crew_skill(const struct ship *sh); int ship_captain_minskill(const struct ship *sh); int ship_damage_percent(const struct ship *sh); diff --git a/src/kernel/ship.test.c b/src/kernel/ship.test.c index 18d8a1754..062e7cd20 100644 --- a/src/kernel/ship.test.c +++ b/src/kernel/ship.test.c @@ -641,21 +641,21 @@ static void test_crew_skill(CuTest *tc) { CuAssertIntEquals(tc, 1, stype->minskill); r = test_create_ocean(0, 0); sh = test_create_ship(r, stype); - CuAssertIntEquals(tc, 0, crew_skill(sh, NULL)); + CuAssertIntEquals(tc, 0, crew_skill(sh)); u = test_create_unit(test_create_faction(NULL), r); set_level(u, SK_SAILING, 1); - CuAssertIntEquals(tc, 0, crew_skill(sh, NULL)); + CuAssertIntEquals(tc, 0, crew_skill(sh)); u_set_ship(u, sh); set_level(u, SK_SAILING, 1); - CuAssertIntEquals(tc, 1, crew_skill(sh, NULL)); + CuAssertIntEquals(tc, 1, crew_skill(sh)); set_number(u, 10); - CuAssertIntEquals(tc, 10, crew_skill(sh, NULL)); + CuAssertIntEquals(tc, 10, crew_skill(sh)); stype->minskill = 2; - CuAssertIntEquals(tc, 0, crew_skill(sh, NULL)); + CuAssertIntEquals(tc, 0, crew_skill(sh)); set_level(u, SK_SAILING, 2); - CuAssertIntEquals(tc, 20, crew_skill(sh, NULL)); + CuAssertIntEquals(tc, 20, crew_skill(sh)); set_level(u, SK_SAILING, 3); - CuAssertIntEquals(tc, 30, crew_skill(sh, NULL)); + CuAssertIntEquals(tc, 30, crew_skill(sh)); test_teardown(); } From 39e3001a5062ad9670e04fdbad28982f5d584300 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 6 Oct 2019 20:42:47 +0200 Subject: [PATCH 04/13] start implementing give_ship --- scripts/tests/e2/ships.lua | 27 +++++++++++++++++++++++++++ src/give.c | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/scripts/tests/e2/ships.lua b/scripts/tests/e2/ships.lua index ad4e3656c..a50182c0d 100644 --- a/scripts/tests/e2/ships.lua +++ b/scripts/tests/e2/ships.lua @@ -163,3 +163,30 @@ function test_ship_convoy_skill() process_orders() assert_equal(r3, u.region) end + +function test_give_ship() + local r = region.create(1, 0, 'ocean') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1.ship = ship.create(r, 'boat') + u1.ship.number = 2 + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") + process_orders() + assert_equal(1, u1.ship.number) + assert_equal(1, u2.ship.number) +end + +function test_give_ship_merge() + local r = region.create(1, 0, 'ocean') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u2.ship = ship.create(r, 'boat') + u1.ship = ship.create(r, 'boat') + u1.ship.number = 2 + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") + process_orders() + assert_equal(1, u1.ship.number) + assert_equal(2, u2.ship.number) +end diff --git a/src/give.c b/src/give.c index ba04e69a6..036a7ae04 100644 --- a/src/give.c +++ b/src/give.c @@ -293,6 +293,14 @@ bool rule_transfermen(void) return rule != 0; } +message * give_ship(unit *u, unit *u2, int n, order *ord) { + assert(u->ship); + if (u->ship->number < n) { + n = u->ship->number; + } + return NULL; +} + message * give_men(int n, unit * u, unit * u2, struct order *ord) { int error = 0; @@ -652,7 +660,19 @@ static void give_all_items(unit *u, unit *u2, order *ord) { } } else { - if (isparam(s, u->faction->locale, P_PERSON)) { + param_t p = findparam(s, u->faction->locale); + if (p == P_SHIP) { + if (u->ship) { + message * msg = give_ship(u, u2, u->ship->number, ord); + if (msg) { + ADDMSG(&u->faction->msgs, msg); + } + } + else { + cmistake(u, ord, 144, MSG_COMMERCE); + } + } + else if (p == P_PERSON) { if (!(u_race(u)->ec_flags & ECF_GIVEPERSON)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); @@ -815,7 +835,19 @@ void give_cmd(unit * u, order * ord) return; } - if (isparam(s, u->faction->locale, P_PERSON)) { + p = findparam(s, u->faction->locale); + if (p == P_SHIP) { + if (u->ship) { + message * msg = give_ship(u, u2, n, ord); + if (msg) { + ADDMSG(&u->faction->msgs, msg); + } + } + else { + cmistake(u, ord, 144, MSG_COMMERCE); + } + } + else if (p == P_PERSON) { if (!(u_race(u)->ec_flags & ECF_GIVEPERSON)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); From f4011af7843aa823df7b1d7b67e74e92c346c715 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 7 Oct 2019 21:45:49 +0200 Subject: [PATCH 05/13] GIB unit n SCHIFF implementiert. --- res/translations/messages.de.po | 6 ++++ scripts/tests/e2/ships.lua | 35 ++++++++++++++++++++++ src/bind_ship.c | 3 +- src/give.c | 53 ++++++++++++++++++++++++--------- src/kernel/build.c | 3 +- src/kernel/ship.c | 7 +++++ src/kernel/ship.h | 1 + 7 files changed, 90 insertions(+), 18 deletions(-) diff --git a/res/translations/messages.de.po b/res/translations/messages.de.po index 776a1e207..759f41ed1 100644 --- a/res/translations/messages.de.po +++ b/res/translations/messages.de.po @@ -2768,6 +2768,12 @@ msgstr "\"$unit($unit) verspeiste $int($amount) Bauern.\"" msgid "error320" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht bewachen, da sie versucht zu fliehen.\"" +msgid "error321" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit gehört nicht zu unserer Partei.\"" + +msgid "error322" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit ist bereits auf einem Schiff.\"" + msgid "dissolve_units_2" msgstr "\"$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),\"wurde zum Baum\", \"wurden zu Bäumen\").\"" diff --git a/scripts/tests/e2/ships.lua b/scripts/tests/e2/ships.lua index a50182c0d..1e101b5b2 100644 --- a/scripts/tests/e2/ships.lua +++ b/scripts/tests/e2/ships.lua @@ -190,3 +190,38 @@ function test_give_ship_merge() assert_equal(1, u1.ship.number) assert_equal(2, u2.ship.number) end + +function test_give_ship_max() + local r = region.create(1, 0, 'plain') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + local sh = ship.create(r, 'boat') + sh.number = 3 + sh.damage = 9 + sh.size = 12 + u1.ship = sh + u1:add_order("GIB " .. itoa36(u2.id) .. " 4 SCHIFF") + process_orders() + assert_equal(1, u1.ship.number) + assert_equal(3, u1.ship.damage) + assert_equal(4, u1.ship.size) + assert_equal(2, u2.ship.number) + assert_equal(6, u2.ship.damage) + assert_equal(8, u2.ship.size) +end + +function test_give_ship_self_only() + local r = region.create(1, 0, 'plain') + local f1 = faction.create("human") + local f2 = faction.create("human") + local u1 = unit.create(f1, r, 1) + local u2 = unit.create(f2, r, 1) + local sh = ship.create(r, 'boat') + sh.number = 2 + u1.ship = sh + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") + process_orders() + assert_equal(2, u1.ship.number) + assert_equal(nil, u2.ship) +end diff --git a/src/bind_ship.c b/src/bind_ship.c index 6711b0370..71b6ae4f4 100644 --- a/src/bind_ship.c +++ b/src/bind_ship.c @@ -49,8 +49,7 @@ static int tolua_ship_set_number(lua_State * L) { ship *sh = (ship *)tolua_tousertype(L, 1, NULL); int n = (int)tolua_tonumber(L, 2, 0); - sh->number = n; - sh->size += sh->type->construction->maxsize; + scale_ship(sh, n); return 0; } diff --git a/src/give.c b/src/give.c index 036a7ae04..52b017448 100644 --- a/src/give.c +++ b/src/give.c @@ -293,8 +293,40 @@ bool rule_transfermen(void) return rule != 0; } -message * give_ship(unit *u, unit *u2, int n, order *ord) { +static void transfer_ships(ship *s1, ship *s2, int n) +{ + assert(n < s1->number); + s2->damage += s1->damage * n / s1->number; + s2->size += s1->size * n / s1->number; + s2->number += n; + scale_ship(s1, s1->number - n); +} + +message * give_ship(unit *u, unit *u2, int n, order *ord) +{ assert(u->ship); + assert(n > 0 && n < u->ship->number); + if (u->faction != u2->faction) { + return msg_error(u, ord, 321); + } + if (u2->ship) { + if (u2->ship->type != u->ship->type) { + return msg_error(u, ord, 322); + } + transfer_ships(u->ship, u2->ship, n); + } + else{ + if (fval(u_race(u2), RCF_CANSAIL)) { + ship * sh = new_ship(u->ship->type, u->region, u->faction->locale); + scale_ship(sh, 0); + u_set_ship(u2, sh); + transfer_ships(u->ship, sh, n); + } + else { + return msg_error(u, ord, 233); + } + + } if (u->ship->number < n) { n = u->ship->number; } @@ -661,18 +693,7 @@ static void give_all_items(unit *u, unit *u2, order *ord) { } else { param_t p = findparam(s, u->faction->locale); - if (p == P_SHIP) { - if (u->ship) { - message * msg = give_ship(u, u2, u->ship->number, ord); - if (msg) { - ADDMSG(&u->faction->msgs, msg); - } - } - else { - cmistake(u, ord, 144, MSG_COMMERCE); - } - } - else if (p == P_PERSON) { + if (p == P_PERSON) { if (!(u_race(u)->ec_flags & ECF_GIVEPERSON)) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); @@ -838,7 +859,11 @@ void give_cmd(unit * u, order * ord) p = findparam(s, u->faction->locale); if (p == P_SHIP) { if (u->ship) { - message * msg = give_ship(u, u2, n, ord); + message * msg; + if (n >= u->ship->number) { + n = u->ship->number - 1; + } + msg = give_ship(u, u2, n, ord); if (msg) { ADDMSG(&u->faction->msgs, msg); } diff --git a/src/kernel/build.c b/src/kernel/build.c index 3a73f8fd5..447db8662 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -932,8 +932,7 @@ static void build_ship(unit * u, ship * sh, int want) msg_message("buildship", "ship unit size", sh, u, n)); } -void -create_ship(unit * u, const struct ship_type *newtype, int want, +void create_ship(unit * u, const struct ship_type *newtype, int want, order * ord) { ship *sh; diff --git a/src/kernel/ship.c b/src/kernel/ship.c index ca2da27b9..1e38257d9 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -424,6 +424,13 @@ bool ship_crewed(const ship *sh) { return (capskill >= ship_captain_minskill(sh)) && (sumskill >= sh->type->sumskill * sh->number); } +void scale_ship(ship *sh, int n) +{ + sh->size = sh->size * n / sh->number; + sh->damage = sh->damage * n / sh->number; + sh->number = n; +} + int ship_capacity(const ship * sh) { if (ship_finished(sh)) { diff --git a/src/kernel/ship.h b/src/kernel/ship.h index 34230f55b..a9a678848 100644 --- a/src/kernel/ship.h +++ b/src/kernel/ship.h @@ -122,6 +122,7 @@ extern "C" { int ship_captain_minskill(const struct ship *sh); int ship_damage_percent(const struct ship *sh); + void scale_ship(struct ship *sh, int n); #ifdef __cplusplus } #endif From 4052cb71ffd804fde7fefd8fea1bdd037ea36e0e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 7 Oct 2019 22:01:02 +0200 Subject: [PATCH 06/13] Show convoy in reports. --- src/creport.c | 2 +- src/report.c | 7 +++++-- src/util/language.c | 13 +++++++++++++ src/util/language.h | 1 + 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/creport.c b/src/creport.c index 4a5188108..46b998066 100644 --- a/src/creport.c +++ b/src/creport.c @@ -84,7 +84,7 @@ static char g_bigbuf[BUFFERSIZE]; bool opt_cr_absolute_coords = false; /* globals */ -#define C_REPORT_VERSION 66 +#define C_REPORT_VERSION 67 struct locale *crtag_locale(void) { static struct locale * lang; diff --git a/src/report.c b/src/report.c index 63886096e..407db00ff 100644 --- a/src/report.c +++ b/src/report.c @@ -1724,11 +1724,14 @@ nr_ship(struct stream *out, const region *r, const ship * sh, const faction * f, if (captain && captain->faction == f) { int n = 0, p = 0; + const char *stname; + getshipweight(sh, &n, &p); n = (n + 99) / 100; /* 1 Silber = 1 GE */ - sbs_printf(&sbs, "%s, %s, (%d/%d)", shipname(sh), - LOC(f->locale, sh->type->_name), n, ship_capacity(sh) / 100); + stname = locale_plural(f->locale, sh->type->_name, sh->number, true); + sbs_printf(&sbs, "%s, %d %s, (%d/%d)", shipname(sh), sh->number, + stname, n, ship_capacity(sh) / 100); } else { sbs_printf(&sbs, "%s, %s", shipname(sh), LOC(f->locale, sh->type->_name)); diff --git a/src/util/language.c b/src/util/language.c index f7894ac4e..f8dac8b39 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -129,6 +129,19 @@ const char *locale_getstring(const locale * lang, const char *key) return NULL; } +const char *locale_plural(const struct locale *lang, const char *key, int n, bool warn) { + assert(lang); + assert(key); + + if (n != 1) { + char plural[32]; + snprintf(plural, 32, "%s_p", key); + plural[31] = '\0'; + return locale_string(lang, plural, warn); + } + return locale_string(lang, key, warn); +} + const char *locale_string(const locale * lang, const char *key, bool warn) { assert(lang); diff --git a/src/util/language.h b/src/util/language.h index fce6bbebd..da1f17817 100644 --- a/src/util/language.h +++ b/src/util/language.h @@ -32,6 +32,7 @@ extern "C" { const char *locale_getstring(const struct locale *lang, const char *key); const char *locale_string(const struct locale *lang, const char *key, bool warn); /* does fallback */ + const char *locale_plural(const struct locale *lang, const char *key, int n, bool warn); unsigned int locale_index(const struct locale *lang); const char *locale_name(const struct locale *lang); From b0e6ed430ba4aace08d147dc43df5453fb55ff9b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 8 Oct 2019 04:52:41 +0200 Subject: [PATCH 07/13] GIB alle Schiffe an andere Einheit. --- scripts/tests/e2/ships.lua | 33 +++++++++++++++++-- src/give.c | 67 +++++++++++++++++++++++++------------- 2 files changed, 75 insertions(+), 25 deletions(-) diff --git a/scripts/tests/e2/ships.lua b/scripts/tests/e2/ships.lua index 1e101b5b2..c71cf9eb3 100644 --- a/scripts/tests/e2/ships.lua +++ b/scripts/tests/e2/ships.lua @@ -191,7 +191,21 @@ function test_give_ship_merge() assert_equal(2, u2.ship.number) end -function test_give_ship_max() +function test_give_ship_only_same() + local r = region.create(1, 0, 'ocean') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u2.ship = ship.create(r, 'boat') + u1.ship = ship.create(r, 'longboat') + u1.ship.number = 2 + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") + process_orders() + assert_equal(2, u1.ship.number) + assert_equal(1, u2.ship.number) +end + +function test_give_ship_scale() local r = region.create(1, 0, 'plain') local f = faction.create("human") local u1 = unit.create(f, r, 1) @@ -201,7 +215,7 @@ function test_give_ship_max() sh.damage = 9 sh.size = 12 u1.ship = sh - u1:add_order("GIB " .. itoa36(u2.id) .. " 4 SCHIFF") + u1:add_order("GIB " .. itoa36(u2.id) .. " 2 SCHIFF") process_orders() assert_equal(1, u1.ship.number) assert_equal(3, u1.ship.damage) @@ -211,6 +225,21 @@ function test_give_ship_max() assert_equal(8, u2.ship.size) end +function test_give_ship_all_ships() + local r = region.create(1, 0, 'plain') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1.ship = ship.create(r, 'boat') + u1.ship.number = 2 + u2.ship = ship.create(r, 'boat') + u2.ship.number = 1 + u1:add_order("GIB " .. itoa36(u2.id) .. " 2 SCHIFF") + process_orders() + assert_equal(3, u2.ship.number) + assert_equal(u2.ship, u1.ship) +end + function test_give_ship_self_only() local r = region.create(1, 0, 'plain') local f1 = faction.create("human") diff --git a/src/give.c b/src/give.c index 52b017448..582532fe1 100644 --- a/src/give.c +++ b/src/give.c @@ -295,40 +295,61 @@ bool rule_transfermen(void) static void transfer_ships(ship *s1, ship *s2, int n) { - assert(n < s1->number); + assert(n <= s1->number); s2->damage += s1->damage * n / s1->number; s2->size += s1->size * n / s1->number; s2->number += n; scale_ship(s1, s1->number - n); } -message * give_ship(unit *u, unit *u2, int n, order *ord) +static void transfer_units(ship *s1, ship *s2) { - assert(u->ship); - assert(n > 0 && n < u->ship->number); - if (u->faction != u2->faction) { - return msg_error(u, ord, 321); - } - if (u2->ship) { - if (u2->ship->type != u->ship->type) { - return msg_error(u, ord, 322); + region * r = s1->region; + unit *u; + for (u = r->units; u; u = u->next) { + if (u->ship == s1) { + leave_ship(u); + u_set_ship(u, s2); } - transfer_ships(u->ship, u2->ship, n); } - else{ - if (fval(u_race(u2), RCF_CANSAIL)) { - ship * sh = new_ship(u->ship->type, u->region, u->faction->locale); - scale_ship(sh, 0); - u_set_ship(u2, sh); - transfer_ships(u->ship, sh, n); +} + +message * give_ship(unit *u1, unit *u2, int n, order *ord) +{ + assert(u1->ship); + assert(n > 0 && n <= u1->ship->number); + if (u1->faction != u2->faction) { + return msg_error(u1, ord, 321); + } + /* TODO: when transferring all ships, unit must hop on the target ship */ + if (u2->ship) { + if (n < u1->ship->number) { + if (u2->ship->type != u1->ship->type) { + return msg_error(u1, ord, 322); + } + transfer_ships(u1->ship, u2->ship, n); } else { - return msg_error(u, ord, 233); + transfer_ships(u1->ship, u2->ship, n); + transfer_units(u1->ship, u2->ship); } - } - if (u->ship->number < n) { - n = u->ship->number; + else { + if (fval(u_race(u2), RCF_CANSAIL)) { + if (n < u1->ship->number) { + ship * sh = new_ship(u1->ship->type, u1->region, u1->faction->locale); + scale_ship(sh, 0); + u_set_ship(u2, sh); + transfer_ships(u1->ship, sh, n); + } + else { + u_set_ship(u2, u1->ship); + ship_set_owner(u2); + } + } + else { + return msg_error(u1, ord, 233); + } } return NULL; } @@ -860,8 +881,8 @@ void give_cmd(unit * u, order * ord) if (p == P_SHIP) { if (u->ship) { message * msg; - if (n >= u->ship->number) { - n = u->ship->number - 1; + if (n > u->ship->number) { + n = u->ship->number; } msg = give_ship(u, u2, n, ord); if (msg) { From 43094e8bf95fa37d1adde898e6837e83635e641f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 8 Oct 2019 05:15:23 +0200 Subject: [PATCH 08/13] plural strings for ships. --- res/translations/strings.de.po | 24 ++++++++++++++++++++++++ res/translations/strings.en.po | 21 +++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/res/translations/strings.de.po b/res/translations/strings.de.po index e6931c344..1351c3d05 100644 --- a/res/translations/strings.de.po +++ b/res/translations/strings.de.po @@ -389,6 +389,9 @@ msgstr "Schaffenstrunk" msgid "balloon_a" msgstr "ein Ballon" +msgid "balloon_p" +msgstr "Ballons" + msgid "undead_name_8" msgstr "Monster" @@ -1115,6 +1118,9 @@ msgstr "Orks" msgid "boat_a" msgstr "ein Boot" +msgid "boat_p" +msgstr "Boote" + msgctxt "race" msgid "nymph" msgstr "Nymphe" @@ -1719,9 +1725,15 @@ msgstr "Ring der Unsichtbarkeit" msgid "caravel_a" msgstr "eine Karavelle" +msgid "caravel_p" +msgstr "Karavellen" + msgid "galleon_a" msgstr "eine Galeone" +msgid "galleon_p" +msgstr "Galeonen" + msgctxt "keyword" msgid "describe" msgstr "BESCHREIBE" @@ -1895,6 +1907,9 @@ msgstr "Untoten" msgid "flyingcarpet_a" msgstr "ein fliegender Teppich" +msgid "flyingcarpet_p" +msgstr "fliegende Teppiche" + msgid "mallorntree_p" msgstr "Mallorn" @@ -2806,6 +2821,9 @@ msgstr "Fjordwuchs" msgid "trireme_a" msgstr "eine Trireme" +msgid "trireme_p" +msgstr "Triremen" + msgctxt "prefix" msgid "Dunkel" msgstr "Dunkel" @@ -4112,6 +4130,9 @@ msgstr "Luchs" msgid "longboat_a" msgstr "ein Langboot" +msgid "longboat_p" +msgstr "Langboote" + msgctxt "race" msgid "human_d" msgstr "Menschen" @@ -5858,6 +5879,9 @@ msgstr "Tiger" msgid "dragonship_a" msgstr "ein Drachenschiff" +msgid "dragonship_p" +msgstr "Drachenschiffe" + msgctxt "race" msgid "mountainguard_x" msgstr "Bergwächter" diff --git a/res/translations/strings.en.po b/res/translations/strings.en.po index 36020a3f6..0eb8d3a37 100644 --- a/res/translations/strings.en.po +++ b/res/translations/strings.en.po @@ -303,6 +303,9 @@ msgstr "busybeer" msgid "balloon_a" msgstr "a balloon" +msgid "balloon_p" +msgstr "balloons" + msgid "jadee_ring" msgstr "Jadee's wedding ring" @@ -879,6 +882,9 @@ msgstr "gems" msgid "boat_a" msgstr "a boat" +msgid "boat_p" +msgstr "boats" + msgctxt "race" msgid "orc_p" msgstr "orcs" @@ -1458,12 +1464,18 @@ msgstr "ring of invisibility" msgid "galleon_a" msgstr "a galleon" +msgid "galleon_p" +msgstr "galleons" + msgid "galleon" msgstr "galleon" msgid "caravel_a" msgstr "a caravel" +msgid "caravel_p" +msgstr "caravels" + msgid "mallornspear_p" msgstr "mallorn spear" @@ -2439,6 +2451,9 @@ msgstr "fjord fungus" msgid "trireme_a" msgstr "a trireme" +msgid "trireme_p" +msgstr "triremes" + msgctxt "spell" msgid "healing" msgstr "Heal" @@ -3639,6 +3654,9 @@ msgstr "goblin head" msgid "longboat_a" msgstr "a longboat" +msgid "longboat_p" +msgstr "longboats" + msgctxt "race" msgid "lynx" msgstr "lynx" @@ -5171,6 +5189,9 @@ msgstr "tiger" msgid "dragonship_a" msgstr "a dragonship" +msgid "dragonship_p" +msgstr "dragonships" + msgctxt "race" msgid "mountainguard_x" msgstr "mountainguard" From 1e0afdc96125f60a91fc7a09323756e5a28ca9bb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 8 Oct 2019 20:56:14 +0200 Subject: [PATCH 09/13] spells can only be cast on single ships. --- res/translations/messages.de.po | 8 ++++- res/translations/messages.en.po | 12 +++++++ scripts/tests/e2/ships.lua | 63 ++++++++++++++++++++++++++++++++- src/give.c | 14 ++++++-- src/items.c | 4 +++ src/kernel/ship.c | 1 - src/spells.c | 8 +++++ 7 files changed, 105 insertions(+), 5 deletions(-) diff --git a/res/translations/messages.de.po b/res/translations/messages.de.po index 759f41ed1..1ea230c8c 100644 --- a/res/translations/messages.de.po +++ b/res/translations/messages.de.po @@ -2768,12 +2768,18 @@ msgstr "\"$unit($unit) verspeiste $int($amount) Bauern.\"" msgid "error320" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht bewachen, da sie versucht zu fliehen.\"" -msgid "error321" +msgid "error325" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - Der Zauber kann nur auf ein einzelnes Schiff gewirkt werden.\"" + +msgid "error324" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit gehört nicht zu unserer Partei.\"" msgid "error322" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit ist bereits auf einem Schiff.\"" +msgid "error323" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - Das Schiff ist verzaubert.\"" + msgid "dissolve_units_2" msgstr "\"$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),\"wurde zum Baum\", \"wurden zu Bäumen\").\"" diff --git a/res/translations/messages.en.po b/res/translations/messages.en.po index 7724fdc07..e6bc922f2 100644 --- a/res/translations/messages.en.po +++ b/res/translations/messages.en.po @@ -2768,6 +2768,18 @@ msgstr "\"$unit($unit) ate $int($amount) peasants.\"" msgid "error320" msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit cannot guard the region because it is trying to flee.\"" +msgid "error325" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - Spells can only be cast on a single ship.\"" + +msgid "error324" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit is not one of ours.\"" + +msgid "error322" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit is already on a ship.\"" + +msgid "error323" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - The ship is under a spell.\"" + msgid "dissolve_units_2" msgstr "\"$unit($unit) in $region($region): $int($number) $race($race,$number) turned into $if($eq($number,1),\"a tree\", \"trees\").\"" diff --git a/scripts/tests/e2/ships.lua b/scripts/tests/e2/ships.lua index c71cf9eb3..5cd723f8e 100644 --- a/scripts/tests/e2/ships.lua +++ b/scripts/tests/e2/ships.lua @@ -177,6 +177,22 @@ function test_give_ship() assert_equal(1, u2.ship.number) end +function test_give_ship_only_to_captain() + local r = region.create(1, 0, 'ocean') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + local u3 = unit.create(f, r, 1) + u2.ship = ship.create(r, 'boat') + u3.ship = u2.ship + u1.ship = ship.create(r, 'boat') + u1.ship.number = 2 + u1:add_order("GIB " .. itoa36(u3.id) .. " 1 SCHIFF") + process_orders() + assert_equal(2, u1.ship.number) + assert_equal(1, u2.ship.number) +end + function test_give_ship_merge() local r = region.create(1, 0, 'ocean') local f = faction.create("human") @@ -227,15 +243,17 @@ end function test_give_ship_all_ships() local r = region.create(1, 0, 'plain') - local f = faction.create("human") + local f = faction.create("human", 'noreply@vg.no') local u1 = unit.create(f, r, 1) local u2 = unit.create(f, r, 1) u1.ship = ship.create(r, 'boat') + u1.ship.damage = 2 u1.ship.number = 2 u2.ship = ship.create(r, 'boat') u2.ship.number = 1 u1:add_order("GIB " .. itoa36(u2.id) .. " 2 SCHIFF") process_orders() + write_reports() assert_equal(3, u2.ship.number) assert_equal(u2.ship, u1.ship) end @@ -254,3 +272,46 @@ function test_give_ship_self_only() assert_equal(2, u1.ship.number) assert_equal(nil, u2.ship) end + +function test_give_ship_not_cursed() + local r = region.create(1, 0, 'plain') + local f = faction.create("human") + local u = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + local sh = ship.create(r, 'boat') + u.ship = sh + u:add_item("speedsail", 1) + u:add_order("BENUTZE 1 Sonnensegel") + process_orders() + u:clear_orders() + assert_equal(1, sh:get_curse('shipspeedup')) + + u:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") + process_orders() + assert_equal(nil, u2.ship) +end + +function test_speedsail_on_ship() + local r = region.create(1, 0, 'plain') + local f = faction.create("human") + local u = unit.create(f, r, 1) + local sh = ship.create(r, 'boat') + u.ship = sh + u:add_item("speedsail", 1) + u:add_order("BENUTZE 1 Sonnensegel") + process_orders() + assert_equal(1, sh:get_curse('shipspeedup')) +end + +function test_no_speedsail_on_convoy() + local r = region.create(1, 0, 'plain') + local f = faction.create("human") + local u = unit.create(f, r, 1) + local sh = ship.create(r, 'boat') + u.ship = sh + sh.number = 2 + u:add_item("speedsail", 2) + u:add_order("BENUTZE 2 Sonnensegel") + process_orders() + assert_equal(nil, sh:get_curse('shipspeedup')) +end diff --git a/src/give.c b/src/give.c index 582532fe1..71c9bab7d 100644 --- a/src/give.c +++ b/src/give.c @@ -314,15 +314,24 @@ static void transfer_units(ship *s1, ship *s2) } } +static bool ship_cursed(const ship *sh) { + return a_find(sh->attribs, &at_curse) != NULL; +} + message * give_ship(unit *u1, unit *u2, int n, order *ord) { assert(u1->ship); assert(n > 0 && n <= u1->ship->number); if (u1->faction != u2->faction) { - return msg_error(u1, ord, 321); + return msg_error(u1, ord, 324); + } + if (ship_cursed(u1->ship)) { + return msg_error(u1, ord, 323); } - /* TODO: when transferring all ships, unit must hop on the target ship */ if (u2->ship) { + if (ship_cursed(u2->ship)) { + return msg_error(u1, ord, 323); + } if (n < u1->ship->number) { if (u2->ship->type != u1->ship->type) { return msg_error(u1, ord, 322); @@ -892,6 +901,7 @@ void give_cmd(unit * u, order * ord) else { cmistake(u, ord, 144, MSG_COMMERCE); } + return; } else if (p == P_PERSON) { if (!(u_race(u)->ec_flags & ECF_GIVEPERSON)) { diff --git a/src/items.c b/src/items.c index c99fc2cdf..7912ff350 100644 --- a/src/items.c +++ b/src/items.c @@ -101,6 +101,10 @@ struct order *ord) cmistake(u, ord, 20, MSG_MOVE); return -1; } + if (sh->number > 1) { + cmistake(u, ord, 325, MSG_MAGIC); + return -1; + } effect = SPEEDSAIL_EFFECT; create_curse(u, &sh->attribs, &ct_shipspeedup, 20, INT_MAX, effect, 0); diff --git a/src/kernel/ship.c b/src/kernel/ship.c index 1e38257d9..601c36d82 100644 --- a/src/kernel/ship.c +++ b/src/kernel/ship.c @@ -314,7 +314,6 @@ int shipspeed(const ship * sh, const unit * u) if (!ship_finished(sh)) { return 0; } - if (sh->attribs) { if (curse_active(get_curse(sh->attribs, &ct_stormwind))) { k *= 2; diff --git a/src/spells.c b/src/spells.c index 486a62b71..200e87f62 100644 --- a/src/spells.c +++ b/src/spells.c @@ -808,6 +808,10 @@ static int sp_goodwinds(castorder * co) return 0; sh = pa->param[0]->data.sh; + if (sh->number > 1) { + cmistake(caster, co->order, 325, MSG_MAGIC); + return 0; + } /* keine Probleme mit C_SHIP_SPEEDUP und C_SHIP_FLYING */ /* NODRIFT bewirkt auch +1 Geschwindigkeit */ @@ -2231,6 +2235,10 @@ static int sp_stormwinds(castorder * co) sh = pa->param[n]->data.sh; + if (sh->number > 1) { + cmistake(caster, co->order, 325, MSG_MAGIC); + continue; + } if (is_cursed(sh->attribs, &ct_flyingship)) { ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, "error_spell_on_flying_ship", "ship", sh)) From 24978a5b80b2949d34eaf20ad1056990050e1ba9 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 8 Oct 2019 21:14:01 +0200 Subject: [PATCH 10/13] =?UTF-8?q?Schiffstransfer=20nur=20zwischen=20Kapit?= =?UTF-8?q?=C3=A4nen.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/tests/e2/ships.lua | 20 ++++++++++++++++++-- src/give.c | 6 ++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/scripts/tests/e2/ships.lua b/scripts/tests/e2/ships.lua index 5cd723f8e..b038553b8 100644 --- a/scripts/tests/e2/ships.lua +++ b/scripts/tests/e2/ships.lua @@ -183,16 +183,32 @@ function test_give_ship_only_to_captain() local u1 = unit.create(f, r, 1) local u2 = unit.create(f, r, 1) local u3 = unit.create(f, r, 1) - u2.ship = ship.create(r, 'boat') - u3.ship = u2.ship u1.ship = ship.create(r, 'boat') u1.ship.number = 2 + u2.ship = ship.create(r, 'boat') + u3.ship = u2.ship u1:add_order("GIB " .. itoa36(u3.id) .. " 1 SCHIFF") process_orders() assert_equal(2, u1.ship.number) assert_equal(1, u2.ship.number) end +function test_give_ship_only_from_captain() + local r = region.create(1, 0, 'ocean') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + local u3 = unit.create(f, r, 1) + u2.ship = ship.create(r, 'boat') + u1.ship = ship.create(r, 'boat') + u1.ship.number = 2 + u3.ship = u1.ship + u3:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") + process_orders() + assert_equal(2, u1.ship.number) + assert_equal(1, u2.ship.number) +end + function test_give_ship_merge() local r = region.create(1, 0, 'ocean') local f = faction.create("human") diff --git a/src/give.c b/src/give.c index 71c9bab7d..cc9f54987 100644 --- a/src/give.c +++ b/src/give.c @@ -328,7 +328,13 @@ message * give_ship(unit *u1, unit *u2, int n, order *ord) if (ship_cursed(u1->ship)) { return msg_error(u1, ord, 323); } + if (u1 != ship_owner(u1->ship)) { + return msg_error(u1, ord, 146); + } if (u2->ship) { + if (u2 != ship_owner(u2->ship)) { + return msg_error(u1, ord, 146); + } if (ship_cursed(u2->ship)) { return msg_error(u1, ord, 323); } From 78e44e0fe396d8c75a0b61929763c8d70cc53ecb Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 10 Oct 2019 16:12:25 +0200 Subject: [PATCH 11/13] check compatible costs --- scripts/tests/e2/ships.lua | 43 +++++++++++++++++++++++++++++++++++ src/give.c | 46 +++++++++++++++++++++++--------------- 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/scripts/tests/e2/ships.lua b/scripts/tests/e2/ships.lua index b038553b8..f8020f3d7 100644 --- a/scripts/tests/e2/ships.lua +++ b/scripts/tests/e2/ships.lua @@ -193,6 +193,49 @@ function test_give_ship_only_to_captain() assert_equal(1, u2.ship.number) end +function test_give_ship_compatible_coasts() + local r = region.create(1, 0, 'plain') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1.ship = ship.create(r, 'boat') + u1.ship.number = 4 + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") + u2.ship = ship.create(r, 'boat') + + -- cannot give a ship with different coast: + u1.ship.coast = 1 + u2.ship.coast = 2 + process_orders() + assert_equal(4, u1.ship.number) + assert_equal(1, u2.ship.number) + + -- can give a ship with no coast: + u1.ship.coast = -1 + u2.ship.coast = 2 + process_orders() + assert_equal(3, u1.ship.number) + assert_equal(2, u2.ship.number) + assert_equal(2, u2.ship.coast) + + -- can give a ship with same coast: + u1.ship.coast = 2 + u2.ship.coast = 2 + process_orders() + assert_equal(2, u1.ship.number) + assert_equal(3, u2.ship.number) + assert_equal(2, u2.ship.coast) + + -- giving to a ship with no coast: + u1.ship.coast = 2 + u2.ship.coast = -1 + process_orders() + assert_equal(1, u1.ship.number) + assert_equal(4, u2.ship.number) + assert_equal(2, u2.ship.coast) + +end + function test_give_ship_only_from_captain() local r = region.create(1, 0, 'ocean') local f = faction.create("human") diff --git a/src/give.c b/src/give.c index cc9f54987..716bab933 100644 --- a/src/give.c +++ b/src/give.c @@ -331,26 +331,36 @@ message * give_ship(unit *u1, unit *u2, int n, order *ord) if (u1 != ship_owner(u1->ship)) { return msg_error(u1, ord, 146); } - if (u2->ship) { - if (u2 != ship_owner(u2->ship)) { - return msg_error(u1, ord, 146); - } - if (ship_cursed(u2->ship)) { - return msg_error(u1, ord, 323); - } - if (n < u1->ship->number) { + if (fval(u_race(u2), RCF_CANSAIL)) { + if (u2->ship) { + if (u2 != ship_owner(u2->ship)) { + return msg_error(u1, ord, 146); + } if (u2->ship->type != u1->ship->type) { return msg_error(u1, ord, 322); } - transfer_ships(u1->ship, u2->ship, n); + if (ship_cursed(u2->ship)) { + return msg_error(u1, ord, 323); + } + if (u1->ship->coast != u2->ship->coast) { + if (u1->ship->coast != NODIRECTION) { + if (u2->ship->coast == NODIRECTION) { + u2->ship->coast = u1->ship->coast; + } + else { + return msg_error(u1, ord, 182); + } + } + } + if (n < u1->ship->number) { + transfer_ships(u1->ship, u2->ship, n); + } + else { + transfer_ships(u1->ship, u2->ship, n); + transfer_units(u1->ship, u2->ship); + } } else { - transfer_ships(u1->ship, u2->ship, n); - transfer_units(u1->ship, u2->ship); - } - } - else { - if (fval(u_race(u2), RCF_CANSAIL)) { if (n < u1->ship->number) { ship * sh = new_ship(u1->ship->type, u1->region, u1->faction->locale); scale_ship(sh, 0); @@ -362,9 +372,9 @@ message * give_ship(unit *u1, unit *u2, int n, order *ord) ship_set_owner(u2); } } - else { - return msg_error(u1, ord, 233); - } + } + else { + return msg_error(u1, ord, 233); } return NULL; } From 1d405e2ef8f6aa80a6771654274d6857284db859 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 10 Oct 2019 20:17:25 +0200 Subject: [PATCH 12/13] =?UTF-8?q?GIB=200=20n=20SCHIFFE=20Keine=20Boote=20e?= =?UTF-8?q?rlauben=20=C3=9Cbergabe=20an=20eigene=20Besatzung.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- res/translations/messages.de.po | 6 ++ res/translations/messages.en.po | 3 + scripts/tests/e2/ships.lua | 133 ++++++++++++++++++++++++-------- src/give.c | 99 +++++++++++++++--------- 4 files changed, 171 insertions(+), 70 deletions(-) diff --git a/res/translations/messages.de.po b/res/translations/messages.de.po index 1ea230c8c..5d2717e51 100644 --- a/res/translations/messages.de.po +++ b/res/translations/messages.de.po @@ -2780,6 +2780,12 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit ist msgid "error323" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Das Schiff ist verzaubert.\"" +msgid "error327" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - So viele Schiffe kann die Einheit nicht übergeben.\"" + +msgid "error326" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - Diese Schiffe können keinen Konvoi bilden.\"" + msgid "dissolve_units_2" msgstr "\"$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),\"wurde zum Baum\", \"wurden zu Bäumen\").\"" diff --git a/res/translations/messages.en.po b/res/translations/messages.en.po index e6bc922f2..135053782 100644 --- a/res/translations/messages.en.po +++ b/res/translations/messages.en.po @@ -2771,6 +2771,9 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit cannot msgid "error325" msgstr "\"$unit($unit) in $region($region): '$order($command)' - Spells can only be cast on a single ship.\"" +msgid "error326" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - These ships cannot form a convoy.\"" + msgid "error324" msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit is not one of ours.\"" diff --git a/scripts/tests/e2/ships.lua b/scripts/tests/e2/ships.lua index f8020f3d7..9286cc8f1 100644 --- a/scripts/tests/e2/ships.lua +++ b/scripts/tests/e2/ships.lua @@ -83,9 +83,9 @@ function test_ship_convoy_capacity() local u = unit.create(f, r1, 1) u:add_order('NACH O') - u:set_skill('sailing', 2, true) - u:add_item('jewel', 40) - u.ship = ship.create(r1, 'boat') + u:set_skill('sailing', 10, true) + u:add_item('jewel', 490) + u.ship = ship.create(r1, 'longboat') assert_equal(1, u.ship.number) process_orders() u:clear_orders() @@ -99,19 +99,17 @@ function test_ship_convoy_capacity() assert_equal(r2, u.region) -- too heavy u:add_order('NACH W') - u:add_item('jewel', 39) + u:add_item('jewel', 489) u.ship.number = 2 u.number = 2 - u:set_skill('sailing', 2, true) + u:set_skill('sailing', 10, true) process_orders() u:clear_orders() assert_equal(r1, u.region) -- double capacity u:add_order('NACH O') u.ship.number = 2 - u.name = 'Bolgrim' u:add_item('jewel', 1) -- too heavy again - u:set_skill('sailing', 2, true) process_orders() u:clear_orders() assert_equal(r1, u.region) @@ -122,17 +120,17 @@ function test_ship_convoy_crew() local r2 = region.create(2, 0, 'ocean') local f = faction.create("human") local u = unit.create(f, r1, 1) - u.ship = ship.create(r1, 'boat') + u.ship = ship.create(r1, 'longboat') u.ship.number = 2 - u:set_skill('sailing', 4, true) + u.number = 2 + u:set_skill('sailing', 5, true) u:add_order('NACH O') process_orders() u:clear_orders() assert_equal(r1, u.region) -- not enough captains - u.number = 2 - u:set_skill('sailing', 2, true) + u:set_skill('sailing', 10, true) u:add_order('NACH O') process_orders() u:clear_orders() @@ -146,20 +144,20 @@ function test_ship_convoy_skill() local f = faction.create("human") local u = unit.create(f, r1, 1) - u:set_skill('sailing', 2, true) - u.ship = ship.create(r1, 'boat') + u:set_skill('sailing', 10, true) + u.ship = ship.create(r1, 'longboat') assert_equal(1, u.ship.number) u:add_order('NACH O') process_orders() assert_equal(r2, u.region) u.ship.number = 2 - u:set_skill('sailing', 4, true) + u:set_skill('sailing', 20, true) process_orders() assert_equal(r2, u.region) -- not enough captains u.number = 2 - u:set_skill('sailing', 2, true) + u:set_skill('sailing', 10, true) process_orders() assert_equal(r3, u.region) end @@ -169,7 +167,7 @@ function test_give_ship() local f = faction.create("human") local u1 = unit.create(f, r, 1) local u2 = unit.create(f, r, 1) - u1.ship = ship.create(r, 'boat') + u1.ship = ship.create(r, 'longboat') u1.ship.number = 2 u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") process_orders() @@ -177,15 +175,84 @@ function test_give_ship() assert_equal(1, u2.ship.number) end +function test_give_ship_new_unit() + local r = region.create(1, 0, 'ocean') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1.ship = ship.create(r, 'longboat') + u1.ship.number = 2 + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") + process_orders() + assert_equal(1, u1.ship.number) + assert_equal(1, u2.ship.number) +end + +function test_give_ship_same_ship() + local r = region.create(1, 0, 'ocean') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1.ship = ship.create(r, 'longboat') + u2.ship = u1.ship + u1.ship.number = 2 + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") + process_orders() + assert_equal(1, u1.ship.number) + assert_equal(1, u2.ship.number) + assert_not_equal(u1.ship, u2.ship) +end + +function test_give_ship_dont_give_all() + local r = region.create(1, 0, 'ocean') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + u1.ship = ship.create(r, 'longboat') + u1.ship.number = 2 + u1:add_order("GIB 0 2 SCHIFF") + process_orders() + assert_equal(2, u1.ship.number) +end + +function test_give_ship_no_boat() + local r = region.create(1, 0, 'ocean') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1.ship = ship.create(r, 'boat') + u1.ship.number = 1 + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") + process_orders() + assert_equal(1, u1.ship.number) + assert_equal(nil, u2.ship) +end + +function test_give_ship_away() + local r = region.create(1, 0, 'ocean') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + u1.ship = ship.create(r, 'longboat') + u1.ship.number = 2 + u1:add_order("GIB 0 1 SCHIFF") + process_orders() + assert_equal(1, u1.ship.number) + local count = 0 + for sh in r.ships do + assert_equal(1, sh.number) + count = count + 1 + end + assert_equal(2, count) +end + function test_give_ship_only_to_captain() local r = region.create(1, 0, 'ocean') local f = faction.create("human") local u1 = unit.create(f, r, 1) local u2 = unit.create(f, r, 1) local u3 = unit.create(f, r, 1) - u1.ship = ship.create(r, 'boat') + u1.ship = ship.create(r, 'longboat') u1.ship.number = 2 - u2.ship = ship.create(r, 'boat') + u2.ship = ship.create(r, 'longboat') u3.ship = u2.ship u1:add_order("GIB " .. itoa36(u3.id) .. " 1 SCHIFF") process_orders() @@ -198,10 +265,10 @@ function test_give_ship_compatible_coasts() local f = faction.create("human") local u1 = unit.create(f, r, 1) local u2 = unit.create(f, r, 1) - u1.ship = ship.create(r, 'boat') + u1.ship = ship.create(r, 'longboat') u1.ship.number = 4 u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") - u2.ship = ship.create(r, 'boat') + u2.ship = ship.create(r, 'longboat') -- cannot give a ship with different coast: u1.ship.coast = 1 @@ -242,8 +309,8 @@ function test_give_ship_only_from_captain() local u1 = unit.create(f, r, 1) local u2 = unit.create(f, r, 1) local u3 = unit.create(f, r, 1) - u2.ship = ship.create(r, 'boat') - u1.ship = ship.create(r, 'boat') + u2.ship = ship.create(r, 'longboat') + u1.ship = ship.create(r, 'longboat') u1.ship.number = 2 u3.ship = u1.ship u3:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") @@ -257,8 +324,8 @@ function test_give_ship_merge() local f = faction.create("human") local u1 = unit.create(f, r, 1) local u2 = unit.create(f, r, 1) - u2.ship = ship.create(r, 'boat') - u1.ship = ship.create(r, 'boat') + u2.ship = ship.create(r, 'longboat') + u1.ship = ship.create(r, 'longboat') u1.ship.number = 2 u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") process_orders() @@ -271,8 +338,8 @@ function test_give_ship_only_same() local f = faction.create("human") local u1 = unit.create(f, r, 1) local u2 = unit.create(f, r, 1) - u2.ship = ship.create(r, 'boat') - u1.ship = ship.create(r, 'longboat') + u2.ship = ship.create(r, 'longboat') + u1.ship = ship.create(r, 'caravel') u1.ship.number = 2 u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") process_orders() @@ -285,7 +352,7 @@ function test_give_ship_scale() local f = faction.create("human") local u1 = unit.create(f, r, 1) local u2 = unit.create(f, r, 1) - local sh = ship.create(r, 'boat') + local sh = ship.create(r, 'longboat') sh.number = 3 sh.damage = 9 sh.size = 12 @@ -305,10 +372,10 @@ function test_give_ship_all_ships() local f = faction.create("human", 'noreply@vg.no') local u1 = unit.create(f, r, 1) local u2 = unit.create(f, r, 1) - u1.ship = ship.create(r, 'boat') + u1.ship = ship.create(r, 'longboat') u1.ship.damage = 2 u1.ship.number = 2 - u2.ship = ship.create(r, 'boat') + u2.ship = ship.create(r, 'longboat') u2.ship.number = 1 u1:add_order("GIB " .. itoa36(u2.id) .. " 2 SCHIFF") process_orders() @@ -323,7 +390,7 @@ function test_give_ship_self_only() local f2 = faction.create("human") local u1 = unit.create(f1, r, 1) local u2 = unit.create(f2, r, 1) - local sh = ship.create(r, 'boat') + local sh = ship.create(r, 'longboat') sh.number = 2 u1.ship = sh u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") @@ -337,7 +404,7 @@ function test_give_ship_not_cursed() local f = faction.create("human") local u = unit.create(f, r, 1) local u2 = unit.create(f, r, 1) - local sh = ship.create(r, 'boat') + local sh = ship.create(r, 'longboat') u.ship = sh u:add_item("speedsail", 1) u:add_order("BENUTZE 1 Sonnensegel") @@ -354,7 +421,7 @@ function test_speedsail_on_ship() local r = region.create(1, 0, 'plain') local f = faction.create("human") local u = unit.create(f, r, 1) - local sh = ship.create(r, 'boat') + local sh = ship.create(r, 'longboat') u.ship = sh u:add_item("speedsail", 1) u:add_order("BENUTZE 1 Sonnensegel") @@ -366,7 +433,7 @@ function test_no_speedsail_on_convoy() local r = region.create(1, 0, 'plain') local f = faction.create("human") local u = unit.create(f, r, 1) - local sh = ship.create(r, 'boat') + local sh = ship.create(r, 'longboat') u.ship = sh sh.number = 2 u:add_item("speedsail", 2) diff --git a/src/give.c b/src/give.c index 716bab933..ad157225a 100644 --- a/src/give.c +++ b/src/give.c @@ -299,6 +299,9 @@ static void transfer_ships(ship *s1, ship *s2, int n) s2->damage += s1->damage * n / s1->number; s2->size += s1->size * n / s1->number; s2->number += n; + if (s1->coast != NODIRECTION) { + s2->coast = s1->coast; + } scale_ship(s1, s1->number - n); } @@ -322,8 +325,9 @@ message * give_ship(unit *u1, unit *u2, int n, order *ord) { assert(u1->ship); assert(n > 0 && n <= u1->ship->number); - if (u1->faction != u2->faction) { - return msg_error(u1, ord, 324); + if (u1->ship->type->range < 3) { + /* Keine Boote und anderes Kleinzeug erlaubt */ + return msg_error(u1, ord, 326); } if (ship_cursed(u1->ship)) { return msg_error(u1, ord, 323); @@ -331,51 +335,72 @@ message * give_ship(unit *u1, unit *u2, int n, order *ord) if (u1 != ship_owner(u1->ship)) { return msg_error(u1, ord, 146); } - if (fval(u_race(u2), RCF_CANSAIL)) { - if (u2->ship) { - if (u2 != ship_owner(u2->ship)) { - return msg_error(u1, ord, 146); - } - if (u2->ship->type != u1->ship->type) { - return msg_error(u1, ord, 322); - } - if (ship_cursed(u2->ship)) { - return msg_error(u1, ord, 323); - } - if (u1->ship->coast != u2->ship->coast) { - if (u1->ship->coast != NODIRECTION) { - if (u2->ship->coast == NODIRECTION) { - u2->ship->coast = u1->ship->coast; + if (u2 == NULL) { + if (n < u1->ship->number) { + ship * sh = new_ship(u1->ship->type, u1->region, u1->faction->locale); + scale_ship(sh, 0); + transfer_ships(u1->ship, sh, n); + } + else { + return msg_error(u1, ord, 327); + } + } else { + if (u1->faction != u2->faction) { + return msg_error(u1, ord, 324); + } + if (fval(u_race(u2), RCF_CANSAIL)) { + if (u2->ship) { + if (u2->ship == u1->ship) { + ship * sh = new_ship(u1->ship->type, u1->region, u1->faction->locale); + scale_ship(sh, 0); + leave_ship(u2); + u_set_ship(u2, sh); + } else { + if (u2 != ship_owner(u2->ship)) { + return msg_error(u1, ord, 146); } - else { - return msg_error(u1, ord, 182); + if (u2->ship->type != u1->ship->type) { + return msg_error(u1, ord, 322); + } + if (ship_cursed(u2->ship)) { + return msg_error(u1, ord, 323); + } + if (u1->ship->coast != u2->ship->coast) { + if (u1->ship->coast != NODIRECTION) { + if (u2->ship->coast == NODIRECTION) { + u2->ship->coast = u1->ship->coast; + } + else { + return msg_error(u1, ord, 182); + } + } } } - } - if (n < u1->ship->number) { - transfer_ships(u1->ship, u2->ship, n); + if (n < u1->ship->number) { + transfer_ships(u1->ship, u2->ship, n); + } + else { + transfer_ships(u1->ship, u2->ship, n); + transfer_units(u1->ship, u2->ship); + } } else { - transfer_ships(u1->ship, u2->ship, n); - transfer_units(u1->ship, u2->ship); + if (n < u1->ship->number) { + ship * sh = new_ship(u1->ship->type, u1->region, u1->faction->locale); + scale_ship(sh, 0); + u_set_ship(u2, sh); + transfer_ships(u1->ship, sh, n); + } + else { + u_set_ship(u2, u1->ship); + ship_set_owner(u2); + } } } else { - if (n < u1->ship->number) { - ship * sh = new_ship(u1->ship->type, u1->region, u1->faction->locale); - scale_ship(sh, 0); - u_set_ship(u2, sh); - transfer_ships(u1->ship, sh, n); - } - else { - u_set_ship(u2, u1->ship); - ship_set_owner(u2); - } + return msg_error(u1, ord, 233); } } - else { - return msg_error(u1, ord, 233); - } return NULL; } From 12491ffc168b86e4ffa5dc99d6b562e27569b3f7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 10 Oct 2019 20:24:18 +0200 Subject: [PATCH 13/13] GIB 0 an Land kann alle Schiffe geben, auf Ozean nicht. --- res/translations/messages.en.po | 3 +++ scripts/tests/e2/ships.lua | 16 ++++++++++++++-- src/give.c | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/res/translations/messages.en.po b/res/translations/messages.en.po index 135053782..659adee9f 100644 --- a/res/translations/messages.en.po +++ b/res/translations/messages.en.po @@ -2774,6 +2774,9 @@ msgstr "\"$unit($unit) in $region($region): '$order($command)' - Spells can only msgid "error326" msgstr "\"$unit($unit) in $region($region): '$order($command)' - These ships cannot form a convoy.\"" +msgid "error327" +msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit must keep at least one ship.\"" + msgid "error324" msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit is not one of ours.\"" diff --git a/scripts/tests/e2/ships.lua b/scripts/tests/e2/ships.lua index 9286cc8f1..416677d26 100644 --- a/scripts/tests/e2/ships.lua +++ b/scripts/tests/e2/ships.lua @@ -203,8 +203,8 @@ function test_give_ship_same_ship() assert_not_equal(u1.ship, u2.ship) end -function test_give_ship_dont_give_all() - local r = region.create(1, 0, 'ocean') +function test_give_ship_all_on_ocean() + local r = region.create(0, 0, 'ocean') local f = faction.create("human") local u1 = unit.create(f, r, 1) u1.ship = ship.create(r, 'longboat') @@ -214,6 +214,18 @@ function test_give_ship_dont_give_all() assert_equal(2, u1.ship.number) end +function test_give_ship_all_on_land() + local r = region.create(0, 0, 'plain') + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + u1.ship = ship.create(r, 'longboat') + u1.ship.number = 2 + u1:add_order("GIB 0 2 SCHIFF") + process_orders() + assert_equal(nil, u1.ship) + assert_not_equal(nil, r.ships()) +end + function test_give_ship_no_boat() local r = region.create(1, 0, 'ocean') local f = faction.create("human") diff --git a/src/give.c b/src/give.c index ad157225a..47f472ec1 100644 --- a/src/give.c +++ b/src/give.c @@ -336,7 +336,7 @@ message * give_ship(unit *u1, unit *u2, int n, order *ord) return msg_error(u1, ord, 146); } if (u2 == NULL) { - if (n < u1->ship->number) { + if (fval(u1->region->terrain, LAND_REGION) || n < u1->ship->number) { ship * sh = new_ship(u1->ship->type, u1->region, u1->faction->locale); scale_ship(sh, 0); transfer_ships(u1->ship, sh, n);