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

Proposed by Benedikt Straub on 2019-05-14
Status: Needs review
Proposed branch: lp:~widelands-dev/widelands/constructionsite_options
Merge into: lp:widelands
Diff against target: 2863 lines (+1576/-202)
38 files modified
src/ai/defaultai_seafaring.cc (+1/-1)
src/economy/economy.cc (+5/-5)
src/economy/request.cc (+1/-1)
src/logic/editor_game_base.cc (+8/-2)
src/logic/editor_game_base.h (+3/-1)
src/logic/game.cc (+7/-2)
src/logic/game.h (+3/-0)
src/logic/map_objects/CMakeLists.txt (+2/-0)
src/logic/map_objects/tribes/bill_of_materials.h (+0/-23)
src/logic/map_objects/tribes/building.cc (+3/-3)
src/logic/map_objects/tribes/building.h (+10/-5)
src/logic/map_objects/tribes/building_settings.cc (+346/-0)
src/logic/map_objects/tribes/building_settings.h (+123/-0)
src/logic/map_objects/tribes/constructionsite.cc (+265/-21)
src/logic/map_objects/tribes/constructionsite.h (+21/-0)
src/logic/map_objects/tribes/militarysite.cc (+7/-0)
src/logic/map_objects/tribes/militarysite.h (+2/-0)
src/logic/map_objects/tribes/productionsite.cc (+29/-6)
src/logic/map_objects/tribes/productionsite.h (+2/-0)
src/logic/map_objects/tribes/trainingsite.cc (+7/-0)
src/logic/map_objects/tribes/trainingsite.h (+2/-0)
src/logic/map_objects/tribes/warehouse.cc (+20/-8)
src/logic/map_objects/tribes/warehouse.h (+36/-33)
src/logic/player.cc (+2/-1)
src/logic/playercommand.cc (+99/-26)
src/logic/playercommand.h (+5/-3)
src/map_io/map_buildingdata_packet.cc (+24/-4)
src/notifications/note_ids.h (+1/-0)
src/scripting/lua_map.cc (+15/-15)
src/wui/actionconfirm.cc (+22/-10)
src/wui/actionconfirm.h (+2/-1)
src/wui/buildingwindow.cc (+3/-3)
src/wui/buildingwindow.h (+5/-1)
src/wui/constructionsitewindow.cc (+340/-1)
src/wui/constructionsitewindow.h (+39/-0)
src/wui/inputqueuedisplay.cc (+91/-17)
src/wui/inputqueuedisplay.h (+17/-1)
src/wui/warehousewindow.cc (+8/-8)
To merge this branch: bzr merge lp:~widelands-dev/widelands/constructionsite_options
Reviewer Review Type Date Requested Status
GunChleoc 2019-05-14 Needs Fixing on 2019-06-08
Review via email: mp+367428@code.launchpad.net

Commit message

Allow players to define settings for and to enhance buildings under construction

To post a comment you must log in.
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4971. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/532431388.
Appveyor build 4752. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_constructionsite_options-4752.

Toni Förster (stonerl) wrote :

I get these compiler warnings a couple of times.

/Users/toni/Launchpad/widelands-repo/working_tree/src/logic/map_objects/tribes/building_settings.h:42:8: warning: 'Widelands::BuildingSettings' has virtual functions but non-virtual destructor [-Wnon-virtual-dtor]
struct BuildingSettings {
       ^
/Users/toni/Launchpad/widelands-repo/working_tree/src/logic/map_objects/tribes/building_settings.h:57:8: warning: 'Widelands::ProductionsiteSettings' has virtual functions but non-virtual destructor [-Wnon-virtual-dtor]
struct ProductionsiteSettings : public BuildingSettings {
       ^
/Users/toni/Launchpad/widelands-repo/working_tree/src/logic/map_objects/tribes/building_settings.h:74:8: warning: 'Widelands::MilitarysiteSettings' has virtual functions but non-virtual destructor [-Wnon-virtual-dtor]
struct MilitarysiteSettings : public BuildingSettings {
       ^
/Users/toni/Launchpad/widelands-repo/working_tree/src/logic/map_objects/tribes/building_settings.h:86:8: warning: 'Widelands::TrainingsiteSettings' has virtual functions but non-virtual destructor [-Wnon-virtual-dtor]
struct TrainingsiteSettings : public ProductionsiteSettings {
       ^
/Users/toni/Launchpad/widelands-repo/working_tree/src/logic/map_objects/tribes/building_settings.h:97:8: warning: 'Widelands::WarehouseSettings' has virtual functions but non-virtual destructor [-Wnon-virtual-dtor]
struct WarehouseSettings : public BuildingSettings {
       ^
5 warnings generated.

Toni Förster (stonerl) wrote :

Some comments regarding the UI.

I think we should keep the UI consistent. Instead of checkboxes please use the icons/buttons that are used in the building's window. The same applies for the priority settings. We use traffic lights instead of buttons.

9106. By Nordfriese on 2019-05-15

Added virtual destructor

9107. By Nordfriese on 2019-05-15

Made UI design more consistant

Benedikt Straub (nordfriese) wrote :

Fixed the compiler warnings and made the UI design consistent. I did not convert the Stop and Launch Expedition to toggle-buttons though because it is never clear with such buttons whether the icon shows the current state or the action taken by clicking it IMHO.

By the way, when clicking the Enhance button, the window will annoyingly switch to the first tab – this is unrelated to this branch, see bug 1818857.

9108. By Nordfriese on 2019-05-15

Some glitches fixed

9109. By Nordfriese on 2019-05-15

Some glitches fixed

Toni Förster (stonerl) wrote :

hmm. I would prefer icons but you are completely right. I opened a topic in the forum:

https://wl.widelands.org/forum/topic/4518/?page=1#post-27957

Toni Förster (stonerl) wrote :

Four warnings left:

src/logic/playercommand.cc:2288:6: warning: default label in switch which covers all enumeration values [-Wcovered-switch-default]
                                        default:

src/logic/playercommand.cc:2384:6: warning: default label in switch which covers all enumeration values [-Wcovered-switch-default]
                                        default:

src/wui/constructionsitewindow.cc:197:3: warning: default label in switch which covers all enumeration values [-Wcovered-switch-default]
                default:

src/logic/map_objects/tribes/building_settings.cc:176:5: warning: default label in switch which covers all enumeration values [-Wcovered-switch-default]
                                default:

Toni Förster (stonerl) wrote :

Your buttons are a little too big. The buttons for in-/decreasing the wares are 24x24 while yours are 25x30.

Also, some wares are covered by the button; see the fish in the tavern (I guess that is because of your buttons being to big)

Toni Förster (stonerl) wrote :

With this branch I get crashes after a while. Not sure if the culprit is this branch or something in trunk, though.

/Users/toni/Launchpad/widelands-repo/working_tree/src/graphic/animation.cc:451] Requested unknown animation with id: -432781024
==54196==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000000000000 bp 0x7ffee6344650 sp 0x7ffee63445a8 T0)

9110. By Nordfriese on 2019-05-15

FakeInputQueue layouting fixes

Benedikt Straub (nordfriese) wrote :

Took care of the warnings and fixed the input queue layout.

> src/graphic/animation.cc:451] Requested unknown animation with id: -432781024

A backtrace would be helpful…
Did you get this while an (enhanced?) constructionsite was being built, or when a constructionsite was being completed? I got similar crashes before, but I thought I had caught all corner cases now…

9111. By Nordfriese on 2019-05-15

Minimum soldier capacity in militarysites is 1

Toni Förster (stonerl) wrote :

Assertion failed: (military_site_->capacity_ != capacity), function set_soldier_capacity, file /Users/toni/Launchpad/widelands-repo/working_tree/src/logic/map_objects/tribes/militarysite.cc, line 85.

9112. By Nordfriese on 2019-05-16

Prevent assert failure

Benedikt Straub (nordfriese) wrote :

Assert fail fixed :)

kaputtnik (franku) wrote :

Looks like this branch breaks savegame compatibility. When trying to load a game which runs fine in trunk i get:

Writing Buildingdata Data ... widelands: /home/kaputtnik/Quellcode/widelands-repo/constructionsite_options/src/map_io/map_buildingdata_packet.cc:974: void Widelands::MapBuildingdataPacket::write_constructionsite(const Widelands::ConstructionSite&, FileWrite&, Widelands::Game&, Widelands::MapObjectSaver&): Assertion `constructionsite.settings_' failed.
Abgebrochen (Speicherabzug geschrieben)

9113. By Nordfriese on 2019-05-16

Fixed saveloading

Benedikt Straub (nordfriese) wrote :

Oops… should be fixed now

Toni Förster (stonerl) wrote :

And another assertion.

Assertion failed: (animation_index < animations.size()), function draw, file /Users/toni/Launchpad/widelands-repo/working_tree/src/logic/map_objects/tribes/constructionsite.cc, line 85.

Benedikt Straub (nordfriese) wrote :

This seems to be the same issue as the crash with animation ID -432781024, but with a more usable file&line number. Will push a fix soonish

9114. By Nordfriese on 2019-05-16

Indices are counted from 0…

Benedikt Straub (nordfriese) wrote :

Since the bug is not reproducible, I can´t be certain, but it should most likely be gone now

Toni Förster (stonerl) wrote :

Seems to be fixed.

9115. By Nordfriese on 2019-05-16

Fixed hero/rookie buttons

kaputtnik (franku) wrote :

Trying to load a savgame from trunk prints now in a window (and console):

Game data error
buildingdata: building 524547: not found

Loading in trunk works fine. Save game: https://bugs.launchpad.net/widelands/+bug/1597310/+attachment/5264357/+files/construction_site_settings.wgf

GunChleoc (gunchleoc) wrote :

I am getting a similar error when loading our homepage reference screenshot savegame Build, so we already have a change to saveloading in trunk where we overlooked having to increase the packet number.

bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 5003. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/533470509.
Appveyor build 4784. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_constructionsite_options-4784.

Toni Förster (stonerl) wrote :

Would it be possible to move the tabs for Warehouses' and Ports' to the top, instead of having to tab rows?

Benedikt Straub (nordfriese) wrote :

OK, will change it like this

9116. By Nordfriese on 2019-05-24

Use only one tab row in warehouse construction windows

9117. By Nordfriese on 2019-05-25

Merged trunk

GunChleoc (gunchleoc) wrote :

It would be nice if the tab was remembered after using the "enhance" button.

The target of the help button does not get updated when enhancing, e.g. construction site for deeper coal mine will show the coal mine instead.

"Launch expedition" should be "Start an expedition" like on the button for the finished port.

It would be nice if the extra options like "Start an expedition" or "Stop" would have the same UI buttons as the finished sites. I can live with the checkboxes though.

GunChleoc (gunchleoc) wrote :

Also, this:

=================================================================
==6265==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 2744 byte(s) in 49 object(s) allocated from:
    #0 0x7ff86f576458 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe0458)
    #1 0x55643637edfd in Widelands::MilitarySite::create_building_settings() const ../src/logic/map_objects/tribes/militarysite.cc:978
    #2 0x556435cb4c9b in Widelands::Player::enhance_or_dismantle(Widelands::Building*, unsigned char) ../src/logic/player.cc:763
    #3 0x556435cb47a3 in Widelands::Player::dismantle_building(Widelands::Building*) ../src/logic/player.cc:743
    #4 0x5564366afc07 in Widelands::CmdDismantleBuilding::execute(Widelands::Game&) ../src/logic/playercommand.cc:701
    #5 0x5564366a690e in Widelands::CmdQueue::run_queue(int, unsigned int&) ../src/logic/cmd_queue.cc:122
    #6 0x556435c8be44 in Widelands::Game::think() ../src/logic/game.cc:599
    #7 0x55643605fe76 in InteractiveBase::think() ../src/wui/interactive_base.cc:475
    #8 0x5564360b3bde in InteractivePlayer::think() ../src/wui/interactive_player.cc:228
    #9 0x556435eec265 in UI::Panel::do_think() ../src/ui_basic/panel.cc:483
    #10 0x556435ee95ca in UI::Panel::do_run() ../src/ui_basic/panel.cc:184
    #11 0x556435983b5d in UI::Panel::Returncodes UI::Panel::run<UI::Panel::Returncodes>() ../src/ui_basic/panel.h:104
    #12 0x556435c8b669 in Widelands::Game::run(UI::ProgressWindow*, Widelands::Game::StartGameType, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) ../src/logic/game.cc:569
    #13 0x55643596f976 in WLApplication::new_game() ../src/wlapplication.cc:1354
    #14 0x55643596da4a in WLApplication::mainmenu_singleplayer() ../src/wlapplication.cc:1208
    #15 0x55643596cb95 in WLApplication::mainmenu() ../src/wlapplication.cc:1114
    #16 0x556435963b7b in WLApplication::run() ../src/wlapplication.cc:470
    #17 0x55643595f8ce in main ../src/main.cc:44
    #18 0x7ff86c9a9b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)

9118. By Nordfriese on 2019-05-25

Adressed review

Benedikt Straub (nordfriese) wrote :

> "Launch expedition" should be "Start an expedition" like on the button for the finished port.
> The target of the help button does not get updated when enhancing, e.g. construction site for deeper coal mine will show the coal mine instead.
> ASan

Should all be fixed now

> It would be nice if the tab was remembered after using the "enhance" button.

This is exactly the same as bug 1818857 so it should be fixed independent from this branch. There will likely be one catch-all fix for both flavours of the bug.

> It would be nice if the extra options like "Start an expedition" or "Stop" would have the same UI buttons as the finished sites. I can live with the checkboxes though.

What I could do is to render the appropriate icon next to the checkbox if you like. But unless we change the other UI elements in such a way that they show clearly what the current state is, there is no alternative to the checkboxes IMHO, since the current icons are only acceptable because one can see the active state elsewhere (stats string / expedition tab), which can not happen here.

GunChleoc (gunchleoc) wrote :

OK, let's leave the design as it is :)

This doesn't compile:

ow.cc.o -c ../src/wui/dismantlesitewindow.cc
In file included from ../src/wui/dismantlesitewindow.h:25:0,
                 from ../src/wui/dismantlesitewindow.cc:20:
../src/wui/buildingwindow.h: In member function ‘void BuildingWindow::set_building_descr_for_help(const Widelands::BuildingDescr&)’:
../src/wui/buildingwindow.h:99:30: error: ‘void Widelands::BuildingDescr::operator=(const Widelands::BuildingDescr&)’ is private within this context
   building_descr_for_help_ = d;
                              ^

Once that has been fixed, we still need to look at the code.

9119. By Nordfriese on 2019-05-25

Compile error

9120. By Nordfriese on 2019-05-25

Compile error

9121. By Nordfriese on 2019-05-25

Compile error

9122. By Nordfriese on 2019-05-25

Compile error...

9123. By Nordfriese on 2019-05-28

Merged trunk

bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 5074. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/538200870.
Appveyor build 4854. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_constructionsite_options-4854.

9124. By Nordfriese on 2019-05-28

compile error

bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 5076. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/538299033.
Appveyor build 4856. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_constructionsite_options-4856.

GunChleoc (gunchleoc) wrote :

I finally got around to doing the code review. This branch still has a lot of room for streamlining the code and the performance.

review: Needs Fixing
Benedikt Straub (nordfriese) wrote :

Implemented your comments

9125. By Nordfriese on 2019-06-09

Adressed code review

bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 5185. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/544759817.
Appveyor build 4965. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_constructionsite_options-4965.

GunChleoc (gunchleoc) wrote :

The changes look good - there are still some open comments, though. Sorry it took me a while to get back to this.

9126. By Nordfriese 8 hours ago

Removed struct WareRange

Benedikt Straub (nordfriese) wrote :

No problem. I have very little time for Widelands at the moment anyway :)

9127. By Nordfriese 8 hours ago

Merged trunk

9128. By Nordfriese 7 hours ago

Merge error

9129. By Nordfriese 6 hours ago

Fixed compile error

Unmerged revisions

9129. By Nordfriese 6 hours ago

Fixed compile error

9128. By Nordfriese 7 hours ago

Merge error

9127. By Nordfriese 8 hours ago

Merged trunk

9126. By Nordfriese 8 hours ago

Removed struct WareRange

9125. By Nordfriese on 2019-06-09

Adressed code review

9124. By Nordfriese on 2019-05-28

compile error

9123. By Nordfriese on 2019-05-28

Merged trunk

9122. By Nordfriese on 2019-05-25

Compile error...

9121. By Nordfriese on 2019-05-25

Compile error

9120. By Nordfriese on 2019-05-25

Compile error

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/ai/defaultai_seafaring.cc'
2--- src/ai/defaultai_seafaring.cc 2019-02-23 11:00:49 +0000
3+++ src/ai/defaultai_seafaring.cc 2019-06-19 09:23:26 +0000
4@@ -346,7 +346,7 @@
5 if (site->bo->is(BuildingAttribute::kShipyard)) {
6 for (uint32_t k = 0; k < site->bo->inputs.size(); ++k) {
7 game().send_player_set_ware_priority(
8- *site->site, wwWARE, site->bo->inputs.at(k), HIGH_PRIORITY);
9+ *site->site, wwWARE, site->bo->inputs.at(k), kPriorityHigh);
10 }
11 }
12 }
13
14=== modified file 'src/economy/economy.cc'
15--- src/economy/economy.cc 2019-04-09 16:43:49 +0000
16+++ src/economy/economy.cc 2019-06-19 09:23:26 +0000
17@@ -971,7 +971,7 @@
18 static bool accept_warehouse_if_policy(Warehouse& wh,
19 WareWorker type,
20 DescriptionIndex ware,
21- Warehouse::StockPolicy policy) {
22+ StockPolicy policy) {
23 return wh.get_stock_policy(type, ware) == policy;
24 }
25
26@@ -1005,8 +1005,8 @@
27
28 for (uint32_t nwh = 0; nwh < warehouses_.size(); ++nwh) {
29 Warehouse* wh = warehouses_[nwh];
30- Warehouse::StockPolicy policy = wh->get_stock_policy(type, ware);
31- if (policy == Warehouse::StockPolicy::kPrefer) {
32+ StockPolicy policy = wh->get_stock_policy(type, ware);
33+ if (policy == StockPolicy::kPrefer) {
34 haveprefer = true;
35
36 // Getting count of worker/ware
37@@ -1022,7 +1022,7 @@
38 preferred_wh_stock = current_stock;
39 }
40 }
41- if (policy == Warehouse::StockPolicy::kNormal)
42+ if (policy == StockPolicy::kNormal)
43 havenormal = true;
44 }
45 if (!havenormal && !haveprefer && type == wwWARE)
46@@ -1037,7 +1037,7 @@
47 (!havenormal) ?
48 WarehouseAcceptFn() :
49 boost::bind(&accept_warehouse_if_policy, _1, type, ware,
50- Warehouse::StockPolicy::kNormal));
51+ StockPolicy::kNormal));
52 }
53 if (!wh) {
54 log("Warning: Economy::handle_active_supplies "
55
56=== modified file 'src/economy/request.cc'
57--- src/economy/request.cc 2019-06-13 17:32:28 +0000
58+++ src/economy/request.cc 2019-06-19 09:23:26 +0000
59@@ -266,7 +266,7 @@
60 int32_t Request::get_priority(int32_t cost) const {
61 int MAX_IDLE_PRIORITY = 100;
62 bool is_construction_site = false;
63- int32_t modifier = DEFAULT_PRIORITY;
64+ int32_t modifier = kPriorityNormal;
65
66 if (target_building_) {
67 modifier = target_building_->get_priority(get_type(), get_index());
68
69=== modified file 'src/logic/editor_game_base.cc'
70--- src/logic/editor_game_base.cc 2019-04-26 05:52:49 +0000
71+++ src/logic/editor_game_base.cc 2019-06-19 09:23:26 +0000
72@@ -38,6 +38,7 @@
73 #include "logic/map_objects/map_object.h"
74 #include "logic/map_objects/tribes/battle.h"
75 #include "logic/map_objects/tribes/building.h"
76+#include "logic/map_objects/tribes/constructionsite.h"
77 #include "logic/map_objects/tribes/dismantlesite.h"
78 #include "logic/map_objects/tribes/tribe_descr.h"
79 #include "logic/map_objects/tribes/tribes.h"
80@@ -349,10 +350,15 @@
81 PlayerNumber const owner,
82 DescriptionIndex idx,
83 bool loading,
84- Building::FormerBuildings former_buildings) {
85+ Building::FormerBuildings former_buildings,
86+ const BuildingSettings* settings) {
87 Player* plr = get_player(owner);
88 const TribeDescr& tribe = plr->tribe();
89- return tribe.get_building_descr(idx)->create(*this, plr, c, true, loading, former_buildings);
90+ Building& b = tribe.get_building_descr(idx)->create(*this, plr, c, true, loading, former_buildings);
91+ if (settings) {
92+ dynamic_cast<ConstructionSite&>(b).apply_settings(*settings);
93+ }
94+ return b;
95 }
96
97 /**
98
99=== modified file 'src/logic/editor_game_base.h'
100--- src/logic/editor_game_base.h 2019-02-27 19:00:36 +0000
101+++ src/logic/editor_game_base.h 2019-06-19 09:23:26 +0000
102@@ -56,6 +56,7 @@
103 class TribeDescr;
104 struct Flag;
105 struct AttackController;
106+struct BuildingSettings;
107
108 struct NoteFieldPossession {
109 CAN_BE_SENT_AS_NOTE(NoteId::FieldPossession)
110@@ -130,7 +131,8 @@
111 PlayerNumber,
112 DescriptionIndex,
113 bool loading = false,
114- Building::FormerBuildings former_buildings = Building::FormerBuildings());
115+ Building::FormerBuildings former_buildings = Building::FormerBuildings(),
116+ const BuildingSettings* settings = nullptr);
117 Building&
118 warp_dismantlesite(const Coords&,
119 PlayerNumber,
120
121=== modified file 'src/logic/game.cc'
122--- src/logic/game.cc 2019-05-25 07:36:44 +0000
123+++ src/logic/game.cc 2019-06-19 09:23:26 +0000
124@@ -56,6 +56,7 @@
125 #include "logic/map_objects/tribes/soldier.h"
126 #include "logic/map_objects/tribes/trainingsite.h"
127 #include "logic/map_objects/tribes/tribe_descr.h"
128+#include "logic/map_objects/tribes/warehouse.h"
129 #include "logic/player.h"
130 #include "logic/playercommand.h"
131 #include "logic/replay.h"
132@@ -775,8 +776,7 @@
133 }
134
135 void Game::send_player_enhance_building(Building& building, DescriptionIndex const id) {
136- assert(building.owner().tribe().has_building(id));
137-
138+ assert(building.descr().type() == MapObjectType::CONSTRUCTIONSITE || building.owner().tribe().has_building(id));
139 send_player_command(
140 new CmdEnhanceBuilding(get_gametime(), building.owner().player_number(), building, id));
141 }
142@@ -858,6 +858,11 @@
143 new CmdProposeTrade(get_gametime(), object->get_owner()->player_number(), trade));
144 }
145
146+void Game::send_player_set_stock_policy(Building& imm, WareWorker ww, DescriptionIndex di, StockPolicy sp) {
147+ send_player_command(new CmdSetStockPolicy(get_gametime(), imm.get_owner()->player_number(),
148+ imm, ww == wwWORKER, di, sp));
149+}
150+
151 int Game::propose_trade(const Trade& trade) {
152 // TODO(sirver,trading): Check if a trade is possible (i.e. if there is a
153 // path between the two markets);
154
155=== modified file 'src/logic/game.h'
156--- src/logic/game.h 2019-05-25 07:36:44 +0000
157+++ src/logic/game.h 2019-06-19 09:23:26 +0000
158@@ -46,6 +46,7 @@
159 // See forester_cache_
160 constexpr int16_t kInvalidForesterEntry = -1;
161
162+class ConstructionSite;
163 struct Flag;
164 struct Path;
165 struct PlayerImmovable;
166@@ -56,6 +57,7 @@
167 struct PlayerEndStatus;
168 class TrainingSite;
169 class MilitarySite;
170+enum class StockPolicy;
171
172 enum {
173 gs_notrunning = 0, // game is being prepared
174@@ -262,6 +264,7 @@
175
176 void send_player_enhance_building(Building&, DescriptionIndex);
177 void send_player_evict_worker(Worker&);
178+ void send_player_set_stock_policy(Building&, WareWorker, DescriptionIndex, StockPolicy);
179 void send_player_set_ware_priority(PlayerImmovable&,
180 int32_t type,
181 DescriptionIndex index,
182
183=== modified file 'src/logic/map_objects/CMakeLists.txt'
184--- src/logic/map_objects/CMakeLists.txt 2019-05-12 07:45:59 +0000
185+++ src/logic/map_objects/CMakeLists.txt 2019-06-19 09:23:26 +0000
186@@ -49,6 +49,8 @@
187 tribes/bill_of_materials.h
188 tribes/building.cc
189 tribes/building.h
190+ tribes/building_settings.cc
191+ tribes/building_settings.h
192 tribes/carrier.cc
193 tribes/carrier.h
194 tribes/constructionsite.cc
195
196=== modified file 'src/logic/map_objects/tribes/bill_of_materials.h'
197--- src/logic/map_objects/tribes/bill_of_materials.h 2019-02-23 11:00:49 +0000
198+++ src/logic/map_objects/tribes/bill_of_materials.h 2019-06-19 09:23:26 +0000
199@@ -28,29 +28,6 @@
200 using WareAmount = std::pair<DescriptionIndex, Widelands::Quantity>;
201 using BillOfMaterials = std::vector<WareAmount>;
202
203-// range structure for iterating ware range with index
204-struct WareRange {
205- explicit WareRange(const BillOfMaterials& range)
206- : i(0), current(range.begin()), end(range.end()) {
207- }
208- WareRange& operator++() {
209- ++i;
210- ++current;
211- return *this;
212- }
213- bool empty() const {
214- return current == end;
215- }
216- operator bool() const {
217- return !empty();
218- }
219-
220- uint8_t i;
221- BillOfMaterials::const_iterator current;
222-
223-private:
224- BillOfMaterials::const_iterator const end;
225-};
226 } // namespace Widelands
227
228 #endif // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_BILL_OF_MATERIALS_H
229
230=== modified file 'src/logic/map_objects/tribes/building.cc'
231--- src/logic/map_objects/tribes/building.cc 2019-05-26 17:21:15 +0000
232+++ src/logic/map_objects/tribes/building.cc 2019-06-19 09:23:26 +0000
233@@ -638,13 +638,13 @@
234
235 int32_t
236 Building::get_priority(WareWorker type, DescriptionIndex const ware_index, bool adjust) const {
237- int32_t priority = DEFAULT_PRIORITY;
238+ int32_t priority = kPriorityNormal;
239 if (type == wwWARE) {
240 // if priority is defined for specific ware,
241 // combine base priority and ware priority
242 std::map<DescriptionIndex, int32_t>::const_iterator it = ware_priorities_.find(ware_index);
243 if (it != ware_priorities_.end())
244- priority = adjust ? (priority * it->second / DEFAULT_PRIORITY) : it->second;
245+ priority = adjust ? (priority * it->second / kPriorityNormal) : it->second;
246 }
247
248 return priority;
249@@ -660,7 +660,7 @@
250 std::map<DescriptionIndex, int32_t>& ware_priorities = p[wwWARE];
251 std::map<DescriptionIndex, int32_t>::const_iterator it;
252 for (it = ware_priorities_.begin(); it != ware_priorities_.end(); ++it) {
253- if (it->second == DEFAULT_PRIORITY)
254+ if (it->second == kPriorityNormal)
255 continue;
256 ware_priorities[it->first] = it->second;
257 }
258
259=== modified file 'src/logic/map_objects/tribes/building.h'
260--- src/logic/map_objects/tribes/building.h 2019-05-11 12:37:45 +0000
261+++ src/logic/map_objects/tribes/building.h 2019-06-19 09:23:26 +0000
262@@ -31,6 +31,7 @@
263 #include "logic/map_objects/buildcost.h"
264 #include "logic/map_objects/immovable.h"
265 #include "logic/map_objects/tribes/attack_target.h"
266+#include "logic/map_objects/tribes/building_settings.h"
267 #include "logic/map_objects/tribes/bill_of_materials.h"
268 #include "logic/map_objects/tribes/soldiercontrol.h"
269 #include "logic/map_objects/tribes/wareworker.h"
270@@ -51,9 +52,9 @@
271
272 class Building;
273
274-#define LOW_PRIORITY 2
275-#define DEFAULT_PRIORITY 4
276-#define HIGH_PRIORITY 8
277+constexpr int32_t kPriorityLow = 2;
278+constexpr int32_t kPriorityNormal = 4;
279+constexpr int32_t kPriorityHigh = 8;
280
281 /*
282 * Common to all buildings!
283@@ -266,8 +267,8 @@
284
285 // Get/Set the priority for this waretype for this building. 'type' defines
286 // if this is for a worker or a ware, 'index' is the type of worker or ware.
287- // If 'adjust' is false, the three possible states HIGH_PRIORITY,
288- // DEFAULT_PRIORITY and LOW_PRIORITY are returned, otherwise numerical
289+ // If 'adjust' is false, the three possible states kPriorityHigh,
290+ // kPriorityNormal and kPriorityLow are returned, otherwise numerical
291 // values adjusted to the preciousness of the ware in general are returned.
292 virtual int32_t get_priority(WareWorker type, DescriptionIndex, bool adjust = true) const;
293 void set_priority(int32_t type, DescriptionIndex ware_index, int32_t new_priority);
294@@ -301,6 +302,10 @@
295 void add_worker(Worker&) override;
296 void remove_worker(Worker&) override;
297
298+ virtual const BuildingSettings* create_building_settings() const {
299+ return nullptr;
300+ }
301+
302 // AttackTarget object associated with this building. If the building can
303 // never be attacked (for example productionsites) this will be nullptr.
304 const AttackTarget* attack_target() const {
305
306=== added file 'src/logic/map_objects/tribes/building_settings.cc'
307--- src/logic/map_objects/tribes/building_settings.cc 1970-01-01 00:00:00 +0000
308+++ src/logic/map_objects/tribes/building_settings.cc 2019-06-19 09:23:26 +0000
309@@ -0,0 +1,346 @@
310+/*
311+ * Copyright (C) 2002-2019 by the Widelands Development Team
312+ *
313+ * This program is free software; you can redistribute it and/or
314+ * modify it under the terms of the GNU General Public License
315+ * as published by the Free Software Foundation; either version 2
316+ * of the License, or (at your option) any later version.
317+ *
318+ * This program is distributed in the hope that it will be useful,
319+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
320+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
321+ * GNU General Public License for more details.
322+ *
323+ * You should have received a copy of the GNU General Public License
324+ * along with this program; if not, write to the Free Software
325+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
326+ *
327+ */
328+
329+#include "logic/map_objects/tribes/building_settings.h"
330+
331+#include "io/fileread.h"
332+#include "io/filewrite.h"
333+#include "logic/game.h"
334+#include "logic/game_data_error.h"
335+#include "logic/map_objects/tribes/militarysite.h"
336+#include "logic/map_objects/tribes/productionsite.h"
337+#include "logic/map_objects/tribes/trainingsite.h"
338+#include "logic/map_objects/tribes/tribe_descr.h"
339+#include "logic/map_objects/tribes/warehouse.h"
340+
341+namespace Widelands {
342+
343+ProductionsiteSettings::ProductionsiteSettings(const ProductionSiteDescr& descr)
344+ : BuildingSettings(descr.name()), stopped(false) {
345+ for (const auto& pair : descr.input_wares()) {
346+ ware_queues.push_back(std::make_pair(pair.first,
347+ InputQueueSetting{pair.second, pair.second, kPriorityNormal}));
348+ }
349+ for (const auto& pair : descr.input_workers()) {
350+ worker_queues.push_back(std::make_pair(pair.first,
351+ InputQueueSetting{pair.second, pair.second, kPriorityNormal}));
352+ }
353+}
354+
355+MilitarysiteSettings::MilitarysiteSettings(const MilitarySiteDescr& descr)
356+ : BuildingSettings(descr.name()),
357+ max_capacity(descr.get_max_number_of_soldiers()),
358+ desired_capacity(descr.get_max_number_of_soldiers()),
359+ prefer_heroes(descr.prefers_heroes_at_start_) {
360+}
361+
362+TrainingsiteSettings::TrainingsiteSettings(const TrainingSiteDescr& descr)
363+ : ProductionsiteSettings(descr),
364+ max_capacity(descr.get_max_number_of_soldiers()),
365+ desired_capacity(descr.get_max_number_of_soldiers()) {
366+}
367+
368+WarehouseSettings::WarehouseSettings(const WarehouseDescr& wh, const TribeDescr& tribe)
369+ : BuildingSettings(wh.name()), launch_expedition_allowed(wh.get_isport()), launch_expedition(false) {
370+ for (const DescriptionIndex di : tribe.wares()) {
371+ ware_preferences.emplace(di, StockPolicy::kNormal);
372+ }
373+ for (const DescriptionIndex di : tribe.workers()) {
374+ worker_preferences.emplace(di, StockPolicy::kNormal);
375+ }
376+ for (const DescriptionIndex di : tribe.worker_types_without_cost()) {
377+ worker_preferences.erase(di);
378+ }
379+}
380+
381+void ProductionsiteSettings::apply(const BuildingSettings& bs) {
382+ BuildingSettings::apply(bs);
383+ if (upcast(const ProductionsiteSettings, s, &bs)) {
384+ stopped = s->stopped;
385+ for (auto& pair : ware_queues) {
386+ for (const auto& other : s->ware_queues) {
387+ if (pair.first == other.first) {
388+ pair.second.priority = other.second.priority;
389+ pair.second.desired_fill = std::min(pair.second.max_fill, other.second.desired_fill);
390+ break;
391+ }
392+ }
393+ }
394+ for (auto& pair : worker_queues) {
395+ for (const auto& other : s->worker_queues) {
396+ if (pair.first == other.first) {
397+ pair.second.priority = other.second.priority;
398+ pair.second.desired_fill = std::min(pair.second.max_fill, other.second.desired_fill);
399+ break;
400+ }
401+ }
402+ }
403+ }
404+}
405+
406+void TrainingsiteSettings::apply(const BuildingSettings& bs) {
407+ ProductionsiteSettings::apply(bs);
408+ if (upcast(const TrainingsiteSettings, s, &bs)) {
409+ desired_capacity = std::min(max_capacity, s->desired_capacity);
410+ }
411+}
412+
413+void MilitarysiteSettings::apply(const BuildingSettings& bs) {
414+ BuildingSettings::apply(bs);
415+ if (upcast(const MilitarysiteSettings, s, &bs)) {
416+ desired_capacity = std::min(max_capacity, s->desired_capacity);
417+ prefer_heroes = s->prefer_heroes;
418+ }
419+}
420+
421+void WarehouseSettings::apply(const BuildingSettings& bs) {
422+ BuildingSettings::apply(bs);
423+ if (upcast(const WarehouseSettings, s, &bs)) {
424+ for (auto& pair : ware_preferences) {
425+ const auto it = s->ware_preferences.find(pair.first);
426+ if (it != s->ware_preferences.end()) {
427+ pair.second = it->second;
428+ }
429+ }
430+ for (auto& pair : worker_preferences) {
431+ const auto it = s->worker_preferences.find(pair.first);
432+ if (it != s->worker_preferences.end()) {
433+ pair.second = it->second;
434+ }
435+ }
436+ launch_expedition = launch_expedition_allowed && s->launch_expedition;
437+ }
438+}
439+
440+// Saveloading
441+
442+constexpr uint8_t kCurrentPacketVersion = 1;
443+constexpr uint8_t kCurrentPacketVersionMilitarysite = 1;
444+constexpr uint8_t kCurrentPacketVersionProductionsite = 1;
445+constexpr uint8_t kCurrentPacketVersionTrainingsite = 1;
446+constexpr uint8_t kCurrentPacketVersionWarehouse = 1;
447+
448+enum class BuildingType : uint8_t {
449+ kWarehouse = 1,
450+ kProductionsite = 2,
451+ kTrainingsite = 3,
452+ kMilitarysite = 4,
453+};
454+
455+// static
456+BuildingSettings* BuildingSettings::load(const Game& game, const TribeDescr& tribe, FileRead& fr) {
457+ try {
458+ const uint8_t packet_version = fr.unsigned_8();
459+ if (packet_version == kCurrentPacketVersion) {
460+ const std::string name(fr.c_string());
461+ const DescriptionIndex index = game.tribes().building_index(name);
462+ const BuildingType type = static_cast<BuildingType>(fr.unsigned_8());
463+ BuildingSettings* result = nullptr;
464+ switch (type) {
465+ case BuildingType::kTrainingsite: {
466+ result = new TrainingsiteSettings(*dynamic_cast<const TrainingSiteDescr*>(
467+ game.tribes().get_building_descr(index)));
468+ break;
469+ }
470+ case BuildingType::kProductionsite: {
471+ result = new ProductionsiteSettings(*dynamic_cast<const ProductionSiteDescr*>(
472+ game.tribes().get_building_descr(index)));
473+ break;
474+ }
475+ case BuildingType::kMilitarysite: {
476+ result = new MilitarysiteSettings(*dynamic_cast<const MilitarySiteDescr*>(
477+ game.tribes().get_building_descr(index)));
478+ break;
479+ }
480+ case BuildingType::kWarehouse: {
481+ result = new WarehouseSettings(*dynamic_cast<const WarehouseDescr*>(
482+ game.tribes().get_building_descr(index)), tribe);
483+ break;
484+ }
485+ }
486+ if (!result) {
487+ throw wexception("Unknown building category %u (%s)", static_cast<uint8_t>(type), name.c_str());
488+ }
489+ result->read(game, fr);
490+ return result;
491+ } else {
492+ throw UnhandledVersionError(
493+ "BuildingSettings_load", packet_version, kCurrentPacketVersion);
494+ }
495+ } catch (const WException& e) {
496+ throw GameDataError("BuildingSettings_load: %s", e.what());
497+ }
498+ NEVER_HERE();
499+}
500+
501+void BuildingSettings::read(const Game&, FileRead&) {
502+ // Header was peeled away by load()
503+}
504+
505+void BuildingSettings::save(const Game&, FileWrite& fw) const {
506+ fw.unsigned_8(kCurrentPacketVersion);
507+ fw.c_string(descr_.c_str());
508+}
509+
510+void MilitarysiteSettings::read(const Game& game, FileRead& fr) {
511+ BuildingSettings::read(game, fr);
512+ try {
513+ const uint8_t packet_version = fr.unsigned_8();
514+ if (packet_version == kCurrentPacketVersionMilitarysite) {
515+ desired_capacity = fr.unsigned_32();
516+ prefer_heroes = fr.unsigned_8();
517+ } else {
518+ throw UnhandledVersionError(
519+ "MilitarysiteSettings", packet_version, kCurrentPacketVersionMilitarysite);
520+ }
521+ } catch (const WException& e) {
522+ throw GameDataError("MilitarysiteSettings: %s", e.what());
523+ }
524+}
525+
526+void MilitarysiteSettings::save(const Game& game, FileWrite& fw) const {
527+ BuildingSettings::save(game, fw);
528+ fw.unsigned_8(static_cast<uint8_t>(BuildingType::kMilitarysite));
529+ fw.unsigned_8(kCurrentPacketVersionMilitarysite);
530+
531+ fw.unsigned_32(desired_capacity);
532+ fw.unsigned_8(prefer_heroes ? 1 : 0);
533+}
534+
535+void ProductionsiteSettings::read(const Game& game, FileRead& fr) {
536+ BuildingSettings::read(game, fr);
537+ try {
538+ const uint8_t packet_version = fr.unsigned_8();
539+ if (packet_version == kCurrentPacketVersionProductionsite) {
540+ stopped = fr.unsigned_8();
541+ const uint32_t nr_wares = fr.unsigned_32();
542+ const uint32_t nr_workers = fr.unsigned_32();
543+ for (uint32_t i = 0; i < nr_wares; ++i) {
544+ const DescriptionIndex di = fr.unsigned_32();
545+ const uint32_t fill = fr.unsigned_32();
546+ const int32_t priority = fr.signed_32();
547+ ware_queues.at(i).first = di;
548+ ware_queues.at(i).second.desired_fill = fill;
549+ ware_queues.at(i).second.priority = priority;
550+ }
551+ for (uint32_t i = 0; i < nr_workers; ++i) {
552+ const DescriptionIndex di = fr.unsigned_32();
553+ const uint32_t fill = fr.unsigned_32();
554+ const int32_t priority = fr.signed_32();
555+ worker_queues.at(i).first = di;
556+ worker_queues.at(i).second.desired_fill = fill;
557+ worker_queues.at(i).second.priority = priority;
558+ }
559+ } else {
560+ throw UnhandledVersionError(
561+ "ProductionsiteSettings", packet_version, kCurrentPacketVersionProductionsite);
562+ }
563+ } catch (const WException& e) {
564+ throw GameDataError("ProductionsiteSettings: %s", e.what());
565+ }
566+}
567+
568+void ProductionsiteSettings::save(const Game& game, FileWrite& fw) const {
569+ BuildingSettings::save(game, fw);
570+ fw.unsigned_8(static_cast<uint8_t>(BuildingType::kProductionsite));
571+ fw.unsigned_8(kCurrentPacketVersionProductionsite);
572+
573+ fw.unsigned_8(stopped ? 1 : 0);
574+ fw.unsigned_32(ware_queues.size());
575+ fw.unsigned_32(worker_queues.size());
576+ for (const auto& pair : ware_queues) {
577+ fw.unsigned_32(pair.first);
578+ fw.unsigned_32(pair.second.desired_fill);
579+ fw.signed_32(pair.second.priority);
580+ }
581+ for (const auto& pair : worker_queues) {
582+ fw.unsigned_32(pair.first);
583+ fw.unsigned_32(pair.second.desired_fill);
584+ fw.signed_32(pair.second.priority);
585+ }
586+}
587+
588+void TrainingsiteSettings::read(const Game& game, FileRead& fr) {
589+ ProductionsiteSettings::read(game, fr);
590+ try {
591+ const uint8_t packet_version = fr.unsigned_8();
592+ if (packet_version == kCurrentPacketVersionTrainingsite) {
593+ desired_capacity = fr.unsigned_32();
594+ } else {
595+ throw UnhandledVersionError(
596+ "TrainingsiteSettings", packet_version, kCurrentPacketVersionTrainingsite);
597+ }
598+ } catch (const WException& e) {
599+ throw GameDataError("TrainingsiteSettings: %s", e.what());
600+ }
601+}
602+
603+void TrainingsiteSettings::save(const Game& game, FileWrite& fw) const {
604+ ProductionsiteSettings::save(game, fw);
605+ fw.unsigned_8(static_cast<uint8_t>(BuildingType::kTrainingsite));
606+ fw.unsigned_8(kCurrentPacketVersionTrainingsite);
607+ fw.unsigned_32(desired_capacity);
608+}
609+
610+void WarehouseSettings::read(const Game& game, FileRead& fr) {
611+ BuildingSettings::read(game, fr);
612+ try {
613+ const uint8_t packet_version = fr.unsigned_8();
614+ if (packet_version == kCurrentPacketVersionWarehouse) {
615+ launch_expedition = fr.unsigned_8();
616+ const uint32_t nr_wares = fr.unsigned_32();
617+ const uint32_t nr_workers = fr.unsigned_32();
618+ for (uint32_t i = 0; i < nr_wares; ++i) {
619+ const DescriptionIndex di = fr.unsigned_32();
620+ const uint8_t pref = fr.unsigned_8();
621+ ware_preferences[di] = static_cast<StockPolicy>(pref);
622+ }
623+ for (uint32_t i = 0; i < nr_workers; ++i) {
624+ const DescriptionIndex di = fr.unsigned_32();
625+ const uint8_t pref = fr.unsigned_8();
626+ worker_preferences[di] = static_cast<StockPolicy>(pref);
627+ }
628+ } else {
629+ throw UnhandledVersionError(
630+ "WarehouseSettings", packet_version, kCurrentPacketVersionWarehouse);
631+ }
632+ } catch (const WException& e) {
633+ throw GameDataError("WarehouseSettings: %s", e.what());
634+ }
635+}
636+
637+void WarehouseSettings::save(const Game& game, FileWrite& fw) const {
638+ BuildingSettings::save(game, fw);
639+ fw.unsigned_8(static_cast<uint8_t>(BuildingType::kWarehouse));
640+ fw.unsigned_8(kCurrentPacketVersionWarehouse);
641+
642+ fw.unsigned_8(launch_expedition ? 1 : 0);
643+ fw.unsigned_32(ware_preferences.size());
644+ fw.unsigned_32(worker_preferences.size());
645+ for (const auto& pair : ware_preferences) {
646+ fw.unsigned_32(pair.first);
647+ fw.unsigned_8(static_cast<uint8_t>(pair.second));
648+ }
649+ for (const auto& pair : worker_preferences) {
650+ fw.unsigned_32(pair.first);
651+ fw.unsigned_8(static_cast<uint8_t>(pair.second));
652+ }
653+}
654+
655+} // namespace Widelands
656
657=== added file 'src/logic/map_objects/tribes/building_settings.h'
658--- src/logic/map_objects/tribes/building_settings.h 1970-01-01 00:00:00 +0000
659+++ src/logic/map_objects/tribes/building_settings.h 2019-06-19 09:23:26 +0000
660@@ -0,0 +1,123 @@
661+/*
662+ * Copyright (C) 2002-2019 by the Widelands Development Team
663+ *
664+ * This program is free software; you can redistribute it and/or
665+ * modify it under the terms of the GNU General Public License
666+ * as published by the Free Software Foundation; either version 2
667+ * of the License, or (at your option) any later version.
668+ *
669+ * This program is distributed in the hope that it will be useful,
670+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
671+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
672+ * GNU General Public License for more details.
673+ *
674+ * You should have received a copy of the GNU General Public License
675+ * along with this program; if not, write to the Free Software
676+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
677+ *
678+ */
679+
680+#ifndef WL_LOGIC_MAP_OBJECTS_TRIBES_BUILDING_SETTINGS_H
681+#define WL_LOGIC_MAP_OBJECTS_TRIBES_BUILDING_SETTINGS_H
682+
683+#include <map>
684+#include <string>
685+#include <vector>
686+
687+#include "logic/widelands.h"
688+
689+class FileRead;
690+class FileWrite;
691+
692+namespace Widelands {
693+
694+class Game;
695+class MilitarySiteDescr;
696+class ProductionSiteDescr;
697+enum class StockPolicy;
698+class TrainingSiteDescr;
699+class TribeDescr;
700+class WarehouseDescr;
701+
702+struct BuildingSettings {
703+ BuildingSettings(const std::string& name) : descr_(name) {
704+ }
705+ virtual ~BuildingSettings() {
706+ }
707+
708+ static BuildingSettings* load(const Game&, const TribeDescr&, FileRead&);
709+
710+ virtual void save(const Game&, FileWrite&) const;
711+ virtual void read(const Game&, FileRead&);
712+
713+ virtual void apply(const BuildingSettings&) {
714+ }
715+
716+private:
717+ const std::string descr_;
718+};
719+
720+struct ProductionsiteSettings : public BuildingSettings {
721+ ProductionsiteSettings(const ProductionSiteDescr& descr);
722+ ~ProductionsiteSettings() override {
723+ }
724+ void apply(const BuildingSettings&) override;
725+
726+ void save(const Game&, FileWrite&) const override;
727+ void read(const Game&, FileRead&) override;
728+
729+ struct InputQueueSetting {
730+ const uint32_t max_fill;
731+ uint32_t desired_fill;
732+ int32_t priority;
733+ };
734+ std::vector<std::pair<DescriptionIndex, InputQueueSetting>> ware_queues;
735+ std::vector<std::pair<DescriptionIndex, InputQueueSetting>> worker_queues;
736+ bool stopped;
737+};
738+
739+struct MilitarysiteSettings : public BuildingSettings {
740+ MilitarysiteSettings(const MilitarySiteDescr&);
741+ ~MilitarysiteSettings() override {
742+ }
743+ void apply(const BuildingSettings&) override;
744+
745+ void save(const Game&, FileWrite&) const override;
746+ void read(const Game&, FileRead&) override;
747+
748+ const uint32_t max_capacity;
749+ uint32_t desired_capacity;
750+ bool prefer_heroes;
751+};
752+
753+struct TrainingsiteSettings : public ProductionsiteSettings {
754+ TrainingsiteSettings(const TrainingSiteDescr&);
755+ ~TrainingsiteSettings() override {
756+ }
757+ void apply(const BuildingSettings&) override;
758+
759+ void save(const Game&, FileWrite&) const override;
760+ void read(const Game&, FileRead&) override;
761+
762+ const uint32_t max_capacity;
763+ uint32_t desired_capacity;
764+};
765+
766+struct WarehouseSettings : public BuildingSettings {
767+ WarehouseSettings(const WarehouseDescr&, const TribeDescr&);
768+ ~WarehouseSettings() override {
769+ }
770+ void apply(const BuildingSettings&) override;
771+
772+ void save(const Game&, FileWrite&) const override;
773+ void read(const Game&, FileRead&) override;
774+
775+ std::map<DescriptionIndex, StockPolicy> ware_preferences;
776+ std::map<DescriptionIndex, StockPolicy> worker_preferences;
777+ const bool launch_expedition_allowed;
778+ bool launch_expedition;
779+};
780+
781+} // namespace Widelands
782+
783+#endif // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_BUILDING_SETTINGS_H
784
785=== modified file 'src/logic/map_objects/tribes/constructionsite.cc'
786--- src/logic/map_objects/tribes/constructionsite.cc 2019-05-26 17:21:15 +0000
787+++ src/logic/map_objects/tribes/constructionsite.cc 2019-06-19 09:23:26 +0000
788@@ -32,6 +32,11 @@
789 #include "graphic/rendertarget.h"
790 #include "logic/editor_game_base.h"
791 #include "logic/game.h"
792+#include "logic/game_data_error.h"
793+#include "logic/map_objects/tribes/militarysite.h"
794+#include "logic/map_objects/tribes/partially_finished_building.h"
795+#include "logic/map_objects/tribes/productionsite.h"
796+#include "logic/map_objects/tribes/trainingsite.h"
797 #include "logic/map_objects/tribes/tribe_descr.h"
798 #include "logic/map_objects/tribes/worker.h"
799 #include "sound/note_sound.h"
800@@ -46,32 +51,61 @@
801 const RGBColor& player_color,
802 RenderTarget* dst) const {
803 // Draw the construction site marker
804- const uint32_t anim_idx = becomes->is_animation_known("build") ?
805- becomes->get_animation("build", nullptr) :
806- becomes->get_unoccupied_animation();
807-
808- const Animation& anim = g_gr->animations().get_animation(anim_idx);
809- const size_t nr_frames = anim.nr_frames();
810- const uint32_t cur_frame = totaltime ? completedtime * nr_frames / totaltime : 0;
811- uint32_t anim_time = cur_frame * FRAME_LENGTH;
812-
813- if (cur_frame) { // not the first pic
814- // Draw the complete prev pic , so we won't run into trouble if images have different sizes
815- dst->blit_animation(point_on_dst, Widelands::Coords::null(), scale, anim_idx,
816- anim_time - FRAME_LENGTH, &player_color);
817+ std::vector<std::pair<uint32_t, uint32_t>> animations;
818+ uint32_t total_frames = 0;
819+ auto push_animation = [](const BuildingDescr* d, std::vector<std::pair<uint32_t, uint32_t>>* anims, uint32_t* tf) {
820+ const bool known = d->is_animation_known("build");
821+ const uint32_t anim_idx = known ?
822+ d->get_animation("build", nullptr) :
823+ d->get_unoccupied_animation();
824+ // If there is no build animation, we use only the first frame or we
825+ // would get many build steps with almost the same image...
826+ const uint32_t nrframes = known ? g_gr->animations().get_animation(anim_idx).nr_frames() : 1;
827+ assert(nrframes);
828+ *tf += nrframes;
829+ anims->push_back(std::make_pair(anim_idx, nrframes));
830+ };
831+ for (const BuildingDescr* d : intermediates) {
832+ push_animation(d, &animations, &total_frames);
833+ }
834+ push_animation(becomes, &animations, &total_frames);
835+
836+ uint32_t frame_index = totaltime ? std::min(completedtime * total_frames / totaltime, total_frames - 1) : 0;
837+ uint32_t animation_index = 0;
838+ while (frame_index >= animations[animation_index].second) {
839+ frame_index -= animations[animation_index].second;
840+ ++animation_index;
841+ assert(animation_index < animations.size());
842+ }
843+ const uint32_t anim_time = frame_index * FRAME_LENGTH;
844+
845+ if (frame_index > 0) {
846+ // Not the first pic within this animation – draw the previous one
847+ dst->blit_animation(point_on_dst, Widelands::Coords::null(), scale,
848+ animations[animation_index].first, anim_time - FRAME_LENGTH, &player_color);
849+ } else if (animation_index > 0) {
850+ // The first pic, but not the first series of animations – draw the last pic of the previous series
851+ dst->blit_animation(point_on_dst, Widelands::Coords::null(), scale,
852+ animations[animation_index - 1].first,
853+ FRAME_LENGTH * (animations[animation_index - 1].second - 1), &player_color);
854 } else if (was) {
855- // Is the first picture but there was another building here before,
856- // get its most fitting picture and draw it instead.
857- dst->blit_animation(point_on_dst, Widelands::Coords::null(), scale,
858- was->get_unoccupied_animation(), anim_time - FRAME_LENGTH, &player_color);
859+ // First pic in first series, but there was another building here before –
860+ // get its most fitting picture and draw it instead
861+ const uint32_t unocc = was->get_unoccupied_animation();
862+ dst->blit_animation(point_on_dst, Widelands::Coords::null(), scale, unocc,
863+ FRAME_LENGTH * (g_gr->animations().get_animation(unocc).nr_frames() - 1),
864+ &player_color);
865 }
866 // Now blit a segment of the current construction phase from the bottom.
867- int percent = 100 * completedtime * nr_frames;
868+ int percent = 100 * completedtime * total_frames;
869 if (totaltime) {
870 percent /= totaltime;
871 }
872- percent -= 100 * cur_frame;
873- dst->blit_animation(point_on_dst, coords, scale, anim_idx, anim_time, &player_color, percent);
874+ percent -= 100 * frame_index;
875+ for (uint32_t i = 0; i < animation_index; ++i) {
876+ percent -= 100 * animations[i].second;
877+ }
878+ dst->blit_animation(point_on_dst, coords, scale, animations[animation_index].first, anim_time, &player_color, percent);
879 }
880
881 /**
882@@ -104,7 +138,7 @@
883 */
884
885 ConstructionSite::ConstructionSite(const ConstructionSiteDescr& cs_descr)
886- : PartiallyFinishedBuilding(cs_descr), fetchfromflag_(0), builder_idle_(false) {
887+ : PartiallyFinishedBuilding(cs_descr), fetchfromflag_(0), builder_idle_(false), settings_(nullptr) {
888 }
889
890 void ConstructionSite::update_statistics_string(std::string* s) {
891@@ -181,9 +215,30 @@
892
893 work_steps_ += it->second;
894 }
895+
896+ init_settings();
897+
898 return true;
899 }
900
901+void ConstructionSite::init_settings() {
902+ assert(building_);
903+ assert(!settings_);
904+ if (upcast(const WarehouseDescr, wd, building_)) {
905+ settings_.reset(new WarehouseSettings(*wd, owner().tribe()));
906+ } else if (upcast(const TrainingSiteDescr, td, building_)) {
907+ settings_.reset(new TrainingsiteSettings(*td));
908+ } else if (upcast(const ProductionSiteDescr, pd, building_)) {
909+ settings_.reset(new ProductionsiteSettings(*pd));
910+ } else if (upcast(const MilitarySiteDescr, md, building_)) {
911+ settings_.reset(new MilitarysiteSettings(*md));
912+ } else {
913+ // TODO(Nordfriese): Add support for markets when trading is implemented
914+ log("WARNING: Created constructionsite for a %s, which is not of any known building type\n",
915+ building_->name().c_str());
916+ }
917+}
918+
919 /*
920 ===============
921 Release worker and material (if any is left).
922@@ -207,6 +262,52 @@
923 builder->reset_tasks(dynamic_cast<Game&>(egbase));
924 builder->set_location(&b);
925 }
926+
927+ // Apply settings
928+ if (settings_) {
929+ if (upcast(ProductionsiteSettings, ps, settings_.get())) {
930+ for (const auto& pair : ps->ware_queues) {
931+ b.inputqueue(pair.first, wwWARE).set_max_fill(pair.second.desired_fill);
932+ b.set_priority(wwWARE, pair.first, pair.second.priority);
933+ }
934+ for (const auto& pair : ps->worker_queues) {
935+ b.inputqueue(pair.first, wwWORKER).set_max_fill(pair.second.desired_fill);
936+ b.set_priority(wwWORKER, pair.first, pair.second.priority);
937+ }
938+ if (upcast(TrainingsiteSettings, ts, ps)) {
939+ assert(b.soldier_control());
940+ assert(ts->desired_capacity >= b.soldier_control()->min_soldier_capacity());
941+ assert(ts->desired_capacity <= b.soldier_control()->max_soldier_capacity());
942+ if (ts->desired_capacity != b.soldier_control()->soldier_capacity()) {
943+ b.mutable_soldier_control()->set_soldier_capacity(ts->desired_capacity);
944+ }
945+ }
946+ dynamic_cast<ProductionSite&>(b).set_stopped(ps->stopped);
947+ } else if (upcast(MilitarysiteSettings, ms, settings_.get())) {
948+ assert(b.soldier_control());
949+ assert(ms->desired_capacity >= b.soldier_control()->min_soldier_capacity());
950+ assert(ms->desired_capacity <= b.soldier_control()->max_soldier_capacity());
951+ if (ms->desired_capacity != b.soldier_control()->soldier_capacity()) {
952+ b.mutable_soldier_control()->set_soldier_capacity(ms->desired_capacity);
953+ }
954+ dynamic_cast<MilitarySite&>(b).set_soldier_preference(ms->prefer_heroes ?
955+ SoldierPreference::kHeroes : SoldierPreference::kRookies);
956+ } else if (upcast(WarehouseSettings, ws, settings_.get())) {
957+ Warehouse& site = dynamic_cast<Warehouse&>(b);
958+ for (const auto& pair : ws->ware_preferences) {
959+ site.set_ware_policy(pair.first, pair.second);
960+ }
961+ for (const auto& pair : ws->worker_preferences) {
962+ site.set_worker_policy(pair.first, pair.second);
963+ }
964+ if (ws->launch_expedition) {
965+ get_owner()->start_or_cancel_expedition(site);
966+ }
967+ } else {
968+ NEVER_HERE();
969+ }
970+ }
971+
972 // Open the new building window if needed
973 Notifications::publish(NoteBuilding(b.serial(), NoteBuilding::Action::kFinishWarp));
974 }
975@@ -214,6 +315,138 @@
976
977 /*
978 ===============
979+Start building the next enhancement even before the base building is completed.
980+===============
981+*/
982+void ConstructionSite::enhance(Game&) {
983+ assert(building_->enhancement() != INVALID_INDEX);
984+ Notifications::publish(NoteImmovable(this, NoteImmovable::Ownership::LOST));
985+
986+ info_.intermediates.push_back(building_);
987+ old_buildings_.push_back(owner().tribe().building_index(building_->name()));
988+ building_ = owner().tribe().get_building_descr(building_->enhancement());
989+ assert(building_);
990+ info_.becomes = building_;
991+
992+ const std::map<DescriptionIndex, uint8_t>& buildcost = building_->enhancement_cost();
993+ std::set<DescriptionIndex> new_ware_types;
994+ for (const auto& pair : buildcost) {
995+ bool found = false;
996+ for (const auto& queue : wares_) {
997+ if (queue->get_index() == pair.first) {
998+ found = true;
999+ break;
1000+ }
1001+ }
1002+ if (!found) {
1003+ new_ware_types.insert(pair.first);
1004+ }
1005+ }
1006+
1007+ const size_t old_size = wares_.size();
1008+ wares_.resize(old_size + new_ware_types.size());
1009+
1010+ size_t new_index = 0;
1011+ for (const auto& pair : buildcost) {
1012+ if (new_ware_types.count(pair.first)) {
1013+ WaresQueue& wq = *(wares_[old_size + new_index] = new WaresQueue(*this, pair.first, pair.second));
1014+ wq.set_callback(ConstructionSite::wares_queue_callback, this);
1015+ wq.set_consume_interval(CONSTRUCTIONSITE_STEP_TIME);
1016+ ++new_index;
1017+ } else {
1018+ for (size_t i = 0; i < old_size; ++i) {
1019+ WaresQueue& wq = *wares_[i];
1020+ if (wq.get_index() == pair.first) {
1021+ wq.set_max_size(wq.get_max_size() + pair.second);
1022+ wq.set_max_fill(wq.get_max_fill() + pair.second);
1023+ break;
1024+ }
1025+ }
1026+ }
1027+ work_steps_ += pair.second;
1028+ }
1029+
1030+ BuildingSettings* old_settings = settings_.release();
1031+ if (upcast(const WarehouseDescr, wd, building_)) {
1032+ upcast(WarehouseSettings, ws, old_settings);
1033+ assert(ws);
1034+ WarehouseSettings* new_settings = new WarehouseSettings(*wd, owner().tribe());
1035+ settings_.reset(new_settings);
1036+ for (const auto& pair : ws->ware_preferences) {
1037+ new_settings->ware_preferences[pair.first] = pair.second;
1038+ }
1039+ for (const auto& pair : ws->worker_preferences) {
1040+ new_settings->worker_preferences[pair.first] = pair.second;
1041+ }
1042+ new_settings->launch_expedition = ws->launch_expedition && building_->get_isport();
1043+ } else if (upcast(const TrainingSiteDescr, td, building_)) {
1044+ upcast(TrainingsiteSettings, ts, old_settings);
1045+ assert(ts);
1046+ TrainingsiteSettings* new_settings = new TrainingsiteSettings(*td);
1047+ settings_.reset(new_settings);
1048+ new_settings->stopped = ts->stopped;
1049+ for (const auto& pair_old : ts->ware_queues) {
1050+ for (auto& pair_new : new_settings->ware_queues) {
1051+ if (pair_new.first == pair_old.first) {
1052+ pair_new.second.priority = pair_old.second.priority;
1053+ pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
1054+ break;
1055+ }
1056+ }
1057+ }
1058+ for (const auto& pair_old : ts->worker_queues) {
1059+ for (auto& pair_new : new_settings->worker_queues) {
1060+ if (pair_new.first == pair_old.first) {
1061+ pair_new.second.priority = pair_old.second.priority;
1062+ pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
1063+ break;
1064+ }
1065+ }
1066+ }
1067+ new_settings->desired_capacity = std::min(new_settings->max_capacity, ts->desired_capacity);
1068+ } else if (upcast(const ProductionSiteDescr, pd, building_)) {
1069+ upcast(ProductionsiteSettings, ps, old_settings);
1070+ assert(ps);
1071+ ProductionsiteSettings* new_settings = new ProductionsiteSettings(*pd);
1072+ settings_.reset(new_settings);
1073+ new_settings->stopped = ps->stopped;
1074+ for (const auto& pair_old : ps->ware_queues) {
1075+ for (auto& pair_new : new_settings->ware_queues) {
1076+ if (pair_new.first == pair_old.first) {
1077+ pair_new.second.priority = pair_old.second.priority;
1078+ pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
1079+ break;
1080+ }
1081+ }
1082+ }
1083+ for (const auto& pair_old : ps->worker_queues) {
1084+ for (auto& pair_new : new_settings->worker_queues) {
1085+ if (pair_new.first == pair_old.first) {
1086+ pair_new.second.priority = pair_old.second.priority;
1087+ pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
1088+ break;
1089+ }
1090+ }
1091+ }
1092+ } else if (upcast(const MilitarySiteDescr, md, building_)) {
1093+ upcast(MilitarysiteSettings, ms, old_settings);
1094+ assert(ms);
1095+ MilitarysiteSettings* new_settings = new MilitarysiteSettings(*md);
1096+ settings_.reset(new_settings);
1097+ new_settings->desired_capacity = std::max<uint32_t>(1, std::min<uint32_t>(
1098+ new_settings->max_capacity, ms->desired_capacity));
1099+ new_settings->prefer_heroes = ms->prefer_heroes;
1100+ } else {
1101+ // TODO(Nordfriese): Add support for markets when trading is implemented
1102+ log("WARNING: Enhanced constructionsite to a %s, which is not of any known building type\n",
1103+ building_->name().c_str());
1104+ }
1105+ Notifications::publish(NoteImmovable(this, NoteImmovable::Ownership::GAINED));
1106+ Notifications::publish(NoteBuilding(serial(), NoteBuilding::Action::kChanged));
1107+}
1108+
1109+/*
1110+===============
1111 Construction sites only burn if some of the work has been completed.
1112 ===============
1113 */
1114@@ -343,6 +576,17 @@
1115
1116 /*
1117 ===============
1118+Overwrite as many values of the current settings with those of the given settings as possible.
1119+===============
1120+*/
1121+void ConstructionSite::apply_settings(const BuildingSettings& cs) {
1122+ assert(settings_);
1123+ settings_->apply(cs);
1124+ delete &cs;
1125+}
1126+
1127+/*
1128+===============
1129 Draw the construction site.
1130 ===============
1131 */
1132
1133=== modified file 'src/logic/map_objects/tribes/constructionsite.h'
1134--- src/logic/map_objects/tribes/constructionsite.h 2019-05-05 14:05:07 +0000
1135+++ src/logic/map_objects/tribes/constructionsite.h 2019-06-19 09:23:26 +0000
1136@@ -20,16 +20,26 @@
1137 #ifndef WL_LOGIC_MAP_OBJECTS_TRIBES_CONSTRUCTIONSITE_H
1138 #define WL_LOGIC_MAP_OBJECTS_TRIBES_CONSTRUCTIONSITE_H
1139
1140+#include <memory>
1141 #include <vector>
1142
1143 #include "base/macros.h"
1144+#include "logic/map_objects/tribes/building_settings.h"
1145 #include "logic/map_objects/tribes/partially_finished_building.h"
1146 #include "scripting/lua_table.h"
1147
1148+class FileRead;
1149+class FileWrite;
1150+
1151 namespace Widelands {
1152
1153 class Building;
1154+class MilitarySiteDescr;
1155+class ProductionSiteDescr;
1156 class Request;
1157+enum class StockPolicy;
1158+class TrainingSiteDescr;
1159+class WarehouseDescr;
1160 class WaresQueue;
1161
1162 /// Per-player and per-field constructionsite information
1163@@ -47,6 +57,7 @@
1164 const BuildingDescr*
1165 becomes; // Also works as a marker telling whether there is a construction site.
1166 const BuildingDescr* was; // only valid if "becomes" is an enhanced building.
1167+ std::vector<const BuildingDescr*> intermediates; // If we enhance a building while it's still under construction
1168 uint32_t totaltime;
1169 uint32_t completedtime;
1170 };
1171@@ -114,6 +125,13 @@
1172 bool fetch_from_flag(Game&) override;
1173 bool get_building_work(Game&, Worker&, bool success) override;
1174
1175+ BuildingSettings* get_settings() const {
1176+ return settings_.get();
1177+ }
1178+ void apply_settings(const BuildingSettings&);
1179+
1180+ void enhance(Game&);
1181+
1182 protected:
1183 void update_statistics_string(std::string* statistics_string) override;
1184
1185@@ -135,6 +153,9 @@
1186
1187 bool builder_idle_; // used to determine whether the builder is idle
1188 ConstructionsiteInformation info_; // asked for by player point of view for the gameview
1189+
1190+ std::unique_ptr<BuildingSettings> settings_;
1191+ void init_settings();
1192 };
1193 } // namespace Widelands
1194
1195
1196=== modified file 'src/logic/map_objects/tribes/militarysite.cc'
1197--- src/logic/map_objects/tribes/militarysite.cc 2019-05-26 17:21:15 +0000
1198+++ src/logic/map_objects/tribes/militarysite.cc 2019-06-19 09:23:26 +0000
1199@@ -982,6 +982,13 @@
1200 return false;
1201 }
1202
1203+const BuildingSettings* MilitarySite::create_building_settings() const {
1204+ MilitarysiteSettings* settings = new MilitarysiteSettings(descr());
1205+ settings->desired_capacity = std::min(settings->max_capacity, soldier_control_.soldier_capacity());
1206+ settings->prefer_heroes = soldier_preference_ == SoldierPreference::kHeroes;
1207+ return settings;
1208+}
1209+
1210 // setters
1211
1212 void MilitarySite::set_soldier_preference(SoldierPreference p) {
1213
1214=== modified file 'src/logic/map_objects/tribes/militarysite.h'
1215--- src/logic/map_objects/tribes/militarysite.h 2019-05-05 14:05:07 +0000
1216+++ src/logic/map_objects/tribes/militarysite.h 2019-06-19 09:23:26 +0000
1217@@ -108,6 +108,8 @@
1218 return soldier_preference_;
1219 }
1220
1221+ const BuildingSettings* create_building_settings() const override;
1222+
1223 protected:
1224 void conquer_area(EditorGameBase&);
1225
1226
1227=== modified file 'src/logic/map_objects/tribes/productionsite.cc'
1228--- src/logic/map_objects/tribes/productionsite.cc 2019-05-29 07:14:00 +0000
1229+++ src/logic/map_objects/tribes/productionsite.cc 2019-06-19 09:23:26 +0000
1230@@ -445,13 +445,12 @@
1231 const BillOfMaterials& input_workers = descr().input_workers();
1232 input_queues_.resize(input_wares.size() + input_workers.size());
1233
1234- for (WareRange i(input_wares); i; ++i) {
1235- input_queues_[i.i] = new WaresQueue(*this, i.current->first, i.current->second);
1236+ size_t i = 0;
1237+ for (const WareAmount& pair : input_wares) {
1238+ input_queues_[i++] = new WaresQueue(*this, pair.first, pair.second);
1239 }
1240-
1241- for (WareRange i(input_workers); i; ++i) {
1242- input_queues_[input_wares.size() + i.i] =
1243- new WorkersQueue(*this, i.current->first, i.current->second);
1244+ for (const WareAmount& pair : input_workers) {
1245+ input_queues_[i++] = new WorkersQueue(*this, pair.first, pair.second);
1246 }
1247
1248 // Request missing workers.
1249@@ -1020,6 +1019,30 @@
1250 set_production_result("");
1251 }
1252
1253+const BuildingSettings* ProductionSite::create_building_settings() const {
1254+ ProductionsiteSettings* settings = new ProductionsiteSettings(descr());
1255+ settings->stopped = is_stopped_;
1256+ for (auto& pair : settings->ware_queues) {
1257+ pair.second.priority = get_priority(wwWARE, pair.first, false);
1258+ for (const auto& queue : input_queues_) {
1259+ if (queue->get_type() == wwWARE && queue->get_index() == pair.first) {
1260+ pair.second.desired_fill = std::min(pair.second.max_fill, queue->get_max_fill());
1261+ break;
1262+ }
1263+ }
1264+ }
1265+ for (auto& pair : settings->worker_queues) {
1266+ pair.second.priority = get_priority(wwWORKER, pair.first, false);
1267+ for (const auto& queue : input_queues_) {
1268+ if (queue->get_type() == wwWORKER && queue->get_index() == pair.first) {
1269+ pair.second.desired_fill = std::min(pair.second.max_fill, queue->get_max_fill());
1270+ break;
1271+ }
1272+ }
1273+ }
1274+ return settings;
1275+}
1276+
1277 /// Changes the default anim string to \li anim
1278 void ProductionSite::set_default_anim(std::string anim) {
1279 if (default_anim_ == anim)
1280
1281=== modified file 'src/logic/map_objects/tribes/productionsite.h'
1282--- src/logic/map_objects/tribes/productionsite.h 2019-05-28 21:04:36 +0000
1283+++ src/logic/map_objects/tribes/productionsite.h 2019-06-19 09:23:26 +0000
1284@@ -241,6 +241,8 @@
1285
1286 void set_default_anim(std::string);
1287
1288+ const BuildingSettings* create_building_settings() const override;
1289+
1290 protected:
1291 void update_statistics_string(std::string* statistics) override;
1292
1293
1294=== modified file 'src/logic/map_objects/tribes/trainingsite.cc'
1295--- src/logic/map_objects/tribes/trainingsite.cc 2019-05-05 14:05:07 +0000
1296+++ src/logic/map_objects/tribes/trainingsite.cc 2019-06-19 09:23:26 +0000
1297@@ -525,6 +525,13 @@
1298 }
1299 }
1300
1301+const BuildingSettings* TrainingSite::create_building_settings() const {
1302+ TrainingsiteSettings* settings = new TrainingsiteSettings(descr());
1303+ settings->apply(*ProductionSite::create_building_settings());
1304+ settings->desired_capacity = std::min(settings->max_capacity, soldier_control_.soldier_capacity());
1305+ return settings;
1306+}
1307+
1308 /**
1309 * In addition to advancing the program, update soldier status.
1310 */
1311
1312=== modified file 'src/logic/map_objects/tribes/trainingsite.h'
1313--- src/logic/map_objects/tribes/trainingsite.h 2019-05-05 14:05:07 +0000
1314+++ src/logic/map_objects/tribes/trainingsite.h 2019-06-19 09:23:26 +0000
1315@@ -199,6 +199,8 @@
1316 void training_successful(TrainingAttribute type, uint32_t level);
1317 void training_done();
1318
1319+ const BuildingSettings* create_building_settings() const override;
1320+
1321 protected:
1322 void program_end(Game&, ProgramResult) override;
1323
1324
1325=== modified file 'src/logic/map_objects/tribes/warehouse.cc'
1326--- src/logic/map_objects/tribes/warehouse.cc 2019-03-01 04:19:53 +0000
1327+++ src/logic/map_objects/tribes/warehouse.cc 2019-06-19 09:23:26 +0000
1328@@ -1275,17 +1275,17 @@
1329 }
1330 }
1331
1332-Warehouse::StockPolicy Warehouse::get_ware_policy(DescriptionIndex ware) const {
1333+StockPolicy Warehouse::get_ware_policy(DescriptionIndex ware) const {
1334 assert(ware < static_cast<DescriptionIndex>(ware_policy_.size()));
1335 return ware_policy_[ware];
1336 }
1337
1338-Warehouse::StockPolicy Warehouse::get_worker_policy(DescriptionIndex ware) const {
1339+StockPolicy Warehouse::get_worker_policy(DescriptionIndex ware) const {
1340 assert(ware < static_cast<DescriptionIndex>(worker_policy_.size()));
1341 return worker_policy_[ware];
1342 }
1343
1344-Warehouse::StockPolicy Warehouse::get_stock_policy(WareWorker waretype,
1345+StockPolicy Warehouse::get_stock_policy(WareWorker waretype,
1346 DescriptionIndex wareindex) const {
1347 if (waretype == wwWORKER)
1348 return get_worker_policy(wareindex);
1349@@ -1293,25 +1293,25 @@
1350 return get_ware_policy(wareindex);
1351 }
1352
1353-void Warehouse::set_ware_policy(DescriptionIndex ware, Warehouse::StockPolicy policy) {
1354+void Warehouse::set_ware_policy(DescriptionIndex ware, StockPolicy policy) {
1355 assert(ware < static_cast<DescriptionIndex>(ware_policy_.size()));
1356 ware_policy_[ware] = policy;
1357 }
1358
1359-void Warehouse::set_worker_policy(DescriptionIndex ware, Warehouse::StockPolicy policy) {
1360+void Warehouse::set_worker_policy(DescriptionIndex ware, StockPolicy policy) {
1361 assert(ware < static_cast<DescriptionIndex>(worker_policy_.size()));
1362 worker_policy_[ware] = policy;
1363 }
1364
1365 /**
1366- * Check if there are remaining wares with \ref Warehouse::StockPolicy::kRemove,
1367+ * Check if there are remaining wares with \ref StockPolicy::kRemove,
1368 * and remove one of them if appropriate.
1369 */
1370 void Warehouse::check_remove_stock(Game& game) {
1371 if (base_flag().current_wares() < base_flag().total_capacity() / 2) {
1372 for (DescriptionIndex ware = 0; ware < static_cast<DescriptionIndex>(ware_policy_.size());
1373 ++ware) {
1374- if (get_ware_policy(ware) != Warehouse::StockPolicy::kRemove || !get_wares().stock(ware))
1375+ if (get_ware_policy(ware) != StockPolicy::kRemove || !get_wares().stock(ware))
1376 continue;
1377
1378 launch_ware(game, ware);
1379@@ -1321,7 +1321,7 @@
1380
1381 for (DescriptionIndex widx = 0; widx < static_cast<DescriptionIndex>(worker_policy_.size());
1382 ++widx) {
1383- if (get_worker_policy(widx) != Warehouse::StockPolicy::kRemove || !get_workers().stock(widx))
1384+ if (get_worker_policy(widx) != StockPolicy::kRemove || !get_workers().stock(widx))
1385 continue;
1386
1387 Worker& worker = launch_worker(game, widx, Requirements());
1388@@ -1337,6 +1337,18 @@
1389 return portdock_->expedition_bootstrap()->inputqueue(index, type);
1390 }
1391
1392+const BuildingSettings* Warehouse::create_building_settings() const {
1393+ WarehouseSettings* settings = new WarehouseSettings(descr(), owner().tribe());
1394+ for (auto& pair : settings->ware_preferences) {
1395+ pair.second = get_ware_policy(pair.first);
1396+ }
1397+ for (auto& pair : settings->worker_preferences) {
1398+ pair.second = get_worker_policy(pair.first);
1399+ }
1400+ settings->launch_expedition = portdock_ && portdock_->expedition_started();
1401+ return settings;
1402+}
1403+
1404 void Warehouse::log_general_info(const EditorGameBase& egbase) const {
1405 Building::log_general_info(egbase);
1406
1407
1408=== modified file 'src/logic/map_objects/tribes/warehouse.h'
1409--- src/logic/map_objects/tribes/warehouse.h 2019-05-05 14:05:07 +0000
1410+++ src/logic/map_objects/tribes/warehouse.h 2019-06-19 09:23:26 +0000
1411@@ -68,6 +68,40 @@
1412 DISALLOW_COPY_AND_ASSIGN(WarehouseDescr);
1413 };
1414
1415+/**
1416+ * Each ware and worker type has an associated per-warehouse
1417+ * stock policy that defines whether it will be stocked by this
1418+ * warehouse.
1419+ *
1420+ * \note The values of this enum are written directly into savegames,
1421+ * so be careful when changing them.
1422+ */
1423+enum class StockPolicy {
1424+ /**
1425+ * The default policy allows stocking wares without any special priority.
1426+ */
1427+ kNormal = 0,
1428+
1429+ /**
1430+ * As long as there are warehouses with this policy for a ware, all
1431+ * available unstocked supplies will be transferred to warehouses
1432+ * with this policy.
1433+ */
1434+ kPrefer = 1,
1435+
1436+ /**
1437+ * If a ware has this stock policy, no more of this ware will enter
1438+ * the warehouse.
1439+ */
1440+ kDontStock = 2,
1441+
1442+ /**
1443+ * Like \ref kDontStock, but in addition, existing stock of this ware
1444+ * will be transported out of the warehouse over time.
1445+ */
1446+ kRemove = 3,
1447+};
1448+
1449 class Warehouse : public Building {
1450 friend class PortDock;
1451 friend class MapBuildingdataPacket;
1452@@ -75,39 +109,6 @@
1453 MO_DESCR(WarehouseDescr)
1454
1455 public:
1456- /**
1457- * Each ware and worker type has an associated per-warehouse
1458- * stock policy that defines whether it will be stocked by this
1459- * warehouse.
1460- *
1461- * \note The values of this enum are written directly into savegames,
1462- * so be careful when changing them.
1463- */
1464- enum class StockPolicy {
1465- /**
1466- * The default policy allows stocking wares without any special priority.
1467- */
1468- kNormal = 0,
1469-
1470- /**
1471- * As long as there are warehouses with this policy for a ware, all
1472- * available unstocked supplies will be transferred to warehouses
1473- * with this policy.
1474- */
1475- kPrefer = 1,
1476-
1477- /**
1478- * If a ware has this stock policy, no more of this ware will enter
1479- * the warehouse.
1480- */
1481- kDontStock = 2,
1482-
1483- /**
1484- * Like \ref kDontStock, but in addition, existing stock of this ware
1485- * will be transported out of the warehouse over time.
1486- */
1487- kRemove = 3,
1488- };
1489
1490 /**
1491 * Whether worker indices in count_workers() have to match exactly.
1492@@ -208,6 +209,8 @@
1493 return portdock_;
1494 }
1495
1496+ const BuildingSettings* create_building_settings() const override;
1497+
1498 // Returns the waresqueue of the expedition if this is a port.
1499 // Will throw an exception otherwise.
1500 InputQueue& inputqueue(DescriptionIndex, WareWorker) override;
1501
1502=== modified file 'src/logic/player.cc'
1503--- src/logic/player.cc 2019-05-26 05:58:14 +0000
1504+++ src/logic/player.cc 2019-06-19 09:23:26 +0000
1505@@ -760,6 +760,7 @@
1506 } else {
1507 workers = building->get_workers();
1508 }
1509+ const BuildingSettings* settings = building->create_building_settings();
1510
1511 if (index_of_new_building != INVALID_INDEX) {
1512 // For enhancing, register whether the window was open
1513@@ -770,7 +771,7 @@
1514 // pointer.
1515 if (index_of_new_building != INVALID_INDEX)
1516 building = &egbase().warp_constructionsite(
1517- position, player_number_, index_of_new_building, false, former_buildings);
1518+ position, player_number_, index_of_new_building, false, former_buildings, settings);
1519 else
1520 building = &egbase().warp_dismantlesite(position, player_number_, false, former_buildings);
1521
1522
1523=== modified file 'src/logic/playercommand.cc'
1524--- src/logic/playercommand.cc 2019-05-25 10:54:30 +0000
1525+++ src/logic/playercommand.cc 2019-06-19 09:23:26 +0000
1526@@ -486,8 +486,14 @@
1527 }
1528
1529 void CmdStartStopBuilding::execute(Game& game) {
1530- if (upcast(Building, building, game.objects().get_object(serial)))
1531+ MapObject* mo = game.objects().get_object(serial);
1532+ if (upcast(ConstructionSite, cs, mo)) {
1533+ if (upcast(ProductionsiteSettings, s, cs->get_settings())) {
1534+ s->stopped = !s->stopped;
1535+ }
1536+ } else if (upcast(Building, building, mo)) {
1537 game.get_player(sender())->start_stop_building(*building);
1538+ }
1539 }
1540
1541 void CmdStartStopBuilding::serialize(StreamWrite& ser) {
1542@@ -536,8 +542,14 @@
1543 }
1544
1545 void CmdMilitarySiteSetSoldierPreference::execute(Game& game) {
1546- if (upcast(MilitarySite, building, game.objects().get_object(serial)))
1547+ MapObject* mo = game.objects().get_object(serial);
1548+ if (upcast(ConstructionSite, cs, mo)) {
1549+ if (upcast(MilitarysiteSettings, s, cs->get_settings())) {
1550+ s->prefer_heroes = preference == SoldierPreference::kHeroes;
1551+ }
1552+ } else if (upcast(MilitarySite, building, mo)) {
1553 game.get_player(sender())->military_site_set_soldier_preference(*building, preference);
1554+ }
1555 }
1556
1557 constexpr uint16_t kCurrentPacketVersionSoldierPreference = 1;
1558@@ -582,8 +594,14 @@
1559 }
1560
1561 void CmdStartOrCancelExpedition::execute(Game& game) {
1562- if (upcast(Warehouse, warehouse, game.objects().get_object(serial)))
1563+ MapObject* mo = game.objects().get_object(serial);
1564+ if (upcast(ConstructionSite, cs, mo)) {
1565+ if (upcast(WarehouseSettings, s, cs->get_settings())) {
1566+ s->launch_expedition = !s->launch_expedition;
1567+ }
1568+ } else if (upcast(Warehouse, warehouse, game.objects().get_object(serial))) {
1569 game.get_player(sender())->start_or_cancel_expedition(*warehouse);
1570+ }
1571 }
1572
1573 void CmdStartOrCancelExpedition::serialize(StreamWrite& ser) {
1574@@ -626,8 +644,12 @@
1575 }
1576
1577 void CmdEnhanceBuilding::execute(Game& game) {
1578- if (upcast(Building, building, game.objects().get_object(serial)))
1579+ MapObject* mo = game.objects().get_object(serial);
1580+ if (upcast(ConstructionSite, cs, mo)) {
1581+ cs->enhance(game);
1582+ } else if (upcast(Building, building, mo)) {
1583 game.get_player(sender())->enhance_building(building, bi);
1584+ }
1585 }
1586
1587 void CmdEnhanceBuilding::serialize(StreamWrite& ser) {
1588@@ -1036,14 +1058,22 @@
1589 }
1590
1591 void CmdSetWarePriority::execute(Game& game) {
1592- upcast(Building, psite, game.objects().get_object(serial_));
1593-
1594- if (!psite)
1595- return;
1596- if (psite->owner().player_number() != sender())
1597- return;
1598-
1599- psite->set_priority(type_, index_, priority_);
1600+ MapObject* mo = game.objects().get_object(serial_);
1601+ if (upcast(ConstructionSite, cs, mo)) {
1602+ if (upcast(ProductionsiteSettings, s, cs->get_settings())) {
1603+ for (auto& pair : s->ware_queues) {
1604+ if (pair.first == index_) {
1605+ pair.second.priority = priority_;
1606+ return;
1607+ }
1608+ }
1609+ NEVER_HERE();
1610+ }
1611+ } else if (upcast(Building, psite, mo)) {
1612+ if (psite->owner().player_number() == sender()) {
1613+ psite->set_priority(type_, index_, priority_);
1614+ }
1615+ }
1616 }
1617
1618 constexpr uint16_t kCurrentPacketVersionCmdSetWarePriority = 1;
1619@@ -1110,14 +1140,36 @@
1620 }
1621
1622 void CmdSetInputMaxFill::execute(Game& game) {
1623- upcast(Building, b, game.objects().get_object(serial_));
1624-
1625- if (!b)
1626- return;
1627- if (b->owner().player_number() != sender())
1628- return;
1629-
1630- b->inputqueue(index_, type_).set_max_fill(max_fill_);
1631+ MapObject* mo = game.objects().get_object(serial_);
1632+ if (upcast(ConstructionSite, cs, mo)) {
1633+ if (upcast(ProductionsiteSettings, s, cs->get_settings())) {
1634+ switch (type_) {
1635+ case wwWARE:
1636+ for (auto& pair : s->ware_queues) {
1637+ if (pair.first == index_) {
1638+ assert(pair.second.max_fill >= max_fill_);
1639+ pair.second.desired_fill = max_fill_;
1640+ return;
1641+ }
1642+ }
1643+ NEVER_HERE();
1644+ case wwWORKER:
1645+ for (auto& pair : s->worker_queues) {
1646+ if (pair.first == index_) {
1647+ assert(pair.second.max_fill >= max_fill_);
1648+ pair.second.desired_fill = max_fill_;
1649+ return;
1650+ }
1651+ }
1652+ NEVER_HERE();
1653+ }
1654+ NEVER_HERE();
1655+ }
1656+ } else if (upcast(Building, b, mo)) {
1657+ if (b->owner().player_number() == sender()) {
1658+ b->inputqueue(index_, type_).set_max_fill(max_fill_);
1659+ }
1660+ }
1661 }
1662
1663 constexpr uint16_t kCurrentPacketVersionCmdSetInputMaxFill = 2;
1664@@ -1528,7 +1580,18 @@
1665 }
1666
1667 void CmdChangeSoldierCapacity::execute(Game& game) {
1668- if (upcast(Building, building, game.objects().get_object(serial))) {
1669+ MapObject* mo = game.objects().get_object(serial);
1670+ if (upcast(ConstructionSite, cs, mo)) {
1671+ assert(val >= 0);
1672+ uint32_t capacity = static_cast<uint32_t>(val);
1673+ if (upcast(MilitarysiteSettings, ms, cs->get_settings())) {
1674+ assert(ms->max_capacity >= capacity);
1675+ ms->desired_capacity = capacity;
1676+ } else if (upcast(TrainingsiteSettings, ts, cs->get_settings())) {
1677+ assert(ts->max_capacity >= capacity);
1678+ ts->desired_capacity = capacity;
1679+ }
1680+ } else if (upcast(Building, building, mo)) {
1681 if (building->get_owner() == game.get_player(sender()) &&
1682 building->soldier_control() != nullptr) {
1683 SoldierControl* soldier_control = building->mutable_soldier_control();
1684@@ -1750,10 +1813,10 @@
1685 /*** struct Cmd_SetStockPolicy ***/
1686 CmdSetStockPolicy::CmdSetStockPolicy(uint32_t time,
1687 PlayerNumber p,
1688- Warehouse& wh,
1689+ Building& wh,
1690 bool isworker,
1691 DescriptionIndex ware,
1692- Warehouse::StockPolicy policy)
1693+ StockPolicy policy)
1694 : PlayerCommand(time, p) {
1695 warehouse_ = wh.serial();
1696 isworker_ = isworker;
1697@@ -1768,7 +1831,16 @@
1698 void CmdSetStockPolicy::execute(Game& game) {
1699 // Sanitize data that could have come from the network
1700 if (Player* plr = game.get_player(sender())) {
1701- if (upcast(Warehouse, warehouse, game.objects().get_object(warehouse_))) {
1702+ MapObject* mo = game.objects().get_object(warehouse_);
1703+ if (upcast(ConstructionSite, cs, mo)) {
1704+ if (upcast(WarehouseSettings, s, cs->get_settings())) {
1705+ if (isworker_) {
1706+ s->worker_preferences[ware_] = policy_;
1707+ } else {
1708+ s->ware_preferences[ware_] = policy_;
1709+ }
1710+ }
1711+ } else if (upcast(Warehouse, warehouse, mo)) {
1712 if (warehouse->get_owner() != plr) {
1713 log("Cmd_SetStockPolicy: sender %u, but warehouse owner %u\n", sender(),
1714 warehouse->owner().player_number());
1715@@ -1796,7 +1868,7 @@
1716 warehouse_ = des.unsigned_32();
1717 isworker_ = des.unsigned_8();
1718 ware_ = DescriptionIndex(des.unsigned_8());
1719- policy_ = static_cast<Warehouse::StockPolicy>(des.unsigned_8());
1720+ policy_ = static_cast<StockPolicy>(des.unsigned_8());
1721 }
1722
1723 void CmdSetStockPolicy::serialize(StreamWrite& ser) {
1724@@ -1818,7 +1890,7 @@
1725 warehouse_ = fr.unsigned_32();
1726 isworker_ = fr.unsigned_8();
1727 ware_ = DescriptionIndex(fr.unsigned_8());
1728- policy_ = static_cast<Warehouse::StockPolicy>(fr.unsigned_8());
1729+ policy_ = static_cast<StockPolicy>(fr.unsigned_8());
1730 } else {
1731 throw UnhandledVersionError(
1732 "CmdSetStockPolicy", packet_version, kCurrentPacketVersionCmdSetStockPolicy);
1733@@ -1906,4 +1978,5 @@
1734 // TODO(sirver,trading): Implement this.
1735 NEVER_HERE();
1736 }
1737+
1738 } // namespace Widelands
1739
1740=== modified file 'src/logic/playercommand.h'
1741--- src/logic/playercommand.h 2019-05-29 16:59:16 +0000
1742+++ src/logic/playercommand.h 2019-06-19 09:23:26 +0000
1743@@ -24,6 +24,7 @@
1744
1745 #include "economy/flag.h"
1746 #include "logic/cmd_queue.h"
1747+#include "logic/map_objects/tribes/constructionsite.h"
1748 #include "logic/map_objects/tribes/militarysite.h"
1749 #include "logic/map_objects/tribes/ship.h"
1750 #include "logic/map_objects/tribes/trainingsite.h"
1751@@ -824,10 +825,10 @@
1752 struct CmdSetStockPolicy : PlayerCommand {
1753 CmdSetStockPolicy(uint32_t time,
1754 PlayerNumber p,
1755- Warehouse& wh,
1756+ Building& wh,
1757 bool isworker,
1758 DescriptionIndex ware,
1759- Warehouse::StockPolicy policy);
1760+ StockPolicy policy);
1761
1762 QueueCommandTypes id() const override {
1763 return QueueCommandTypes::kSetStockPolicy;
1764@@ -848,7 +849,7 @@
1765 Serial warehouse_;
1766 bool isworker_;
1767 DescriptionIndex ware_;
1768- Warehouse::StockPolicy policy_;
1769+ StockPolicy policy_;
1770 };
1771
1772 struct CmdProposeTrade : PlayerCommand {
1773@@ -872,6 +873,7 @@
1774 private:
1775 Trade trade_;
1776 };
1777+
1778 } // namespace Widelands
1779
1780 #endif // end of include guard: WL_LOGIC_PLAYERCOMMAND_H
1781
1782=== modified file 'src/map_io/map_buildingdata_packet.cc'
1783--- src/map_io/map_buildingdata_packet.cc 2019-06-13 17:32:28 +0000
1784+++ src/map_io/map_buildingdata_packet.cc 2019-06-19 09:23:26 +0000
1785@@ -60,7 +60,7 @@
1786
1787 // Building type package versions
1788 constexpr uint16_t kCurrentPacketVersionDismantlesite = 1;
1789-constexpr uint16_t kCurrentPacketVersionConstructionsite = 3;
1790+constexpr uint16_t kCurrentPacketVersionConstructionsite = 4;
1791 constexpr uint16_t kCurrentPacketPFBuilding = 1;
1792 // Responsible for warehouses and expedition bootstraps
1793 constexpr uint16_t kCurrentPacketVersionWarehouse = 7;
1794@@ -274,7 +274,7 @@
1795 const TribesLegacyLookupTable& tribes_lookup_table) {
1796 try {
1797 uint16_t const packet_version = fr.unsigned_16();
1798- if (packet_version >= kCurrentPacketVersionConstructionsite) {
1799+ if (packet_version >= 3) {
1800 read_partially_finished_building(constructionsite, fr, game, mol, tribes_lookup_table);
1801
1802 for (ConstructionSite::Wares::iterator wares_iter = constructionsite.wares_.begin();
1803@@ -284,6 +284,18 @@
1804 }
1805
1806 constructionsite.fetchfromflag_ = fr.signed_32();
1807+
1808+ if (packet_version >= 4) {
1809+ const uint32_t intermediates = fr.unsigned_32();
1810+ for (uint32_t i = 0; i < intermediates; ++i) {
1811+ constructionsite.info_.intermediates.push_back(game.tribes().get_building_descr(
1812+ game.tribes().building_index(fr.c_string())));
1813+ }
1814+ constructionsite.settings_.reset(BuildingSettings::load(game,
1815+ constructionsite.owner().tribe(), fr));
1816+ } else {
1817+ constructionsite.init_settings();
1818+ }
1819 } else {
1820 throw UnhandledVersionError("MapBuildingdataPacket - Constructionsite", packet_version,
1821 kCurrentPacketVersionConstructionsite);
1822@@ -329,7 +341,7 @@
1823 const DescriptionIndex& id =
1824 tribe.ware_index(tribes_lookup_table.lookup_ware(fr.c_string()));
1825 Quantity amount = fr.unsigned_32();
1826- Warehouse::StockPolicy policy = static_cast<Warehouse::StockPolicy>(fr.unsigned_8());
1827+ StockPolicy policy = static_cast<StockPolicy>(fr.unsigned_8());
1828
1829 if (game.tribes().ware_exists(id)) {
1830 warehouse.insert_wares(id, amount);
1831@@ -340,7 +352,7 @@
1832 const DescriptionIndex& id =
1833 tribe.worker_index(tribes_lookup_table.lookup_worker(fr.c_string()));
1834 uint32_t amount = fr.unsigned_32();
1835- Warehouse::StockPolicy policy = static_cast<Warehouse::StockPolicy>(fr.unsigned_8());
1836+ StockPolicy policy = static_cast<StockPolicy>(fr.unsigned_8());
1837
1838 if (game.tribes().worker_exists(id)) {
1839 warehouse.insert_workers(id, amount);
1840@@ -978,6 +990,14 @@
1841 write_partially_finished_building(constructionsite, fw, game, mos);
1842
1843 fw.signed_32(constructionsite.fetchfromflag_);
1844+
1845+ fw.unsigned_32(constructionsite.info_.intermediates.size());
1846+ for (const BuildingDescr* d : constructionsite.info_.intermediates) {
1847+ fw.c_string(d->name().c_str());
1848+ }
1849+
1850+ assert(constructionsite.settings_);
1851+ constructionsite.settings_->save(game, fw);
1852 }
1853
1854 void MapBuildingdataPacket::write_dismantlesite(const DismantleSite& dms,
1855
1856=== modified file 'src/notifications/note_ids.h'
1857--- src/notifications/note_ids.h 2019-05-10 17:43:19 +0000
1858+++ src/notifications/note_ids.h 2019-06-19 09:23:26 +0000
1859@@ -29,6 +29,7 @@
1860 ChatMessage,
1861 LogMessage,
1862 Immovable,
1863+ ConstructionsiteEnhanced,
1864 FieldPossession,
1865 FieldTerrainChanged,
1866 ProductionSiteOutOfResources,
1867
1868=== modified file 'src/scripting/lua_map.cc'
1869--- src/scripting/lua_map.cc 2019-05-04 10:47:44 +0000
1870+++ src/scripting/lua_map.cc 2019-06-19 09:23:26 +0000
1871@@ -4871,39 +4871,39 @@
1872 }
1873
1874 // Transforms the given warehouse policy to a string which is used by the lua code
1875-inline void wh_policy_to_string(lua_State* L, Warehouse::StockPolicy p) {
1876+inline void wh_policy_to_string(lua_State* L, StockPolicy p) {
1877 switch (p) {
1878- case Warehouse::StockPolicy::kNormal:
1879+ case StockPolicy::kNormal:
1880 lua_pushstring(L, "normal");
1881 break;
1882- case Warehouse::StockPolicy::kPrefer:
1883+ case StockPolicy::kPrefer:
1884 lua_pushstring(L, "prefer");
1885 break;
1886- case Warehouse::StockPolicy::kDontStock:
1887+ case StockPolicy::kDontStock:
1888 lua_pushstring(L, "dontstock");
1889 break;
1890- case Warehouse::StockPolicy::kRemove:
1891+ case StockPolicy::kRemove:
1892 lua_pushstring(L, "remove");
1893 break;
1894 }
1895 }
1896 // Transforms the given string from the lua code to a warehouse policy
1897-inline Warehouse::StockPolicy string_to_wh_policy(lua_State* L, uint32_t index) {
1898+inline StockPolicy string_to_wh_policy(lua_State* L, uint32_t index) {
1899 std::string str = luaL_checkstring(L, index);
1900 if (str == "normal")
1901- return Warehouse::StockPolicy::kNormal;
1902+ return StockPolicy::kNormal;
1903 else if (str == "prefer")
1904- return Warehouse::StockPolicy::kPrefer;
1905+ return StockPolicy::kPrefer;
1906 else if (str == "dontstock")
1907- return Warehouse::StockPolicy::kDontStock;
1908+ return StockPolicy::kDontStock;
1909 else if (str == "remove")
1910- return Warehouse::StockPolicy::kRemove;
1911+ return StockPolicy::kRemove;
1912 else
1913 report_error(L, "<%s> is no valid warehouse policy!", str.c_str());
1914 }
1915
1916 inline bool
1917-do_set_ware_policy(Warehouse* wh, const DescriptionIndex idx, const Warehouse::StockPolicy p) {
1918+do_set_ware_policy(Warehouse* wh, const DescriptionIndex idx, const StockPolicy p) {
1919 wh->set_ware_policy(idx, p);
1920 return true;
1921 }
1922@@ -4913,7 +4913,7 @@
1923 * If the no ware with the given name exists for the tribe of the warehouse, return false.
1924 */
1925 inline bool
1926-do_set_ware_policy(Warehouse* wh, const std::string& name, const Warehouse::StockPolicy p) {
1927+do_set_ware_policy(Warehouse* wh, const std::string& name, const StockPolicy p) {
1928 const TribeDescr& tribe = wh->owner().tribe();
1929 DescriptionIndex idx = tribe.ware_index(name);
1930 if (!tribe.has_ware(idx)) {
1931@@ -4923,7 +4923,7 @@
1932 }
1933
1934 inline bool
1935-do_set_worker_policy(Warehouse* wh, const DescriptionIndex idx, const Warehouse::StockPolicy p) {
1936+do_set_worker_policy(Warehouse* wh, const DescriptionIndex idx, const StockPolicy p) {
1937 const TribeDescr& tribe = wh->owner().tribe();
1938 // If the worker does not cost anything, ignore it
1939 // Otherwise, an unlimited stream of carriers might leave the warehouse
1940@@ -4942,7 +4942,7 @@
1941 * If no worker with the given name exists for the tribe of the warehouse, return false.
1942 */
1943 inline bool
1944-do_set_worker_policy(Warehouse* wh, const std::string& name, const Warehouse::StockPolicy p) {
1945+do_set_worker_policy(Warehouse* wh, const std::string& name, const StockPolicy p) {
1946 const TribeDescr& tribe = wh->owner().tribe();
1947 DescriptionIndex idx = tribe.worker_index(name);
1948 if (!tribe.has_worker(idx)) {
1949@@ -4972,7 +4972,7 @@
1950 report_error(L, "Wrong number of arguments to set_warehouse_policies!");
1951
1952 Warehouse* wh = get(L, get_egbase(L));
1953- Warehouse::StockPolicy p = string_to_wh_policy(L, -1);
1954+ StockPolicy p = string_to_wh_policy(L, -1);
1955 lua_pop(L, 1);
1956 const TribeDescr& tribe = wh->owner().tribe();
1957
1958
1959=== modified file 'src/wui/actionconfirm.cc'
1960--- src/wui/actionconfirm.cc 2019-04-28 16:53:20 +0000
1961+++ src/wui/actionconfirm.cc 2019-06-19 09:23:26 +0000
1962@@ -92,7 +92,8 @@
1963 struct EnhanceConfirm : public ActionConfirm {
1964 EnhanceConfirm(InteractivePlayer& parent,
1965 Widelands::Building& building,
1966- const Widelands::DescriptionIndex& id);
1967+ const Widelands::DescriptionIndex& id,
1968+ bool still_under_construction);
1969
1970 void think() override;
1971 void ok() override;
1972@@ -100,6 +101,7 @@
1973 private:
1974 // Do not make this a reference - it is a stack variable in the caller
1975 const Widelands::DescriptionIndex id_;
1976+ bool still_under_construction_;
1977 };
1978
1979 /**
1980@@ -259,7 +261,8 @@
1981 */
1982 EnhanceConfirm::EnhanceConfirm(InteractivePlayer& parent,
1983 Widelands::Building& building,
1984- const Widelands::DescriptionIndex& id)
1985+ const Widelands::DescriptionIndex& id,
1986+ bool still_under_construction)
1987 : ActionConfirm(
1988 parent,
1989 _("Enhance building?"),
1990@@ -270,7 +273,8 @@
1991 .str() :
1992 _("Do you really want to enhance this building?"),
1993 building),
1994- id_(id) {
1995+ id_(id),
1996+ still_under_construction_(still_under_construction) {
1997 // Nothing special to do
1998 }
1999
2000@@ -284,7 +288,7 @@
2001 upcast(Widelands::Building, building, object_.get(egbase));
2002
2003 if (!building || !iaplayer().can_act(building->owner().player_number()) ||
2004- !(building->get_playercaps() & Widelands::Building::PCap_Enhancable))
2005+ !(still_under_construction_ || (building->get_playercaps() & Widelands::Building::PCap_Enhancable)))
2006 die();
2007 }
2008
2009@@ -293,11 +297,18 @@
2010 */
2011 void EnhanceConfirm::ok() {
2012 Widelands::Game& game = iaplayer().game();
2013- upcast(Widelands::Building, building, object_.get(game));
2014
2015- if (building && iaplayer().can_act(building->owner().player_number()) &&
2016- (building->get_playercaps() & Widelands::Building::PCap_Enhancable)) {
2017- game.send_player_enhance_building(*building, id_);
2018+ if (still_under_construction_) {
2019+ upcast(Widelands::ConstructionSite, cs, object_.get(game));
2020+ if (cs && iaplayer().can_act(cs->owner().player_number())) {
2021+ game.send_player_enhance_building(*cs, Widelands::INVALID_INDEX);
2022+ }
2023+ } else {
2024+ upcast(Widelands::Building, building, object_.get(game));
2025+ if (building && iaplayer().can_act(building->owner().player_number()) &&
2026+ (building->get_playercaps() & Widelands::Building::PCap_Enhancable)) {
2027+ game.send_player_enhance_building(*building, id_);
2028+ }
2029 }
2030
2031 die();
2032@@ -419,8 +430,9 @@
2033 */
2034 void show_enhance_confirm(InteractivePlayer& player,
2035 Widelands::Building& building,
2036- const Widelands::DescriptionIndex& id) {
2037- new EnhanceConfirm(player, building, id);
2038+ const Widelands::DescriptionIndex& id,
2039+ bool constructionsite) {
2040+ new EnhanceConfirm(player, building, id, constructionsite);
2041 }
2042
2043 /**
2044
2045=== modified file 'src/wui/actionconfirm.h'
2046--- src/wui/actionconfirm.h 2019-02-23 11:00:49 +0000
2047+++ src/wui/actionconfirm.h 2019-06-19 09:23:26 +0000
2048@@ -39,7 +39,8 @@
2049
2050 void show_enhance_confirm(InteractivePlayer& player,
2051 Widelands::Building& building,
2052- const Widelands::DescriptionIndex& id);
2053+ const Widelands::DescriptionIndex& id,
2054+ bool still_under_construction = false);
2055
2056 // Ship confirm windows
2057 void show_ship_sink_confirm(InteractivePlayer& player, Widelands::Ship& ship);
2058
2059=== modified file 'src/wui/buildingwindow.cc'
2060--- src/wui/buildingwindow.cc 2019-05-26 17:21:15 +0000
2061+++ src/wui/buildingwindow.cc 2019-06-19 09:23:26 +0000
2062@@ -54,7 +54,7 @@
2063 is_dying_(false),
2064 parent_(&parent),
2065 building_(&b),
2066- building_descr_for_help_(descr),
2067+ building_descr_for_help_(&descr),
2068 building_position_(b.get_position()),
2069 showing_workarea_(false),
2070 avoid_fastclick_(avoid_fastclick),
2071@@ -363,14 +363,14 @@
2072 g_gr->images().get("images/ui_basic/menu_help.png"), _("Help"));
2073
2074 UI::UniqueWindow::Registry& registry =
2075- igbase()->unique_windows().get_registry(building_descr_for_help_.name() + "_help");
2076+ igbase()->unique_windows().get_registry(building_descr_for_help_->name() + "_help");
2077 registry.open_window = [this, &registry] {
2078 if (parent_ != nullptr) {
2079 Widelands::Building* building_in_lambda = building_.get(parent_->egbase());
2080 if (building_in_lambda == nullptr) {
2081 return;
2082 }
2083- new UI::BuildingHelpWindow(igbase(), registry, building_descr_for_help_,
2084+ new UI::BuildingHelpWindow(igbase(), registry, *building_descr_for_help_,
2085 building_in_lambda->owner().tribe(),
2086 &parent_->egbase().lua());
2087 }
2088
2089=== modified file 'src/wui/buildingwindow.h'
2090--- src/wui/buildingwindow.h 2019-02-23 11:00:49 +0000
2091+++ src/wui/buildingwindow.h 2019-06-19 09:23:26 +0000
2092@@ -95,6 +95,10 @@
2093
2094 bool is_dying_;
2095
2096+ void set_building_descr_for_help(const Widelands::BuildingDescr* d) {
2097+ building_descr_for_help_ = d;
2098+ }
2099+
2100 private:
2101 void create_capsbuttons(UI::Box* buttons, Widelands::Building* building);
2102
2103@@ -110,7 +114,7 @@
2104 Widelands::OPtr<Widelands::Building> building_;
2105
2106 // The building description that will be used for the help button
2107- const Widelands::BuildingDescr& building_descr_for_help_;
2108+ const Widelands::BuildingDescr* building_descr_for_help_;
2109
2110 // We require this to unregister overlays when we are closed. Since the
2111 // building might have been destroyed by then we have to keep a copy of its
2112
2113=== modified file 'src/wui/constructionsitewindow.cc'
2114--- src/wui/constructionsitewindow.cc 2019-02-23 11:00:49 +0000
2115+++ src/wui/constructionsitewindow.cc 2019-06-19 09:23:26 +0000
2116@@ -22,9 +22,67 @@
2117 #include <boost/format.hpp>
2118
2119 #include "graphic/graphic.h"
2120+#include "wui/actionconfirm.h"
2121 #include "wui/inputqueuedisplay.h"
2122+#include "wui/interactive_player.h"
2123
2124 static const char pic_tab_wares[] = "images/wui/buildings/menu_tab_wares.png";
2125+static const char pic_tab_settings[] = "images/wui/menus/menu_stock.png";
2126+static const char pic_tab_settings_wares[] = "images/wui/stats/menu_tab_wares_warehouse.png";
2127+static const char pic_tab_settings_workers[] = "images/wui/stats/menu_tab_workers_warehouse.png";
2128+static const char pic_max_fill_indicator[] = "images/wui/buildings/max_fill_indicator.png";
2129+static const char pic_priority_low[] = "images/wui/buildings/low_priority_button.png";
2130+static const char pic_priority_normal[] = "images/wui/buildings/normal_priority_button.png";
2131+static const char pic_priority_high[] = "images/wui/buildings/high_priority_button.png";
2132+static const char pic_stock_policy_prefer[] = "images/wui/buildings/stock_policy_prefer.png";
2133+static const char pic_stock_policy_dontstock[] = "images/wui/buildings/stock_policy_dontstock.png";
2134+static const char pic_stock_policy_remove[] = "images/wui/buildings/stock_policy_remove.png";
2135+static const char pic_stock_policy_button_normal[] = "images/wui/buildings/stock_policy_button_normal.png";
2136+static const char pic_stock_policy_button_prefer[] = "images/wui/buildings/stock_policy_button_prefer.png";
2137+static const char pic_stock_policy_button_dontstock[] = "images/wui/buildings/stock_policy_button_dontstock.png";
2138+static const char pic_stock_policy_button_remove[] = "images/wui/buildings/stock_policy_button_remove.png";
2139+static const char pic_decrease_capacity[] = "images/wui/buildings/menu_down_train.png";
2140+static const char pic_increase_capacity[] = "images/wui/buildings/menu_up_train.png";
2141+
2142+ConstructionSiteWindow::FakeWaresDisplay::FakeWaresDisplay(UI::Panel* parent,
2143+ bool can_act,
2144+ Widelands::ConstructionSite& cs,
2145+ Widelands::WareWorker type)
2146+ : WaresDisplay(parent, 0, 0, cs.owner().tribe(), type, can_act),
2147+ settings_(*dynamic_cast<Widelands::WarehouseSettings*>(cs.get_settings())),
2148+ tribe_(cs.owner().tribe()) {
2149+}
2150+
2151+void ConstructionSiteWindow::FakeWaresDisplay::draw_ware(RenderTarget& dst, Widelands::DescriptionIndex ware) {
2152+ if (get_type() == Widelands::wwWORKER && std::find(tribe_.worker_types_without_cost().begin(),
2153+ tribe_.worker_types_without_cost().end(), ware) != tribe_.worker_types_without_cost().end()) {
2154+ return;
2155+ }
2156+ WaresDisplay::draw_ware(dst, ware);
2157+
2158+ const auto& map = get_type() == Widelands::wwWARE ? settings_.ware_preferences : settings_.worker_preferences;
2159+ const auto it = map.find(ware);
2160+ if (it == map.end()) {
2161+ return;
2162+ }
2163+ const Image* pic = nullptr;
2164+ switch (it->second) {
2165+ case Widelands::StockPolicy::kPrefer:
2166+ pic = g_gr->images().get(pic_stock_policy_prefer);
2167+ break;
2168+ case Widelands::StockPolicy::kDontStock:
2169+ pic = g_gr->images().get(pic_stock_policy_dontstock);
2170+ break;
2171+ case Widelands::StockPolicy::kRemove:
2172+ pic = g_gr->images().get(pic_stock_policy_remove);
2173+ break;
2174+ case Widelands::StockPolicy::kNormal:
2175+ // No icon for the normal policy
2176+ return;
2177+ }
2178+ assert(pic);
2179+ dst.blit(ware_position(ware), pic);
2180+}
2181
2182 ConstructionSiteWindow::ConstructionSiteWindow(InteractiveGameBase& parent,
2183 UI::UniqueWindow::Registry& reg,
2184@@ -33,13 +91,23 @@
2185 bool workarea_preview_wanted)
2186 : BuildingWindow(parent, reg, cs, cs.building(), avoid_fastclick),
2187 construction_site_(&cs),
2188- progress_(nullptr) {
2189+ progress_(nullptr),
2190+ cs_enhance_(nullptr),
2191+ cs_launch_expedition_(nullptr),
2192+ cs_prefer_heroes_rookies_(nullptr),
2193+ cs_soldier_capacity_decrease_(nullptr),
2194+ cs_soldier_capacity_increase_(nullptr),
2195+ cs_soldier_capacity_display_(nullptr),
2196+ cs_stopped_(nullptr),
2197+ cs_warehouse_wares_(nullptr),
2198+ cs_warehouse_workers_(nullptr) {
2199 init(avoid_fastclick, workarea_preview_wanted);
2200 }
2201
2202 void ConstructionSiteWindow::init(bool avoid_fastclick, bool workarea_preview_wanted) {
2203 Widelands::ConstructionSite* construction_site = construction_site_.get(igbase()->egbase());
2204 assert(construction_site != nullptr);
2205+ set_building_descr_for_help(&construction_site->building());
2206
2207 BuildingWindow::init(avoid_fastclick, workarea_preview_wanted);
2208 UI::Box& box = *new UI::Box(get_tabs(), 0, 0, UI::Box::Vertical);
2209@@ -59,10 +127,245 @@
2210
2211 get_tabs()->add("wares", g_gr->images().get(pic_tab_wares), &box, _("Building materials"));
2212
2213+ if (construction_site->get_settings()) {
2214+ const bool can_act = igbase()->can_act(construction_site->owner().player_number());
2215+ // Create the settings. Since we don't access an actual building, we create
2216+ // a simplified faksimile of the later building window that contains only
2217+ // the relevant options.
2218+ bool nothing_added = false;
2219+ UI::Box& settings_box = *new UI::Box(get_tabs(), 0, 0, UI::Box::Vertical);
2220+ if (upcast(Widelands::ProductionsiteSettings, ps, construction_site->get_settings())) {
2221+ for (const auto& pair : ps->ware_queues) {
2222+ InputQueueDisplay* queue = new InputQueueDisplay(&settings_box, 0, 0, *igbase(),
2223+ *construction_site, Widelands::wwWARE, pair.first);
2224+ settings_box.add(queue);
2225+ settings_box.add_space(8);
2226+ cs_ware_queues_.push_back(queue);
2227+ }
2228+ for (const auto& pair : ps->worker_queues) {
2229+ InputQueueDisplay* queue = new InputQueueDisplay(&settings_box, 0, 0, *igbase(),
2230+ *construction_site, Widelands::wwWORKER, pair.first);
2231+ settings_box.add(queue);
2232+ settings_box.add_space(8);
2233+ cs_ware_queues_.push_back(queue);
2234+ }
2235+ if (upcast(Widelands::TrainingsiteSettings, ts, ps)) {
2236+ UI::Box& soldier_capacity_box = *new UI::Box(&settings_box, 0, 0, UI::Box::Horizontal);
2237+ settings_box.add(&soldier_capacity_box, UI::Box::Resizing::kAlign, UI::Align::kCenter);
2238+ cs_soldier_capacity_decrease_ = new UI::Button(&soldier_capacity_box,
2239+ "decrease", 0, 0, 32, 32, UI::ButtonStyle::kWuiMenu,
2240+ g_gr->images().get(pic_decrease_capacity),
2241+ _("Decrease capacity. Hold down Ctrl to set the capacity to the lowest value"));
2242+ cs_soldier_capacity_increase_ = new UI::Button(&soldier_capacity_box,
2243+ "increase", 0, 0, 32, 32, UI::ButtonStyle::kWuiMenu,
2244+ g_gr->images().get(pic_increase_capacity),
2245+ _("Increase capacity. Hold down Ctrl to set the capacity to the highest value"));
2246+ cs_soldier_capacity_display_ = new UI::Textarea(&soldier_capacity_box,
2247+ "", UI::Align::kCenter);
2248+ cs_soldier_capacity_decrease_->set_enabled(can_act);
2249+ cs_soldier_capacity_increase_->set_enabled(can_act);
2250+ cs_soldier_capacity_decrease_->sigclicked.connect([this, ts]() {
2251+ igbase()->game().send_player_change_soldier_capacity(
2252+ *construction_site_.get(igbase()->egbase()),
2253+ SDL_GetModState() & KMOD_CTRL ? 0 : ts->desired_capacity - 1);
2254+ });
2255+ cs_soldier_capacity_increase_->sigclicked.connect([this, ts]() {
2256+ igbase()->game().send_player_change_soldier_capacity(
2257+ *construction_site_.get(igbase()->egbase()),
2258+ SDL_GetModState() & KMOD_CTRL ? ts->max_capacity : ts->desired_capacity + 1);
2259+ });
2260+ soldier_capacity_box.add(cs_soldier_capacity_decrease_);
2261+ soldier_capacity_box.add_space(8);
2262+ soldier_capacity_box.add(cs_soldier_capacity_display_, UI::Box::Resizing::kAlign, UI::Align::kCenter);
2263+ soldier_capacity_box.add_space(8);
2264+ soldier_capacity_box.add(cs_soldier_capacity_increase_);
2265+ settings_box.add_space(8);
2266+ }
2267+ cs_stopped_ = new UI::Checkbox(&settings_box, Vector2i::zero(),
2268+ _("Stopped"),
2269+ _("Stop this building’s work after completion"));
2270+ cs_stopped_->clickedto.connect([this, ps](bool stop) {
2271+ if (stop != ps->stopped) {
2272+ igbase()->game().send_player_start_stop_building(*construction_site_.get(igbase()->egbase()));
2273+ }
2274+ });
2275+ settings_box.add(cs_stopped_, UI::Box::Resizing::kFullSize);
2276+ settings_box.add_space(8);
2277+ cs_stopped_->set_enabled(can_act);
2278+ } else if (upcast(Widelands::MilitarysiteSettings, ms, construction_site->get_settings())) {
2279+ UI::Box& soldier_capacity_box = *new UI::Box(&settings_box, 0, 0, UI::Box::Horizontal);
2280+ settings_box.add(&soldier_capacity_box, UI::Box::Resizing::kAlign, UI::Align::kCenter);
2281+ cs_soldier_capacity_decrease_ = new UI::Button(&soldier_capacity_box,
2282+ "decrease", 0, 0, 32, 32, UI::ButtonStyle::kWuiMenu,
2283+ g_gr->images().get(pic_decrease_capacity),
2284+ _("Decrease capacity. Hold down Ctrl to set the capacity to the lowest value"));
2285+ cs_soldier_capacity_increase_ = new UI::Button(&soldier_capacity_box,
2286+ "increase", 0, 0, 32, 32, UI::ButtonStyle::kWuiMenu,
2287+ g_gr->images().get(pic_increase_capacity),
2288+ _("Increase capacity. Hold down Ctrl to set the capacity to the highest value"));
2289+ cs_soldier_capacity_display_ = new UI::Textarea(&soldier_capacity_box,
2290+ "", UI::Align::kCenter);
2291+ cs_soldier_capacity_decrease_->set_enabled(can_act);
2292+ cs_soldier_capacity_increase_->set_enabled(can_act);
2293+ cs_soldier_capacity_decrease_->sigclicked.connect([this, ms]() {
2294+ igbase()->game().send_player_change_soldier_capacity(
2295+ *construction_site_.get(igbase()->egbase()),
2296+ SDL_GetModState() & KMOD_CTRL ? 0 : ms->desired_capacity - 1);
2297+ });
2298+ cs_soldier_capacity_increase_->sigclicked.connect([this, ms]() {
2299+ igbase()->game().send_player_change_soldier_capacity(
2300+ *construction_site_.get(igbase()->egbase()),
2301+ SDL_GetModState() & KMOD_CTRL ? ms->max_capacity : ms->desired_capacity + 1);
2302+ });
2303+ soldier_capacity_box.add(cs_soldier_capacity_decrease_);
2304+ soldier_capacity_box.add_space(8);
2305+ soldier_capacity_box.add(cs_soldier_capacity_display_, UI::Box::Resizing::kAlign, UI::Align::kCenter);
2306+ soldier_capacity_box.add_space(8);
2307+ soldier_capacity_box.add(cs_soldier_capacity_increase_);
2308+ settings_box.add_space(8);
2309+
2310+ UI::Box& soldier_preference_box = *new UI::Box(&settings_box, 0, 0, UI::Box::Horizontal);
2311+ settings_box.add(&soldier_preference_box, UI::Box::Resizing::kAlign, UI::Align::kCenter);
2312+ UI::Panel& soldier_preference_panel = *new UI::Panel(&soldier_preference_box, 0, 0, 64, 32);
2313+ soldier_preference_box.add(&soldier_preference_panel);
2314+ cs_prefer_heroes_rookies_.reset(new UI::Radiogroup());
2315+ cs_prefer_heroes_rookies_->add_button(&soldier_preference_panel, Vector2i::zero(),
2316+ g_gr->images().get("images/wui/buildings/prefer_rookies.png"),
2317+ _("Prefer rookies"));
2318+ cs_prefer_heroes_rookies_->add_button(&soldier_preference_panel, Vector2i(32, 0),
2319+ g_gr->images().get("images/wui/buildings/prefer_heroes.png"),
2320+ _("Prefer heroes"));
2321+ if (can_act) {
2322+ cs_prefer_heroes_rookies_->changedto.connect([this](int32_t state) {
2323+ igbase()->game().send_player_militarysite_set_soldier_preference(
2324+ *construction_site_.get(igbase()->egbase()),
2325+ state ? Widelands::SoldierPreference::kHeroes : Widelands::SoldierPreference::kRookies);
2326+ });
2327+ }
2328+ settings_box.add_space(8);
2329+ } else if (upcast(Widelands::WarehouseSettings, ws, construction_site->get_settings())) {
2330+ auto add_tab = [this, construction_site, can_act](Widelands::WareWorker ww, FakeWaresDisplay** display) {
2331+ UI::Box& mainbox = *new UI::Box(get_tabs(), 0, 0, UI::Box::Vertical);
2332+ *display = new FakeWaresDisplay(&mainbox, can_act, *construction_site, ww);
2333+ mainbox.add(*display, UI::Box::Resizing::kFullSize);
2334+ mainbox.add_space(8);
2335+ UI::Box& buttonsbox = *new UI::Box(&mainbox, 0, 0, UI::Box::Horizontal);
2336+ mainbox.add(&buttonsbox, UI::Box::Resizing::kAlign, UI::Align::kCenter);
2337+ mainbox.add_space(8);
2338+ UI::Button& sp_normal = *new UI::Button(&buttonsbox, "stock_policy_normal", 0, 0, 34, 34,
2339+ UI::ButtonStyle::kWuiMenu, g_gr->images().get(pic_stock_policy_button_normal),
2340+ _("Normal policy"));
2341+ UI::Button& sp_prefer = *new UI::Button(&buttonsbox, "stock_policy_prefer", 0, 0, 34, 34,
2342+ UI::ButtonStyle::kWuiMenu, g_gr->images().get(pic_stock_policy_button_prefer),
2343+ _("Preferably store selected wares here"));
2344+ UI::Button& sp_dont = *new UI::Button(&buttonsbox, "stock_policy_dontstock", 0, 0, 34, 34,
2345+ UI::ButtonStyle::kWuiMenu, g_gr->images().get(pic_stock_policy_button_dontstock),
2346+ _("Do not store selected wares here"));
2347+ UI::Button& sp_remove = *new UI::Button(&buttonsbox, "stock_policy_remove", 0, 0, 34, 34,
2348+ UI::ButtonStyle::kWuiMenu, g_gr->images().get(pic_stock_policy_button_remove),
2349+ _("Remove selected wares from here"));
2350+ sp_remove.sigclicked.connect(
2351+ boost::bind(&ConstructionSiteWindow::change_policy, this, ww, Widelands::StockPolicy::kRemove));
2352+ sp_dont.sigclicked.connect(
2353+ boost::bind(&ConstructionSiteWindow::change_policy, this, ww, Widelands::StockPolicy::kDontStock));
2354+ sp_prefer.sigclicked.connect(
2355+ boost::bind(&ConstructionSiteWindow::change_policy, this, ww, Widelands::StockPolicy::kPrefer));
2356+ sp_normal.sigclicked.connect(
2357+ boost::bind(&ConstructionSiteWindow::change_policy, this, ww, Widelands::StockPolicy::kNormal));
2358+ sp_normal.set_enabled(can_act);
2359+ sp_dont.set_enabled(can_act);
2360+ sp_remove.set_enabled(can_act);
2361+ sp_prefer.set_enabled(can_act);
2362+ buttonsbox.add(&sp_normal);
2363+ buttonsbox.add_space(8);
2364+ buttonsbox.add(&sp_prefer);
2365+ buttonsbox.add_space(8);
2366+ buttonsbox.add(&sp_dont);
2367+ buttonsbox.add_space(8);
2368+ buttonsbox.add(&sp_remove);
2369+ if (ww == Widelands::wwWARE) {
2370+ get_tabs()->add("warehouse_wares", g_gr->images().get(pic_tab_settings_wares),
2371+ &mainbox, _("Ware settings to apply after construction"));
2372+ } else {
2373+ get_tabs()->add("warehouse_workers", g_gr->images().get(pic_tab_settings_workers),
2374+ &mainbox, _("Worker settings to apply after construction"));
2375+ }
2376+ };
2377+ add_tab(Widelands::wwWARE, &cs_warehouse_wares_);
2378+ add_tab(Widelands::wwWORKER, &cs_warehouse_workers_);
2379+ if (construction_site->get_info().becomes->get_isport()) {
2380+ cs_launch_expedition_ = new UI::Checkbox(&settings_box, Vector2i::zero(),
2381+ _("Start an expedition"),
2382+ _("Start an expedition from this port after completion"));
2383+ cs_launch_expedition_->clickedto.connect([this, ws](bool launch) {
2384+ if (launch != ws->launch_expedition) {
2385+ igbase()->game().send_player_start_or_cancel_expedition(
2386+ *construction_site_.get(igbase()->egbase()));
2387+ }
2388+ });
2389+ settings_box.add(cs_launch_expedition_, UI::Box::Resizing::kFullSize);
2390+ settings_box.add_space(8);
2391+ cs_launch_expedition_->set_enabled(can_act);
2392+ } else {
2393+ nothing_added = true;
2394+ }
2395+ } else {
2396+ NEVER_HERE();
2397+ }
2398+
2399+ if (can_act && construction_site->get_info().becomes->enhancement() != Widelands::INVALID_INDEX) {
2400+ const Widelands::BuildingDescr& building_descr = *igbase()->egbase().tribes().get_building_descr(
2401+ construction_site->get_info().becomes->enhancement());
2402+ std::string enhance_tooltip =
2403+ (boost::format(_("Enhance to %s")) % building_descr.descname().c_str()).str() +
2404+ "<br><font size=11>" + _("Construction costs:") + "</font><br>" +
2405+ waremap_to_richtext(construction_site->owner().tribe(), building_descr.enhancement_cost());
2406+ cs_enhance_ = new UI::Button(&settings_box, "enhance", 0, 0, 34, 34, UI::ButtonStyle::kWuiMenu,
2407+ building_descr.icon(), enhance_tooltip);
2408+ cs_enhance_->sigclicked.connect([this, construction_site] {
2409+ if (SDL_GetModState() & KMOD_CTRL) {
2410+ igbase()->game().send_player_enhance_building(*construction_site, Widelands::INVALID_INDEX);
2411+ } else {
2412+ show_enhance_confirm(dynamic_cast<InteractivePlayer&>(*igbase()),
2413+ *construction_site, construction_site->get_info().becomes->enhancement(), true);
2414+ }
2415+ });
2416+ settings_box.add(cs_enhance_, UI::Box::Resizing::kAlign, UI::Align::kCenter);
2417+ settings_box.add_space(8);
2418+ nothing_added = false;
2419+ }
2420+ if (!nothing_added) {
2421+ get_tabs()->add("settings", g_gr->images().get(pic_tab_settings),
2422+ &settings_box, _("Settings to apply after construction"));
2423+ }
2424+ }
2425+
2426 set_title((boost::format("(%s)") % construction_site->building().descname()).str());
2427 think();
2428 }
2429
2430+void ConstructionSiteWindow::change_policy(Widelands::WareWorker ww, Widelands::StockPolicy p) {
2431+ Widelands::ConstructionSite* construction_site = construction_site_.get(igbase()->egbase());
2432+ assert(construction_site);
2433+ upcast(Widelands::WarehouseSettings, ws, construction_site->get_settings());
2434+ assert(ws);
2435+ if (ww == Widelands::wwWARE) {
2436+ for (const auto& pair : ws->ware_preferences) {
2437+ if (cs_warehouse_wares_->ware_selected(pair.first)) {
2438+ igbase()->game().send_player_set_stock_policy(*construction_site,
2439+ Widelands::wwWARE, pair.first, p);
2440+ }
2441+ }
2442+ } else {
2443+ for (const auto& pair : ws->worker_preferences) {
2444+ if (cs_warehouse_workers_->ware_selected(pair.first)) {
2445+ igbase()->game().send_player_set_stock_policy(*construction_site,
2446+ Widelands::wwWORKER, pair.first, p);
2447+ }
2448+ }
2449+ }
2450+}
2451+
2452 /*
2453 ===============
2454 Make sure the window is redrawn when necessary.
2455@@ -77,5 +380,41 @@
2456 if (construction_site == nullptr) {
2457 return;
2458 }
2459+
2460 progress_->set_state(construction_site->get_built_per64k());
2461+
2462+ const bool can_act = igbase()->can_act(construction_site->owner().player_number());
2463+ // InputQueueDisplay and FakeWaresDisplay update themselves – we need to refresh the other settings
2464+ if (upcast(Widelands::ProductionsiteSettings, ps, construction_site->get_settings())) {
2465+ assert(cs_stopped_);
2466+ cs_stopped_->set_state(ps->stopped);
2467+ }
2468+ if (upcast(Widelands::TrainingsiteSettings, ts, construction_site->get_settings())) {
2469+ assert(cs_soldier_capacity_decrease_);
2470+ assert(cs_soldier_capacity_increase_);
2471+ assert(cs_soldier_capacity_display_);
2472+ cs_soldier_capacity_display_->set_text((boost::format(ngettext("%u soldier", "%u soldiers",
2473+ ts->desired_capacity)) % ts->desired_capacity).str());
2474+ cs_soldier_capacity_decrease_->set_enabled(can_act && ts->desired_capacity > 0);
2475+ cs_soldier_capacity_increase_->set_enabled(can_act && ts->desired_capacity < ts->max_capacity);
2476+ } else if (upcast(Widelands::MilitarysiteSettings, ms, construction_site->get_settings())) {
2477+ assert(cs_soldier_capacity_decrease_);
2478+ assert(cs_soldier_capacity_increase_);
2479+ assert(cs_soldier_capacity_display_);
2480+ assert(cs_prefer_heroes_rookies_);
2481+ cs_soldier_capacity_display_->set_text((boost::format(ngettext("%u soldier", "%u soldiers",
2482+ ms->desired_capacity)) % ms->desired_capacity).str());
2483+ cs_soldier_capacity_decrease_->set_enabled(can_act && ms->desired_capacity > 1);
2484+ cs_soldier_capacity_increase_->set_enabled(can_act && ms->desired_capacity < ms->max_capacity);
2485+ cs_prefer_heroes_rookies_->set_state(ms->prefer_heroes ? 1 : 0);
2486+ } else if (upcast(Widelands::WarehouseSettings, ws, construction_site->get_settings())) {
2487+ if (cs_launch_expedition_) {
2488+ cs_launch_expedition_->set_state(ws->launch_expedition);
2489+ }
2490+#ifndef NDEBUG
2491+ else {
2492+ assert(!ws->launch_expedition);
2493+ }
2494+#endif
2495+ }
2496 }
2497
2498=== modified file 'src/wui/constructionsitewindow.h'
2499--- src/wui/constructionsitewindow.h 2019-02-23 11:00:49 +0000
2500+++ src/wui/constructionsitewindow.h 2019-06-19 09:23:26 +0000
2501@@ -20,9 +20,18 @@
2502 #ifndef WL_WUI_CONSTRUCTIONSITEWINDOW_H
2503 #define WL_WUI_CONSTRUCTIONSITEWINDOW_H
2504
2505+#include <memory>
2506+#include <vector>
2507+
2508 #include "logic/map_objects/tribes/constructionsite.h"
2509+#include "ui_basic/button.h"
2510+#include "ui_basic/checkbox.h"
2511 #include "ui_basic/progressbar.h"
2512+#include "ui_basic/radiobutton.h"
2513+#include "ui_basic/tabpanel.h"
2514+#include "ui_basic/textarea.h"
2515 #include "wui/buildingwindow.h"
2516+#include "wui/inputqueuedisplay.h"
2517
2518 /**
2519 * Status window for construction sites.
2520@@ -40,8 +49,38 @@
2521 void init(bool avoid_fastclick, bool workarea_preview_wanted) override;
2522
2523 private:
2524+ class FakeWaresDisplay : public WaresDisplay {
2525+ public:
2526+ FakeWaresDisplay(UI::Panel* parent,
2527+ bool can_act,
2528+ Widelands::ConstructionSite& cs,
2529+ Widelands::WareWorker type);
2530+
2531+ protected:
2532+ void draw_ware(RenderTarget& dst, Widelands::DescriptionIndex ware) override;
2533+
2534+ private:
2535+ Widelands::WarehouseSettings& settings_;
2536+ const Widelands::TribeDescr& tribe_;
2537+ };
2538+
2539 Widelands::OPtr<Widelands::ConstructionSite> construction_site_;
2540 UI::ProgressBar* progress_;
2541+
2542+ // BuildingSettings-related UI elements
2543+ UI::Button* cs_enhance_;
2544+ UI::Checkbox* cs_launch_expedition_;
2545+ std::unique_ptr<UI::Radiogroup> cs_prefer_heroes_rookies_;
2546+ UI::Button* cs_soldier_capacity_decrease_;
2547+ UI::Button* cs_soldier_capacity_increase_;
2548+ UI::Textarea* cs_soldier_capacity_display_;
2549+ std::vector<InputQueueDisplay*> cs_ware_queues_;
2550+ std::vector<InputQueueDisplay*> cs_worker_queues_;
2551+ UI::Checkbox* cs_stopped_;
2552+ FakeWaresDisplay* cs_warehouse_wares_;
2553+ FakeWaresDisplay* cs_warehouse_workers_;
2554+ void change_policy(Widelands::WareWorker, Widelands::StockPolicy);
2555+
2556 DISALLOW_COPY_AND_ASSIGN(ConstructionSiteWindow);
2557 };
2558
2559
2560=== modified file 'src/wui/inputqueuedisplay.cc'
2561--- src/wui/inputqueuedisplay.cc 2019-05-29 06:24:42 +0000
2562+++ src/wui/inputqueuedisplay.cc 2019-06-19 09:23:26 +0000
2563@@ -46,7 +46,8 @@
2564 : UI::Panel(parent, x, y, 0, 28),
2565 igb_(igb),
2566 building_(building),
2567- queue_(queue),
2568+ queue_(&queue),
2569+ settings_(nullptr),
2570 priority_radiogroup_(nullptr),
2571 increase_max_fill_(nullptr),
2572 decrease_max_fill_(nullptr),
2573@@ -58,12 +59,58 @@
2574 total_height_(0),
2575 show_only_(show_only) {
2576 if (type_ == Widelands::wwWARE) {
2577- const Widelands::WareDescr& ware = *queue.owner().tribe().get_ware_descr(queue_.get_index());
2578+ const Widelands::WareDescr& ware = *queue.owner().tribe().get_ware_descr(queue_->get_index());
2579 set_tooltip(ware.descname().c_str());
2580 icon_ = ware.icon();
2581 } else {
2582 const Widelands::WorkerDescr& worker =
2583- *queue.owner().tribe().get_worker_descr(queue_.get_index());
2584+ *queue.owner().tribe().get_worker_descr(queue_->get_index());
2585+ set_tooltip(worker.descname().c_str());
2586+ icon_ = worker.icon();
2587+ }
2588+
2589+ uint16_t ph = max_fill_indicator_->height();
2590+
2591+ uint32_t priority_button_height = show_only ? 0 : 3 * PriorityButtonSize;
2592+ uint32_t image_height =
2593+ show_only ? kWareMenuPicHeight : std::max<int32_t>(kWareMenuPicHeight, ph);
2594+
2595+ total_height_ = std::max(priority_button_height, image_height) + 2 * Border;
2596+
2597+ max_size_changed();
2598+
2599+ set_thinks(true);
2600+}
2601+
2602+InputQueueDisplay::InputQueueDisplay(UI::Panel* const parent,
2603+ int32_t const x,
2604+ int32_t const y,
2605+ InteractiveGameBase& igb,
2606+ Widelands::ConstructionSite& building,
2607+ Widelands::WareWorker ww,
2608+ Widelands::DescriptionIndex di,
2609+ bool show_only)
2610+ : UI::Panel(parent, x, y, 0, 28),
2611+ igb_(igb),
2612+ building_(building),
2613+ queue_(nullptr),
2614+ settings_(dynamic_cast<const Widelands::ProductionsiteSettings*>(building.get_settings())),
2615+ priority_radiogroup_(nullptr),
2616+ increase_max_fill_(nullptr),
2617+ decrease_max_fill_(nullptr),
2618+ index_(di),
2619+ type_(ww),
2620+ max_fill_indicator_(g_gr->images().get(pic_max_fill_indicator)),
2621+ total_height_(0),
2622+ show_only_(show_only) {
2623+ cache_size_ = check_max_size();
2624+ cache_max_fill_ = check_max_fill();
2625+ if (type_ == Widelands::wwWARE) {
2626+ const Widelands::WareDescr& ware = *building.owner().tribe().get_ware_descr(index_);
2627+ set_tooltip(ware.descname().c_str());
2628+ icon_ = ware.icon();
2629+ } else {
2630+ const Widelands::WorkerDescr& worker = *building.owner().tribe().get_worker_descr(index_);
2631 set_tooltip(worker.descname().c_str());
2632 icon_ = worker.icon();
2633 }
2634@@ -85,6 +132,32 @@
2635 delete priority_radiogroup_;
2636 }
2637
2638+uint32_t InputQueueDisplay::check_max_size() const {
2639+ if (queue_) {
2640+ return queue_->get_max_size();
2641+ }
2642+ assert(settings_);
2643+ for (const auto& pair : type_ == Widelands::wwWARE ? settings_->ware_queues : settings_->worker_queues) {
2644+ if (pair.first == index_) {
2645+ return pair.second.max_fill;
2646+ }
2647+ }
2648+ NEVER_HERE();
2649+}
2650+
2651+uint32_t InputQueueDisplay::check_max_fill() const {
2652+ if (queue_) {
2653+ return queue_->get_max_fill();
2654+ }
2655+ assert(settings_);
2656+ for (const auto& pair : type_ == Widelands::wwWARE ? settings_->ware_queues : settings_->worker_queues) {
2657+ if (pair.first == index_) {
2658+ return pair.second.desired_fill;
2659+ }
2660+ }
2661+ NEVER_HERE();
2662+}
2663+
2664 /**
2665 * Recalculate the panel's size based on the size of the queue.
2666 *
2667@@ -94,7 +167,7 @@
2668 uint32_t pbs = show_only_ ? 0 : PriorityButtonSize;
2669 uint32_t ctrl_b_size = show_only_ ? 0 : 2 * kWareMenuPicWidth;
2670
2671- cache_size_ = queue_.get_max_size();
2672+ cache_size_ = check_max_size();
2673
2674 update_priority_buttons();
2675 update_max_fill_buttons();
2676@@ -111,12 +184,12 @@
2677 * Compare the current InputQueue state with the cached state; update if necessary.
2678 */
2679 void InputQueueDisplay::think() {
2680- if (static_cast<uint32_t>(queue_.get_max_size()) != cache_size_)
2681+ if (static_cast<uint32_t>(check_max_size()) != cache_size_)
2682 max_size_changed();
2683
2684 // TODO(sirver): It seems cache_max_fill_ is not really useful for anything.
2685- if (static_cast<uint32_t>(queue_.get_max_fill()) != cache_max_fill_) {
2686- cache_max_fill_ = queue_.get_max_fill();
2687+ if (static_cast<uint32_t>(check_max_fill()) != cache_max_fill_) {
2688+ cache_max_fill_ = check_max_fill();
2689 compute_max_fill_buttons_enabled_state();
2690 }
2691 }
2692@@ -128,11 +201,12 @@
2693 if (!cache_size_)
2694 return;
2695
2696- cache_max_fill_ = queue_.get_max_fill();
2697+ cache_max_fill_ = check_max_fill();
2698
2699- uint32_t nr_inputs_to_draw = std::min(queue_.get_filled(), cache_size_);
2700+ uint32_t nr_inputs_to_draw = queue_ ? std::min(queue_->get_filled(), cache_size_) : cache_max_fill_;
2701 uint32_t nr_missing_to_draw =
2702- std::min(queue_.get_missing(), cache_max_fill_) + cache_size_ - cache_max_fill_;
2703+ queue_ ? std::min(queue_->get_missing(), cache_max_fill_) + cache_size_ - cache_max_fill_ :
2704+ cache_size_ - cache_max_fill_;
2705 if (nr_inputs_to_draw > cache_max_fill_) {
2706 nr_missing_to_draw -= nr_inputs_to_draw - cache_max_fill_;
2707 }
2708@@ -162,7 +236,7 @@
2709 uint16_t pw = max_fill_indicator_->width();
2710 point.y = Border;
2711 point.x = Border + CellWidth + CellSpacing +
2712- (queue_.get_max_fill() * (CellWidth + CellSpacing)) - CellSpacing / 2 - pw / 2;
2713+ (cache_max_fill_ * (CellWidth + CellSpacing)) - CellSpacing / 2 - pw / 2;
2714 dst.blit(point, max_fill_indicator_);
2715 }
2716 }
2717@@ -206,13 +280,13 @@
2718
2719 int32_t priority = building_.get_priority(type_, index_, false);
2720 switch (priority) {
2721- case HIGH_PRIORITY:
2722+ case Widelands::kPriorityHigh:
2723 priority_radiogroup_->set_state(0);
2724 break;
2725- case DEFAULT_PRIORITY:
2726+ case Widelands::kPriorityNormal:
2727 priority_radiogroup_->set_state(1);
2728 break;
2729- case LOW_PRIORITY:
2730+ case Widelands::kPriorityLow:
2731 priority_radiogroup_->set_state(2);
2732 break;
2733 default:
2734@@ -314,13 +388,13 @@
2735
2736 switch (state) {
2737 case 0:
2738- priority = HIGH_PRIORITY;
2739+ priority = Widelands::kPriorityHigh;
2740 break;
2741 case 1:
2742- priority = DEFAULT_PRIORITY;
2743+ priority = Widelands::kPriorityNormal;
2744 break;
2745 case 2:
2746- priority = LOW_PRIORITY;
2747+ priority = Widelands::kPriorityLow;
2748 break;
2749 default:
2750 return;
2751
2752=== modified file 'src/wui/inputqueuedisplay.h'
2753--- src/wui/inputqueuedisplay.h 2019-05-06 10:53:42 +0000
2754+++ src/wui/inputqueuedisplay.h 2019-06-19 09:23:26 +0000
2755@@ -39,6 +39,8 @@
2756
2757 namespace Widelands {
2758 class Building;
2759+class ConstructionSite;
2760+struct ProductionsiteSettings;
2761 class InputQueue;
2762 } // namespace Widelands
2763
2764@@ -51,6 +53,7 @@
2765 public:
2766 enum { CellWidth = kWareMenuPicWidth, CellSpacing = 2, Border = 4, PriorityButtonSize = 10 };
2767
2768+ // Constructor for real queues (e.g. in ProductionSites)
2769 InputQueueDisplay(UI::Panel* parent,
2770 int32_t x,
2771 int32_t y,
2772@@ -58,6 +61,15 @@
2773 Widelands::Building& building,
2774 const Widelands::InputQueue& queue,
2775 bool = false);
2776+ // Constructor for fake queues (e.g. in ConstructionSite settings)
2777+ InputQueueDisplay(UI::Panel* parent,
2778+ int32_t x,
2779+ int32_t y,
2780+ InteractiveGameBase&,
2781+ Widelands::ConstructionSite&,
2782+ Widelands::WareWorker,
2783+ Widelands::DescriptionIndex,
2784+ bool = false);
2785 ~InputQueueDisplay() override;
2786
2787 void think() override;
2788@@ -66,7 +78,8 @@
2789 private:
2790 InteractiveGameBase& igb_;
2791 Widelands::Building& building_;
2792- const Widelands::InputQueue& queue_;
2793+ const Widelands::InputQueue* queue_;
2794+ const Widelands::ProductionsiteSettings* settings_;
2795 UI::Radiogroup* priority_radiogroup_;
2796 UI::Button* increase_max_fill_;
2797 UI::Button* decrease_max_fill_;
2798@@ -90,6 +103,9 @@
2799 void update_siblings_priority(int32_t);
2800 void update_siblings_fill(int32_t);
2801
2802+ uint32_t check_max_size() const;
2803+ uint32_t check_max_fill() const;
2804+
2805 void compute_max_fill_buttons_enabled_state();
2806 };
2807
2808
2809=== modified file 'src/wui/warehousewindow.cc'
2810--- src/wui/warehousewindow.cc 2019-05-01 07:20:25 +0000
2811+++ src/wui/warehousewindow.cc 2019-06-19 09:23:26 +0000
2812@@ -75,19 +75,19 @@
2813 void WarehouseWaresDisplay::draw_ware(RenderTarget& dst, Widelands::DescriptionIndex ware) {
2814 WaresDisplay::draw_ware(dst, ware);
2815
2816- Widelands::Warehouse::StockPolicy policy = warehouse_.get_stock_policy(get_type(), ware);
2817+ Widelands::StockPolicy policy = warehouse_.get_stock_policy(get_type(), ware);
2818 const Image* pic = nullptr;
2819 switch (policy) {
2820- case Widelands::Warehouse::StockPolicy::kPrefer:
2821+ case Widelands::StockPolicy::kPrefer:
2822 pic = g_gr->images().get(pic_policy_prefer);
2823 break;
2824- case Widelands::Warehouse::StockPolicy::kDontStock:
2825+ case Widelands::StockPolicy::kDontStock:
2826 pic = g_gr->images().get(pic_policy_dontstock);
2827 break;
2828- case Widelands::Warehouse::StockPolicy::kRemove:
2829+ case Widelands::StockPolicy::kRemove:
2830 pic = g_gr->images().get(pic_policy_remove);
2831 break;
2832- case Widelands::Warehouse::StockPolicy::kNormal:
2833+ case Widelands::StockPolicy::kNormal:
2834 // don't draw anything for the normal policy
2835 return;
2836 }
2837@@ -106,7 +106,7 @@
2838 Widelands::Warehouse&,
2839 Widelands::WareWorker type);
2840
2841- void set_policy(Widelands::Warehouse::StockPolicy);
2842+ void set_policy(Widelands::StockPolicy);
2843
2844 private:
2845 InteractiveGameBase& gb_;
2846@@ -139,7 +139,7 @@
2847 buttons, #policy, 0, 0, 34, 34, UI::ButtonStyle::kWuiMenu, \
2848 g_gr->images().get("images/wui/buildings/stock_policy_button_" #policy ".png"), tooltip), \
2849 b->sigclicked.connect(boost::bind( \
2850- &WarehouseWaresPanel::set_policy, this, Widelands::Warehouse::StockPolicy::k##policyname)), \
2851+ &WarehouseWaresPanel::set_policy, this, Widelands::StockPolicy::k##policyname)), \
2852 buttons->add(b);
2853
2854 ADD_POLICY_BUTTON(normal, Normal, _("Normal policy"))
2855@@ -152,7 +152,7 @@
2856 /**
2857 * Add Buttons policy buttons
2858 */
2859-void WarehouseWaresPanel::set_policy(Widelands::Warehouse::StockPolicy newpolicy) {
2860+void WarehouseWaresPanel::set_policy(Widelands::StockPolicy newpolicy) {
2861 if (gb_.can_act(wh_.owner().player_number())) {
2862 bool is_workers = type_ == Widelands::wwWORKER;
2863 const std::set<Widelands::DescriptionIndex> indices =