Merge lp:~widelands-dev/widelands/bug-1687100-reveal_fields into lp:widelands

Proposed by GunChleoc
Status: Merged
Merged at revision: 8540
Proposed branch: lp:~widelands-dev/widelands/bug-1687100-reveal_fields
Merge into: lp:widelands
Diff against target: 652 lines (+237/-137)
8 files modified
src/logic/CMakeLists.txt (+1/-0)
src/logic/player.cc (+58/-23)
src/logic/player.h (+17/-18)
src/logic/see_unsee_node.h (+26/-0)
src/map_io/map_players_view_packet.cc (+35/-2)
src/scripting/lua_game.cc (+15/-18)
test/maps/lua_testsuite.wmf/scripting/gplayer.lua (+0/-76)
test/maps/plain.wmf/scripting/test_player_vision.lua (+85/-0)
To merge this branch: bzr merge lp:~widelands-dev/widelands/bug-1687100-reveal_fields
Reviewer Review Type Date Requested Status
kaputtnik (community) testing Approve
GunChleoc Needs Resubmitting
Review via email: mp+323721@code.launchpad.net

Commit message

When the hide_completely option is not selected, LuaPlayer::hide_fields no longer hides fields that the player's buildings see. Vision information for Unexplored fields is now kept in a new container in the Player object.

Also, removed unused bool view_changed_ from player.h and removed compatibility code for border_file in the player vision packet.

Description of the change

This was actually a long-standing bug - the function wasn't doing what the documentation described in the first place.

Can be tested by hacking the seafaring tutorial:

=== modified file 'data/campaigns/tutorial03_seafaring.wmf/scripting/mission_thread.lua'
--- data/campaigns/tutorial03_seafaring.wmf/scripting/mission_thread.lua 2016-10-23 11:31:25 +0000
+++ data/campaigns/tutorial03_seafaring.wmf/scripting/mission_thread.lua 2017-05-07 07:51:04 +0000
@@ -5,6 +5,14 @@
 function introduction()
    additional_port_space.terr = "summer_water" -- disable the port space
    sleep(1000)
+
+plr:reveal_fields(wl.Game().map:get_field(41,43):region(60))
+plr:hide_fields(wl.Game().map:get_field(41,43):region(40),true)
+
+plr:hide_fields(wl.Game().map:get_field(43,52):region(20),true)
+plr:reveal_fields(wl.Game().map:get_field(43,52):region(20))
+sleep(600000)
+
    message_box_objective(plr, intro_south)
    sleep(300)
    message_box_objective(plr, intro_north)

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

Continuous integration builds have changed state:

Travis build 2154. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/229623909.
Appveyor build 1989. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1687100_reveal_fields-1989.

Revision history for this message
kaputtnik (franku) wrote :

Doesn't work for me... add just

   plr:hide_fields(wl.Game().map:get_field(41,43):region(40),true)
   sleep(6000000)

to the mission_thread.lua and you see that every field is visible.

review: Needs Fixing
Revision history for this message
kaputtnik (franku) wrote :

Maybe a better branch for testing is the branch where i have added already some reveal/hide animations to the first tutorials. This is also the branch where i had encountered this bug.

https://code.launchpad.net/~widelands-dev/widelands/reveal_hide_animations

Revision history for this message
GunChleoc (gunchleoc) wrote :

Next try.

review: Needs Resubmitting
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2221. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/234277729.
Appveyor build 2056. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1687100_reveal_fields-2056.

Revision history for this message
kaputtnik (franku) wrote :

Looks good now :-)

One small nit: Since hide_completely and reveal_completely are optional it should be clarified which boolean (true/false) will take an effect at all.

I want to make some more tests, before approval of testing. In the meantime someone else could look at the logic...

Revision history for this message
GunChleoc (gunchleoc) wrote :

How is the documentation for you now?

Revision history for this message
kaputtnik (franku) wrote :

> How is the documentation for you now?

Perfect :-) Thanks

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2230. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/234503590.
Appveyor build 2065. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1687100_reveal_fields-2065.

Revision history for this message
kaputtnik (franku) wrote :

Hmmm... this do not work. From my understanding the function is_seeing() restricts the seen fields to MapObjectType::WAREHOUSE;

So all nodes (fields) which are not in the area a Warehouse sees, behaves as before: E.g. the census and statistics disappear for a short time.

You could see this when playing this branch with the datadir of the reveal_hide_animations branch and playing the seafaring tutorial. Enable census and statistics and watch the region of the foresters at the southern islands (increase game speed).

I think at least the military buildings must be added to set the seen fields.

