Merge pull request #880 from ennorehling/develop

Schiffe und Konvois
This commit is contained in:
Enno Rehling 2019-10-10 20:48:15 +02:00 committed by GitHub
commit bec38f544b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 829 additions and 126 deletions

View File

@ -2768,6 +2768,24 @@ msgstr "\"$unit($unit) verspeiste $int($amount) Bauern.\""
msgid "error320" msgid "error320"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - Die Einheit kann nicht bewachen, da sie versucht zu fliehen.\"" 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" 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\").\"" msgstr "\"$unit($unit) in $region($region): $int($number) $race($race,$number) $if($eq($number,1),\"wurde zum Baum\", \"wurden zu Bäumen\").\""

View File

@ -2768,6 +2768,24 @@ msgstr "\"$unit($unit) ate $int($amount) peasants.\""
msgid "error320" msgid "error320"
msgstr "\"$unit($unit) in $region($region): '$order($command)' - The unit cannot guard the region because it is trying to flee.\"" 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" msgid "dissolve_units_2"
msgstr "\"$unit($unit) in $region($region): $int($number) $race($race,$number) turned into $if($eq($number,1),\"a tree\", \"trees\").\"" msgstr "\"$unit($unit) in $region($region): $int($number) $race($race,$number) turned into $if($eq($number,1),\"a tree\", \"trees\").\""

View File

@ -389,6 +389,9 @@ msgstr "Schaffenstrunk"
msgid "balloon_a" msgid "balloon_a"
msgstr "ein Ballon" msgstr "ein Ballon"
msgid "balloon_p"
msgstr "Ballons"
msgid "undead_name_8" msgid "undead_name_8"
msgstr "Monster" msgstr "Monster"
@ -1115,6 +1118,9 @@ msgstr "Orks"
msgid "boat_a" msgid "boat_a"
msgstr "ein Boot" msgstr "ein Boot"
msgid "boat_p"
msgstr "Boote"
msgctxt "race" msgctxt "race"
msgid "nymph" msgid "nymph"
msgstr "Nymphe" msgstr "Nymphe"
@ -1719,9 +1725,15 @@ msgstr "Ring der Unsichtbarkeit"
msgid "caravel_a" msgid "caravel_a"
msgstr "eine Karavelle" msgstr "eine Karavelle"
msgid "caravel_p"
msgstr "Karavellen"
msgid "galleon_a" msgid "galleon_a"
msgstr "eine Galeone" msgstr "eine Galeone"
msgid "galleon_p"
msgstr "Galeonen"
msgctxt "keyword" msgctxt "keyword"
msgid "describe" msgid "describe"
msgstr "BESCHREIBE" msgstr "BESCHREIBE"
@ -1895,6 +1907,9 @@ msgstr "Untoten"
msgid "flyingcarpet_a" msgid "flyingcarpet_a"
msgstr "ein fliegender Teppich" msgstr "ein fliegender Teppich"
msgid "flyingcarpet_p"
msgstr "fliegende Teppiche"
msgid "mallorntree_p" msgid "mallorntree_p"
msgstr "Mallorn" msgstr "Mallorn"
@ -2806,6 +2821,9 @@ msgstr "Fjordwuchs"
msgid "trireme_a" msgid "trireme_a"
msgstr "eine Trireme" msgstr "eine Trireme"
msgid "trireme_p"
msgstr "Triremen"
msgctxt "prefix" msgctxt "prefix"
msgid "Dunkel" msgid "Dunkel"
msgstr "Dunkel" msgstr "Dunkel"
@ -4112,6 +4130,9 @@ msgstr "Luchs"
msgid "longboat_a" msgid "longboat_a"
msgstr "ein Langboot" msgstr "ein Langboot"
msgid "longboat_p"
msgstr "Langboote"
msgctxt "race" msgctxt "race"
msgid "human_d" msgid "human_d"
msgstr "Menschen" msgstr "Menschen"
@ -5858,6 +5879,9 @@ msgstr "Tiger"
msgid "dragonship_a" msgid "dragonship_a"
msgstr "ein Drachenschiff" msgstr "ein Drachenschiff"
msgid "dragonship_p"
msgstr "Drachenschiffe"
msgctxt "race" msgctxt "race"
msgid "mountainguard_x" msgid "mountainguard_x"
msgstr "Bergwächter" msgstr "Bergwächter"

View File

@ -303,6 +303,9 @@ msgstr "busybeer"
msgid "balloon_a" msgid "balloon_a"
msgstr "a balloon" msgstr "a balloon"
msgid "balloon_p"
msgstr "balloons"
msgid "jadee_ring" msgid "jadee_ring"
msgstr "Jadee's wedding ring" msgstr "Jadee's wedding ring"
@ -879,6 +882,9 @@ msgstr "gems"
msgid "boat_a" msgid "boat_a"
msgstr "a boat" msgstr "a boat"
msgid "boat_p"
msgstr "boats"
msgctxt "race" msgctxt "race"
msgid "orc_p" msgid "orc_p"
msgstr "orcs" msgstr "orcs"
@ -1458,12 +1464,18 @@ msgstr "ring of invisibility"
msgid "galleon_a" msgid "galleon_a"
msgstr "a galleon" msgstr "a galleon"
msgid "galleon_p"
msgstr "galleons"
msgid "galleon" msgid "galleon"
msgstr "galleon" msgstr "galleon"
msgid "caravel_a" msgid "caravel_a"
msgstr "a caravel" msgstr "a caravel"
msgid "caravel_p"
msgstr "caravels"
msgid "mallornspear_p" msgid "mallornspear_p"
msgstr "mallorn spear" msgstr "mallorn spear"
@ -2439,6 +2451,9 @@ msgstr "fjord fungus"
msgid "trireme_a" msgid "trireme_a"
msgstr "a trireme" msgstr "a trireme"
msgid "trireme_p"
msgstr "triremes"
msgctxt "spell" msgctxt "spell"
msgid "healing" msgid "healing"
msgstr "Heal" msgstr "Heal"
@ -3639,6 +3654,9 @@ msgstr "goblin head"
msgid "longboat_a" msgid "longboat_a"
msgstr "a longboat" msgstr "a longboat"
msgid "longboat_p"
msgstr "longboats"
msgctxt "race" msgctxt "race"
msgid "lynx" msgid "lynx"
msgstr "lynx" msgstr "lynx"
@ -5171,6 +5189,9 @@ msgstr "tiger"
msgid "dragonship_a" msgid "dragonship_a"
msgstr "a dragonship" msgstr "a dragonship"
msgid "dragonship_p"
msgstr "dragonships"
msgctxt "race" msgctxt "race"
msgid "mountainguard_x" msgid "mountainguard_x"
msgstr "mountainguard" msgstr "mountainguard"

View File

@ -75,3 +75,381 @@ function test_speedy_ship_fast()
process_orders() process_orders()
assert_equal(8, u1.region.x) assert_equal(8, u1.region.x)
end 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

View File

@ -38,39 +38,54 @@ int tolua_shiplist_next(lua_State * L)
return 0; /* no more values to return */ 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) static int tolua_ship_get_id(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
lua_pushinteger(L, self->no); lua_pushinteger(L, sh->no);
return 1; return 1;
} }
static int tolua_ship_get_name(lua_State * L) static int tolua_ship_get_name(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
tolua_pushstring(L, ship_getname(self)); tolua_pushstring(L, ship_getname(sh));
return 1; return 1;
} }
static int tolua_ship_get_size(lua_State * L) static int tolua_ship_get_size(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
lua_pushinteger(L, self->size); lua_pushinteger(L, sh->size);
return 1; return 1;
} }
static int tolua_ship_get_display(lua_State * L) static int tolua_ship_get_display(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
tolua_pushstring(L, self->display); tolua_pushstring(L, sh->display);
return 1; return 1;
} }
static int tolua_ship_get_region(lua_State * L) static int tolua_ship_get_region(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
if (self) { if (sh) {
tolua_pushusertype(L, self->region, TOLUA_CAST "region"); tolua_pushusertype(L, sh->region, TOLUA_CAST "region");
return 1; return 1;
} }
return 0; return 0;
@ -78,43 +93,43 @@ static int tolua_ship_get_region(lua_State * L)
static int tolua_ship_set_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); region *r = (region *)tolua_tousertype(L, 2, NULL);
if (self) { if (sh) {
move_ship(self, self->region, r, NULL); move_ship(sh, sh->region, r, NULL);
} }
return 0; return 0;
} }
static int tolua_ship_set_name(lua_State * L) static int tolua_ship_set_name(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
ship_setname(self, tolua_tostring(L, 2, NULL)); ship_setname(sh, tolua_tostring(L, 2, NULL));
return 0; return 0;
} }
static int tolua_ship_set_size(lua_State * L) static int tolua_ship_set_size(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
self->size = lua_tointeger(L, 2); sh->size = lua_tointeger(L, 2);
return 0; return 0;
} }
static int tolua_ship_set_display(lua_State * L) static int tolua_ship_set_display(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
free(self->display); free(sh->display);
self->display = str_strdup(tolua_tostring(L, 2, NULL)); sh->display = str_strdup(tolua_tostring(L, 2, NULL));
return 0; return 0;
} }
static int tolua_ship_get_units(lua_State * L) 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 **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; u = u->next;
luaL_getmetatable(L, TOLUA_CAST "unit"); luaL_getmetatable(L, TOLUA_CAST "unit");
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
@ -147,42 +162,42 @@ static int tolua_ship_create(lua_State * L)
static int static int
tolua_ship_tostring(lua_State * L) tolua_ship_tostring(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
lua_pushstring(L, shipname(self)); lua_pushstring(L, shipname(sh));
return 1; return 1;
} }
static int tolua_ship_get_flags(lua_State * L) static int tolua_ship_get_flags(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
lua_pushinteger(L, self->flags); lua_pushinteger(L, sh->flags);
return 1; return 1;
} }
static int tolua_ship_set_flags(lua_State * L) static int tolua_ship_set_flags(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
self->flags = (int)lua_tointeger(L, 2); sh->flags = (int)lua_tointeger(L, 2);
return 0; return 0;
} }
static int tolua_ship_set_coast(lua_State * L) 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)) { if (lua_isnil(L, 2)) {
self->coast = NODIRECTION; sh->coast = NODIRECTION;
} }
else if (lua_isnumber(L, 2)) { else if (lua_isnumber(L, 2)) {
self->coast = (direction_t)lua_tointeger(L, 2); sh->coast = (direction_t)lua_tointeger(L, 2);
} }
return 0; return 0;
} }
static int tolua_ship_get_coast(lua_State * L) static int tolua_ship_get_coast(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
if (self->coast) { if (sh->coast) {
lua_pushinteger(L, self->coast); lua_pushinteger(L, sh->coast);
return 1; return 1;
} }
return 0; return 0;
@ -190,30 +205,30 @@ static int tolua_ship_get_coast(lua_State * L)
static int tolua_ship_get_type(lua_State * L) static int tolua_ship_get_type(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
tolua_pushstring(L, self->type->_name); tolua_pushstring(L, sh->type->_name);
return 1; return 1;
} }
static int tolua_ship_get_damage(lua_State * L) static int tolua_ship_get_damage(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
lua_pushinteger(L, self->damage); lua_pushinteger(L, sh->damage);
return 1; return 1;
} }
static int tolua_ship_set_damage(lua_State * L) static int tolua_ship_set_damage(lua_State * L)
{ {
ship *self = (ship *)tolua_tousertype(L, 1, NULL); ship *sh = (ship *)tolua_tousertype(L, 1, NULL);
self->damage = (int)lua_tointeger(L, 2); sh->damage = (int)lua_tointeger(L, 2);
return 0; return 0;
} }
static int tolua_ship_get_curse(lua_State *L) { 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); const char *name = tolua_tostring(L, 2, NULL);
if (self->attribs) { if (sh->attribs) {
curse * c = get_curse(self->attribs, ct_find(name)); curse * c = get_curse(sh->attribs, ct_find(name));
if (c) { if (c) {
lua_pushnumber(L, curse_geteffect(c)); lua_pushnumber(L, curse_geteffect(c));
return 1; return 1;
@ -223,9 +238,9 @@ static int tolua_ship_get_curse(lua_State *L) {
} }
static int tolua_ship_has_attrib(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); 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); lua_pushboolean(L, a != NULL);
return 1; return 1;
} }
@ -243,6 +258,7 @@ void tolua_ship_open(lua_State * L)
{ {
tolua_function(L, TOLUA_CAST "__tostring", tolua_ship_tostring); 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 "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_variable(L, TOLUA_CAST "name", tolua_ship_get_name,
tolua_ship_set_name); tolua_ship_set_name);
tolua_variable(L, TOLUA_CAST "size", tolua_ship_get_size, tolua_variable(L, TOLUA_CAST "size", tolua_ship_get_size,

View File

@ -884,9 +884,19 @@ static int tolua_unit_create(lua_State * L)
const char *rcname = tolua_tostring(L, 4, NULL); const char *rcname = tolua_tostring(L, 4, NULL);
const race *rc; 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; 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); u = create_unit(r, f, num, rc, 0, NULL, NULL);
tolua_pushusertype(L, u, TOLUA_CAST "unit"); tolua_pushusertype(L, u, TOLUA_CAST "unit");
return 1; return 1;

View File

@ -84,7 +84,7 @@ static char g_bigbuf[BUFFERSIZE];
bool opt_cr_absolute_coords = false; bool opt_cr_absolute_coords = false;
/* globals */ /* globals */
#define C_REPORT_VERSION 66 #define C_REPORT_VERSION 67
struct locale *crtag_locale(void) { struct locale *crtag_locale(void) {
static struct locale * lang; static struct locale * lang;
@ -515,8 +515,10 @@ static void report_crtypes(FILE * F, const struct locale *lang)
fputc('\"', F); fputc('\"', F);
fputs(crescape(nrt_string(kmt->mtype, lang), buffer, sizeof(buffer)), F); fputs(crescape(nrt_string(kmt->mtype, lang), buffer, sizeof(buffer)), F);
fputs("\";text\n", F); fputs("\";text\n", F);
if (kmt->mtype->section) {
fprintf(F, "\"%s\";section\n", kmt->mtype->section); fprintf(F, "\"%s\";section\n", kmt->mtype->section);
} }
}
while (mtypehash[i]) { while (mtypehash[i]) {
kmt = mtypehash[i]; kmt = mtypehash[i];
mtypehash[i] = mtypehash[i]->nexthash; mtypehash[i] = mtypehash[i]->nexthash;
@ -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\";Beschr\n", sh->display);
stream_printf(out, "\"%s\";Typ\n", translate(sh->type->_name, stream_printf(out, "\"%s\";Typ\n", translate(sh->type->_name,
LOC(f->locale, 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); stream_printf(out, "%d;Groesse\n", sh->size);
if (sh->damage) { if (sh->damage) {
int percent = int percent =
@ -710,7 +713,7 @@ static void cr_output_ship(struct stream *out, const ship *sh, const unit *u,
/* calculate cargo */ /* calculate cargo */
if (u && (u->faction == f || omniscient(f))) { if (u && (u->faction == f || omniscient(f))) {
int n = 0, p = 0; int n = 0, p = 0;
int mweight = shipcapacity(sh); int mweight = ship_capacity(sh);
getshipweight(sh, &n, &p); getshipweight(sh, &n, &p);
stream_printf(out, "%d;capacity\n", mweight); stream_printf(out, "%d;capacity\n", mweight);

View File

@ -293,6 +293,117 @@ bool rule_transfermen(void)
return rule != 0; 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) message * give_men(int n, unit * u, unit * u2, struct order *ord)
{ {
int error = 0; int error = 0;
@ -652,7 +763,8 @@ static void give_all_items(unit *u, unit *u2, order *ord) {
} }
} }
else { 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)) { if (!(u_race(u)->ec_flags & ECF_GIVEPERSON)) {
ADDMSG(&u->faction->msgs, ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); msg_feedback(u, ord, "race_noregroup", "race", u_race(u)));
@ -815,7 +927,24 @@ void give_cmd(unit * u, order * ord)
return; 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)) { if (!(u_race(u)->ec_flags & ECF_GIVEPERSON)) {
ADDMSG(&u->faction->msgs, ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); msg_feedback(u, ord, "race_noregroup", "race", u_race(u)));

View File

@ -101,6 +101,10 @@ struct order *ord)
cmistake(u, ord, 20, MSG_MOVE); cmistake(u, ord, 20, MSG_MOVE);
return -1; return -1;
} }
if (sh->number > 1) {
cmistake(u, ord, 325, MSG_MAGIC);
return -1;
}
effect = SPEEDSAIL_EFFECT; effect = SPEEDSAIL_EFFECT;
create_curse(u, &sh->attribs, &ct_shipspeedup, 20, INT_MAX, effect, 0); create_curse(u, &sh->attribs, &ct_shipspeedup, 20, INT_MAX, effect, 0);

View File

@ -932,8 +932,7 @@ static void build_ship(unit * u, ship * sh, int want)
msg_message("buildship", "ship unit size", sh, u, n)); msg_message("buildship", "ship unit size", sh, u, n));
} }
void void create_ship(unit * u, const struct ship_type *newtype, int want,
create_ship(unit * u, const struct ship_type *newtype, int want,
order * ord) order * ord)
{ {
ship *sh; ship *sh;

View File

@ -45,8 +45,9 @@
#define FIX_RES_BASE_VERSION 367 /* fixing resource base */ #define FIX_RES_BASE_VERSION 367 /* fixing resource base */
#define FIX_CLONES_VERSION 368 /* dissolve clones */ #define FIX_CLONES_VERSION 368 /* dissolve clones */
#define FIX_MIGRANT_AURA_VERSION 369 /* bug 2585, migrants with aura */ #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 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 */ #define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */

View File

@ -1283,6 +1283,8 @@ void write_ship(gamedata *data, const ship *sh)
WRITE_STR(store, (const char *)sh->name); WRITE_STR(store, (const char *)sh->name);
WRITE_STR(store, sh->display ? (const char *)sh->display : ""); WRITE_STR(store, sh->display ? (const char *)sh->display : "");
WRITE_TOK(store, sh->type->_name); WRITE_TOK(store, sh->type->_name);
assert(sh->number > 0);
WRITE_INT(store, sh->number);
WRITE_INT(store, sh->size); WRITE_INT(store, sh->size);
WRITE_INT(store, sh->damage); WRITE_INT(store, sh->damage);
WRITE_INT(store, sh->flags & SFL_SAVEMASK); WRITE_INT(store, sh->flags & SFL_SAVEMASK);
@ -1320,6 +1322,12 @@ ship *read_ship(gamedata *data)
} }
assert(sh->type || !"ship_type not registered!"); 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->size);
READ_INT(store, &sh->damage); READ_INT(store, &sh->damage);
if (data->version >= FOSS_VERSION) { if (data->version >= FOSS_VERSION) {

View File

@ -181,6 +181,7 @@ ship *new_ship(const ship_type * stype, region * r, const struct locale *lang)
sh->coast = NODIRECTION; sh->coast = NODIRECTION;
sh->type = stype; sh->type = stype;
sh->region = r; sh->region = r;
sh->number = 1;
if (lang) { if (lang) {
sname = LOC(lang, stype->_name); sname = LOC(lang, stype->_name);
@ -275,13 +276,13 @@ static int ShipSpeedBonus(const unit * u)
} }
if (bonus > 0) { if (bonus > 0) {
int skl = effskill(u, SK_SAILING, NULL); 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; return (skl - minsk) / bonus;
} }
else if (sh->type->flags & SFL_SPEEDY) { else if (sh->type->flags & SFL_SPEEDY) {
int base = 3; int base = 3;
int speed = 0; int speed = 0;
int minsk = sh->type->cptskill * base; int minsk = ship_captain_minskill(sh) * base;
int skl = effskill(u, SK_SAILING, NULL); int skl = effskill(u, SK_SAILING, NULL);
while (skl >= minsk) { while (skl >= minsk) {
++speed; ++speed;
@ -292,21 +293,8 @@ static int ShipSpeedBonus(const unit * u)
return 0; return 0;
} }
int crew_skill(const ship *sh) { int ship_captain_minskill(const ship *sh) {
int n = 0; return sh->type->cptskill;
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 shipspeed(const ship * sh, const unit * u) int shipspeed(const ship * sh, const unit * u)
@ -323,9 +311,9 @@ int shipspeed(const ship * sh, const unit * u)
assert(sh->type->construction); assert(sh->type->construction);
k = sh->type->range; k = sh->type->range;
if (sh->size != sh->type->construction->maxsize) if (!ship_finished(sh)) {
return 0; return 0;
}
if (sh->attribs) { if (sh->attribs) {
if (curse_active(get_curse(sh->attribs, &ct_stormwind))) { if (curse_active(get_curse(sh->attribs, &ct_stormwind))) {
k *= 2; k *= 2;
@ -385,17 +373,85 @@ const char *shipname(const ship * sh)
return write_shipname(sh, ibuf, sizeof(idbuf[0])); 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) {
return (sh->size >= sh->number * sh->type->construction->maxsize);
}
return true;
}
if (sh->type->construction && sh->size != sh->type->construction->maxsize) int enoughsailors(const ship * sh, int crew_skill)
return 0; {
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) { if (sh->damage) {
i = (int)ceil(i * (1.0 - sh->damage / sh->size / (double)DAMAGE_SCALE)); i = (int)ceil(i * (1.0 - sh->damage / sh->size / (double)DAMAGE_SCALE));
} }
return i; 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) 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); 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); free(sh->name);
self->name = name ? str_strdup(name) : 0; 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) { int ship_damage_percent(const ship *sh) {
return (ship->damage * 100 + DAMAGE_SCALE - 1) / (ship->size * DAMAGE_SCALE); return (sh->damage * 100 + DAMAGE_SCALE - 1) / (sh->size * DAMAGE_SCALE);
} }

View File

@ -73,6 +73,7 @@ extern "C" {
struct ship *nexthash; struct ship *nexthash;
struct unit * _owner; /* never use directly, always use ship_owner() */ struct unit * _owner; /* never use directly, always use ship_owner() */
int no; int no;
int number;
struct region *region; struct region *region;
char *name; char *name;
char *display; char *display;
@ -89,8 +90,10 @@ extern "C" {
struct unit *ship_owner(const struct ship *sh); struct unit *ship_owner(const struct ship *sh);
void ship_update_owner(struct ship * sh); void ship_update_owner(struct ship * sh);
extern const char *shipname(const struct ship *self); const char *shipname(const struct ship *self);
extern int shipcapacity(const struct ship *sh); 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 void getshipweight(const struct ship *sh, int *weight, int *cabins);
extern ship *new_ship(const struct ship_type *stype, struct region *r, 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); const char *ship_getname(const struct ship *sh);
void ship_setname(struct ship *self, const char *name); void ship_setname(struct ship *self, const char *name);
int shipspeed(const struct ship *sh, const struct unit *u); 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 crew_skill(const struct ship *sh);
int ship_captain_minskill(const struct ship *sh);
int ship_damage_percent(const struct ship *sh); int ship_damage_percent(const struct ship *sh);
void scale_ship(struct ship *sh, int n);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1094,8 +1094,8 @@ int enter_ship(unit * u, struct order *ord, int id, bool report)
} }
if (CheckOverload()) { if (CheckOverload()) {
int sweight, scabins; int sweight, scabins;
int mweight = shipcapacity(sh); int mweight = ship_capacity(sh);
int mcabins = sh->type->cabins; int mcabins = ship_cabins(sh);
if (mweight > 0) { if (mweight > 0) {
getshipweight(sh, &sweight, &scabins); getshipweight(sh, &sweight, &scabins);
@ -2598,7 +2598,7 @@ void sinkships(struct region * r)
if (!sh->type->construction || sh->size >= sh->type->construction->maxsize) { if (!sh->type->construction || sh->size >= sh->type->construction->maxsize) {
if (fval(r->terrain, SEA_REGION)) { 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 */ /* ship is at sea, but not enough people to control it */
double dmg = config_get_flt("rules.ship.damage.nocrewocean", 0.3); double dmg = config_get_flt("rules.ship.damage.nocrewocean", 0.3);
damage_ship(sh, dmg); damage_ship(sh, dmg);

View File

@ -470,13 +470,13 @@ static bool cansail(const region * r, ship * sh)
{ {
UNUSED_ARG(r); UNUSED_ARG(r);
if (sh->type->construction && sh->size != sh->type->construction->maxsize) { if (!ship_finished(sh)) {
return false; return false;
} }
else { else {
int n = 0, p = 0; int n = 0, p = 0;
int mweight = shipcapacity(sh); int mweight = ship_capacity(sh);
int mcabins = sh->type->cabins; int mcabins = ship_cabins(sh);
getshipweight(sh, &n, &p); getshipweight(sh, &n, &p);
@ -492,12 +492,12 @@ static double overload(const region * r, ship * sh)
{ {
UNUSED_ARG(r); UNUSED_ARG(r);
if (sh->type->construction && sh->size != sh->type->construction->maxsize) { if (!ship_finished(sh)) {
return DBL_MAX; return DBL_MAX;
} }
else { else {
int n = 0, p = 0; int n = 0, p = 0;
int mcabins = sh->type->cabins; int mcabins = sh->type->cabins * sh->number;
double ovl; double ovl;
getshipweight(sh, &n, &p); 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) static ship *do_maelstrom(region * r, unit * u)
@ -808,7 +803,7 @@ static void drifting_ships(region * r)
ship *sh = *shp; ship *sh = *shp;
region *rnext = NULL; region *rnext = NULL;
region_list *route = NULL; region_list *route = NULL;
unit *firstu = r->units, *lastu = NULL, *captain; unit *firstu = r->units, *lastu = NULL;
direction_t dir = NODIRECTION; direction_t dir = NODIRECTION;
double ovl; double ovl;
@ -822,16 +817,10 @@ static void drifting_ships(region * r)
continue; continue;
} }
/* Kapitaen bestimmen */
captain = ship_owner(sh);
if (captain && effskill(captain, SK_SAILING, r) < sh->type->cptskill)
captain = NULL;
/* Kapitaen da? Beschaedigt? Genuegend Matrosen? /* Kapitaen da? Beschaedigt? Genuegend Matrosen?
* Genuegend leicht? Dann ist alles OK. */ * Genuegend leicht? Dann ist alles OK. */
if (captain && sh->size == sh->type->construction->maxsize if (ship_finished(sh) && ship_crewed(sh) && cansail(r, sh)) {
&& enoughsailors(sh, crew_skill(sh)) && cansail(r, sh)) {
shp = &sh->next; shp = &sh->next;
continue; continue;
} }
@ -1639,19 +1628,17 @@ static bool ship_ready(const region * r, unit * u, order * ord)
cmistake(u, ord, 146, MSG_MOVE); cmistake(u, ord, 146, MSG_MOVE);
return false; 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, 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)); u->ship));
return false; return false;
} }
if (u->ship->type->construction) { if (!ship_finished(u->ship)) {
if (u->ship->size != u->ship->type->construction->maxsize) {
cmistake(u, ord, 15, MSG_MOVE); cmistake(u, ord, 15, MSG_MOVE);
return false; return false;
} }
} if (!ship_crewed(u->ship)) {
if (!enoughsailors(u->ship, crew_skill(u->ship))) {
cmistake(u, ord, 1, MSG_MOVE); cmistake(u, ord, 1, MSG_MOVE);
return false; return false;
} }

View File

@ -53,7 +53,6 @@ extern "C" {
int personcapacity(const struct unit *u); int personcapacity(const struct unit *u);
void movement(void); void movement(void);
void run_to(struct unit *u, struct region *to);
int enoughsailors(const struct ship *sh, int sumskill); int enoughsailors(const struct ship *sh, int sumskill);
bool canswim(struct unit *u); bool canswim(struct unit *u);
bool canfly(struct unit *u); bool canfly(struct unit *u);

View File

@ -1724,11 +1724,14 @@ nr_ship(struct stream *out, const region *r, const ship * sh, const faction * f,
if (captain && captain->faction == f) { if (captain && captain->faction == f) {
int n = 0, p = 0; int n = 0, p = 0;
const char *stname;
getshipweight(sh, &n, &p); getshipweight(sh, &n, &p);
n = (n + 99) / 100; /* 1 Silber = 1 GE */ n = (n + 99) / 100; /* 1 Silber = 1 GE */
sbs_printf(&sbs, "%s, %s, (%d/%d)", shipname(sh), stname = locale_plural(f->locale, sh->type->_name, sh->number, true);
LOC(f->locale, sh->type->_name), n, shipcapacity(sh) / 100); sbs_printf(&sbs, "%s, %d %s, (%d/%d)", shipname(sh), sh->number,
stname, n, ship_capacity(sh) / 100);
} }
else { else {
sbs_printf(&sbs, "%s, %s", shipname(sh), LOC(f->locale, sh->type->_name)); sbs_printf(&sbs, "%s, %s", shipname(sh), LOC(f->locale, sh->type->_name));

View File

@ -808,6 +808,10 @@ static int sp_goodwinds(castorder * co)
return 0; return 0;
sh = pa->param[0]->data.sh; 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 */ /* keine Probleme mit C_SHIP_SPEEDUP und C_SHIP_FLYING */
/* NODRIFT bewirkt auch +1 Geschwindigkeit */ /* NODRIFT bewirkt auch +1 Geschwindigkeit */
@ -2231,6 +2235,10 @@ static int sp_stormwinds(castorder * co)
sh = pa->param[n]->data.sh; 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)) { if (is_cursed(sh->attribs, &ct_flyingship)) {
ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order, ADDMSG(&caster->faction->msgs, msg_feedback(caster, co->order,
"error_spell_on_flying_ship", "ship", sh)) "error_spell_on_flying_ship", "ship", sh))

View File

@ -129,6 +129,19 @@ const char *locale_getstring(const locale * lang, const char *key)
return NULL; 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) const char *locale_string(const locale * lang, const char *key, bool warn)
{ {
assert(lang); assert(lang);

View File

@ -32,6 +32,7 @@ extern "C" {
const char *locale_getstring(const struct locale *lang, const char *locale_getstring(const struct locale *lang,
const char *key); const char *key);
const char *locale_string(const struct locale *lang, const char *key, bool warn); /* does fallback */ 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); unsigned int locale_index(const struct locale *lang);
const char *locale_name(const struct locale *lang); const char *locale_name(const struct locale *lang);