TiborB has proposed merging lp:~widelands-dev/widelands/bug-1380287 into lp:widelands.
Requested reviews: Widelands Developers (widelands-dev) Related bugs: Bug #1380287 in widelands: "Ships should be supported in Lua scripting" https://bugs.launchpad.net/widelands/+bug/1380287 For more details, see: https://code.launchpad.net/~widelands-dev/widelands/bug-1380287/+merge/252507 I implemented some LUA interface for ships, f.e.: map:get_ships - to get list of player' ships on map ships.field - to get a field where ship is located ships.status - to get status of ship (what is it doing) port:start_expedition(), port:cancel_expedition(), port.expedition_in_progress - selfexplanatory... ship.scout_direction, ship.island_scout_direction - sets and get direction of ship if in expedition mode ship:build_colonization_port() Please review -- Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/bug-1380287 into lp:widelands.
=== modified file 'src/logic/ship.cc' --- src/logic/ship.cc 2015-02-05 12:11:20 +0000 +++ src/logic/ship.cc 2015-03-10 20:18:11 +0000 @@ -831,6 +831,22 @@ m_expedition->island_exploration = false; } +//Returns integer of direction, or 255 if query invalid +//Intended for LUA scripting +uint8_t Ship::get_scout_direction() { + if (!m_expedition) { + return std::numeric_limits<uint8_t>::max(); + } + if (m_ship_state != EXP_SCOUTING) { + return std::numeric_limits<uint8_t>::max(); + } + if (m_expedition->island_exploration) { + return std::numeric_limits<uint8_t>::max(); + } + + return static_cast<uint8_t>(m_expedition->direction); +} + /// Initializes the construction of a port at @arg c /// @note only called via player command void Ship::exp_construct_port(Game&, const Coords& c) { @@ -850,6 +866,23 @@ m_expedition->island_exploration = true; } +//Returns integer of direction, or 255 if query invalid +//Intended for LUA scripting +uint8_t Ship::get_island_explore_direction() { + if (!m_expedition) { + return std::numeric_limits<uint8_t>::max(); + } + if (m_ship_state != EXP_SCOUTING) { + return std::numeric_limits<uint8_t>::max(); + } + if (!m_expedition->island_exploration) { + return std::numeric_limits<uint8_t>::max(); + } + + return static_cast<uint8_t>(m_expedition->scouting_direction); +} + + /// Cancels a currently running expedition /// @note only called via player command void Ship::exp_cancel(Game& game) { === modified file 'src/logic/ship.h' --- src/logic/ship.h 2015-02-05 12:11:20 +0000 +++ src/logic/ship.h 2015-03-10 20:18:11 +0000 @@ -205,6 +205,8 @@ void exp_scout_direction(Game &, uint8_t); void exp_construct_port (Game &, const Coords&); void exp_explore_island (Game &, ScoutingDirection); + uint8_t get_scout_direction(); + uint8_t get_island_explore_direction(); void exp_cancel (Game &); void sink_ship (Game &); === modified file 'src/scripting/lua_game.cc' --- src/scripting/lua_game.cc 2015-01-31 16:03:59 +0000 +++ src/scripting/lua_game.cc 2015-03-10 20:18:11 +0000 @@ -97,6 +97,7 @@ METHOD(LuaPlayer, hide_fields), METHOD(LuaPlayer, reveal_scenario), METHOD(LuaPlayer, reveal_campaign), + METHOD(LuaPlayer, get_ships), METHOD(LuaPlayer, get_buildings), METHOD(LuaPlayer, get_suitability), METHOD(LuaPlayer, allow_workers), @@ -628,6 +629,7 @@ int LuaPlayer::reveal_campaign(lua_State * L) { if (get_game(L).get_ipl()->player_number() != player_number()) report_error(L, "Can only be called for interactive player!"); + report_error(L, "Can only be called for interactive player!"); CampaignVisibilitySave cvs; cvs.set_campaign_visibility(luaL_checkstring(L, 2), true); @@ -635,6 +637,42 @@ return 0; } +/* RST + .. method:: get_ships() + + :returns: array of player's ships + :rtype: :class:`array` or :class:`table` +*/ + +int LuaPlayer::get_ships(lua_State * L) { + EditorGameBase & egbase = get_egbase(L); + Map * map = egbase.get_map(); + PlayerNumber p = (get(L, egbase)).player_number(); + lua_newtable(L); + uint32_t cidx = 1; + + std::set<OPtr<Ship>> found_ships; + for (int16_t y = 0; y < map->get_height(); ++y) { + for (int16_t x = 0; x < map->get_width(); ++x) { + FCoords f = map->get_fcoords(Coords(x, y)); + // there are too many bobs on the map so we investigate + // only bobs on water + if (f.field->nodecaps() & MOVECAPS_SWIM) { + for (Bob* bob = f.field->get_first_bob(); bob; bob = bob->get_next_on_field()) { + if (upcast(Ship, ship, bob)) { + if (ship->get_owner()->player_number() == p && !found_ships.count(ship)) { + found_ships.insert(ship); + lua_pushuint32(L, cidx++); + LuaMaps::upcasted_map_object_to_lua(L, ship); + lua_rawset(L, -3); + } + } + } + } + } + } + return 1; +} /* RST .. method:: get_buildings(which) === modified file 'src/scripting/lua_game.h' --- src/scripting/lua_game.h 2015-02-09 05:57:08 +0000 +++ src/scripting/lua_game.h 2015-03-10 20:18:11 +0000 @@ -83,6 +83,7 @@ int hide_fields(lua_State * L); int reveal_scenario(lua_State * L); int reveal_campaign(lua_State * L); + int get_ships(lua_State * L); int get_buildings(lua_State * L); int get_suitability(lua_State * L); int allow_workers(lua_State * L); === modified file 'src/scripting/lua_map.cc' --- src/scripting/lua_map.cc 2015-02-12 21:03:20 +0000 +++ src/scripting/lua_map.cc 2015-03-10 20:18:11 +0000 @@ -32,6 +32,7 @@ #include "logic/maphollowregion.h" #include "logic/mapregion.h" #include "logic/player.h" +#include "logic/ship.h" #include "logic/soldier.h" #include "logic/warelist.h" #include "logic/widelands_geometry.h" @@ -44,6 +45,10 @@ #include "scripting/lua_game.h" #include "wui/mapviewpixelfunctions.h" + +//#include "scripting/luna_impl.h" // +//#include "economy/portdock.h" + using namespace Widelands; namespace LuaMaps { @@ -2681,13 +2686,13 @@ ========================================================== */ + /* ========================================================== C METHODS ========================================================== */ - /* RST Building -------- @@ -2806,10 +2811,13 @@ METHOD(LuaWarehouse, get_workers), METHOD(LuaWarehouse, set_soldiers), METHOD(LuaWarehouse, get_soldiers), + METHOD(LuaWarehouse, start_expedition), + METHOD(LuaWarehouse, cancel_expedition), {nullptr, nullptr}, }; const PropertyType<LuaWarehouse> LuaWarehouse::Properties[] = { PROP_RO(LuaWarehouse, portdock), + PROP_RO(LuaWarehouse, expedition_in_progress), {nullptr, nullptr, nullptr}, }; @@ -2829,6 +2837,26 @@ return upcasted_map_object_to_lua(L, get(L, get_egbase(L))->get_portdock()); } +/* RST + .. attribute:: expedition_in_progress + + (RO) If this Warehouse is a port, and an expedition is in + progress, returns true, otherwise nil +*/ +int LuaWarehouse::get_expedition_in_progress(lua_State * L) { + + Warehouse* Wh = get(L, get_egbase(L)); + + if (upcast(Game, game, &get_egbase(L))) { + PortDock* pd = Wh->get_portdock(); + if (pd) { + if (pd->expedition_started()){ + return 1; + } + } + } + return 0; +} /* ========================================================== @@ -2895,13 +2923,72 @@ return do_set_soldiers(L, wh->get_position(), wh, wh->get_owner()); } +/* RST + .. method:: start_expedition(port) + + :arg port + + Starts preparation for expedition + +*/ +int LuaWarehouse::start_expedition(lua_State* L) { + + Warehouse* Wh = get(L, get_egbase(L)); + + if (!Wh) { + return 0; + } + + if (upcast(Game, game, &get_egbase(L))) { + PortDock* pd = Wh->get_portdock(); + if (!pd) { + return 0; + } + if (!pd->expedition_started()){ + game->send_player_start_or_cancel_expedition(*Wh); + return 1; + } + } + + return 0; +} + +/* RST + .. method:: cancel_expedition(port) + + :arg port + + Cancels an expedition if in progress + +*/ +int LuaWarehouse::cancel_expedition(lua_State* L) { + + Warehouse* Wh = get(L, get_egbase(L)); + + if (!Wh) { + return 0; + } + + if (upcast(Game, game, &get_egbase(L))) { + PortDock* pd = Wh->get_portdock(); + if (!pd) { + return 0; + } + if (pd->expedition_started()){ + game->send_player_start_or_cancel_expedition(*Wh); + return 1; + } + } + + return 0; +} + /* ========================================================== C METHODS ========================================================== */ - /* RST ProductionSite -------------- @@ -3179,6 +3266,7 @@ {nullptr, nullptr}, }; const PropertyType<LuaBob> LuaBob::Properties[] = { + PROP_RO(LuaBob, field), {nullptr, nullptr, nullptr}, }; @@ -3189,6 +3277,27 @@ */ /* RST + .. attribute:: field //working here + + (RO) The field the bob is located on +*/ +// UNTESTED +int LuaBob::get_field(lua_State * L) { + + EditorGameBase & egbase = get_egbase(L); + + Coords coords = get(L, egbase)->get_position(); + + return to_lua<LuaMaps::LuaField>(L, new LuaMaps::LuaField(coords.x, coords.y)); +} + + +/* + ========================================================== + LUA METHODS + ========================================================== + */ +/* RST .. method:: has_caps(capname) Similar to :meth:`Field::has_caps`. @@ -3214,13 +3323,6 @@ return 1; } - -/* - ========================================================== - LUA METHODS - ========================================================== - */ - /* ========================================================== C METHODS @@ -3240,12 +3342,16 @@ const MethodType<LuaShip> LuaShip::Methods[] = { METHOD(LuaShip, get_wares), METHOD(LuaShip, get_workers), + METHOD(LuaShip, build_colonization_port), {nullptr, nullptr}, }; const PropertyType<LuaShip> LuaShip::Properties[] = { PROP_RO(LuaShip, debug_economy), PROP_RO(LuaShip, last_portdock), PROP_RO(LuaShip, destination), + PROP_RO(LuaShip, status), + PROP_RW(LuaShip, scout_direction), + PROP_RW(LuaShip, island_scout_direction), {nullptr, nullptr, nullptr}, }; @@ -3285,6 +3391,74 @@ return upcasted_map_object_to_lua(L, get(L, egbase)->get_lastdock(egbase)); } +/* RST // + .. attribute:: status + + (RW) returns/sets one of statuses as defined in enum in ship.h + (integer) + +*/ +int LuaShip::get_status(lua_State* L) { + EditorGameBase & egbase = get_egbase(L); + lua_pushuint32(L, static_cast<uint32_t>(get(L, egbase)->get_ship_state())); + return 1; +} + +int LuaShip::get_scout_direction(lua_State* L) { + + Ship* ship = get(L, get_egbase(L)); + if (upcast(Game, game, &get_egbase(L))) { + lua_pushuint32(L, static_cast<uint32_t>(ship->get_scout_direction())); + return 1; + } + return 0; +} + +int LuaShip::set_scout_direction(lua_State* L) { + + uint8_t dir = static_cast<uint8_t>(luaL_checkuint32(L, -1)); + Ship* ship = get(L, get_egbase(L)); + + if (upcast(Game, game, &get_egbase(L))) { + game->send_player_ship_scout_direction(*ship, dir); + return 1; + } + return 0; + +} + +/* RST + .. attribute:: island_scout_direction + + (RW) actual direction if the ship sails around an island. + Sets/returns int as defined in enum in logic/ship.h + now: CounterClockwise = 0, Clockwise = 1 + +*/ +// UNTESTED +int LuaShip::get_island_scout_direction(lua_State* L) { + + Ship* ship = get(L, get_egbase(L)); + if (upcast(Game, game, &get_egbase(L))) { + lua_pushuint32(L, static_cast<uint32_t>(ship->get_island_explore_direction())); + return 1; + } + return 0; +} + +int LuaShip::set_island_scout_direction(lua_State* L) { + + uint8_t dir = static_cast<uint8_t>(luaL_checkuint32(L, -1)); + Ship* ship = get(L, get_egbase(L)); + + if (upcast(Game, game, &get_egbase(L))) { + game->send_player_ship_explore_island(*ship, static_cast<Widelands::ScoutingDirection>(dir)); + return 1; + } + return 0; + +} + /* ========================================================== LUA METHODS @@ -3341,6 +3515,25 @@ return 1; } +/* RST + .. method:: build_colonization_port() + + Returns true if port space construction was started (ship was in adequate + status and a found portspace was nearby) + + :returns: true/false +*/ +int LuaShip::build_colonization_port(lua_State* L) { + Ship* ship = get(L, get_egbase(L)); + if (ship->get_ship_state() == 3) { // I would prefer here EXP_FOUNDPORTSPACE + if (upcast(Game, game, &get_egbase(L))) { + game->send_player_ship_construct_port(*ship, ship->exp_port_spaces()->front()); + return 1; + } + } + return 0; +} + /* ========================================================== C METHODS === modified file 'src/scripting/lua_map.h' --- src/scripting/lua_map.h 2015-02-12 21:03:20 +0000 +++ src/scripting/lua_map.h 2015-03-10 20:18:11 +0000 @@ -688,6 +688,7 @@ * Properties */ int get_portdock(lua_State* L); + int get_expedition_in_progress(lua_State* L); /* * Lua Methods @@ -698,6 +699,8 @@ int set_workers(lua_State*); int set_soldiers(lua_State*); int get_soldiers(lua_State*); + int start_expedition(lua_State*); + int cancel_expedition(lua_State*); /* * C Methods @@ -806,6 +809,7 @@ /* * Properties */ + int get_field(lua_State *); int has_caps(lua_State *); /* @@ -885,12 +889,17 @@ int get_debug_economy(lua_State * L); int get_last_portdock(lua_State* L); int get_destination(lua_State* L); - + int get_status(lua_State* L); + int get_scout_direction(lua_State* L); + int set_scout_direction(lua_State* L); + int get_island_scout_direction(lua_State* L); + int set_island_scout_direction(lua_State* L); /* * Lua methods */ int get_wares(lua_State* L); int get_workers(lua_State* L); + int build_colonization_port(lua_State* L); /* * C methods === modified file 'test/maps/expedition.wmf/scripting/init.lua' --- test/maps/expedition.wmf/scripting/init.lua 2014-08-01 15:30:12 +0000 +++ test/maps/expedition.wmf/scripting/init.lua 2015-03-10 20:18:11 +0000 @@ -93,24 +93,6 @@ assert_equal(1, port:get_workers("builder")) end -function start_expedition() - assert_true(click_building(p1, "port")) - sleep(100) - assert_true(click_button("start_expedition")) - sleep(100) - close_windows() - sleep(100) -end - -function cancel_expedition_in_port() - assert_true(click_building(p1, "port")) - sleep(100) - assert_true(click_button("cancel_expedition")) - sleep(100) - close_windows() - sleep(100) -end - function cancel_expedition_in_shipwindow(which_ship) click_on_ship(which_ship or first_ship) assert_true(click_button("cancel_expedition")) @@ -174,7 +156,7 @@ game.desired_speed = 10 * 1000 -- Start a new expedition. - start_expedition() + port:start_expedition() wait_for_message("Expedition Ready") game.desired_speed = 10 * 1000 sleep(10000) @@ -205,14 +187,15 @@ game.desired_speed = 10 * 1000 -- Start a new expedition. - start_expedition() + port:start_expedition() wait_for_message("Expedition Ready") game.desired_speed = 10 * 1000 sleep(10000) - click_on_ship(first_ship) - assert_true(click_button("expccw")) - sleep(8000) + first_ship.island_scout_direction=0 + sleep(2000) + assert_equal(0,first_ship.island_scout_direction) + sleep(6000) stable_save("sailing") assert_equal(1, p1:get_workers("builder")) @@ -235,13 +218,14 @@ game.desired_speed = 10 * 1000 -- Send expedition to port space. - start_expedition() + port:start_expedition() wait_for_message("Expedition Ready") assert_equal(1, p1:get_workers("builder")) sleep(500) - click_on_ship(first_ship) - assert_true(click_button("expccw")) + first_ship.island_scout_direction=0 + sleep(2000) + assert_equal(0,first_ship.island_scout_direction) wait_for_message("Port Space Found") sleep(500) assert_equal(1, p1:get_workers("builder")) @@ -272,12 +256,13 @@ port:set_wares("blackwood", 100) - start_expedition() + port:start_expedition() wait_for_message("Expedition Ready") - click_on_ship(first_ship) - assert_true(click_button("expccw")) + first_ship.island_scout_direction=0 + sleep(2000) + assert_equal(0,first_ship.island_scout_direction) wait_for_message("Port Space Found") - assert_true(click_button("buildport")) + first_ship:build_colonization_port() sleep(500) assert_equal(1, p1:get_workers("builder")) wait_for_message("Port") === added file 'test/maps/expedition.wmf/scripting/test_ship_movement_controls.lua' --- test/maps/expedition.wmf/scripting/test_ship_movement_controls.lua 1970-01-01 00:00:00 +0000 +++ test/maps/expedition.wmf/scripting/test_ship_movement_controls.lua 2015-03-10 20:18:11 +0000 @@ -0,0 +1,86 @@ +run(function() + game.desired_speed = 30 * 1000 + p1:place_bob("ship", map:get_field(10, 10)) + + port = map:get_field(16, 16).immovable + port:set_wares("log", 10) -- no sense to wait + port:set_wares("blackwood", 10) + + --getting table with all our ships (single one only) + ships = p1:get_ships() + + --veryfing that ship is indeed placed where should be :) + assert_equal(10,ships[1].field.x) + assert_equal(10,ships[1].field.y) + + --ships table should contain 1 item (1 ship) + assert_equal(1, #ships) + + --ship has no wares on it + assert_equal(0,ships[1]:get_wares()) + + --no destination is set + assert(not ships[1].destination) + + --ships in transport state (=0) + assert_equal(0,ships[1].status) + + --the warehouse is probably not in expedition status :) + assert(not map:get_field(8, 18).immovable.expedition_in_progress) + + --starting prepartion for expedition + assert(not port.expedition_in_progress) + port:start_expedition() + sleep (300) + assert(port.expedition_in_progress) + + --ships changes status when exp ready + while ships[1].status == 0 do sleep(2000) end + + --sending NW and verifying + ships[1].scout_direction=6 + sleep(3000) + assert_equal(6, ships[1].scout_direction) + + while ships[1].scout_direction == 6 do + sleep (2000) + end + + --now ships stops nearby NW coast, so sending it back + ships[1].scout_direction=3 + sleep(3000) + assert_equal(3, ships[1].scout_direction) + + --waiting till it stops (value=255) + while ships[1].scout_direction <255 do sleep(2000) end + + --sending to scout the island + ships[1].island_scout_direction=1; + sleep(3000) + assert_equal(1, ships[1].island_scout_direction) + + --fine, now change the direction + ships[1].island_scout_direction=0; + sleep(3000) + assert_equal(0, ships[1].island_scout_direction) + + -- wait till it finds a port + wait_for_message("Port Space Found") + --starting colonization port here + assert(ships[1]:build_colonization_port()) + sleep(15000) + stable_save("port_in_constr") + + -- while unfinished yet, removing it + new_port=map:get_field(16,2).immovable + assert(new_port) + new_port:remove() + sleep(3000) + + --yes, the ships is back in transport mode + assert(0,ships[1].status) + + print("# All Tests passed.") + wl.ui.MapView():close() + +end) === modified file 'test/maps/expedition.wmf/scripting/test_starting_and_immediately_canceling.lua' --- test/maps/expedition.wmf/scripting/test_starting_and_immediately_canceling.lua 2013-10-29 20:22:08 +0000 +++ test/maps/expedition.wmf/scripting/test_starting_and_immediately_canceling.lua 2015-03-10 20:18:11 +0000 @@ -5,8 +5,8 @@ -- Start and immediately cancel an expedition. print("---- 1 -----") - start_expedition() - cancel_expedition_in_port() + port:start_expedition() + port:cancel_expedition() sleep(500) assert_equal(1, p1:get_workers("builder")) === modified file 'test/maps/expedition.wmf/scripting/test_starting_wait_a_while_cancel.lua' --- test/maps/expedition.wmf/scripting/test_starting_wait_a_while_cancel.lua 2013-10-29 20:22:08 +0000 +++ test/maps/expedition.wmf/scripting/test_starting_wait_a_while_cancel.lua 2015-03-10 20:18:11 +0000 @@ -4,12 +4,12 @@ -- Start an expedition, but let them carry some wares into it. This also -- gives the builder enough time to walk over. - start_expedition() + port:start_expedition() sleep(50000) stable_save("cancel_in_port") assert_equal(1, p1:get_workers("builder")) - cancel_expedition_in_port() + port:cancel_expedition() sleep(500) assert_equal(1, p1:get_workers("builder")) === modified file 'test/maps/ship_transportation.wmf/scripting/init.lua' --- test/maps/ship_transportation.wmf/scripting/init.lua 2015-02-10 21:25:14 +0000 +++ test/maps/ship_transportation.wmf/scripting/init.lua 2015-03-10 20:18:11 +0000 @@ -37,23 +37,6 @@ return nil end -function portdock2() - local portdock = map:get_field(15, 4).immovable - if portdock then - return portdock - end - local portdock = map:get_field(14, 5).immovable - if portdock then - return portdock - end - local portdock = map:get_field(14, 4).immovable - if portdock then - return portdock - end - print ("portdock not found") - return nill -end - function start_building_farm() p1:place_building("farm", map:get_field(18, 4), true, true) connected_road(p1, map:get_field(18,5).immovable, "l,l|tl,tr|", true) === modified file 'test/maps/ship_transportation.wmf/scripting/test_rip_portdock_with_worker_and_ware_in_transit.lua' --- test/maps/ship_transportation.wmf/scripting/test_rip_portdock_with_worker_and_ware_in_transit.lua 2015-02-10 21:25:14 +0000 +++ test/maps/ship_transportation.wmf/scripting/test_rip_portdock_with_worker_and_ware_in_transit.lua 2015-03-10 20:18:11 +0000 @@ -32,7 +32,9 @@ stable_save("restored_port") -- remove the portdock while the blackwood is in transit. - portdock2():remove() + port2_portdock=port2().portdock + assert(port2_portdock) + port2_portdock:remove() sleep(5000) === modified file 'test/maps/ship_transportation.wmf/scripting/test_rip_second_port_with_worker_in_portdock.lua' --- test/maps/ship_transportation.wmf/scripting/test_rip_second_port_with_worker_in_portdock.lua 2014-01-18 12:40:08 +0000 +++ test/maps/ship_transportation.wmf/scripting/test_rip_second_port_with_worker_in_portdock.lua 2015-03-10 20:18:11 +0000 @@ -5,6 +5,13 @@ create_first_port() create_second_port() + --removing portdock first + portdock_fields=port2().portdock.fields + portdock_fields[1].immovable:remove() + sleep(100) + --portdock should be back, as port is still there + assert (portdock_fields[1].immovable) + start_building_farm() port1():set_workers{ builder = 1, @@ -16,8 +23,13 @@ assert_equal(p1:get_workers("builder"), 1) assert_equal(port1():get_workers("builder"), 0) + portdock_fields=port2().portdock.fields port2():remove() sleep(100) + --verify that also portdock was removed + assert (not portdock_fields[1].immovable) + + sleep(100) stable_save("worker_in_portdock")
_______________________________________________ Mailing list: https://launchpad.net/~widelands-dev Post to : widelands-dev@lists.launchpad.net Unsubscribe : https://launchpad.net/~widelands-dev More help : https://help.launchpad.net/ListHelp