Another approach is maybe to make the function sees_field() (https://wl.widelands.org/docs/wl/autogen_wl_game/#wl.game.Player.sees_field) read- and settable. So a modder could read and set it by himself.

review: Needs Fixing
Revision history for this message
kaputtnik (franku) wrote :

Oh i didn't understood the code... is_seen() is only used to hide fields. But partly not working is revealing fields.

I am not familiar with the code, but i am asking myself why the function hide_fields() is now much complicated than the one in trunk ( http://bazaar.launchpad.net/~widelands-dev/widelands/trunk/view/head:/src/scripting/lua_game.cc#L628 ). Just asking because the one in trunk works fine imho.

Revision history for this message
kaputtnik (franku) wrote :

I have just seen that the mentioned behavior (disappearing census and statistics) do also happen in current trunk when playing the seafaring tutorial.

I check this in build 19... (must first compile from scratch)

Revision history for this message
kaputtnik (franku) wrote :

Sorry, wrong alert :S

I accidentally edited the seafaring tutorial in trunk ... So trunk does NOT show this behavior.

Seems i must limit the things i am working on... Sorry for the noise.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I have dug some more into the vision stuff and completely reimplemented the thing. The new implementation should be safe for multiplayer too.

Could you please test again, and if still it doesn't work as expected, copy over some of your failing scripting code so I will have some real data to test with?

It would also be interesting to see if we can't just always hide completely, this would make the code a bit simpler.

I still need to implement saveloading, but I'll wait with that until it works.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2262. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/236985137.
Appveyor build 2097. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1687100_reveal_fields-2097.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I guess the bug in the military scenario is that the soldiers see where they are going - do you want that switched off?

Revision history for this message
kaputtnik (franku) wrote :

> do you want that switched off?

Lets say: If it doesn't make much work it would be fine to have the possibility to switch that off :-) Otherwise i could live with the current state.

The bug with the disappearing census and statistics is gone now.

Thank you very much for working on this.

You can always test your code if you run widelands with the --datadir= option pointing the data folder of my branch. Doesn't that work for you?

Revision history for this message
GunChleoc (gunchleoc) wrote :

Well, it turns out that it makes insanely complicated work, so worker vision will have to stay as it is.

Duh, I never thought of the datadir option!

BTW you don't need the boolean now when revealing fields, as the necessary steps are detected automatically. We still need the 2 modes for hiding though, e.g. in the Barbarian campaign scenario 2 when the tracks are discovered, we don't want to black this out.

Now on to saveloading...

Revision history for this message
kaputtnik (franku) wrote :

Sorry Gun,

with your last changes the prior problem appear again: The census and statistics overlay for some buildings suddenly disappear in the seafaring tutorial.

I have reverted to revision 8358 and then it works: The census and statistics overlays keep alive.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Thanks for testing again. I thought the new changes would make the code more correct, but I was obviously wrong, since the test suite also blew up.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I found the error in the test suite: we need to sleep after calls now, because the playercommands are causing delays.

I deleted the commit that broke things for you from the branch's history, so you will need to pull the branch with the option --overwrite.

Revision history for this message
kaputtnik (franku) wrote :

I have a fresh branch and compiled from scratch.

Works again :-)

review: Approve (testing)
Revision history for this message
GunChleoc (gunchleoc) wrote :

Saveloading is implemented, so this is ready for review again.

review: Needs Resubmitting
Revision history for this message
kaputtnik (franku) wrote :

Sorry, isn't working. Now it is the economy tutorial which does not work. Please run the branch with the --datadir option pointing to my branch and open first the seafaring tutorial, and afterwards the economy tutorial. Within the seafaring tutorial you see the 'reveal_randomly' code is working, whereas in the economy tutorial the same code isn't working (most areas get not hidden prior revealing). Maybe i have made a mistake in my code, so i would be glad if you can take a look at it.

review: Needs Fixing
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2284. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/240085373.
Appveyor build 2119. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1687100_reveal_fields-2119.

Revision history for this message
GunChleoc (gunchleoc) wrote :

The difference is the headquarters in the economy tutorial - seems that it is creating vision no matter what we do.

Revision history for this message
kaputtnik (franku) wrote :

Hm.. that's strange, because this works also for the first tutorial, where a headquarter is used. The first campaign "A Place to Call Home" works also nicely with a headquarter.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Yep, really strange. It very obviously is the vision or conquer radius of the headquarters though. Your code doesn't look any different to the Seafaring tutorial code, so I don't think that's it either.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I have found the culprit - some of the roads are messing this up. So, I have moved them into a separate function and add them after the land has been revealed.

We can surely still pretty this up, but I need to create a debug build first so that I can see the coordinates.

Revision history for this message
GunChleoc (gunchleoc) wrote :

OK, done with my work on the other branch. The problem happens when we connect mines and constructionsites to the road network - there is nothing in the vision code that makes mines special as far as I can see, so I haven't the foggiest what's causing this. I'd say let's leave it as it is and live with the workaround that I coded for the Economy tutorial.

Revision history for this message
kaputtnik (franku) wrote :

Wow, thanks a lot :-)

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2287. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/242180501.
Appveyor build 2122. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1687100_reveal_fields-2122.

Revision history for this message
kaputtnik (franku) wrote :

I think this is working now :-)

review: Approve (testing)
Revision history for this message
Klaus Halfmann (klaus-halfmann) wrote :

Testing hint:

use this datadir this will use the functions
https://code.launchpad.net/~widelands-dev/widelands/reveal_hide_animations,

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2504. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/261130470.
Appveyor build 2328. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1687100_reveal_fields-2328.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2528. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/263771923.
Appveyor build 2352. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1687100_reveal_fields-2352.

Revision history for this message
SirVer (sirver) wrote :

I starting looking through the code and there is a lot to digest here. I have a few questions:

- Why do we require the player command? It seems that we only want to mess with the normal rules of vision through scripting which has to run in parallel on each machine anyways, i.e. should not require a player command. Using a player command will be more fragile, as for example the scripting code has no guarantee when the see/unsee actually happens (can be seconds if the network connection is bad).
- The semantis of hidden_fields_ is unclear to me. What happens in this case: Field f is seen by two buildings and a worker, i.e. f.vision = 4 (1 (has been seen before) + 3 viewers). It is now hidden through scripting. The worker will walk away eventually, so 'f.vision = 3'. What happens if the field is now 'revealed'?

Revision history for this message
GunChleoc (gunchleoc) wrote :

> I starting looking through the code and there is a lot to digest here. I have a few questions:
>
> - Why do we require the player command? It seems that we only want to mess with the normal rules of vision through scripting which has to run in parallel on each machine anyways, i.e. should not require a player command. Using a player command will be more fragile, as for example the scripting code has no guarantee when the see/unsee actually happens (can be seconds if the network connection is bad).

I wasn't sure whether we needed one or not and decided to be rather safe
than sorry. I don't have a problem with removing it.

> - The semantis of hidden_fields_ is unclear to me.

Join the club. I arrived at the solution pretty much through trial and
error. Since I wrote this a long time ago, I'd need to completely
reanalzye the code myself - let me know if you need me to do so and I'll
do that next month.

Revision history for this message
SirVer (sirver) wrote :

> I don't have a problem with removing it.

please do and ping me for another round of reviews here.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I have removed the playercommand now.

Here's what I remember of the vision code:

Vision state of a field is an integer. Everything in sight of a building with vision is always visible. Every time a worker walks past an area, the vision on the field is incremented. It then slowly gets decremented until the player loses vision. Then the fields are darkened and not updated any longer, but never blacked out.

What we needed in the hide/reveal code were 2 versions of hiding fields from the player:

1. Just the darkened state
2. A permanent black state that can be undone by scripting, field by field

Buildings and workers will interfere with the hiding state, so implementing this became a bit tricky and also needed some extra data in the savegame.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2731. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/295910371.
Appveyor build 2543. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1687100_reveal_fields-2543.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2778. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/298423953.
Appveyor build 2590. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1687100_reveal_fields-2590.

Revision history for this message
GunChleoc (gunchleoc) wrote :

This branch has been sitting here well tested for half a year now, so let's have it before we get more code duplication in from the next campaign scenario.

@bunnybot merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/logic/CMakeLists.txt'
2--- src/logic/CMakeLists.txt 2017-11-20 13:50:51 +0000
3+++ src/logic/CMakeLists.txt 2017-12-19 07:13:00 +0000
4@@ -164,6 +164,7 @@
5 roadtype.h
6 save_handler.cc
7 save_handler.h
8+ see_unsee_node.h
9 trade_agreement.h
10 widelands_geometry_io.cc
11 widelands_geometry_io.h
12
13=== modified file 'src/logic/player.cc'
14--- src/logic/player.cc 2017-12-02 12:43:38 +0000
15+++ src/logic/player.cc 2017-12-19 07:13:00 +0000
16@@ -173,7 +173,7 @@
17 field_terrain_changed_subscriber_ = Notifications::subscribe<NoteFieldTerrainChanged>(
18 [this](const NoteFieldTerrainChanged& note) {
19 if (vision(note.map_index) > 1) {
20- rediscover_node(egbase().map(), egbase().map()[0], note.fc);
21+ rediscover_node(egbase().map(), note.fc);
22 }
23 });
24
25@@ -923,16 +923,15 @@
26 }
27 }
28
29-void Player::rediscover_node(const Map& map,
30- const Widelands::Field& first_map_field,
31- const FCoords& f) {
32+void Player::rediscover_node(const Map& map, const FCoords& f) {
33
34 assert(0 <= f.x);
35 assert(f.x < map.get_width());
36 assert(0 <= f.y);
37 assert(f.y < map.get_height());
38- assert(&map[0] <= f.field);
39- assert(f.field < &map[0] + map.max_index());
40+ const Widelands::Field& first_map_field = map[0];
41+ assert(&first_map_field <= f.field);
42+ assert(f.field < &first_map_field + map.max_index());
43
44 Field& field = fields_[f.field - &first_map_field];
45
46@@ -1031,8 +1030,8 @@
47 }
48 }
49
50-void Player::see_node(const Map& map,
51- const Widelands::Field& first_map_field,
52+/// Returns the resulting vision.
53+Vision Player::see_node(const Map& map,
54 const FCoords& f,
55 Time const gametime,
56 bool const forward) {
57@@ -1040,7 +1039,8 @@
58 assert(f.x < map.get_width());
59 assert(0 <= f.y);
60 assert(f.y < map.get_height());
61- assert(&map[0] <= f.field);
62+ const Widelands::Field& first_map_field = map[0];
63+ assert(&first_map_field <= f.field);
64 assert(f.field < &first_map_field + map.max_index());
65
66 // If this is not already a forwarded call, we should inform allied players
67@@ -1049,31 +1049,34 @@
68 update_team_players();
69 if (!forward && !team_player_.empty()) {
70 for (uint8_t j = 0; j < team_player_.size(); ++j)
71- team_player_[j]->see_node(map, first_map_field, f, gametime, true);
72+ team_player_[j]->see_node(map, f, gametime, true);
73 }
74
75 Field& field = fields_[f.field - &first_map_field];
76 assert(fields_ <= &field);
77 assert(&field < fields_ + map.max_index());
78- Vision fvision = field.vision;
79- if (fvision == 0)
80- fvision = 1;
81- if (fvision == 1)
82- rediscover_node(map, first_map_field, f);
83- ++fvision;
84- field.vision = fvision;
85+
86+ if (field.vision == 0) {
87+ field.vision = 1;
88+ }
89+ if (field.vision == 1) {
90+ rediscover_node(map, f);
91+ }
92+ return ++field.vision;
93 }
94
95 /// If 'mode' = UnseeMode::kUnexplore, fields will be marked as unexplored. Else, player no longer
96-/// sees what's currently going on.
97-void Player::unsee_node(MapIndex const i,
98+/// sees what's currently going on. Returns the vision that this node had before it was hidden.
99+Vision Player::unsee_node(MapIndex const i,
100 Time const gametime,
101- const UnseeNodeMode mode,
102+ const SeeUnseeNode mode,
103 bool const forward) {
104 Field& field = fields_[i];
105- if ((mode == UnseeNodeMode::kUnsee && field.vision <= 1) ||
106+ if ((mode == SeeUnseeNode::kUnsee && field.vision <= 1) ||
107 field.vision < 1) // Already does not see this
108- return;
109+ return field.vision;
110+
111+ const Vision original_vision = field.vision;
112
113 // If this is not already a forwarded call, we should inform allied players
114 // as well of this change.
115@@ -1084,7 +1087,7 @@
116 team_player_[j]->unsee_node(i, gametime, mode, true);
117 }
118
119- if (mode == UnseeNodeMode::kUnexplore) {
120+ if (mode == SeeUnseeNode::kUnexplore) {
121 field.vision = 0;
122 } else {
123 --field.vision;
124@@ -1093,6 +1096,38 @@
125 if (field.vision < 2) {
126 field.time_node_last_unseen = gametime;
127 }
128+ return original_vision;
129+}
130+
131+void Player::hide_or_reveal_field(const uint32_t gametime, const Coords& coords, SeeUnseeNode mode) {
132+ const Map& map = egbase().map();
133+ FCoords fcoords = map.get_fcoords(coords);
134+ const Widelands::MapIndex index = fcoords.field - &map[0];
135+
136+ switch (mode) {
137+ // Reveal field
138+ case SeeUnseeNode::kReveal: {
139+ Widelands::Vision new_vision = see_node(map, fcoords, gametime);
140+ // If the field was manually hidden, restore the original vision
141+ if (hidden_fields_.count(index) == 1) {
142+ auto iter = hidden_fields_.find(index);
143+ Vision original_vision = iter->second;
144+ while (new_vision < original_vision) {
145+ new_vision = see_node(map, fcoords, gametime);
146+ }
147+ hidden_fields_.erase(iter);
148+ }
149+ } break;
150+ // Hide field
151+ case SeeUnseeNode::kUnsee:
152+ case SeeUnseeNode::kUnexplore: {
153+ const Widelands::Vision new_vision = unsee_node(index, gametime, mode);
154+ // Remember the original vision so that we can unhide the fields again
155+ if (hidden_fields_.count(index) != 1) {
156+ hidden_fields_.insert(std::make_pair(index, new_vision));
157+ }
158+ } break;
159+ }
160 }
161
162 /**
163
164=== modified file 'src/logic/player.h'
165--- src/logic/player.h 2017-11-20 07:54:19 +0000
166+++ src/logic/player.h 2017-12-19 07:13:00 +0000
167@@ -34,6 +34,7 @@
168 #include "logic/map_objects/tribes/warehouse.h"
169 #include "logic/mapregion.h"
170 #include "logic/message_queue.h"
171+#include "logic/see_unsee_node.h"
172 #include "logic/widelands.h"
173
174 class Node;
175@@ -146,7 +147,6 @@
176 // For cheating
177 void set_see_all(bool const t) {
178 see_all_ = t;
179- view_changed_ = true;
180 }
181 bool see_all() const {
182 return see_all_;
183@@ -433,37 +433,28 @@
184 return (see_all_ ? 2 : 0) + fields_[i].vision;
185 }
186
187- bool has_view_changed() {
188- bool t = view_changed_;
189- view_changed_ = false;
190- return t;
191- }
192-
193 /**
194 * Update this player's information about this node and the surrounding
195 * triangles and edges.
196 */
197- void see_node(const Map&,
198- const Widelands::Field& first_map_field,
199+ Vision see_node(const Map&,
200 const FCoords&,
201 const Time,
202 const bool forward = false);
203
204 /// Decrement this player's vision for a node.
205- enum class UnseeNodeMode { kUnsee, kUnexplore };
206- void
207- unsee_node(MapIndex, Time, UnseeNodeMode mode = UnseeNodeMode::kUnsee, bool forward = false);
208+
209+ Vision
210+ unsee_node(MapIndex, Time, SeeUnseeNode mode = SeeUnseeNode::kUnsee, bool forward = false);
211
212 /// Call see_node for each node in the area.
213 void see_area(const Area<FCoords>& area) {
214 const Time gametime = egbase().get_gametime();
215 const Map& map = egbase().map();
216- const Widelands::Field& first_map_field = map[0];
217 MapRegion<Area<FCoords>> mr(map, area);
218 do {
219- see_node(map, first_map_field, mr.location(), gametime);
220+ see_node(map, mr.location(), gametime);
221 } while (mr.advance(map));
222- view_changed_ = true;
223 }
224
225 /// Decrement this player's vision for each node in an area.
226@@ -475,9 +466,15 @@
227 do
228 unsee_node(mr.location().field - &first_map_field, gametime);
229 while (mr.advance(map));
230- view_changed_ = true;
231 }
232
233+ /// Explicitly hide or reveal the field at 'c'. The modes are as follows:
234+ /// - kUnsee: Decrement the field's vision
235+ /// - kUnexplore: Set the field's vision to 0
236+ /// - kReveal: If the field was hidden previously, restore the vision to the value it had
237+ /// at the time of hiding. Otherwise, increment the vision.
238+ void hide_or_reveal_field(const uint32_t gametime, const Coords& c, SeeUnseeNode mode);
239+
240 MilitaryInfluence military_influence(MapIndex const i) const {
241 return fields_[i].military_influence;
242 }
243@@ -618,7 +615,7 @@
244 // Called when a node becomes seen or has changed. Discovers the node and
245 // those of the 6 surrounding edges/triangles that are not seen from another
246 // node.
247- void rediscover_node(const Map&, const Widelands::Field&, const FCoords&);
248+ void rediscover_node(const Map&, const FCoords&);
249
250 std::unique_ptr<Notifications::Subscriber<NoteImmovable>> immovable_subscriber_;
251 std::unique_ptr<Notifications::Subscriber<NoteFieldTerrainChanged>>
252@@ -634,7 +631,6 @@
253 std::vector<Player*> team_player_;
254 bool team_player_uptodate_;
255 bool see_all_;
256- bool view_changed_;
257 const PlayerNumber player_number_;
258 const TribeDescr& tribe_; // buildings, wares, workers, sciences
259 uint32_t casualties_, kills_;
260@@ -649,6 +645,9 @@
261 std::string name_; // Player name
262 std::string ai_; /**< Name of preferred AI implementation */
263
264+ // Fields that were explicitly hidden, with their vision at the time of hiding
265+ std::map<MapIndex, Widelands::Vision> hidden_fields_;
266+
267 /**
268 * Wares produced (by ware id) since the last call to @ref sample_statistics
269 */
270
271=== added file 'src/logic/see_unsee_node.h'
272--- src/logic/see_unsee_node.h 1970-01-01 00:00:00 +0000
273+++ src/logic/see_unsee_node.h 2017-12-19 07:13:00 +0000
274@@ -0,0 +1,26 @@
275+/*
276+ * Copyright (C) 2017 by the Widelands Development Team
277+ *
278+ * This program is free software; you can redistribute it and/or
279+ * modify it under the terms of the GNU General Public License
280+ * as published by the Free Software Foundation; either version 2
281+ * of the License, or (at your option) any later version.
282+ *
283+ * This program is distributed in the hope that it will be useful,
284+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
285+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
286+ * GNU General Public License for more details.
287+ *
288+ * You should have received a copy of the GNU General Public License
289+ * along with this program; if not, write to the Free Software
290+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
291+ *
292+ */
293+
294+#ifndef WL_LOGIC_SEE_UNSEE_NODE_H
295+#define WL_LOGIC_SEE_UNSEE_NODE_H
296+
297+namespace Widelands {
298+ enum class SeeUnseeNode { kUnsee, kUnexplore, kReveal };
299+}
300+#endif // end of include guard: WL_LOGIC_SEE_UNSEE_NODE_H
301
302=== modified file 'src/map_io/map_players_view_packet.cc'
303--- src/map_io/map_players_view_packet.cc 2017-09-03 11:19:21 +0000
304+++ src/map_io/map_players_view_packet.cc 2017-12-19 07:13:00 +0000
305@@ -72,6 +72,9 @@
306 constexpr uint8_t kCurrentPacketVersionSurveyTimes = 1;
307 #define SURVEY_TIMES_FILENAME_TEMPLATE DIRNAME_TEMPLATE "/survey_times_%u"
308
309+constexpr uint8_t kCurrentPacketVersionHidden = 1;
310+#define HIDDEN_FILENAME_TEMPLATE DIRNAME_TEMPLATE "/hidden_%u"
311+
312 constexpr uint8_t kCurrentPacketVersionVision = 1;
313 #define VISION_FILENAME_TEMPLATE DIRNAME_TEMPLATE "/vision_%u"
314
315@@ -292,7 +295,7 @@
316 const uint16_t mapheight = map.get_height();
317 Field& first_field = map[0];
318 const PlayerNumber nr_players = map.get_nrplayers();
319- iterate_players_existing_const(plnum, nr_players, egbase, player) {
320+ iterate_players_existing(plnum, nr_players, egbase, player) {
321 Player::Field* const player_fields = player->fields_;
322 uint32_t const gametime = egbase.get_gametime();
323
324@@ -466,10 +469,14 @@
325 OPEN_INPUT_FILE(FileRead, survey_times_file, survey_times_filename,
326 SURVEY_TIMES_FILENAME_TEMPLATE, kCurrentPacketVersionSurveyTimes);
327
328- OPEN_INPUT_FILE_NEW_VERSION_SILENT(FileRead, border_file, border_filename,
329+ OPEN_INPUT_FILE_NEW_VERSION(FileRead, border_file, border_filename,
330 border_file_version, BORDER_FILENAME_TEMPLATE,
331 kCurrentPacketVersionBorder);
332
333+ OPEN_INPUT_FILE_NEW_VERSION_SILENT(FileRead, hidden_file, hidden_filename,
334+ hidden_file_version, HIDDEN_FILENAME_TEMPLATE,
335+ kCurrentPacketVersionHidden);
336+
337 for (FCoords first_in_row(Coords(0, 0), &first_field); first_in_row.y < mapheight;
338 ++first_in_row.y, first_in_row.field += mapwidth) {
339 FCoords r = first_in_row, br = map.bl_n(r);
340@@ -777,6 +784,21 @@
341 }
342 } while (r.x);
343 }
344+
345+ // Read the number of explicitly hidden fields and then loop through them
346+ if (hidden_file_version == kCurrentPacketVersionHidden) {
347+ const uint32_t no_of_hidden_fields = hidden_file.unsigned_32();
348+ for (uint32_t i = 0; i < no_of_hidden_fields; ++i) {
349+ player->hidden_fields_.insert(std::make_pair(hidden_file.unsigned_32(), hidden_file.unsigned_16()));
350+ }
351+ } else if (hidden_file_version < 0) {
352+ // TODO(GunChleoc): Savegame compatibility - remove after Build 20
353+ log("MapPlayersViewPacket - No hidden fields to read for Player %d - probably an old save file\n", plnum);
354+ } else {
355+ throw UnhandledVersionError("MapPlayersViewPacket - Hidden fields file",
356+ hidden_file_version, kCurrentPacketVersionHidden);
357+ }
358+
359 CHECK_TRAILING_BYTES(unseen_times_file, unseen_times_filename);
360 CHECK_TRAILING_BYTES(node_immovable_kinds_file, node_immovable_kinds_filename);
361 CHECK_TRAILING_BYTES(node_immovables_file, node_immovables_filename);
362@@ -788,6 +810,8 @@
363 CHECK_TRAILING_BYTES(surveys_file, surveys_filename);
364 CHECK_TRAILING_BYTES(survey_amounts_file, survey_amounts_filename);
365 CHECK_TRAILING_BYTES(survey_times_file, survey_times_filename);
366+ CHECK_TRAILING_BYTES(border_file, border_filename);
367+ CHECK_TRAILING_BYTES(hidden_file, hidden_filename);
368 }
369 }
370
371@@ -864,6 +888,7 @@
372 FileWrite surveys_file;
373 FileWrite survey_amounts_file;
374 FileWrite survey_times_file;
375+ FileWrite hidden_file;
376 FileWrite vision_file;
377 FileWrite border_file;
378 for (FCoords first_in_row(Coords(0, 0), &first_field); first_in_row.y < mapheight;
379@@ -970,6 +995,12 @@
380 }
381 } while (r.x);
382 }
383+ // Write the number of explicitly hidden fields and then loop through them
384+ hidden_file.unsigned_32(player->hidden_fields_.size());
385+ for (const auto& hidden : player->hidden_fields_) {
386+ hidden_file.unsigned_32(hidden.first);
387+ hidden_file.unsigned_16(hidden.second);
388+ }
389
390 char filename[FILENAME_SIZE];
391
392@@ -1005,6 +1036,8 @@
393
394 WRITE(survey_times_file, SURVEY_TIMES_FILENAME_TEMPLATE, kCurrentPacketVersionSurveyTimes);
395
396+ WRITE(hidden_file, HIDDEN_FILENAME_TEMPLATE, kCurrentPacketVersionHidden);
397+
398 WRITE(vision_file, VISION_FILENAME_TEMPLATE, kCurrentPacketVersionVision);
399
400 WRITE(border_file, BORDER_FILENAME_TEMPLATE, kCurrentPacketVersionBorder);
401
402=== modified file 'src/scripting/lua_game.cc'
403--- src/scripting/lua_game.cc 2017-12-17 03:57:22 +0000
404+++ src/scripting/lua_game.cc 2017-12-19 07:13:00 +0000
405@@ -564,25 +564,23 @@
406 /* RST
407 .. method:: reveal_fields(fields)
408
409- Make these fields visible for the current player. The fields will remain
410- visible until they are hidden again.
411+ Make these fields visible for the current player. If the fields were previously hidden via
412+ `hide_fields`, restores the exact vision that they had before that was done.
413
414- :arg fields: The fields to show
415+ :arg fields: The fields to reveal
416 :type fields: :class:`array` of :class:`wl.map.Fields`
417
418 :returns: :const:`nil`
419 */
420 int LuaPlayer::reveal_fields(lua_State* L) {
421- EditorGameBase& egbase = get_egbase(L);
422- Player& p = get(L, egbase);
423- const Map& map = egbase.map();
424+ Game& game = get_game(L);
425+ Player& p = get(L, game);
426
427 luaL_checktype(L, 2, LUA_TTABLE);
428
429 lua_pushnil(L); /* first key */
430 while (lua_next(L, 2) != 0) {
431- p.see_node(
432- map, map[0], (*get_user_class<LuaField>(L, -1))->fcoords(L), egbase.get_gametime());
433+ p.hide_or_reveal_field(game.get_gametime(), (*get_user_class<LuaField>(L, -1))->coords(), SeeUnseeNode::kReveal);
434 lua_pop(L, 1);
435 }
436
437@@ -592,29 +590,28 @@
438 /* RST
439 .. method:: hide_fields(fields)
440
441- Make these fields hidden for the current player if they are not
442- seen by a military building.
443+ Make these fields hidden for the current player.
444
445 :arg fields: The fields to hide
446 :type fields: :class:`array` of :class:`wl.map.Fields`
447
448- :arg hide_completely: *Optional*. The fields will be marked as unexplored.
449- :type hide_completely: :class:`boolean`
450+ :arg unexplore: *Optional*. If `true`, the fields will be marked as completely unexplored.
451+ :type unexplore: :class:`boolean`
452
453 :returns: :const:`nil`
454 */
455 int LuaPlayer::hide_fields(lua_State* L) {
456- EditorGameBase& egbase = get_egbase(L);
457- Player& p = get(L, egbase);
458+ Game& game = get_game(L);
459+ Player& p = get(L, game);
460
461 luaL_checktype(L, 2, LUA_TTABLE);
462- const bool mode = !lua_isnone(L, 3) && luaL_checkboolean(L, 3);
463+ const SeeUnseeNode mode = (!lua_isnone(L, 3) && luaL_checkboolean(L, 3)) ?
464+ SeeUnseeNode::kUnexplore :
465+ SeeUnseeNode::kUnsee;
466
467 lua_pushnil(L); /* first key */
468 while (lua_next(L, 2) != 0) {
469- p.unsee_node((*get_user_class<LuaField>(L, -1))->fcoords(L).field - &egbase.map()[0],
470- egbase.get_gametime(),
471- mode ? Player::UnseeNodeMode::kUnexplore : Player::UnseeNodeMode::kUnsee);
472+ p.hide_or_reveal_field(game.get_gametime(), (*get_user_class<LuaField>(L, -1))->coords(), mode);
473 lua_pop(L, 1);
474 }
475
476
477=== modified file 'test/maps/lua_testsuite.wmf/scripting/gplayer.lua'
478--- test/maps/lua_testsuite.wmf/scripting/gplayer.lua 2017-03-24 08:31:08 +0000
479+++ test/maps/lua_testsuite.wmf/scripting/gplayer.lua 2017-12-19 07:13:00 +0000
480@@ -8,82 +8,6 @@
481 assert_equal("Awesome Atlantean", egbase.players[3].name)
482 end
483
484--- -- =======================================================================
485--- -- See Fields/Hide Fields
486--- -- =======================================================================
487-player_vision_tests = lunit.TestCase("Player vision tests")
488-function player_vision_tests:setup()
489- self.f = map:get_field(50, 20)
490- player1.see_all = false
491-end
492-function player_vision_tests:teardown()
493- player1:hide_fields(self.f:region(1))
494- player1.see_all = false
495-end
496--- This test must appear as the very first
497-function player_vision_tests:test_seen_field()
498- assert_equal(false, player1:sees_field(self.f))
499- assert_equal(false, player1:seen_field(self.f))
500- player1:reveal_fields(self.f:region(1))
501- player1:hide_fields(self.f:region(1))
502- assert_equal(false, player1:sees_field(self.f))
503- assert_equal(true, player1:seen_field(self.f))
504-end
505-
506-function player_vision_tests:test_sees_field()
507- assert_equal(false, player1:sees_field(self.f))
508- player1:reveal_fields(self.f:region(1))
509- assert_equal(true, player1:sees_field(self.f))
510- player1:hide_fields(self.f:region(1))
511- assert_equal(false, player1:sees_field(self.f))
512-end
513-function player_vision_tests:test_see_all()
514- assert_equal(false, player1:sees_field(self.f))
515- player1.see_all = true
516- assert_equal(true, player1.see_all)
517- assert_equal(true, player1:sees_field(self.f))
518- player1.see_all = false
519- assert_equal(false, player1:sees_field(self.f))
520-end
521-function player_vision_tests:test_sees_field_see_all_hide()
522- player1.see_all = true
523- assert_equal(true, player1:sees_field(self.f))
524- player1:hide_fields(self.f:region(1))
525- assert_equal(true, player1:sees_field(self.f))
526- player1.see_all = false
527- assert_equal(false, player1:sees_field(self.f))
528-
529- player1:reveal_fields(self.f:region(1))
530- assert_equal(true, player1:sees_field(self.f))
531- player1.see_all = false
532- assert_equal(true, player1:sees_field(self.f))
533-end
534-
535--- This test must go last, because we change the state of player1:seen_field.
536-function player_vision_tests:test_hide_completely()
537- player1.see_all = true
538- assert_equal(true, player1:sees_field(self.f))
539- player1.see_all = false
540- assert_equal(false, player1:sees_field(self.f))
541-
542- player1:hide_fields(self.f:region(1), false)
543- game.desired_speed = 0;
544- assert_equal(false, player1:sees_field(self.f))
545- assert_equal(true, player1:seen_field(self.f))
546-
547- player1.see_all = true
548- assert_equal(true, player1:sees_field(self.f))
549- player1.see_all = false
550- assert_equal(false, player1:sees_field(self.f))
551-
552- player1:hide_fields(self.f:region(1), true)
553- game.desired_speed = 0;
554- assert_equal(false, player1:sees_field(self.f))
555- assert_equal(false, player1:seen_field(self.f))
556- player1:reveal_fields(self.f:region(1))
557-end
558-
559-
560 -- =========================
561 -- Forbid & Allow buildings
562 -- =========================
563
564=== added file 'test/maps/plain.wmf/scripting/test_player_vision.lua'
565--- test/maps/plain.wmf/scripting/test_player_vision.lua 1970-01-01 00:00:00 +0000
566+++ test/maps/plain.wmf/scripting/test_player_vision.lua 2017-12-19 07:13:00 +0000
567@@ -0,0 +1,85 @@
568+-- -- =======================================================================
569+-- -- See Fields/Hide Fields
570+-- -- =======================================================================
571+
572+run(function()
573+ function cleanup(field)
574+ p1:hide_fields(field:region(1))
575+ p1.see_all = false
576+ end
577+
578+ sleep(5000)
579+ local field = wl.Game().map:get_field(50, 20)
580+ cleanup(field)
581+
582+ -- Seen field
583+ assert_equal(false, p1:sees_field(field))
584+ assert_equal(false, p1:seen_field(field))
585+ p1:reveal_fields(field:region(1))
586+ sleep(1000)
587+ p1:hide_fields(field:region(1))
588+ sleep(1000)
589+ assert_equal(false, p1:sees_field(field))
590+ assert_equal(true, p1:seen_field(field))
591+ cleanup(field)
592+
593+ -- Sees field
594+ assert_equal(false, p1:sees_field(field))
595+ p1:reveal_fields(field:region(1))
596+ sleep(1000)
597+ assert_equal(true, p1:sees_field(field))
598+ p1:hide_fields(field:region(1))
599+ sleep(1000)
600+ assert_equal(false, p1:sees_field(field))
601+ cleanup(field)
602+
603+ -- See all
604+ assert_equal(false, p1:sees_field(field))
605+ p1.see_all = true
606+ assert_equal(true, p1.see_all)
607+ assert_equal(true, p1:sees_field(field))
608+ p1.see_all = false
609+ assert_equal(false, p1:sees_field(field))
610+ cleanup(field)
611+
612+ -- Sees field see all hide
613+ p1.see_all = true
614+ assert_equal(true, p1:sees_field(field))
615+ p1:hide_fields(field:region(1))
616+ sleep(1000)
617+ assert_equal(true, p1:sees_field(field))
618+ p1.see_all = false
619+ assert_equal(false, p1:sees_field(field))
620+ cleanup(field)
621+
622+ p1:reveal_fields(field:region(1))
623+ sleep(1000)
624+ assert_equal(true, p1:sees_field(field))
625+ p1.see_all = false
626+ assert_equal(true, p1:sees_field(field))
627+ cleanup(field)
628+
629+ -- Unexplore
630+ p1:hide_fields(field:region(1), false)
631+ sleep(1000)
632+ assert_equal(false, p1:sees_field(field))
633+ assert_equal(true, p1:seen_field(field))
634+
635+ p1.see_all = true
636+ assert_equal(true, p1:sees_field(field))
637+ p1.see_all = false
638+ assert_equal(false, p1:sees_field(field))
639+
640+ p1:hide_fields(field:region(1), true)
641+ sleep(1000)
642+ assert_equal(false, p1:sees_field(field))
643+ assert_equal(false, p1:seen_field(field))
644+ p1:reveal_fields(field:region(1))
645+ sleep(1000)
646+ assert_equal(true, p1:sees_field(field))
647+ assert_equal(true, p1:seen_field(field))
648+ cleanup(field)
649+
650+ print("# All Tests passed.")
651+ wl.ui.MapView():close()
652+end)

Subscribers

People subscribed via source and target branches

to status/vote changes: