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

Proposed by Benedikt Straub on 2019-05-14
Status: Merged
Merged at revision: 9157
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 Approve on 2019-06-22
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 on 2019-06-19

Removed struct WareRange

Benedikt Straub (nordfriese) wrote :

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

9127. By Nordfriese on 2019-06-19

Merged trunk

9128. By Nordfriese on 2019-06-19

Merge error

9129. By Nordfriese on 2019-06-19

Fixed compile error

bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 5203. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/547642295.
Appveyor build 4982. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_constructionsite_options-4982.

GunChleoc (gunchleoc) wrote :

LGTM now :)

I'd like to retest this due to the code changes made during review.

review: Approve
GunChleoc (gunchleoc) wrote :

Tested and still working - thanks for this great feature!

@bunnybot merge

bunnybot (widelandsofficial) wrote :

Refusing to merge, since Travis is not green. Use @bunnybot merge force for merging anyways.

Travis build 5203. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/547642295.

GunChleoc (gunchleoc) wrote :

inputqueues again

@bunnybot merge force

bunnybot (widelandsofficial) wrote :

Error merging this proposal:

Output:
stdout:

stderr:
Unable to obtain lock held by <email address hidden> on taotie (process #21580), acquired 19 hours, 2 minutes ago.
See "bzr help break-lock" for more.
bzr: ERROR: Could not acquire lock "(remote lock)": bzr+ssh://bazaar.launchpad.net/~widelands-dev/widelands/trunk/

GunChleoc (gunchleoc) wrote :

@bunnybot merge force

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/ai/defaultai_seafaring.cc'
--- src/ai/defaultai_seafaring.cc 2019-02-23 11:00:49 +0000
+++ src/ai/defaultai_seafaring.cc 2019-06-19 09:23:26 +0000
@@ -346,7 +346,7 @@
346 if (site->bo->is(BuildingAttribute::kShipyard)) {346 if (site->bo->is(BuildingAttribute::kShipyard)) {
347 for (uint32_t k = 0; k < site->bo->inputs.size(); ++k) {347 for (uint32_t k = 0; k < site->bo->inputs.size(); ++k) {
348 game().send_player_set_ware_priority(348 game().send_player_set_ware_priority(
349 *site->site, wwWARE, site->bo->inputs.at(k), HIGH_PRIORITY);349 *site->site, wwWARE, site->bo->inputs.at(k), kPriorityHigh);
350 }350 }
351 }351 }
352 }352 }
353353
=== modified file 'src/economy/economy.cc'
--- src/economy/economy.cc 2019-04-09 16:43:49 +0000
+++ src/economy/economy.cc 2019-06-19 09:23:26 +0000
@@ -971,7 +971,7 @@
971static bool accept_warehouse_if_policy(Warehouse& wh,971static bool accept_warehouse_if_policy(Warehouse& wh,
972 WareWorker type,972 WareWorker type,
973 DescriptionIndex ware,973 DescriptionIndex ware,
974 Warehouse::StockPolicy policy) {974 StockPolicy policy) {
975 return wh.get_stock_policy(type, ware) == policy;975 return wh.get_stock_policy(type, ware) == policy;
976}976}
977977
@@ -1005,8 +1005,8 @@
10051005
1006 for (uint32_t nwh = 0; nwh < warehouses_.size(); ++nwh) {1006 for (uint32_t nwh = 0; nwh < warehouses_.size(); ++nwh) {
1007 Warehouse* wh = warehouses_[nwh];1007 Warehouse* wh = warehouses_[nwh];
1008 Warehouse::StockPolicy policy = wh->get_stock_policy(type, ware);1008 StockPolicy policy = wh->get_stock_policy(type, ware);
1009 if (policy == Warehouse::StockPolicy::kPrefer) {1009 if (policy == StockPolicy::kPrefer) {
1010 haveprefer = true;1010 haveprefer = true;
10111011
1012 // Getting count of worker/ware1012 // Getting count of worker/ware
@@ -1022,7 +1022,7 @@
1022 preferred_wh_stock = current_stock;1022 preferred_wh_stock = current_stock;
1023 }1023 }
1024 }1024 }
1025 if (policy == Warehouse::StockPolicy::kNormal)1025 if (policy == StockPolicy::kNormal)
1026 havenormal = true;1026 havenormal = true;
1027 }1027 }
1028 if (!havenormal && !haveprefer && type == wwWARE)1028 if (!havenormal && !haveprefer && type == wwWARE)
@@ -1037,7 +1037,7 @@
1037 (!havenormal) ?1037 (!havenormal) ?
1038 WarehouseAcceptFn() :1038 WarehouseAcceptFn() :
1039 boost::bind(&accept_warehouse_if_policy, _1, type, ware,1039 boost::bind(&accept_warehouse_if_policy, _1, type, ware,
1040 Warehouse::StockPolicy::kNormal));1040 StockPolicy::kNormal));
1041 }1041 }
1042 if (!wh) {1042 if (!wh) {
1043 log("Warning: Economy::handle_active_supplies "1043 log("Warning: Economy::handle_active_supplies "
10441044
=== modified file 'src/economy/request.cc'
--- src/economy/request.cc 2019-06-13 17:32:28 +0000
+++ src/economy/request.cc 2019-06-19 09:23:26 +0000
@@ -266,7 +266,7 @@
266int32_t Request::get_priority(int32_t cost) const {266int32_t Request::get_priority(int32_t cost) const {
267 int MAX_IDLE_PRIORITY = 100;267 int MAX_IDLE_PRIORITY = 100;
268 bool is_construction_site = false;268 bool is_construction_site = false;
269 int32_t modifier = DEFAULT_PRIORITY;269 int32_t modifier = kPriorityNormal;
270270
271 if (target_building_) {271 if (target_building_) {
272 modifier = target_building_->get_priority(get_type(), get_index());272 modifier = target_building_->get_priority(get_type(), get_index());
273273
=== modified file 'src/logic/editor_game_base.cc'
--- src/logic/editor_game_base.cc 2019-04-26 05:52:49 +0000
+++ src/logic/editor_game_base.cc 2019-06-19 09:23:26 +0000
@@ -38,6 +38,7 @@
38#include "logic/map_objects/map_object.h"38#include "logic/map_objects/map_object.h"
39#include "logic/map_objects/tribes/battle.h"39#include "logic/map_objects/tribes/battle.h"
40#include "logic/map_objects/tribes/building.h"40#include "logic/map_objects/tribes/building.h"
41#include "logic/map_objects/tribes/constructionsite.h"
41#include "logic/map_objects/tribes/dismantlesite.h"42#include "logic/map_objects/tribes/dismantlesite.h"
42#include "logic/map_objects/tribes/tribe_descr.h"43#include "logic/map_objects/tribes/tribe_descr.h"
43#include "logic/map_objects/tribes/tribes.h"44#include "logic/map_objects/tribes/tribes.h"
@@ -349,10 +350,15 @@
349 PlayerNumber const owner,350 PlayerNumber const owner,
350 DescriptionIndex idx,351 DescriptionIndex idx,
351 bool loading,352 bool loading,
352 Building::FormerBuildings former_buildings) {353 Building::FormerBuildings former_buildings,
354 const BuildingSettings* settings) {
353 Player* plr = get_player(owner);355 Player* plr = get_player(owner);
354 const TribeDescr& tribe = plr->tribe();356 const TribeDescr& tribe = plr->tribe();
355 return tribe.get_building_descr(idx)->create(*this, plr, c, true, loading, former_buildings);357 Building& b = tribe.get_building_descr(idx)->create(*this, plr, c, true, loading, former_buildings);
358 if (settings) {
359 dynamic_cast<ConstructionSite&>(b).apply_settings(*settings);
360 }
361 return b;
356}362}
357363
358/**364/**
359365
=== modified file 'src/logic/editor_game_base.h'
--- src/logic/editor_game_base.h 2019-02-27 19:00:36 +0000
+++ src/logic/editor_game_base.h 2019-06-19 09:23:26 +0000
@@ -56,6 +56,7 @@
56class TribeDescr;56class TribeDescr;
57struct Flag;57struct Flag;
58struct AttackController;58struct AttackController;
59struct BuildingSettings;
5960
60struct NoteFieldPossession {61struct NoteFieldPossession {
61 CAN_BE_SENT_AS_NOTE(NoteId::FieldPossession)62 CAN_BE_SENT_AS_NOTE(NoteId::FieldPossession)
@@ -130,7 +131,8 @@
130 PlayerNumber,131 PlayerNumber,
131 DescriptionIndex,132 DescriptionIndex,
132 bool loading = false,133 bool loading = false,
133 Building::FormerBuildings former_buildings = Building::FormerBuildings());134 Building::FormerBuildings former_buildings = Building::FormerBuildings(),
135 const BuildingSettings* settings = nullptr);
134 Building&136 Building&
135 warp_dismantlesite(const Coords&,137 warp_dismantlesite(const Coords&,
136 PlayerNumber,138 PlayerNumber,
137139
=== modified file 'src/logic/game.cc'
--- src/logic/game.cc 2019-05-25 07:36:44 +0000
+++ src/logic/game.cc 2019-06-19 09:23:26 +0000
@@ -56,6 +56,7 @@
56#include "logic/map_objects/tribes/soldier.h"56#include "logic/map_objects/tribes/soldier.h"
57#include "logic/map_objects/tribes/trainingsite.h"57#include "logic/map_objects/tribes/trainingsite.h"
58#include "logic/map_objects/tribes/tribe_descr.h"58#include "logic/map_objects/tribes/tribe_descr.h"
59#include "logic/map_objects/tribes/warehouse.h"
59#include "logic/player.h"60#include "logic/player.h"
60#include "logic/playercommand.h"61#include "logic/playercommand.h"
61#include "logic/replay.h"62#include "logic/replay.h"
@@ -775,8 +776,7 @@
775}776}
776777
777void Game::send_player_enhance_building(Building& building, DescriptionIndex const id) {778void Game::send_player_enhance_building(Building& building, DescriptionIndex const id) {
778 assert(building.owner().tribe().has_building(id));779 assert(building.descr().type() == MapObjectType::CONSTRUCTIONSITE || building.owner().tribe().has_building(id));
779
780 send_player_command(780 send_player_command(
781 new CmdEnhanceBuilding(get_gametime(), building.owner().player_number(), building, id));781 new CmdEnhanceBuilding(get_gametime(), building.owner().player_number(), building, id));
782}782}
@@ -858,6 +858,11 @@
858 new CmdProposeTrade(get_gametime(), object->get_owner()->player_number(), trade));858 new CmdProposeTrade(get_gametime(), object->get_owner()->player_number(), trade));
859}859}
860860
861void Game::send_player_set_stock_policy(Building& imm, WareWorker ww, DescriptionIndex di, StockPolicy sp) {
862 send_player_command(new CmdSetStockPolicy(get_gametime(), imm.get_owner()->player_number(),
863 imm, ww == wwWORKER, di, sp));
864}
865
861int Game::propose_trade(const Trade& trade) {866int Game::propose_trade(const Trade& trade) {
862 // TODO(sirver,trading): Check if a trade is possible (i.e. if there is a867 // TODO(sirver,trading): Check if a trade is possible (i.e. if there is a
863 // path between the two markets);868 // path between the two markets);
864869
=== modified file 'src/logic/game.h'
--- src/logic/game.h 2019-05-25 07:36:44 +0000
+++ src/logic/game.h 2019-06-19 09:23:26 +0000
@@ -46,6 +46,7 @@
46// See forester_cache_46// See forester_cache_
47constexpr int16_t kInvalidForesterEntry = -1;47constexpr int16_t kInvalidForesterEntry = -1;
4848
49class ConstructionSite;
49struct Flag;50struct Flag;
50struct Path;51struct Path;
51struct PlayerImmovable;52struct PlayerImmovable;
@@ -56,6 +57,7 @@
56struct PlayerEndStatus;57struct PlayerEndStatus;
57class TrainingSite;58class TrainingSite;
58class MilitarySite;59class MilitarySite;
60enum class StockPolicy;
5961
60enum {62enum {
61 gs_notrunning = 0, // game is being prepared63 gs_notrunning = 0, // game is being prepared
@@ -262,6 +264,7 @@
262264
263 void send_player_enhance_building(Building&, DescriptionIndex);265 void send_player_enhance_building(Building&, DescriptionIndex);
264 void send_player_evict_worker(Worker&);266 void send_player_evict_worker(Worker&);
267 void send_player_set_stock_policy(Building&, WareWorker, DescriptionIndex, StockPolicy);
265 void send_player_set_ware_priority(PlayerImmovable&,268 void send_player_set_ware_priority(PlayerImmovable&,
266 int32_t type,269 int32_t type,
267 DescriptionIndex index,270 DescriptionIndex index,
268271
=== modified file 'src/logic/map_objects/CMakeLists.txt'
--- src/logic/map_objects/CMakeLists.txt 2019-05-12 07:45:59 +0000
+++ src/logic/map_objects/CMakeLists.txt 2019-06-19 09:23:26 +0000
@@ -49,6 +49,8 @@
49 tribes/bill_of_materials.h49 tribes/bill_of_materials.h
50 tribes/building.cc50 tribes/building.cc
51 tribes/building.h51 tribes/building.h
52 tribes/building_settings.cc
53 tribes/building_settings.h
52 tribes/carrier.cc54 tribes/carrier.cc
53 tribes/carrier.h55 tribes/carrier.h
54 tribes/constructionsite.cc56 tribes/constructionsite.cc
5557
=== modified file 'src/logic/map_objects/tribes/bill_of_materials.h'
--- src/logic/map_objects/tribes/bill_of_materials.h 2019-02-23 11:00:49 +0000
+++ src/logic/map_objects/tribes/bill_of_materials.h 2019-06-19 09:23:26 +0000
@@ -28,29 +28,6 @@
28using WareAmount = std::pair<DescriptionIndex, Widelands::Quantity>;28using WareAmount = std::pair<DescriptionIndex, Widelands::Quantity>;
29using BillOfMaterials = std::vector<WareAmount>;29using BillOfMaterials = std::vector<WareAmount>;
3030
31// range structure for iterating ware range with index
32struct WareRange {
33 explicit WareRange(const BillOfMaterials& range)
34 : i(0), current(range.begin()), end(range.end()) {
35 }
36 WareRange& operator++() {
37 ++i;
38 ++current;
39 return *this;
40 }
41 bool empty() const {
42 return current == end;
43 }
44 operator bool() const {
45 return !empty();
46 }
47
48 uint8_t i;
49 BillOfMaterials::const_iterator current;
50
51private:
52 BillOfMaterials::const_iterator const end;
53};
54} // namespace Widelands31} // namespace Widelands
5532
56#endif // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_BILL_OF_MATERIALS_H33#endif // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_BILL_OF_MATERIALS_H
5734
=== modified file 'src/logic/map_objects/tribes/building.cc'
--- src/logic/map_objects/tribes/building.cc 2019-05-26 17:21:15 +0000
+++ src/logic/map_objects/tribes/building.cc 2019-06-19 09:23:26 +0000
@@ -638,13 +638,13 @@
638638
639int32_t639int32_t
640Building::get_priority(WareWorker type, DescriptionIndex const ware_index, bool adjust) const {640Building::get_priority(WareWorker type, DescriptionIndex const ware_index, bool adjust) const {
641 int32_t priority = DEFAULT_PRIORITY;641 int32_t priority = kPriorityNormal;
642 if (type == wwWARE) {642 if (type == wwWARE) {
643 // if priority is defined for specific ware,643 // if priority is defined for specific ware,
644 // combine base priority and ware priority644 // combine base priority and ware priority
645 std::map<DescriptionIndex, int32_t>::const_iterator it = ware_priorities_.find(ware_index);645 std::map<DescriptionIndex, int32_t>::const_iterator it = ware_priorities_.find(ware_index);
646 if (it != ware_priorities_.end())646 if (it != ware_priorities_.end())
647 priority = adjust ? (priority * it->second / DEFAULT_PRIORITY) : it->second;647 priority = adjust ? (priority * it->second / kPriorityNormal) : it->second;
648 }648 }
649649
650 return priority;650 return priority;
@@ -660,7 +660,7 @@
660 std::map<DescriptionIndex, int32_t>& ware_priorities = p[wwWARE];660 std::map<DescriptionIndex, int32_t>& ware_priorities = p[wwWARE];
661 std::map<DescriptionIndex, int32_t>::const_iterator it;661 std::map<DescriptionIndex, int32_t>::const_iterator it;
662 for (it = ware_priorities_.begin(); it != ware_priorities_.end(); ++it) {662 for (it = ware_priorities_.begin(); it != ware_priorities_.end(); ++it) {
663 if (it->second == DEFAULT_PRIORITY)663 if (it->second == kPriorityNormal)
664 continue;664 continue;
665 ware_priorities[it->first] = it->second;665 ware_priorities[it->first] = it->second;
666 }666 }
667667
=== modified file 'src/logic/map_objects/tribes/building.h'
--- src/logic/map_objects/tribes/building.h 2019-05-11 12:37:45 +0000
+++ src/logic/map_objects/tribes/building.h 2019-06-19 09:23:26 +0000
@@ -31,6 +31,7 @@
31#include "logic/map_objects/buildcost.h"31#include "logic/map_objects/buildcost.h"
32#include "logic/map_objects/immovable.h"32#include "logic/map_objects/immovable.h"
33#include "logic/map_objects/tribes/attack_target.h"33#include "logic/map_objects/tribes/attack_target.h"
34#include "logic/map_objects/tribes/building_settings.h"
34#include "logic/map_objects/tribes/bill_of_materials.h"35#include "logic/map_objects/tribes/bill_of_materials.h"
35#include "logic/map_objects/tribes/soldiercontrol.h"36#include "logic/map_objects/tribes/soldiercontrol.h"
36#include "logic/map_objects/tribes/wareworker.h"37#include "logic/map_objects/tribes/wareworker.h"
@@ -51,9 +52,9 @@
5152
52class Building;53class Building;
5354
54#define LOW_PRIORITY 255constexpr int32_t kPriorityLow = 2;
55#define DEFAULT_PRIORITY 456constexpr int32_t kPriorityNormal = 4;
56#define HIGH_PRIORITY 857constexpr int32_t kPriorityHigh = 8;
5758
58/*59/*
59 * Common to all buildings!60 * Common to all buildings!
@@ -266,8 +267,8 @@
266267
267 // Get/Set the priority for this waretype for this building. 'type' defines268 // Get/Set the priority for this waretype for this building. 'type' defines
268 // if this is for a worker or a ware, 'index' is the type of worker or ware.269 // if this is for a worker or a ware, 'index' is the type of worker or ware.
269 // If 'adjust' is false, the three possible states HIGH_PRIORITY,270 // If 'adjust' is false, the three possible states kPriorityHigh,
270 // DEFAULT_PRIORITY and LOW_PRIORITY are returned, otherwise numerical271 // kPriorityNormal and kPriorityLow are returned, otherwise numerical
271 // values adjusted to the preciousness of the ware in general are returned.272 // values adjusted to the preciousness of the ware in general are returned.
272 virtual int32_t get_priority(WareWorker type, DescriptionIndex, bool adjust = true) const;273 virtual int32_t get_priority(WareWorker type, DescriptionIndex, bool adjust = true) const;
273 void set_priority(int32_t type, DescriptionIndex ware_index, int32_t new_priority);274 void set_priority(int32_t type, DescriptionIndex ware_index, int32_t new_priority);
@@ -301,6 +302,10 @@
301 void add_worker(Worker&) override;302 void add_worker(Worker&) override;
302 void remove_worker(Worker&) override;303 void remove_worker(Worker&) override;
303304
305 virtual const BuildingSettings* create_building_settings() const {
306 return nullptr;
307 }
308
304 // AttackTarget object associated with this building. If the building can309 // AttackTarget object associated with this building. If the building can
305 // never be attacked (for example productionsites) this will be nullptr.310 // never be attacked (for example productionsites) this will be nullptr.
306 const AttackTarget* attack_target() const {311 const AttackTarget* attack_target() const {
307312
=== added file 'src/logic/map_objects/tribes/building_settings.cc'
--- src/logic/map_objects/tribes/building_settings.cc 1970-01-01 00:00:00 +0000
+++ src/logic/map_objects/tribes/building_settings.cc 2019-06-19 09:23:26 +0000
@@ -0,0 +1,346 @@
1/*
2 * Copyright (C) 2002-2019 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#include "logic/map_objects/tribes/building_settings.h"
21
22#include "io/fileread.h"
23#include "io/filewrite.h"
24#include "logic/game.h"
25#include "logic/game_data_error.h"
26#include "logic/map_objects/tribes/militarysite.h"
27#include "logic/map_objects/tribes/productionsite.h"
28#include "logic/map_objects/tribes/trainingsite.h"
29#include "logic/map_objects/tribes/tribe_descr.h"
30#include "logic/map_objects/tribes/warehouse.h"
31
32namespace Widelands {
33
34ProductionsiteSettings::ProductionsiteSettings(const ProductionSiteDescr& descr)
35 : BuildingSettings(descr.name()), stopped(false) {
36 for (const auto& pair : descr.input_wares()) {
37 ware_queues.push_back(std::make_pair(pair.first,
38 InputQueueSetting{pair.second, pair.second, kPriorityNormal}));
39 }
40 for (const auto& pair : descr.input_workers()) {
41 worker_queues.push_back(std::make_pair(pair.first,
42 InputQueueSetting{pair.second, pair.second, kPriorityNormal}));
43 }
44}
45
46MilitarysiteSettings::MilitarysiteSettings(const MilitarySiteDescr& descr)
47 : BuildingSettings(descr.name()),
48 max_capacity(descr.get_max_number_of_soldiers()),
49 desired_capacity(descr.get_max_number_of_soldiers()),
50 prefer_heroes(descr.prefers_heroes_at_start_) {
51}
52
53TrainingsiteSettings::TrainingsiteSettings(const TrainingSiteDescr& descr)
54 : ProductionsiteSettings(descr),
55 max_capacity(descr.get_max_number_of_soldiers()),
56 desired_capacity(descr.get_max_number_of_soldiers()) {
57}
58
59WarehouseSettings::WarehouseSettings(const WarehouseDescr& wh, const TribeDescr& tribe)
60 : BuildingSettings(wh.name()), launch_expedition_allowed(wh.get_isport()), launch_expedition(false) {
61 for (const DescriptionIndex di : tribe.wares()) {
62 ware_preferences.emplace(di, StockPolicy::kNormal);
63 }
64 for (const DescriptionIndex di : tribe.workers()) {
65 worker_preferences.emplace(di, StockPolicy::kNormal);
66 }
67 for (const DescriptionIndex di : tribe.worker_types_without_cost()) {
68 worker_preferences.erase(di);
69 }
70}
71
72void ProductionsiteSettings::apply(const BuildingSettings& bs) {
73 BuildingSettings::apply(bs);
74 if (upcast(const ProductionsiteSettings, s, &bs)) {
75 stopped = s->stopped;
76 for (auto& pair : ware_queues) {
77 for (const auto& other : s->ware_queues) {
78 if (pair.first == other.first) {
79 pair.second.priority = other.second.priority;
80 pair.second.desired_fill = std::min(pair.second.max_fill, other.second.desired_fill);
81 break;
82 }
83 }
84 }
85 for (auto& pair : worker_queues) {
86 for (const auto& other : s->worker_queues) {
87 if (pair.first == other.first) {
88 pair.second.priority = other.second.priority;
89 pair.second.desired_fill = std::min(pair.second.max_fill, other.second.desired_fill);
90 break;
91 }
92 }
93 }
94 }
95}
96
97void TrainingsiteSettings::apply(const BuildingSettings& bs) {
98 ProductionsiteSettings::apply(bs);
99 if (upcast(const TrainingsiteSettings, s, &bs)) {
100 desired_capacity = std::min(max_capacity, s->desired_capacity);
101 }
102}
103
104void MilitarysiteSettings::apply(const BuildingSettings& bs) {
105 BuildingSettings::apply(bs);
106 if (upcast(const MilitarysiteSettings, s, &bs)) {
107 desired_capacity = std::min(max_capacity, s->desired_capacity);
108 prefer_heroes = s->prefer_heroes;
109 }
110}
111
112void WarehouseSettings::apply(const BuildingSettings& bs) {
113 BuildingSettings::apply(bs);
114 if (upcast(const WarehouseSettings, s, &bs)) {
115 for (auto& pair : ware_preferences) {
116 const auto it = s->ware_preferences.find(pair.first);
117 if (it != s->ware_preferences.end()) {
118 pair.second = it->second;
119 }
120 }
121 for (auto& pair : worker_preferences) {
122 const auto it = s->worker_preferences.find(pair.first);
123 if (it != s->worker_preferences.end()) {
124 pair.second = it->second;
125 }
126 }
127 launch_expedition = launch_expedition_allowed && s->launch_expedition;
128 }
129}
130
131// Saveloading
132
133constexpr uint8_t kCurrentPacketVersion = 1;
134constexpr uint8_t kCurrentPacketVersionMilitarysite = 1;
135constexpr uint8_t kCurrentPacketVersionProductionsite = 1;
136constexpr uint8_t kCurrentPacketVersionTrainingsite = 1;
137constexpr uint8_t kCurrentPacketVersionWarehouse = 1;
138
139enum class BuildingType : uint8_t {
140 kWarehouse = 1,
141 kProductionsite = 2,
142 kTrainingsite = 3,
143 kMilitarysite = 4,
144};
145
146// static
147BuildingSettings* BuildingSettings::load(const Game& game, const TribeDescr& tribe, FileRead& fr) {
148 try {
149 const uint8_t packet_version = fr.unsigned_8();
150 if (packet_version == kCurrentPacketVersion) {
151 const std::string name(fr.c_string());
152 const DescriptionIndex index = game.tribes().building_index(name);
153 const BuildingType type = static_cast<BuildingType>(fr.unsigned_8());
154 BuildingSettings* result = nullptr;
155 switch (type) {
156 case BuildingType::kTrainingsite: {
157 result = new TrainingsiteSettings(*dynamic_cast<const TrainingSiteDescr*>(
158 game.tribes().get_building_descr(index)));
159 break;
160 }
161 case BuildingType::kProductionsite: {
162 result = new ProductionsiteSettings(*dynamic_cast<const ProductionSiteDescr*>(
163 game.tribes().get_building_descr(index)));
164 break;
165 }
166 case BuildingType::kMilitarysite: {
167 result = new MilitarysiteSettings(*dynamic_cast<const MilitarySiteDescr*>(
168 game.tribes().get_building_descr(index)));
169 break;
170 }
171 case BuildingType::kWarehouse: {
172 result = new WarehouseSettings(*dynamic_cast<const WarehouseDescr*>(
173 game.tribes().get_building_descr(index)), tribe);
174 break;
175 }
176 }
177 if (!result) {
178 throw wexception("Unknown building category %u (%s)", static_cast<uint8_t>(type), name.c_str());
179 }
180 result->read(game, fr);
181 return result;
182 } else {
183 throw UnhandledVersionError(
184 "BuildingSettings_load", packet_version, kCurrentPacketVersion);
185 }
186 } catch (const WException& e) {
187 throw GameDataError("BuildingSettings_load: %s", e.what());
188 }
189 NEVER_HERE();
190}
191
192void BuildingSettings::read(const Game&, FileRead&) {
193 // Header was peeled away by load()
194}
195
196void BuildingSettings::save(const Game&, FileWrite& fw) const {
197 fw.unsigned_8(kCurrentPacketVersion);
198 fw.c_string(descr_.c_str());
199}
200
201void MilitarysiteSettings::read(const Game& game, FileRead& fr) {
202 BuildingSettings::read(game, fr);
203 try {
204 const uint8_t packet_version = fr.unsigned_8();
205 if (packet_version == kCurrentPacketVersionMilitarysite) {
206 desired_capacity = fr.unsigned_32();
207 prefer_heroes = fr.unsigned_8();
208 } else {
209 throw UnhandledVersionError(
210 "MilitarysiteSettings", packet_version, kCurrentPacketVersionMilitarysite);
211 }
212 } catch (const WException& e) {
213 throw GameDataError("MilitarysiteSettings: %s", e.what());
214 }
215}
216
217void MilitarysiteSettings::save(const Game& game, FileWrite& fw) const {
218 BuildingSettings::save(game, fw);
219 fw.unsigned_8(static_cast<uint8_t>(BuildingType::kMilitarysite));
220 fw.unsigned_8(kCurrentPacketVersionMilitarysite);
221
222 fw.unsigned_32(desired_capacity);
223 fw.unsigned_8(prefer_heroes ? 1 : 0);
224}
225
226void ProductionsiteSettings::read(const Game& game, FileRead& fr) {
227 BuildingSettings::read(game, fr);
228 try {
229 const uint8_t packet_version = fr.unsigned_8();
230 if (packet_version == kCurrentPacketVersionProductionsite) {
231 stopped = fr.unsigned_8();
232 const uint32_t nr_wares = fr.unsigned_32();
233 const uint32_t nr_workers = fr.unsigned_32();
234 for (uint32_t i = 0; i < nr_wares; ++i) {
235 const DescriptionIndex di = fr.unsigned_32();
236 const uint32_t fill = fr.unsigned_32();
237 const int32_t priority = fr.signed_32();
238 ware_queues.at(i).first = di;
239 ware_queues.at(i).second.desired_fill = fill;
240 ware_queues.at(i).second.priority = priority;
241 }
242 for (uint32_t i = 0; i < nr_workers; ++i) {
243 const DescriptionIndex di = fr.unsigned_32();
244 const uint32_t fill = fr.unsigned_32();
245 const int32_t priority = fr.signed_32();
246 worker_queues.at(i).first = di;
247 worker_queues.at(i).second.desired_fill = fill;
248 worker_queues.at(i).second.priority = priority;
249 }
250 } else {
251 throw UnhandledVersionError(
252 "ProductionsiteSettings", packet_version, kCurrentPacketVersionProductionsite);
253 }
254 } catch (const WException& e) {
255 throw GameDataError("ProductionsiteSettings: %s", e.what());
256 }
257}
258
259void ProductionsiteSettings::save(const Game& game, FileWrite& fw) const {
260 BuildingSettings::save(game, fw);
261 fw.unsigned_8(static_cast<uint8_t>(BuildingType::kProductionsite));
262 fw.unsigned_8(kCurrentPacketVersionProductionsite);
263
264 fw.unsigned_8(stopped ? 1 : 0);
265 fw.unsigned_32(ware_queues.size());
266 fw.unsigned_32(worker_queues.size());
267 for (const auto& pair : ware_queues) {
268 fw.unsigned_32(pair.first);
269 fw.unsigned_32(pair.second.desired_fill);
270 fw.signed_32(pair.second.priority);
271 }
272 for (const auto& pair : worker_queues) {
273 fw.unsigned_32(pair.first);
274 fw.unsigned_32(pair.second.desired_fill);
275 fw.signed_32(pair.second.priority);
276 }
277}
278
279void TrainingsiteSettings::read(const Game& game, FileRead& fr) {
280 ProductionsiteSettings::read(game, fr);
281 try {
282 const uint8_t packet_version = fr.unsigned_8();
283 if (packet_version == kCurrentPacketVersionTrainingsite) {
284 desired_capacity = fr.unsigned_32();
285 } else {
286 throw UnhandledVersionError(
287 "TrainingsiteSettings", packet_version, kCurrentPacketVersionTrainingsite);
288 }
289 } catch (const WException& e) {
290 throw GameDataError("TrainingsiteSettings: %s", e.what());
291 }
292}
293
294void TrainingsiteSettings::save(const Game& game, FileWrite& fw) const {
295 ProductionsiteSettings::save(game, fw);
296 fw.unsigned_8(static_cast<uint8_t>(BuildingType::kTrainingsite));
297 fw.unsigned_8(kCurrentPacketVersionTrainingsite);
298 fw.unsigned_32(desired_capacity);
299}
300
301void WarehouseSettings::read(const Game& game, FileRead& fr) {
302 BuildingSettings::read(game, fr);
303 try {
304 const uint8_t packet_version = fr.unsigned_8();
305 if (packet_version == kCurrentPacketVersionWarehouse) {
306 launch_expedition = fr.unsigned_8();
307 const uint32_t nr_wares = fr.unsigned_32();
308 const uint32_t nr_workers = fr.unsigned_32();
309 for (uint32_t i = 0; i < nr_wares; ++i) {
310 const DescriptionIndex di = fr.unsigned_32();
311 const uint8_t pref = fr.unsigned_8();
312 ware_preferences[di] = static_cast<StockPolicy>(pref);
313 }
314 for (uint32_t i = 0; i < nr_workers; ++i) {
315 const DescriptionIndex di = fr.unsigned_32();
316 const uint8_t pref = fr.unsigned_8();
317 worker_preferences[di] = static_cast<StockPolicy>(pref);
318 }
319 } else {
320 throw UnhandledVersionError(
321 "WarehouseSettings", packet_version, kCurrentPacketVersionWarehouse);
322 }
323 } catch (const WException& e) {
324 throw GameDataError("WarehouseSettings: %s", e.what());
325 }
326}
327
328void WarehouseSettings::save(const Game& game, FileWrite& fw) const {
329 BuildingSettings::save(game, fw);
330 fw.unsigned_8(static_cast<uint8_t>(BuildingType::kWarehouse));
331 fw.unsigned_8(kCurrentPacketVersionWarehouse);
332
333 fw.unsigned_8(launch_expedition ? 1 : 0);
334 fw.unsigned_32(ware_preferences.size());
335 fw.unsigned_32(worker_preferences.size());
336 for (const auto& pair : ware_preferences) {
337 fw.unsigned_32(pair.first);
338 fw.unsigned_8(static_cast<uint8_t>(pair.second));
339 }
340 for (const auto& pair : worker_preferences) {
341 fw.unsigned_32(pair.first);
342 fw.unsigned_8(static_cast<uint8_t>(pair.second));
343 }
344}
345
346} // namespace Widelands
0347
=== added file 'src/logic/map_objects/tribes/building_settings.h'
--- src/logic/map_objects/tribes/building_settings.h 1970-01-01 00:00:00 +0000
+++ src/logic/map_objects/tribes/building_settings.h 2019-06-19 09:23:26 +0000
@@ -0,0 +1,123 @@
1/*
2 * Copyright (C) 2002-2019 by the Widelands Development Team
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20#ifndef WL_LOGIC_MAP_OBJECTS_TRIBES_BUILDING_SETTINGS_H
21#define WL_LOGIC_MAP_OBJECTS_TRIBES_BUILDING_SETTINGS_H
22
23#include <map>
24#include <string>
25#include <vector>
26
27#include "logic/widelands.h"
28
29class FileRead;
30class FileWrite;
31
32namespace Widelands {
33
34class Game;
35class MilitarySiteDescr;
36class ProductionSiteDescr;
37enum class StockPolicy;
38class TrainingSiteDescr;
39class TribeDescr;
40class WarehouseDescr;
41
42struct BuildingSettings {
43 BuildingSettings(const std::string& name) : descr_(name) {
44 }
45 virtual ~BuildingSettings() {
46 }
47
48 static BuildingSettings* load(const Game&, const TribeDescr&, FileRead&);
49
50 virtual void save(const Game&, FileWrite&) const;
51 virtual void read(const Game&, FileRead&);
52
53 virtual void apply(const BuildingSettings&) {
54 }
55
56private:
57 const std::string descr_;
58};
59
60struct ProductionsiteSettings : public BuildingSettings {
61 ProductionsiteSettings(const ProductionSiteDescr& descr);
62 ~ProductionsiteSettings() override {
63 }
64 void apply(const BuildingSettings&) override;
65
66 void save(const Game&, FileWrite&) const override;
67 void read(const Game&, FileRead&) override;
68
69 struct InputQueueSetting {
70 const uint32_t max_fill;
71 uint32_t desired_fill;
72 int32_t priority;
73 };
74 std::vector<std::pair<DescriptionIndex, InputQueueSetting>> ware_queues;
75 std::vector<std::pair<DescriptionIndex, InputQueueSetting>> worker_queues;
76 bool stopped;
77};
78
79struct MilitarysiteSettings : public BuildingSettings {
80 MilitarysiteSettings(const MilitarySiteDescr&);
81 ~MilitarysiteSettings() override {
82 }
83 void apply(const BuildingSettings&) override;
84
85 void save(const Game&, FileWrite&) const override;
86 void read(const Game&, FileRead&) override;
87
88 const uint32_t max_capacity;
89 uint32_t desired_capacity;
90 bool prefer_heroes;
91};
92
93struct TrainingsiteSettings : public ProductionsiteSettings {
94 TrainingsiteSettings(const TrainingSiteDescr&);
95 ~TrainingsiteSettings() override {
96 }
97 void apply(const BuildingSettings&) override;
98
99 void save(const Game&, FileWrite&) const override;
100 void read(const Game&, FileRead&) override;
101
102 const uint32_t max_capacity;
103 uint32_t desired_capacity;
104};
105
106struct WarehouseSettings : public BuildingSettings {
107 WarehouseSettings(const WarehouseDescr&, const TribeDescr&);
108 ~WarehouseSettings() override {
109 }
110 void apply(const BuildingSettings&) override;
111
112 void save(const Game&, FileWrite&) const override;
113 void read(const Game&, FileRead&) override;
114
115 std::map<DescriptionIndex, StockPolicy> ware_preferences;
116 std::map<DescriptionIndex, StockPolicy> worker_preferences;
117 const bool launch_expedition_allowed;
118 bool launch_expedition;
119};
120
121} // namespace Widelands
122
123#endif // end of include guard: WL_LOGIC_MAP_OBJECTS_TRIBES_BUILDING_SETTINGS_H
0124
=== modified file 'src/logic/map_objects/tribes/constructionsite.cc'
--- src/logic/map_objects/tribes/constructionsite.cc 2019-05-26 17:21:15 +0000
+++ src/logic/map_objects/tribes/constructionsite.cc 2019-06-19 09:23:26 +0000
@@ -32,6 +32,11 @@
32#include "graphic/rendertarget.h"32#include "graphic/rendertarget.h"
33#include "logic/editor_game_base.h"33#include "logic/editor_game_base.h"
34#include "logic/game.h"34#include "logic/game.h"
35#include "logic/game_data_error.h"
36#include "logic/map_objects/tribes/militarysite.h"
37#include "logic/map_objects/tribes/partially_finished_building.h"
38#include "logic/map_objects/tribes/productionsite.h"
39#include "logic/map_objects/tribes/trainingsite.h"
35#include "logic/map_objects/tribes/tribe_descr.h"40#include "logic/map_objects/tribes/tribe_descr.h"
36#include "logic/map_objects/tribes/worker.h"41#include "logic/map_objects/tribes/worker.h"
37#include "sound/note_sound.h"42#include "sound/note_sound.h"
@@ -46,32 +51,61 @@
46 const RGBColor& player_color,51 const RGBColor& player_color,
47 RenderTarget* dst) const {52 RenderTarget* dst) const {
48 // Draw the construction site marker53 // Draw the construction site marker
49 const uint32_t anim_idx = becomes->is_animation_known("build") ?54 std::vector<std::pair<uint32_t, uint32_t>> animations;
50 becomes->get_animation("build", nullptr) :55 uint32_t total_frames = 0;
51 becomes->get_unoccupied_animation();56 auto push_animation = [](const BuildingDescr* d, std::vector<std::pair<uint32_t, uint32_t>>* anims, uint32_t* tf) {
5257 const bool known = d->is_animation_known("build");
53 const Animation& anim = g_gr->animations().get_animation(anim_idx);58 const uint32_t anim_idx = known ?
54 const size_t nr_frames = anim.nr_frames();59 d->get_animation("build", nullptr) :
55 const uint32_t cur_frame = totaltime ? completedtime * nr_frames / totaltime : 0;60 d->get_unoccupied_animation();
56 uint32_t anim_time = cur_frame * FRAME_LENGTH;61 // If there is no build animation, we use only the first frame or we
5762 // would get many build steps with almost the same image...
58 if (cur_frame) { // not the first pic63 const uint32_t nrframes = known ? g_gr->animations().get_animation(anim_idx).nr_frames() : 1;
59 // Draw the complete prev pic , so we won't run into trouble if images have different sizes64 assert(nrframes);
60 dst->blit_animation(point_on_dst, Widelands::Coords::null(), scale, anim_idx,65 *tf += nrframes;
61 anim_time - FRAME_LENGTH, &player_color);66 anims->push_back(std::make_pair(anim_idx, nrframes));
67 };
68 for (const BuildingDescr* d : intermediates) {
69 push_animation(d, &animations, &total_frames);
70 }
71 push_animation(becomes, &animations, &total_frames);
72
73 uint32_t frame_index = totaltime ? std::min(completedtime * total_frames / totaltime, total_frames - 1) : 0;
74 uint32_t animation_index = 0;
75 while (frame_index >= animations[animation_index].second) {
76 frame_index -= animations[animation_index].second;
77 ++animation_index;
78 assert(animation_index < animations.size());
79 }
80 const uint32_t anim_time = frame_index * FRAME_LENGTH;
81
82 if (frame_index > 0) {
83 // Not the first pic within this animation – draw the previous one
84 dst->blit_animation(point_on_dst, Widelands::Coords::null(), scale,
85 animations[animation_index].first, anim_time - FRAME_LENGTH, &player_color);
86 } else if (animation_index > 0) {
87 // The first pic, but not the first series of animations – draw the last pic of the previous series
88 dst->blit_animation(point_on_dst, Widelands::Coords::null(), scale,
89 animations[animation_index - 1].first,
90 FRAME_LENGTH * (animations[animation_index - 1].second - 1), &player_color);
62 } else if (was) {91 } else if (was) {
63 // Is the first picture but there was another building here before,92 // First pic in first series, but there was another building here before –
64 // get its most fitting picture and draw it instead.93 // get its most fitting picture and draw it instead
65 dst->blit_animation(point_on_dst, Widelands::Coords::null(), scale,94 const uint32_t unocc = was->get_unoccupied_animation();
66 was->get_unoccupied_animation(), anim_time - FRAME_LENGTH, &player_color);95 dst->blit_animation(point_on_dst, Widelands::Coords::null(), scale, unocc,
96 FRAME_LENGTH * (g_gr->animations().get_animation(unocc).nr_frames() - 1),
97 &player_color);
67 }98 }
68 // Now blit a segment of the current construction phase from the bottom.99 // Now blit a segment of the current construction phase from the bottom.
69 int percent = 100 * completedtime * nr_frames;100 int percent = 100 * completedtime * total_frames;
70 if (totaltime) {101 if (totaltime) {
71 percent /= totaltime;102 percent /= totaltime;
72 }103 }
73 percent -= 100 * cur_frame;104 percent -= 100 * frame_index;
74 dst->blit_animation(point_on_dst, coords, scale, anim_idx, anim_time, &player_color, percent);105 for (uint32_t i = 0; i < animation_index; ++i) {
106 percent -= 100 * animations[i].second;
107 }
108 dst->blit_animation(point_on_dst, coords, scale, animations[animation_index].first, anim_time, &player_color, percent);
75}109}
76110
77/**111/**
@@ -104,7 +138,7 @@
104*/138*/
105139
106ConstructionSite::ConstructionSite(const ConstructionSiteDescr& cs_descr)140ConstructionSite::ConstructionSite(const ConstructionSiteDescr& cs_descr)
107 : PartiallyFinishedBuilding(cs_descr), fetchfromflag_(0), builder_idle_(false) {141 : PartiallyFinishedBuilding(cs_descr), fetchfromflag_(0), builder_idle_(false), settings_(nullptr) {
108}142}
109143
110void ConstructionSite::update_statistics_string(std::string* s) {144void ConstructionSite::update_statistics_string(std::string* s) {
@@ -181,9 +215,30 @@
181215
182 work_steps_ += it->second;216 work_steps_ += it->second;
183 }217 }
218
219 init_settings();
220
184 return true;221 return true;
185}222}
186223
224void ConstructionSite::init_settings() {
225 assert(building_);
226 assert(!settings_);
227 if (upcast(const WarehouseDescr, wd, building_)) {
228 settings_.reset(new WarehouseSettings(*wd, owner().tribe()));
229 } else if (upcast(const TrainingSiteDescr, td, building_)) {
230 settings_.reset(new TrainingsiteSettings(*td));
231 } else if (upcast(const ProductionSiteDescr, pd, building_)) {
232 settings_.reset(new ProductionsiteSettings(*pd));
233 } else if (upcast(const MilitarySiteDescr, md, building_)) {
234 settings_.reset(new MilitarysiteSettings(*md));
235 } else {
236 // TODO(Nordfriese): Add support for markets when trading is implemented
237 log("WARNING: Created constructionsite for a %s, which is not of any known building type\n",
238 building_->name().c_str());
239 }
240}
241
187/*242/*
188===============243===============
189Release worker and material (if any is left).244Release worker and material (if any is left).
@@ -207,6 +262,52 @@
207 builder->reset_tasks(dynamic_cast<Game&>(egbase));262 builder->reset_tasks(dynamic_cast<Game&>(egbase));
208 builder->set_location(&b);263 builder->set_location(&b);
209 }264 }
265
266 // Apply settings
267 if (settings_) {
268 if (upcast(ProductionsiteSettings, ps, settings_.get())) {
269 for (const auto& pair : ps->ware_queues) {
270 b.inputqueue(pair.first, wwWARE).set_max_fill(pair.second.desired_fill);
271 b.set_priority(wwWARE, pair.first, pair.second.priority);
272 }
273 for (const auto& pair : ps->worker_queues) {
274 b.inputqueue(pair.first, wwWORKER).set_max_fill(pair.second.desired_fill);
275 b.set_priority(wwWORKER, pair.first, pair.second.priority);
276 }
277 if (upcast(TrainingsiteSettings, ts, ps)) {
278 assert(b.soldier_control());
279 assert(ts->desired_capacity >= b.soldier_control()->min_soldier_capacity());
280 assert(ts->desired_capacity <= b.soldier_control()->max_soldier_capacity());
281 if (ts->desired_capacity != b.soldier_control()->soldier_capacity()) {
282 b.mutable_soldier_control()->set_soldier_capacity(ts->desired_capacity);
283 }
284 }
285 dynamic_cast<ProductionSite&>(b).set_stopped(ps->stopped);
286 } else if (upcast(MilitarysiteSettings, ms, settings_.get())) {
287 assert(b.soldier_control());
288 assert(ms->desired_capacity >= b.soldier_control()->min_soldier_capacity());
289 assert(ms->desired_capacity <= b.soldier_control()->max_soldier_capacity());
290 if (ms->desired_capacity != b.soldier_control()->soldier_capacity()) {
291 b.mutable_soldier_control()->set_soldier_capacity(ms->desired_capacity);
292 }
293 dynamic_cast<MilitarySite&>(b).set_soldier_preference(ms->prefer_heroes ?
294 SoldierPreference::kHeroes : SoldierPreference::kRookies);
295 } else if (upcast(WarehouseSettings, ws, settings_.get())) {
296 Warehouse& site = dynamic_cast<Warehouse&>(b);
297 for (const auto& pair : ws->ware_preferences) {
298 site.set_ware_policy(pair.first, pair.second);
299 }
300 for (const auto& pair : ws->worker_preferences) {
301 site.set_worker_policy(pair.first, pair.second);
302 }
303 if (ws->launch_expedition) {
304 get_owner()->start_or_cancel_expedition(site);
305 }
306 } else {
307 NEVER_HERE();
308 }
309 }
310
210 // Open the new building window if needed311 // Open the new building window if needed
211 Notifications::publish(NoteBuilding(b.serial(), NoteBuilding::Action::kFinishWarp));312 Notifications::publish(NoteBuilding(b.serial(), NoteBuilding::Action::kFinishWarp));
212 }313 }
@@ -214,6 +315,138 @@
214315
215/*316/*
216===============317===============
318Start building the next enhancement even before the base building is completed.
319===============
320*/
321void ConstructionSite::enhance(Game&) {
322 assert(building_->enhancement() != INVALID_INDEX);
323 Notifications::publish(NoteImmovable(this, NoteImmovable::Ownership::LOST));
324
325 info_.intermediates.push_back(building_);
326 old_buildings_.push_back(owner().tribe().building_index(building_->name()));
327 building_ = owner().tribe().get_building_descr(building_->enhancement());
328 assert(building_);
329 info_.becomes = building_;
330
331 const std::map<DescriptionIndex, uint8_t>& buildcost = building_->enhancement_cost();
332 std::set<DescriptionIndex> new_ware_types;
333 for (const auto& pair : buildcost) {
334 bool found = false;
335 for (const auto& queue : wares_) {
336 if (queue->get_index() == pair.first) {
337 found = true;
338 break;
339 }
340 }
341 if (!found) {
342 new_ware_types.insert(pair.first);
343 }
344 }
345
346 const size_t old_size = wares_.size();
347 wares_.resize(old_size + new_ware_types.size());
348
349 size_t new_index = 0;
350 for (const auto& pair : buildcost) {
351 if (new_ware_types.count(pair.first)) {
352 WaresQueue& wq = *(wares_[old_size + new_index] = new WaresQueue(*this, pair.first, pair.second));
353 wq.set_callback(ConstructionSite::wares_queue_callback, this);
354 wq.set_consume_interval(CONSTRUCTIONSITE_STEP_TIME);
355 ++new_index;
356 } else {
357 for (size_t i = 0; i < old_size; ++i) {
358 WaresQueue& wq = *wares_[i];
359 if (wq.get_index() == pair.first) {
360 wq.set_max_size(wq.get_max_size() + pair.second);
361 wq.set_max_fill(wq.get_max_fill() + pair.second);
362 break;
363 }
364 }
365 }
366 work_steps_ += pair.second;
367 }
368
369 BuildingSettings* old_settings = settings_.release();
370 if (upcast(const WarehouseDescr, wd, building_)) {
371 upcast(WarehouseSettings, ws, old_settings);
372 assert(ws);
373 WarehouseSettings* new_settings = new WarehouseSettings(*wd, owner().tribe());
374 settings_.reset(new_settings);
375 for (const auto& pair : ws->ware_preferences) {
376 new_settings->ware_preferences[pair.first] = pair.second;
377 }
378 for (const auto& pair : ws->worker_preferences) {
379 new_settings->worker_preferences[pair.first] = pair.second;
380 }
381 new_settings->launch_expedition = ws->launch_expedition && building_->get_isport();
382 } else if (upcast(const TrainingSiteDescr, td, building_)) {
383 upcast(TrainingsiteSettings, ts, old_settings);
384 assert(ts);
385 TrainingsiteSettings* new_settings = new TrainingsiteSettings(*td);
386 settings_.reset(new_settings);
387 new_settings->stopped = ts->stopped;
388 for (const auto& pair_old : ts->ware_queues) {
389 for (auto& pair_new : new_settings->ware_queues) {
390 if (pair_new.first == pair_old.first) {
391 pair_new.second.priority = pair_old.second.priority;
392 pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
393 break;
394 }
395 }
396 }
397 for (const auto& pair_old : ts->worker_queues) {
398 for (auto& pair_new : new_settings->worker_queues) {
399 if (pair_new.first == pair_old.first) {
400 pair_new.second.priority = pair_old.second.priority;
401 pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
402 break;
403 }
404 }
405 }
406 new_settings->desired_capacity = std::min(new_settings->max_capacity, ts->desired_capacity);
407 } else if (upcast(const ProductionSiteDescr, pd, building_)) {
408 upcast(ProductionsiteSettings, ps, old_settings);
409 assert(ps);
410 ProductionsiteSettings* new_settings = new ProductionsiteSettings(*pd);
411 settings_.reset(new_settings);
412 new_settings->stopped = ps->stopped;
413 for (const auto& pair_old : ps->ware_queues) {
414 for (auto& pair_new : new_settings->ware_queues) {
415 if (pair_new.first == pair_old.first) {
416 pair_new.second.priority = pair_old.second.priority;
417 pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
418 break;
419 }
420 }
421 }
422 for (const auto& pair_old : ps->worker_queues) {
423 for (auto& pair_new : new_settings->worker_queues) {
424 if (pair_new.first == pair_old.first) {
425 pair_new.second.priority = pair_old.second.priority;
426 pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
427 break;
428 }
429 }
430 }
431 } else if (upcast(const MilitarySiteDescr, md, building_)) {
432 upcast(MilitarysiteSettings, ms, old_settings);
433 assert(ms);
434 MilitarysiteSettings* new_settings = new MilitarysiteSettings(*md);
435 settings_.reset(new_settings);
436 new_settings->desired_capacity = std::max<uint32_t>(1, std::min<uint32_t>(
437 new_settings->max_capacity, ms->desired_capacity));
438 new_settings->prefer_heroes = ms->prefer_heroes;
439 } else {
440 // TODO(Nordfriese): Add support for markets when trading is implemented
441 log("WARNING: Enhanced constructionsite to a %s, which is not of any known building type\n",
442 building_->name().c_str());
443 }
444 Notifications::publish(NoteImmovable(this, NoteImmovable::Ownership::GAINED));
445 Notifications::publish(NoteBuilding(serial(), NoteBuilding::Action::kChanged));
446}
447
448/*
449===============
217Construction sites only burn if some of the work has been completed.450Construction sites only burn if some of the work has been completed.
218===============451===============
219*/452*/
@@ -343,6 +576,17 @@
343576
344/*577/*
345===============578===============
579Overwrite as many values of the current settings with those of the given settings as possible.
580===============
581*/
582void ConstructionSite::apply_settings(const BuildingSettings& cs) {
583 assert(settings_);
584 settings_->apply(cs);
585 delete &cs;
586}
587
588/*
589===============
346Draw the construction site.590Draw the construction site.
347===============591===============
348*/592*/
349593
=== modified file 'src/logic/map_objects/tribes/constructionsite.h'
--- src/logic/map_objects/tribes/constructionsite.h 2019-05-05 14:05:07 +0000
+++ src/logic/map_objects/tribes/constructionsite.h 2019-06-19 09:23:26 +0000
@@ -20,16 +20,26 @@
20#ifndef WL_LOGIC_MAP_OBJECTS_TRIBES_CONSTRUCTIONSITE_H20#ifndef WL_LOGIC_MAP_OBJECTS_TRIBES_CONSTRUCTIONSITE_H
21#define WL_LOGIC_MAP_OBJECTS_TRIBES_CONSTRUCTIONSITE_H21#define WL_LOGIC_MAP_OBJECTS_TRIBES_CONSTRUCTIONSITE_H
2222
23#include <memory>
23#include <vector>24#include <vector>
2425
25#include "base/macros.h"26#include "base/macros.h"
27#include "logic/map_objects/tribes/building_settings.h"
26#include "logic/map_objects/tribes/partially_finished_building.h"28#include "logic/map_objects/tribes/partially_finished_building.h"
27#include "scripting/lua_table.h"29#include "scripting/lua_table.h"
2830
31class FileRead;
32class FileWrite;
33
29namespace Widelands {34namespace Widelands {
3035
31class Building;36class Building;
37class MilitarySiteDescr;
38class ProductionSiteDescr;
32class Request;39class Request;
40enum class StockPolicy;
41class TrainingSiteDescr;
42class WarehouseDescr;
33class WaresQueue;43class WaresQueue;
3444
35/// Per-player and per-field constructionsite information45/// Per-player and per-field constructionsite information
@@ -47,6 +57,7 @@
47 const BuildingDescr*57 const BuildingDescr*
48 becomes; // Also works as a marker telling whether there is a construction site.58 becomes; // Also works as a marker telling whether there is a construction site.
49 const BuildingDescr* was; // only valid if "becomes" is an enhanced building.59 const BuildingDescr* was; // only valid if "becomes" is an enhanced building.
60 std::vector<const BuildingDescr*> intermediates; // If we enhance a building while it's still under construction
50 uint32_t totaltime;61 uint32_t totaltime;
51 uint32_t completedtime;62 uint32_t completedtime;
52};63};
@@ -114,6 +125,13 @@
114 bool fetch_from_flag(Game&) override;125 bool fetch_from_flag(Game&) override;
115 bool get_building_work(Game&, Worker&, bool success) override;126 bool get_building_work(Game&, Worker&, bool success) override;
116127
128 BuildingSettings* get_settings() const {
129 return settings_.get();
130 }
131 void apply_settings(const BuildingSettings&);
132
133 void enhance(Game&);
134
117protected:135protected:
118 void update_statistics_string(std::string* statistics_string) override;136 void update_statistics_string(std::string* statistics_string) override;
119137
@@ -135,6 +153,9 @@
135153
136 bool builder_idle_; // used to determine whether the builder is idle154 bool builder_idle_; // used to determine whether the builder is idle
137 ConstructionsiteInformation info_; // asked for by player point of view for the gameview155 ConstructionsiteInformation info_; // asked for by player point of view for the gameview
156
157 std::unique_ptr<BuildingSettings> settings_;
158 void init_settings();
138};159};
139} // namespace Widelands160} // namespace Widelands
140161
141162
=== modified file 'src/logic/map_objects/tribes/militarysite.cc'
--- src/logic/map_objects/tribes/militarysite.cc 2019-05-26 17:21:15 +0000
+++ src/logic/map_objects/tribes/militarysite.cc 2019-06-19 09:23:26 +0000
@@ -982,6 +982,13 @@
982 return false;982 return false;
983}983}
984984
985const BuildingSettings* MilitarySite::create_building_settings() const {
986 MilitarysiteSettings* settings = new MilitarysiteSettings(descr());
987 settings->desired_capacity = std::min(settings->max_capacity, soldier_control_.soldier_capacity());
988 settings->prefer_heroes = soldier_preference_ == SoldierPreference::kHeroes;
989 return settings;
990}
991
985// setters992// setters
986993
987void MilitarySite::set_soldier_preference(SoldierPreference p) {994void MilitarySite::set_soldier_preference(SoldierPreference p) {
988995
=== modified file 'src/logic/map_objects/tribes/militarysite.h'
--- src/logic/map_objects/tribes/militarysite.h 2019-05-05 14:05:07 +0000
+++ src/logic/map_objects/tribes/militarysite.h 2019-06-19 09:23:26 +0000
@@ -108,6 +108,8 @@
108 return soldier_preference_;108 return soldier_preference_;
109 }109 }
110110
111 const BuildingSettings* create_building_settings() const override;
112
111protected:113protected:
112 void conquer_area(EditorGameBase&);114 void conquer_area(EditorGameBase&);
113115
114116
=== modified file 'src/logic/map_objects/tribes/productionsite.cc'
--- src/logic/map_objects/tribes/productionsite.cc 2019-05-29 07:14:00 +0000
+++ src/logic/map_objects/tribes/productionsite.cc 2019-06-19 09:23:26 +0000
@@ -445,13 +445,12 @@
445 const BillOfMaterials& input_workers = descr().input_workers();445 const BillOfMaterials& input_workers = descr().input_workers();
446 input_queues_.resize(input_wares.size() + input_workers.size());446 input_queues_.resize(input_wares.size() + input_workers.size());
447447
448 for (WareRange i(input_wares); i; ++i) {448 size_t i = 0;
449 input_queues_[i.i] = new WaresQueue(*this, i.current->first, i.current->second);449 for (const WareAmount& pair : input_wares) {
450 input_queues_[i++] = new WaresQueue(*this, pair.first, pair.second);
450 }451 }
451452 for (const WareAmount& pair : input_workers) {
452 for (WareRange i(input_workers); i; ++i) {453 input_queues_[i++] = new WorkersQueue(*this, pair.first, pair.second);
453 input_queues_[input_wares.size() + i.i] =
454 new WorkersQueue(*this, i.current->first, i.current->second);
455 }454 }
456455
457 // Request missing workers.456 // Request missing workers.
@@ -1020,6 +1019,30 @@
1020 set_production_result("");1019 set_production_result("");
1021}1020}
10221021
1022const BuildingSettings* ProductionSite::create_building_settings() const {
1023 ProductionsiteSettings* settings = new ProductionsiteSettings(descr());
1024 settings->stopped = is_stopped_;
1025 for (auto& pair : settings->ware_queues) {
1026 pair.second.priority = get_priority(wwWARE, pair.first, false);
1027 for (const auto& queue : input_queues_) {
1028 if (queue->get_type() == wwWARE && queue->get_index() == pair.first) {
1029 pair.second.desired_fill = std::min(pair.second.max_fill, queue->get_max_fill());
1030 break;
1031 }
1032 }
1033 }
1034 for (auto& pair : settings->worker_queues) {
1035 pair.second.priority = get_priority(wwWORKER, pair.first, false);
1036 for (const auto& queue : input_queues_) {
1037 if (queue->get_type() == wwWORKER && queue->get_index() == pair.first) {
1038 pair.second.desired_fill = std::min(pair.second.max_fill, queue->get_max_fill());
1039 break;
1040 }
1041 }
1042 }
1043 return settings;
1044}
1045
1023/// Changes the default anim string to \li anim1046/// Changes the default anim string to \li anim
1024void ProductionSite::set_default_anim(std::string anim) {1047void ProductionSite::set_default_anim(std::string anim) {
1025 if (default_anim_ == anim)1048 if (default_anim_ == anim)
10261049
=== modified file 'src/logic/map_objects/tribes/productionsite.h'
--- src/logic/map_objects/tribes/productionsite.h 2019-05-28 21:04:36 +0000
+++ src/logic/map_objects/tribes/productionsite.h 2019-06-19 09:23:26 +0000
@@ -241,6 +241,8 @@
241241
242 void set_default_anim(std::string);242 void set_default_anim(std::string);
243243
244 const BuildingSettings* create_building_settings() const override;
245
244protected:246protected:
245 void update_statistics_string(std::string* statistics) override;247 void update_statistics_string(std::string* statistics) override;
246248
247249
=== modified file 'src/logic/map_objects/tribes/trainingsite.cc'
--- src/logic/map_objects/tribes/trainingsite.cc 2019-05-05 14:05:07 +0000
+++ src/logic/map_objects/tribes/trainingsite.cc 2019-06-19 09:23:26 +0000
@@ -525,6 +525,13 @@
525 }525 }
526}526}
527527
528const BuildingSettings* TrainingSite::create_building_settings() const {
529 TrainingsiteSettings* settings = new TrainingsiteSettings(descr());
530 settings->apply(*ProductionSite::create_building_settings());
531 settings->desired_capacity = std::min(settings->max_capacity, soldier_control_.soldier_capacity());
532 return settings;
533}
534
528/**535/**
529 * In addition to advancing the program, update soldier status.536 * In addition to advancing the program, update soldier status.
530 */537 */
531538
=== modified file 'src/logic/map_objects/tribes/trainingsite.h'
--- src/logic/map_objects/tribes/trainingsite.h 2019-05-05 14:05:07 +0000
+++ src/logic/map_objects/tribes/trainingsite.h 2019-06-19 09:23:26 +0000
@@ -199,6 +199,8 @@
199 void training_successful(TrainingAttribute type, uint32_t level);199 void training_successful(TrainingAttribute type, uint32_t level);
200 void training_done();200 void training_done();
201201
202 const BuildingSettings* create_building_settings() const override;
203
202protected:204protected:
203 void program_end(Game&, ProgramResult) override;205 void program_end(Game&, ProgramResult) override;
204206
205207
=== modified file 'src/logic/map_objects/tribes/warehouse.cc'
--- src/logic/map_objects/tribes/warehouse.cc 2019-03-01 04:19:53 +0000
+++ src/logic/map_objects/tribes/warehouse.cc 2019-06-19 09:23:26 +0000
@@ -1275,17 +1275,17 @@
1275 }1275 }
1276}1276}
12771277
1278Warehouse::StockPolicy Warehouse::get_ware_policy(DescriptionIndex ware) const {1278StockPolicy Warehouse::get_ware_policy(DescriptionIndex ware) const {
1279 assert(ware < static_cast<DescriptionIndex>(ware_policy_.size()));1279 assert(ware < static_cast<DescriptionIndex>(ware_policy_.size()));
1280 return ware_policy_[ware];1280 return ware_policy_[ware];
1281}1281}
12821282
1283Warehouse::StockPolicy Warehouse::get_worker_policy(DescriptionIndex ware) const {1283StockPolicy Warehouse::get_worker_policy(DescriptionIndex ware) const {
1284 assert(ware < static_cast<DescriptionIndex>(worker_policy_.size()));1284 assert(ware < static_cast<DescriptionIndex>(worker_policy_.size()));
1285 return worker_policy_[ware];1285 return worker_policy_[ware];
1286}1286}
12871287
1288Warehouse::StockPolicy Warehouse::get_stock_policy(WareWorker waretype,1288StockPolicy Warehouse::get_stock_policy(WareWorker waretype,
1289 DescriptionIndex wareindex) const {1289 DescriptionIndex wareindex) const {
1290 if (waretype == wwWORKER)1290 if (waretype == wwWORKER)
1291 return get_worker_policy(wareindex);1291 return get_worker_policy(wareindex);
@@ -1293,25 +1293,25 @@
1293 return get_ware_policy(wareindex);1293 return get_ware_policy(wareindex);
1294}1294}
12951295
1296void Warehouse::set_ware_policy(DescriptionIndex ware, Warehouse::StockPolicy policy) {1296void Warehouse::set_ware_policy(DescriptionIndex ware, StockPolicy policy) {
1297 assert(ware < static_cast<DescriptionIndex>(ware_policy_.size()));1297 assert(ware < static_cast<DescriptionIndex>(ware_policy_.size()));
1298 ware_policy_[ware] = policy;1298 ware_policy_[ware] = policy;
1299}1299}
13001300
1301void Warehouse::set_worker_policy(DescriptionIndex ware, Warehouse::StockPolicy policy) {1301void Warehouse::set_worker_policy(DescriptionIndex ware, StockPolicy policy) {
1302 assert(ware < static_cast<DescriptionIndex>(worker_policy_.size()));1302 assert(ware < static_cast<DescriptionIndex>(worker_policy_.size()));
1303 worker_policy_[ware] = policy;1303 worker_policy_[ware] = policy;
1304}1304}
13051305
1306/**1306/**
1307 * Check if there are remaining wares with \ref Warehouse::StockPolicy::kRemove,1307 * Check if there are remaining wares with \ref StockPolicy::kRemove,
1308 * and remove one of them if appropriate.1308 * and remove one of them if appropriate.
1309 */1309 */
1310void Warehouse::check_remove_stock(Game& game) {1310void Warehouse::check_remove_stock(Game& game) {
1311 if (base_flag().current_wares() < base_flag().total_capacity() / 2) {1311 if (base_flag().current_wares() < base_flag().total_capacity() / 2) {
1312 for (DescriptionIndex ware = 0; ware < static_cast<DescriptionIndex>(ware_policy_.size());1312 for (DescriptionIndex ware = 0; ware < static_cast<DescriptionIndex>(ware_policy_.size());
1313 ++ware) {1313 ++ware) {
1314 if (get_ware_policy(ware) != Warehouse::StockPolicy::kRemove || !get_wares().stock(ware))1314 if (get_ware_policy(ware) != StockPolicy::kRemove || !get_wares().stock(ware))
1315 continue;1315 continue;
13161316
1317 launch_ware(game, ware);1317 launch_ware(game, ware);
@@ -1321,7 +1321,7 @@
13211321
1322 for (DescriptionIndex widx = 0; widx < static_cast<DescriptionIndex>(worker_policy_.size());1322 for (DescriptionIndex widx = 0; widx < static_cast<DescriptionIndex>(worker_policy_.size());
1323 ++widx) {1323 ++widx) {
1324 if (get_worker_policy(widx) != Warehouse::StockPolicy::kRemove || !get_workers().stock(widx))1324 if (get_worker_policy(widx) != StockPolicy::kRemove || !get_workers().stock(widx))
1325 continue;1325 continue;
13261326
1327 Worker& worker = launch_worker(game, widx, Requirements());1327 Worker& worker = launch_worker(game, widx, Requirements());
@@ -1337,6 +1337,18 @@
1337 return portdock_->expedition_bootstrap()->inputqueue(index, type);1337 return portdock_->expedition_bootstrap()->inputqueue(index, type);
1338}1338}
13391339
1340const BuildingSettings* Warehouse::create_building_settings() const {
1341 WarehouseSettings* settings = new WarehouseSettings(descr(), owner().tribe());
1342 for (auto& pair : settings->ware_preferences) {
1343 pair.second = get_ware_policy(pair.first);
1344 }
1345 for (auto& pair : settings->worker_preferences) {
1346 pair.second = get_worker_policy(pair.first);
1347 }
1348 settings->launch_expedition = portdock_ && portdock_->expedition_started();
1349 return settings;
1350}
1351
1340void Warehouse::log_general_info(const EditorGameBase& egbase) const {1352void Warehouse::log_general_info(const EditorGameBase& egbase) const {
1341 Building::log_general_info(egbase);1353 Building::log_general_info(egbase);
13421354
13431355
=== modified file 'src/logic/map_objects/tribes/warehouse.h'
--- src/logic/map_objects/tribes/warehouse.h 2019-05-05 14:05:07 +0000
+++ src/logic/map_objects/tribes/warehouse.h 2019-06-19 09:23:26 +0000
@@ -68,6 +68,40 @@
68 DISALLOW_COPY_AND_ASSIGN(WarehouseDescr);68 DISALLOW_COPY_AND_ASSIGN(WarehouseDescr);
69};69};
7070
71/**
72 * Each ware and worker type has an associated per-warehouse
73 * stock policy that defines whether it will be stocked by this
74 * warehouse.
75 *
76 * \note The values of this enum are written directly into savegames,
77 * so be careful when changing them.
78 */
79enum class StockPolicy {
80 /**
81 * The default policy allows stocking wares without any special priority.
82 */
83 kNormal = 0,
84
85 /**
86 * As long as there are warehouses with this policy for a ware, all
87 * available unstocked supplies will be transferred to warehouses
88 * with this policy.
89 */
90 kPrefer = 1,
91
92 /**
93 * If a ware has this stock policy, no more of this ware will enter
94 * the warehouse.
95 */
96 kDontStock = 2,
97
98 /**
99 * Like \ref kDontStock, but in addition, existing stock of this ware
100 * will be transported out of the warehouse over time.
101 */
102 kRemove = 3,
103};
104
71class Warehouse : public Building {105class Warehouse : public Building {
72 friend class PortDock;106 friend class PortDock;
73 friend class MapBuildingdataPacket;107 friend class MapBuildingdataPacket;
@@ -75,39 +109,6 @@
75 MO_DESCR(WarehouseDescr)109 MO_DESCR(WarehouseDescr)
76110
77public:111public:
78 /**
79 * Each ware and worker type has an associated per-warehouse
80 * stock policy that defines whether it will be stocked by this
81 * warehouse.
82 *
83 * \note The values of this enum are written directly into savegames,
84 * so be careful when changing them.
85 */
86 enum class StockPolicy {
87 /**
88 * The default policy allows stocking wares without any special priority.
89 */
90 kNormal = 0,
91
92 /**
93 * As long as there are warehouses with this policy for a ware, all
94 * available unstocked supplies will be transferred to warehouses
95 * with this policy.
96 */
97 kPrefer = 1,
98
99 /**
100 * If a ware has this stock policy, no more of this ware will enter
101 * the warehouse.
102 */
103 kDontStock = 2,
104
105 /**
106 * Like \ref kDontStock, but in addition, existing stock of this ware
107 * will be transported out of the warehouse over time.
108 */
109 kRemove = 3,
110 };
111112
112 /**113 /**
113 * Whether worker indices in count_workers() have to match exactly.114 * Whether worker indices in count_workers() have to match exactly.
@@ -208,6 +209,8 @@
208 return portdock_;209 return portdock_;
209 }210 }
210211
212 const BuildingSettings* create_building_settings() const override;
213
211 // Returns the waresqueue of the expedition if this is a port.214 // Returns the waresqueue of the expedition if this is a port.
212 // Will throw an exception otherwise.215 // Will throw an exception otherwise.
213 InputQueue& inputqueue(DescriptionIndex, WareWorker) override;216 InputQueue& inputqueue(DescriptionIndex, WareWorker) override;
214217
=== modified file 'src/logic/player.cc'
--- src/logic/player.cc 2019-05-26 05:58:14 +0000
+++ src/logic/player.cc 2019-06-19 09:23:26 +0000
@@ -760,6 +760,7 @@
760 } else {760 } else {
761 workers = building->get_workers();761 workers = building->get_workers();
762 }762 }
763 const BuildingSettings* settings = building->create_building_settings();
763764
764 if (index_of_new_building != INVALID_INDEX) {765 if (index_of_new_building != INVALID_INDEX) {
765 // For enhancing, register whether the window was open766 // For enhancing, register whether the window was open
@@ -770,7 +771,7 @@
770 // pointer.771 // pointer.
771 if (index_of_new_building != INVALID_INDEX)772 if (index_of_new_building != INVALID_INDEX)
772 building = &egbase().warp_constructionsite(773 building = &egbase().warp_constructionsite(
773 position, player_number_, index_of_new_building, false, former_buildings);774 position, player_number_, index_of_new_building, false, former_buildings, settings);
774 else775 else
775 building = &egbase().warp_dismantlesite(position, player_number_, false, former_buildings);776 building = &egbase().warp_dismantlesite(position, player_number_, false, former_buildings);
776777
777778
=== modified file 'src/logic/playercommand.cc'
--- src/logic/playercommand.cc 2019-05-25 10:54:30 +0000
+++ src/logic/playercommand.cc 2019-06-19 09:23:26 +0000
@@ -486,8 +486,14 @@
486}486}
487487
488void CmdStartStopBuilding::execute(Game& game) {488void CmdStartStopBuilding::execute(Game& game) {
489 if (upcast(Building, building, game.objects().get_object(serial)))489 MapObject* mo = game.objects().get_object(serial);
490 if (upcast(ConstructionSite, cs, mo)) {
491 if (upcast(ProductionsiteSettings, s, cs->get_settings())) {
492 s->stopped = !s->stopped;
493 }
494 } else if (upcast(Building, building, mo)) {
490 game.get_player(sender())->start_stop_building(*building);495 game.get_player(sender())->start_stop_building(*building);
496 }
491}497}
492498
493void CmdStartStopBuilding::serialize(StreamWrite& ser) {499void CmdStartStopBuilding::serialize(StreamWrite& ser) {
@@ -536,8 +542,14 @@
536}542}
537543
538void CmdMilitarySiteSetSoldierPreference::execute(Game& game) {544void CmdMilitarySiteSetSoldierPreference::execute(Game& game) {
539 if (upcast(MilitarySite, building, game.objects().get_object(serial)))545 MapObject* mo = game.objects().get_object(serial);
546 if (upcast(ConstructionSite, cs, mo)) {
547 if (upcast(MilitarysiteSettings, s, cs->get_settings())) {
548 s->prefer_heroes = preference == SoldierPreference::kHeroes;
549 }
550 } else if (upcast(MilitarySite, building, mo)) {
540 game.get_player(sender())->military_site_set_soldier_preference(*building, preference);551 game.get_player(sender())->military_site_set_soldier_preference(*building, preference);
552 }
541}553}
542554
543constexpr uint16_t kCurrentPacketVersionSoldierPreference = 1;555constexpr uint16_t kCurrentPacketVersionSoldierPreference = 1;
@@ -582,8 +594,14 @@
582}594}
583595
584void CmdStartOrCancelExpedition::execute(Game& game) {596void CmdStartOrCancelExpedition::execute(Game& game) {
585 if (upcast(Warehouse, warehouse, game.objects().get_object(serial)))597 MapObject* mo = game.objects().get_object(serial);
598 if (upcast(ConstructionSite, cs, mo)) {
599 if (upcast(WarehouseSettings, s, cs->get_settings())) {
600 s->launch_expedition = !s->launch_expedition;
601 }
602 } else if (upcast(Warehouse, warehouse, game.objects().get_object(serial))) {
586 game.get_player(sender())->start_or_cancel_expedition(*warehouse);603 game.get_player(sender())->start_or_cancel_expedition(*warehouse);
604 }
587}605}
588606
589void CmdStartOrCancelExpedition::serialize(StreamWrite& ser) {607void CmdStartOrCancelExpedition::serialize(StreamWrite& ser) {
@@ -626,8 +644,12 @@
626}644}
627645
628void CmdEnhanceBuilding::execute(Game& game) {646void CmdEnhanceBuilding::execute(Game& game) {
629 if (upcast(Building, building, game.objects().get_object(serial)))647 MapObject* mo = game.objects().get_object(serial);
648 if (upcast(ConstructionSite, cs, mo)) {
649 cs->enhance(game);
650 } else if (upcast(Building, building, mo)) {
630 game.get_player(sender())->enhance_building(building, bi);651 game.get_player(sender())->enhance_building(building, bi);
652 }
631}653}
632654
633void CmdEnhanceBuilding::serialize(StreamWrite& ser) {655void CmdEnhanceBuilding::serialize(StreamWrite& ser) {
@@ -1036,14 +1058,22 @@
1036}1058}
10371059
1038void CmdSetWarePriority::execute(Game& game) {1060void CmdSetWarePriority::execute(Game& game) {
1039 upcast(Building, psite, game.objects().get_object(serial_));1061 MapObject* mo = game.objects().get_object(serial_);
10401062 if (upcast(ConstructionSite, cs, mo)) {
1041 if (!psite)1063 if (upcast(ProductionsiteSettings, s, cs->get_settings())) {
1042 return;1064 for (auto& pair : s->ware_queues) {
1043 if (psite->owner().player_number() != sender())1065 if (pair.first == index_) {
1044 return;1066 pair.second.priority = priority_;
10451067 return;
1046 psite->set_priority(type_, index_, priority_);1068 }
1069 }
1070 NEVER_HERE();
1071 }
1072 } else if (upcast(Building, psite, mo)) {
1073 if (psite->owner().player_number() == sender()) {
1074 psite->set_priority(type_, index_, priority_);
1075 }
1076 }
1047}1077}
10481078
1049constexpr uint16_t kCurrentPacketVersionCmdSetWarePriority = 1;1079constexpr uint16_t kCurrentPacketVersionCmdSetWarePriority = 1;
@@ -1110,14 +1140,36 @@
1110}1140}
11111141
1112void CmdSetInputMaxFill::execute(Game& game) {1142void CmdSetInputMaxFill::execute(Game& game) {
1113 upcast(Building, b, game.objects().get_object(serial_));1143 MapObject* mo = game.objects().get_object(serial_);
11141144 if (upcast(ConstructionSite, cs, mo)) {
1115 if (!b)1145 if (upcast(ProductionsiteSettings, s, cs->get_settings())) {
1116 return;1146 switch (type_) {
1117 if (b->owner().player_number() != sender())1147 case wwWARE:
1118 return;1148 for (auto& pair : s->ware_queues) {
11191149 if (pair.first == index_) {
1120 b->inputqueue(index_, type_).set_max_fill(max_fill_);1150 assert(pair.second.max_fill >= max_fill_);
1151 pair.second.desired_fill = max_fill_;
1152 return;
1153 }
1154 }
1155 NEVER_HERE();
1156 case wwWORKER:
1157 for (auto& pair : s->worker_queues) {
1158 if (pair.first == index_) {
1159 assert(pair.second.max_fill >= max_fill_);
1160 pair.second.desired_fill = max_fill_;
1161 return;
1162 }
1163 }
1164 NEVER_HERE();
1165 }
1166 NEVER_HERE();
1167 }
1168 } else if (upcast(Building, b, mo)) {
1169 if (b->owner().player_number() == sender()) {
1170 b->inputqueue(index_, type_).set_max_fill(max_fill_);
1171 }
1172 }
1121}1173}
11221174
1123constexpr uint16_t kCurrentPacketVersionCmdSetInputMaxFill = 2;1175constexpr uint16_t kCurrentPacketVersionCmdSetInputMaxFill = 2;
@@ -1528,7 +1580,18 @@
1528}1580}
15291581
1530void CmdChangeSoldierCapacity::execute(Game& game) {1582void CmdChangeSoldierCapacity::execute(Game& game) {
1531 if (upcast(Building, building, game.objects().get_object(serial))) {1583 MapObject* mo = game.objects().get_object(serial);
1584 if (upcast(ConstructionSite, cs, mo)) {
1585 assert(val >= 0);
1586 uint32_t capacity = static_cast<uint32_t>(val);
1587 if (upcast(MilitarysiteSettings, ms, cs->get_settings())) {
1588 assert(ms->max_capacity >= capacity);
1589 ms->desired_capacity = capacity;
1590 } else if (upcast(TrainingsiteSettings, ts, cs->get_settings())) {
1591 assert(ts->max_capacity >= capacity);
1592 ts->desired_capacity = capacity;
1593 }
1594 } else if (upcast(Building, building, mo)) {
1532 if (building->get_owner() == game.get_player(sender()) &&1595 if (building->get_owner() == game.get_player(sender()) &&
1533 building->soldier_control() != nullptr) {1596 building->soldier_control() != nullptr) {
1534 SoldierControl* soldier_control = building->mutable_soldier_control();1597 SoldierControl* soldier_control = building->mutable_soldier_control();
@@ -1750,10 +1813,10 @@
1750/*** struct Cmd_SetStockPolicy ***/1813/*** struct Cmd_SetStockPolicy ***/
1751CmdSetStockPolicy::CmdSetStockPolicy(uint32_t time,1814CmdSetStockPolicy::CmdSetStockPolicy(uint32_t time,
1752 PlayerNumber p,1815 PlayerNumber p,
1753 Warehouse& wh,1816 Building& wh,
1754 bool isworker,1817 bool isworker,
1755 DescriptionIndex ware,1818 DescriptionIndex ware,
1756 Warehouse::StockPolicy policy)1819 StockPolicy policy)
1757 : PlayerCommand(time, p) {1820 : PlayerCommand(time, p) {
1758 warehouse_ = wh.serial();1821 warehouse_ = wh.serial();
1759 isworker_ = isworker;1822 isworker_ = isworker;
@@ -1768,7 +1831,16 @@
1768void CmdSetStockPolicy::execute(Game& game) {1831void CmdSetStockPolicy::execute(Game& game) {
1769 // Sanitize data that could have come from the network1832 // Sanitize data that could have come from the network
1770 if (Player* plr = game.get_player(sender())) {1833 if (Player* plr = game.get_player(sender())) {
1771 if (upcast(Warehouse, warehouse, game.objects().get_object(warehouse_))) {1834 MapObject* mo = game.objects().get_object(warehouse_);
1835 if (upcast(ConstructionSite, cs, mo)) {
1836 if (upcast(WarehouseSettings, s, cs->get_settings())) {
1837 if (isworker_) {
1838 s->worker_preferences[ware_] = policy_;
1839 } else {
1840 s->ware_preferences[ware_] = policy_;
1841 }
1842 }
1843 } else if (upcast(Warehouse, warehouse, mo)) {
1772 if (warehouse->get_owner() != plr) {1844 if (warehouse->get_owner() != plr) {
1773 log("Cmd_SetStockPolicy: sender %u, but warehouse owner %u\n", sender(),1845 log("Cmd_SetStockPolicy: sender %u, but warehouse owner %u\n", sender(),
1774 warehouse->owner().player_number());1846 warehouse->owner().player_number());
@@ -1796,7 +1868,7 @@
1796 warehouse_ = des.unsigned_32();1868 warehouse_ = des.unsigned_32();
1797 isworker_ = des.unsigned_8();1869 isworker_ = des.unsigned_8();
1798 ware_ = DescriptionIndex(des.unsigned_8());1870 ware_ = DescriptionIndex(des.unsigned_8());
1799 policy_ = static_cast<Warehouse::StockPolicy>(des.unsigned_8());1871 policy_ = static_cast<StockPolicy>(des.unsigned_8());
1800}1872}
18011873
1802void CmdSetStockPolicy::serialize(StreamWrite& ser) {1874void CmdSetStockPolicy::serialize(StreamWrite& ser) {
@@ -1818,7 +1890,7 @@
1818 warehouse_ = fr.unsigned_32();1890 warehouse_ = fr.unsigned_32();
1819 isworker_ = fr.unsigned_8();1891 isworker_ = fr.unsigned_8();
1820 ware_ = DescriptionIndex(fr.unsigned_8());1892 ware_ = DescriptionIndex(fr.unsigned_8());
1821 policy_ = static_cast<Warehouse::StockPolicy>(fr.unsigned_8());1893 policy_ = static_cast<StockPolicy>(fr.unsigned_8());
1822 } else {1894 } else {
1823 throw UnhandledVersionError(1895 throw UnhandledVersionError(
1824 "CmdSetStockPolicy", packet_version, kCurrentPacketVersionCmdSetStockPolicy);1896 "CmdSetStockPolicy", packet_version, kCurrentPacketVersionCmdSetStockPolicy);
@@ -1906,4 +1978,5 @@
1906 // TODO(sirver,trading): Implement this.1978 // TODO(sirver,trading): Implement this.
1907 NEVER_HERE();1979 NEVER_HERE();
1908}1980}
1981
1909} // namespace Widelands1982} // namespace Widelands
19101983
=== modified file 'src/logic/playercommand.h'
--- src/logic/playercommand.h 2019-05-29 16:59:16 +0000
+++ src/logic/playercommand.h 2019-06-19 09:23:26 +0000
@@ -24,6 +24,7 @@
2424
25#include "economy/flag.h"25#include "economy/flag.h"
26#include "logic/cmd_queue.h"26#include "logic/cmd_queue.h"
27#include "logic/map_objects/tribes/constructionsite.h"
27#include "logic/map_objects/tribes/militarysite.h"28#include "logic/map_objects/tribes/militarysite.h"
28#include "logic/map_objects/tribes/ship.h"29#include "logic/map_objects/tribes/ship.h"
29#include "logic/map_objects/tribes/trainingsite.h"30#include "logic/map_objects/tribes/trainingsite.h"
@@ -824,10 +825,10 @@
824struct CmdSetStockPolicy : PlayerCommand {825struct CmdSetStockPolicy : PlayerCommand {
825 CmdSetStockPolicy(uint32_t time,826 CmdSetStockPolicy(uint32_t time,
826 PlayerNumber p,827 PlayerNumber p,
827 Warehouse& wh,828 Building& wh,
828 bool isworker,829 bool isworker,
829 DescriptionIndex ware,830 DescriptionIndex ware,
830 Warehouse::StockPolicy policy);831 StockPolicy policy);
831832
832 QueueCommandTypes id() const override {833 QueueCommandTypes id() const override {
833 return QueueCommandTypes::kSetStockPolicy;834 return QueueCommandTypes::kSetStockPolicy;
@@ -848,7 +849,7 @@
848 Serial warehouse_;849 Serial warehouse_;
849 bool isworker_;850 bool isworker_;
850 DescriptionIndex ware_;851 DescriptionIndex ware_;
851 Warehouse::StockPolicy policy_;852 StockPolicy policy_;
852};853};
853854
854struct CmdProposeTrade : PlayerCommand {855struct CmdProposeTrade : PlayerCommand {
@@ -872,6 +873,7 @@
872private:873private:
873 Trade trade_;874 Trade trade_;
874};875};
876
875} // namespace Widelands877} // namespace Widelands
876878
877#endif // end of include guard: WL_LOGIC_PLAYERCOMMAND_H879#endif // end of include guard: WL_LOGIC_PLAYERCOMMAND_H
878880
=== modified file 'src/map_io/map_buildingdata_packet.cc'
--- src/map_io/map_buildingdata_packet.cc 2019-06-13 17:32:28 +0000
+++ src/map_io/map_buildingdata_packet.cc 2019-06-19 09:23:26 +0000
@@ -60,7 +60,7 @@
6060
61// Building type package versions61// Building type package versions
62constexpr uint16_t kCurrentPacketVersionDismantlesite = 1;62constexpr uint16_t kCurrentPacketVersionDismantlesite = 1;
63constexpr uint16_t kCurrentPacketVersionConstructionsite = 3;63constexpr uint16_t kCurrentPacketVersionConstructionsite = 4;
64constexpr uint16_t kCurrentPacketPFBuilding = 1;64constexpr uint16_t kCurrentPacketPFBuilding = 1;
65// Responsible for warehouses and expedition bootstraps65// Responsible for warehouses and expedition bootstraps
66constexpr uint16_t kCurrentPacketVersionWarehouse = 7;66constexpr uint16_t kCurrentPacketVersionWarehouse = 7;
@@ -274,7 +274,7 @@
274 const TribesLegacyLookupTable& tribes_lookup_table) {274 const TribesLegacyLookupTable& tribes_lookup_table) {
275 try {275 try {
276 uint16_t const packet_version = fr.unsigned_16();276 uint16_t const packet_version = fr.unsigned_16();
277 if (packet_version >= kCurrentPacketVersionConstructionsite) {277 if (packet_version >= 3) {
278 read_partially_finished_building(constructionsite, fr, game, mol, tribes_lookup_table);278 read_partially_finished_building(constructionsite, fr, game, mol, tribes_lookup_table);
279279
280 for (ConstructionSite::Wares::iterator wares_iter = constructionsite.wares_.begin();280 for (ConstructionSite::Wares::iterator wares_iter = constructionsite.wares_.begin();
@@ -284,6 +284,18 @@
284 }284 }
285285
286 constructionsite.fetchfromflag_ = fr.signed_32();286 constructionsite.fetchfromflag_ = fr.signed_32();
287
288 if (packet_version >= 4) {
289 const uint32_t intermediates = fr.unsigned_32();
290 for (uint32_t i = 0; i < intermediates; ++i) {
291 constructionsite.info_.intermediates.push_back(game.tribes().get_building_descr(
292 game.tribes().building_index(fr.c_string())));
293 }
294 constructionsite.settings_.reset(BuildingSettings::load(game,
295 constructionsite.owner().tribe(), fr));
296 } else {
297 constructionsite.init_settings();
298 }
287 } else {299 } else {
288 throw UnhandledVersionError("MapBuildingdataPacket - Constructionsite", packet_version,300 throw UnhandledVersionError("MapBuildingdataPacket - Constructionsite", packet_version,
289 kCurrentPacketVersionConstructionsite);301 kCurrentPacketVersionConstructionsite);
@@ -329,7 +341,7 @@
329 const DescriptionIndex& id =341 const DescriptionIndex& id =
330 tribe.ware_index(tribes_lookup_table.lookup_ware(fr.c_string()));342 tribe.ware_index(tribes_lookup_table.lookup_ware(fr.c_string()));
331 Quantity amount = fr.unsigned_32();343 Quantity amount = fr.unsigned_32();
332 Warehouse::StockPolicy policy = static_cast<Warehouse::StockPolicy>(fr.unsigned_8());344 StockPolicy policy = static_cast<StockPolicy>(fr.unsigned_8());
333345
334 if (game.tribes().ware_exists(id)) {346 if (game.tribes().ware_exists(id)) {
335 warehouse.insert_wares(id, amount);347 warehouse.insert_wares(id, amount);
@@ -340,7 +352,7 @@
340 const DescriptionIndex& id =352 const DescriptionIndex& id =
341 tribe.worker_index(tribes_lookup_table.lookup_worker(fr.c_string()));353 tribe.worker_index(tribes_lookup_table.lookup_worker(fr.c_string()));
342 uint32_t amount = fr.unsigned_32();354 uint32_t amount = fr.unsigned_32();
343 Warehouse::StockPolicy policy = static_cast<Warehouse::StockPolicy>(fr.unsigned_8());355 StockPolicy policy = static_cast<StockPolicy>(fr.unsigned_8());
344356
345 if (game.tribes().worker_exists(id)) {357 if (game.tribes().worker_exists(id)) {
346 warehouse.insert_workers(id, amount);358 warehouse.insert_workers(id, amount);
@@ -978,6 +990,14 @@
978 write_partially_finished_building(constructionsite, fw, game, mos);990 write_partially_finished_building(constructionsite, fw, game, mos);
979991
980 fw.signed_32(constructionsite.fetchfromflag_);992 fw.signed_32(constructionsite.fetchfromflag_);
993
994 fw.unsigned_32(constructionsite.info_.intermediates.size());
995 for (const BuildingDescr* d : constructionsite.info_.intermediates) {
996 fw.c_string(d->name().c_str());
997 }
998
999 assert(constructionsite.settings_);
1000 constructionsite.settings_->save(game, fw);
981}1001}
9821002
983void MapBuildingdataPacket::write_dismantlesite(const DismantleSite& dms,1003void MapBuildingdataPacket::write_dismantlesite(const DismantleSite& dms,
9841004
=== modified file 'src/notifications/note_ids.h'
--- src/notifications/note_ids.h 2019-05-10 17:43:19 +0000
+++ src/notifications/note_ids.h 2019-06-19 09:23:26 +0000
@@ -29,6 +29,7 @@
29 ChatMessage,29 ChatMessage,
30 LogMessage,30 LogMessage,
31 Immovable,31 Immovable,
32 ConstructionsiteEnhanced,
32 FieldPossession,33 FieldPossession,
33 FieldTerrainChanged,34 FieldTerrainChanged,
34 ProductionSiteOutOfResources,35 ProductionSiteOutOfResources,
3536
=== modified file 'src/scripting/lua_map.cc'
--- src/scripting/lua_map.cc 2019-05-04 10:47:44 +0000
+++ src/scripting/lua_map.cc 2019-06-19 09:23:26 +0000
@@ -4871,39 +4871,39 @@
4871}4871}
48724872
4873// Transforms the given warehouse policy to a string which is used by the lua code4873// Transforms the given warehouse policy to a string which is used by the lua code
4874inline void wh_policy_to_string(lua_State* L, Warehouse::StockPolicy p) {4874inline void wh_policy_to_string(lua_State* L, StockPolicy p) {
4875 switch (p) {4875 switch (p) {
4876 case Warehouse::StockPolicy::kNormal:4876 case StockPolicy::kNormal:
4877 lua_pushstring(L, "normal");4877 lua_pushstring(L, "normal");
4878 break;4878 break;
4879 case Warehouse::StockPolicy::kPrefer:4879 case StockPolicy::kPrefer:
4880 lua_pushstring(L, "prefer");4880 lua_pushstring(L, "prefer");
4881 break;4881 break;
4882 case Warehouse::StockPolicy::kDontStock:4882 case StockPolicy::kDontStock:
4883 lua_pushstring(L, "dontstock");4883 lua_pushstring(L, "dontstock");
4884 break;4884 break;
4885 case Warehouse::StockPolicy::kRemove:4885 case StockPolicy::kRemove:
4886 lua_pushstring(L, "remove");4886 lua_pushstring(L, "remove");
4887 break;4887 break;
4888 }4888 }
4889}4889}
4890// Transforms the given string from the lua code to a warehouse policy4890// Transforms the given string from the lua code to a warehouse policy
4891inline Warehouse::StockPolicy string_to_wh_policy(lua_State* L, uint32_t index) {4891inline StockPolicy string_to_wh_policy(lua_State* L, uint32_t index) {
4892 std::string str = luaL_checkstring(L, index);4892 std::string str = luaL_checkstring(L, index);
4893 if (str == "normal")4893 if (str == "normal")
4894 return Warehouse::StockPolicy::kNormal;4894 return StockPolicy::kNormal;
4895 else if (str == "prefer")4895 else if (str == "prefer")
4896 return Warehouse::StockPolicy::kPrefer;4896 return StockPolicy::kPrefer;
4897 else if (str == "dontstock")4897 else if (str == "dontstock")
4898 return Warehouse::StockPolicy::kDontStock;4898 return StockPolicy::kDontStock;
4899 else if (str == "remove")4899 else if (str == "remove")
4900 return Warehouse::StockPolicy::kRemove;4900 return StockPolicy::kRemove;
4901 else4901 else
4902 report_error(L, "<%s> is no valid warehouse policy!", str.c_str());4902 report_error(L, "<%s> is no valid warehouse policy!", str.c_str());
4903}4903}
49044904
4905inline bool4905inline bool
4906do_set_ware_policy(Warehouse* wh, const DescriptionIndex idx, const Warehouse::StockPolicy p) {4906do_set_ware_policy(Warehouse* wh, const DescriptionIndex idx, const StockPolicy p) {
4907 wh->set_ware_policy(idx, p);4907 wh->set_ware_policy(idx, p);
4908 return true;4908 return true;
4909}4909}
@@ -4913,7 +4913,7 @@
4913 * If the no ware with the given name exists for the tribe of the warehouse, return false.4913 * If the no ware with the given name exists for the tribe of the warehouse, return false.
4914 */4914 */
4915inline bool4915inline bool
4916do_set_ware_policy(Warehouse* wh, const std::string& name, const Warehouse::StockPolicy p) {4916do_set_ware_policy(Warehouse* wh, const std::string& name, const StockPolicy p) {
4917 const TribeDescr& tribe = wh->owner().tribe();4917 const TribeDescr& tribe = wh->owner().tribe();
4918 DescriptionIndex idx = tribe.ware_index(name);4918 DescriptionIndex idx = tribe.ware_index(name);
4919 if (!tribe.has_ware(idx)) {4919 if (!tribe.has_ware(idx)) {
@@ -4923,7 +4923,7 @@
4923}4923}
49244924
4925inline bool4925inline bool
4926do_set_worker_policy(Warehouse* wh, const DescriptionIndex idx, const Warehouse::StockPolicy p) {4926do_set_worker_policy(Warehouse* wh, const DescriptionIndex idx, const StockPolicy p) {
4927 const TribeDescr& tribe = wh->owner().tribe();4927 const TribeDescr& tribe = wh->owner().tribe();
4928 // If the worker does not cost anything, ignore it4928 // If the worker does not cost anything, ignore it
4929 // Otherwise, an unlimited stream of carriers might leave the warehouse4929 // Otherwise, an unlimited stream of carriers might leave the warehouse
@@ -4942,7 +4942,7 @@
4942 * If no worker with the given name exists for the tribe of the warehouse, return false.4942 * If no worker with the given name exists for the tribe of the warehouse, return false.
4943 */4943 */
4944inline bool4944inline bool
4945do_set_worker_policy(Warehouse* wh, const std::string& name, const Warehouse::StockPolicy p) {4945do_set_worker_policy(Warehouse* wh, const std::string& name, const StockPolicy p) {
4946 const TribeDescr& tribe = wh->owner().tribe();4946 const TribeDescr& tribe = wh->owner().tribe();
4947 DescriptionIndex idx = tribe.worker_index(name);4947 DescriptionIndex idx = tribe.worker_index(name);
4948 if (!tribe.has_worker(idx)) {4948 if (!tribe.has_worker(idx)) {
@@ -4972,7 +4972,7 @@
4972 report_error(L, "Wrong number of arguments to set_warehouse_policies!");4972 report_error(L, "Wrong number of arguments to set_warehouse_policies!");
49734973
4974 Warehouse* wh = get(L, get_egbase(L));4974 Warehouse* wh = get(L, get_egbase(L));
4975 Warehouse::StockPolicy p = string_to_wh_policy(L, -1);4975 StockPolicy p = string_to_wh_policy(L, -1);
4976 lua_pop(L, 1);4976 lua_pop(L, 1);
4977 const TribeDescr& tribe = wh->owner().tribe();4977 const TribeDescr& tribe = wh->owner().tribe();
49784978
49794979
=== modified file 'src/wui/actionconfirm.cc'
--- src/wui/actionconfirm.cc 2019-04-28 16:53:20 +0000
+++ src/wui/actionconfirm.cc 2019-06-19 09:23:26 +0000
@@ -92,7 +92,8 @@
92struct EnhanceConfirm : public ActionConfirm {92struct EnhanceConfirm : public ActionConfirm {
93 EnhanceConfirm(InteractivePlayer& parent,93 EnhanceConfirm(InteractivePlayer& parent,
94 Widelands::Building& building,94 Widelands::Building& building,
95 const Widelands::DescriptionIndex& id);95 const Widelands::DescriptionIndex& id,
96 bool still_under_construction);
9697
97 void think() override;98 void think() override;
98 void ok() override;99 void ok() override;
@@ -100,6 +101,7 @@
100private:101private:
101 // Do not make this a reference - it is a stack variable in the caller102 // Do not make this a reference - it is a stack variable in the caller
102 const Widelands::DescriptionIndex id_;103 const Widelands::DescriptionIndex id_;
104 bool still_under_construction_;
103};105};
104106
105/**107/**
@@ -259,7 +261,8 @@
259*/261*/
260EnhanceConfirm::EnhanceConfirm(InteractivePlayer& parent,262EnhanceConfirm::EnhanceConfirm(InteractivePlayer& parent,
261 Widelands::Building& building,263 Widelands::Building& building,
262 const Widelands::DescriptionIndex& id)264 const Widelands::DescriptionIndex& id,
265 bool still_under_construction)
263 : ActionConfirm(266 : ActionConfirm(
264 parent,267 parent,
265 _("Enhance building?"),268 _("Enhance building?"),
@@ -270,7 +273,8 @@
270 .str() :273 .str() :
271 _("Do you really want to enhance this building?"),274 _("Do you really want to enhance this building?"),
272 building),275 building),
273 id_(id) {276 id_(id),
277 still_under_construction_(still_under_construction) {
274 // Nothing special to do278 // Nothing special to do
275}279}
276280
@@ -284,7 +288,7 @@
284 upcast(Widelands::Building, building, object_.get(egbase));288 upcast(Widelands::Building, building, object_.get(egbase));
285289
286 if (!building || !iaplayer().can_act(building->owner().player_number()) ||290 if (!building || !iaplayer().can_act(building->owner().player_number()) ||
287 !(building->get_playercaps() & Widelands::Building::PCap_Enhancable))291 !(still_under_construction_ || (building->get_playercaps() & Widelands::Building::PCap_Enhancable)))
288 die();292 die();
289}293}
290294
@@ -293,11 +297,18 @@
293 */297 */
294void EnhanceConfirm::ok() {298void EnhanceConfirm::ok() {
295 Widelands::Game& game = iaplayer().game();299 Widelands::Game& game = iaplayer().game();
296 upcast(Widelands::Building, building, object_.get(game));
297300
298 if (building && iaplayer().can_act(building->owner().player_number()) &&301 if (still_under_construction_) {
299 (building->get_playercaps() & Widelands::Building::PCap_Enhancable)) {302 upcast(Widelands::ConstructionSite, cs, object_.get(game));
300 game.send_player_enhance_building(*building, id_);303 if (cs && iaplayer().can_act(cs->owner().player_number())) {
304 game.send_player_enhance_building(*cs, Widelands::INVALID_INDEX);
305 }
306 } else {
307 upcast(Widelands::Building, building, object_.get(game));
308 if (building && iaplayer().can_act(building->owner().player_number()) &&
309 (building->get_playercaps() & Widelands::Building::PCap_Enhancable)) {
310 game.send_player_enhance_building(*building, id_);
311 }
301 }312 }
302313
303 die();314 die();
@@ -419,8 +430,9 @@
419 */430 */
420void show_enhance_confirm(InteractivePlayer& player,431void show_enhance_confirm(InteractivePlayer& player,
421 Widelands::Building& building,432 Widelands::Building& building,
422 const Widelands::DescriptionIndex& id) {433 const Widelands::DescriptionIndex& id,
423 new EnhanceConfirm(player, building, id);434 bool constructionsite) {
435 new EnhanceConfirm(player, building, id, constructionsite);
424}436}
425437
426/**438/**
427439
=== modified file 'src/wui/actionconfirm.h'
--- src/wui/actionconfirm.h 2019-02-23 11:00:49 +0000
+++ src/wui/actionconfirm.h 2019-06-19 09:23:26 +0000
@@ -39,7 +39,8 @@
3939
40void show_enhance_confirm(InteractivePlayer& player,40void show_enhance_confirm(InteractivePlayer& player,
41 Widelands::Building& building,41 Widelands::Building& building,
42 const Widelands::DescriptionIndex& id);42 const Widelands::DescriptionIndex& id,
43 bool still_under_construction = false);
4344
44// Ship confirm windows45// Ship confirm windows
45void show_ship_sink_confirm(InteractivePlayer& player, Widelands::Ship& ship);46void show_ship_sink_confirm(InteractivePlayer& player, Widelands::Ship& ship);
4647
=== modified file 'src/wui/buildingwindow.cc'
--- src/wui/buildingwindow.cc 2019-05-26 17:21:15 +0000
+++ src/wui/buildingwindow.cc 2019-06-19 09:23:26 +0000
@@ -54,7 +54,7 @@
54 is_dying_(false),54 is_dying_(false),
55 parent_(&parent),55 parent_(&parent),
56 building_(&b),56 building_(&b),
57 building_descr_for_help_(descr),57 building_descr_for_help_(&descr),
58 building_position_(b.get_position()),58 building_position_(b.get_position()),
59 showing_workarea_(false),59 showing_workarea_(false),
60 avoid_fastclick_(avoid_fastclick),60 avoid_fastclick_(avoid_fastclick),
@@ -363,14 +363,14 @@
363 g_gr->images().get("images/ui_basic/menu_help.png"), _("Help"));363 g_gr->images().get("images/ui_basic/menu_help.png"), _("Help"));
364364
365 UI::UniqueWindow::Registry& registry =365 UI::UniqueWindow::Registry& registry =
366 igbase()->unique_windows().get_registry(building_descr_for_help_.name() + "_help");366 igbase()->unique_windows().get_registry(building_descr_for_help_->name() + "_help");
367 registry.open_window = [this, &registry] {367 registry.open_window = [this, &registry] {
368 if (parent_ != nullptr) {368 if (parent_ != nullptr) {
369 Widelands::Building* building_in_lambda = building_.get(parent_->egbase());369 Widelands::Building* building_in_lambda = building_.get(parent_->egbase());
370 if (building_in_lambda == nullptr) {370 if (building_in_lambda == nullptr) {
371 return;371 return;
372 }372 }
373 new UI::BuildingHelpWindow(igbase(), registry, building_descr_for_help_,373 new UI::BuildingHelpWindow(igbase(), registry, *building_descr_for_help_,
374 building_in_lambda->owner().tribe(),374 building_in_lambda->owner().tribe(),
375 &parent_->egbase().lua());375 &parent_->egbase().lua());
376 }376 }
377377
=== modified file 'src/wui/buildingwindow.h'
--- src/wui/buildingwindow.h 2019-02-23 11:00:49 +0000
+++ src/wui/buildingwindow.h 2019-06-19 09:23:26 +0000
@@ -95,6 +95,10 @@
9595
96 bool is_dying_;96 bool is_dying_;
9797
98 void set_building_descr_for_help(const Widelands::BuildingDescr* d) {
99 building_descr_for_help_ = d;
100 }
101
98private:102private:
99 void create_capsbuttons(UI::Box* buttons, Widelands::Building* building);103 void create_capsbuttons(UI::Box* buttons, Widelands::Building* building);
100104
@@ -110,7 +114,7 @@
110 Widelands::OPtr<Widelands::Building> building_;114 Widelands::OPtr<Widelands::Building> building_;
111115
112 // The building description that will be used for the help button116 // The building description that will be used for the help button
113 const Widelands::BuildingDescr& building_descr_for_help_;117 const Widelands::BuildingDescr* building_descr_for_help_;
114118
115 // We require this to unregister overlays when we are closed. Since the119 // We require this to unregister overlays when we are closed. Since the
116 // building might have been destroyed by then we have to keep a copy of its120 // building might have been destroyed by then we have to keep a copy of its
117121
=== modified file 'src/wui/constructionsitewindow.cc'
--- src/wui/constructionsitewindow.cc 2019-02-23 11:00:49 +0000
+++ src/wui/constructionsitewindow.cc 2019-06-19 09:23:26 +0000
@@ -22,9 +22,67 @@
22#include <boost/format.hpp>22#include <boost/format.hpp>
2323
24#include "graphic/graphic.h"24#include "graphic/graphic.h"
25#include "wui/actionconfirm.h"
25#include "wui/inputqueuedisplay.h"26#include "wui/inputqueuedisplay.h"
27#include "wui/interactive_player.h"
2628
27static const char pic_tab_wares[] = "images/wui/buildings/menu_tab_wares.png";29static const char pic_tab_wares[] = "images/wui/buildings/menu_tab_wares.png";
30static const char pic_tab_settings[] = "images/wui/menus/menu_stock.png";
31static const char pic_tab_settings_wares[] = "images/wui/stats/menu_tab_wares_warehouse.png";
32static const char pic_tab_settings_workers[] = "images/wui/stats/menu_tab_workers_warehouse.png";
33static const char pic_max_fill_indicator[] = "images/wui/buildings/max_fill_indicator.png";
34static const char pic_priority_low[] = "images/wui/buildings/low_priority_button.png";
35static const char pic_priority_normal[] = "images/wui/buildings/normal_priority_button.png";
36static const char pic_priority_high[] = "images/wui/buildings/high_priority_button.png";
37static const char pic_stock_policy_prefer[] = "images/wui/buildings/stock_policy_prefer.png";
38static const char pic_stock_policy_dontstock[] = "images/wui/buildings/stock_policy_dontstock.png";
39static const char pic_stock_policy_remove[] = "images/wui/buildings/stock_policy_remove.png";
40static const char pic_stock_policy_button_normal[] = "images/wui/buildings/stock_policy_button_normal.png";
41static const char pic_stock_policy_button_prefer[] = "images/wui/buildings/stock_policy_button_prefer.png";
42static const char pic_stock_policy_button_dontstock[] = "images/wui/buildings/stock_policy_button_dontstock.png";
43static const char pic_stock_policy_button_remove[] = "images/wui/buildings/stock_policy_button_remove.png";
44static const char pic_decrease_capacity[] = "images/wui/buildings/menu_down_train.png";
45static const char pic_increase_capacity[] = "images/wui/buildings/menu_up_train.png";
46
47ConstructionSiteWindow::FakeWaresDisplay::FakeWaresDisplay(UI::Panel* parent,
48 bool can_act,
49 Widelands::ConstructionSite& cs,
50 Widelands::WareWorker type)
51 : WaresDisplay(parent, 0, 0, cs.owner().tribe(), type, can_act),
52 settings_(*dynamic_cast<Widelands::WarehouseSettings*>(cs.get_settings())),
53 tribe_(cs.owner().tribe()) {
54}
55
56void ConstructionSiteWindow::FakeWaresDisplay::draw_ware(RenderTarget& dst, Widelands::DescriptionIndex ware) {
57 if (get_type() == Widelands::wwWORKER && std::find(tribe_.worker_types_without_cost().begin(),
58 tribe_.worker_types_without_cost().end(), ware) != tribe_.worker_types_without_cost().end()) {
59 return;
60 }
61 WaresDisplay::draw_ware(dst, ware);
62
63 const auto& map = get_type() == Widelands::wwWARE ? settings_.ware_preferences : settings_.worker_preferences;
64 const auto it = map.find(ware);
65 if (it == map.end()) {
66 return;
67 }
68 const Image* pic = nullptr;
69 switch (it->second) {
70 case Widelands::StockPolicy::kPrefer:
71 pic = g_gr->images().get(pic_stock_policy_prefer);
72 break;
73 case Widelands::StockPolicy::kDontStock:
74 pic = g_gr->images().get(pic_stock_policy_dontstock);
75 break;
76 case Widelands::StockPolicy::kRemove:
77 pic = g_gr->images().get(pic_stock_policy_remove);
78 break;
79 case Widelands::StockPolicy::kNormal:
80 // No icon for the normal policy
81 return;
82 }
83 assert(pic);
84 dst.blit(ware_position(ware), pic);
85}
2886
29ConstructionSiteWindow::ConstructionSiteWindow(InteractiveGameBase& parent,87ConstructionSiteWindow::ConstructionSiteWindow(InteractiveGameBase& parent,
30 UI::UniqueWindow::Registry& reg,88 UI::UniqueWindow::Registry& reg,
@@ -33,13 +91,23 @@
33 bool workarea_preview_wanted)91 bool workarea_preview_wanted)
34 : BuildingWindow(parent, reg, cs, cs.building(), avoid_fastclick),92 : BuildingWindow(parent, reg, cs, cs.building(), avoid_fastclick),
35 construction_site_(&cs),93 construction_site_(&cs),
36 progress_(nullptr) {94 progress_(nullptr),
95 cs_enhance_(nullptr),
96 cs_launch_expedition_(nullptr),
97 cs_prefer_heroes_rookies_(nullptr),
98 cs_soldier_capacity_decrease_(nullptr),
99 cs_soldier_capacity_increase_(nullptr),
100 cs_soldier_capacity_display_(nullptr),
101 cs_stopped_(nullptr),
102 cs_warehouse_wares_(nullptr),
103 cs_warehouse_workers_(nullptr) {
37 init(avoid_fastclick, workarea_preview_wanted);104 init(avoid_fastclick, workarea_preview_wanted);
38}105}
39106
40void ConstructionSiteWindow::init(bool avoid_fastclick, bool workarea_preview_wanted) {107void ConstructionSiteWindow::init(bool avoid_fastclick, bool workarea_preview_wanted) {
41 Widelands::ConstructionSite* construction_site = construction_site_.get(igbase()->egbase());108 Widelands::ConstructionSite* construction_site = construction_site_.get(igbase()->egbase());
42 assert(construction_site != nullptr);109 assert(construction_site != nullptr);
110 set_building_descr_for_help(&construction_site->building());
43111
44 BuildingWindow::init(avoid_fastclick, workarea_preview_wanted);112 BuildingWindow::init(avoid_fastclick, workarea_preview_wanted);
45 UI::Box& box = *new UI::Box(get_tabs(), 0, 0, UI::Box::Vertical);113 UI::Box& box = *new UI::Box(get_tabs(), 0, 0, UI::Box::Vertical);
@@ -59,10 +127,245 @@
59127
60 get_tabs()->add("wares", g_gr->images().get(pic_tab_wares), &box, _("Building materials"));128 get_tabs()->add("wares", g_gr->images().get(pic_tab_wares), &box, _("Building materials"));
61129
130 if (construction_site->get_settings()) {
131 const bool can_act = igbase()->can_act(construction_site->owner().player_number());
132 // Create the settings. Since we don't access an actual building, we create
133 // a simplified faksimile of the later building window that contains only
134 // the relevant options.
135 bool nothing_added = false;
136 UI::Box& settings_box = *new UI::Box(get_tabs(), 0, 0, UI::Box::Vertical);
137 if (upcast(Widelands::ProductionsiteSettings, ps, construction_site->get_settings())) {
138 for (const auto& pair : ps->ware_queues) {
139 InputQueueDisplay* queue = new InputQueueDisplay(&settings_box, 0, 0, *igbase(),
140 *construction_site, Widelands::wwWARE, pair.first);
141 settings_box.add(queue);
142 settings_box.add_space(8);
143 cs_ware_queues_.push_back(queue);
144 }
145 for (const auto& pair : ps->worker_queues) {
146 InputQueueDisplay* queue = new InputQueueDisplay(&settings_box, 0, 0, *igbase(),
147 *construction_site, Widelands::wwWORKER, pair.first);
148 settings_box.add(queue);
149 settings_box.add_space(8);
150 cs_ware_queues_.push_back(queue);
151 }
152 if (upcast(Widelands::TrainingsiteSettings, ts, ps)) {
153 UI::Box& soldier_capacity_box = *new UI::Box(&settings_box, 0, 0, UI::Box::Horizontal);
154 settings_box.add(&soldier_capacity_box, UI::Box::Resizing::kAlign, UI::Align::kCenter);
155 cs_soldier_capacity_decrease_ = new UI::Button(&soldier_capacity_box,
156 "decrease", 0, 0, 32, 32, UI::ButtonStyle::kWuiMenu,
157 g_gr->images().get(pic_decrease_capacity),
158 _("Decrease capacity. Hold down Ctrl to set the capacity to the lowest value"));
159 cs_soldier_capacity_increase_ = new UI::Button(&soldier_capacity_box,
160 "increase", 0, 0, 32, 32, UI::ButtonStyle::kWuiMenu,
161 g_gr->images().get(pic_increase_capacity),
162 _("Increase capacity. Hold down Ctrl to set the capacity to the highest value"));
163 cs_soldier_capacity_display_ = new UI::Textarea(&soldier_capacity_box,
164 "", UI::Align::kCenter);
165 cs_soldier_capacity_decrease_->set_enabled(can_act);
166 cs_soldier_capacity_increase_->set_enabled(can_act);
167 cs_soldier_capacity_decrease_->sigclicked.connect([this, ts]() {
168 igbase()->game().send_player_change_soldier_capacity(
169 *construction_site_.get(igbase()->egbase()),
170 SDL_GetModState() & KMOD_CTRL ? 0 : ts->desired_capacity - 1);
171 });
172 cs_soldier_capacity_increase_->sigclicked.connect([this, ts]() {
173 igbase()->game().send_player_change_soldier_capacity(
174 *construction_site_.get(igbase()->egbase()),
175 SDL_GetModState() & KMOD_CTRL ? ts->max_capacity : ts->desired_capacity + 1);
176 });
177 soldier_capacity_box.add(cs_soldier_capacity_decrease_);
178 soldier_capacity_box.add_space(8);
179 soldier_capacity_box.add(cs_soldier_capacity_display_, UI::Box::Resizing::kAlign, UI::Align::kCenter);
180 soldier_capacity_box.add_space(8);
181 soldier_capacity_box.add(cs_soldier_capacity_increase_);
182 settings_box.add_space(8);
183 }
184 cs_stopped_ = new UI::Checkbox(&settings_box, Vector2i::zero(),
185 _("Stopped"),
186 _("Stop this building’s work after completion"));
187 cs_stopped_->clickedto.connect([this, ps](bool stop) {
188 if (stop != ps->stopped) {
189 igbase()->game().send_player_start_stop_building(*construction_site_.get(igbase()->egbase()));
190 }
191 });
192 settings_box.add(cs_stopped_, UI::Box::Resizing::kFullSize);
193 settings_box.add_space(8);
194 cs_stopped_->set_enabled(can_act);
195 } else if (upcast(Widelands::MilitarysiteSettings, ms, construction_site->get_settings())) {
196 UI::Box& soldier_capacity_box = *new UI::Box(&settings_box, 0, 0, UI::Box::Horizontal);
197 settings_box.add(&soldier_capacity_box, UI::Box::Resizing::kAlign, UI::Align::kCenter);
198 cs_soldier_capacity_decrease_ = new UI::Button(&soldier_capacity_box,
199 "decrease", 0, 0, 32, 32, UI::ButtonStyle::kWuiMenu,
200 g_gr->images().get(pic_decrease_capacity),
201 _("Decrease capacity. Hold down Ctrl to set the capacity to the lowest value"));
202 cs_soldier_capacity_increase_ = new UI::Button(&soldier_capacity_box,
203 "increase", 0, 0, 32, 32, UI::ButtonStyle::kWuiMenu,
204 g_gr->images().get(pic_increase_capacity),
205 _("Increase capacity. Hold down Ctrl to set the capacity to the highest value"));
206 cs_soldier_capacity_display_ = new UI::Textarea(&soldier_capacity_box,
207 "", UI::Align::kCenter);
208 cs_soldier_capacity_decrease_->set_enabled(can_act);
209 cs_soldier_capacity_increase_->set_enabled(can_act);
210 cs_soldier_capacity_decrease_->sigclicked.connect([this, ms]() {
211 igbase()->game().send_player_change_soldier_capacity(
212 *construction_site_.get(igbase()->egbase()),
213 SDL_GetModState() & KMOD_CTRL ? 0 : ms->desired_capacity - 1);
214 });
215 cs_soldier_capacity_increase_->sigclicked.connect([this, ms]() {
216 igbase()->game().send_player_change_soldier_capacity(
217 *construction_site_.get(igbase()->egbase()),
218 SDL_GetModState() & KMOD_CTRL ? ms->max_capacity : ms->desired_capacity + 1);
219 });
220 soldier_capacity_box.add(cs_soldier_capacity_decrease_);
221 soldier_capacity_box.add_space(8);
222 soldier_capacity_box.add(cs_soldier_capacity_display_, UI::Box::Resizing::kAlign, UI::Align::kCenter);
223 soldier_capacity_box.add_space(8);
224 soldier_capacity_box.add(cs_soldier_capacity_increase_);
225 settings_box.add_space(8);
226
227 UI::Box& soldier_preference_box = *new UI::Box(&settings_box, 0, 0, UI::Box::Horizontal);
228 settings_box.add(&soldier_preference_box, UI::Box::Resizing::kAlign, UI::Align::kCenter);
229 UI::Panel& soldier_preference_panel = *new UI::Panel(&soldier_preference_box, 0, 0, 64, 32);
230 soldier_preference_box.add(&soldier_preference_panel);
231 cs_prefer_heroes_rookies_.reset(new UI::Radiogroup());
232 cs_prefer_heroes_rookies_->add_button(&soldier_preference_panel, Vector2i::zero(),
233 g_gr->images().get("images/wui/buildings/prefer_rookies.png"),
234 _("Prefer rookies"));
235 cs_prefer_heroes_rookies_->add_button(&soldier_preference_panel, Vector2i(32, 0),
236 g_gr->images().get("images/wui/buildings/prefer_heroes.png"),
237 _("Prefer heroes"));
238 if (can_act) {
239 cs_prefer_heroes_rookies_->changedto.connect([this](int32_t state) {
240 igbase()->game().send_player_militarysite_set_soldier_preference(
241 *construction_site_.get(igbase()->egbase()),
242 state ? Widelands::SoldierPreference::kHeroes : Widelands::SoldierPreference::kRookies);
243 });
244 }
245 settings_box.add_space(8);
246 } else if (upcast(Widelands::WarehouseSettings, ws, construction_site->get_settings())) {
247 auto add_tab = [this, construction_site, can_act](Widelands::WareWorker ww, FakeWaresDisplay** display) {
248 UI::Box& mainbox = *new UI::Box(get_tabs(), 0, 0, UI::Box::Vertical);
249 *display = new FakeWaresDisplay(&mainbox, can_act, *construction_site, ww);
250 mainbox.add(*display, UI::Box::Resizing::kFullSize);
251 mainbox.add_space(8);
252 UI::Box& buttonsbox = *new UI::Box(&mainbox, 0, 0, UI::Box::Horizontal);
253 mainbox.add(&buttonsbox, UI::Box::Resizing::kAlign, UI::Align::kCenter);
254 mainbox.add_space(8);
255 UI::Button& sp_normal = *new UI::Button(&buttonsbox, "stock_policy_normal", 0, 0, 34, 34,
256 UI::ButtonStyle::kWuiMenu, g_gr->images().get(pic_stock_policy_button_normal),
257 _("Normal policy"));
258 UI::Button& sp_prefer = *new UI::Button(&buttonsbox, "stock_policy_prefer", 0, 0, 34, 34,
259 UI::ButtonStyle::kWuiMenu, g_gr->images().get(pic_stock_policy_button_prefer),
260 _("Preferably store selected wares here"));
261 UI::Button& sp_dont = *new UI::Button(&buttonsbox, "stock_policy_dontstock", 0, 0, 34, 34,
262 UI::ButtonStyle::kWuiMenu, g_gr->images().get(pic_stock_policy_button_dontstock),
263 _("Do not store selected wares here"));
264 UI::Button& sp_remove = *new UI::Button(&buttonsbox, "stock_policy_remove", 0, 0, 34, 34,
265 UI::ButtonStyle::kWuiMenu, g_gr->images().get(pic_stock_policy_button_remove),
266 _("Remove selected wares from here"));
267 sp_remove.sigclicked.connect(
268 boost::bind(&ConstructionSiteWindow::change_policy, this, ww, Widelands::StockPolicy::kRemove));
269 sp_dont.sigclicked.connect(
270 boost::bind(&ConstructionSiteWindow::change_policy, this, ww, Widelands::StockPolicy::kDontStock));
271 sp_prefer.sigclicked.connect(
272 boost::bind(&ConstructionSiteWindow::change_policy, this, ww, Widelands::StockPolicy::kPrefer));
273 sp_normal.sigclicked.connect(
274 boost::bind(&ConstructionSiteWindow::change_policy, this, ww, Widelands::StockPolicy::kNormal));
275 sp_normal.set_enabled(can_act);
276 sp_dont.set_enabled(can_act);
277 sp_remove.set_enabled(can_act);
278 sp_prefer.set_enabled(can_act);
279 buttonsbox.add(&sp_normal);
280 buttonsbox.add_space(8);
281 buttonsbox.add(&sp_prefer);
282 buttonsbox.add_space(8);
283 buttonsbox.add(&sp_dont);
284 buttonsbox.add_space(8);
285 buttonsbox.add(&sp_remove);
286 if (ww == Widelands::wwWARE) {
287 get_tabs()->add("warehouse_wares", g_gr->images().get(pic_tab_settings_wares),
288 &mainbox, _("Ware settings to apply after construction"));
289 } else {
290 get_tabs()->add("warehouse_workers", g_gr->images().get(pic_tab_settings_workers),
291 &mainbox, _("Worker settings to apply after construction"));
292 }
293 };
294 add_tab(Widelands::wwWARE, &cs_warehouse_wares_);
295 add_tab(Widelands::wwWORKER, &cs_warehouse_workers_);
296 if (construction_site->get_info().becomes->get_isport()) {
297 cs_launch_expedition_ = new UI::Checkbox(&settings_box, Vector2i::zero(),
298 _("Start an expedition"),
299 _("Start an expedition from this port after completion"));
300 cs_launch_expedition_->clickedto.connect([this, ws](bool launch) {
301 if (launch != ws->launch_expedition) {
302 igbase()->game().send_player_start_or_cancel_expedition(
303 *construction_site_.get(igbase()->egbase()));
304 }
305 });
306 settings_box.add(cs_launch_expedition_, UI::Box::Resizing::kFullSize);
307 settings_box.add_space(8);
308 cs_launch_expedition_->set_enabled(can_act);
309 } else {
310 nothing_added = true;
311 }
312 } else {
313 NEVER_HERE();
314 }
315
316 if (can_act && construction_site->get_info().becomes->enhancement() != Widelands::INVALID_INDEX) {
317 const Widelands::BuildingDescr& building_descr = *igbase()->egbase().tribes().get_building_descr(
318 construction_site->get_info().becomes->enhancement());
319 std::string enhance_tooltip =
320 (boost::format(_("Enhance to %s")) % building_descr.descname().c_str()).str() +
321 "<br><font size=11>" + _("Construction costs:") + "</font><br>" +
322 waremap_to_richtext(construction_site->owner().tribe(), building_descr.enhancement_cost());
323 cs_enhance_ = new UI::Button(&settings_box, "enhance", 0, 0, 34, 34, UI::ButtonStyle::kWuiMenu,
324 building_descr.icon(), enhance_tooltip);
325 cs_enhance_->sigclicked.connect([this, construction_site] {
326 if (SDL_GetModState() & KMOD_CTRL) {
327 igbase()->game().send_player_enhance_building(*construction_site, Widelands::INVALID_INDEX);
328 } else {
329 show_enhance_confirm(dynamic_cast<InteractivePlayer&>(*igbase()),
330 *construction_site, construction_site->get_info().becomes->enhancement(), true);
331 }
332 });
333 settings_box.add(cs_enhance_, UI::Box::Resizing::kAlign, UI::Align::kCenter);
334 settings_box.add_space(8);
335 nothing_added = false;
336 }
337 if (!nothing_added) {
338 get_tabs()->add("settings", g_gr->images().get(pic_tab_settings),
339 &settings_box, _("Settings to apply after construction"));
340 }
341 }
342
62 set_title((boost::format("(%s)") % construction_site->building().descname()).str());343 set_title((boost::format("(%s)") % construction_site->building().descname()).str());
63 think();344 think();
64}345}
65346
347void ConstructionSiteWindow::change_policy(Widelands::WareWorker ww, Widelands::StockPolicy p) {
348 Widelands::ConstructionSite* construction_site = construction_site_.get(igbase()->egbase());
349 assert(construction_site);
350 upcast(Widelands::WarehouseSettings, ws, construction_site->get_settings());
351 assert(ws);
352 if (ww == Widelands::wwWARE) {
353 for (const auto& pair : ws->ware_preferences) {
354 if (cs_warehouse_wares_->ware_selected(pair.first)) {
355 igbase()->game().send_player_set_stock_policy(*construction_site,
356 Widelands::wwWARE, pair.first, p);
357 }
358 }
359 } else {
360 for (const auto& pair : ws->worker_preferences) {
361 if (cs_warehouse_workers_->ware_selected(pair.first)) {
362 igbase()->game().send_player_set_stock_policy(*construction_site,
363 Widelands::wwWORKER, pair.first, p);
364 }
365 }
366 }
367}
368
66/*369/*
67===============370===============
68Make sure the window is redrawn when necessary.371Make sure the window is redrawn when necessary.
@@ -77,5 +380,41 @@
77 if (construction_site == nullptr) {380 if (construction_site == nullptr) {
78 return;381 return;
79 }382 }
383
80 progress_->set_state(construction_site->get_built_per64k());384 progress_->set_state(construction_site->get_built_per64k());
385
386 const bool can_act = igbase()->can_act(construction_site->owner().player_number());
387 // InputQueueDisplay and FakeWaresDisplay update themselves – we need to refresh the other settings
388 if (upcast(Widelands::ProductionsiteSettings, ps, construction_site->get_settings())) {
389 assert(cs_stopped_);
390 cs_stopped_->set_state(ps->stopped);
391 }
392 if (upcast(Widelands::TrainingsiteSettings, ts, construction_site->get_settings())) {
393 assert(cs_soldier_capacity_decrease_);
394 assert(cs_soldier_capacity_increase_);
395 assert(cs_soldier_capacity_display_);
396 cs_soldier_capacity_display_->set_text((boost::format(ngettext("%u soldier", "%u soldiers",
397 ts->desired_capacity)) % ts->desired_capacity).str());
398 cs_soldier_capacity_decrease_->set_enabled(can_act && ts->desired_capacity > 0);
399 cs_soldier_capacity_increase_->set_enabled(can_act && ts->desired_capacity < ts->max_capacity);
400 } else if (upcast(Widelands::MilitarysiteSettings, ms, construction_site->get_settings())) {
401 assert(cs_soldier_capacity_decrease_);
402 assert(cs_soldier_capacity_increase_);
403 assert(cs_soldier_capacity_display_);
404 assert(cs_prefer_heroes_rookies_);
405 cs_soldier_capacity_display_->set_text((boost::format(ngettext("%u soldier", "%u soldiers",
406 ms->desired_capacity)) % ms->desired_capacity).str());
407 cs_soldier_capacity_decrease_->set_enabled(can_act && ms->desired_capacity > 1);
408 cs_soldier_capacity_increase_->set_enabled(can_act && ms->desired_capacity < ms->max_capacity);
409 cs_prefer_heroes_rookies_->set_state(ms->prefer_heroes ? 1 : 0);
410 } else if (upcast(Widelands::WarehouseSettings, ws, construction_site->get_settings())) {
411 if (cs_launch_expedition_) {
412 cs_launch_expedition_->set_state(ws->launch_expedition);
413 }
414#ifndef NDEBUG
415 else {
416 assert(!ws->launch_expedition);
417 }
418#endif
419 }
81}420}
82421
=== modified file 'src/wui/constructionsitewindow.h'
--- src/wui/constructionsitewindow.h 2019-02-23 11:00:49 +0000
+++ src/wui/constructionsitewindow.h 2019-06-19 09:23:26 +0000
@@ -20,9 +20,18 @@
20#ifndef WL_WUI_CONSTRUCTIONSITEWINDOW_H20#ifndef WL_WUI_CONSTRUCTIONSITEWINDOW_H
21#define WL_WUI_CONSTRUCTIONSITEWINDOW_H21#define WL_WUI_CONSTRUCTIONSITEWINDOW_H
2222
23#include <memory>
24#include <vector>
25
23#include "logic/map_objects/tribes/constructionsite.h"26#include "logic/map_objects/tribes/constructionsite.h"
27#include "ui_basic/button.h"
28#include "ui_basic/checkbox.h"
24#include "ui_basic/progressbar.h"29#include "ui_basic/progressbar.h"
30#include "ui_basic/radiobutton.h"
31#include "ui_basic/tabpanel.h"
32#include "ui_basic/textarea.h"
25#include "wui/buildingwindow.h"33#include "wui/buildingwindow.h"
34#include "wui/inputqueuedisplay.h"
2635
27/**36/**
28 * Status window for construction sites.37 * Status window for construction sites.
@@ -40,8 +49,38 @@
40 void init(bool avoid_fastclick, bool workarea_preview_wanted) override;49 void init(bool avoid_fastclick, bool workarea_preview_wanted) override;
4150
42private:51private:
52 class FakeWaresDisplay : public WaresDisplay {
53 public:
54 FakeWaresDisplay(UI::Panel* parent,
55 bool can_act,
56 Widelands::ConstructionSite& cs,
57 Widelands::WareWorker type);
58
59 protected:
60 void draw_ware(RenderTarget& dst, Widelands::DescriptionIndex ware) override;
61
62 private:
63 Widelands::WarehouseSettings& settings_;
64 const Widelands::TribeDescr& tribe_;
65 };
66
43 Widelands::OPtr<Widelands::ConstructionSite> construction_site_;67 Widelands::OPtr<Widelands::ConstructionSite> construction_site_;
44 UI::ProgressBar* progress_;68 UI::ProgressBar* progress_;
69
70 // BuildingSettings-related UI elements
71 UI::Button* cs_enhance_;
72 UI::Checkbox* cs_launch_expedition_;
73 std::unique_ptr<UI::Radiogroup> cs_prefer_heroes_rookies_;
74 UI::Button* cs_soldier_capacity_decrease_;
75 UI::Button* cs_soldier_capacity_increase_;
76 UI::Textarea* cs_soldier_capacity_display_;
77 std::vector<InputQueueDisplay*> cs_ware_queues_;
78 std::vector<InputQueueDisplay*> cs_worker_queues_;
79 UI::Checkbox* cs_stopped_;
80 FakeWaresDisplay* cs_warehouse_wares_;
81 FakeWaresDisplay* cs_warehouse_workers_;
82 void change_policy(Widelands::WareWorker, Widelands::StockPolicy);
83
45 DISALLOW_COPY_AND_ASSIGN(ConstructionSiteWindow);84 DISALLOW_COPY_AND_ASSIGN(ConstructionSiteWindow);
46};85};
4786
4887
=== modified file 'src/wui/inputqueuedisplay.cc'
--- src/wui/inputqueuedisplay.cc 2019-05-29 06:24:42 +0000
+++ src/wui/inputqueuedisplay.cc 2019-06-19 09:23:26 +0000
@@ -46,7 +46,8 @@
46 : UI::Panel(parent, x, y, 0, 28),46 : UI::Panel(parent, x, y, 0, 28),
47 igb_(igb),47 igb_(igb),
48 building_(building),48 building_(building),
49 queue_(queue),49 queue_(&queue),
50 settings_(nullptr),
50 priority_radiogroup_(nullptr),51 priority_radiogroup_(nullptr),
51 increase_max_fill_(nullptr),52 increase_max_fill_(nullptr),
52 decrease_max_fill_(nullptr),53 decrease_max_fill_(nullptr),
@@ -58,12 +59,58 @@
58 total_height_(0),59 total_height_(0),
59 show_only_(show_only) {60 show_only_(show_only) {
60 if (type_ == Widelands::wwWARE) {61 if (type_ == Widelands::wwWARE) {
61 const Widelands::WareDescr& ware = *queue.owner().tribe().get_ware_descr(queue_.get_index());62 const Widelands::WareDescr& ware = *queue.owner().tribe().get_ware_descr(queue_->get_index());
62 set_tooltip(ware.descname().c_str());63 set_tooltip(ware.descname().c_str());
63 icon_ = ware.icon();64 icon_ = ware.icon();
64 } else {65 } else {
65 const Widelands::WorkerDescr& worker =66 const Widelands::WorkerDescr& worker =
66 *queue.owner().tribe().get_worker_descr(queue_.get_index());67 *queue.owner().tribe().get_worker_descr(queue_->get_index());
68 set_tooltip(worker.descname().c_str());
69 icon_ = worker.icon();
70 }
71
72 uint16_t ph = max_fill_indicator_->height();
73
74 uint32_t priority_button_height = show_only ? 0 : 3 * PriorityButtonSize;
75 uint32_t image_height =
76 show_only ? kWareMenuPicHeight : std::max<int32_t>(kWareMenuPicHeight, ph);
77
78 total_height_ = std::max(priority_button_height, image_height) + 2 * Border;
79
80 max_size_changed();
81
82 set_thinks(true);
83}
84
85InputQueueDisplay::InputQueueDisplay(UI::Panel* const parent,
86 int32_t const x,
87 int32_t const y,
88 InteractiveGameBase& igb,
89 Widelands::ConstructionSite& building,
90 Widelands::WareWorker ww,
91 Widelands::DescriptionIndex di,
92 bool show_only)
93 : UI::Panel(parent, x, y, 0, 28),
94 igb_(igb),
95 building_(building),
96 queue_(nullptr),
97 settings_(dynamic_cast<const Widelands::ProductionsiteSettings*>(building.get_settings())),
98 priority_radiogroup_(nullptr),
99 increase_max_fill_(nullptr),
100 decrease_max_fill_(nullptr),
101 index_(di),
102 type_(ww),
103 max_fill_indicator_(g_gr->images().get(pic_max_fill_indicator)),
104 total_height_(0),
105 show_only_(show_only) {
106 cache_size_ = check_max_size();
107 cache_max_fill_ = check_max_fill();
108 if (type_ == Widelands::wwWARE) {
109 const Widelands::WareDescr& ware = *building.owner().tribe().get_ware_descr(index_);
110 set_tooltip(ware.descname().c_str());
111 icon_ = ware.icon();
112 } else {
113 const Widelands::WorkerDescr& worker = *building.owner().tribe().get_worker_descr(index_);
67 set_tooltip(worker.descname().c_str());114 set_tooltip(worker.descname().c_str());
68 icon_ = worker.icon();115 icon_ = worker.icon();
69 }116 }
@@ -85,6 +132,32 @@
85 delete priority_radiogroup_;132 delete priority_radiogroup_;
86}133}
87134
135uint32_t InputQueueDisplay::check_max_size() const {
136 if (queue_) {
137 return queue_->get_max_size();
138 }
139 assert(settings_);
140 for (const auto& pair : type_ == Widelands::wwWARE ? settings_->ware_queues : settings_->worker_queues) {
141 if (pair.first == index_) {
142 return pair.second.max_fill;
143 }
144 }
145 NEVER_HERE();
146}
147
148uint32_t InputQueueDisplay::check_max_fill() const {
149 if (queue_) {
150 return queue_->get_max_fill();
151 }
152 assert(settings_);
153 for (const auto& pair : type_ == Widelands::wwWARE ? settings_->ware_queues : settings_->worker_queues) {
154 if (pair.first == index_) {
155 return pair.second.desired_fill;
156 }
157 }
158 NEVER_HERE();
159}
160
88/**161/**
89 * Recalculate the panel's size based on the size of the queue.162 * Recalculate the panel's size based on the size of the queue.
90 *163 *
@@ -94,7 +167,7 @@
94 uint32_t pbs = show_only_ ? 0 : PriorityButtonSize;167 uint32_t pbs = show_only_ ? 0 : PriorityButtonSize;
95 uint32_t ctrl_b_size = show_only_ ? 0 : 2 * kWareMenuPicWidth;168 uint32_t ctrl_b_size = show_only_ ? 0 : 2 * kWareMenuPicWidth;
96169
97 cache_size_ = queue_.get_max_size();170 cache_size_ = check_max_size();
98171
99 update_priority_buttons();172 update_priority_buttons();
100 update_max_fill_buttons();173 update_max_fill_buttons();
@@ -111,12 +184,12 @@
111 * Compare the current InputQueue state with the cached state; update if necessary.184 * Compare the current InputQueue state with the cached state; update if necessary.
112 */185 */
113void InputQueueDisplay::think() {186void InputQueueDisplay::think() {
114 if (static_cast<uint32_t>(queue_.get_max_size()) != cache_size_)187 if (static_cast<uint32_t>(check_max_size()) != cache_size_)
115 max_size_changed();188 max_size_changed();
116189
117 // TODO(sirver): It seems cache_max_fill_ is not really useful for anything.190 // TODO(sirver): It seems cache_max_fill_ is not really useful for anything.
118 if (static_cast<uint32_t>(queue_.get_max_fill()) != cache_max_fill_) {191 if (static_cast<uint32_t>(check_max_fill()) != cache_max_fill_) {
119 cache_max_fill_ = queue_.get_max_fill();192 cache_max_fill_ = check_max_fill();
120 compute_max_fill_buttons_enabled_state();193 compute_max_fill_buttons_enabled_state();
121 }194 }
122}195}
@@ -128,11 +201,12 @@
128 if (!cache_size_)201 if (!cache_size_)
129 return;202 return;
130203
131 cache_max_fill_ = queue_.get_max_fill();204 cache_max_fill_ = check_max_fill();
132205
133 uint32_t nr_inputs_to_draw = std::min(queue_.get_filled(), cache_size_);206 uint32_t nr_inputs_to_draw = queue_ ? std::min(queue_->get_filled(), cache_size_) : cache_max_fill_;
134 uint32_t nr_missing_to_draw =207 uint32_t nr_missing_to_draw =
135 std::min(queue_.get_missing(), cache_max_fill_) + cache_size_ - cache_max_fill_;208 queue_ ? std::min(queue_->get_missing(), cache_max_fill_) + cache_size_ - cache_max_fill_ :
209 cache_size_ - cache_max_fill_;
136 if (nr_inputs_to_draw > cache_max_fill_) {210 if (nr_inputs_to_draw > cache_max_fill_) {
137 nr_missing_to_draw -= nr_inputs_to_draw - cache_max_fill_;211 nr_missing_to_draw -= nr_inputs_to_draw - cache_max_fill_;
138 }212 }
@@ -162,7 +236,7 @@
162 uint16_t pw = max_fill_indicator_->width();236 uint16_t pw = max_fill_indicator_->width();
163 point.y = Border;237 point.y = Border;
164 point.x = Border + CellWidth + CellSpacing +238 point.x = Border + CellWidth + CellSpacing +
165 (queue_.get_max_fill() * (CellWidth + CellSpacing)) - CellSpacing / 2 - pw / 2;239 (cache_max_fill_ * (CellWidth + CellSpacing)) - CellSpacing / 2 - pw / 2;
166 dst.blit(point, max_fill_indicator_);240 dst.blit(point, max_fill_indicator_);
167 }241 }
168}242}
@@ -206,13 +280,13 @@
206280
207 int32_t priority = building_.get_priority(type_, index_, false);281 int32_t priority = building_.get_priority(type_, index_, false);
208 switch (priority) {282 switch (priority) {
209 case HIGH_PRIORITY:283 case Widelands::kPriorityHigh:
210 priority_radiogroup_->set_state(0);284 priority_radiogroup_->set_state(0);
211 break;285 break;
212 case DEFAULT_PRIORITY:286 case Widelands::kPriorityNormal:
213 priority_radiogroup_->set_state(1);287 priority_radiogroup_->set_state(1);
214 break;288 break;
215 case LOW_PRIORITY:289 case Widelands::kPriorityLow:
216 priority_radiogroup_->set_state(2);290 priority_radiogroup_->set_state(2);
217 break;291 break;
218 default:292 default:
@@ -314,13 +388,13 @@
314388
315 switch (state) {389 switch (state) {
316 case 0:390 case 0:
317 priority = HIGH_PRIORITY;391 priority = Widelands::kPriorityHigh;
318 break;392 break;
319 case 1:393 case 1:
320 priority = DEFAULT_PRIORITY;394 priority = Widelands::kPriorityNormal;
321 break;395 break;
322 case 2:396 case 2:
323 priority = LOW_PRIORITY;397 priority = Widelands::kPriorityLow;
324 break;398 break;
325 default:399 default:
326 return;400 return;
327401
=== modified file 'src/wui/inputqueuedisplay.h'
--- src/wui/inputqueuedisplay.h 2019-05-06 10:53:42 +0000
+++ src/wui/inputqueuedisplay.h 2019-06-19 09:23:26 +0000
@@ -39,6 +39,8 @@
3939
40namespace Widelands {40namespace Widelands {
41class Building;41class Building;
42class ConstructionSite;
43struct ProductionsiteSettings;
42class InputQueue;44class InputQueue;
43} // namespace Widelands45} // namespace Widelands
4446
@@ -51,6 +53,7 @@
51public:53public:
52 enum { CellWidth = kWareMenuPicWidth, CellSpacing = 2, Border = 4, PriorityButtonSize = 10 };54 enum { CellWidth = kWareMenuPicWidth, CellSpacing = 2, Border = 4, PriorityButtonSize = 10 };
5355
56 // Constructor for real queues (e.g. in ProductionSites)
54 InputQueueDisplay(UI::Panel* parent,57 InputQueueDisplay(UI::Panel* parent,
55 int32_t x,58 int32_t x,
56 int32_t y,59 int32_t y,
@@ -58,6 +61,15 @@
58 Widelands::Building& building,61 Widelands::Building& building,
59 const Widelands::InputQueue& queue,62 const Widelands::InputQueue& queue,
60 bool = false);63 bool = false);
64 // Constructor for fake queues (e.g. in ConstructionSite settings)
65 InputQueueDisplay(UI::Panel* parent,
66 int32_t x,
67 int32_t y,
68 InteractiveGameBase&,
69 Widelands::ConstructionSite&,
70 Widelands::WareWorker,
71 Widelands::DescriptionIndex,
72 bool = false);
61 ~InputQueueDisplay() override;73 ~InputQueueDisplay() override;
6274
63 void think() override;75 void think() override;
@@ -66,7 +78,8 @@
66private:78private:
67 InteractiveGameBase& igb_;79 InteractiveGameBase& igb_;
68 Widelands::Building& building_;80 Widelands::Building& building_;
69 const Widelands::InputQueue& queue_;81 const Widelands::InputQueue* queue_;
82 const Widelands::ProductionsiteSettings* settings_;
70 UI::Radiogroup* priority_radiogroup_;83 UI::Radiogroup* priority_radiogroup_;
71 UI::Button* increase_max_fill_;84 UI::Button* increase_max_fill_;
72 UI::Button* decrease_max_fill_;85 UI::Button* decrease_max_fill_;
@@ -90,6 +103,9 @@
90 void update_siblings_priority(int32_t);103 void update_siblings_priority(int32_t);
91 void update_siblings_fill(int32_t);104 void update_siblings_fill(int32_t);
92105
106 uint32_t check_max_size() const;
107 uint32_t check_max_fill() const;
108
93 void compute_max_fill_buttons_enabled_state();109 void compute_max_fill_buttons_enabled_state();
94};110};
95111
96112
=== modified file 'src/wui/warehousewindow.cc'
--- src/wui/warehousewindow.cc 2019-05-01 07:20:25 +0000
+++ src/wui/warehousewindow.cc 2019-06-19 09:23:26 +0000
@@ -75,19 +75,19 @@
75void WarehouseWaresDisplay::draw_ware(RenderTarget& dst, Widelands::DescriptionIndex ware) {75void WarehouseWaresDisplay::draw_ware(RenderTarget& dst, Widelands::DescriptionIndex ware) {
76 WaresDisplay::draw_ware(dst, ware);76 WaresDisplay::draw_ware(dst, ware);
7777
78 Widelands::Warehouse::StockPolicy policy = warehouse_.get_stock_policy(get_type(), ware);78 Widelands::StockPolicy policy = warehouse_.get_stock_policy(get_type(), ware);
79 const Image* pic = nullptr;79 const Image* pic = nullptr;
80 switch (policy) {80 switch (policy) {
81 case Widelands::Warehouse::StockPolicy::kPrefer:81 case Widelands::StockPolicy::kPrefer:
82 pic = g_gr->images().get(pic_policy_prefer);82 pic = g_gr->images().get(pic_policy_prefer);
83 break;83 break;
84 case Widelands::Warehouse::StockPolicy::kDontStock:84 case Widelands::StockPolicy::kDontStock:
85 pic = g_gr->images().get(pic_policy_dontstock);85 pic = g_gr->images().get(pic_policy_dontstock);
86 break;86 break;
87 case Widelands::Warehouse::StockPolicy::kRemove:87 case Widelands::StockPolicy::kRemove:
88 pic = g_gr->images().get(pic_policy_remove);88 pic = g_gr->images().get(pic_policy_remove);
89 break;89 break;
90 case Widelands::Warehouse::StockPolicy::kNormal:90 case Widelands::StockPolicy::kNormal:
91 // don't draw anything for the normal policy91 // don't draw anything for the normal policy
92 return;92 return;
93 }93 }
@@ -106,7 +106,7 @@
106 Widelands::Warehouse&,106 Widelands::Warehouse&,
107 Widelands::WareWorker type);107 Widelands::WareWorker type);
108108
109 void set_policy(Widelands::Warehouse::StockPolicy);109 void set_policy(Widelands::StockPolicy);
110110
111private:111private:
112 InteractiveGameBase& gb_;112 InteractiveGameBase& gb_;
@@ -139,7 +139,7 @@
139 buttons, #policy, 0, 0, 34, 34, UI::ButtonStyle::kWuiMenu, \139 buttons, #policy, 0, 0, 34, 34, UI::ButtonStyle::kWuiMenu, \
140 g_gr->images().get("images/wui/buildings/stock_policy_button_" #policy ".png"), tooltip), \140 g_gr->images().get("images/wui/buildings/stock_policy_button_" #policy ".png"), tooltip), \
141 b->sigclicked.connect(boost::bind( \141 b->sigclicked.connect(boost::bind( \
142 &WarehouseWaresPanel::set_policy, this, Widelands::Warehouse::StockPolicy::k##policyname)), \142 &WarehouseWaresPanel::set_policy, this, Widelands::StockPolicy::k##policyname)), \
143 buttons->add(b);143 buttons->add(b);
144144
145 ADD_POLICY_BUTTON(normal, Normal, _("Normal policy"))145 ADD_POLICY_BUTTON(normal, Normal, _("Normal policy"))
@@ -152,7 +152,7 @@
152/**152/**
153 * Add Buttons policy buttons153 * Add Buttons policy buttons
154 */154 */
155void WarehouseWaresPanel::set_policy(Widelands::Warehouse::StockPolicy newpolicy) {155void WarehouseWaresPanel::set_policy(Widelands::StockPolicy newpolicy) {
156 if (gb_.can_act(wh_.owner().player_number())) {156 if (gb_.can_act(wh_.owner().player_number())) {
157 bool is_workers = type_ == Widelands::wwWORKER;157 bool is_workers = type_ == Widelands::wwWORKER;
158 const std::set<Widelands::DescriptionIndex> indices =158 const std::set<Widelands::DescriptionIndex> indices =