diff --git a/res/translations/messages.de.po b/res/translations/messages.de.po index 776a1e207..5d2717e51 100644 --- a/res/translations/messages.de.po +++ b/res/translations/messages.de.po @@ -2768,6 +2768,24 @@ 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 "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 "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 7724fdc07..659adee9f 100644 --- a/res/translations/messages.en.po +++ b/res/translations/messages.en.po @@ -2768,6 +2768,24 @@ 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 "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.\"" + +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/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" diff --git a/scripts/tests/e2/ships.lua b/scripts/tests/e2/ships.lua index 3208f0a0d..416677d26 100644 --- a/scripts/tests/e2/ships.lua +++ b/scripts/tests/e2/ships.lua @@ -75,3 +75,381 @@ 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', 10, true) + u:add_item('jewel', 490) + u.ship = ship.create(r1, 'longboat') + 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', 489) + u.ship.number = 2 + u.number = 2 + 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:add_item('jewel', 1) -- too heavy again + 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, 'longboat') + u.ship.number = 2 + + 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:set_skill('sailing', 10, 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', 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', 20, true) + process_orders() + assert_equal(r2, u.region) -- not enough captains + + u.number = 2 + u:set_skill('sailing', 10, true) + 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, '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_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_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') + u1.ship.number = 2 + u1:add_order("GIB 0 2 SCHIFF") + process_orders() + 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") + 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, 'longboat') + u1.ship.number = 2 + u2.ship = ship.create(r, 'longboat') + 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_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, 'longboat') + u1.ship.number = 4 + u1:add_order("GIB " .. itoa36(u2.id) .. " 1 SCHIFF") + u2.ship = ship.create(r, 'longboat') + + -- 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") + 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, 'longboat') + u1.ship = ship.create(r, 'longboat') + 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") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + 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() + assert_equal(1, u1.ship.number) + assert_equal(2, u2.ship.number) +end + +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, 'longboat') + u1.ship = ship.create(r, 'caravel') + 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) + local u2 = unit.create(f, r, 1) + local sh = ship.create(r, 'longboat') + sh.number = 3 + sh.damage = 9 + sh.size = 12 + u1.ship = sh + u1:add_order("GIB " .. itoa36(u2.id) .. " 2 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_all_ships() + local r = region.create(1, 0, 'plain') + 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, 'longboat') + u1.ship.damage = 2 + u1.ship.number = 2 + u2.ship = ship.create(r, 'longboat') + 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 + +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, 'longboat') + 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 + +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, 'longboat') + 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, 'longboat') + 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, 'longboat') + 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/bind_ship.c b/src/bind_ship.c index d335d996d..71b6ae4f4 100644 --- a/src/bind_ship.c +++ b/src/bind_ship.c @@ -38,39 +38,54 @@ 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); + scale_ship(sh, n); + 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 +93,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 +162,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 +205,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 +238,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 +258,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..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; @@ -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/give.c b/src/give.c index ba04e69a6..47f472ec1 100644 --- a/src/give.c +++ b/src/give.c @@ -293,6 +293,117 @@ bool rule_transfermen(void) return rule != 0; } +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; + if (s1->coast != NODIRECTION) { + s2->coast = s1->coast; + } + scale_ship(s1, s1->number - n); +} + +static void transfer_units(ship *s1, ship *s2) +{ + 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); + } + } +} + +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->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); + } + if (u1 != ship_owner(u1->ship)) { + return msg_error(u1, ord, 146); + } + if (u2 == NULL) { + 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); + } + 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); + } + 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); + } + else { + transfer_ships(u1->ship, u2->ship, n); + transfer_units(u1->ship, u2->ship); + } + } + 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); + } + } + } + else { + return msg_error(u1, ord, 233); + } + } + return NULL; +} + message * give_men(int n, unit * u, unit * u2, struct order *ord) { int error = 0; @@ -652,7 +763,8 @@ 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_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 +927,24 @@ 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; + if (n > u->ship->number) { + n = u->ship->number; + } + msg = give_ship(u, u2, n, ord); + if (msg) { + ADDMSG(&u->faction->msgs, msg); + } + } + else { + cmistake(u, ord, 144, MSG_COMMERCE); + } + return; + } + 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))); 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/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/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..a65dda7e1 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1283,6 +1283,8 @@ 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); WRITE_INT(store, sh->flags & SFL_SAVEMASK); @@ -1320,6 +1322,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..601c36d82 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,9 +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))) { k *= 2; @@ -385,17 +373,85 @@ 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->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 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->minskill) { + n += es * u->number; + } + } + } + return n; +} + +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); +} + +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)) { + 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) @@ -465,17 +521,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..a9a678848 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; @@ -89,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, @@ -113,9 +116,13 @@ 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); + + bool ship_crewed(const struct ship *sh); int crew_skill(const struct ship *sh); + 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 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..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, shipcapacity(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/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)) 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);