1 /*
2 * Copyright (C) 2004-2020 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20 #include "economy/flag.h"
21
22 #include <algorithm>
23 #include <iterator>
24
25 #include "base/macros.h"
26 #include "base/wexception.h"
27 #include "economy/economy.h"
28 #include "economy/portdock.h"
29 #include "economy/request.h"
30 #include "economy/road.h"
31 #include "economy/ware_instance.h"
32 #include "economy/waterway.h"
33 #include "graphic/rendertarget.h"
34 #include "logic/editor_game_base.h"
35 #include "logic/game.h"
36 #include "logic/map_objects/map_object.h"
37 #include "logic/map_objects/tribes/building.h"
38 #include "logic/map_objects/tribes/tribe_descr.h"
39 #include "logic/map_objects/tribes/warehouse.h"
40 #include "logic/map_objects/tribes/worker.h"
41 #include "logic/player.h"
42
43 namespace Widelands {
44
45 FlagDescr g_flag_descr("flag", "Flag");
46
descr() const47 const FlagDescr& Flag::descr() const {
48 return g_flag_descr;
49 }
50
51 /**
52 * A bare flag, used for testing only.
53 */
Flag()54 Flag::Flag()
55 : PlayerImmovable(g_flag_descr),
56 animstart_(0),
57 building_(nullptr),
58 ware_capacity_(8),
59 ware_filled_(0),
60 wares_(new PendingWare[ware_capacity_]),
61 always_call_for_flag_(nullptr) {
62 std::fill(std::begin(roads_), std::end(roads_), nullptr);
63 }
64
65 /**
66 * Shouldn't be necessary to do anything,
67 * since die() always calls cleanup() first.
68 */
~Flag()69 Flag::~Flag() {
70 if (ware_filled_) {
71 log("Flag: ouch! wares left\n");
72 }
73 delete[] wares_;
74
75 if (building_) {
76 log("Flag: ouch! building left\n");
77 }
78
79 if (flag_jobs_.size()) {
80 log("Flag: ouch! flagjobs left\n");
81 }
82
83 for (const RoadBase* const road : roads_) {
84 if (road) {
85 log("Flag: ouch! road left\n");
86 }
87 }
88 }
89
load_finish(EditorGameBase & egbase)90 void Flag::load_finish(EditorGameBase& egbase) {
91 auto should_be_deleted = [&egbase, this](const OPtr<Worker>& r) {
92 Worker& worker = *r.get(egbase);
93 Bob::State const* const state = worker.get_state(Worker::taskWaitforcapacity);
94 if (state == nullptr) {
95 log("WARNING: worker %u is in the capacity wait queue of flag %u but "
96 "does not have a waitforcapacity task! Removing from queue.\n",
97 worker.serial(), serial());
98 return true;
99 }
100 if (state->objvar1 != this) {
101 log("WARNING: worker %u is in the capacity wait queue of flag %u but "
102 "its waitforcapacity task is for map object %u! Removing from "
103 "queue.\n",
104 worker.serial(), serial(), state->objvar1.serial());
105 return true;
106 }
107 return false;
108 };
109
110 capacity_wait_.erase(
111 std::remove_if(capacity_wait_.begin(), capacity_wait_.end(), should_be_deleted),
112 capacity_wait_.end());
113 }
114
115 /**
116 * Creates a flag at the given location.
117 */
Flag(EditorGameBase & egbase,Player * owning_player,const Coords & coords,Economy * ware_eco,Economy * worker_eco)118 Flag::Flag(EditorGameBase& egbase,
119 Player* owning_player,
120 const Coords& coords,
121 Economy* ware_eco,
122 Economy* worker_eco)
123 : PlayerImmovable(g_flag_descr),
124 building_(nullptr),
125 ware_capacity_(8),
126 ware_filled_(0),
127 wares_(new PendingWare[ware_capacity_]),
128 always_call_for_flag_(nullptr) {
129 std::fill(std::begin(roads_), std::end(roads_), nullptr);
130
131 set_owner(owning_player);
132
133 set_flag_position(coords);
134
135 upcast(RoadBase, road, egbase.map().get_immovable(coords));
136 upcast(Game, game, &egbase);
137
138 if (game) {
139 if (ware_eco) {
140 // We're saveloading
141 ware_eco->add_flag(*this);
142 } else {
143 // we split a road, or a new, standalone flag is created
144 (road ? road->get_economy(wwWARE) : owning_player->create_economy(wwWARE))
145 ->add_flag(*this);
146 }
147 if (worker_eco) {
148 // We're saveloading
149 worker_eco->add_flag(*this);
150 } else {
151 // we split a road, or a new, standalone flag is created
152 (road ? road->get_economy(wwWORKER) : owning_player->create_economy(wwWORKER))
153 ->add_flag(*this);
154 }
155 if (road && !ware_eco && !worker_eco) {
156 road->presplit(*game, coords);
157 }
158 }
159
160 init(egbase);
161
162 if (!ware_eco && !worker_eco && road && game) {
163 road->postsplit(*game, *this);
164 }
165 }
166
set_flag_position(Coords coords)167 void Flag::set_flag_position(Coords coords) {
168 position_ = coords;
169 }
170
get_size() const171 int32_t Flag::get_size() const {
172 return SMALL;
173 }
174
get_passable() const175 bool Flag::get_passable() const {
176 return true;
177 }
178
base_flag()179 Flag& Flag::base_flag() {
180 return *this;
181 }
182
183 /**
184 * Call this only from Economy code!
185 */
set_economy(Economy * const e,WareWorker type)186 void Flag::set_economy(Economy* const e, WareWorker type) {
187 Economy* const old = get_economy(type);
188
189 if (old == e) {
190 return;
191 }
192
193 PlayerImmovable::set_economy(e, type);
194
195 if (type == wwWARE) {
196 for (int32_t i = 0; i < ware_filled_; ++i) {
197 wares_[i].ware->set_economy(e);
198 }
199 }
200
201 if (building_) {
202 building_->set_economy(e, type);
203 }
204
205 for (const FlagJob& temp_job : flag_jobs_) {
206 if (temp_job.request->get_type() == type) {
207 temp_job.request->set_economy(e);
208 }
209 }
210
211 for (RoadBase* const road : roads_) {
212 if (road) {
213 road->set_economy(e, type);
214 }
215 }
216 }
217
218 /**
219 * Call this only from the Building init!
220 */
attach_building(EditorGameBase & egbase,Building & building)221 void Flag::attach_building(EditorGameBase& egbase, Building& building) {
222 assert(!building_ || building_ == &building);
223
224 building_ = &building;
225
226 const Map& map = egbase.map();
227 egbase.set_road(
228 map.get_fcoords(map.tl_n(position_)), WALK_SE,
229 building_->get_size() == BaseImmovable::SMALL ? RoadSegment::kNormal : RoadSegment::kBusy);
230
231 building.set_economy(get_economy(wwWARE), wwWARE);
232 building.set_economy(get_economy(wwWORKER), wwWORKER);
233 }
234
235 /**
236 * Call this only from the Building cleanup!
237 */
detach_building(EditorGameBase & egbase)238 void Flag::detach_building(EditorGameBase& egbase) {
239 assert(building_);
240
241 building_->set_economy(nullptr, wwWARE);
242 building_->set_economy(nullptr, wwWORKER);
243
244 const Map& map = egbase.map();
245 egbase.set_road(map.get_fcoords(map.tl_n(position_)), WALK_SE, RoadSegment::kNone);
246
247 building_ = nullptr;
248 }
249
250 /**
251 * Call this only from the RoadBase init!
252 */
attach_road(int32_t const dir,RoadBase * const road)253 void Flag::attach_road(int32_t const dir, RoadBase* const road) {
254 assert(!roads_[dir - 1] || roads_[dir - 1] == road);
255
256 roads_[dir - 1] = road;
257 roads_[dir - 1]->set_economy(get_economy(wwWARE), wwWARE);
258 roads_[dir - 1]->set_economy(get_economy(wwWORKER), wwWORKER);
259 }
260
261 /**
262 * Call this only from the RoadBase init!
263 */
detach_road(int32_t const dir)264 void Flag::detach_road(int32_t const dir) {
265 assert(roads_[dir - 1]);
266
267 roads_[dir - 1]->set_economy(nullptr, wwWARE);
268 roads_[dir - 1]->set_economy(nullptr, wwWORKER);
269 roads_[dir - 1] = nullptr;
270 }
271
272 /**
273 * \return all positions we occupy on the map. For a Flag, this is only one.
274 */
get_positions(const EditorGameBase &) const275 BaseImmovable::PositionList Flag::get_positions(const EditorGameBase&) const {
276 PositionList rv;
277 rv.push_back(position_);
278 return rv;
279 }
280
281 /**
282 * \return neighbouring flags.
283 */
get_neighbours(WareWorker type,RoutingNodeNeighbours & neighbours)284 void Flag::get_neighbours(WareWorker type, RoutingNodeNeighbours& neighbours) {
285 for (RoadBase* const road : roads_) {
286 if (!road) {
287 continue;
288 }
289
290 // Only wares, workers cannot use ferries
291 if (Waterway::is_waterway_descr(&road->descr()) && type == wwWORKER) {
292 continue;
293 }
294
295 Flag* f = &road->get_flag(RoadBase::FlagEnd);
296 int32_t nb_cost;
297 if (f != this) {
298 nb_cost = road->get_cost(RoadBase::FlagStart);
299 } else {
300 f = &road->get_flag(RoadBase::FlagStart);
301 nb_cost = road->get_cost(RoadBase::FlagEnd);
302 }
303 if (type == wwWARE) {
304 nb_cost += nb_cost * (get_waitcost() + f->get_waitcost()) / 2;
305 }
306 RoutingNodeNeighbour n(f, nb_cost);
307
308 assert(n.get_neighbour() != this);
309 neighbours.push_back(n);
310 }
311
312 if (building_ && building_->descr().get_isport()) {
313 Warehouse* wh = static_cast<Warehouse*>(building_);
314 if (PortDock* pd = wh->get_portdock()) {
315 pd->add_neighbours(neighbours);
316 }
317 }
318 }
319
320 /**
321 * \return the road that leads to the given flag.
322 */
get_roadbase(Flag & flag)323 RoadBase* Flag::get_roadbase(Flag& flag) {
324 for (RoadBase* const road : roads_) {
325 if (road) {
326 if (&road->get_flag(RoadBase::FlagStart) == &flag ||
327 &road->get_flag(RoadBase::FlagEnd) == &flag) {
328 return road;
329 }
330 }
331 }
332 return nullptr;
333 }
get_road(Flag & flag)334 Road* Flag::get_road(Flag& flag) {
335 for (int8_t i = WalkingDir::FIRST_DIRECTION; i <= WalkingDir::LAST_DIRECTION; ++i) {
336 if (Road* const road = get_road(i)) {
337 if (&road->get_flag(RoadBase::FlagStart) == &flag ||
338 &road->get_flag(RoadBase::FlagEnd) == &flag) {
339 return road;
340 }
341 }
342 }
343 return nullptr;
344 }
345
get_road(uint8_t const dir) const346 Road* Flag::get_road(uint8_t const dir) const {
347 if (roads_[dir - 1] && Road::is_road_descr(&roads_[dir - 1]->descr())) {
348 return dynamic_cast<Road*>(roads_[dir - 1]);
349 }
350 return nullptr;
351 }
get_waterway(uint8_t const dir) const352 Waterway* Flag::get_waterway(uint8_t const dir) const {
353 if (roads_[dir - 1] && Waterway::is_waterway_descr(&roads_[dir - 1]->descr())) {
354 return dynamic_cast<Waterway*>(roads_[dir - 1]);
355 }
356 return nullptr;
357 }
358
359 /// \return the number of RoadBases connected to the flag
nr_of_roadbases() const360 uint8_t Flag::nr_of_roadbases() const {
361 uint8_t counter = 0;
362 for (uint8_t road_id = WalkingDir::LAST_DIRECTION; road_id >= WalkingDir::FIRST_DIRECTION;
363 --road_id) {
364 if (get_roadbase(road_id) != nullptr) {
365 ++counter;
366 }
367 }
368 return counter;
369 }
370
371 /// \return the number of roads connected to the flag.
nr_of_roads() const372 uint8_t Flag::nr_of_roads() const {
373 uint8_t counter = 0;
374 for (uint8_t road_id = WalkingDir::LAST_DIRECTION; road_id >= WalkingDir::FIRST_DIRECTION;
375 --road_id) {
376 if (get_roadbase(road_id) != nullptr) {
377 ++counter;
378 }
379 }
380 return counter;
381 }
382
383 /// \return the number of waterways connected to the flag.
nr_of_waterways() const384 uint8_t Flag::nr_of_waterways() const {
385 uint8_t counter = 0;
386 for (uint8_t road_id = WalkingDir::LAST_DIRECTION; road_id >= WalkingDir::FIRST_DIRECTION;
387 --road_id) {
388 if (get_waterway(road_id) != nullptr) {
389 ++counter;
390 }
391 }
392 return counter;
393 }
394
is_dead_end() const395 bool Flag::is_dead_end() const {
396 if (get_building()) {
397 return false;
398 }
399 Flag const* first_other_flag = nullptr;
400 for (uint8_t road_id = WalkingDir::LAST_DIRECTION; road_id >= WalkingDir::FIRST_DIRECTION;
401 --road_id) {
402 if (RoadBase* const road = get_roadbase(road_id)) {
403 Flag& start = road->get_flag(RoadBase::FlagStart);
404 Flag& other = this == &start ? road->get_flag(RoadBase::FlagEnd) : start;
405 if (first_other_flag) {
406 if (&other != first_other_flag)
407 return false;
408 } else {
409 first_other_flag = &other;
410 }
411 }
412 }
413 return true;
414 }
415
416 /**
417 * Returns true if the flag can hold more wares.
418 */
has_capacity() const419 bool Flag::has_capacity() const {
420 return (ware_filled_ < ware_capacity_);
421 }
422
423 /**
424 * Signal the given bob by interrupting its task as soon as capacity becomes
425 * free.
426 *
427 * The capacity queue is a simple FIFO queue.
428 */
wait_for_capacity(Game &,Worker & bob)429 void Flag::wait_for_capacity(Game&, Worker& bob) {
430 capacity_wait_.push_back(&bob);
431 }
432
433 /**
434 * Remove the worker from the list of workers waiting for free capacity.
435 */
skip_wait_for_capacity(Game &,Worker & w)436 void Flag::skip_wait_for_capacity(Game&, Worker& w) {
437 CapacityWaitQueue::iterator const it =
438 std::find(capacity_wait_.begin(), capacity_wait_.end(), &w);
439 if (it != capacity_wait_.end())
440 capacity_wait_.erase(it);
441 }
442
add_ware(EditorGameBase & egbase,WareInstance & ware)443 void Flag::add_ware(EditorGameBase& egbase, WareInstance& ware) {
444
445 assert(ware_filled_ < ware_capacity_);
446
447 PendingWare& pi = wares_[ware_filled_++];
448 pi.ware = &ware;
449 pi.pending = false;
450 pi.nextstep = nullptr;
451 pi.priority = 0;
452
453 Transfer* trans = ware.get_transfer();
454 if (trans) {
455 uint32_t trans_steps = trans->get_steps_left();
456 if (trans_steps < 3) {
457 pi.priority = 2;
458 } else if (trans_steps == 3) {
459 pi.priority = 1;
460 }
461
462 Request* req = trans->get_request();
463 if (req) {
464 pi.priority = pi.priority + req->get_transfer_priority();
465 }
466 }
467
468 ware.set_location(egbase, this);
469
470 if (upcast(Game, game, &egbase)) {
471 ware.update(*game); // will call call_carrier() if necessary
472 }
473 }
474
475 /**
476 * \return true if a ware is currently waiting for a carrier to the given Flag.
477 *
478 * \note Due to fetch_from_flag() semantics, this function makes no sense
479 * for a building destination.
480 */
has_pending_ware(Game &,Flag & dest)481 bool Flag::has_pending_ware(Game&, Flag& dest) {
482 for (int32_t i = 0; i < ware_filled_; ++i) {
483 if (!wares_[i].pending) {
484 continue;
485 }
486
487 if (wares_[i].nextstep != &dest) {
488 continue;
489 }
490
491 return true;
492 }
493
494 return false;
495 }
496
497 /**
498 * Clamp the maximal value of \ref PendingWare::priority.
499 * After reaching this value, the pure FIFO approach is applied
500 */
501 #define MAX_TRANSFER_PRIORITY 16
502
503 /**
504 * Called by carrier code to indicate that the carrier is moving to pick up an
505 * ware. Ware with highest transfer priority is chosen.
506 * \return true if an ware is actually waiting for the carrier.
507 */
ack_pickup(Game &,Flag & destflag)508 bool Flag::ack_pickup(Game&, Flag& destflag) {
509 int32_t highest_pri = -1;
510 int32_t i_pri = -1;
511
512 for (int32_t i = 0; i < ware_filled_; ++i) {
513 if (!wares_[i].pending) {
514 continue;
515 }
516
517 if (wares_[i].nextstep != &destflag) {
518 continue;
519 }
520
521 if (wares_[i].priority > highest_pri) {
522 highest_pri = wares_[i].priority;
523 i_pri = i;
524
525 // Increase ware priority, it matters only if the ware has to wait.
526 if (wares_[i].priority < MAX_TRANSFER_PRIORITY) {
527 wares_[i].priority++;
528 }
529 }
530 }
531
532 if (i_pri >= 0) {
533 wares_[i_pri].pending = false;
534 return true;
535 }
536
537 return false;
538 }
539 /**
540 * Called by carrier code to find the best among the wares on this flag
541 * that are meant for the provided dest.
542 * \return index of found ware (carrier will take it)
543 * or kNotFoundAppropriate (carrier will leave empty-handed)
544 */
cancel_pickup(Game & game,Flag & destflag)545 bool Flag::cancel_pickup(Game& game, Flag& destflag) {
546 int32_t lowest_prio = MAX_TRANSFER_PRIORITY + 1;
547 int32_t i_pri = -1;
548
549 for (int32_t i = 0; i < ware_filled_; ++i) {
550 if (wares_[i].pending) {
551 continue;
552 }
553
554 if (wares_[i].nextstep != &destflag) {
555 continue;
556 }
557
558 if (wares_[i].priority < lowest_prio) {
559 lowest_prio = wares_[i].priority;
560 i_pri = i;
561 }
562 }
563
564 if (i_pri >= 0) {
565 wares_[i_pri].pending = true;
566 wares_[i_pri].ware->update(game); // will call call_carrier() if necessary
567 return true;
568 }
569
570 return false;
571 }
572
573 /**
574 * Wake one sleeper from the capacity queue.
575 */
wake_up_capacity_queue(Game & game)576 void Flag::wake_up_capacity_queue(Game& game) {
577 while (!capacity_wait_.empty()) {
578 Worker* const w = capacity_wait_.front().get(game);
579 capacity_wait_.pop_front();
580 if (w && w->wakeup_flag_capacity(game, *this)) {
581 break;
582 }
583 }
584 }
585
586 /**
587 * Called by carrier code to retrieve one of the wares on the flag that is meant
588 * for that carrier.
589 *
590 * This function may return 0 even if \ref ack_pickup() has already been
591 * called successfully.
592 */
fetch_pending_ware(Game & game,PlayerImmovable & dest)593 WareInstance* Flag::fetch_pending_ware(Game& game, PlayerImmovable& dest) {
594 int32_t best_index = -1;
595
596 for (int32_t i = 0; i < ware_filled_; ++i) {
597 if (wares_[i].nextstep != &dest) {
598 continue;
599 }
600
601 // We prefer to retrieve wares that have already been acked
602 if (best_index < 0 || !wares_[i].pending) {
603 best_index = i;
604 }
605 }
606
607 if (best_index < 0) {
608 return nullptr;
609 }
610
611 // move the other wares up the list and return this one
612 WareInstance* const ware = wares_[best_index].ware;
613 --ware_filled_;
614 memmove(&wares_[best_index], &wares_[best_index + 1],
615 sizeof(wares_[0]) * (ware_filled_ - best_index));
616
617 ware->set_location(game, nullptr);
618
619 // wake up capacity wait queue
620 wake_up_capacity_queue(game);
621
622 return ware;
623 }
624
625 /**
626 * Accelerate potential promotion of roads adjacent to a newly promoted road.
627 */
propagate_promoted_road(Road * const promoted_road)628 void Flag::propagate_promoted_road(Road* const promoted_road) {
629 // Abort if flag has a building attached to it
630 if (building_) {
631 return;
632 }
633
634 // Calculate the sum of the involved wallets' adjusted value
635 int32_t sum = 0;
636 for (int8_t i = WalkingDir::FIRST_DIRECTION; i <= WalkingDir::LAST_DIRECTION; ++i) {
637 Road* const road = get_road(i);
638 if (road && road != promoted_road) {
639 sum += kRoadMaxWallet + road->wallet() * road->wallet();
640 }
641 }
642
643 // Distribute propagation coins in a smart way
644 for (int8_t i = WalkingDir::FIRST_DIRECTION; i <= WalkingDir::LAST_DIRECTION; ++i) {
645 Road* const road = get_road(i);
646 if (road && !road->is_busy()) {
647 road->add_to_wallet(0.5 * (kRoadMaxWallet - road->wallet()) *
648 (kRoadMaxWallet + road->wallet() * road->wallet()) / sum);
649 }
650 }
651 }
652
653 /**
654 * Count only those wares which are awaiting to be carried along the same road.
655 */
count_wares_in_queue(PlayerImmovable & dest) const656 uint8_t Flag::count_wares_in_queue(PlayerImmovable& dest) const {
657 uint8_t n = 0;
658 for (int32_t i = 0; i < ware_filled_; ++i) {
659 if (wares_[i].nextstep == &dest) {
660 ++n;
661 }
662 }
663 return n;
664 }
665
666 /**
667 * Return a List of all the wares currently on this Flag.
668 * Do not rely the result value to stay valid and do not change them.
669 */
get_wares()670 Flag::Wares Flag::get_wares() {
671 Wares rv;
672
673 for (int32_t i = 0; i < ware_filled_; ++i) {
674 rv.push_back(wares_[i].ware);
675 }
676
677 return rv;
678 }
679
680 /**
681 * Force a removal of the given ware from this flag.
682 * Called by \ref WareInstance::cleanup()
683 */
remove_ware(EditorGameBase & egbase,WareInstance * const ware)684 void Flag::remove_ware(EditorGameBase& egbase, WareInstance* const ware) {
685 for (int32_t i = 0; i < ware_filled_; ++i) {
686 if (wares_[i].ware != ware) {
687 continue;
688 }
689
690 --ware_filled_;
691 memmove(&wares_[i], &wares_[i + 1], sizeof(wares_[0]) * (ware_filled_ - i));
692
693 if (upcast(Game, game, &egbase)) {
694 wake_up_capacity_queue(*game);
695 }
696
697 return;
698 }
699
700 throw wexception("MO(%u): Flag::remove_ware: ware %u not on flag", serial(), ware->serial());
701 }
702
703 /**
704 * If nextstep is not null, a carrier will be called to move this ware to
705 * the given flag or building.
706 *
707 * If nextstep is null, the internal data will be reset to indicate that the
708 * ware isn't going anywhere right now.
709 *
710 * nextstep is compared with the cached data, and a new carrier is only called
711 * if that data hasn't changed.
712 *
713 * This behaviour is overridden by always_call_for_step_, which is set by
714 * update_wares() to ensure that new carriers are called when roads are
715 * split, for example.
716 */
call_carrier(Game & game,WareInstance & ware,PlayerImmovable * const nextstep)717 void Flag::call_carrier(Game& game, WareInstance& ware, PlayerImmovable* const nextstep) {
718 PendingWare* pi = nullptr;
719 int32_t i = 0;
720
721 // Find the PendingWare entry
722 for (; i < ware_filled_; ++i) {
723 if (wares_[i].ware != &ware) {
724 continue;
725 }
726
727 pi = &wares_[i];
728 break;
729 }
730
731 assert(pi);
732
733 // Deal with the non-moving case quickly
734 if (!nextstep) {
735 pi->nextstep = nullptr;
736 pi->pending = true;
737 return;
738 }
739
740 // Find out whether we need to do anything
741 if (pi->nextstep == nextstep && pi->nextstep != always_call_for_flag_) {
742 return; // no update needed
743 }
744
745 pi->nextstep = nextstep;
746 pi->pending = false;
747
748 // Deal with the building case
749 if (nextstep == get_building()) {
750 molog("Flag::call_carrier(%u): Tell building to fetch this ware\n", ware.serial());
751
752 if (!get_building()->fetch_from_flag(game)) {
753 pi->ware->cancel_moving();
754 pi->ware->update(game);
755 }
756
757 return;
758 }
759
760 // Deal with the normal (flag) case
761 const Flag& nextflag = dynamic_cast<const Flag&>(*nextstep);
762
763 for (int32_t dir = WalkingDir::FIRST_DIRECTION; dir <= WalkingDir::LAST_DIRECTION; ++dir) {
764 RoadBase* const road = get_roadbase(dir);
765 Flag* other;
766 RoadBase::FlagId flagid;
767
768 if (!road) {
769 continue;
770 }
771
772 if (&road->get_flag(RoadBase::FlagStart) == this) {
773 flagid = RoadBase::FlagStart;
774 other = &road->get_flag(RoadBase::FlagEnd);
775 } else {
776 flagid = RoadBase::FlagEnd;
777 other = &road->get_flag(RoadBase::FlagStart);
778 }
779
780 if (other != &nextflag) {
781 continue;
782 }
783
784 // Yes, this is the road we want; inform it
785 if (road->notify_ware(game, flagid)) {
786 return;
787 }
788
789 // If the road doesn't react to the ware immediately, we try other roads:
790 // They might lead to the same flag!
791 }
792
793 // Nothing found, just let it be picked up by somebody
794 pi->pending = true;
795 return;
796 }
797
798 /**
799 * Called whenever a road gets broken or split.
800 * Make sure all wares on this flag are rerouted if necessary.
801 *
802 * \note When two roads connect the same two flags, and one of these roads
803 * is removed, this might cause the carrier(s) on the other road to
804 * move unnecessarily. Fixing this could potentially be very expensive and
805 * fragile.
806 * A similar thing can happen when a road is split.
807 */
update_wares(Game & game,Flag * const other)808 void Flag::update_wares(Game& game, Flag* const other) {
809 always_call_for_flag_ = other;
810
811 for (int32_t i = 0; i < ware_filled_; ++i) {
812 wares_[i].ware->update(game);
813 }
814
815 always_call_for_flag_ = nullptr;
816 }
817
init(EditorGameBase & egbase)818 bool Flag::init(EditorGameBase& egbase) {
819 PlayerImmovable::init(egbase);
820
821 set_position(egbase, position_);
822
823 animstart_ = egbase.get_gametime();
824 return true;
825 }
826
827 /**
828 * Detach building and free roads.
829 */
cleanup(EditorGameBase & egbase)830 void Flag::cleanup(EditorGameBase& egbase) {
831 while (!flag_jobs_.empty()) {
832 delete flag_jobs_.begin()->request;
833 flag_jobs_.erase(flag_jobs_.begin());
834 }
835
836 while (ware_filled_) {
837 WareInstance& ware = *wares_[--ware_filled_].ware;
838
839 ware.set_location(egbase, nullptr);
840 ware.destroy(egbase);
841 }
842
843 if (building_) {
844 building_->remove(egbase); // immediate death
845 assert(!building_);
846 }
847
848 for (uint8_t i = 0; i < (sizeof(roads_) / sizeof(roads_[0])); ++i) {
849 if (roads_[i]) {
850 roads_[i]->remove(egbase); // immediate death
851 assert(!roads_[i]);
852 }
853 }
854
855 if (Economy* e = get_economy(wwWARE)) {
856 e->remove_flag(*this);
857 }
858 if (Economy* e = get_economy(wwWORKER)) {
859 e->remove_flag(*this);
860 }
861
862 unset_position(egbase, position_);
863
864 PlayerImmovable::cleanup(egbase);
865 }
866
draw(uint32_t gametime,const InfoToDraw,const Vector2f & field_on_dst,const Coords & coords,float scale,RenderTarget * dst)867 void Flag::draw(uint32_t gametime,
868 const InfoToDraw,
869 const Vector2f& field_on_dst,
870 const Coords& coords,
871 float scale,
872 RenderTarget* dst) {
873 static struct {
874 float x, y;
875 } ware_offsets[8] = {{-5.f, 1.f}, {-1.f, 3.f}, {3.f, 3.f}, {7.f, 1.f},
876 {-6.f, -3.f}, {-1.f, -2.f}, {3.f, -2.f}, {8.f, -3.f}};
877
878 const RGBColor& player_color = owner().get_playercolor();
879 dst->blit_animation(field_on_dst, coords, scale, owner().tribe().flag_animation(),
880 gametime - animstart_, &player_color);
881
882 for (int32_t i = 0; i < ware_filled_; ++i) { // draw wares
883 Vector2f warepos = field_on_dst;
884 if (i < 8) {
885 warepos.x += ware_offsets[i].x * scale;
886 warepos.y += ware_offsets[i].y * scale;
887 } else {
888 warepos.y -= (6.f + (i - 8.f) * 3.f) * scale;
889 }
890 dst->blit_animation(warepos, Widelands::Coords::null(), scale,
891 wares_[i].ware->descr().get_animation("idle", wares_[i].ware), 0,
892 &player_color);
893 }
894 }
895
896 /**
897 * Destroy the building as well.
898 *
899 * \note This is needed in addition to the call to building_->remove() in
900 * \ref Flag::cleanup(). This function is needed to ensure a fire is created
901 * when a player removes a flag.
902 */
destroy(EditorGameBase & egbase)903 void Flag::destroy(EditorGameBase& egbase) {
904 if (building_) {
905 building_->destroy(egbase);
906 assert(!building_);
907 }
908
909 PlayerImmovable::destroy(egbase);
910 }
911
912 /**
913 * Add a new flag job to request the worker with the given ID,
914 * and to execute the given program once it's completed.
915 */
add_flag_job(Game &,DescriptionIndex const workerware,const std::string & programname)916 void Flag::add_flag_job(Game&, DescriptionIndex const workerware, const std::string& programname) {
917 FlagJob j;
918
919 j.request = new Request(*this, workerware, Flag::flag_job_request_callback, wwWORKER);
920 j.program = programname;
921
922 flag_jobs_.push_back(j);
923 }
924
925 /**
926 * This function is called when one of the flag job workers arrives on
927 * the flag. Give him his job.
928 */
flag_job_request_callback(Game & game,Request & rq,DescriptionIndex,Worker * const w,PlayerImmovable & target)929 void Flag::flag_job_request_callback(
930 Game& game, Request& rq, DescriptionIndex, Worker* const w, PlayerImmovable& target) {
931 Flag& flag = dynamic_cast<Flag&>(target);
932
933 assert(w);
934
935 for (FlagJobs::iterator flag_iter = flag.flag_jobs_.begin(); flag_iter != flag.flag_jobs_.end();
936 ++flag_iter) {
937 if (flag_iter->request == &rq) {
938 delete &rq;
939
940 w->start_task_program(game, flag_iter->program);
941
942 flag.flag_jobs_.erase(flag_iter);
943 return;
944 }
945 }
946
947 flag.molog("BUG: flag_job_request_callback: worker not found in list\n");
948 }
949
log_general_info(const Widelands::EditorGameBase & egbase) const950 void Flag::log_general_info(const Widelands::EditorGameBase& egbase) const {
951 molog("Flag at %i,%i\n", position_.x, position_.y);
952
953 Widelands::PlayerImmovable::log_general_info(egbase);
954
955 if (ware_filled_) {
956 molog("Wares at flag:\n");
957 for (int i = 0; i < ware_filled_; ++i) {
958 PendingWare& pi = wares_[i];
959 molog(" %i/%i: %s(%i), nextstep %i, %s\n", i + 1, ware_capacity_,
960 pi.ware->descr().name().c_str(), pi.ware->serial(), pi.nextstep.serial(),
961 pi.pending ? "pending" : "acked by carrier");
962 }
963 } else {
964 molog("No wares at flag.\n");
965 }
966 }
967 } // namespace Widelands
968