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.

lp:~widelands-dev/widelands/peaceful updated
9025. By Nordfriese

Adressed code review

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.

lp:~widelands-dev/widelands/peaceful updated
9026. By Nordfriese

Allow win conditions to forbid peaceful mode; nicer tooltips

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.

lp:~widelands-dev/widelands/peaceful updated
9027. By Nordfriese

Adjusted tooltips

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

Tooltips changed

lp:~widelands-dev/widelands/peaceful updated
9028. By Nordfriese

Merged trunk

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
1=== modified file 'data/campaigns/fri02.wmf/scripting/mission_thread.lua'
2--- data/campaigns/fri02.wmf/scripting/mission_thread.lua 2018-09-29 08:43:57 +0000
3+++ data/campaigns/fri02.wmf/scripting/mission_thread.lua 2019-04-26 16:56:58 +0000
4@@ -280,7 +280,8 @@
5 if not p2.defeated then
6 campaign_message_box(defeat_murilius_1)
7 campaign_message_box(defeat_murilius_2)
8- p2.team = 2
9+ p1:set_attack_forbidden(2, false)
10+ p2:set_attack_forbidden(1, false)
11 o = add_campaign_objective(obj_defeat_murilius)
12 local def = false
13 while not def do
14@@ -299,7 +300,8 @@
15 end
16
17 function defeat_murilius()
18- p2.team = 2
19+ p1:set_attack_forbidden(2, false)
20+ p2:set_attack_forbidden(1, false)
21 campaign_message_box(defeat_both)
22 local o = add_campaign_objective(obj_defeat_both)
23 while not (p2.defeated and p3.defeated) do sleep(4829) end
24@@ -333,13 +335,28 @@
25 include "map:scripting/starting_conditions.lua"
26 sleep(5000)
27
28- p1.team = 1
29- p2.team = 1
30- p3.team = 2
31--- TODO: instead of alliances, just forbid certain players to attack each other:
32--- · Beginning: forbid 1>2, 2>1, 2>3
33--- · Refusing alliance: forbid only 2>3
34--- · Accepting alliance: first unchanged, after p3 defeated: allow all
35+ p1:set_attack_forbidden(2, true)
36+ p2:set_attack_forbidden(1, true)
37+ p2:set_attack_forbidden(3, true)
38+ run(function()
39+ repeat
40+ local conquered = (#p3:get_buildings("empire_sentry") +
41+ #p3:get_buildings("empire_blockhouse") +
42+ #p3:get_buildings("empire_outpost") +
43+ #p3:get_buildings("empire_barrier") +
44+ #p3:get_buildings("empire_tower") +
45+ #p3:get_buildings("empire_fortress") +
46+ #p3:get_buildings("empire_castle") -
47+ #p2:get_buildings("barbarians_sentry") -
48+ #p2:get_buildings("barbarians_barrier") -
49+ #p2:get_buildings("barbarians_tower") -
50+ #p2:get_buildings("barbarians_fortress") -
51+ #p2:get_buildings("barbarians_citadel"))
52+ p2:set_attack_forbidden(3, conquered <= 0)
53+ sleep(6913)
54+ until p3.defeated or p2.defeated
55+ p2:set_attack_forbidden(3, false)
56+ end)
57
58 campaign_message_box(intro_3)
59 local o = add_campaign_objective(obj_new_home)
60
61=== modified file 'data/scripting/win_conditions/artifacts.lua'
62--- data/scripting/win_conditions/artifacts.lua 2019-04-25 12:07:53 +0000
63+++ data/scripting/win_conditions/artifacts.lua 2019-04-26 16:56:58 +0000
64@@ -23,6 +23,7 @@
65 return {
66 name = wc_name,
67 description = wc_desc,
68+ peaceful_mode_allowed = true,
69 map_tags = { "artifacts" }, -- Map tags needed so that this win condition will be available only for suitable maps
70 init = function()
71 -- Find all artifacts
72
73=== modified file 'data/scripting/win_conditions/collectors.lua'
74--- data/scripting/win_conditions/collectors.lua 2019-02-13 16:29:08 +0000
75+++ data/scripting/win_conditions/collectors.lua 2019-04-26 16:56:58 +0000
76@@ -24,6 +24,7 @@
77 return {
78 name = wc_name,
79 description = wc_desc,
80+ peaceful_mode_allowed = true,
81 func = function()
82
83 -- set the objective with the game type for all players
84
85=== modified file 'data/scripting/win_conditions/defeat_all.lua'
86--- data/scripting/win_conditions/defeat_all.lua 2016-03-15 08:42:41 +0000
87+++ data/scripting/win_conditions/defeat_all.lua 2019-04-26 16:56:58 +0000
88@@ -18,6 +18,7 @@
89 return {
90 name = wc_name,
91 description = wc_desc,
92+ peaceful_mode_allowed = false,
93 func = function()
94 local plrs = wl.Game().players
95
96
97=== modified file 'data/scripting/win_conditions/endless_game.lua'
98--- data/scripting/win_conditions/endless_game.lua 2016-03-15 08:42:41 +0000
99+++ data/scripting/win_conditions/endless_game.lua 2019-04-26 16:56:58 +0000
100@@ -18,6 +18,7 @@
101 return {
102 name = wc_name,
103 description = wc_desc,
104+ peaceful_mode_allowed = true,
105 func = function()
106 local plrs = wl.Game().players
107
108
109=== modified file 'data/scripting/win_conditions/endless_game_fogless.lua'
110--- data/scripting/win_conditions/endless_game_fogless.lua 2016-03-15 08:42:41 +0000
111+++ data/scripting/win_conditions/endless_game_fogless.lua 2019-04-26 16:56:58 +0000
112@@ -18,6 +18,7 @@
113 return {
114 name = wc_name,
115 description = wc_desc,
116+ peaceful_mode_allowed = true,
117 func = function()
118 local plrs = wl.Game().players
119
120
121=== modified file 'data/scripting/win_conditions/territorial_lord.lua'
122--- data/scripting/win_conditions/territorial_lord.lua 2019-04-25 06:13:15 +0000
123+++ data/scripting/win_conditions/territorial_lord.lua 2019-04-26 16:56:58 +0000
124@@ -26,6 +26,7 @@
125 return {
126 name = wc_name,
127 description = wc_desc,
128+ peaceful_mode_allowed = false,
129 init = function()
130 fields = wl.Game().map:count_conquerable_fields()
131 end,
132
133=== modified file 'data/scripting/win_conditions/territorial_time.lua'
134--- data/scripting/win_conditions/territorial_time.lua 2019-04-25 06:13:15 +0000
135+++ data/scripting/win_conditions/territorial_time.lua 2019-04-26 16:56:58 +0000
136@@ -30,6 +30,7 @@
137 return {
138 name = wc_name,
139 description = wc_desc,
140+ peaceful_mode_allowed = false,
141 init = function()
142 fields = wl.Game().map:count_conquerable_fields()
143 end,
144
145=== modified file 'data/scripting/win_conditions/wood_gnome.lua'
146--- data/scripting/win_conditions/wood_gnome.lua 2019-03-09 10:55:24 +0000
147+++ data/scripting/win_conditions/wood_gnome.lua 2019-04-26 16:56:58 +0000
148@@ -24,6 +24,7 @@
149 return {
150 name = wc_name,
151 description = wc_desc,
152+ peaceful_mode_allowed = true,
153 init = function()
154 -- Calculate valuable fields
155 wl.Game().map:count_terrestrial_fields()
156
157=== modified file 'src/game_io/game_player_info_packet.cc'
158--- src/game_io/game_player_info_packet.cc 2019-02-23 11:00:49 +0000
159+++ src/game_io/game_player_info_packet.cc 2019-04-26 16:56:58 +0000
160@@ -30,14 +30,14 @@
161
162 namespace Widelands {
163
164-constexpr uint16_t kCurrentPacketVersion = 22;
165+constexpr uint16_t kCurrentPacketVersion = 23;
166
167 void GamePlayerInfoPacket::read(FileSystem& fs, Game& game, MapObjectLoader*) {
168 try {
169 FileRead fr;
170 fr.open(fs, "binary/player_info");
171 uint16_t const packet_version = fr.unsigned_16();
172- if (packet_version == kCurrentPacketVersion) {
173+ if (packet_version <= kCurrentPacketVersion && packet_version >= 22) {
174 uint32_t const max_players = fr.unsigned_16();
175 for (uint32_t i = 1; i < max_players + 1; ++i) {
176 game.remove_player(i);
177@@ -59,6 +59,15 @@
178 player->set_see_all(see_all);
179
180 player->set_ai(fr.c_string());
181+
182+ if (packet_version == kCurrentPacketVersion) {
183+ player->forbid_attack_.clear();
184+ uint8_t size = fr.unsigned_8();
185+ for (uint8_t j = 0; j < size; ++j) {
186+ player->forbid_attack_.emplace(fr.unsigned_8());
187+ }
188+ }
189+
190 player->read_statistics(fr, packet_version);
191 player->read_remaining_shipnames(fr);
192
193@@ -118,6 +127,11 @@
194 fw.c_string(plr->name_.c_str());
195 fw.c_string(plr->ai_.c_str());
196
197+ fw.unsigned_8(plr->forbid_attack_.size());
198+ for (const auto& it : plr->forbid_attack_) {
199+ fw.unsigned_8(it);
200+ }
201+
202 plr->write_statistics(fw);
203 plr->write_remaining_shipnames(fw);
204 fw.unsigned_32(plr->casualties());
205
206=== modified file 'src/logic/game.cc'
207--- src/logic/game.cc 2019-04-08 06:45:49 +0000
208+++ src/logic/game.cc 2019-04-26 16:56:58 +0000
209@@ -323,6 +323,19 @@
210 // Check for win_conditions
211 if (!settings.scenario) {
212 loader_ui->step(_("Initializing game…"));
213+ if (settings.peaceful) {
214+ for (uint32_t i = 1; i < settings.players.size(); ++i) {
215+ if (Player* p1 = get_player(i)) {
216+ for (uint32_t j = i + 1; j <= settings.players.size(); ++j) {
217+ if (Player* p2 = get_player(j)) {
218+ p1->set_attack_forbidden(j, true);
219+ p2->set_attack_forbidden(i, true);
220+ }
221+ }
222+ }
223+ }
224+ }
225+
226 std::unique_ptr<LuaTable> table(lua().run_script(settings.win_condition_script));
227 table->do_not_warn_about_unaccessed_keys();
228 win_condition_displayname_ = table->get_string("name");
229
230=== modified file 'src/logic/game_settings.h'
231--- src/logic/game_settings.h 2019-02-23 11:00:49 +0000
232+++ src/logic/game_settings.h 2019-04-26 16:56:58 +0000
233@@ -111,7 +111,7 @@
234 * Think of it as the Model in MVC.
235 */
236 struct GameSettings {
237- GameSettings() : playernum(0), usernum(0), scenario(false), multiplayer(false), savegame(false) {
238+ GameSettings() : playernum(0), usernum(0), scenario(false), multiplayer(false), savegame(false), peaceful(false) {
239 std::unique_ptr<LuaInterface> lua(new LuaInterface);
240 std::unique_ptr<LuaTable> win_conditions(
241 lua->run_script("scripting/win_conditions/init.lua"));
242@@ -156,6 +156,9 @@
243 /// Is a savegame selected for loading?
244 bool savegame;
245
246+ // Is all fighting forbidden?
247+ bool peaceful;
248+
249 /// List of tribes that players are allowed to choose
250 std::vector<Widelands::TribeBasicInfo> tribes;
251
252@@ -210,6 +213,9 @@
253 virtual void set_win_condition_script(const std::string& wc) = 0;
254 virtual std::string get_win_condition_script() = 0;
255
256+ virtual void set_peaceful_mode(bool peace) = 0;
257+ virtual bool is_peaceful_mode() = 0;
258+
259 // For retrieving tips texts
260 struct NoTribe {};
261 const std::string& get_players_tribe() {
262
263=== modified file 'src/logic/player.cc'
264--- src/logic/player.cc 2019-04-24 06:01:37 +0000
265+++ src/logic/player.cc 2019-04-26 16:56:58 +0000
266@@ -254,7 +254,8 @@
267 * each other.
268 */
269 bool Player::is_hostile(const Player& other) const {
270- return &other != this && (!team_number_ || team_number_ != other.team_number_);
271+ return &other != this && (!team_number_ || team_number_ != other.team_number_) &&
272+ !is_attack_forbidden(other.player_number());
273 }
274
275 bool Player::is_defeated() const {
276@@ -1334,6 +1335,21 @@
277 return ai_;
278 }
279
280+bool Player::is_attack_forbidden(PlayerNumber who) const {
281+ return forbid_attack_.find(who) != forbid_attack_.end();
282+}
283+
284+void Player::set_attack_forbidden(PlayerNumber who, bool forbid) {
285+ const auto it = forbid_attack_.find(who);
286+ if (forbid ^ (it == forbid_attack_.end())) {
287+ return;
288+ } else if (forbid) {
289+ forbid_attack_.emplace(who);
290+ } else {
291+ forbid_attack_.erase(it);
292+ }
293+}
294+
295 /**
296 * Pick random name from remaining names (if any)
297 */
298
299=== modified file 'src/logic/player.h'
300--- src/logic/player.h 2019-03-17 11:44:04 +0000
301+++ src/logic/player.h 2019-04-26 16:56:58 +0000
302@@ -604,6 +604,9 @@
303 further_initializations_.push_back(init);
304 }
305
306+ void set_attack_forbidden(PlayerNumber who, bool forbid);
307+ bool is_attack_forbidden(PlayerNumber who) const;
308+
309 const std::string pick_shipname();
310
311 private:
312@@ -681,6 +684,8 @@
313 */
314 std::vector<std::vector<uint32_t>> ware_stocks_;
315
316+ std::set<PlayerNumber> forbid_attack_;
317+
318 PlayerBuildingStats building_stats_;
319
320 FxId message_fx_;
321
322=== modified file 'src/logic/single_player_game_settings_provider.cc'
323--- src/logic/single_player_game_settings_provider.cc 2019-02-23 11:00:49 +0000
324+++ src/logic/single_player_game_settings_provider.cc 2019-04-26 16:56:58 +0000
325@@ -69,6 +69,14 @@
326 return s.mapfilename;
327 }
328
329+bool SinglePlayerGameSettingsProvider::is_peaceful_mode() {
330+ return s.peaceful;
331+}
332+
333+void SinglePlayerGameSettingsProvider::set_peaceful_mode(bool peace) {
334+ s.peaceful = peace;
335+}
336+
337 void SinglePlayerGameSettingsProvider::set_map(const std::string& mapname,
338 const std::string& mapfilename,
339 uint32_t const maxplayers,
340
341=== modified file 'src/logic/single_player_game_settings_provider.h'
342--- src/logic/single_player_game_settings_provider.h 2019-02-23 11:00:49 +0000
343+++ src/logic/single_player_game_settings_provider.h 2019-04-26 16:56:58 +0000
344@@ -62,6 +62,9 @@
345 std::string get_win_condition_script() override;
346 void set_win_condition_script(const std::string& wc) override;
347
348+ void set_peaceful_mode(bool peace) override;
349+ bool is_peaceful_mode() override;
350+
351 private:
352 GameSettings s;
353 };
354
355=== modified file 'src/network/gameclient.cc'
356--- src/network/gameclient.cc 2019-02-23 11:00:49 +0000
357+++ src/network/gameclient.cc 2019-04-26 16:56:58 +0000
358@@ -405,6 +405,15 @@
359 // set_player_number(uint8_t) to the host.
360 }
361
362+
363+void GameClient::set_peaceful_mode(bool peace) {
364+ d->settings.peaceful = peace;
365+}
366+
367+bool GameClient::is_peaceful_mode() {
368+ return d->settings.peaceful;
369+}
370+
371 std::string GameClient::get_win_condition_script() {
372 return d->settings.win_condition_script;
373 }
374@@ -819,6 +828,10 @@
375 d->settings.win_condition_script = g_fs->FileSystem::fix_cross_file(packet.string());
376 break;
377 }
378+ case NETCMD_PEACEFUL_MODE: {
379+ d->settings.peaceful = packet.unsigned_8();
380+ break;
381+ }
382
383 case NETCMD_LAUNCH: {
384 if (!d->modal || d->game) {
385
386=== modified file 'src/network/gameclient.h'
387--- src/network/gameclient.h 2019-02-23 11:00:49 +0000
388+++ src/network/gameclient.h 2019-04-26 16:56:58 +0000
389@@ -95,6 +95,9 @@
390 void set_win_condition_script(const std::string&) override;
391 std::string get_win_condition_script() override;
392
393+ void set_peaceful_mode(bool peace) override;
394+ bool is_peaceful_mode() override;
395+
396 // ChatProvider interface
397 void send(const std::string& msg) override;
398 const std::vector<ChatMessage>& get_messages() const override;
399
400=== modified file 'src/network/gamehost.cc'
401--- src/network/gamehost.cc 2019-02-23 11:00:49 +0000
402+++ src/network/gamehost.cc 2019-04-26 16:56:58 +0000
403@@ -203,6 +203,13 @@
404 host_->set_win_condition_script(wc);
405 }
406
407+ void set_peaceful_mode(bool peace) override {
408+ host_->set_peaceful_mode(peace);
409+ }
410+ bool is_peaceful_mode() override {
411+ return host_->settings().peaceful;
412+ }
413+
414 private:
415 GameHost* host_;
416 std::vector<std::string> wincondition_scripts_;
417@@ -1368,6 +1375,16 @@
418 broadcast(packet);
419 }
420
421+void GameHost::set_peaceful_mode(bool peace) {
422+ d->settings.peaceful = peace;
423+
424+ // Broadcast changes
425+ SendPacket packet;
426+ packet.unsigned_8(NETCMD_PEACEFUL_MODE);
427+ packet.unsigned_8(peace ? 1 : 0);
428+ broadcast(packet);
429+}
430+
431 void GameHost::switch_to_player(uint32_t user, uint8_t number) {
432 if (number < d->settings.players.size() &&
433 (d->settings.players.at(number).state != PlayerSettings::State::kOpen &&
434@@ -1676,6 +1693,11 @@
435 packet.string(d->settings.win_condition_script);
436 d->net->send(client.sock_id, packet);
437
438+ packet.reset();
439+ packet.unsigned_8(NETCMD_PEACEFUL_MODE);
440+ packet.unsigned_8(d->settings.peaceful ? 1 : 0);
441+ d->net->send(client.sock_id, packet);
442+
443 // Broadcast new information about the player to everybody
444 packet.reset();
445 packet.unsigned_8(NETCMD_SETTING_USER);
446@@ -2143,6 +2165,12 @@
447 }
448 break;
449
450+ case NETCMD_PEACEFUL_MODE:
451+ if (!d->game) {
452+ throw DisconnectException("NO_ACCESS_TO_SERVER");
453+ }
454+ break;
455+
456 case NETCMD_LAUNCH:
457 if (!d->game) {
458 throw DisconnectException("NO_ACCESS_TO_SERVER");
459
460=== modified file 'src/network/gamehost.h'
461--- src/network/gamehost.h 2019-02-23 11:00:49 +0000
462+++ src/network/gamehost.h 2019-04-26 16:56:58 +0000
463@@ -80,6 +80,7 @@
464 void set_player_shared(PlayerSlot number, Widelands::PlayerNumber shared);
465 void switch_to_player(uint32_t user, uint8_t number);
466 void set_win_condition_script(const std::string& wc);
467+ void set_peaceful_mode(bool peace);
468 void replace_client_with_ai(uint8_t playernumber, const std::string& ai);
469
470 // just visible stuff for the select mapmenu
471
472=== modified file 'src/network/network_protocol.h'
473--- src/network/network_protocol.h 2019-02-23 11:00:49 +0000
474+++ src/network/network_protocol.h 2019-04-26 16:56:58 +0000
475@@ -28,7 +28,7 @@
476 * The current version of the in-game network protocol. Client and host
477 * protocol versions must match.
478 */
479- NETWORK_PROTOCOL_VERSION = 22,
480+ NETWORK_PROTOCOL_VERSION = 23,
481
482 /**
483 * The default interval (in milliseconds) in which the host issues
484@@ -429,6 +429,14 @@
485 NETCMD_SYSTEM_MESSAGE_CODE = 32,
486
487 /**
488+ * Sent by the host to toggle peaceful mode.
489+ *
490+ * Attached data is:
491+ * \li uint8_t: 1 if peaceful mode is enabled, 0 otherwise
492+ */
493+ NETCMD_PEACEFUL_MODE = 33,
494+
495+ /**
496 * Sent by the metaserver to a freshly opened game to check connectability
497 */
498 NETCMD_METASERVER_PING = 64
499
500=== modified file 'src/scripting/lua_game.cc'
501--- src/scripting/lua_game.cc 2019-04-24 06:43:22 +0000
502+++ src/scripting/lua_game.cc 2019-04-26 16:56:58 +0000
503@@ -100,6 +100,8 @@
504 METHOD(LuaPlayer, allow_workers),
505 METHOD(LuaPlayer, switchplayer),
506 METHOD(LuaPlayer, get_produced_wares_count),
507+ METHOD(LuaPlayer, set_attack_forbidden),
508+ METHOD(LuaPlayer, is_attack_forbidden),
509 {nullptr, nullptr},
510 };
511 const PropertyType<LuaPlayer> LuaPlayer::Properties[] = {
512@@ -856,6 +858,39 @@
513 return 1;
514 }
515
516+/* RST
517+ .. method:: is_attack_forbidden(who)
518+
519+ Returns true if this player is currently forbidden to attack the player with the specified
520+ player number. Note that the return value `false` does not necessarily mean that this
521+ player *can* attack the other player, as they might for example be in the same team.
522+
523+ :arg who: player number of the player to query
524+ :type who: :class:`int`
525+ :rtype: :class:`boolean`
526+*/
527+int LuaPlayer::is_attack_forbidden(lua_State* L) {
528+ lua_pushboolean(L, get(L, get_egbase(L)).is_attack_forbidden(luaL_checkinteger(L, 2)));
529+ return 1;
530+}
531+
532+/* RST
533+ .. method:: set_attack_forbidden(who, forbid)
534+
535+ Sets whether this player is forbidden to attack the player with the specified
536+ player number. Note that setting this to `false` does not necessarily mean that this
537+ player *can* attack the other player, as they might for example be in the same team.
538+
539+ :arg who: player number of the player to query
540+ :type who: :class:`int`
541+ :arg forbid: Whether to allow or forbid attacks
542+ :type forbid: :class:`boolean`
543+*/
544+int LuaPlayer::set_attack_forbidden(lua_State* L) {
545+ get(L, get_egbase(L)).set_attack_forbidden(luaL_checkinteger(L, 2), luaL_checkboolean(L, 3));
546+ return 0;
547+}
548+
549 /*
550 ==========================================================
551 C METHODS
552
553=== modified file 'src/scripting/lua_game.h'
554--- src/scripting/lua_game.h 2019-04-18 16:50:35 +0000
555+++ src/scripting/lua_game.h 2019-04-26 16:56:58 +0000
556@@ -96,6 +96,8 @@
557 int allow_workers(lua_State* L);
558 int switchplayer(lua_State* L);
559 int get_produced_wares_count(lua_State* L);
560+ int set_attack_forbidden(lua_State* L);
561+ int is_attack_forbidden(lua_State* L);
562
563 /*
564 * C methods
565
566=== modified file 'src/ui_fsmenu/launch_game.cc'
567--- src/ui_fsmenu/launch_game.cc 2019-02-23 11:00:49 +0000
568+++ src/ui_fsmenu/launch_game.cc 2019-04-26 16:56:58 +0000
569@@ -55,6 +55,11 @@
570 "",
571 UI::DropdownType::kTextual,
572 UI::PanelStyle::kFsMenu),
573+
574+ peaceful_(this,
575+ Vector2i(get_w() * 7 / 10,
576+ get_h() * 19 / 40 + buth_),
577+ _("Peaceful mode")),
578 ok_(this, "ok", 0, 0, butw_, buth_, UI::ButtonStyle::kFsMenuPrimary, _("Start game")),
579 back_(this, "back", 0, 0, butw_, buth_, UI::ButtonStyle::kFsMenuSecondary, _("Back")),
580 // Text labels
581@@ -62,9 +67,12 @@
582 // Variables and objects used in the menu
583 settings_(settings),
584 ctrl_(ctrl),
585+ peaceful_mode_forbidden_(false),
586 nr_players_(0) {
587 win_condition_dropdown_.selected.connect(
588 boost::bind(&FullscreenMenuLaunchGame::win_condition_selected, this));
589+ peaceful_.changed.connect(
590+ boost::bind(&FullscreenMenuLaunchGame::toggle_peaceful, this));
591 back_.sigclicked.connect(
592 boost::bind(&FullscreenMenuLaunchGame::clicked_back, boost::ref(*this)));
593 ok_.sigclicked.connect(boost::bind(&FullscreenMenuLaunchGame::clicked_ok, boost::ref(*this)));
594@@ -78,6 +86,23 @@
595 delete lua_;
596 }
597
598+void FullscreenMenuLaunchGame::update_peaceful_mode() {
599+ bool forbidden = peaceful_mode_forbidden_ || settings_->settings().scenario || settings_->settings().savegame;
600+ peaceful_.set_enabled(!forbidden && settings_->can_change_map());
601+ if (forbidden) {
602+ peaceful_.set_state(false);
603+ }
604+ if (settings_->settings().scenario) {
605+ peaceful_.set_tooltip(_("The relations between players are set by the scenario"));
606+ } else if (settings_->settings().savegame) {
607+ peaceful_.set_tooltip(_("The relations between players are set by the saved game"));
608+ } else if (peaceful_mode_forbidden_) {
609+ peaceful_.set_tooltip(_("The selected win condition does not allow peaceful matches"));
610+ } else {
611+ peaceful_.set_tooltip(_("Forbid fighting between players"));
612+ }
613+}
614+
615 bool FullscreenMenuLaunchGame::init_win_condition_label() {
616 if (settings_->settings().scenario) {
617 win_condition_dropdown_.set_enabled(false);
618@@ -190,6 +215,10 @@
619 return t;
620 }
621
622+void FullscreenMenuLaunchGame::toggle_peaceful() {
623+ settings_->set_peaceful_mode(peaceful_.get_state());
624+}
625+
626 // Implemented by subclasses
627 void FullscreenMenuLaunchGame::clicked_ok() {
628 NEVER_HERE();
629
630=== modified file 'src/ui_fsmenu/launch_game.h'
631--- src/ui_fsmenu/launch_game.h 2019-02-23 11:00:49 +0000
632+++ src/ui_fsmenu/launch_game.h 2019-04-26 16:56:58 +0000
633@@ -26,6 +26,7 @@
634 #include "graphic/playercolor.h"
635 #include "logic/map.h"
636 #include "ui_basic/button.h"
637+#include "ui_basic/checkbox.h"
638 #include "ui_basic/dropdown.h"
639 #include "ui_basic/textarea.h"
640 #include "ui_fsmenu/base.h"
641@@ -56,6 +57,9 @@
642 /// Creates a blank label/tooltip and returns 'false' otherwise.
643 bool init_win_condition_label();
644
645+ /// Enables or disables the peaceful mode checkbox.
646+ void update_peaceful_mode();
647+
648 /// Loads all win conditions that can be played with the map into the selection dropdown.
649 /// Disables the dropdown if the map is a scenario.
650 void update_win_conditions();
651@@ -71,16 +75,21 @@
652 std::unique_ptr<LuaTable> win_condition_if_valid(const std::string& win_condition_script,
653 std::set<std::string> tags) const;
654
655+ void toggle_peaceful();
656+
657 uint32_t butw_;
658 uint32_t buth_;
659
660 UI::Dropdown<std::string> win_condition_dropdown_;
661+ UI::Checkbox peaceful_;
662 std::string last_win_condition_;
663 UI::Button ok_, back_;
664 UI::Textarea title_;
665 GameSettingsProvider* settings_;
666 GameController* ctrl_;
667
668+ bool peaceful_mode_forbidden_;
669+
670 Widelands::PlayerNumber nr_players_;
671 };
672
673
674=== modified file 'src/ui_fsmenu/launch_mpg.cc'
675--- src/ui_fsmenu/launch_mpg.cc 2019-02-23 11:00:49 +0000
676+++ src/ui_fsmenu/launch_mpg.cc 2019-04-26 16:56:58 +0000
677@@ -159,7 +159,7 @@
678 UI::PanelStyle::kFsMenu),
679 client_info_(this,
680 right_column_x_,
681- get_h() * 13 / 20 - 2 * label_height_,
682+ get_h() * 15 / 20 - 2 * label_height_,
683 butw_,
684 get_h(),
685 UI::PanelStyle::kFsMenu),
686@@ -167,7 +167,8 @@
687
688 // Variables and objects used in the menu
689 chat_(nullptr) {
690- ok_.set_pos(Vector2i(right_column_x_, get_h() * 12 / 20 - 2 * label_height_));
691+ peaceful_.set_pos(Vector2i(right_column_x_, get_h() * 25 / 40 - 2 * label_height_));
692+ ok_.set_pos(Vector2i(right_column_x_, get_h() * 14 / 20 - 2 * label_height_));
693 back_.set_pos(Vector2i(right_column_x_, get_h() * 218 / 240));
694 win_condition_dropdown_.set_pos(
695 Vector2i(right_column_x_, get_h() * 11 / 20 - 2 * label_height_));
696@@ -240,6 +241,11 @@
697 if (settings_->can_change_map() && win_condition_dropdown_.has_selection()) {
698 settings_->set_win_condition_script(win_condition_dropdown_.get_selected());
699 last_win_condition_ = win_condition_dropdown_.get_selected();
700+
701+ std::unique_ptr<LuaTable> t = lua_->run_script(last_win_condition_);
702+ t->do_not_warn_about_unaccessed_keys();
703+ peaceful_mode_forbidden_ = !t->get_bool("peaceful_mode_allowed");
704+ update_peaceful_mode();
705 }
706 }
707
708@@ -422,6 +428,9 @@
709 change_map_or_save_.set_enabled(settings_->can_change_map());
710 change_map_or_save_.set_visible(settings_->can_change_map());
711
712+ update_peaceful_mode();
713+ peaceful_.set_state(settings_->is_peaceful_mode());
714+
715 if (!settings_->can_change_map() && !init_win_condition_label()) {
716 try {
717 // We do not validate the scripts for the client - it's only a label.
718
719=== modified file 'src/ui_fsmenu/launch_spg.cc'
720--- src/ui_fsmenu/launch_spg.cc 2019-02-23 11:00:49 +0000
721+++ src/ui_fsmenu/launch_spg.cc 2019-04-26 16:56:58 +0000
722@@ -166,6 +166,11 @@
723 void FullscreenMenuLaunchSPG::win_condition_selected() {
724 if (win_condition_dropdown_.has_selection()) {
725 last_win_condition_ = win_condition_dropdown_.get_selected();
726+
727+ std::unique_ptr<LuaTable> t = lua_->run_script(last_win_condition_);
728+ t->do_not_warn_about_unaccessed_keys();
729+ peaceful_mode_forbidden_ = !t->get_bool("peaceful_mode_allowed");
730+ update_peaceful_mode();
731 }
732 }
733
734@@ -217,6 +222,8 @@
735 select_map_.set_visible(settings_->can_change_map());
736 select_map_.set_enabled(settings_->can_change_map());
737
738+ peaceful_.set_state(settings_->is_peaceful_mode());
739+
740 set_player_names_and_tribes();
741 }
742
743@@ -262,6 +269,7 @@
744 safe_place_for_host(nr_players_);
745 settings_->set_map(mapdata.name, mapdata.filename, nr_players_);
746 update_win_conditions();
747+ update_peaceful_mode();
748 update(true);
749 return true;
750 }
751
752=== added file 'test/maps/port_space.wmf/scripting/test_attack_forbidden.lua'
753--- test/maps/port_space.wmf/scripting/test_attack_forbidden.lua 1970-01-01 00:00:00 +0000
754+++ test/maps/port_space.wmf/scripting/test_attack_forbidden.lua 2019-04-26 16:56:58 +0000
755@@ -0,0 +1,38 @@
756+run(function()
757+ -- Initially, no overrides exist
758+ assert_equal(false, p1:is_attack_forbidden(2))
759+ assert_equal(false, p2:is_attack_forbidden(1))
760+ -- No dumbness checks should take place
761+ assert_equal(false, p1:is_attack_forbidden(1))
762+ assert_equal(false, p2:is_attack_forbidden(2))
763+ assert_equal(false, p1:is_attack_forbidden(3))
764+
765+ p1:set_attack_forbidden(2, true)
766+
767+ assert_equal(true, p1:is_attack_forbidden(2))
768+ assert_equal(false, p2:is_attack_forbidden(1))
769+ assert_equal(false, p1:is_attack_forbidden(3))
770+
771+ p2:set_attack_forbidden(3, true)
772+
773+ assert_equal(true, p1:is_attack_forbidden(2))
774+ assert_equal(false, p2:is_attack_forbidden(1))
775+ assert_equal(false, p1:is_attack_forbidden(3))
776+ assert_equal(true, p2:is_attack_forbidden(3))
777+
778+ p2:set_attack_forbidden(1, true)
779+
780+ assert_equal(true, p1:is_attack_forbidden(2))
781+ assert_equal(true, p2:is_attack_forbidden(1))
782+ assert_equal(true, p2:is_attack_forbidden(3))
783+
784+ p2:set_attack_forbidden(1, false)
785+ p1:set_attack_forbidden(2, false)
786+
787+ assert_equal(false, p2:is_attack_forbidden(1))
788+ assert_equal(false, p1:is_attack_forbidden(2))
789+ assert_equal(true, p2:is_attack_forbidden(3))
790+
791+ print("# All Tests passed.")
792+ wl.ui.MapView():close()
793+end)

Subscribers

People subscribed via source and target branches

to status/vote changes: