Merge lp:~widelands-dev/widelands/ship_scheduling into lp:widelands

Proposed by TiborB
Status: Merged
Merged at revision: 7515
Proposed branch: lp:~widelands-dev/widelands/ship_scheduling
Merge into: lp:widelands
Diff against target: 794 lines (+456/-96)
11 files modified
src/economy/fleet.cc (+261/-60)
src/economy/fleet.h (+7/-0)
src/economy/portdock.cc (+9/-1)
src/economy/portdock.h (+1/-0)
src/logic/ship.cc (+43/-21)
src/logic/ship.h (+2/-0)
src/logic/warehouse.cc (+20/-2)
test/maps/expedition.wmf/scripting/init.lua (+65/-8)
test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_one_ship.lua (+2/-1)
test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_two_ships.lua (+3/-2)
test/maps/expedition.wmf/scripting/test_cancel_when_port_space_was_reached_two_ships.lua (+43/-1)
To merge this branch: bzr merge lp:~widelands-dev/widelands/ship_scheduling
Reviewer Review Type Date Requested Status
SirVer Approve
Review via email: mp+266626@code.launchpad.net

Description of the change

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...

To post a comment you must log in.
Revision history for this message
SirVer (sirver) wrote :

lgtm.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/economy/fleet.cc'
2--- src/economy/fleet.cc 2015-02-05 12:11:20 +0000
3+++ src/economy/fleet.cc 2015-08-30 19:39:04 +0000
4@@ -337,6 +337,28 @@
5 return true;
6 }
7
8+uint32_t Fleet::count_ships(){
9+ return m_ships.size();
10+}
11+
12+uint32_t Fleet::count_ships_heading_here(EditorGameBase & egbase, PortDock * port){
13+ uint32_t ships_on_way = 0;
14+ for (uint16_t s = 0; s < m_ships.size(); s += 1){
15+ if (m_ships[s]->get_destination(egbase) == port){
16+ ships_on_way += 1;
17+ }
18+ }
19+
20+ return ships_on_way;
21+}
22+
23+uint32_t Fleet::count_ports(){
24+ return m_ports.size();
25+}
26+bool Fleet::get_act_pending(){
27+ return m_act_pending;
28+}
29+
30 void Fleet::add_neighbours(PortDock & pd, std::vector<RoutingNodeNeighbour> & neighbours)
31 {
32 uint32_t idx = std::find(m_ports.begin(), m_ports.end(), &pd) - m_ports.begin();
33@@ -576,6 +598,25 @@
34 }
35
36 /**
37+ * Search among the docks of the fleet for the one that has matches given coordinates.
38+ * Intended for a ship querying in what portdock it is now.
39+ *
40+ * @return the dock, or 0 if not found.
41+ */
42+PortDock * Fleet::get_dock(EditorGameBase & egbase, Coords field_coords) const
43+{
44+ for (PortDock * temp_port : m_ports) {
45+ for (Coords tmp_coords : temp_port->get_positions(egbase)) {
46+ if (tmp_coords == field_coords){
47+ return temp_port;
48+ }
49+ }
50+ }
51+
52+ return nullptr;
53+}
54+
55+/**
56 * @return an arbitrary dock of the fleet, or 0 if the fleet has no docks
57 */
58 PortDock * Fleet::get_arbitrary_dock() const
59@@ -590,8 +631,9 @@
60 */
61 void Fleet::update(EditorGameBase & egbase)
62 {
63- if (m_act_pending)
64+ if (m_act_pending){
65 return;
66+ }
67
68 if (upcast(Game, game, &egbase)) {
69 schedule_act(*game, 100);
70@@ -608,6 +650,7 @@
71 void Fleet::act(Game & game, uint32_t /* data */)
72 {
73 m_act_pending = false;
74+
75 if (!active()) {
76 // If we are here, most likely act() was called by a port with waiting wares or an expedition ready
77 // although there are still no ships. We can't handle it now, so we reschedule the act()
78@@ -618,63 +661,222 @@
79
80 molog("Fleet::act\n");
81
82- for (Ship * temp_ship : m_ships) {
83- Ship & ship = *temp_ship;
84- if (ship.get_nritems() > 0 && !ship.get_destination(game)) {
85- molog("Ship %u has items\n", ship.serial());
86- bool found_dst = false;
87- for (ShippingItem& temp_item : ship.m_items) {
88- PortDock * dst = temp_item.get_destination(game);
89- if (dst) {
90- molog("... sending to portdock %u\n", dst->serial());
91- ship.set_destination(game, *dst);
92- found_dst = true;
93- break;
94- }
95- }
96- // If we end here, we just send the ship to the first port - maybe the old port got destroyed
97- if (!found_dst) {
98- assert(!m_ports.empty());
99- ship.set_destination(game, *m_ports[0]);
100- }
101- }
102- }
103-
104- for (uint32_t i = 0; i < m_ports.size(); ++i) {
105- PortDock & pd = *m_ports[i];
106-
107- if (pd.get_need_ship()) {
108- molog("Port %u needs ship\n", pd.serial());
109-
110- bool success = false;
111- for (Ship * temp_ship : m_ships) {
112- Ship & ship = *temp_ship;
113- // Check whether ship is in TRANSPORT state
114- if (ship.get_ship_state() != Ship::TRANSPORT)
115- continue;
116-
117- PortDock * dst = ship.get_destination(game);
118- // Check if ship has currently a different destination
119- if (dst && dst != &pd)
120- continue;
121- if (ship.get_nritems() >= ship.descr().get_capacity())
122- continue;
123-
124- molog("... ship %u takes care of it\n", ship.serial());
125-
126- if (!dst)
127- ship.set_destination(game, pd);
128-
129- success = true;
130- break;
131- }
132-
133- if (!success) {
134- schedule_act(game, 5000); // retry in the next time
135- m_act_pending = true;
136- break;
137- }
138- }
139+ // we need to calculate what ship is to be send to which port
140+ // for this we will have temporary data structure with format
141+ // <<ship,port>,score>
142+ // where ship and port are not objects but positions in m_ports and m_ships
143+ // this is to allow native hashing
144+ std::map<std::pair<uint16_t, uint16_t>, uint16_t> scores;
145+
146+ // so we will identify all pairs: idle ship : ports, and score all such
147+ // pairs. We consider
148+ // - count of wares onboard, first ware (oldest) is counted as 8 (prioritization)
149+ // (counting wares for particular port only)
150+ // - count wares waiting at the port/3
151+ // - distance between ship and a port (0-10 points, the closer the more points)
152+ // - is another ship heading there right now?
153+
154+ // at the end we must know if requrests of all ports asking for ship were addressed
155+ // if any unsatisfied, we must schedule new run of this function
156+ // when we send a ship there, the port is removed from list
157+ std::list<uint16_t> waiting_ports;
158+
159+ // this is just helper - first member of scores map
160+ std::pair<uint16_t, uint16_t> mapping; //ship number, port number
161+
162+ // first we go over ships - idle ones (=without destination)
163+ // then over wares on these ships and create first ship-port
164+ // pairs with score
165+ for (uint16_t s = 0; s < m_ships.size(); s += 1){
166+ if (m_ships[s]->get_destination(game)) {
167+ continue;
168+ }
169+ if (m_ships[s]->get_ship_state() != Ship::TRANSPORT) {
170+ continue; // in expedition obviously
171+ }
172+
173+ for (uint16_t i = 0; i < m_ships[s]->get_nritems(); i += 1){
174+ PortDock * dst = m_ships[s]->m_items[i].get_destination(game);
175+ if (!dst) {
176+ // if wares without destination on ship without destination
177+ // such ship can be send to any port, and should be sent
178+ // to some port, so we add 1 point to score for each port
179+ for (uint16_t p = 0; p < m_ports.size(); p += 1){
180+ mapping.first = s;
181+ mapping.second = p;
182+ scores[mapping] += 1;
183+ }
184+ continue;
185+ }
186+
187+ bool destination_found = false; //just a functional check
188+ for (uint16_t p = 0; p < m_ports.size(); p += 1){
189+ if (m_ports[p] == m_ships[s]->m_items[i].get_destination(game)){
190+ mapping.first = s;
191+ mapping.second = p;
192+ scores[mapping] += (i == 0)?8:1;
193+ destination_found = true;
194+ }
195+ }
196+ if (!destination_found){
197+ // Perhaps the throw here is too strong
198+ // we can still remove it before stable release if it proves too much
199+ // during my testing this situation never happened
200+ throw wexception("A ware with destination that does not match any of player's"
201+ " ports, ship %u, ware's destination: %u",
202+ m_ships[s]->serial(),
203+ m_ships[s]->m_items[i].get_destination(game)->serial());
204+ }
205+ }
206+ }
207+
208+ // now opposite aproach - we go over ports to find out those that have wares
209+ // waiting for ship then find candidate ships to satisfy the requests
210+ for (uint16_t p = 0; p < m_ports.size(); p += 1){
211+ PortDock & pd = *m_ports[p];
212+ if (!pd.get_need_ship()){
213+ continue;
214+ }
215+
216+ // general stategy is "one ship for port is enough", but sometimes
217+ // amount of ware waiting for ship is too high
218+ if (count_ships_heading_here(game, &pd) * 25 > pd.count_waiting()) {
219+ continue;
220+ }
221+
222+ waiting_ports.push_back(p);
223+
224+ // scoring and entering the pair into scores (or increasing existing
225+ // score if the pair is already there)
226+ for (uint16_t s = 0; s < m_ships.size(); s += 1){
227+
228+ if (m_ships[s]->get_destination(game)) {
229+ continue; // already has destination
230+ }
231+
232+ if (m_ships[s]->get_ship_state() != Ship::TRANSPORT) {
233+ continue; // in expedition obviously
234+ }
235+
236+ mapping.first = s;
237+ mapping.second = p;
238+ // folowing aproximately considers free capacity of a ship
239+ scores[mapping] += ((m_ships[s]->get_nritems() > 15)?1:3)
240+ +
241+ std::min(
242+ m_ships[s]->descr().get_capacity() - m_ships[s]->get_nritems(),
243+ m_ports[p]->count_waiting()) / 3;
244+ }
245+ }
246+
247+ //now adding score for distance
248+ for (std::pair<std::pair<uint16_t, uint16_t>, uint16_t> ship_port_relation : scores) {
249+
250+ // here we get distance ship->port
251+ // possibilities are:
252+ // - we are in port and it is the same as target port
253+ // - we are in other port, then we use get_dock() function to fetch precalculated path
254+ // - if above fails, we calculate path "manually"
255+ int16_t route_length = -1;
256+
257+ PortDock * current_portdock = get_dock(game, m_ships[ship_port_relation.first.first]->get_position());
258+
259+ if (current_portdock) { // we try to use precalculated paths of game
260+
261+ // we are in the same portdock
262+ if (current_portdock == m_ports[ship_port_relation.first.second]) {
263+ route_length = 0;
264+ } else { // it is different portdock then
265+ Path tmp_path;
266+ if (get_path(*current_portdock, *m_ports[ship_port_relation.first.second], tmp_path)) {
267+ route_length = tmp_path.get_nsteps();
268+ }
269+ }
270+ }
271+
272+ // most probably the ship is not in a portdock (should not happen frequently)
273+ if (route_length == -1) {
274+ route_length = m_ships[ship_port_relation.first.first]->calculate_sea_route
275+ (game, *m_ports[ship_port_relation.first.second]);
276+ }
277+
278+ // now we have length of route, so we need to calculate score
279+ int16_t score_for_distance = 0;
280+ if (route_length < 3) {
281+ score_for_distance = 10;
282+ } else {
283+ score_for_distance = 8 - route_length / 50;
284+ }
285+ // must not be negative
286+ score_for_distance = (score_for_distance < 0)?0:score_for_distance;
287+
288+ scores[ship_port_relation.first] += score_for_distance;
289+ }
290+
291+ // looking for best scores and sending ships accordingly
292+ uint16_t best_ship = 0;
293+ uint16_t best_port = 0;
294+ uint16_t best_score;
295+
296+ // after sending a ship we will remove one or more items from scores
297+ while (!scores.empty()){
298+ best_score = 0;
299+
300+ // searching for combination with highest score
301+ for (std::pair<std::pair<uint16_t, uint16_t>, uint16_t> combination : scores) {
302+ if (combination.second > best_score){
303+ best_score = combination.second;
304+ best_ship = combination.first.first;
305+ best_port = combination.first.second;
306+ }
307+ }
308+ if (best_score == 0){
309+ // this is check of correctnes of this algorithm, this should not happen
310+ throw wexception("Fleet::act(): No port-destination pair selected or its score is zero");
311+ }
312+
313+ // making sure the winner has no destination set
314+ assert(!m_ships[best_ship]->get_destination(game));
315+
316+ // now actual setting destination for "best ship"
317+ m_ships[best_ship]->set_destination(game, *m_ports[best_port]);
318+ molog("... ship %u sent to port %u, wares onboard: %2d, the port is asking for a ship: %s\n",
319+ m_ships[best_ship]->serial(),
320+ m_ports[best_port]->serial(),
321+ m_ships[best_ship]->get_nritems(),
322+ (m_ports[best_port]->get_need_ship())?"yes":"no");
323+
324+ // pruning the scores table
325+ // the ship that was just sent somewhere cannot be send elsewhere :)
326+ for (auto it = scores.cbegin(); it != scores.cend();){
327+
328+ // decreasing score for target port as there was a ship just sent there
329+ if (it->first.second == best_port) {
330+ mapping.first = it->first.first;
331+ mapping.second = it->first.second;
332+ scores[mapping] /= 2;
333+ // just make sure it is nonzero
334+ scores[mapping] = (scores[mapping] == 0)?1:scores[mapping];
335+ }
336+
337+ // but removing all pairs where best ship is participating as it is not available anymore
338+ // (because it was sent to "best port")
339+ if (it->first.first == best_ship) {
340+ scores.erase(it++);
341+ } else {
342+ ++it;
343+ }
344+ }
345+
346+ // also removing the port from waiting_ports
347+ waiting_ports.remove(best_port);
348+ }
349+
350+ if (!waiting_ports.empty()) {
351+ molog("... there are %" PRIuS " ports requesting ship(s) we cannot satisfy yet\n",
352+ waiting_ports.size());
353+ schedule_act(game, 5000); // retry next time
354+ m_act_pending = true;
355 }
356 }
357
358@@ -682,8 +884,7 @@
359 {
360 MapObject::log_general_info(egbase);
361
362- molog
363- ("%" PRIuS " ships and %" PRIuS " ports\n", m_ships.size(), m_ports.size());
364+ molog ("%" PRIuS " ships and %" PRIuS " ports\n", m_ships.size(), m_ports.size());
365 }
366
367 #define FLEET_SAVEGAME_VERSION 4
368
369=== modified file 'src/economy/fleet.h'
370--- src/economy/fleet.h 2014-09-10 08:55:04 +0000
371+++ src/economy/fleet.h 2015-08-30 19:39:04 +0000
372@@ -24,6 +24,7 @@
373
374 #include "base/macros.h"
375 #include "logic/instances.h"
376+#include "logic/widelands_geometry.h"
377
378 namespace Widelands {
379
380@@ -79,6 +80,7 @@
381 Player & owner() const {return m_owner;}
382
383 PortDock * get_dock(Flag & flag) const;
384+ PortDock * get_dock(EditorGameBase &, Coords) const;
385 PortDock * get_arbitrary_dock() const;
386 void set_economy(Economy * e);
387
388@@ -98,6 +100,11 @@
389 bool get_path(PortDock & start, PortDock & end, Path & path);
390 void add_neighbours(PortDock & pd, std::vector<RoutingNodeNeighbour> & neighbours);
391
392+ uint32_t count_ships();
393+ uint32_t count_ships_heading_here(EditorGameBase & egbase, PortDock * port);
394+ uint32_t count_ports();
395+ bool get_act_pending();
396+
397 protected:
398 void act(Game &, uint32_t data) override;
399
400
401=== modified file 'src/economy/portdock.cc'
402--- src/economy/portdock.cc 2015-05-05 20:00:21 +0000
403+++ src/economy/portdock.cc 2015-08-30 19:39:04 +0000
404@@ -364,8 +364,9 @@
405 m_waiting.pop_back();
406 }
407
408- if (m_waiting.empty())
409+ if (m_waiting.empty()){
410 set_need_ship(game, false);
411+ }
412 }
413
414 m_fleet->update(game);
415@@ -408,6 +409,13 @@
416 return count;
417 }
418
419+/**
420+ * Return the number of wares or workers waiting at the dock.
421+ */
422+uint32_t PortDock::count_waiting() {
423+ return m_waiting.size();
424+}
425+
426 /// \returns whether an expedition was started or is even ready
427 bool PortDock::expedition_started() {
428 return (m_expedition_bootstrap.get() != nullptr) || m_expedition_ready;
429
430=== modified file 'src/economy/portdock.h'
431--- src/economy/portdock.h 2014-09-10 10:18:46 +0000
432+++ src/economy/portdock.h 2015-08-30 19:39:04 +0000
433@@ -113,6 +113,7 @@
434 void log_general_info(const EditorGameBase &) override;
435
436 uint32_t count_waiting(WareWorker waretype, WareIndex wareindex);
437+ uint32_t count_waiting();
438
439 // Returns true if a expedition is started or ready to be send out.
440 bool expedition_started();
441
442=== modified file 'src/logic/ship.cc'
443--- src/logic/ship.cc 2015-04-07 20:56:02 +0000
444+++ src/logic/ship.cc 2015-08-30 19:39:04 +0000
445@@ -242,18 +242,8 @@
446
447 PortDock* dst = get_destination(game);
448 if (!dst) {
449- molog("ship_update: No destination anymore.\n");
450- if (m_items.empty())
451- return false;
452- molog("but it has wares....\n");
453- pop_task(game);
454- PortDock* other_dock = m_fleet->get_arbitrary_dock();
455- // TODO(sirver): What happens if there is no port anymore?
456- if (other_dock) {
457- set_destination(game, *other_dock);
458- } else {
459- start_task_idle(game, descr().main_animation(), 2000);
460- }
461+ //here we just do nothing, this is usually OK
462+ start_task_idle(game, descr().main_animation(), 10000);
463 return true;
464 }
465
466@@ -729,7 +719,7 @@
467 * @note This is supposed to be called only from the scheduling code of @ref Fleet.
468 */
469 void Ship::set_destination(Game& game, PortDock& pd) {
470- molog("set_destination to %u (currently %" PRIuS " items)\n", pd.serial(), m_items.size());
471+ molog("set_destination / sending to portdock %u (carrying %" PRIuS " items)\n", pd.serial(), m_items.size());
472 m_destination = &pd;
473 send_signal(game, "wakeup");
474 }
475@@ -755,9 +745,9 @@
476 }
477
478 /**
479- * Find a path to the dock @p pd and follow it without using precomputed paths.
480+ * Find a path to the dock @p pd, returns its length, and the path optionally.
481 */
482-void Ship::start_task_movetodock(Game& game, PortDock& pd) {
483+uint32_t Ship::calculate_sea_route(Game& game, PortDock& pd, Path* finalpath){
484 Map& map = game.map();
485 StepEvalAStar se(pd.get_warehouse()->get_position());
486 se.m_swim = true;
487@@ -772,15 +762,47 @@
488 FCoords cur;
489 while (astar.step(cur, cost)) {
490 if (cur.field->get_immovable() == &pd) {
491- Path path;
492- astar.pathto(cur, path);
493- start_task_movepath(game, path, descr().get_sail_anims());
494- return;
495+ if (finalpath){
496+ astar.pathto(cur, *finalpath);
497+ return finalpath->get_nsteps();
498+ } else {
499+ Path path;
500+ astar.pathto(cur, path);
501+ return path.get_nsteps();
502+ }
503 }
504 }
505
506- molog("start_task_movedock: Failed to find path!\n");
507- start_task_idle(game, descr().main_animation(), 5000);
508+ molog(" calculate_sea_distance: Failed to find path!\n");
509+ return std::numeric_limits<uint32_t>::max();
510+
511+}
512+
513+/**
514+ * Find a path to the dock @p pd and follow it without using precomputed paths.
515+ */
516+void Ship::start_task_movetodock(Game& game, PortDock& pd) {
517+ Path path;
518+
519+ uint32_t const distance = calculate_sea_route(game, pd, &path);
520+
521+ // if we get a meaningfull result
522+ if (distance < std::numeric_limits<uint32_t>::max()) {
523+ start_task_movepath(game, path, descr().get_sail_anims());
524+ return;
525+ } else {
526+ log("start_task_movedock: Failed to find a path: ship at %3dx%3d to port at: %3dx%3d\n",
527+ get_position().x,
528+ get_position().y,
529+ pd.get_positions(game)[0].x,
530+ pd.get_positions(game)[0].y);
531+ //this should not happen, but in theory there could be some inconstinency
532+ //I (tiborb) failed to invoke this situation when testing so
533+ //I am not sure if following line behaves allright
534+ get_fleet()->update(game);
535+ start_task_idle(game, descr().main_animation(), 5000);
536+ }
537+
538 }
539
540 /// Prepare everything for the coming exploration
541
542=== modified file 'src/logic/ship.h'
543--- src/logic/ship.h 2015-06-10 06:46:40 +0000
544+++ src/logic/ship.h 2015-08-30 19:39:04 +0000
545@@ -115,6 +115,8 @@
546 void start_task_movetodock(Game &, PortDock &);
547 void start_task_expedition(Game &);
548
549+ uint32_t calculate_sea_route(Game& game, PortDock& pd, Path* finalpath = nullptr);
550+
551 void log_general_info(const EditorGameBase &) override;
552
553 uint32_t get_nritems() const {return m_items.size();}
554
555=== modified file 'src/logic/warehouse.cc'
556--- src/logic/warehouse.cc 2015-02-13 22:39:34 +0000
557+++ src/logic/warehouse.cc 2015-08-30 19:39:04 +0000
558@@ -28,6 +28,7 @@
559 #include "base/wexception.h"
560 #include "economy/economy.h"
561 #include "economy/flag.h"
562+#include "economy/fleet.h"
563 #include "economy/portdock.h"
564 #include "economy/request.h"
565 #include "economy/ware_instance.h"
566@@ -1427,8 +1428,25 @@
567 {
568 Building::log_general_info(egbase);
569
570- if (descr().get_isport())
571- molog("Port dock: %u\n", m_portdock ? m_portdock->serial() : 0);
572+ if (descr().get_isport()){
573+ PortDock* pd_tmp = m_portdock;
574+ if (pd_tmp){
575+ molog("Port dock: %u\n", pd_tmp->serial());
576+ molog("port needs ship: %s\n", (pd_tmp->get_need_ship())?"true":"false");
577+ molog("wares and workers waiting: %u\n", pd_tmp->count_waiting());
578+ molog("exped. in progr.: %s\n", (pd_tmp->expedition_started())?"true":"false");
579+ Fleet* fleet = pd_tmp->get_fleet();
580+ if (fleet) {
581+ molog("* fleet: %u\n", fleet->serial());
582+ molog(" ships: %u, ports: %u\n", fleet->count_ships(), fleet->count_ports());
583+ molog(" m_act_pending: %s\n", (fleet->get_act_pending())?"true":"false");
584+ } else {
585+ molog("No fleet?!\n");
586+ }
587+ } else {
588+ molog ("No port dock!?\n");
589+ }
590+ }
591 }
592
593
594
595=== modified file 'test/maps/expedition.wmf/scripting/init.lua'
596--- test/maps/expedition.wmf/scripting/init.lua 2015-06-29 13:49:35 +0000
597+++ test/maps/expedition.wmf/scripting/init.lua 2015-08-30 19:39:04 +0000
598@@ -103,6 +103,36 @@
599 sleep(100)
600 end
601
602+--function cancel_expedition_or_sink_in_shipwindow()
603+ --if second_ship then
604+ --ship_to_click=second_ship
605+ --elseif first_ship then
606+ --ship_to_click=first_ship
607+ --else
608+ --assert(false)
609+ --end
610+
611+ --click_on_ship(ship_to_click)
612+ --if click_button("cancel_expedition") then
613+ --sleep(100)
614+ --assert_true(click_button("ok"))
615+ --sleep(100)
616+ --close_windows()
617+ --sleep(100)
618+ --print (" DEBUG expedition cancelled")
619+ --else
620+ --click_on_ship(ship_to_click)
621+ --assert_true(click_button("sink"))
622+ --sleep(100)
623+ --assert_true(click_button("ok"))
624+ --sleep(100)
625+ --close_windows()
626+ --sleep(100)
627+ --print (" DEBUG ship sunk")
628+ --end
629+--end
630+
631+
632 function dismantle_hardener()
633 assert_true(click_building(p1, "hardener"))
634 assert_true(click_button("dismantle"))
635@@ -151,18 +181,28 @@
636 first_ship = p1:place_bob("ship", map:get_field(10, 10))
637 end
638
639+function create_second_ship()
640+ second_ship = p1:place_bob("ship", map:get_field(14, 10))
641+end
642+
643 function create_two_ships()
644 create_one_ship()
645- second_ship = p1:place_bob("ship", map:get_field(14, 10))
646+ create_second_ship()
647 end
648
649-function test_cancel_started_expedition_on_ship()
650+function test_cancel_started_expedition_on_ship(needs_second_ship)
651 sleep(100)
652 game.desired_speed = 10 * 1000
653
654 -- Start a new expedition.
655 port:start_expedition()
656 wait_for_message("Expedition Ready")
657+
658+ --if current test requires second ship...
659+ if needs_second_ship then
660+ create_second_ship()
661+ end
662+
663 game.desired_speed = 10 * 1000
664 sleep(10000)
665
666@@ -197,15 +237,23 @@
667 game.desired_speed = 10 * 1000
668 sleep(10000)
669
670- first_ship.island_explore_direction="ccw"
671+ if first_ship.state=="exp_waiting" then
672+ expedition_ship=first_ship
673+ elseif second_ship.state=="exp_waiting" then
674+ expedition_ship=second_ship
675+ else
676+ assert(false)
677+ end
678+
679+ expedition_ship.island_explore_direction="ccw"
680 sleep(2000)
681- assert_equal("ccw",first_ship.island_explore_direction)
682+ assert_equal("ccw",expedition_ship.island_explore_direction)
683 sleep(6000)
684
685 stable_save("sailing")
686 assert_equal(1, p1:get_workers("builder"))
687
688- cancel_expedition_in_shipwindow(first_ship)
689+ cancel_expedition_in_shipwindow(expedition_ship)
690 sleep(20000)
691 assert_equal(1, p1:get_workers("builder"))
692 check_wares_in_port_are_all_there()
693@@ -263,11 +311,20 @@
694
695 port:start_expedition()
696 wait_for_message("Expedition Ready")
697- first_ship.island_explore_direction="ccw"
698+
699+ if first_ship.state=="exp_waiting" then
700+ expedition_ship=first_ship
701+ elseif second_ship.state=="exp_waiting" then
702+ expedition_ship=second_ship
703+ else
704+ assert(false)
705+ end
706+
707+ expedition_ship.island_explore_direction="ccw"
708 sleep(2000)
709- assert_equal("ccw",first_ship.island_explore_direction)
710+ assert_equal("ccw",expedition_ship.island_explore_direction)
711 wait_for_message("Port Space Found")
712- first_ship:build_colonization_port()
713+ expedition_ship:build_colonization_port()
714 sleep(500)
715 assert_equal(1, p1:get_workers("builder"))
716 wait_for_message("Port")
717
718=== modified file 'test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_one_ship.lua'
719--- test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_one_ship.lua 2013-10-29 20:22:08 +0000
720+++ test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_one_ship.lua 2015-08-30 19:39:04 +0000
721@@ -1,5 +1,6 @@
722 run(function()
723 create_one_ship()
724
725- test_cancel_started_expedition_on_ship()
726+ --false indicates that second ship is not to be created
727+ test_cancel_started_expedition_on_ship(false)
728 end)
729
730=== modified file 'test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_two_ships.lua'
731--- test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_two_ships.lua 2013-10-29 20:22:08 +0000
732+++ test/maps/expedition.wmf/scripting/test_cancel_started_expedition_on_ship_two_ships.lua 2015-08-30 19:39:04 +0000
733@@ -1,5 +1,6 @@
734 run(function()
735- create_two_ships()
736+ create_one_ship()
737
738- test_cancel_started_expedition_on_ship()
739+ --true indicates that second ship is to be created
740+ test_cancel_started_expedition_on_ship(true)
741 end)
742
743=== modified file 'test/maps/expedition.wmf/scripting/test_cancel_when_port_space_was_reached_two_ships.lua'
744--- test/maps/expedition.wmf/scripting/test_cancel_when_port_space_was_reached_two_ships.lua 2013-10-29 20:22:08 +0000
745+++ test/maps/expedition.wmf/scripting/test_cancel_when_port_space_was_reached_two_ships.lua 2015-08-30 19:39:04 +0000
746@@ -1,5 +1,47 @@
747 run(function()
748 create_two_ships()
749
750- test_cancel_when_port_space_was_reached()
751+
752+ sleep(100)
753+ game.desired_speed = 10 * 1000
754+
755+ -- Send expedition to port space.
756+ port:start_expedition()
757+ wait_for_message("Expedition Ready")
758+ assert_equal(1, p1:get_workers("builder"))
759+ sleep(500)
760+
761+
762+ if first_ship.state=="exp_waiting" then
763+ expedition_ship=first_ship
764+ elseif second_ship.state=="exp_waiting" then
765+ expedition_ship=second_ship
766+ else
767+ assert(false)
768+ end
769+
770+ expedition_ship.island_explore_direction="ccw"
771+ sleep(2000)
772+ assert_equal("ccw",expedition_ship.island_explore_direction)
773+ wait_for_message("Port Space Found")
774+ sleep(500)
775+ assert_equal(1, p1:get_workers("builder"))
776+
777+ stable_save("reached_port_space")
778+ assert_equal(1, p1:get_workers("builder"))
779+
780+ cancel_expedition_in_shipwindow(expedition_ship)
781+ sleep(20000)
782+ assert_equal(1, p1:get_workers("builder"))
783+ check_wares_in_port_are_all_there()
784+
785+ -- Dismantle the hardener to make sure that the builder is able to do his work.
786+ game.desired_speed = 50 * 1000
787+ dismantle_hardener()
788+
789+ print("# All Tests passed.")
790+ wl.ui.MapView():close()
791+
792+
793+
794 end)

Subscribers

People subscribed via source and target branches

to status/vote changes: