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

Proposed by Benedikt Straub
Status: Merged
Merged at revision: 9086
Proposed branch: lp:~widelands-dev/widelands/peaceful
Merge into: lp:widelands
Diff against target: 793 lines (+289/-16)
28 files modified
data/campaigns/fri02.wmf/scripting/mission_thread.lua (+26/-9)
data/scripting/win_conditions/artifacts.lua (+1/-0)
data/scripting/win_conditions/collectors.lua (+1/-0)
data/scripting/win_conditions/defeat_all.lua (+1/-0)
data/scripting/win_conditions/endless_game.lua (+1/-0)
data/scripting/win_conditions/endless_game_fogless.lua (+1/-0)
data/scripting/win_conditions/territorial_lord.lua (+1/-0)
data/scripting/win_conditions/territorial_time.lua (+1/-0)
data/scripting/win_conditions/wood_gnome.lua (+1/-0)
src/game_io/game_player_info_packet.cc (+16/-2)
src/logic/game.cc (+13/-0)
src/logic/game_settings.h (+7/-1)
src/logic/player.cc (+17/-1)
src/logic/player.h (+5/-0)
src/logic/single_player_game_settings_provider.cc (+8/-0)
src/logic/single_player_game_settings_provider.h (+3/-0)
src/network/gameclient.cc (+13/-0)
src/network/gameclient.h (+3/-0)
src/network/gamehost.cc (+28/-0)
src/network/gamehost.h (+1/-0)
src/network/network_protocol.h (+9/-1)
src/scripting/lua_game.cc (+35/-0)
src/scripting/lua_game.h (+2/-0)
src/ui_fsmenu/launch_game.cc (+29/-0)
src/ui_fsmenu/launch_game.h (+9/-0)
src/ui_fsmenu/launch_mpg.cc (+11/-2)
src/ui_fsmenu/launch_spg.cc (+8/-0)
test/maps/port_space.wmf/scripting/test_attack_forbidden.lua (+38/-0)
To merge this branch: bzr merge lp:~widelands-dev/widelands/peaceful
Reviewer Review Type Date Requested Status
Widelands Developers Pending
Review via email: mp+365273@code.launchpad.net

Commit message

Allow scripts to override the hostility of each player to each other player.
Add an option »Peaceful Mode« to the launch game screen.

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

Continuous integration builds have changed state:

Travis build 4656. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/512954165.
Appveyor build 4443. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_peaceful-4443.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Code LGTM so far except for a few nits, not tested.

I think we should also add some code to the fieldactions to forbid attacking a building, and the AI will need changing as well.

Revision history for this message
Benedikt Straub (nordfriese) wrote :

Implemented your comments.
Fieldaction and the AI already work correctly, because they use
  if (player_->is_hostile(bld->owner())) …
to see whether the aggressor is hostile to a building´s owner, and is_hostile() is where I put the important logic.
The only change the AI might need is that I´m not sure how it will handle players in a different team whom it is forbidden to attack. But when I tested the 2nd frisian scenario with these changes, it behaved well.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Tested and working.

I think we should not allow peaceful mode for territorial time, territorial lord or autocrat, because it can make those game modes unwinnable. UI-wise, you could hook into the win condition dropdown's selected signal and show/hide the checkbox.

Revision history for this message
Benedikt Straub (nordfriese) wrote :

OK, implemented that :)

Revision history for this message
GunChleoc (gunchleoc) wrote :

Code LGTM, 1 nit. Will do some testing.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Tested.

1 more thing: Tooltips that have only 1 sentence in them should not have a . at the end.

Revision history for this message
Benedikt Straub (nordfriese) wrote :

Tooltips changed

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4815. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/525048138.
Appveyor build 4596. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_peaceful-4596.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Excellent :)

@bunnybot merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'data/campaigns/fri02.wmf/scripting/mission_thread.lua'
--- data/campaigns/fri02.wmf/scripting/mission_thread.lua 2018-09-29 08:43:57 +0000
+++ data/campaigns/fri02.wmf/scripting/mission_thread.lua 2019-04-26 16:56:58 +0000
@@ -280,7 +280,8 @@
280 if not p2.defeated then280 if not p2.defeated then
281 campaign_message_box(defeat_murilius_1)281 campaign_message_box(defeat_murilius_1)
282 campaign_message_box(defeat_murilius_2)282 campaign_message_box(defeat_murilius_2)
283 p2.team = 2283 p1:set_attack_forbidden(2, false)
284 p2:set_attack_forbidden(1, false)
284 o = add_campaign_objective(obj_defeat_murilius)285 o = add_campaign_objective(obj_defeat_murilius)
285 local def = false286 local def = false
286 while not def do287 while not def do
@@ -299,7 +300,8 @@
299end300end
300301
301function defeat_murilius()302function defeat_murilius()
302 p2.team = 2303 p1:set_attack_forbidden(2, false)
304 p2:set_attack_forbidden(1, false)
303 campaign_message_box(defeat_both)305 campaign_message_box(defeat_both)
304 local o = add_campaign_objective(obj_defeat_both)306 local o = add_campaign_objective(obj_defeat_both)
305 while not (p2.defeated and p3.defeated) do sleep(4829) end307 while not (p2.defeated and p3.defeated) do sleep(4829) end
@@ -333,13 +335,28 @@
333 include "map:scripting/starting_conditions.lua"335 include "map:scripting/starting_conditions.lua"
334 sleep(5000)336 sleep(5000)
335337
336 p1.team = 1338 p1:set_attack_forbidden(2, true)
337 p2.team = 1339 p2:set_attack_forbidden(1, true)
338 p3.team = 2340 p2:set_attack_forbidden(3, true)
339-- TODO: instead of alliances, just forbid certain players to attack each other:341 run(function()
340-- · Beginning: forbid 1>2, 2>1, 2>3342 repeat
341-- · Refusing alliance: forbid only 2>3343 local conquered = (#p3:get_buildings("empire_sentry") +
342-- · Accepting alliance: first unchanged, after p3 defeated: allow all344 #p3:get_buildings("empire_blockhouse") +
345 #p3:get_buildings("empire_outpost") +
346 #p3:get_buildings("empire_barrier") +
347 #p3:get_buildings("empire_tower") +
348 #p3:get_buildings("empire_fortress") +
349 #p3:get_buildings("empire_castle") -
350 #p2:get_buildings("barbarians_sentry") -
351 #p2:get_buildings("barbarians_barrier") -
352 #p2:get_buildings("barbarians_tower") -
353 #p2:get_buildings("barbarians_fortress") -
354 #p2:get_buildings("barbarians_citadel"))
355 p2:set_attack_forbidden(3, conquered <= 0)
356 sleep(6913)
357 until p3.defeated or p2.defeated
358 p2:set_attack_forbidden(3, false)
359 end)
343360
344 campaign_message_box(intro_3)361 campaign_message_box(intro_3)
345 local o = add_campaign_objective(obj_new_home)362 local o = add_campaign_objective(obj_new_home)
346363
=== modified file 'data/scripting/win_conditions/artifacts.lua'
--- data/scripting/win_conditions/artifacts.lua 2019-04-25 12:07:53 +0000
+++ data/scripting/win_conditions/artifacts.lua 2019-04-26 16:56:58 +0000
@@ -23,6 +23,7 @@
23return {23return {
24 name = wc_name,24 name = wc_name,
25 description = wc_desc,25 description = wc_desc,
26 peaceful_mode_allowed = true,
26 map_tags = { "artifacts" }, -- Map tags needed so that this win condition will be available only for suitable maps27 map_tags = { "artifacts" }, -- Map tags needed so that this win condition will be available only for suitable maps
27 init = function()28 init = function()
28 -- Find all artifacts29 -- Find all artifacts
2930
=== modified file 'data/scripting/win_conditions/collectors.lua'
--- data/scripting/win_conditions/collectors.lua 2019-02-13 16:29:08 +0000
+++ data/scripting/win_conditions/collectors.lua 2019-04-26 16:56:58 +0000
@@ -24,6 +24,7 @@
24return {24return {
25 name = wc_name,25 name = wc_name,
26 description = wc_desc,26 description = wc_desc,
27 peaceful_mode_allowed = true,
27 func = function()28 func = function()
2829
29 -- set the objective with the game type for all players30 -- set the objective with the game type for all players
3031
=== modified file 'data/scripting/win_conditions/defeat_all.lua'
--- data/scripting/win_conditions/defeat_all.lua 2016-03-15 08:42:41 +0000
+++ data/scripting/win_conditions/defeat_all.lua 2019-04-26 16:56:58 +0000
@@ -18,6 +18,7 @@
18return {18return {
19 name = wc_name,19 name = wc_name,
20 description = wc_desc,20 description = wc_desc,
21 peaceful_mode_allowed = false,
21 func = function()22 func = function()
22 local plrs = wl.Game().players23 local plrs = wl.Game().players
2324
2425
=== modified file 'data/scripting/win_conditions/endless_game.lua'
--- data/scripting/win_conditions/endless_game.lua 2016-03-15 08:42:41 +0000
+++ data/scripting/win_conditions/endless_game.lua 2019-04-26 16:56:58 +0000
@@ -18,6 +18,7 @@
18return {18return {
19 name = wc_name,19 name = wc_name,
20 description = wc_desc,20 description = wc_desc,
21 peaceful_mode_allowed = true,
21 func = function()22 func = function()
22 local plrs = wl.Game().players23 local plrs = wl.Game().players
2324
2425
=== modified file 'data/scripting/win_conditions/endless_game_fogless.lua'
--- data/scripting/win_conditions/endless_game_fogless.lua 2016-03-15 08:42:41 +0000
+++ data/scripting/win_conditions/endless_game_fogless.lua 2019-04-26 16:56:58 +0000
@@ -18,6 +18,7 @@
18return {18return {
19 name = wc_name,19 name = wc_name,
20 description = wc_desc,20 description = wc_desc,
21 peaceful_mode_allowed = true,
21 func = function()22 func = function()
22 local plrs = wl.Game().players23 local plrs = wl.Game().players
2324
2425
=== modified file 'data/scripting/win_conditions/territorial_lord.lua'
--- data/scripting/win_conditions/territorial_lord.lua 2019-04-25 06:13:15 +0000
+++ data/scripting/win_conditions/territorial_lord.lua 2019-04-26 16:56:58 +0000
@@ -26,6 +26,7 @@
26return {26return {
27 name = wc_name,27 name = wc_name,
28 description = wc_desc,28 description = wc_desc,
29 peaceful_mode_allowed = false,
29 init = function()30 init = function()
30 fields = wl.Game().map:count_conquerable_fields()31 fields = wl.Game().map:count_conquerable_fields()
31 end,32 end,
3233
=== modified file 'data/scripting/win_conditions/territorial_time.lua'
--- data/scripting/win_conditions/territorial_time.lua 2019-04-25 06:13:15 +0000
+++ data/scripting/win_conditions/territorial_time.lua 2019-04-26 16:56:58 +0000
@@ -30,6 +30,7 @@
30return {30return {
31 name = wc_name,31 name = wc_name,
32 description = wc_desc,32 description = wc_desc,
33 peaceful_mode_allowed = false,
33 init = function()34 init = function()
34 fields = wl.Game().map:count_conquerable_fields()35 fields = wl.Game().map:count_conquerable_fields()
35 end,36 end,
3637
=== modified file 'data/scripting/win_conditions/wood_gnome.lua'
--- data/scripting/win_conditions/wood_gnome.lua 2019-03-09 10:55:24 +0000
+++ data/scripting/win_conditions/wood_gnome.lua 2019-04-26 16:56:58 +0000
@@ -24,6 +24,7 @@
24return {24return {
25 name = wc_name,25 name = wc_name,
26 description = wc_desc,26 description = wc_desc,
27 peaceful_mode_allowed = true,
27 init = function()28 init = function()
28 -- Calculate valuable fields29 -- Calculate valuable fields
29 wl.Game().map:count_terrestrial_fields()30 wl.Game().map:count_terrestrial_fields()
3031
=== modified file 'src/game_io/game_player_info_packet.cc'
--- src/game_io/game_player_info_packet.cc 2019-02-23 11:00:49 +0000
+++ src/game_io/game_player_info_packet.cc 2019-04-26 16:56:58 +0000
@@ -30,14 +30,14 @@
3030
31namespace Widelands {31namespace Widelands {
3232
33constexpr uint16_t kCurrentPacketVersion = 22;33constexpr uint16_t kCurrentPacketVersion = 23;
3434
35void GamePlayerInfoPacket::read(FileSystem& fs, Game& game, MapObjectLoader*) {35void GamePlayerInfoPacket::read(FileSystem& fs, Game& game, MapObjectLoader*) {
36 try {36 try {
37 FileRead fr;37 FileRead fr;
38 fr.open(fs, "binary/player_info");38 fr.open(fs, "binary/player_info");
39 uint16_t const packet_version = fr.unsigned_16();39 uint16_t const packet_version = fr.unsigned_16();
40 if (packet_version == kCurrentPacketVersion) {40 if (packet_version <= kCurrentPacketVersion && packet_version >= 22) {
41 uint32_t const max_players = fr.unsigned_16();41 uint32_t const max_players = fr.unsigned_16();
42 for (uint32_t i = 1; i < max_players + 1; ++i) {42 for (uint32_t i = 1; i < max_players + 1; ++i) {
43 game.remove_player(i);43 game.remove_player(i);
@@ -59,6 +59,15 @@
59 player->set_see_all(see_all);59 player->set_see_all(see_all);
6060
61 player->set_ai(fr.c_string());61 player->set_ai(fr.c_string());
62
63 if (packet_version == kCurrentPacketVersion) {
64 player->forbid_attack_.clear();
65 uint8_t size = fr.unsigned_8();
66 for (uint8_t j = 0; j < size; ++j) {
67 player->forbid_attack_.emplace(fr.unsigned_8());
68 }
69 }
70
62 player->read_statistics(fr, packet_version);71 player->read_statistics(fr, packet_version);
63 player->read_remaining_shipnames(fr);72 player->read_remaining_shipnames(fr);
6473
@@ -118,6 +127,11 @@
118 fw.c_string(plr->name_.c_str());127 fw.c_string(plr->name_.c_str());
119 fw.c_string(plr->ai_.c_str());128 fw.c_string(plr->ai_.c_str());
120129
130 fw.unsigned_8(plr->forbid_attack_.size());
131 for (const auto& it : plr->forbid_attack_) {
132 fw.unsigned_8(it);
133 }
134
121 plr->write_statistics(fw);135 plr->write_statistics(fw);
122 plr->write_remaining_shipnames(fw);136 plr->write_remaining_shipnames(fw);
123 fw.unsigned_32(plr->casualties());137 fw.unsigned_32(plr->casualties());
124138
=== modified file 'src/logic/game.cc'
--- src/logic/game.cc 2019-04-08 06:45:49 +0000
+++ src/logic/game.cc 2019-04-26 16:56:58 +0000
@@ -323,6 +323,19 @@
323 // Check for win_conditions323 // Check for win_conditions
324 if (!settings.scenario) {324 if (!settings.scenario) {
325 loader_ui->step(_("Initializing game…"));325 loader_ui->step(_("Initializing game…"));
326 if (settings.peaceful) {
327 for (uint32_t i = 1; i < settings.players.size(); ++i) {
328 if (Player* p1 = get_player(i)) {
329 for (uint32_t j = i + 1; j <= settings.players.size(); ++j) {
330 if (Player* p2 = get_player(j)) {
331 p1->set_attack_forbidden(j, true);
332 p2->set_attack_forbidden(i, true);
333 }
334 }
335 }
336 }
337 }
338
326 std::unique_ptr<LuaTable> table(lua().run_script(settings.win_condition_script));339 std::unique_ptr<LuaTable> table(lua().run_script(settings.win_condition_script));
327 table->do_not_warn_about_unaccessed_keys();340 table->do_not_warn_about_unaccessed_keys();
328 win_condition_displayname_ = table->get_string("name");341 win_condition_displayname_ = table->get_string("name");
329342
=== modified file 'src/logic/game_settings.h'
--- src/logic/game_settings.h 2019-02-23 11:00:49 +0000
+++ src/logic/game_settings.h 2019-04-26 16:56:58 +0000
@@ -111,7 +111,7 @@
111 * Think of it as the Model in MVC.111 * Think of it as the Model in MVC.
112 */112 */
113struct GameSettings {113struct GameSettings {
114 GameSettings() : playernum(0), usernum(0), scenario(false), multiplayer(false), savegame(false) {114 GameSettings() : playernum(0), usernum(0), scenario(false), multiplayer(false), savegame(false), peaceful(false) {
115 std::unique_ptr<LuaInterface> lua(new LuaInterface);115 std::unique_ptr<LuaInterface> lua(new LuaInterface);
116 std::unique_ptr<LuaTable> win_conditions(116 std::unique_ptr<LuaTable> win_conditions(
117 lua->run_script("scripting/win_conditions/init.lua"));117 lua->run_script("scripting/win_conditions/init.lua"));
@@ -156,6 +156,9 @@
156 /// Is a savegame selected for loading?156 /// Is a savegame selected for loading?
157 bool savegame;157 bool savegame;
158158
159 // Is all fighting forbidden?
160 bool peaceful;
161
159 /// List of tribes that players are allowed to choose162 /// List of tribes that players are allowed to choose
160 std::vector<Widelands::TribeBasicInfo> tribes;163 std::vector<Widelands::TribeBasicInfo> tribes;
161164
@@ -210,6 +213,9 @@
210 virtual void set_win_condition_script(const std::string& wc) = 0;213 virtual void set_win_condition_script(const std::string& wc) = 0;
211 virtual std::string get_win_condition_script() = 0;214 virtual std::string get_win_condition_script() = 0;
212215
216 virtual void set_peaceful_mode(bool peace) = 0;
217 virtual bool is_peaceful_mode() = 0;
218
213 // For retrieving tips texts219 // For retrieving tips texts
214 struct NoTribe {};220 struct NoTribe {};
215 const std::string& get_players_tribe() {221 const std::string& get_players_tribe() {
216222
=== modified file 'src/logic/player.cc'
--- src/logic/player.cc 2019-04-24 06:01:37 +0000
+++ src/logic/player.cc 2019-04-26 16:56:58 +0000
@@ -254,7 +254,8 @@
254 * each other.254 * each other.
255 */255 */
256bool Player::is_hostile(const Player& other) const {256bool Player::is_hostile(const Player& other) const {
257 return &other != this && (!team_number_ || team_number_ != other.team_number_);257 return &other != this && (!team_number_ || team_number_ != other.team_number_) &&
258 !is_attack_forbidden(other.player_number());
258}259}
259260
260bool Player::is_defeated() const {261bool Player::is_defeated() const {
@@ -1334,6 +1335,21 @@
1334 return ai_;1335 return ai_;
1335}1336}
13361337
1338bool Player::is_attack_forbidden(PlayerNumber who) const {
1339 return forbid_attack_.find(who) != forbid_attack_.end();
1340}
1341
1342void Player::set_attack_forbidden(PlayerNumber who, bool forbid) {
1343 const auto it = forbid_attack_.find(who);
1344 if (forbid ^ (it == forbid_attack_.end())) {
1345 return;
1346 } else if (forbid) {
1347 forbid_attack_.emplace(who);
1348 } else {
1349 forbid_attack_.erase(it);
1350 }
1351}
1352
1337/**1353/**
1338 * Pick random name from remaining names (if any)1354 * Pick random name from remaining names (if any)
1339 */1355 */
13401356
=== modified file 'src/logic/player.h'
--- src/logic/player.h 2019-03-17 11:44:04 +0000
+++ src/logic/player.h 2019-04-26 16:56:58 +0000
@@ -604,6 +604,9 @@
604 further_initializations_.push_back(init);604 further_initializations_.push_back(init);
605 }605 }
606606
607 void set_attack_forbidden(PlayerNumber who, bool forbid);
608 bool is_attack_forbidden(PlayerNumber who) const;
609
607 const std::string pick_shipname();610 const std::string pick_shipname();
608611
609private:612private:
@@ -681,6 +684,8 @@
681 */684 */
682 std::vector<std::vector<uint32_t>> ware_stocks_;685 std::vector<std::vector<uint32_t>> ware_stocks_;
683686
687 std::set<PlayerNumber> forbid_attack_;
688
684 PlayerBuildingStats building_stats_;689 PlayerBuildingStats building_stats_;
685690
686 FxId message_fx_;691 FxId message_fx_;
687692
=== modified file 'src/logic/single_player_game_settings_provider.cc'
--- src/logic/single_player_game_settings_provider.cc 2019-02-23 11:00:49 +0000
+++ src/logic/single_player_game_settings_provider.cc 2019-04-26 16:56:58 +0000
@@ -69,6 +69,14 @@
69 return s.mapfilename;69 return s.mapfilename;
70}70}
7171
72bool SinglePlayerGameSettingsProvider::is_peaceful_mode() {
73 return s.peaceful;
74}
75
76void SinglePlayerGameSettingsProvider::set_peaceful_mode(bool peace) {
77 s.peaceful = peace;
78}
79
72void SinglePlayerGameSettingsProvider::set_map(const std::string& mapname,80void SinglePlayerGameSettingsProvider::set_map(const std::string& mapname,
73 const std::string& mapfilename,81 const std::string& mapfilename,
74 uint32_t const maxplayers,82 uint32_t const maxplayers,
7583
=== modified file 'src/logic/single_player_game_settings_provider.h'
--- src/logic/single_player_game_settings_provider.h 2019-02-23 11:00:49 +0000
+++ src/logic/single_player_game_settings_provider.h 2019-04-26 16:56:58 +0000
@@ -62,6 +62,9 @@
62 std::string get_win_condition_script() override;62 std::string get_win_condition_script() override;
63 void set_win_condition_script(const std::string& wc) override;63 void set_win_condition_script(const std::string& wc) override;
6464
65 void set_peaceful_mode(bool peace) override;
66 bool is_peaceful_mode() override;
67
65private:68private:
66 GameSettings s;69 GameSettings s;
67};70};
6871
=== modified file 'src/network/gameclient.cc'
--- src/network/gameclient.cc 2019-02-23 11:00:49 +0000
+++ src/network/gameclient.cc 2019-04-26 16:56:58 +0000
@@ -405,6 +405,15 @@
405 // set_player_number(uint8_t) to the host.405 // set_player_number(uint8_t) to the host.
406}406}
407407
408
409void GameClient::set_peaceful_mode(bool peace) {
410 d->settings.peaceful = peace;
411}
412
413bool GameClient::is_peaceful_mode() {
414 return d->settings.peaceful;
415}
416
408std::string GameClient::get_win_condition_script() {417std::string GameClient::get_win_condition_script() {
409 return d->settings.win_condition_script;418 return d->settings.win_condition_script;
410}419}
@@ -819,6 +828,10 @@
819 d->settings.win_condition_script = g_fs->FileSystem::fix_cross_file(packet.string());828 d->settings.win_condition_script = g_fs->FileSystem::fix_cross_file(packet.string());
820 break;829 break;
821 }830 }
831 case NETCMD_PEACEFUL_MODE: {
832 d->settings.peaceful = packet.unsigned_8();
833 break;
834 }
822835
823 case NETCMD_LAUNCH: {836 case NETCMD_LAUNCH: {
824 if (!d->modal || d->game) {837 if (!d->modal || d->game) {
825838
=== modified file 'src/network/gameclient.h'
--- src/network/gameclient.h 2019-02-23 11:00:49 +0000
+++ src/network/gameclient.h 2019-04-26 16:56:58 +0000
@@ -95,6 +95,9 @@
95 void set_win_condition_script(const std::string&) override;95 void set_win_condition_script(const std::string&) override;
96 std::string get_win_condition_script() override;96 std::string get_win_condition_script() override;
9797
98 void set_peaceful_mode(bool peace) override;
99 bool is_peaceful_mode() override;
100
98 // ChatProvider interface101 // ChatProvider interface
99 void send(const std::string& msg) override;102 void send(const std::string& msg) override;
100 const std::vector<ChatMessage>& get_messages() const override;103 const std::vector<ChatMessage>& get_messages() const override;
101104
=== modified file 'src/network/gamehost.cc'
--- src/network/gamehost.cc 2019-02-23 11:00:49 +0000
+++ src/network/gamehost.cc 2019-04-26 16:56:58 +0000
@@ -203,6 +203,13 @@
203 host_->set_win_condition_script(wc);203 host_->set_win_condition_script(wc);
204 }204 }
205205
206 void set_peaceful_mode(bool peace) override {
207 host_->set_peaceful_mode(peace);
208 }
209 bool is_peaceful_mode() override {
210 return host_->settings().peaceful;
211 }
212
206private:213private:
207 GameHost* host_;214 GameHost* host_;
208 std::vector<std::string> wincondition_scripts_;215 std::vector<std::string> wincondition_scripts_;
@@ -1368,6 +1375,16 @@
1368 broadcast(packet);1375 broadcast(packet);
1369}1376}
13701377
1378void GameHost::set_peaceful_mode(bool peace) {
1379 d->settings.peaceful = peace;
1380
1381 // Broadcast changes
1382 SendPacket packet;
1383 packet.unsigned_8(NETCMD_PEACEFUL_MODE);
1384 packet.unsigned_8(peace ? 1 : 0);
1385 broadcast(packet);
1386}
1387
1371void GameHost::switch_to_player(uint32_t user, uint8_t number) {1388void GameHost::switch_to_player(uint32_t user, uint8_t number) {
1372 if (number < d->settings.players.size() &&1389 if (number < d->settings.players.size() &&
1373 (d->settings.players.at(number).state != PlayerSettings::State::kOpen &&1390 (d->settings.players.at(number).state != PlayerSettings::State::kOpen &&
@@ -1676,6 +1693,11 @@
1676 packet.string(d->settings.win_condition_script);1693 packet.string(d->settings.win_condition_script);
1677 d->net->send(client.sock_id, packet);1694 d->net->send(client.sock_id, packet);
16781695
1696 packet.reset();
1697 packet.unsigned_8(NETCMD_PEACEFUL_MODE);
1698 packet.unsigned_8(d->settings.peaceful ? 1 : 0);
1699 d->net->send(client.sock_id, packet);
1700
1679 // Broadcast new information about the player to everybody1701 // Broadcast new information about the player to everybody
1680 packet.reset();1702 packet.reset();
1681 packet.unsigned_8(NETCMD_SETTING_USER);1703 packet.unsigned_8(NETCMD_SETTING_USER);
@@ -2143,6 +2165,12 @@
2143 }2165 }
2144 break;2166 break;
21452167
2168 case NETCMD_PEACEFUL_MODE:
2169 if (!d->game) {
2170 throw DisconnectException("NO_ACCESS_TO_SERVER");
2171 }
2172 break;
2173
2146 case NETCMD_LAUNCH:2174 case NETCMD_LAUNCH:
2147 if (!d->game) {2175 if (!d->game) {
2148 throw DisconnectException("NO_ACCESS_TO_SERVER");2176 throw DisconnectException("NO_ACCESS_TO_SERVER");
21492177
=== modified file 'src/network/gamehost.h'
--- src/network/gamehost.h 2019-02-23 11:00:49 +0000
+++ src/network/gamehost.h 2019-04-26 16:56:58 +0000
@@ -80,6 +80,7 @@
80 void set_player_shared(PlayerSlot number, Widelands::PlayerNumber shared);80 void set_player_shared(PlayerSlot number, Widelands::PlayerNumber shared);
81 void switch_to_player(uint32_t user, uint8_t number);81 void switch_to_player(uint32_t user, uint8_t number);
82 void set_win_condition_script(const std::string& wc);82 void set_win_condition_script(const std::string& wc);
83 void set_peaceful_mode(bool peace);
83 void replace_client_with_ai(uint8_t playernumber, const std::string& ai);84 void replace_client_with_ai(uint8_t playernumber, const std::string& ai);
8485
85 // just visible stuff for the select mapmenu86 // just visible stuff for the select mapmenu
8687
=== modified file 'src/network/network_protocol.h'
--- src/network/network_protocol.h 2019-02-23 11:00:49 +0000
+++ src/network/network_protocol.h 2019-04-26 16:56:58 +0000
@@ -28,7 +28,7 @@
28 * The current version of the in-game network protocol. Client and host28 * The current version of the in-game network protocol. Client and host
29 * protocol versions must match.29 * protocol versions must match.
30 */30 */
31 NETWORK_PROTOCOL_VERSION = 22,31 NETWORK_PROTOCOL_VERSION = 23,
3232
33 /**33 /**
34 * The default interval (in milliseconds) in which the host issues34 * The default interval (in milliseconds) in which the host issues
@@ -429,6 +429,14 @@
429 NETCMD_SYSTEM_MESSAGE_CODE = 32,429 NETCMD_SYSTEM_MESSAGE_CODE = 32,
430430
431 /**431 /**
432 * Sent by the host to toggle peaceful mode.
433 *
434 * Attached data is:
435 * \li uint8_t: 1 if peaceful mode is enabled, 0 otherwise
436 */
437 NETCMD_PEACEFUL_MODE = 33,
438
439 /**
432 * Sent by the metaserver to a freshly opened game to check connectability440 * Sent by the metaserver to a freshly opened game to check connectability
433 */441 */
434 NETCMD_METASERVER_PING = 64442 NETCMD_METASERVER_PING = 64
435443
=== modified file 'src/scripting/lua_game.cc'
--- src/scripting/lua_game.cc 2019-04-24 06:43:22 +0000
+++ src/scripting/lua_game.cc 2019-04-26 16:56:58 +0000
@@ -100,6 +100,8 @@
100 METHOD(LuaPlayer, allow_workers),100 METHOD(LuaPlayer, allow_workers),
101 METHOD(LuaPlayer, switchplayer),101 METHOD(LuaPlayer, switchplayer),
102 METHOD(LuaPlayer, get_produced_wares_count),102 METHOD(LuaPlayer, get_produced_wares_count),
103 METHOD(LuaPlayer, set_attack_forbidden),
104 METHOD(LuaPlayer, is_attack_forbidden),
103 {nullptr, nullptr},105 {nullptr, nullptr},
104};106};
105const PropertyType<LuaPlayer> LuaPlayer::Properties[] = {107const PropertyType<LuaPlayer> LuaPlayer::Properties[] = {
@@ -856,6 +858,39 @@
856 return 1;858 return 1;
857}859}
858860
861/* RST
862 .. method:: is_attack_forbidden(who)
863
864 Returns true if this player is currently forbidden to attack the player with the specified
865 player number. Note that the return value `false` does not necessarily mean that this
866 player *can* attack the other player, as they might for example be in the same team.
867
868 :arg who: player number of the player to query
869 :type who: :class:`int`
870 :rtype: :class:`boolean`
871*/
872int LuaPlayer::is_attack_forbidden(lua_State* L) {
873 lua_pushboolean(L, get(L, get_egbase(L)).is_attack_forbidden(luaL_checkinteger(L, 2)));
874 return 1;
875}
876
877/* RST
878 .. method:: set_attack_forbidden(who, forbid)
879
880 Sets whether this player is forbidden to attack the player with the specified
881 player number. Note that setting this to `false` does not necessarily mean that this
882 player *can* attack the other player, as they might for example be in the same team.
883
884 :arg who: player number of the player to query
885 :type who: :class:`int`
886 :arg forbid: Whether to allow or forbid attacks
887 :type forbid: :class:`boolean`
888*/
889int LuaPlayer::set_attack_forbidden(lua_State* L) {
890 get(L, get_egbase(L)).set_attack_forbidden(luaL_checkinteger(L, 2), luaL_checkboolean(L, 3));
891 return 0;
892}
893
859/*894/*
860 ==========================================================895 ==========================================================
861 C METHODS896 C METHODS
862897
=== modified file 'src/scripting/lua_game.h'
--- src/scripting/lua_game.h 2019-04-18 16:50:35 +0000
+++ src/scripting/lua_game.h 2019-04-26 16:56:58 +0000
@@ -96,6 +96,8 @@
96 int allow_workers(lua_State* L);96 int allow_workers(lua_State* L);
97 int switchplayer(lua_State* L);97 int switchplayer(lua_State* L);
98 int get_produced_wares_count(lua_State* L);98 int get_produced_wares_count(lua_State* L);
99 int set_attack_forbidden(lua_State* L);
100 int is_attack_forbidden(lua_State* L);
99101
100 /*102 /*
101 * C methods103 * C methods
102104
=== modified file 'src/ui_fsmenu/launch_game.cc'
--- src/ui_fsmenu/launch_game.cc 2019-02-23 11:00:49 +0000
+++ src/ui_fsmenu/launch_game.cc 2019-04-26 16:56:58 +0000
@@ -55,6 +55,11 @@
55 "",55 "",
56 UI::DropdownType::kTextual,56 UI::DropdownType::kTextual,
57 UI::PanelStyle::kFsMenu),57 UI::PanelStyle::kFsMenu),
58
59 peaceful_(this,
60 Vector2i(get_w() * 7 / 10,
61 get_h() * 19 / 40 + buth_),
62 _("Peaceful mode")),
58 ok_(this, "ok", 0, 0, butw_, buth_, UI::ButtonStyle::kFsMenuPrimary, _("Start game")),63 ok_(this, "ok", 0, 0, butw_, buth_, UI::ButtonStyle::kFsMenuPrimary, _("Start game")),
59 back_(this, "back", 0, 0, butw_, buth_, UI::ButtonStyle::kFsMenuSecondary, _("Back")),64 back_(this, "back", 0, 0, butw_, buth_, UI::ButtonStyle::kFsMenuSecondary, _("Back")),
60 // Text labels65 // Text labels
@@ -62,9 +67,12 @@
62 // Variables and objects used in the menu67 // Variables and objects used in the menu
63 settings_(settings),68 settings_(settings),
64 ctrl_(ctrl),69 ctrl_(ctrl),
70 peaceful_mode_forbidden_(false),
65 nr_players_(0) {71 nr_players_(0) {
66 win_condition_dropdown_.selected.connect(72 win_condition_dropdown_.selected.connect(
67 boost::bind(&FullscreenMenuLaunchGame::win_condition_selected, this));73 boost::bind(&FullscreenMenuLaunchGame::win_condition_selected, this));
74 peaceful_.changed.connect(
75 boost::bind(&FullscreenMenuLaunchGame::toggle_peaceful, this));
68 back_.sigclicked.connect(76 back_.sigclicked.connect(
69 boost::bind(&FullscreenMenuLaunchGame::clicked_back, boost::ref(*this)));77 boost::bind(&FullscreenMenuLaunchGame::clicked_back, boost::ref(*this)));
70 ok_.sigclicked.connect(boost::bind(&FullscreenMenuLaunchGame::clicked_ok, boost::ref(*this)));78 ok_.sigclicked.connect(boost::bind(&FullscreenMenuLaunchGame::clicked_ok, boost::ref(*this)));
@@ -78,6 +86,23 @@
78 delete lua_;86 delete lua_;
79}87}
8088
89void FullscreenMenuLaunchGame::update_peaceful_mode() {
90 bool forbidden = peaceful_mode_forbidden_ || settings_->settings().scenario || settings_->settings().savegame;
91 peaceful_.set_enabled(!forbidden && settings_->can_change_map());
92 if (forbidden) {
93 peaceful_.set_state(false);
94 }
95 if (settings_->settings().scenario) {
96 peaceful_.set_tooltip(_("The relations between players are set by the scenario"));
97 } else if (settings_->settings().savegame) {
98 peaceful_.set_tooltip(_("The relations between players are set by the saved game"));
99 } else if (peaceful_mode_forbidden_) {
100 peaceful_.set_tooltip(_("The selected win condition does not allow peaceful matches"));
101 } else {
102 peaceful_.set_tooltip(_("Forbid fighting between players"));
103 }
104}
105
81bool FullscreenMenuLaunchGame::init_win_condition_label() {106bool FullscreenMenuLaunchGame::init_win_condition_label() {
82 if (settings_->settings().scenario) {107 if (settings_->settings().scenario) {
83 win_condition_dropdown_.set_enabled(false);108 win_condition_dropdown_.set_enabled(false);
@@ -190,6 +215,10 @@
190 return t;215 return t;
191}216}
192217
218void FullscreenMenuLaunchGame::toggle_peaceful() {
219 settings_->set_peaceful_mode(peaceful_.get_state());
220}
221
193// Implemented by subclasses222// Implemented by subclasses
194void FullscreenMenuLaunchGame::clicked_ok() {223void FullscreenMenuLaunchGame::clicked_ok() {
195 NEVER_HERE();224 NEVER_HERE();
196225
=== modified file 'src/ui_fsmenu/launch_game.h'
--- src/ui_fsmenu/launch_game.h 2019-02-23 11:00:49 +0000
+++ src/ui_fsmenu/launch_game.h 2019-04-26 16:56:58 +0000
@@ -26,6 +26,7 @@
26#include "graphic/playercolor.h"26#include "graphic/playercolor.h"
27#include "logic/map.h"27#include "logic/map.h"
28#include "ui_basic/button.h"28#include "ui_basic/button.h"
29#include "ui_basic/checkbox.h"
29#include "ui_basic/dropdown.h"30#include "ui_basic/dropdown.h"
30#include "ui_basic/textarea.h"31#include "ui_basic/textarea.h"
31#include "ui_fsmenu/base.h"32#include "ui_fsmenu/base.h"
@@ -56,6 +57,9 @@
56 /// Creates a blank label/tooltip and returns 'false' otherwise.57 /// Creates a blank label/tooltip and returns 'false' otherwise.
57 bool init_win_condition_label();58 bool init_win_condition_label();
5859
60 /// Enables or disables the peaceful mode checkbox.
61 void update_peaceful_mode();
62
59 /// Loads all win conditions that can be played with the map into the selection dropdown.63 /// Loads all win conditions that can be played with the map into the selection dropdown.
60 /// Disables the dropdown if the map is a scenario.64 /// Disables the dropdown if the map is a scenario.
61 void update_win_conditions();65 void update_win_conditions();
@@ -71,16 +75,21 @@
71 std::unique_ptr<LuaTable> win_condition_if_valid(const std::string& win_condition_script,75 std::unique_ptr<LuaTable> win_condition_if_valid(const std::string& win_condition_script,
72 std::set<std::string> tags) const;76 std::set<std::string> tags) const;
7377
78 void toggle_peaceful();
79
74 uint32_t butw_;80 uint32_t butw_;
75 uint32_t buth_;81 uint32_t buth_;
7682
77 UI::Dropdown<std::string> win_condition_dropdown_;83 UI::Dropdown<std::string> win_condition_dropdown_;
84 UI::Checkbox peaceful_;
78 std::string last_win_condition_;85 std::string last_win_condition_;
79 UI::Button ok_, back_;86 UI::Button ok_, back_;
80 UI::Textarea title_;87 UI::Textarea title_;
81 GameSettingsProvider* settings_;88 GameSettingsProvider* settings_;
82 GameController* ctrl_;89 GameController* ctrl_;
8390
91 bool peaceful_mode_forbidden_;
92
84 Widelands::PlayerNumber nr_players_;93 Widelands::PlayerNumber nr_players_;
85};94};
8695
8796
=== modified file 'src/ui_fsmenu/launch_mpg.cc'
--- src/ui_fsmenu/launch_mpg.cc 2019-02-23 11:00:49 +0000
+++ src/ui_fsmenu/launch_mpg.cc 2019-04-26 16:56:58 +0000
@@ -159,7 +159,7 @@
159 UI::PanelStyle::kFsMenu),159 UI::PanelStyle::kFsMenu),
160 client_info_(this,160 client_info_(this,
161 right_column_x_,161 right_column_x_,
162 get_h() * 13 / 20 - 2 * label_height_,162 get_h() * 15 / 20 - 2 * label_height_,
163 butw_,163 butw_,
164 get_h(),164 get_h(),
165 UI::PanelStyle::kFsMenu),165 UI::PanelStyle::kFsMenu),
@@ -167,7 +167,8 @@
167167
168 // Variables and objects used in the menu168 // Variables and objects used in the menu
169 chat_(nullptr) {169 chat_(nullptr) {
170 ok_.set_pos(Vector2i(right_column_x_, get_h() * 12 / 20 - 2 * label_height_));170 peaceful_.set_pos(Vector2i(right_column_x_, get_h() * 25 / 40 - 2 * label_height_));
171 ok_.set_pos(Vector2i(right_column_x_, get_h() * 14 / 20 - 2 * label_height_));
171 back_.set_pos(Vector2i(right_column_x_, get_h() * 218 / 240));172 back_.set_pos(Vector2i(right_column_x_, get_h() * 218 / 240));
172 win_condition_dropdown_.set_pos(173 win_condition_dropdown_.set_pos(
173 Vector2i(right_column_x_, get_h() * 11 / 20 - 2 * label_height_));174 Vector2i(right_column_x_, get_h() * 11 / 20 - 2 * label_height_));
@@ -240,6 +241,11 @@
240 if (settings_->can_change_map() && win_condition_dropdown_.has_selection()) {241 if (settings_->can_change_map() && win_condition_dropdown_.has_selection()) {
241 settings_->set_win_condition_script(win_condition_dropdown_.get_selected());242 settings_->set_win_condition_script(win_condition_dropdown_.get_selected());
242 last_win_condition_ = win_condition_dropdown_.get_selected();243 last_win_condition_ = win_condition_dropdown_.get_selected();
244
245 std::unique_ptr<LuaTable> t = lua_->run_script(last_win_condition_);
246 t->do_not_warn_about_unaccessed_keys();
247 peaceful_mode_forbidden_ = !t->get_bool("peaceful_mode_allowed");
248 update_peaceful_mode();
243 }249 }
244}250}
245251
@@ -422,6 +428,9 @@
422 change_map_or_save_.set_enabled(settings_->can_change_map());428 change_map_or_save_.set_enabled(settings_->can_change_map());
423 change_map_or_save_.set_visible(settings_->can_change_map());429 change_map_or_save_.set_visible(settings_->can_change_map());
424430
431 update_peaceful_mode();
432 peaceful_.set_state(settings_->is_peaceful_mode());
433
425 if (!settings_->can_change_map() && !init_win_condition_label()) {434 if (!settings_->can_change_map() && !init_win_condition_label()) {
426 try {435 try {
427 // We do not validate the scripts for the client - it's only a label.436 // We do not validate the scripts for the client - it's only a label.
428437
=== modified file 'src/ui_fsmenu/launch_spg.cc'
--- src/ui_fsmenu/launch_spg.cc 2019-02-23 11:00:49 +0000
+++ src/ui_fsmenu/launch_spg.cc 2019-04-26 16:56:58 +0000
@@ -166,6 +166,11 @@
166void FullscreenMenuLaunchSPG::win_condition_selected() {166void FullscreenMenuLaunchSPG::win_condition_selected() {
167 if (win_condition_dropdown_.has_selection()) {167 if (win_condition_dropdown_.has_selection()) {
168 last_win_condition_ = win_condition_dropdown_.get_selected();168 last_win_condition_ = win_condition_dropdown_.get_selected();
169
170 std::unique_ptr<LuaTable> t = lua_->run_script(last_win_condition_);
171 t->do_not_warn_about_unaccessed_keys();
172 peaceful_mode_forbidden_ = !t->get_bool("peaceful_mode_allowed");
173 update_peaceful_mode();
169 }174 }
170}175}
171176
@@ -217,6 +222,8 @@
217 select_map_.set_visible(settings_->can_change_map());222 select_map_.set_visible(settings_->can_change_map());
218 select_map_.set_enabled(settings_->can_change_map());223 select_map_.set_enabled(settings_->can_change_map());
219224
225 peaceful_.set_state(settings_->is_peaceful_mode());
226
220 set_player_names_and_tribes();227 set_player_names_and_tribes();
221 }228 }
222229
@@ -262,6 +269,7 @@
262 safe_place_for_host(nr_players_);269 safe_place_for_host(nr_players_);
263 settings_->set_map(mapdata.name, mapdata.filename, nr_players_);270 settings_->set_map(mapdata.name, mapdata.filename, nr_players_);
264 update_win_conditions();271 update_win_conditions();
272 update_peaceful_mode();
265 update(true);273 update(true);
266 return true;274 return true;
267}275}
268276
=== added file 'test/maps/port_space.wmf/scripting/test_attack_forbidden.lua'
--- test/maps/port_space.wmf/scripting/test_attack_forbidden.lua 1970-01-01 00:00:00 +0000
+++ test/maps/port_space.wmf/scripting/test_attack_forbidden.lua 2019-04-26 16:56:58 +0000
@@ -0,0 +1,38 @@
1run(function()
2 -- Initially, no overrides exist
3 assert_equal(false, p1:is_attack_forbidden(2))
4 assert_equal(false, p2:is_attack_forbidden(1))
5 -- No dumbness checks should take place
6 assert_equal(false, p1:is_attack_forbidden(1))
7 assert_equal(false, p2:is_attack_forbidden(2))
8 assert_equal(false, p1:is_attack_forbidden(3))
9
10 p1:set_attack_forbidden(2, true)
11
12 assert_equal(true, p1:is_attack_forbidden(2))
13 assert_equal(false, p2:is_attack_forbidden(1))
14 assert_equal(false, p1:is_attack_forbidden(3))
15
16 p2:set_attack_forbidden(3, true)
17
18 assert_equal(true, p1:is_attack_forbidden(2))
19 assert_equal(false, p2:is_attack_forbidden(1))
20 assert_equal(false, p1:is_attack_forbidden(3))
21 assert_equal(true, p2:is_attack_forbidden(3))
22
23 p2:set_attack_forbidden(1, true)
24
25 assert_equal(true, p1:is_attack_forbidden(2))
26 assert_equal(true, p2:is_attack_forbidden(1))
27 assert_equal(true, p2:is_attack_forbidden(3))
28
29 p2:set_attack_forbidden(1, false)
30 p1:set_attack_forbidden(2, false)
31
32 assert_equal(false, p2:is_attack_forbidden(1))
33 assert_equal(false, p1:is_attack_forbidden(2))
34 assert_equal(true, p2:is_attack_forbidden(3))
35
36 print("# All Tests passed.")
37 wl.ui.MapView():close()
38end)

Subscribers

People subscribed via source and target branches

to status/vote changes: