widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #04242
[Merge] lp:~widelands-dev/widelands/ship_scheduling into lp:widelands
TiborB has proposed merging lp:~widelands-dev/widelands/ship_scheduling into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/ship_scheduling/+merge/266626
This is rework of ship transportation - with goal to make it more effective (f.e. eliminate unexplained moves of ships and so on).
But I had to modify also regression tests, because in some situation ships behave differently, f.e. in current code in some situation first ship in m_ships is sent, or ship is sent to first port in m_ports, not considering distance or so.
I think there will have to be some discussion about this design :)
Oh, also debug window for port was improved, but still debug window for ship is missing, or rather not accessible in normal way... Once I had a ship on coast and was able to open debug window of ship. Obviously land and sea has bit different logic for opening debug wndows...
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/ship_scheduling into lp:widelands.
=== modified file 'src/economy/fleet.cc'
--- src/economy/fleet.cc 2015-02-05 12:11:20 +0000
+++ src/economy/fleet.cc 2015-07-31 20:49:05 +0000
@@ -337,6 +337,29 @@
return true;
}
+uint32_t Fleet::count_ships(){
+ return m_ships.size();
+}
+
+uint32_t Fleet::count_ships_heading_here(EditorGameBase & egbase, PortDock * port){
+ uint32_t ships_on_way = 0;
+ //if (upcast(Game, game, &owner().egbase())) { //NOCOM is upcast needed?
+ for (uint16_t s = 0; s < m_ships.size(); s += 1){
+ if (m_ships[s]->get_destination(egbase) == port){
+ ships_on_way += 1;
+ }
+ }
+ //}
+ return ships_on_way;
+}
+
+uint32_t Fleet::count_ports(){
+ return m_ports.size();
+}
+bool Fleet::get_act_pending(){
+ return m_act_pending;
+}
+
void Fleet::add_neighbours(PortDock & pd, std::vector<RoutingNodeNeighbour> & neighbours)
{
uint32_t idx = std::find(m_ports.begin(), m_ports.end(), &pd) - m_ports.begin();
@@ -576,6 +599,25 @@
}
/**
+ * Search among the docks of the fleet for the one that has matches given coordinates.
+ * Intended for a ship querying in what portdock it is now.
+ *
+ * @return the dock, or 0 if not found.
+ */
+PortDock * Fleet::get_dock(EditorGameBase & egbase, Coords field_coords) const
+{
+ for (PortDock * temp_port : m_ports) {
+ for (Coords tmp_coords : temp_port->get_positions(egbase)) {
+ if (tmp_coords == field_coords){
+ return temp_port;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+/**
* @return an arbitrary dock of the fleet, or 0 if the fleet has no docks
*/
PortDock * Fleet::get_arbitrary_dock() const
@@ -590,8 +632,9 @@
*/
void Fleet::update(EditorGameBase & egbase)
{
- if (m_act_pending)
+ if (m_act_pending){
return;
+ }
if (upcast(Game, game, &egbase)) {
schedule_act(*game, 100);
@@ -608,6 +651,7 @@
void Fleet::act(Game & game, uint32_t /* data */)
{
m_act_pending = false;
+
if (!active()) {
// If we are here, most likely act() was called by a port with waiting wares or an expedition ready
// although there are still no ships. We can't handle it now, so we reschedule the act()
@@ -618,63 +662,225 @@
molog("Fleet::act\n");
- for (Ship * temp_ship : m_ships) {
- Ship & ship = *temp_ship;
- if (ship.get_nritems() > 0 && !ship.get_destination(game)) {
- molog("Ship %u has items\n", ship.serial());
- bool found_dst = false;
- for (ShippingItem& temp_item : ship.m_items) {
- PortDock * dst = temp_item.get_destination(game);
- if (dst) {
- molog("... sending to portdock %u\n", dst->serial());
- ship.set_destination(game, *dst);
- found_dst = true;
- break;
- }
- }
- // If we end here, we just send the ship to the first port - maybe the old port got destroyed
- if (!found_dst) {
- assert(!m_ports.empty());
- ship.set_destination(game, *m_ports[0]);
- }
- }
- }
-
- for (uint32_t i = 0; i < m_ports.size(); ++i) {
- PortDock & pd = *m_ports[i];
-
- if (pd.get_need_ship()) {
- molog("Port %u needs ship\n", pd.serial());
-
- bool success = false;
- for (Ship * temp_ship : m_ships) {
- Ship & ship = *temp_ship;
- // Check whether ship is in TRANSPORT state
- if (ship.get_ship_state() != Ship::TRANSPORT)
- continue;
-
- PortDock * dst = ship.get_destination(game);
- // Check if ship has currently a different destination
- if (dst && dst != &pd)
- continue;
- if (ship.get_nritems() >= ship.descr().get_capacity())
- continue;
-
- molog("... ship %u takes care of it\n", ship.serial());
-
- if (!dst)
- ship.set_destination(game, pd);
-
- success = true;
- break;
- }
-
- if (!success) {
- schedule_act(game, 5000); // retry in the next time
- m_act_pending = true;
- break;
- }
- }
+ // we need to calculate what ship is to be send to which port
+ // for this we will have temporary data structure with format
+ // <<ship,port>,score>
+ // where ship and port are not objects but positions in m_ports and m_ships
+ // this is to allow native hashing
+ std::map<std::pair<uint16_t, uint16_t>, uint16_t> scores;
+
+ // so we will identify all pairs: idle ship : ports, and score all such
+ // pairs. We consider
+ // - count of wares onboard, first ware (oldest) is counted as 8 (prioritization)
+ // (counting wares for particular port only)
+ // - count wares waiting at the port/3
+ // - distance between ship and a port (0-10 points, the closer the more points)
+ // - is another ship heading there right now?
+
+ // at the end we must know if requrests of all ports asking for ship were addressed
+ // if any unsatisfied, we must schedule new run of this function
+ // when we send a ship there, the port is removed from list
+ std::list<uint16_t> waiting_ports;
+
+ // this is just helper - first member of scores map
+ std::pair<uint16_t, uint16_t> mapping; //ship number, port number
+
+ // first we go over ships - idle ones (=without destination)
+ // then over wares on these ships and create first ship-port
+ // pairs with score
+ for (uint16_t s = 0; s < m_ships.size(); s += 1){
+ if (m_ships[s]->get_destination(game)) {
+ continue;
+ }
+ if (m_ships[s]->get_ship_state() != Ship::TRANSPORT) {
+ continue; // in expedition obviously
+ }
+
+ for (uint16_t i = 0; i < m_ships[s]->get_nritems(); i += 1){
+ PortDock * dst = m_ships[s]->m_items[i].get_destination(game);
+ if (!dst) {
+ // if wares without destination on ship without destination
+ // such ship can be send to any port, and should be sent
+ // to some port, so we add 1 point to score for each port
+ for (uint16_t p = 0; p < m_ports.size(); p += 1){
+ mapping.first = s;
+ mapping.second = p;
+ scores[mapping] += 1;
+ }
+ continue;
+ }
+
+ bool destination_found = false; //just a functional check
+ for (uint16_t p = 0; p < m_ports.size(); p += 1){
+ if (m_ports[p] == m_ships[s]->m_items[i].get_destination(game)){
+ mapping.first = s;
+ mapping.second = p;
+ scores[mapping] += (i == 0)?8:1;
+ destination_found = true;
+ }
+ }
+ if (!destination_found){
+ // Perhaps the throw here is too strong
+ // we can still remove it before stable release if it proves too much
+ // during my testing this situation never happened
+ throw wexception("A ware with destination that does not match any of player's"
+ " ports, ship %u, ware's destination: %u",
+ m_ships[s]->serial(),
+ m_ships[s]->m_items[i].get_destination(game)->serial());
+ }
+ }
+ }
+
+ // now opposite aproach - we go over ports to find out those that have wares
+ // waiting for ship then find candidate ships to satisfy the requests
+ for (uint16_t p = 0; p < m_ports.size(); p += 1){
+ PortDock & pd = *m_ports[p];
+ if (!pd.get_need_ship()){
+ continue;
+ }
+
+ // general stategy is "one ship for port is enough", but sometimes
+ // amount of ware waiting for ship is too high
+ if (count_ships_heading_here(game, &pd) * 25 > pd.count_waiting()) {
+ continue;
+ }
+
+ waiting_ports.push_back(p);
+
+ // scoring and entering the pair into scores (or increasing existing
+ // score if the pair is already there)
+ // following is to prohibit sending more then one empty ship to
+ // this port (no big harm, but regression tests does not like it) change the comment NOCOM
+ //uint16_t empty_ships_sent_here = 0;
+ for (uint16_t s = 0; s < m_ships.size(); s += 1){
+
+ if (m_ships[s]->get_destination(game)) {
+ continue; // already has destination
+ }
+
+ if (m_ships[s]->get_ship_state() != Ship::TRANSPORT) {
+ continue; // in expedition obviously
+ }
+
+ mapping.first = s;
+ mapping.second = p;
+ // folowing aproximately considers free capacity of a ship
+ scores[mapping] += ((m_ships[s]->get_nritems() > 15)?1:3)
+ +
+ std::min(
+ m_ships[s]->descr().get_capacity() - m_ships[s]->get_nritems(),
+ m_ports[p]->count_waiting()) / 3;
+ }
+ }
+
+ //now adding score for distance
+ for (std::pair<std::pair<uint16_t, uint16_t>, uint16_t> ship_port_relation : scores) {
+
+ // here we get distance ship->port
+ // possibilities are:
+ // - we are in port and it is the same as target port
+ // - we are in other port, then we use get_dock() function to fetch precalculated path
+ // - if above fails, we calculate path "manually"
+ int16_t route_length = -1;
+
+ PortDock * current_portdock = get_dock(game, m_ships[ship_port_relation.first.first]->get_position());
+
+ if (current_portdock) { // we try to use precalculated paths of game
+
+ // we are in the same portdock
+ if (current_portdock == m_ports[ship_port_relation.first.second]) {
+ route_length = 0;
+ } else { // it is different portdock then
+ Path tmp_path;
+ if (get_path(*current_portdock, *m_ports[ship_port_relation.first.second], tmp_path)) {
+ route_length = tmp_path.get_nsteps();
+ }
+ }
+ }
+
+ // most probably the ship is not in a portdock (should not happen frequently)
+ if (route_length == -1) {
+ route_length = m_ships[ship_port_relation.first.first]->calculate_sea_route
+ (game, *m_ports[ship_port_relation.first.second]);
+ }
+
+ // now we have length of route, so we need to calculate score
+ int16_t score_for_distance = 0;
+ if (route_length < 3) {
+ score_for_distance = 10;
+ } else {
+ score_for_distance = 8 - route_length / 50;
+ }
+ // must not be negative
+ score_for_distance = (score_for_distance < 0)?0:score_for_distance;
+
+ scores[ship_port_relation.first] += score_for_distance;
+ }
+
+ // looking for best scores and sending ships accordingly
+ uint16_t best_ship = 0;
+ uint16_t best_port = 0;
+ uint16_t best_score;
+
+ // after sending a ship we will remove one or more items from scores
+ while (!scores.empty()){
+ best_score = 0;
+
+ // searching for combination with highest score
+ for (std::pair<std::pair<uint16_t, uint16_t>, uint16_t> combination : scores) {
+ if (combination.second > best_score){
+ best_score = combination.second;
+ best_ship = combination.first.first;
+ best_port = combination.first.second;
+ }
+ }
+ if (best_score == 0){
+ // this is check of correctnes of this algorithm, this should not happen
+ throw wexception("Fleet::act(): No port-destination pair selected or its score is zero");
+ }
+
+ // making sure the winner has no destination set
+ assert(!m_ships[best_ship]->get_destination(game));
+
+ // now actual setting destination for "best ship"
+ m_ships[best_ship]->set_destination(game, *m_ports[best_port]);
+ molog("... ship %u sent to port %u, wares onboard: %2d, the port is asking for a ship: %s\n",
+ m_ships[best_ship]->serial(),
+ m_ports[best_port]->serial(),
+ m_ships[best_ship]->get_nritems(),
+ (m_ports[best_port]->get_need_ship())?"yes":"no");
+
+ // pruning the scores table
+ // the ship that was just sent somewhere cannot be send elsewhere :)
+ for (auto it = scores.cbegin(); it != scores.cend();){
+
+ // decreasing score for target port as there was a ship just sent there
+ if (it->first.second == best_port) {
+ mapping.first = it->first.first;
+ mapping.second = it->first.second;
+ scores[mapping] /= 2;
+ // just make sure it is nonzero
+ scores[mapping] = (scores[mapping] == 0)?1:scores[mapping];
+ }
+
+ // but removing all pairs where best ship is participating as it is not available anymore
+ // (because it was sent to "best port")
+ if (it->first.first == best_ship) {
+ scores.erase(it++);
+ } else {
+ ++it;
+ }
+ }
+
+ // also removing the port from waiting_ports
+ waiting_ports.remove(best_port);
+ }
+
+ if (!waiting_ports.empty()) {
+ molog("... there are %" PRIuS " ports requesting ship(s) we cannot satisfy yet\n",
+ waiting_ports.size());
+ schedule_act(game, 5000); // retry next time
+ m_act_pending = true;
}
}
@@ -682,8 +888,7 @@
{
MapObject::log_general_info(egbase);
- molog
- ("%" PRIuS " ships and %" PRIuS " ports\n", m_ships.size(), m_ports.size());
+ molog ("%" PRIuS " ships and %" PRIuS " ports\n", m_ships.size(), m_ports.size());
}
#define FLEET_SAVEGAME_VERSION 4
=== modified file 'src/economy/fleet.h'
--- src/economy/fleet.h 2014-09-10 08:55:04 +0000
+++ src/economy/fleet.h 2015-07-31 20:49:05 +0000
@@ -24,6 +24,7 @@
#include "base/macros.h"
#include "logic/instances.h"
+#include "logic/widelands_geometry.h"
namespace Widelands {
@@ -79,6 +80,7 @@
Player & owner() const {return m_owner;}
PortDock * get_dock(Flag & flag) const;
+ PortDock * get_dock(EditorGameBase &, Coords) const;
PortDock * get_arbitrary_dock() const;
void set_economy(Economy * e);
@@ -98,6 +100,11 @@
bool get_path(PortDock & start, PortDock & end, Path & path);
void add_neighbours(PortDock & pd, std::vector<RoutingNodeNeighbour> & neighbours);
+ uint32_t count_ships();
+ uint32_t count_ships_heading_here(EditorGameBase & egbase, PortDock * port);
+ uint32_t count_ports();
+ bool get_act_pending();
+
protected:
void act(Game &, uint32_t data) override;
=== modified file 'src/economy/portdock.cc'
--- src/economy/portdock.cc 2015-05-05 20:00:21 +0000
+++ src/economy/portdock.cc 2015-07-31 20:49:05 +0000
@@ -364,8 +364,9 @@
m_waiting.pop_back();
}
- if (m_waiting.empty())
+ if (m_waiting.empty()){
set_need_ship(game, false);
+ }
}
m_fleet->update(game);
@@ -408,6 +409,13 @@
return count;
}
+/**
+ * Return the number of wares or workers waiting at the dock.
+ */
+uint32_t PortDock::count_waiting() {
+ return m_waiting.size();
+}
+
/// \returns whether an expedition was started or is even ready
bool PortDock::expedition_started() {
return (m_expedition_bootstrap.get() != nullptr) || m_expedition_ready;
=== modified file 'src/economy/portdock.h'
--- src/economy/portdock.h 2014-09-10 10:18:46 +0000
+++ src/economy/portdock.h 2015-07-31 20:49:05 +0000
@@ -113,6 +113,7 @@
void log_general_info(const EditorGameBase &) override;
uint32_t count_waiting(WareWorker waretype, WareIndex wareindex);
+ uint32_t count_waiting();
// Returns true if a expedition is started or ready to be send out.
bool expedition_started();
=== modified file 'src/logic/ship.cc'
--- src/logic/ship.cc 2015-04-07 20:56:02 +0000
+++ src/logic/ship.cc 2015-07-31 20:49:05 +0000
@@ -242,18 +242,8 @@
PortDock* dst = get_destination(game);
if (!dst) {
- molog("ship_update: No destination anymore.\n");
- if (m_items.empty())
- return false;
- molog("but it has wares....\n");
- pop_task(game);
- PortDock* other_dock = m_fleet->get_arbitrary_dock();
- // TODO(sirver): What happens if there is no port anymore?
- if (other_dock) {
- set_destination(game, *other_dock);
- } else {
- start_task_idle(game, descr().main_animation(), 2000);
- }
+ //here we just do nothing, this is usually OK
+ start_task_idle(game, descr().main_animation(), 10000);
return true;
}
@@ -729,7 +719,7 @@
* @note This is supposed to be called only from the scheduling code of @ref Fleet.
*/
void Ship::set_destination(Game& game, PortDock& pd) {
- molog("set_destination to %u (currently %" PRIuS " items)\n", pd.serial(), m_items.size());
+ molog("set_destination / sending to portdock %u (carrying %" PRIuS " items)\n", pd.serial(), m_items.size());
m_destination = &pd;
send_signal(game, "wakeup");
}
@@ -755,9 +745,9 @@
}
/**
- * Find a path to the dock @p pd and follow it without using precomputed paths.
+ * Find a path to the dock @p pd, returns its length, and the path optionally.
*/
-void Ship::start_task_movetodock(Game& game, PortDock& pd) {
+uint32_t Ship::calculate_sea_route(Game& game, PortDock& pd, Path* finalpath){
Map& map = game.map();
StepEvalAStar se(pd.get_warehouse()->get_position());
se.m_swim = true;
@@ -772,15 +762,47 @@
FCoords cur;
while (astar.step(cur, cost)) {
if (cur.field->get_immovable() == &pd) {
- Path path;
- astar.pathto(cur, path);
- start_task_movepath(game, path, descr().get_sail_anims());
- return;
+ if (finalpath){
+ astar.pathto(cur, *finalpath);
+ return finalpath->get_nsteps();
+ } else {
+ Path path;
+ astar.pathto(cur, path);
+ return path.get_nsteps();
+ }
}
}
- molog("start_task_movedock: Failed to find path!\n");
- start_task_idle(game, descr().main_animation(), 5000);
+ molog(" calculate_sea_distance: Failed to find path!\n");
+ return std::numeric_limits<uint32_t>::max();
+
+}
+
+/**
+ * Find a path to the dock @p pd and follow it without using precomputed paths.
+ */
+void Ship::start_task_movetodock(Game& game, PortDock& pd) {
+ Path path;
+
+ uint32_t const distance = calculate_sea_route(game, pd, &path);
+
+ // if we get a meaningfull result
+ if (distance < std::numeric_limits<uint32_t>::max()) {
+ start_task_movepath(game, path, descr().get_sail_anims());
+ return;
+ } else {
+ log("start_task_movedock: Failed to find a path: ship at %3dx%3d to port at: %3dx%3d\n",
+ get_position().x,
+ get_position().y,
+ pd.get_positions(game)[0].x,
+ pd.get_positions(game)[0].y);
+ //this should not happen, but in theory there could be some inconstinency
+ //I (tiborb) failed to invoke this situation when testing so
+ //I am not sure if following line behaves allright
+ get_fleet()->update(game);
+ start_task_idle(game, descr().main_animation(), 5000);
+ }
+
}
/// Prepare everything for the coming exploration
=== modified file 'src/logic/ship.h'
--- src/logic/ship.h 2015-06-10 06:46:40 +0000
+++ src/logic/ship.h 2015-07-31 20:49:05 +0000
@@ -115,6 +115,8 @@
void start_task_movetodock(Game &, PortDock &);
void start_task_expedition(Game &);
+ uint32_t calculate_sea_route(Game& game, PortDock& pd, Path* finalpath = nullptr);
+
void log_general_info(const EditorGameBase &) override;
uint32_t get_nritems() const {return m_items.size();}
=== modified file 'src/logic/warehouse.cc'
--- src/logic/warehouse.cc 2015-02-13 22:39:34 +0000
+++ src/logic/warehouse.cc 2015-07-31 20:49:05 +0000
@@ -28,6 +28,7 @@
#include "base/wexception.h"
#include "economy/economy.h"
#include "economy/flag.h"
+#include "economy/fleet.h"
#include "economy/portdock.h"
#include "economy/request.h"
#include "economy/ware_instance.h"
@@ -1427,8 +1428,25 @@
{
Building::log_general_info(egbase);
- if (descr().get_isport())
- molog("Port dock: %u\n", m_portdock ? m_portdock->serial() : 0);
+ if (descr().get_isport()){
+ PortDock* pd_tmp = m_portdock;
+ if (pd_tmp){
+ molog("Port dock: %u\n", pd_tmp->serial());
+ molog("port needs ship: %s\n", (pd_tmp->get_need_ship())?"true":"false");
+ molog("wares and workers waiting: %u\n", pd_tmp->count_waiting());
+ molog("exped. in progr.: %s\n", (pd_tmp->expedition_started())?"true":"false");
+ Fleet* fleet = pd_tmp->get_fleet();
+ if (fleet) {
+ molog("* fleet: %u\n", fleet->serial());
+ molog(" ships: %u, ports: %u\n", fleet->count_ships(), fleet->count_ports());
+ molog(" m_act_pending: %s\n", (fleet->get_act_pending())?"true":"false");
+ } else {
+ molog("No fleet?!\n");
+ }
+ } else {
+ molog ("No port dock!?\n");
+ }
+ }
}
=== modified file 'test/maps/expedition.wmf/scripting/init.lua'
--- test/maps/expedition.wmf/scripting/init.lua 2015-06-29 13:49:35 +0000
+++ test/maps/expedition.wmf/scripting/init.lua 2015-07-31 20:49:05 +0000
@@ -103,6 +103,36 @@
sleep(100)
end
+--function cancel_expedition_or_sink_in_shipwindow()
+ --if second_ship then
+ --ship_to_click=second_ship
+ --elseif first_ship then
+ --ship_to_click=first_ship
+ --else
+ --assert(false)
+ --end
+
+ --click_on_ship(ship_to_click)
+ --if click_button("cancel_expedition") then
+ --sleep(100)
+ --assert_true(click_button("ok"))
+ --sleep(100)
+ --close_windows()
+ --sleep(100)
+ --print (" DEBUG expedition cancelled")
+ --else
+ --click_on_ship(ship_to_click)
+ --assert_true(click_button("sink"))
+ --sleep(100)
+ --assert_true(click_button("ok"))
+ --sleep(100)
+ --close_windows()
+ --sleep(100)
+ --print (" DEBUG ship sunk")
+ --end
+--end
+
+
function dismantle_hardener()
assert_true(click_building(p1, "hardener"))
assert_true(click_button("dismantle"))
@@ -151,18 +181,28 @@
first_ship = p1:place_bob("ship", map:get_field(10, 10))
end
+function create_second_ship()
+ second_ship = p1:place_bob("ship", map:get_field(14, 10))
+end
+
function create_two_ships()
create_one_ship()
- second_ship = p1:place_bob("ship", map:get_field(14, 10))
+ create_second_ship()
end
-function test_cancel_started_expedition_on_ship()
+function test_cancel_started_expedition_on_ship(needs_second_ship)
sleep(100)
game.desired_speed = 10 * 1000
-- Start a new expedition.
port:start_expedition()
wait_for_message("Expedition Ready")
+
+ --if current test requires second ship...
+ if needs_second_ship then
+ create_second_ship()
+ end
+
game.desired_speed = 10 * 1000
sleep(10000)
@@ -197,15 +237,23 @@
game.desired_speed = 10 * 1000
sleep(10000)
- first_ship.island_explore_direction="ccw"
+ if first_ship.state=="exp_waiting" then
+ expedition_ship=first_ship
+ elseif second_ship.state=="exp_waiting" then
+ expedition_ship=second_ship
+ else
+ assert(false)
+ end
+
+ expedition_ship.island_explore_direction="ccw"
sleep(2000)
- assert_equal("ccw",first_ship.island_explore_direction)
+ assert_equal("ccw",expedition_ship.island_explore_direction)
sleep(6000)
stable_save("sailing")
assert_equal(1, p1:get_workers("builder"))
- cancel_expedition_in_shipwindow(first_ship)
+ cancel_expedition_in_shipwindow(expedition_ship)
sleep(20000)
assert_equal(1, p1:get_workers("builder"))
check_wares_in_port_are_all_there()
@@ -218,6 +266,7 @@
wl.ui.MapView():close()
end
+--NOCOM needed?
function test_cancel_when_port_space_was_reached()
sleep(100)
game.desired_speed = 10 * 1000
@@ -263,11 +312,20 @@
port:start_expedition()
wait_for_message("Expedition Ready")
- first_ship.island_explore_direction="ccw"
+
+ if first_ship.state=="exp_waiting" then
+ expedition_ship=first_ship
+ elseif second_ship.state=="exp_waiting" then
+ expedition_ship=second_ship
+ else
+ assert(false)
+ end
+
+ expedition_ship.island_explore_direction="ccw"
sleep(2000)
- assert_equal("ccw",first_ship.island_explore_direction)
+ assert_equal("ccw",expedition_ship.island_explore_direction)
wait_for_message("Port Space Found")
- first_ship:build_colonization_port()
+ expedition_ship:build_colonization_port()
sleep(500)
assert_equal(1, p1:get_workers("builder"))
wait_for_message("Port")
=== modified file 'test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_one_ship.lua'
--- test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_one_ship.lua 2013-10-29 20:22:08 +0000
+++ test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_one_ship.lua 2015-07-31 20:49:05 +0000
@@ -1,5 +1,6 @@
run(function()
create_one_ship()
- test_cancel_started_expedition_on_ship()
+ --false indicates that second ship is not to be created
+ test_cancel_started_expedition_on_ship(false)
end)
=== modified file 'test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_two_ships.lua'
--- test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_two_ships.lua 2013-10-29 20:22:08 +0000
+++ test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_two_ships.lua 2015-07-31 20:49:05 +0000
@@ -1,5 +1,6 @@
run(function()
- create_two_ships()
+ create_one_ship()
- test_cancel_started_expedition_on_ship()
+ --true indicates that second ship is to be created
+ test_cancel_started_expedition_on_ship(true)
end)
=== modified file 'test/maps/expedition.wmf/scripting/test_cancel_when_port_space_was_reached_two_ships.lua'
--- test/maps/expedition.wmf/scripting/test_cancel_when_port_space_was_reached_two_ships.lua 2013-10-29 20:22:08 +0000
+++ test/maps/expedition.wmf/scripting/test_cancel_when_port_space_was_reached_two_ships.lua 2015-07-31 20:49:05 +0000
@@ -1,5 +1,47 @@
run(function()
create_two_ships()
- test_cancel_when_port_space_was_reached()
+
+ sleep(100)
+ game.desired_speed = 10 * 1000
+
+ -- Send expedition to port space.
+ port:start_expedition()
+ wait_for_message("Expedition Ready")
+ assert_equal(1, p1:get_workers("builder"))
+ sleep(500)
+
+
+ if first_ship.state=="exp_waiting" then
+ expedition_ship=first_ship
+ elseif second_ship.state=="exp_waiting" then
+ expedition_ship=second_ship
+ else
+ assert(false)
+ end
+
+ expedition_ship.island_explore_direction="ccw"
+ sleep(2000)
+ assert_equal("ccw",expedition_ship.island_explore_direction)
+ wait_for_message("Port Space Found")
+ sleep(500)
+ assert_equal(1, p1:get_workers("builder"))
+
+ stable_save("reached_port_space")
+ assert_equal(1, p1:get_workers("builder"))
+
+ cancel_expedition_in_shipwindow(expedition_ship)
+ sleep(20000)
+ assert_equal(1, p1:get_workers("builder"))
+ check_wares_in_port_are_all_there()
+
+ -- Dismantle the hardener to make sure that the builder is able to do his work.
+ game.desired_speed = 50 * 1000
+ dismantle_hardener()
+
+ print("# All Tests passed.")
+ wl.ui.MapView():close()
+
+
+
end)
Follow ups