/[glob2]/glob2/src/Map.cpp
ViewVC logotype

Contents of /glob2/src/Map.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.197.2.1 - (show annotations) (download)
Wed Jul 6 23:06:48 2005 UTC (18 years, 10 months ago) by andrew_sayers
Branch: experimental
Changes since 1.197: +1467 -3700 lines
This is an initial upload of the changes I made to Map.h/Map.cpp, and knock-on changes that had on the system in general.

The Map files are nowhere near ready - they don't even resemble something that might compile.  But the basic principles are all there.

1 /*
2 Copyright (C) 2001-2004 Stephane Magnenat & Luc-Olivier de Charrière
3 for any question or comment contact us at nct@ysagoon.com or nuage@ysagoon.com
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include "Map.h"
21 #include "Game.h"
22 #include "Utilities.h"
23 #include "GlobalContainer.h"
24 #include "LogFileManager.h"
25 #include "Unit.h"
26
27 #include <algorithm>
28 #include <valarray>
29 #include <Stream.h>
30
31 // use deltaOne for first perpendicular direction
32 static const int deltaOne[8][2]={
33 { 0, -1},
34 { 1, 0},
35 { 0, 1},
36 {-1, 0},
37 {-1, -1},
38 { 1, -1},
39 { 1, 1},
40 {-1, 1}};
41
42 // use tabClose for original circular direction
43 static const int tabClose[8][2]={
44 {-1, -1},
45 { 0, -1},
46 { 1, -1},
47 { 1, 0},
48 { 1, 1},
49 { 0, 1},
50 {-1, 1},
51 {-1, 0}};
52
53
54 Map(team_count_t Teams=0, undertile_t T = WATER)
55 : File(F), MaxTeams(Teams), logFile(globalContainer->logFileManager->getFile("Map.log")), DirtyBuildings(), FogOfWar(),
56 pathToResourceCountTot(), pathToResourceCountSuccess(), pathToResourceCountFailure(),
57
58 localResourcesUpdateCount(),
59
60 pathfindLocalResourceCount(), pathfindLocalResourceCountWait(), pathfindLocalResourceCountSuccessBase(), pathfindLocalResourceCountSuccessLocked(),
61 pathfindLocalResourceCountSuccessUpdate(), pathfindLocalResourceCountSuccessUpdateLocked(), pathfindLocalResourceCountFailureUnusable(),
62 pathfindLocalResourceCountFailureNone(), pathfindLocalResourceCountFailureBad(),
63
64 pathToBuildingCountTot(),
65
66 pathToBuildingCountClose(), pathToBuildingCountCloseSuccessStand(), pathToBuildingCountCloseSuccessBase(), pathToBuildingCountCloseSuccessUpdated(),
67 pathToBuildingCountCloseFailureLocked(), pathToBuildingCountCloseFailureEnd(),
68
69 pathToBuildingCountIsFar(), pathToBuildingCountFar(), pathToBuildingCountFarIsNew(), pathToBuildingCountFarOldSuccess(),
70 pathToBuildingCountFarOldFailureLocked(), pathToBuildingCountFarOldFailureBad(), pathToBuildingCountFarOldFailureRepeat(),
71 pathToBuildingCountFarOldFailureUnusable(), pathToBuildingCountFarUpdateSuccess(), pathToBuildingCountFarUpdateFailureLocked(),
72 pathToBuildingCountFarUpdateFailureVirtual(), pathToBuildingCountFarUpdateFailureBad(),
73
74 localBuildingElevationUpdate(), localBuildingElevationUpdateLocked(), globalBuildingElevationUpdate(), globalBuildingElevationUpdateLocked(),
75
76 buildingAvailableCountTot(),
77
78 buildingAvailableCountClose(), buildingAvailableCountCloseSuccessFast(), buildingAvailableCountCloseSuccessAround(), buildingAvailableCountCloseSuccessUpdate(),
79 buildingAvailableCountCloseSuccessUpdateAround(), buildingAvailableCountCloseFailureLocked(), buildingAvailableCountCloseFailureEnd(),
80
81 buildingAvailableCountIsFar(), buildingAvailableCountFar(), buildingAvailableCountFarNew(), buildingAvailableCountFarNewSuccessFast(),
82 buildingAvailableCountFarNewSuccessClosely(), buildingAvailableCountFarNewFailureLocked(), buildingAvailableCountFarNewFailureVirtual(),
83 buildingAvailableCountFarNewFailureEnd(), buildingAvailableCountFarOld(), buildingAvailableCountFarOldSuccessFast(),
84 buildingAvailableCountFarOldSuccessAround(), buildingAvailableCountFarOldFailureLocked(), buildingAvailableCountFarOldFailureEnd(),
85
86 pathfindForbiddenCount(), pathfindForbiddenCountSuccess(), pathfindForbiddenCountFailure()
87 {
88 for (int x=0; x<Width; ++x)
89 for (int y=0; y<Height; ++y)
90 Cells[CellWidth, CellHeight].Cell(Teams, T);
91
92 for (int p=0; x<SectorSize; ++p)
93 Sector Sectors[p]();
94
95 //! Elevations to be dirtied - note that individual resources can be dirtied, or the whole lot can be dirtied at once
96 for (int i=0; i<Teams; ++i) {
97 for (int j=0; j<MAX_NB_RESOURCES; ++j)
98 DirtyResource[i][j]=false;
99 DirtyResources[i]=false;
100 DirtyForbidden[i]=false;
101 DirtyGuarded[i]=false;
102 };
103
104 //Elevations stats:
105 for (int t=0; t<16; t++)
106 for (int r=0; r<MAX_RESOURCES; r++)
107 {
108 resourceAvailableCount[t][r]=0;
109 resourceAvailableCountSuccess[t][r]=0;
110 resourceAvailableCountFailure[t][r]=0;
111 }
112
113 regenerate();
114 };
115
116 void Map::~Map()
117 {
118 for (int x=0; x<Width; ++x)
119 for (int y=0; y<Height; ++y)
120 Cells[CellWidth, CellHeight].~Cell(Teams, T);
121
122 for (int p=0; x<SectorSize; ++p)
123 Sector Sectors[p].~Sector();
124
125 if (!verbose) return;
126
127 fprintf(logFile, "\n");
128 for (int t=0; t<16; t++)
129 for (int r=0; r<MAX_RESOURCES; r++)
130 if (resourceAvailableCount[t][r])
131 {
132 fprintf(logFile, "resourceAvailableCount[%d][%d]=%d\n", t, r,
133 resourceAvailableCount[t][r]);
134 fprintf(logFile, "| resourceAvailableCountSuccess[%d][%d]=%d (%f %%)\n", t, r,
135 resourceAvailableCountSuccess[t][r],
136 100.*(double)resourceAvailableCountSuccess[t][r]/(double)resourceAvailableCount[t][r]);
137 fprintf(logFile, "| resourceAvailableCountFailure[%d][%d]=%d (%f %%)\n", t, r,
138 resourceAvailableCountFailure,
139 100.*(double)resourceAvailableCountFailure[t][r]/(double)resourceAvailableCount[t][r]);
140 }
141
142 for (int t=0; t<16; t++)
143 for (int r=0; r<MAX_RESOURCES; r++)
144 {
145 resourceAvailableCount[t][r]=0;
146 resourceAvailableCountSuccess[t][r]=0;
147 resourceAvailableCountFailure[t][r]=0;
148 }
149
150 fprintf(logFile, "\n");
151 fprintf(logFile, "pathToResourceCountTot=%d\n", pathToResourceCountTot);
152 if (pathToBuildingCountTot)
153 {
154 fprintf(logFile, "| pathToResourceCountSuccess=%d (%f %% of tot)\n",
155 pathToResourceCountSuccess,
156 100.*(double)pathToResourceCountSuccess/(double)pathToResourceCountTot);
157 fprintf(logFile, "| pathToResourceCountFailure=%d (%f %% of tot)\n",
158 pathToResourceCountFailure,
159 100.*(double)pathToResourceCountFailure/(double)pathToResourceCountTot);
160 }
161 pathToResourceCountTot=0;
162 pathToResourceCountSuccess=0;
163 pathToResourceCountFailure=0;
164
165 fprintf(logFile, "\n");
166
167 fprintf(logFile, "pathfindLocalResourceCount=%d\n", pathfindLocalResourceCount);
168 if (pathfindLocalResourceCount)
169 {
170 fprintf(logFile, "+ localResourcesUpdateCount=%d (%f %% of calls)\n",
171 localResourcesUpdateCount,
172 100.*(float)localResourcesUpdateCount/(float)pathfindLocalResourceCount);
173
174 fprintf(logFile, "| pathfindLocalResourceCountWait=%d (%f %% of count)\n",
175 pathfindLocalResourceCountWait,
176 100.*(float)pathfindLocalResourceCountWait/(float)pathfindLocalResourceCount);
177
178 int pathfindLocalResourceCountSuccess=
179 +pathfindLocalResourceCountSuccessBase
180 +pathfindLocalResourceCountSuccessLocked
181 +pathfindLocalResourceCountSuccessUpdate
182 +pathfindLocalResourceCountSuccessUpdateLocked;
183
184 fprintf(logFile, "| pathfindLocalResourceCountSuccess=%d (%f %% of count)\n",
185 pathfindLocalResourceCountSuccess,
186 100.*(float)pathfindLocalResourceCountSuccess/(float)pathfindLocalResourceCount);
187 fprintf(logFile, "|- pathfindLocalResourceCountSuccessBase=%d (%f %% of count) (%f %% of success)\n",
188 pathfindLocalResourceCountSuccessBase,
189 100.*(float)pathfindLocalResourceCountSuccessBase/(float)pathfindLocalResourceCount,
190 100.*(float)pathfindLocalResourceCountSuccessBase/(float)pathfindLocalResourceCountSuccess);
191 fprintf(logFile, "|- pathfindLocalResourceCountSuccessLocked=%d (%f %% of count) (%f %% of success)\n",
192 pathfindLocalResourceCountSuccessLocked,
193 100.*(float)pathfindLocalResourceCountSuccessLocked/(float)pathfindLocalResourceCount,
194 100.*(float)pathfindLocalResourceCountSuccessLocked/(float)pathfindLocalResourceCountSuccess);
195 fprintf(logFile, "|- pathfindLocalResourceCountSuccessUpdate=%d (%f %% of count) (%f %% of success)\n",
196 pathfindLocalResourceCountSuccessUpdate,
197 100.*(float)pathfindLocalResourceCountSuccessUpdate/(float)pathfindLocalResourceCount,
198 100.*(float)pathfindLocalResourceCountSuccessUpdate/(float)pathfindLocalResourceCountSuccess);
199 fprintf(logFile, "|- pathfindLocalResourceCountSuccessUpdateLocked=%d (%f %% of count) (%f %% of success)\n",
200 pathfindLocalResourceCountSuccessUpdateLocked,
201 100.*(float)pathfindLocalResourceCountSuccessUpdateLocked/(float)pathfindLocalResourceCount,
202 100.*(float)pathfindLocalResourceCountSuccessUpdateLocked/(float)pathfindLocalResourceCountSuccess);
203
204 int pathfindLocalResourceCountFailure=
205 +pathfindLocalResourceCountFailureUnusable
206 +pathfindLocalResourceCountFailureNone
207 +pathfindLocalResourceCountFailureBad;
208
209 fprintf(logFile, "| pathfindLocalResourceCountFailure=%d (%f %% of count)\n",
210 pathfindLocalResourceCountFailure,
211 100.*(float)pathfindLocalResourceCountFailure/(float)pathfindLocalResourceCount);
212 fprintf(logFile, "|- pathfindLocalResourceCountFailureUnusable=%d (%f %% of count) (%f %% of failure)\n",
213 pathfindLocalResourceCountFailureUnusable,
214 100.*(float)pathfindLocalResourceCountFailureUnusable/(float)pathfindLocalResourceCount,
215 100.*(float)pathfindLocalResourceCountFailureUnusable/(float)pathfindLocalResourceCountFailure);
216 fprintf(logFile, "|- pathfindLocalResourceCountFailureNone=%d (%f %% of count) (%f %% of failure)\n",
217 pathfindLocalResourceCountFailureNone,
218 100.*(float)pathfindLocalResourceCountFailureNone/(float)pathfindLocalResourceCount,
219 100.*(float)pathfindLocalResourceCountFailureNone/(float)pathfindLocalResourceCountFailure);
220 fprintf(logFile, "|- pathfindLocalResourceCountFailureBad=%d (%f %% of count) (%f %% of failure)\n",
221 pathfindLocalResourceCountFailureBad,
222 100.*(float)pathfindLocalResourceCountFailureBad/(float)pathfindLocalResourceCount,
223 100.*(float)pathfindLocalResourceCountFailureBad/(float)pathfindLocalResourceCountFailure);
224 }
225
226 localResourcesUpdateCount=0;
227
228 pathfindLocalResourceCount=0;
229 pathfindLocalResourceCountWait=0;
230 pathfindLocalResourceCountSuccessBase=0;
231 pathfindLocalResourceCountSuccessLocked=0;
232 pathfindLocalResourceCountSuccessUpdate=0;
233 pathfindLocalResourceCountSuccessUpdateLocked=0;
234 pathfindLocalResourceCountFailureUnusable=0;
235 pathfindLocalResourceCountFailureNone=0;
236 pathfindLocalResourceCountFailureBad=0;
237
238 fprintf(logFile, "\n");
239 fprintf(logFile, "pathToBuildingCountTot=%d\n", pathToBuildingCountTot);
240 if (pathToBuildingCountTot)
241 {
242 fprintf(logFile, "|- pathToBuildingCountClose=%d (%f %% of tot)\n",
243 pathToBuildingCountClose,
244 100.*(double)pathToBuildingCountClose/(double)pathToBuildingCountTot);
245
246 int pathToBuildingCountCloseSuccessTot=
247 +pathToBuildingCountCloseSuccessStand
248 +pathToBuildingCountCloseSuccessBase
249 +pathToBuildingCountCloseSuccessUpdated;
250
251 fprintf(logFile, "|- pathToBuildingCountCloseSuccessTot=%d (%f %% of tot) (%f %% of close)\n",
252 pathToBuildingCountCloseSuccessTot,
253 100.*(double)pathToBuildingCountCloseSuccessTot/(double)pathToBuildingCountTot,
254 100.*(double)pathToBuildingCountCloseSuccessTot/(double)pathToBuildingCountClose);
255
256 fprintf(logFile, "|- pathToBuildingCountCloseSuccessStand=%d (%f %% of tot) (%f %% of close) (%f %% of successTot)\n",
257 pathToBuildingCountCloseSuccessStand,
258 100.*(double)pathToBuildingCountCloseSuccessStand/(double)pathToBuildingCountTot,
259 100.*(double)pathToBuildingCountCloseSuccessStand/(double)pathToBuildingCountClose,
260 100.*(double)pathToBuildingCountCloseSuccessStand/(double)pathToBuildingCountCloseSuccessTot);
261
262 fprintf(logFile, "|- pathToBuildingCountCloseSuccessBase=%d (%f %% of tot) (%f %% of close) (%f %% of successTot)\n",
263 pathToBuildingCountCloseSuccessBase,
264 100.*(double)pathToBuildingCountCloseSuccessBase/(double)pathToBuildingCountTot,
265 100.*(double)pathToBuildingCountCloseSuccessBase/(double)pathToBuildingCountClose,
266 100.*(double)pathToBuildingCountCloseSuccessBase/(double)pathToBuildingCountCloseSuccessTot);
267
268 fprintf(logFile, "|- pathToBuildingCountCloseSuccessUpdated=%d (%f %% of tot) (%f %% of close) (%f %% of successTot)\n",
269 pathToBuildingCountCloseSuccessUpdated,
270 100.*(double)pathToBuildingCountCloseSuccessUpdated/(double)pathToBuildingCountTot,
271 100.*(double)pathToBuildingCountCloseSuccessUpdated/(double)pathToBuildingCountClose,
272 100.*(double)pathToBuildingCountCloseSuccessUpdated/(double)pathToBuildingCountCloseSuccessTot);
273
274 int pathToBuildingCountCloseFailure=
275 +pathToBuildingCountCloseFailureLocked
276 +pathToBuildingCountCloseFailureEnd;
277 fprintf(logFile, "|- pathToBuildingCountCloseFailure=%d (%f %% of tot) (%f %% of close)\n",
278 pathToBuildingCountCloseFailure,
279 100.*(double)pathToBuildingCountCloseFailure/(double)pathToBuildingCountTot,
280 100.*(double)pathToBuildingCountCloseFailure/(double)pathToBuildingCountClose);
281 fprintf(logFile, "|- pathToBuildingCountCloseFailureLocked=%d (%f %% of tot) (%f %% of close) (%f %% of failure)\n",
282 pathToBuildingCountCloseFailureLocked,
283 100.*(double)pathToBuildingCountCloseFailureLocked/(double)pathToBuildingCountTot,
284 100.*(double)pathToBuildingCountCloseFailureLocked/(double)pathToBuildingCountClose,
285 100.*(double)pathToBuildingCountCloseFailureLocked/(double)pathToBuildingCountCloseFailure);
286 fprintf(logFile, "|- pathToBuildingCountCloseFailureEnd=%d (%f %% of tot) (%f %% of close) (%f %% of failure)\n",
287 pathToBuildingCountCloseFailureEnd,
288 100.*(double)pathToBuildingCountCloseFailureEnd/(double)pathToBuildingCountTot,
289 100.*(double)pathToBuildingCountCloseFailureEnd/(double)pathToBuildingCountClose,
290 100.*(double)pathToBuildingCountCloseFailureEnd/(double)pathToBuildingCountCloseFailure);
291
292 assert(pathToBuildingCountFar==
293 //+pathToBuildingCountFarIsNew // doesn't return
294 +pathToBuildingCountFarOldSuccess
295 +pathToBuildingCountFarOldFailureLocked
296 +pathToBuildingCountFarOldFailureBad
297 +pathToBuildingCountFarOldFailureRepeat
298 //+pathToBuildingCountFarOldFailureUnusable // doesn't return
299 +pathToBuildingCountFarUpdateSuccess
300 +pathToBuildingCountFarUpdateFailureLocked
301 +pathToBuildingCountFarUpdateFailureVirtual
302 +pathToBuildingCountFarUpdateFailureBad);
303 fprintf(logFile, "|- pathToBuildingCountFar=%d (%f %% of tot)\n",
304 pathToBuildingCountFar,
305 100.*(double)pathToBuildingCountFar/(double)pathToBuildingCountTot);
306 fprintf(logFile, "|+ pathToBuildingCountIsFar=%d (%f %% of tot) (%f %% of far)\n",
307 pathToBuildingCountIsFar,
308 100.*(double)pathToBuildingCountIsFar/(double)pathToBuildingCountTot,
309 100.*(double)pathToBuildingCountIsFar/(double)pathToBuildingCountFar);
310
311 int pathToBuildingCountFarOld=
312 +pathToBuildingCountFarOldSuccess
313 +pathToBuildingCountFarOldFailureLocked
314 +pathToBuildingCountFarOldFailureBad
315 +pathToBuildingCountFarOldFailureRepeat
316 +pathToBuildingCountFarOldFailureUnusable;
317 fprintf(logFile, "|- pathToBuildingCountFarOld=%d (%f %% of tot) (%f %% of far)\n",
318 pathToBuildingCountFarOld,
319 100.*(double)pathToBuildingCountFarOld/(double)pathToBuildingCountTot,
320 100.*(double)pathToBuildingCountFarOld/(double)pathToBuildingCountFar);
321
322 fprintf(logFile, "|- pathToBuildingCountFarOldSuccess=%d (%f %% of tot) (%f %% of far) (%f %% of old)\n",
323 pathToBuildingCountFarOldSuccess,
324 100.*(double)pathToBuildingCountFarOldSuccess/(double)pathToBuildingCountTot,
325 100.*(double)pathToBuildingCountFarOldSuccess/(double)pathToBuildingCountFar,
326 100.*(double)pathToBuildingCountFarOldSuccess/(double)pathToBuildingCountFarOld);
327
328 int pathToBuildingCountFarOldFailure=
329 +pathToBuildingCountFarOldFailureLocked
330 +pathToBuildingCountFarOldFailureBad
331 +pathToBuildingCountFarOldFailureRepeat
332 +pathToBuildingCountFarOldFailureUnusable;
333 fprintf(logFile, "|- pathToBuildingCountFarOldFailure=%d (%f %% of tot) (%f %% of far) (%f %% of old)\n",
334 pathToBuildingCountFarOldFailure,
335 100.*(double)pathToBuildingCountFarOldFailure/(double)pathToBuildingCountTot,
336 100.*(double)pathToBuildingCountFarOldFailure/(double)pathToBuildingCountFar,
337 100.*(double)pathToBuildingCountFarOldFailure/(double)pathToBuildingCountFarOld);
338 fprintf(logFile, "|- pathToBuildingCountFarOldFailureLocked=%d (%f %% of tot) (%f %% of far) (%f %% of old) (%f %% of failure)\n",
339 pathToBuildingCountFarOldFailureLocked,
340 100.*(double)pathToBuildingCountFarOldFailureLocked/(double)pathToBuildingCountTot,
341 100.*(double)pathToBuildingCountFarOldFailureLocked/(double)pathToBuildingCountFar,
342 100.*(double)pathToBuildingCountFarOldFailureLocked/(double)pathToBuildingCountFarOld,
343 100.*(double)pathToBuildingCountFarOldFailureLocked/(double)pathToBuildingCountFarOldFailure);
344 fprintf(logFile, "|- pathToBuildingCountFarOldFailureBad=%d (%f %% of tot) (%f %% of far) (%f %% of old) (%f %% of failure)\n",
345 pathToBuildingCountFarOldFailureBad,
346 100.*(double)pathToBuildingCountFarOldFailureBad/(double)pathToBuildingCountTot,
347 100.*(double)pathToBuildingCountFarOldFailureBad/(double)pathToBuildingCountFar,
348 100.*(double)pathToBuildingCountFarOldFailureBad/(double)pathToBuildingCountFarOld,
349 100.*(double)pathToBuildingCountFarOldFailureBad/(double)pathToBuildingCountFarOldFailure);
350 fprintf(logFile, "|- pathToBuildingCountFarOldFailureRepeat=%d (%f %% of tot) (%f %% of far) (%f %% of old) (%f %% of failure)\n",
351 pathToBuildingCountFarOldFailureRepeat,
352 100.*(double)pathToBuildingCountFarOldFailureRepeat/(double)pathToBuildingCountTot,
353 100.*(double)pathToBuildingCountFarOldFailureRepeat/(double)pathToBuildingCountFar,
354 100.*(double)pathToBuildingCountFarOldFailureRepeat/(double)pathToBuildingCountFarOld,
355 100.*(double)pathToBuildingCountFarOldFailureRepeat/(double)pathToBuildingCountFarOldFailure);
356 fprintf(logFile, "|- pathToBuildingCountFarOldFailureUnusable=%d (%f %% of tot) (%f %% of far) (%f %% of old) (%f %% of failure)\n",
357 pathToBuildingCountFarOldFailureUnusable,
358 100.*(double)pathToBuildingCountFarOldFailureUnusable/(double)pathToBuildingCountTot,
359 100.*(double)pathToBuildingCountFarOldFailureUnusable/(double)pathToBuildingCountFar,
360 100.*(double)pathToBuildingCountFarOldFailureUnusable/(double)pathToBuildingCountFarOld,
361 100.*(double)pathToBuildingCountFarOldFailureUnusable/(double)pathToBuildingCountFarOldFailure);
362
363 int pathToBuildingCountFarUpdate=
364 +pathToBuildingCountFarUpdateSuccess
365 +pathToBuildingCountFarUpdateFailureLocked
366 +pathToBuildingCountFarUpdateFailureVirtual
367 +pathToBuildingCountFarUpdateFailureBad;
368 fprintf(logFile, "|- pathToBuildingCountFarUpdate=%d (%f %% of tot) (%f %% of far)\n",
369 pathToBuildingCountFarUpdate,
370 100.*(double)pathToBuildingCountFarUpdate/(double)pathToBuildingCountTot,
371 100.*(double)pathToBuildingCountFarUpdate/(double)pathToBuildingCountFar);
372 fprintf(logFile, "|+ pathToBuildingCountFarIsNew=%d (%f %% of tot) (%f %% of far) (%f %% of update)\n",
373 pathToBuildingCountFarIsNew,
374 100.*(double)pathToBuildingCountFarIsNew/(double)pathToBuildingCountTot,
375 100.*(double)pathToBuildingCountFarIsNew/(double)pathToBuildingCountFar,
376 100.*(double)pathToBuildingCountFarIsNew/(double)pathToBuildingCountFarUpdate);
377 fprintf(logFile, "|- pathToBuildingCountFarUpdateSuccess=%d (%f %% of tot) (%f %% of far) (%f %% of update)\n",
378 pathToBuildingCountFarUpdateSuccess,
379 100.*(double)pathToBuildingCountFarUpdateSuccess/(double)pathToBuildingCountTot,
380 100.*(double)pathToBuildingCountFarUpdateSuccess/(double)pathToBuildingCountFar,
381 100.*(double)pathToBuildingCountFarUpdateSuccess/(double)pathToBuildingCountFarUpdate);
382
383 int pathToBuildingCountFarUpdateFailure=
384 +pathToBuildingCountFarUpdateFailureLocked
385 +pathToBuildingCountFarUpdateFailureVirtual
386 +pathToBuildingCountFarUpdateFailureBad;
387 fprintf(logFile, "|- pathToBuildingCountFarUpdateFailure=%d (%f %% of tot) (%f %% of far) (%f %% of update)\n",
388 pathToBuildingCountFarUpdateFailure,
389 100.*(double)pathToBuildingCountFarUpdateFailure/(double)pathToBuildingCountTot,
390 100.*(double)pathToBuildingCountFarUpdateFailure/(double)pathToBuildingCountFar,
391 100.*(double)pathToBuildingCountFarUpdateFailure/(double)pathToBuildingCountFarUpdate);
392 fprintf(logFile, "|- pathToBuildingCountFarUpdateFailureLocked=%d (%f %% of tot) (%f %% of far) (%f %% of update) (%f %% of failure)\n",
393 pathToBuildingCountFarUpdateFailureLocked,
394 100.*(double)pathToBuildingCountFarUpdateFailureLocked/(double)pathToBuildingCountTot,
395 100.*(double)pathToBuildingCountFarUpdateFailureLocked/(double)pathToBuildingCountFar,
396 100.*(double)pathToBuildingCountFarUpdateFailureLocked/(double)pathToBuildingCountFarUpdate,
397 100.*(double)pathToBuildingCountFarUpdateFailureLocked/(double)pathToBuildingCountFarUpdateFailure);
398 fprintf(logFile, "|- pathToBuildingCountFarUpdateFailureVirtual=%d (%f %% of tot) (%f %% of far) (%f %% of update) (%f %% of failure)\n",
399 pathToBuildingCountFarUpdateFailureVirtual,
400 100.*(double)pathToBuildingCountFarUpdateFailureVirtual/(double)pathToBuildingCountTot,
401 100.*(double)pathToBuildingCountFarUpdateFailureVirtual/(double)pathToBuildingCountFar,
402 100.*(double)pathToBuildingCountFarUpdateFailureVirtual/(double)pathToBuildingCountFarUpdate,
403 100.*(double)pathToBuildingCountFarUpdateFailureVirtual/(double)pathToBuildingCountFarUpdateFailure);
404 fprintf(logFile, "|- pathToBuildingCountFarUpdateFailureBad=%d (%f %% of tot) (%f %% of far) (%f %% of update) (%f %% of failure)\n",
405 pathToBuildingCountFarUpdateFailureBad,
406 100.*(double)pathToBuildingCountFarUpdateFailureBad/(double)pathToBuildingCountTot,
407 100.*(double)pathToBuildingCountFarUpdateFailureBad/(double)pathToBuildingCountFar,
408 100.*(double)pathToBuildingCountFarUpdateFailureBad/(double)pathToBuildingCountFarUpdate,
409 100.*(double)pathToBuildingCountFarUpdateFailureBad/(double)pathToBuildingCountFarUpdateFailure);
410 }
411
412 pathToBuildingCountTot=0;
413 pathToBuildingCountClose=0;
414 pathToBuildingCountCloseSuccessStand=0;
415 pathToBuildingCountCloseSuccessBase=0;
416 pathToBuildingCountCloseSuccessUpdated=0;
417 pathToBuildingCountCloseFailureLocked=0;
418 pathToBuildingCountCloseFailureEnd=0;
419
420 pathToBuildingCountIsFar=0;
421 pathToBuildingCountFar=0;
422
423 pathToBuildingCountFarIsNew=0;
424 pathToBuildingCountFarOldSuccess=0;
425 pathToBuildingCountFarOldFailureLocked=0;
426 pathToBuildingCountFarOldFailureBad=0;
427 pathToBuildingCountFarOldFailureRepeat=0;
428 pathToBuildingCountFarOldFailureUnusable=0;
429
430 pathToBuildingCountFarUpdateSuccess=0;
431 pathToBuildingCountFarUpdateFailureLocked=0;
432 pathToBuildingCountFarUpdateFailureBad=0;
433
434 int buildingElevationUpdate=localBuildingElevationUpdate+globalBuildingElevationUpdate;
435 fprintf(logFile, "\n");
436 fprintf(logFile, "buildingElevationUpdate=%d\n", buildingElevationUpdate);
437 if (buildingElevationUpdate)
438 {
439 fprintf(logFile, "|- localBuildingElevationUpdate=%d (%f %%)\n",
440 localBuildingElevationUpdate,
441 100.*(double)localBuildingElevationUpdate/(double)buildingElevationUpdate);
442 fprintf(logFile, "|- localBuildingElevationUpdateLocked=%d (%f %%) (%f %% of local)\n",
443 localBuildingElevationUpdateLocked,
444 100.*(double)localBuildingElevationUpdateLocked/(double)buildingElevationUpdate,
445 100.*(double)localBuildingElevationUpdateLocked/(double)localBuildingElevationUpdate);
446
447 fprintf(logFile, "|- globalBuildingElevationUpdate=%d (%f %%)\n",
448 globalBuildingElevationUpdate,
449 100.*(double)globalBuildingElevationUpdate/(double)buildingElevationUpdate);
450 fprintf(logFile, "|- globalBuildingElevationUpdateLocked=%d (%f %%) (%f %% of global)\n",
451 globalBuildingElevationUpdateLocked,
452 100.*(double)globalBuildingElevationUpdateLocked/(double)buildingElevationUpdate,
453 100.*(double)globalBuildingElevationUpdateLocked/(double)globalBuildingElevationUpdate);
454 }
455
456 localBuildingElevationUpdate=0;
457 localBuildingElevationUpdateLocked=0;
458 globalBuildingElevationUpdate=0;
459 globalBuildingElevationUpdateLocked=0;
460
461 fprintf(logFile, "\n");
462 fprintf(logFile, "buildingAvailableCountTot=%d\n", buildingAvailableCountTot);
463 if (buildingAvailableCountTot)
464 {
465 fprintf(logFile, "|- buildingAvailableCountClose=%d (%f %%)\n",
466 buildingAvailableCountClose,
467 100.*(double)buildingAvailableCountClose/(double)buildingAvailableCountTot);
468
469 int buildingAvailableCountCloseSuccess=
470 +buildingAvailableCountCloseSuccessFast
471 +buildingAvailableCountCloseSuccessAround
472 +buildingAvailableCountCloseSuccessUpdate
473 +buildingAvailableCountCloseSuccessUpdateAround;
474 fprintf(logFile, "|- buildingAvailableCountCloseSuccess=%d (%f %% of tot) (%f %% of close)\n",
475 buildingAvailableCountCloseSuccess,
476 100.*(double)buildingAvailableCountCloseSuccess/(double)buildingAvailableCountTot,
477 100.*(double)buildingAvailableCountCloseSuccess/(double)buildingAvailableCountClose);
478 fprintf(logFile, "|- buildingAvailableCountCloseSuccessFast=%d (%f %% of tot) (%f %% of close) (%f %% of close success)\n",
479 buildingAvailableCountCloseSuccessFast,
480 100.*(double)buildingAvailableCountCloseSuccessFast/(double)buildingAvailableCountTot,
481 100.*(double)buildingAvailableCountCloseSuccessFast/(double)buildingAvailableCountClose,
482 100.*(double)buildingAvailableCountCloseSuccessFast/(double)buildingAvailableCountCloseSuccess);
483 fprintf(logFile, "|- buildingAvailableCountCloseSuccessAround=%d (%f %% of tot) (%f %% of close) (%f %% of close success)\n",
484 buildingAvailableCountCloseSuccessAround,
485 100.*(double)buildingAvailableCountCloseSuccessAround/(double)buildingAvailableCountTot,
486 100.*(double)buildingAvailableCountCloseSuccessAround/(double)buildingAvailableCountClose,
487 100.*(double)buildingAvailableCountCloseSuccessAround/(double)buildingAvailableCountCloseSuccess);
488 fprintf(logFile, "|- buildingAvailableCountCloseSuccessUpdate=%d (%f %% of tot) (%f %% of close) (%f %% of close success)\n",
489 buildingAvailableCountCloseSuccessUpdate,
490 100.*(double)buildingAvailableCountCloseSuccessUpdate/(double)buildingAvailableCountTot,
491 100.*(double)buildingAvailableCountCloseSuccessUpdate/(double)buildingAvailableCountClose,
492 100.*(double)buildingAvailableCountCloseSuccessUpdate/(double)buildingAvailableCountCloseSuccess);
493 fprintf(logFile, "|- buildingAvailableCountCloseSuccessUpdateAround=%d (%f %% of tot) (%f %% of close) (%f %% of close success)\n",
494 buildingAvailableCountCloseSuccessUpdateAround,
495 100.*(double)buildingAvailableCountCloseSuccessUpdateAround/(double)buildingAvailableCountTot,
496 100.*(double)buildingAvailableCountCloseSuccessUpdateAround/(double)buildingAvailableCountClose,
497 100.*(double)buildingAvailableCountCloseSuccessUpdateAround/(double)buildingAvailableCountCloseSuccess);
498
499 int buildingAvailableCountCloseFailure=
500 +buildingAvailableCountCloseFailureLocked
501 +buildingAvailableCountCloseFailureEnd;
502 fprintf(logFile, "|- buildingAvailableCountCloseFailure=%d (%f %% of tot) (%f %% of close)\n",
503 buildingAvailableCountCloseFailure,
504 100.*(double)buildingAvailableCountCloseFailure/(double)buildingAvailableCountTot,
505 100.*(double)buildingAvailableCountCloseFailure/(double)buildingAvailableCountClose);
506 fprintf(logFile, "|- buildingAvailableCountCloseFailureLocked=%d (%f %% of tot) (%f %% of close) (%f %% of failure)\n",
507 buildingAvailableCountCloseFailureLocked,
508 100.*(double)buildingAvailableCountCloseFailureLocked/(double)buildingAvailableCountTot,
509 100.*(double)buildingAvailableCountCloseFailureLocked/(double)buildingAvailableCountClose,
510 100.*(double)buildingAvailableCountCloseFailureLocked/(double)buildingAvailableCountCloseFailure);
511 fprintf(logFile, "|- buildingAvailableCountCloseFailureEnd=%d (%f %% of tot) (%f %% of close) (%f %% of failure)\n",
512 buildingAvailableCountCloseFailureEnd,
513 100.*(double)buildingAvailableCountCloseFailureEnd/(double)buildingAvailableCountTot,
514 100.*(double)buildingAvailableCountCloseFailureEnd/(double)buildingAvailableCountClose,
515 100.*(double)buildingAvailableCountCloseFailureEnd/(double)buildingAvailableCountCloseFailure);
516
517 fprintf(logFile, "|- buildingAvailableCountFar=%d (%f %%)\n",
518 buildingAvailableCountFar,
519 100.*(double)buildingAvailableCountFar/(double)buildingAvailableCountTot);
520 fprintf(logFile, "|+ buildingAvailableCountIsFar=%d (%f %% of tot) (%f %% of far)\n",
521 buildingAvailableCountIsFar,
522 100.*(double)buildingAvailableCountIsFar/(double)buildingAvailableCountTot,
523 100.*(double)buildingAvailableCountIsFar/(double)buildingAvailableCountFar);
524
525 fprintf(logFile, "|- buildingAvailableCountFarOld=%d (%f %% of tot) (%f %% of far)\n",
526 buildingAvailableCountFarOld,
527 100.*(double)buildingAvailableCountFarOld/(double)buildingAvailableCountTot,
528 100.*(double)buildingAvailableCountFarOld/(double)buildingAvailableCountFar);
529
530 int buildingAvailableCountFarOldSuccess=
531 +buildingAvailableCountFarOldSuccessFast
532 +buildingAvailableCountFarOldSuccessAround;
533 fprintf(logFile, "|- buildingAvailableCountFarOldSuccess=%d (%f %% of tot) (%f %% of far) (%f %% of old)\n",
534 buildingAvailableCountFarOldSuccess,
535 100.*(double)buildingAvailableCountFarOldSuccess/(double)buildingAvailableCountTot,
536 100.*(double)buildingAvailableCountFarOldSuccess/(double)buildingAvailableCountFar,
537 100.*(double)buildingAvailableCountFarOldSuccess/(double)buildingAvailableCountFarOld);
538 fprintf(logFile, "|- buildingAvailableCountFarOldSuccessFast=%d (%f %% of tot) (%f %% of far) (%f %% of old) (%f %% of old success)\n",
539 buildingAvailableCountFarOldSuccessFast,
540 100.*(double)buildingAvailableCountFarOldSuccessFast/(double)buildingAvailableCountTot,
541 100.*(double)buildingAvailableCountFarOldSuccessFast/(double)buildingAvailableCountFar,
542 100.*(double)buildingAvailableCountFarOldSuccessFast/(double)buildingAvailableCountFarOld,
543 100.*(double)buildingAvailableCountFarOldSuccessFast/(double)buildingAvailableCountFarOldSuccess);
544 fprintf(logFile, "|- buildingAvailableCountFarOldSuccessAround=%d (%f %% of tot) (%f %% of far) (%f %% of old) (%f %% of old success)\n",
545 buildingAvailableCountFarOldSuccessAround,
546 100.*(double)buildingAvailableCountFarOldSuccessAround/(double)buildingAvailableCountTot,
547 100.*(double)buildingAvailableCountFarOldSuccessAround/(double)buildingAvailableCountFar,
548 100.*(double)buildingAvailableCountFarOldSuccessAround/(double)buildingAvailableCountFarOld,
549 100.*(double)buildingAvailableCountFarOldSuccessAround/(double)buildingAvailableCountFarOldSuccess);
550
551 int buildingAvailableCountFarOldFailure=
552 +buildingAvailableCountFarOldFailureLocked
553 +buildingAvailableCountFarOldFailureEnd;
554 fprintf(logFile, "|- buildingAvailableCountFarOldFailure=%d (%f %% of tot) (%f %% of far) (%f %% of old)\n",
555 buildingAvailableCountFarOldFailure,
556 100.*(double)buildingAvailableCountFarOldFailure/(double)buildingAvailableCountTot,
557 100.*(double)buildingAvailableCountFarOldFailure/(double)buildingAvailableCountFar,
558 100.*(double)buildingAvailableCountFarOldFailure/(double)buildingAvailableCountFarOld);
559 fprintf(logFile, "|- buildingAvailableCountFarOldFailureLocked=%d (%f %% of tot) (%f %% of far) (%f %% of old) (%f %% of failure)\n",
560 buildingAvailableCountFarOldFailureLocked,
561 100.*(double)buildingAvailableCountFarOldFailureLocked/(double)buildingAvailableCountTot,
562 100.*(double)buildingAvailableCountFarOldFailureLocked/(double)buildingAvailableCountFar,
563 100.*(double)buildingAvailableCountFarOldFailureLocked/(double)buildingAvailableCountFarOld,
564 100.*(double)buildingAvailableCountFarOldFailureLocked/(double)buildingAvailableCountFarOldFailure);
565 fprintf(logFile, "|- buildingAvailableCountFarOldFailureEnd=%d (%f %% of tot) (%f %% of far) (%f %% of old) (%f %% of failure)\n",
566 buildingAvailableCountFarOldFailureEnd,
567 100.*(double)buildingAvailableCountFarOldFailureEnd/(double)buildingAvailableCountTot,
568 100.*(double)buildingAvailableCountFarOldFailureEnd/(double)buildingAvailableCountFar,
569 100.*(double)buildingAvailableCountFarOldFailureEnd/(double)buildingAvailableCountFarOld,
570 100.*(double)buildingAvailableCountFarOldFailureEnd/(double)buildingAvailableCountFarOldFailure);
571
572 fprintf(logFile, "|- buildingAvailableCountFarNew=%d (%f %% of tot) (%f %% of far)\n",
573 buildingAvailableCountFarNew,
574 100.*(double)buildingAvailableCountFarNew/(double)buildingAvailableCountTot,
575 100.*(double)buildingAvailableCountFarNew/(double)buildingAvailableCountFar);
576
577 int buildingAvailableCountFarNewSuccess=buildingAvailableCountFarNewSuccessFast+buildingAvailableCountFarNewSuccessClosely;
578 fprintf(logFile, "|- buildingAvailableCountFarNewSuccess=%d (%f %% of tot) (%f %% of far) (%f %% of new)\n",
579 buildingAvailableCountFarNewSuccess,
580 100.*(double)buildingAvailableCountFarNewSuccess/(double)buildingAvailableCountTot,
581 100.*(double)buildingAvailableCountFarNewSuccess/(double)buildingAvailableCountFar,
582 100.*(double)buildingAvailableCountFarNewSuccess/(double)buildingAvailableCountFarNew);
583 fprintf(logFile, "|- buildingAvailableCountFarNewSuccessFast=%d (%f %% of tot) (%f %% of far) (%f %% of new) (%f %% of success)\n",
584 buildingAvailableCountFarNewSuccessFast,
585 100.*(double)buildingAvailableCountFarNewSuccessFast/(double)buildingAvailableCountTot,
586 100.*(double)buildingAvailableCountFarNewSuccessFast/(double)buildingAvailableCountFar,
587 100.*(double)buildingAvailableCountFarNewSuccessFast/(double)buildingAvailableCountFarNew,
588 100.*(double)buildingAvailableCountFarNewSuccessFast/(double)buildingAvailableCountFarNewSuccess);
589 fprintf(logFile, "|- buildingAvailableCountFarNewSuccessClosely=%d (%f %% of tot) (%f %% of far) (%f %% of new) (%f %% of success)\n",
590 buildingAvailableCountFarNewSuccessClosely,
591 100.*(double)buildingAvailableCountFarNewSuccessClosely/(double)buildingAvailableCountTot,
592 100.*(double)buildingAvailableCountFarNewSuccessClosely/(double)buildingAvailableCountFar,
593 100.*(double)buildingAvailableCountFarNewSuccessClosely/(double)buildingAvailableCountFarNew,
594 100.*(double)buildingAvailableCountFarNewSuccessClosely/(double)buildingAvailableCountFarNewSuccess);
595
596 int buildingAvailableCountFarNewFailure=
597 +buildingAvailableCountFarNewFailureLocked
598 +buildingAvailableCountFarNewFailureVirtual
599 +buildingAvailableCountFarNewFailureEnd;
600 fprintf(logFile, "|- buildingAvailableCountFarNewFailure=%d (%f %% of tot) (%f %% of far) (%f %% of new)\n",
601 buildingAvailableCountFarNewFailure,
602 100.*(double)buildingAvailableCountFarNewFailure/(double)buildingAvailableCountTot,
603 100.*(double)buildingAvailableCountFarNewFailure/(double)buildingAvailableCountFar,
604 100.*(double)buildingAvailableCountFarNewFailure/(double)buildingAvailableCountFarNew);
605 fprintf(logFile, "|- buildingAvailableCountFarNewFailureLocked=%d (%f %% of tot) (%f %% of far) (%f %% of new) (%f %% of failure)\n",
606 buildingAvailableCountFarNewFailureLocked,
607 100.*(double)buildingAvailableCountFarNewFailureLocked/(double)buildingAvailableCountTot,
608 100.*(double)buildingAvailableCountFarNewFailureLocked/(double)buildingAvailableCountFar,
609 100.*(double)buildingAvailableCountFarNewFailureLocked/(double)buildingAvailableCountFarNew,
610 100.*(double)buildingAvailableCountFarNewFailureLocked/(double)buildingAvailableCountFarNewFailure);
611 fprintf(logFile, "|- buildingAvailableCountFarNewFailureVirtual=%d (%f %% of tot) (%f %% of far) (%f %% of new) (%f %% of failure)\n",
612 buildingAvailableCountFarNewFailureVirtual,
613 100.*(double)buildingAvailableCountFarNewFailureVirtual/(double)buildingAvailableCountTot,
614 100.*(double)buildingAvailableCountFarNewFailureVirtual/(double)buildingAvailableCountFar,
615 100.*(double)buildingAvailableCountFarNewFailureVirtual/(double)buildingAvailableCountFarNew,
616 100.*(double)buildingAvailableCountFarNewFailureVirtual/(double)buildingAvailableCountFarNewFailure);
617 fprintf(logFile, "|- buildingAvailableCountFarNewFailureEnd=%d (%f %% of tot) (%f %% of far) (%f %% of new) (%f %% of failure)\n",
618 buildingAvailableCountFarNewFailureEnd,
619 100.*(double)buildingAvailableCountFarNewFailureEnd/(double)buildingAvailableCountTot,
620 100.*(double)buildingAvailableCountFarNewFailureEnd/(double)buildingAvailableCountFar,
621 100.*(double)buildingAvailableCountFarNewFailureEnd/(double)buildingAvailableCountFarNew,
622 100.*(double)buildingAvailableCountFarNewFailureEnd/(double)buildingAvailableCountFarNewFailure);
623 }
624
625 buildingAvailableCountTot=0;
626
627 buildingAvailableCountClose=0;
628 buildingAvailableCountCloseSuccessFast=0;
629 buildingAvailableCountCloseSuccessAround=0;
630 buildingAvailableCountCloseSuccessUpdate=0;
631 buildingAvailableCountCloseSuccessUpdateAround=0;
632 buildingAvailableCountCloseFailureLocked=0;
633 buildingAvailableCountCloseFailureEnd=0;
634
635 buildingAvailableCountIsFar=0;
636 buildingAvailableCountFar=0;
637 buildingAvailableCountFarNew=0;
638 buildingAvailableCountFarNewSuccessFast=0;
639 buildingAvailableCountFarNewSuccessClosely=0;
640 buildingAvailableCountFarNewFailureLocked=0;
641 buildingAvailableCountFarNewFailureVirtual=0;
642 buildingAvailableCountFarNewFailureEnd=0;
643 buildingAvailableCountFarOld=0;
644 buildingAvailableCountFarOldSuccessFast=0;
645 buildingAvailableCountFarOldSuccessAround=0;
646 buildingAvailableCountFarOldFailureLocked=0;
647 buildingAvailableCountFarOldFailureEnd=0;
648
649 fprintf(logFile, "\n");
650 fprintf(logFile, "pathfindForbiddenCount=%d\n", pathfindForbiddenCount);
651 if (pathfindForbiddenCount)
652 {
653 fprintf(logFile, "|- pathfindForbiddenCountSuccess=%d (%f %%)\n",
654 pathfindForbiddenCountSuccess,
655 100.*(double)pathfindForbiddenCountSuccess/(double)pathfindForbiddenCount);
656
657 fprintf(logFile, "|- pathfindForbiddenCountFailure=%d (%f %%)\n",
658 pathfindForbiddenCountFailure,
659 100.*(double)pathfindForbiddenCountFailure/(double)pathfindForbiddenCount);
660 }
661
662 pathfindForbiddenCount=0;
663 pathfindForbiddenCountSuccess=0;
664 pathfindForbiddenCountFailure=0;
665 }
666
667 bool Map::load(const GAGCore::InputStream *stream, const SessionGame& sessionGame, const Game *const game=0)
668 {
669 assert(sessionGame->versionMinor>=16);
670
671 Map();
672
673 stream->readEnterSection("Map");
674
675 char signature[4];
676 stream->read(signature, 4, "signatureStart");
677 if (memcmp(signature, "MapB", 4))
678 {
679 if (verbose)
680 fprintf(stderr, "Map:: Failed to find signature at the beginning of Map.\n");
681 return false;
682 }
683
684 // We load and compute size:
685 wDec = stream->readSint32("wDec");
686 hDec = stream->readSint32("hDec");
687 w = 1<<wDec;
688 h = 1<<hDec;
689 wMask = w-1;
690 hMask = h-1;
691 size = w*h;
692
693 // We allocate memory:
694 mapDiscovered = new Uint32[size];
695 fogOfWarA = new Uint32[size];
696 fogOfWarB = new Uint32[size];
697 fogOfWar = fogOfWarA;
698 memset(fogOfWarA, 0, size*sizeof(Uint32));
699 memset(fogOfWarB, 0, size*sizeof(Uint32));
700 localForbiddenMap.resize(size, false);
701 localGuardAreaMap.resize(size, false);
702 localClearAreaMap.resize(size, false);
703 cases = new Case[size];
704 undermap = new Uint8[size];
705
706 // We read what's inside the map:
707 stream->read(undermap, size, "undermap");
708 stream->readEnterSection("cases");
709 for (size_t i=0; i<size; i++)
710 {
711 stream->readEnterSection(i);
712 mapDiscovered[i] = stream->readUint32("mapDiscovered");
713
714 cases[i].terrain = stream->readUint16("terrain");
715 cases[i].building = stream->readUint16("building");
716
717 stream->read(&(cases[i].resource), 4, "resource");
718 if (sessionGame->versionMinor < 28)
719 {
720 Resource &r=cases[i].resource;
721 if (r.type!=NO_RES_TYPE)
722 {
723 ResourceType *rt=globalContainer->resourcesTypes.get(r.type);
724 if (r.amount>rt->sizesCount)
725 r.amount=rt->sizesCount;
726 }
727 }
728 cases[i].groundUnit = stream->readUint16("groundUnit");
729 cases[i].airUnit = stream->readUint16("airUnit");
730
731 cases[i].forbidden = stream->readUint32("forbidden");
732
733 if (sessionGame->versionMinor >= 36)
734 cases[i].guardArea = stream->readUint32("guardArea");
735 else
736 cases[i].guardArea = 0;
737
738 if (sessionGame->versionMinor >= 38)
739 cases[i].clearArea = stream->readUint32("clearArea");
740 else
741 cases[i].clearArea = 0;
742
743 stream->readLeaveSection();
744 }
745 stream->readLeaveSection();
746
747 if (game)
748 {
749 // This is a game, so we do compute elevations
750 for (int t=0; t<sessionGame->numberOfTeam; t++)
751 for (int r=0; r<MAX_RESOURCES; r++)
752 for (int s=0; s<2; s++)
753 {
754 assert(resourcesElevation[t][r][s]==NULL);
755 resourcesElevation[t][r][s]=new Uint8[size];
756 updateResourcesElevation(t, r, (bool)s);
757 }
758 for (int t=0; t<32; t++)
759 for (int r=0; r<MAX_RESOURCES; r++)
760 for (int s=0; s<1; s++)
761 elevationUpdated[t][r][s]=false;
762
763 for (int t=0; t<sessionGame->numberOfTeam; t++)
764 for (int s=0; s<2; s++)
765 {
766 assert(forbiddenElevation[t][s] == NULL);
767 forbiddenElevation[t][s] = new Uint8[size];
768 updateForbiddenElevation(t, s);
769 assert(guardAreasElevation[t][s] == NULL);
770 guardAreasElevation[t][s] = new Uint8[size];
771 updateGuardAreasElevation(t, s);
772 }
773 }
774
775 // We load sectors:
776 wSector = stream->readSint32("wSector");
777 hSector = stream->readSint32("hSector");
778 sizeSector = wSector*hSector;
779 assert(sectors == NULL);
780 sectors = new Sector[sizeSector];
781 arraysBuilt = true;
782
783 stream->readEnterSection("sectors");
784 for (int i=0; i<sizeSector; i++)
785 {
786 stream->readEnterSection(i);
787 if (!sectors[i].load(stream, game))
788 {
789 stream->readLeaveSection(3);
790 return false;
791 }
792 stream->readLeaveSection();
793 }
794 stream->readLeaveSection();
795
796 stream->read(signature, 4, "signatureEnd");
797 stream->readLeaveSection();
798
799 if (memcmp(signature, "MapE", 4)!=0)
800 {
801 if (verbose)
802 fprintf(stderr, "Map:: Failed to find signature at the end of Map.\n");
803 return false;
804 }
805
806 return true;
807 }
808
809 void Map::save(GAGCore::OutputStream *stream)
810 {
811 stream->writeEnterSection("Map");
812 stream->write("MapB", 4, "signatureStart");
813
814 // We save size:
815 stream->writeSint32(wDec, "wDec");
816 stream->writeSint32(hDec, "hDec");
817
818 // We write what's inside the map:
819 stream->write(undermap, size, "undermap");
820 stream->writeEnterSection("cases");
821 for (size_t i=0; i<size ;i++)
822 {
823 stream->writeEnterSection(i);
824 stream->writeUint32(mapDiscovered[i], "mapDiscovered");
825
826 stream->writeUint16(cases[i].terrain, "terrain");
827 stream->writeUint16(cases[i].building, "building");
828
829 //SDL_WriteBE32(stream, cases[i].resource.id);
830 stream->write(&(cases[i].resource), 4, "resource");
831
832 stream->writeUint16(cases[i].groundUnit, "groundUnit");
833 stream->writeUint16(cases[i].airUnit, "airUnit");
834 stream->writeUint32(cases[i].forbidden, "forbidden");
835 stream->writeUint32(cases[i].guardArea, "guardArea");
836 stream->writeUint32(cases[i].clearArea, "clearArea");
837 stream->writeLeaveSection();
838 }
839 stream->writeLeaveSection();
840
841 // We save sectors:
842 stream->writeSint32(wSector, "wSector");
843 stream->writeSint32(hSector, "hSector");
844 stream->writeEnterSection("sectors");
845 for (int i=0; i<sizeSector; i++)
846 {
847 stream->writeEnterSection(i);
848 sectors[i].save(stream);
849 stream->writeLeaveSection();
850 }
851 stream->writeLeaveSection();
852
853 stream->write("MapE", 4, "signatureEnd");
854 stream->writeLeaveSection();
855 }
856
857 void Map::addTeam(const team_length_t NewMaximum)
858 {
859 if (MaxTeams < NewMaximum) {
860 MaxTeams = NewMaximum;
861 for (cell_xoffset_t x=0; x<Width; ++x)
862 for (cell_yoffset_t y=0; y<Height; ++y)
863 Cells[x, y].TeamData.resize(MaxTeams);
864 };
865 }
866
867 /* ALGORITHM:
868
869 Along the X axis of the map, examine every 4th row, starting at a random row between 0 and 3.
870 For each examined row, start at a random square between 0 and 15, then move right by a random number between 0 and 15 squares until you reach the end of the row.
871
872 If there is no resource there, do nothing.
873
874 Else, look at a square rand(15) - rand(15) squares to the right, and rand(15) - rand(15) down. In other words, binomially distributed around the current square. We'll refer to that as point 1.
875 Also, look at the square twice as far away in the same direction (point 2).
876 Also, look at the square the same distance in the other direction (point -1).
877
878 * If there is alga on the current tile, do nothing unless there is water at point 1 and sand at point 2.
879 * If there is wood or wheat on the current tile, do nothing unless there is water at point 1 and NOT sand at point -1.
880 * Else, carry on no matter what
881
882 If the current size of the resource is less than or equal to rand(7), the resource grows by one square.
883 Else, if the resource is capable of extending, it attempts to extend into a random square next to the current one (and does nothing if it fails)
884
885 */
886
887 void Map::syncStep(Uint32 stepCounter, const Game& game) {
888 // STEP 1: Grow Resources
889 const int dy=(syncRand()&0x3);
890 for (cell_ypos_t y=dy; y<Height; y+=4)
891 for (cell_xpos_t x=(syncRand()&0xF); x<Width; x+=(syncRand()&0x1F)) {
892 Cell& r=GetCell(x, y);
893 if (r.HasResource())
894 {
895 cell_xoffset_t XOffset=(syncRand()&0xF)-(syncRand()&0xF);
896 cell_yoffset_t YOffset=(syncRand()&0xF)-(syncRand()&0xF);
897
898 // alga, wood and wheat are limited by near underground. Others are not.
899 if ((r.ResourceType()==ALGA )?GetCell(x+XOffset, x+YOffset).isWater()&& GetCell(x+XOffset*2, x+YOffset*2).isSand():
900 (r.ResourceType()==WOOD||r.ResourceType()==WHEAT)?GetCell(x+XOffset, x+YOffset).isWater()&&!GetCell(x-XOffset , x-YOffset ).isSand():
901 true)
902 if (r.ResourceAmount()<=(syncRand()&7))
903 // we grow the resource:
904 incResource(x, y, r.type, r.variety);
905 else if (globalContainer->resourcesTypes.get(r.type)->extendable)
906 // extend the resource into a neighbouring square (or grow it in the current square anyway)
907 incResource(x+(syncRand()&2)-1, ny(syncRand()&2)-1, r.type, r.variety);
908 }
909 }
910
911 // STEP 2: step over each sector
912 for (sector_xpos_t x=0; x<SectorWidth; ++x)
913 for (sector_ypos_t y=0; y<SectorHeight; ++y)
914 Sectors[x, y].syncstep(this, game);
915
916 // STEP 3: update one resource elevation (a different one each tick)
917 team_ID_t ResourceElevationTeam;
918 Resource_enum ResourceElevationResource;
919 bool ResourceElevationCanSwim; // Must initialise to true
920
921 for (unsigned int n=0; n<Teams * MAX_RESOURCES * 2; ++n) { // Stop after a complete circuit
922 // Increment all our values first
923 if (ResourceElevationCanSwim = !ResourceElevationCanSwim) {
924 if (++ResourceElevationResource >= MAX_RESOURCES) {
925 ResourceElevationResource=0;
926 if (++ResourceElevationTeam >= Teams)
927 ResourceElevationTeam = 0;
928 };
929 };
930
931 if (DirtyResources[ResourceElevationTeam] || DirtyResource[ResourceElevationTeam][ResourceElevationResource]) {
932 updateResourceElevation(ResourceElevationTeam, ResourceElevationResource, ResourceElevationCanSwim);
933 return;
934 };
935 };
936 }
937
938 inline void Map::decResource(int x, int y) {
939 Cell& C = GetCell(x, y);
940 assert(C.ResourceType()!=NO_RES_TYPE)
941
942 const RessourceType *const fulltype=globalContainer->ressourcesTypes.get(type);
943
944 if (!fulltype->shrinkable) return;
945
946 if (fulltype->eternal)
947 if (C.ResourceAmount()) C.decResource(); else;
948 else
949 if (fulltype->granular && C.ResourceAmount()>1)
950 C.decResource();
951 else
952 clear();
953 }
954
955 inline void Map::decResource(int x, int y, resource_t R) {
956 Cell& C = GetCell(x, y);
957 if (C.ResourceType() != R) return;
958
959 const RessourceType *const fulltype=globalContainer->ressourcesTypes.get(type);
960
961 if (!fulltype->shrinkable) return;
962
963 if (fulltype->eternal)
964 if (C.ResourceAmount()) C.decResource(); else;
965 else
966 if (fulltype->granular && C.ResourceAmount()>1)
967 C.decResource();
968 else
969 clear();
970 }
971
972 bool Map::incResource(int x, int y, int resourceType, int variety) {
973 Cell& C = GetCell(x, y);
974
975 if (C.type==NO_RES_TYPE)
976 {
977 if (C.Building || C.GroundUnit || C.Terrain() != globalContainer->resourcesTypes.get(resourceType)->terrain)
978 return false;
979
980 C.Resource().Resource(resourceType, variety, 1, 0);
981 return true;
982 } else {
983 const RessourceType *const fulltype=globalContainer->ressourcesTypes.get(type);
984
985 if (!fulltype->shrinkable)
986 return false;
987
988 if (C.ResourceAmount()<fulltype->sizesCount) {
989 C.IncResource();
990 return true;
991 } else {
992 C.DecResource();
993 return false;
994 }
995 }
996 }
997
998
999
1000 inline const bool const Map::doesPosTouchBuilding(cell_xpos_t X, cell_ypos_t Y, Building* B)
1001 {
1002 const bool Touches(const Cell& C, cell_xoffset_t OffsetX, cell_yoffset_t OffsetY) { return C.Building == B };
1003 return FindAdjacentCell(&Touches, X, Y);
1004 }
1005
1006 inline const bool const Map::doesPosTouchBuilding(cell_xpos_t X, cell_ypos_t Y, Building* B, cell_xpos_t& DirectionX, cell_ypos_t& DirectionY)
1007 {
1008 const bool Touches(const Cell& C, cell_xoffset_t OffsetX, cell_yoffset_t OffsetY) { return C.Building == B };
1009 return FindAdjacentCell(&Touches, X, Y, DirectionX, DirectionY);
1010 }
1011
1012 inline const bool const Map::doesPosTouchResource(cell_xpos_t X, cell_ypos_t Y, Resource_enum r)
1013 {
1014 const bool Touches(const Cell& C, cell_xoffset_t OffsetX, cell_yoffset_t OffsetY) { return C.Resource.type == r };
1015 return FindAdjacentCell(&Touches, X, Y);
1016 }
1017
1018 inline const bool const Map::doesPosTouchResource(cell_xpos_t X, cell_ypos_t Y, Resource_enum r, cell_xpos_t& DirectionX, cell_ypos_t& DirectionY)
1019 {
1020 const bool Touches(const Cell& C, cell_xoffset_t OffsetX, cell_yoffset_t OffsetY) { return C.Resource.type == r };
1021 return FindAdjacentCell(&Touches, X, Y, DirectionX, DirectionY);
1022 }
1023
1024 inline const bool const Map::doesUnitTouchBuilding(const Unit& unit, Building* B, cell_xpos_t& DirectionX, cell_ypos_t& DirectionY)
1025 { return doesPosTouchBuilding(Pos.X, Pos.Y, B, DirectionX, DirectionY); }
1026 inline const bool const Map::doesUnitTouchBuilding(const Unit& unit, Building* B )
1027 { return doesPosTouchBuilding(Pos.X, Pos.Y, B); }
1028 inline const bool const Map::doesUnitTouchResource(const Unit& unit, Resource_enum r, cell_xpos_t& DirectionX, cell_ypos_t& DirectionY)
1029 { return doesPosTouchResource(Pos.X, Pos.Y, r, DirectionX, DirectionY); }
1030 inline const bool const Map::doesUnitTouchResource(const Unit& unit, Resource_enum r )
1031 { return doesPosTouchResource(Pos.X, Pos.Y, r); }
1032
1033 //! This method gives a good direction to hit for a warrior, and return false if nothing was found.
1034 //! Currently, it chooses to hit any turret if available, then units, then other buildings. It chooses between units based on their speed and delta(?)
1035 //! It should somehow realise when it's under attack and go after the dangerous things
1036 //TODO: can ground WARRIOR hit flying EXPLORER ?
1037 bool Map::doesUnitTouchEnemy(const Unit& unit, cell_xpos_t& DirectionX, cell_ypos_t& DirectionY)
1038 {
1039 elevation_sum_t BestTime=elevation_max+1;
1040 const bool Touches(const Cell& C, cell_xoffset_t OffsetX, cell_yoffset_t OffsetY) {
1041 if (C.Building() && Unit.Team.EnemyOf(C.Building()->Team) && C.Building.type->defaultUnitStayRange) {
1042 if (b->type->shootingRange) {
1043 DirectionX=OffsetX;
1044 DirectionY=OffsetY;
1045 return true;
1046 } else if (bestTime==elevation_max+1) {
1047 DirectionX=OffsetX;
1048 DirectionY=OffsetY;
1049 bestTime=elevation_max;
1050 };
1051 };
1052
1053 if (C.GroundUnit() && Unit.Team.EnemyOf(C.GroundUnit()->Team) && (C.GroundUnit()->foreingExchangeBuilding==NULL || C.GroundUnit()->Team->sharedVisionExchange()==0))
1054 if (int time=(elevation_max-otherUnit->delta)/otherUnit->speed < bestTime) {
1055 bestTime=time;
1056 DirectionX=OffsetX;
1057 DirectionY=OffsetY;
1058 };
1059 return false;
1060 };
1061
1062 FindAdjacentCell(&Touches, X, Y);
1063 return bestTime < elevation_max;
1064 }
1065
1066 // Fixme: shouldn't we iterate one more along the X and Y axes? See SetUndermapArea for example
1067 void Map::setNoResource(const cell_xpos_t x, const cell_ypos_t y, const cell_size_t Length)
1068 {
1069 assert(l>=0);
1070 assert(l<w);
1071 assert(l<h);
1072 const cell_size_t HalfLength = Length >> 1;
1073 for (cell_xoffset_t X1=X-HalfLength; X1<X+HalfLength; ++XOffset)
1074 for (cell_yoffset_t Y1=Y-HalfLength; YOffset<=Y+HalfLength; ++YOffset)
1075 GetCell(X1, Y1).Resource().Resource();
1076 }
1077
1078 //! Fill a the squares (x-L/2, y-L/2)..(x+L/2, y+L/2) with resources of the specified type
1079 void Map::FillAreaWithResource(int x, int y, int type, int Length)
1080 {
1081 assert(l>=0);
1082 assert(l<w);
1083 assert(l<h);
1084 const cell_size_t HalfLength = Length >> 1;
1085 for (cell_xoffset_t X1=X-HalfLength; X1<X+HalfLength; ++XOffset)
1086 for (cell_yoffset_t Y1=Y-HalfLength; YOffset<=Y+HalfLength; ++YOffset)
1087 if (GetCell(X1, Y1).isResourceAllowed(type)) {
1088 Resource& r = GetCell(X1, Y1).Resource();
1089 r.type=type;
1090 ResourceType *rt=globalContainer->resourcesTypes.get(type);
1091 r.variety = syncRand() % rt->varietiesCount;
1092 assert(rt->sizesCount>1);
1093 r.ResourceAmount()=1 + syncRand() % (rt->sizesCount-1);
1094 r.animation=0;
1095 }
1096 }
1097
1098 const bool Map::resourceAvailable(const team_ID_t Team, const Resource_Enum R, const bool CanSwim, const cell_xpos_t x, const cell_ypos_t y, cell_xpos_t& targetX, cell_ypos_t& targetY, const elevation_t* dist) const {
1099 // distance and availability
1100 bool result = GetCell(x, y)[Team].ResourceAvailable(R, CanSwim);
1101
1102 if (dist) *dist = result?elevation_max - result:result;
1103
1104 // target position
1105 resourceAvailableCount[Team][R]++;
1106 if (getGlobalElevationDestination(targetX=x, targetY=y, Team, (Can_Swim?RESOURCE_SWIM:RESOURCE_NOSWIM) + R))
1107 resourceAvailableCountSuccess[teamNumber][resourceType]++;
1108 else
1109 resourceAvailableCountFailure[teamNumber][resourceType]++;
1110
1111 return result;
1112 }
1113
1114 //! Climb the elevation hill to the highest point in MaxHillclimbIterations iterations, to a local maximum, or to the destination
1115 typedef const elevation_t (*ElevationCalculator)(const Cell&, const cell_xpos_t, const cell_ypos_t);
1116 static bool Map::ClimbElevationHill(cell_xpos_t& x, cell_ypos_t& y, const team_ID_t p, const ElevationCalculator& Elevation)
1117 {
1118 // max is initiaslized to elevation value of current position
1119 elevation_t max = Elevation(x, y);
1120
1121 // for up to 256 steps, we follow elevation
1122 for (int count=0; count<MaxHillclimbIterations; count++)
1123 {
1124 bool found = false;
1125 x_offset_t best_x = 0; // -1, 0, or +1
1126 y_offset_t best_y = 0; // -1, 0, or +1
1127 elevation_t g;
1128
1129 inline void check_direction(const cell_xpos_t x1, const cell_xpos_t y1) { if ((g=Elevation(x+x1, y+y1)>max) { max=g; best_x=x1; best_y=y1; found=true; } };
1130
1131 check_direction(-1, -1); check_direction(0, -1); check_direction(1, -1);
1132 check_direction(0, -1); /* Current cell */ check_direction(1, 0);
1133 check_direction(1, -1); check_direction(0, 1); check_direction(1, 1);
1134
1135 x += best_x;
1136 y += best_y;
1137
1138 // break if we have reached a local maximum or the destination
1139 if (!found || max == elevation_max)
1140 return found;
1141 }
1142
1143 return false;
1144 }
1145
1146 /**
1147 Update Elevations
1148 **/
1149
1150 //! Take a elevation map where individual squares have had elevations applied, and propagate those values to nearby squares
1151 void Map::PropagateElevation(const team_ID_t p, const elevation_index_t i) {
1152 assert(i < TotalElevations);
1153 void update(const cell_pos_t x, const cell_pos_t y, const elevation_t g) {
1154 if (Cells[x, y][p][i] >= g) return;
1155 Cells[x, y][p][i] = g--;
1156 if (g<elevation_min) next;
1157
1158 update(x-1, y-1, g); update(x, y-1, g); update(x+1, y-1);
1159 update(x-1, y , g); /* current cell */ update(x+1, y );
1160 update(x-1, y+1, g); update(x, y+1, g); update(x+1, y+1);
1161 };
1162
1163 for (cell_ypos_t y = 0; y < Height; ++y)
1164 for (cell_xpos_t x = 0; x < Width; ++x) {
1165 const elevation_t g = Cells[x, y][p][i] - 1;
1166 if (g<elevation_min) next;
1167
1168 update(x-1, y-1); update(x, y-1); update(x+1, y-1);
1169 update(x-1, y ); /* current cell */ update(x+1, y );
1170 update(x-1, y+1); update(x, y+1); update(x+1, y+1);
1171 };
1172 };
1173
1174 void Map::updateResourcesElevation(const team_ID_t p, const Resource_enum R, const bool CanSwim)
1175 {
1176 const elevation_index_t i = (CanSwim?RESOURCE_SWIM:RESOURCE_NOSWIM) + R;
1177 assert(i < TotalElevations);
1178 bool NotVisibleToBeCollected=(globalContainer->resourcesTypes.get(resourceType)->visibleToBeCollected)?0:1;
1179
1180 const bool updateCell(Cell& c, cell_xpos_t, cell_ypos_t) {
1181 c[p][i] =
1182 c[p].Forbidden || // is it a forbidden area?
1183 c.Building || // is it a building?
1184 (!canSwim && c.isWater())?0: // Is it water (and you can't swim)?
1185 c.Resource.type==ResourceType && // Otherwise, is it the right resource, invisible and hidden(?)
1186 (NotVisibleToBeCollected || c[p].Fog(FogOfWarAB))?elevation_max:
1187 1
1188 return true;
1189 }
1190 IterateOverArea(&updateCell);
1191 PropagateElevation(i);
1192 }
1193
1194 //! The forbidden map controls all types of forbidden area:
1195 // cells with a resource, building or water (if you can't swim) are most forbidden,
1196 // cells in a forbidden area are slightly less forbidden,
1197 // other cells are totally allowed
1198 void Map::updateForbiddenElevation(const team_ID_t p, const bool CanSwim)
1199 {
1200 const elevation_index_t i = CanSwim?FORBIDDEN_SWIM:FORBIDDEN_NOSWIM;
1201 assert(i < TotalElevations);
1202
1203 const bool updateCell(Cell& c, cell_xpos_t, cell_ypos_t) {
1204 c[p][i] =
1205 (c.Resource().type!=NO_RES_TYPE) ||
1206 c.Building ||
1207 (!canSwim && c.isWater())?0:
1208 c[p].Forbidden()?1:elevation_max
1209 return true;
1210 }
1211 IterateOverArea(&updateCell);
1212 PropagateElevation(i);
1213 }
1214
1215 inline void Map::updateForbiddenElevation(const team_ID_t p) {
1216 updateForbiddenElevation(p, false);
1217 updateForbiddenElevation(p, true);
1218 };
1219
1220 void Map::updateGuardAreasElevation(const team_ID_t p, const bool CanSwim)
1221 {
1222 const elevation_index_t i = CanSwim?GUARD_SWIM:GUARD_NOSWIM;
1223 assert(i < TotalElevations);
1224
1225 const bool updateCell(Cell& c, cell_xpos_t, cell_ypos_t) {
1226 c[p][i] =
1227 c[p].Forbidden() || // Is it a forbidden area?
1228 (c.Resource().type!=NO_RES_TYPE) || // Is there a resource in the way?
1229 c.Building || // Is there a building in the way?
1230 (!canSwim && c.isWater())?0: // Is there water you can't swim past?
1231 c[p].Guarded()?elevation_max:1 // Is it a forbidden area?
1232 return true;
1233 }
1234 IterateOverArea(&updateCell);
1235 PropagateElevation(i);
1236 }
1237
1238 inline void Map::updateGuardAreasElevation(const team_ID_t p) {
1239 updateGuardAreasElevation(p, false);
1240 updateGuardAreasElevation(p, true);
1241 };
1242
1243
1244 /** The following could *seems* to be redundant. I'll remove it later if that turns out to be the case
1245
1246 A mini-elevation is a 5x5 grid of elevations, where the values have not been propagated to one another.
1247 It is used to heuristically decide which way to move from a given position.
1248
1249 The miniElevationToDirection() function looks at the eight directions you could move in next turn...
1250 for diagonal moves, it looks at the five sensible moves you can make from there...
1251 for horizontal and vertical moves, it looks at the three sensible moves you can make from there...
1252 here is a diagram showing the "sensible" moves:
1253
1254 *** *** ***
1255 ** * **
1256 * *
1257
1258 * *
1259 ** * **
1260 * *
1261
1262 * *
1263 ** * **
1264 *** *** ***
1265
1266 (for example, it's not sensible to move up then left, or left then right)
1267
1268 The function looks at the highest elevation you could get to in two moves, and where there's a tie, the highest elevation in one move is a tiebreaker.
1269
1270 In "strict" mode, the function will fail unless a better elevation is found. Otherwise, it will fail unless a *different* elevation is found.
1271
1272 ** /
1273
1274 bool MiniElevationsientToDirection(elevation_t MiniElevations[5, 5], cell_xoffset_t& dx, cell_yoffset_t& dy, const bool strict, bool verbose)
1275 {
1276
1277 elevation_t max;
1278 const elevation_t CentralElevation=(MiniElevations[2, 2]<<8)|MiniElevations[2, 2];
1279 elevation_t GreatestElevation=CentralElevation;
1280 int GreatestDirection=8; // Direction with the greatest elevation
1281 bool AcceptableDestination=false; // Have we seen a destination that looks acceptable
1282
1283 inline void CheckDiagonal(Direction, x0, y0, x1, y1, x2, y2, x3, y3, x4, y4, x5, y5) {
1284 if (max=MiniElevations[x0, y0] && max != elevation_max) { // if the nearby cell isn't a perfect success of perfect failure
1285 max=1;
1286 if (MiniElevations[x1, y1]>max) max = MiniElevations[x1, y1];
1287 if (MiniElevations[x2, y2]>max) max = MiniElevations[x2, y2];
1288 if (MiniElevations[x3, y3]>max) max = MiniElevations[x3, y3];
1289 if (MiniElevations[x4, y4]>max) max = MiniElevations[x4, y4];
1290 if (MiniElevations[x5, y5]>max) max = MiniElevations[x5, y5];
1291 };
1292
1293 Uint32 Elevation = (max<<8)|MiniElevations[x0, y0];
1294 if (strict?Elevation>CentralElevation:Elevation && Elevation!=CentralElevation)
1295 AcceptableDestination=true;
1296 if (Elevation>=GreatestElevation) {
1297 GreatestElevation=Elevation;
1298 GreatestDirection=Direction;
1299 }
1300 };
1301 inline void CheckHorizontalVertical(Direction, x0, y0, x1, y1, x2, y2, x3, y3) {
1302 if (max=MiniElevations[x0, y0] && max != elevation_max) { // if the nearby cell isn't a perfect success of perfect failure
1303 max=1;
1304 if (MiniElevations[x1, y1]>max) max = MiniElevations[x1, y1];
1305 if (MiniElevations[x2, y2]>max) max = MiniElevations[x2, y2];
1306 if (MiniElevations[x3, y3]>max) max = MiniElevations[x3, y3];
1307 };
1308
1309 Uint32 Elevation = (max<<8)|MiniElevations[x0, y0];
1310 if (strict?Elevation>CentralElevation:Elevation && Elevation!=CentralElevation)
1311 AcceptableDestination=true;
1312 if (Elevation>=GreatestElevation) {
1313 GreatestElevation=Elevation;
1314 GreatestDirection=Direction;
1315 }
1316 };
1317
1318 CheckDiagonal(0, 1,1, 0,2, 0,1, 0,0, 1,0, 2,0); // Top-left
1319 CheckDiagonal(1, 3,1, 2,0, 3,0, 4,0, 4,1, 4,2); // Top-right
1320 CheckDiagonal(2, 3,3, 4,2, 4,3, 4,4, 3,4, 2,4); // Bottom-right
1321 CheckDiagonal(3, 1,3, 2,4, 1,4, 0,4, 0,3, 0,2); // Bottom-left
1322
1323 CheckHorizontalVertical(4, 2,1, 1,0, 2,0, 3,0); // Top
1324 CheckHorizontalVertical(5, 3,2, 4,1, 4,2, 4,3); // Right
1325 CheckHorizontalVertical(6, 2,3, 1,4, 2,4, 3,4); // Bottom
1326 CheckHorizontalVertical(7, 1,2, 0,1, 0,2, 0,3); // Left
1327
1328 if (verbose)
1329 {
1330 printf("MiniElevations (%d):\n", strict);
1331 for (int ry=0; ry<5; ry++)
1332 {
1333 for (int rx=0; rx<5; rx++)
1334 printf("%4d", MiniElevations[rx, ry]);
1335 printf("\n");
1336 }
1337 printf("max=%4d.%4d (%d), d=%d, AcceptableDestination=%d\n", GreatestElevation>>8, GreatestElevation&0xFF, GreatestElevation, GreatestDirection, AcceptableDestination);
1338 }
1339
1340 if (!AcceptableDestination)
1341 return false;
1342
1343 Unit::dxdyfromDirection((GreatestDirection<4)?GreatestDirection<<1:
1344 GreatestDirection==8?8:
1345 1+((GreatestDirection-4)<<1),
1346 dx, dy);
1347
1348 return true;
1349 }
1350
1351 //! Generate a mini-elevation grid then pass it to MiniElevationsientToDirection() for handling
1352 bool Map::directionByMiniElevations(const team_ID_t team, const bool CanSwim, const elevation_index_t ElevationIndex, cell_xpos_t x, cell_ypos_t y, cell_xoffset_t& dx, cell_xoffset_t& dy, const bool strict, const bool verbose)
1353 {
1354 elevation_t MiniElevations[5, 5];
1355
1356 // Outside horizontal lines
1357 for (elevation_index_t i=0; i<4; ++i) {
1358 const Cell& C = GetCell(x+i, y ); MiniElevations[i, 0] = (C[Team][ElevationIndex]==0 || C[Team][ElevationIndex]==elevation_max || C.isFreeForGroundUnit(CanSwim, team))?C[Team][ElevationIndex]:0;
1359 const Cell& D = GetCell(x+i, y+4); MiniElevations[i, 4] = (D[Team][ElevationIndex]==0 || D[Team][ElevationIndex]==elevation_max || D.isFreeForGroundUnit(CanSwim, team))?D[Team][ElevationIndex]:0;
1360 };
1361 // Outside and inside vertical lines
1362 for (elevation_index_t i=1; i<3; ++i) {
1363 const Cell& C = GetCell(x , y+i); MiniElevations[0, i] = (C[Team][ElevationIndex]==0 || C[Team][ElevationIndex]==elevation_max || C.isFreeForGroundUnit(CanSwim, team))?C[Team][ElevationIndex]:0;
1364 const Cell& D = GetCell(x+4, y+i); MiniElevations[4, i] = (D[Team][ElevationIndex]==0 || D[Team][ElevationIndex]==elevation_max || D.isFreeForGroundUnit(CanSwim, team))?D[Team][ElevationIndex]:0;
1365
1366 const Cell& E = GetCell(x+1, y+i); MiniElevations[1, i] = (E[Team][ElevationIndex]==0 || E.isFreeForGroundUnit(CanSwim, team))?E[Team][ElevationIndex]:0;
1367 const Cell& F = GetCell(x+3, y+i); MiniElevations[3, i] = (F[Team][ElevationIndex]==0 || F.isFreeForGroundUnit(CanSwim, team))?F[Team][ElevationIndex]:0;
1368 };
1369
1370 // Inside middle vertical lines
1371 const Cell& C = GetCell(x+2, y+1); MiniElevations[2, 1] = (C[Team][ElevationIndex]==0 || C.isFreeForGroundUnit(CanSwim, team))?C[Team][ElevationIndex]:0;
1372 MiniElevations[2, 2] = GetCell(x+2, y+2)[Team][ElevationIndex];
1373 const Cell& D = GetCell(x+2, y+3); MiniElevations[2, 3] = (D[Team][ElevationIndex]==0 || D.isFreeForGroundUnit(CanSwim, team))?D[Team][ElevationIndex]:0;
1374
1375 if (verbose)
1376 printf("directionByMinigrad global %d\n", canSwim);
1377 return directionFromMinigrad(MiniElevations, dx, dy, strict, verbose);
1378 }
1379
1380 //! Same, but use a specific local elevation map
1381 bool Map::directionByMiniElevation(const team_ID_t team, const bool CanSwim, const cell_xpos_t x, const cell_ypos_t y,
1382 const cell_xoffset_t LocalOffsetX, cost cell_yoffset_t LocalOffsetY,
1383 cell_xoffset_t& dx, cell_yoffset_t& dy,
1384 elevation_t localElevation[32, 32], bool strict, bool verbose) {
1385 Uint8 miniElevations[5, 5];
1386 for (cell_xoffset_t XOffset=0; XOffset<5; ++XOffset)
1387 for (cell_yoffset_t YOffset=0; YOffset<5; ++YOffset)
1388 {
1389 int GlobalX=(x+XOffset-2);
1390 int GlobalY=(y+YOffset-2);
1391 int LocalX=(GlobalX-LocalOffsetX+15)%Width;
1392 int LocalY=(GlobalY-LocalOffsetY+15)%Height;
1393
1394 if (LocalX==Width-1) { ++GlobalX; LocalX=0; }
1395 else if (LocalX==32) { --GlobalX; LocalX=31; }
1396
1397 if (LocalY==hMask) { ++GlobalY; LocalY=0; }
1398 else if (LocalY==32) { --GlobalY; LocalY=31; }
1399
1400 assert(LocalX>=0); assert(LocalY>=0);
1401 assert(LocalX<32); assert(LocalY<32);
1402
1403 elevation_t Elevation=localElevation[LocalX, LocalY];
1404
1405 miniElevations[XOffset, YOffset] =
1406 (Elevation==0 || Elevation==elevation_max || (XOffset==2 && YOffset==2) || GetCell(GlobalX, GlobalY).isFreeForGroundUnit(canSwim, team))?Elevation:0;
1407 }
1408
1409 for (cell_xoffset_t XOffset=1; XOffset<4; ++XOffset)
1410 for (cell_yoffset_t YOffset=1; YOffset<4; ++YOffset)
1411 if (miniElevations[XOffset, YOffset]==elevation_max && !GetCell((x+XOffset-2)%Width, (y+YOffset-2)%Height).isFreeForGroundUnit(canSwim, teamMask))
1412 miniGrad[XOffset, YOffset]=0;
1413
1414 if (verbose)
1415 printf("directionByMinigrad local %d\n", CanSwim);
1416 return directionFromMinigrad(miniElevations, dx, dy, strict, verbose);
1417 }
1418 */
1419
1420 typedef const elevation_sum_t (*ElevationFinder)(const Cell&, const cell_xpos_t, const cell_ypos_t);
1421 template <ElevationFinder OptionElevation, elevation_t hilltop=255, elevation_t valley=1, elevation_t trough=0, gradient_t gradient=1>
1422 const bool const Map::PathFind(team_ID_t team, bool CanSwim, cell_xpos_t X, cell_ypos_t Y, cell_xpos_t& DirectionX, cell_ypos_t& DirectionY) {
1423
1424 elevation_sum_t max = OptionElevation(GetCell(X, Y), X, Y);
1425
1426 if (max == hilltop) // can't get any higher than a hilltop
1427 return false;
1428
1429 const bool Found(const Cell& C, const cell_xpos_t x, const cell_ypos_t y) {
1430 if (!C.isFreeForGroundUnitNoForbidden(canSwim))
1431 continue;
1432
1433 const elevation_sum_t C_Elevation = OptionElevation(C, x, y);
1434
1435 if (C_Elevation >= max) {
1436 max = C_Elevation;
1437 if (verbose)
1438 printf("new max=%d\n", max);
1439 DirectionX = x;
1440 DirectionY = y;
1441 };
1442
1443 return C_Elevation == hilltop;
1444 };
1445
1446 FindAdjacentCell(&Found);
1447
1448 return maxValue;
1449 }
1450
1451 const bool const Map::PathFindForbidden(team_ID_t team, bool CanSwim, cell_xpos_t X, cell_ypos_t Y, cell_xpos_t& DirectionX, cell_ypos_t& DirectionY) {
1452 if (verbose)
1453 printf("pathFindForbidden(%d, %d, (%d, %d))\n", team, CanSwim, X, Y);
1454 ++pathfindForbiddenCount;
1455
1456 const elevation_index_t ElevationIndex = CanSwim?FORBIDDEN_SWIM:FORBIDDEN_NOSWIM;
1457 const elevation_sum_t forbidden(const Cell& C, const cell_xpos_t, const cell_ypos_t) { return C[ElevationIndex] };
1458
1459 if (PathFind<forbidden>(team, CanSwim, X, Y, DirectionX, DirectionY)) {
1460 if (verbose)
1461 printf(" Success (%d:%d) (%d, %d)\n", (maxValue>>8), (maxValue&0xFF), *dx, *dy);
1462 pathfindForbiddenCountSuccess++;
1463 return true;
1464 } else {
1465 if (verbose)
1466 printf(" Failure (%d)\n", maxValue);
1467 pathfindForbiddenCountFailure++;
1468 return false;
1469 };
1470
1471 };
1472
1473 const bool const Map::PathFindGuardArea(team_ID_t team, bool CanSwim, cell_xpos_t X, cell_ypos_t Y, cell_xpos_t& DirectionX, cell_ypos_t& DirectionY) {
1474 if (verbose)
1475 printf("pathFindGuardArea(%d, %d, (%d, %d))\n", team, CanSwim, X, Y);
1476 ++pathfindGuardAreaCount;
1477
1478 const elevation_index_t ElevationIndex = CanSwim?GUARDAREA_SWIM:GUARDAREA_NOSWIM;
1479 const elevation_sum_t guardarea(const Cell& C, const cell_xpos_t, const cell_ypos_t) { return C[ElevationIndex] };
1480
1481 if (PathFind<guardarea>(team, CanSwim, X, Y, DirectionX, DirectionY)) {
1482 if (verbose)
1483 printf(" Success (%d:%d) (%d, %d)\n", (maxValue>>8), (maxValue&0xFF), *dx, *dy);
1484 pathfindGuardAreaCountSuccess++;
1485 return true;
1486 } else {
1487 updateGuardAreasElevation(team, CanSwim);
1488 if (verbose)
1489 printf(" Failure (%d)\n", maxValue);
1490 pathfindGuardAreaCountFailure++;
1491 return false;
1492 };
1493
1494 };
1495
1496 bool Map::pathfindResource(const team_ID_t team, resource_t R, const bool CanSwim, const cell_xpos_t X, const cell_ypos_t Y, cell_xpos_t& DirectionX, cell_ypos_t& DirectionY, bool& stopWork) {
1497 if (verbose)
1498 printf("pathFindResource(%d, %d, (%d, %d))\n", team, CanSwim, X, Y);
1499 ++pathfindResourceCount;
1500 assert(resourceType<MAX_RESOURCES);
1501
1502 const elevation_index_t ElevationIndex = (CanSwim?RESOURCE_SWIM:RESOURCE_NOSWIM) + R;
1503 const elevation_index_t ForbiddenIndex = (CanSwim?FORBIDDEN_SWIM:FORBIDDEN_NOSWIM);
1504
1505 const elevation_sum_t resource(const Cell& C, const cell_xpos_t, const cell_ypos_t) { return C[ForbiddenIndex]<<8 + C[ElevationIndex] };
1506
1507 if (PathFind<resource>(team, CanSwim, X, Y, DirectionX, DirectionY)) {
1508 stopWork=true;
1509
1510 if (verbose)
1511 printf(" Success (%d:%d) (%d, %d)\n", (maxValue>>8), (maxValue&0xFF), *dx, *dy);
1512 pathfindResourceCountSuccess++;
1513 return true;
1514 } else {
1515 stopWork = GetCell(X, Y)[ElevationIndex]<2;
1516
1517 if (verbose)
1518 printf(" Failure (%d)\n", maxValue);
1519 pathfindResourceCountFailure++;
1520 return false;
1521 };
1522 }
1523
1524 inline void Map::dirtyAllBuildingElevations(cell_xpos_t x, cell_ypos_t y, cell_height_t XMax, cell_width_t YMax, Team* T)
1525 {
1526 const bool DirtyBuilding(const Cell& C, cell_xpos_t, cell_ypos_t) { if (C.Building() && C.Building->Team == T) C.Building()->MakeDirty() };
1527 return IterateOverArea(&DirtyBuilding, x, y, XMax-1, YMax-1);
1528 }
1529
1530 /**
1531 Set the undermap for a square of Length*Length cells
1532 Since grass isn't allowed next to water, sand is inserted around the edge as necessary
1533 **/
1534 void Map::SetUndermapArea(cell_xpos_t X, cell_ypos_t Y, undertile_t t, cell_size_t Length)
1535 {
1536 const cell_size_t HalfLength = Length >> 1;
1537 for (cell_xoffset_t X1=X-HalfLength; X1<=X+HalfLength; ++XOffset)
1538 for (cell_yoffset_t Y1=Y-HalfLength; YOffset<=Y+HalfLength; ++YOffset)
1539 GetCell(X1, Y1).Undertile(t);
1540
1541 if (t==SAND)
1542 return regenerate(x-HalfLength-1,y-HalfLength-1,Length+1,Length+1);
1543
1544 const undertile_t OtherType = (t==GRASS)?WATER:GRASS;
1545 const cell_ypos_t Top = Y-HalfLength-1;
1546 const cell_ypos_t Bottom = Y+HalfLength+1;
1547 const cell_ypos_t Left = X-HalfLength-1;
1548 const cell_ypos_t Right = X+HalfLength+1;
1549
1550 for (cell_xpos_t X1=Left; X1<=Right; ++X1) {
1551 Cell(X1, Top ).MaybeToSand(OtherType);
1552 Cell(X1, Bottom).MaybeToSand(OtherType);
1553 };
1554 for (cell_ypos_t Y1=Top+1; X1<Bottom; ++Y1) {
1555 Cell(Left , Y1).MaybeToSand(OtherType);
1556 Cell(Right, Y1).MaybeToSand(OtherType);
1557 };
1558
1559 regenerate(x-HalfLength-2,y-HalfLength-2,Length+3,Length+3);
1560 }
1561
1562 /**
1563 If a tile contains a resource, there is a 1/32 chance that...
1564 If the amount of resources there is less than a random number from 0 to 3, it is incremented by one.
1565 Else, pick a random adjacent square.
1566 If there is no ground unit ther and the terrain is of the appropriate type, put a resource there of the same type, level either 0 or 5
1567 **/
1568 inline void Map::smoothResources(unsigned int times) {
1569 const bool SmoothResource(const Cell& C, const cell_xpos_t x, const cell_ypos_t y) {
1570 Resource& R = C.Resource();
1571 if (R && (syncRand&1)) {
1572 if (R.amount < syncRand()&3)
1573 ++R; // Increment the level of the resource
1574 else
1575 GetAdjacentCell(x, y).SetResource(Resource.type, (syncRand()&1)*5);
1576 };
1577 };
1578
1579
1580 while (times--)
1581 IterateOverArea(&SmoothResource);
1582 };
1583
1584 //! Create a random terrain, smooth it out, then fill it with resources
1585 bool Map::makeRandomMap(const MapGenerationDescriptor &descriptor)
1586 {
1587 //! Create a square grid of random terrains, of side 8^(smooth&0x3), smooth it 'smooth' times, then return the number of water, wood, and sand squares
1588 //! This is better than simply generating numbers based on the appropriate ratios, because it accounts for the biases introduced when smoothing a grid of a given size.
1589 //! Note: this code is closely folloed by a section of the main program - any changes here should be put there too
1590 void simulateRandomMap(unsigned int smooth, double& Water, double& Sand, double& Grass)
1591 {
1592 const unsigned int length=8<<(smooth&0x3);
1593 const unsigned int area=length*length;
1594 resource_t undermap[area];
1595
1596 int totalRatio=0x7FFF;
1597 int waterRatio=(int)(Water*((double)totalRatio)); assert(waterRatio >= 0);
1598 int sandRatio =(int)(Sand *((double)totalRatio)); assert( sandRatio >= 0);
1599 int grassRatio=(int)(Grass*((double)totalRatio)); assert(grassRatio >= 0);
1600 totalRatio=waterRatio+sandRatio+grassRatio;
1601
1602 // ONE: create a fully random patchwork
1603 for (int p=0; p<area; ++p) {
1604 int r=syncRand()%totalRatio;
1605 undermap[p] = (r-=waterRatio<0)?WATER:(r-=grassRatio<0)?GRASS:(r<sandRatio)?SAND:assert(false);
1606 }
1607
1608 // TWO: where tiles on two different sides are of the same type, set the current tile to that type (i.e. smooth out the distribution of tiles)
1609 inline const bool setUndermap(const int testPos) {
1610 if (undermap[(p+testPos)%area]==undermap[(p-testPos)%area]) { undermap[p]=undermap[(p+testPos)%area]; return true } else return false;
1611 };
1612 while (smooth--)
1613 for (int p=0; p<area; ++p)
1614 if (((syncRand()&1)?setUndermap( 1 ):setUndermap(length )) ||
1615 ((syncRand()&1)?setUndermap(length+1 ):setUndermap(length-1 )) ||
1616 ((syncRand()&1)?setUndermap(length-2 ):setUndermap(length -(length<<1))) ||
1617 ((syncRand()&1)?setUndermap(length+2+(length<<1)):setUndermap(length+2-(length<<1))))
1618 {};
1619
1620 // What's finally in ?
1621 double Counts[undertile_total]; totals[WATER]==0; totals[SAND]==0; totals[GRASS]==0;
1622 for (int p=0; p<area; ++p)
1623 ++Counts[undermap[p]];
1624
1625 Water=Counts[WATER]/area;
1626 Sand =Counts[SAND ]/area;
1627 Grass=Counts[GRASS]/area;
1628 }
1629
1630
1631 /**
1632 ONE: Find good values for Water, Sand and Grass, based on a complicated algorithm
1633
1634 The principle seems to be that if you ask for a smoothed random map with a certain amount of
1635 water, sand and grass, you won't get it, because the smoothing will bias things towards one or other type.
1636 Instead, the algorithm tries to find values for Water, Sand and Grass that will give acceptable results.
1637
1638 This is done by repeatedly doing the following:
1639 * run "alpha" and "beta" simulations,
1640 * run 10 "gamma" simulations based on alpha and beta
1641 * pick the gamma simulation with the lowest summed square of errors
1642 * Use those Water/Sand/Grass values as the input to the next iteration
1643 **/
1644
1645 double baseWater, baseSand, baseGrass;
1646
1647 if (int totalRatio = descriptor.waterRatio + descriptor.sandRatio + descriptor.grassRatio) {
1648 baseWater=descriptor.waterRatio / totalRatio;
1649 baseSand =descriptor.sandRatio / totalRatio;
1650 baseGrass=descriptor.grassRatio / totalRatio;
1651 } else
1652 baseWater = baseSand = baseGrass = 1.0/3.0;
1653
1654 if (verbose)
1655 printf("makeRandomMap::old-base=(%f, %f, %f).\n", baseWater, baseSand, baseGrass);
1656
1657 double Water=baseWater, Sand =baseSand, Grass=baseGrass;
1658
1659 for (int r=0; r<smooth; ++r)
1660 for (int prec=0; prec<3; prec++) {
1661 double finalAlphaWater=Water, finalAlphaSand=Water, finalAlphaGrass=Water;
1662 simulateRandomMap(r, &finalAlphaWater, &finalAlphaSand, &finalAlphaGrass);
1663
1664 double betaWater= finalAlphaWater?(Water*baseWater)/finalAlphaWater:0;
1665 double betaSand = finalAlphaSand ?(Sand *baseSand )/finalAlphaSand :0;
1666 double betaGrass= finalAlphaGrass?(Grass*baseGrass)/finalAlphaGrass:0;
1667 const double betaSum=betaWater+betaSand+betaGrass;
1668 betaWater/=betaSum;
1669 betaSand /=betaSum;
1670 betaGrass/=betaSum;
1671
1672 double finalBetaWater=betaWater, finalBetaSand=betaSand, finalBetaGrass=betaGrass;
1673 simulateRandomMap(r, finalBetaWater, finalBetaSand, finalBetaGrass);
1674
1675 double proj =
1676 (finalAlphaWater - baseWater)*(finalAlphaWater - baseWater)+
1677 (finalAlphaSand - baseSand )*(finalAlphaSand - baseSand )+
1678 (finalAlphaGrass - baseGrass)*(finalAlphaGrass - baseGrass);
1679 if (proj<=0)
1680 continue;
1681 double proj =
1682 (((finalAlphaWater - baseWater)*(finalBetaWater - baseWater)+
1683 (finalAlphaSand - baseSand )*(finalBetaSand - baseSand )+
1684 (finalAlphaGrass - baseGrass)*(finalBetaGrass - baseGrass))/proj)/10;
1685
1686 double minErr=DBL_MAX;
1687 for (double cf=0.0; cfi>=-proj*10; cfi-=proj) {
1688 const double sumCenter=cf-1.0;
1689 double gammaWater=(cf*betaWater+1.0*Water)/sumCenter;
1690 double gammaSand =(cf*betaSand +1.0*Sand )/sumCenter;
1691 double gammaGrass=(cf*betaGrass+1.0*Grass)/sumCenter;
1692 if (gammaWater<0.0)
1693 gammaWater=0.0;
1694 if (gammaSand<0.0)
1695 gammaSand=0.0;
1696 if (gammaGrass<0.0)
1697 gammaGrass=0.0;
1698 double gammaSum=betaWater+betaSand+betaGrass;
1699 if (gammaSum<=0)
1700 continue;
1701 gammaWater/=gammaSum;
1702 gammaSand /=gammaSum;
1703 gammaGrass/=gammaSum;
1704
1705 double finalGammaWater=gammaWater, finalGammaSand=gammaSand, finalGammaGrass=gammaGrass;
1706 simulateRandomMap(r, finalGammaWater, finalGammaSand, finalGammaGrass);
1707
1708 double errGamma =
1709 (finalGammaWater - baseWater)*(finalGammaWater - baseWater)+
1710 (finalGammaSand - baseSand )*(finalGammaSand - baseSand )+
1711 (finalGammaGrass - baseGrass)*(finalGammaGrass - baseGrass);
1712 if (errGamma<minErr) {
1713 minErr=errGamma;
1714 Water=gammaWater;
1715 Sand =gammaSand;
1716 Grass=gammaGrass;
1717 }
1718 }
1719 };
1720
1721 if (verbose) {
1722 printf("makeRandomMap::new-base =(%f, %f, %f).\n", Water, Sand, Grass);
1723 double simWater=Water, simSand=Sand, simGrass=Sand;
1724 simulateRandomMap(smooth, &simWater=Water, &simSand=Water, &simGrass=Sand);
1725 printf("makeRandomMap::simulateRandomMap=(%f, %f, %f).\n", simWater, simSand, simGrass);
1726 };
1727
1728 /**
1729 TWO: Create the actual undermap, based on the derived amounts of water, sand and grass
1730
1731 This code closely follows simulateRandomMap() - any changes here should be put there too
1732 **/
1733
1734 totalRatio=0x7FFF;
1735 waterRatio=(int)(Water*((double)totalRatio)); assert(waterRatio >= 0);
1736 sandRatio =(int)(Sand *((double)totalRatio)); assert( sandRatio >= 0);
1737 grassRatio=(int)(Grass*((double)totalRatio)); assert(grassRatio >= 0);
1738 totalRatio=waterRatio+sandRatio+grassRatio;
1739
1740 for (int p=0; p<area; ++p) {
1741 int r=syncRand()%totalRatio;
1742 GetCell(p+testPos).UnderTile((r-=waterRatio<0)?WATER:(r-=grassRatio<0)?GRASS:(r<sandRatio)?SAND:assert(false));
1743 }
1744 inline const bool setUndermap(const int testPos) {
1745 if (GetCell(p+testPos).UnderTile()==GetCell(p-testPos).UnderTile()) { GetCell(p).UnderTile(GetCell(p+testPos).UnderTile()); return true } else return false;
1746 };
1747 for (int i=0; i<smooth; i++)
1748 for (int p=0; p<Size; ++p)
1749 if (((syncRand()&1)?setUndermap( 1 ):setUndermap(length )) ||
1750 ((syncRand()&1)?setUndermap(length+1 ):setUndermap(length-1 )) ||
1751 ((syncRand()&1)?setUndermap(length-2 ):setUndermap(length -(length<<1))) ||
1752 ((syncRand()&1)?setUndermap(length+2+(length<<1)):setUndermap(length+2-(length<<1))))
1753 {};
1754
1755 /**
1756 THREE: improve the undermap by making squares equal to those either side of it,
1757 with a probability relative to the deviation from the desired amount of water/sand/grass
1758 **/
1759
1760 while (--smooth)
1761 {
1762 double Error[undertile_total]; totals[WATER]==0; totals[SAND]==0; totals[GRASS]==0;
1763 for (int p=0; p<Size; ++p)
1764 ++Error[GetCell(p).UnderTile()];
1765
1766 (Error[WATER] /= Size) -= baseWater; Error[WATER] = (Error[WATER]<=0)?0:pow(Error[WATER], 0.125)*4294967296; assert(Error[WATER]<=4294967295);
1767 (Error[SAND ] /= Size) -= baseSand ; Error[SAND ] = (Error[SAND ]<=0)?0:pow(Error[SAND ], 0.125)*4294967296; assert(Error[SAND ]<=4294967295);
1768 (Error[GRASS] /= Size) -= baseGrass; Error[GRASS] = (Error[GRASS]<=0)?0:pow(Error[GRASS], 0.125)*4294967296; assert(Error[GRASS]<=4294967295);
1769
1770 inline bool ConvertSquare(x1, y1) {
1771 const undertile_t t = GetCell(x+x1, y+y1).UnderTile();
1772 if ((t == GetCell(x-x1, y-y1).UnderTile()) && allowed[a]<=syncRand()) { C.UnderTile(a); return true }; return false;
1773 };
1774
1775 for (int y=0; y<h; y++)
1776 for (int x=0; x<w; x++)
1777 if (((syncRand()&1)?ConvertSquare(1, 0):ConvertSquare(0, 1)) ||
1778 ((syncRand()&1)?ConvertSquare(1, 1):ConvertSquare(1, -1)) ||
1779 ((syncRand()&1)?ConvertSquare(2, 0):ConvertSquare(0, -2)) ||
1780 ((syncRand()&1)?ConvertSquare(2, 2):ConvertSquare(2, -2))) {};
1781 }
1782
1783 // Turn water/grass to sand where necessary
1784 for (cell_ypos_t y=0; y<Height; ++y)
1785 for (cell_xpos_t x=0; x<Width; ++x)
1786 GetCell(x, y).MaybeToSand(GetCell(x+1, y), GetCell(x, y+1), GetCell(x+1, y+1));
1787
1788 /**
1789 FIVE: Find suitable places for teams
1790
1791 Place each team in a patch of grass no less than 7 squares wide, and no less than minDistSquare squares from their nearest opponent
1792 Areas with a greater larger patch of grass are preferred, based on (grasswidth * grassheight)
1793
1794 **/
1795
1796 cell_count_t minDistSquare = 0;
1797 for (int p=0; p<Size; ++p)
1798 if (GetCell(p).UnderTile()==GRASS)
1799 ++minDistSquare;
1800 minDistSquare /= nbTeams;
1801 const int squareSize=5+(int)(sqrt((double)minDistSquare)/4.5);
1802 if (verbose)
1803 printf("minDistSquare=%d (%f).\n" "squareSize=%d.\n", minDistSquare, sqrt((double)minDistSquare), squareSize);
1804
1805 if (minDistSquare<=0)
1806 return false;
1807
1808 const int* bootX=descriptor.bootX;
1809 const int* bootY=descriptor.bootY;
1810
1811 //TODO: First pass to find the number of available places.
1812 for (team_ID_t team=0; team<nbTeams; team++)
1813 {
1814 int maxSurface=0;
1815 int maxX=0;
1816 int maxY=0;
1817 for (cell_ypos_t y=0; y<h; y++)
1818 {
1819 int width=0;
1820 int startx=Width-1;
1821 int x=Width;
1822 while (GetCell(startx, y).UnderTile()==GRASS) {++width; --startx};
1823 if (startx==Width-1) startx=0; else ++startx;
1824
1825 for (cell_xpos_t x=0; x<w; x++) {
1826 const undertile_t a = GetCell(x, y).UnderTile();
1827 if (a==GRASS)
1828 ++width;
1829 else {
1830 if (width>7) {
1831 const cell_xpos_t centerx=((x+startx)>>1);
1832 int top=y-1, bot=y+1;
1833 for (top; top<Height && GetCell(centerx, y-top).UnderTile()==GRASS; ++top) {};
1834 for (bot; bot<Height && GetCell(centerx, y+bot).UnderTile()==GRASS; ++bot) {};
1835 const int surface=(top+bot-1)*width;
1836 const int centery=y+(bot-top)/2;
1837 assert(surface>0);
1838
1839 if (surface>maxSurface) {
1840 for (int ti=0; ti<team; ti++)
1841 if (warpDistSquare(centerx, centery, bootX[ti], bootY[ti])<minDistSquare)
1842 goto NEXT;
1843 maxSurface=surface;
1844 maxX=centerx;
1845 maxY=centery;
1846 };
1847 NEXT:
1848 }
1849 width=0;
1850 startx=x;
1851 }
1852 }
1853 }
1854
1855 if (maxSurface<=0)
1856 return false;
1857 bootX[team]=maxX;
1858 bootY[team]=maxY;
1859
1860 // add some green space for the team:
1861 SetUndermapArea(maxX-1, maxY+0, GRASS, 6);
1862 SetUndermapArea(maxX+2, maxY+0, GRASS, squareSize);
1863 SetUndermapArea(maxX+2, maxY+2, GRASS, squareSize);
1864 }
1865
1866 regenerate();
1867
1868 if (verbose)
1869 printf("makeRandomMap::success\n");
1870
1871 /**
1872 For each team,
1873 for each land resource,
1874 for each direction out of up, down, left, right, up-left, up-right, down-left and down-right...
1875 Find the first non-grass square in that direction which is at least 5 squares away, and preceded by at least 3 grass squares (i.e. the first decent-sized patch of grass),
1876 Choose a direction based on the relative weighting the resource gives to distance and weight
1877 Create a group of resources of that type in the preferred direction
1878 For algae, more-or-less as before, except to find the first non-sea resource
1879 **/
1880 int *bootX=descriptor.bootX;
1881 int *bootY=descriptor.bootY;
1882 team_ID_t team = descriptor.nbTeams;
1883 const int limitDistance=(Width+Height)/(team*2);
1884
1885 while (team--) {
1886 int smallestWidth=limitDistance;
1887 resource_t smallestResource;
1888 int smallestDistanceWeight;
1889 int smallestWidthWeight;
1890
1891 bool dirUsed[3, 3] = { false, false, false,
1892 false, true , false,
1893 false, false, false };
1894
1895 void placeLandResource(resource_t res, int distanceWeight, int widthWeight) {
1896 static int amount=descriptor.resource[res];
1897 if (!amount) return; assert(amount>0);
1898
1899 int OffsetX;
1900 int OffsetY;
1901 int maxWidth=0;
1902 int maxDistance=0;
1903
1904 const bool PreferredDirection(const Cell& C, const cell_xoffset_t X, cell_yoffset_t Y) {
1905 if (!dirUsed[X+1, Y+1]) {
1906 cell_length_t width=0;
1907 for (distance=5; distance<limitDistance; distance++)
1908 if GetCell(bootX[team]+X*distance, bootY[team]+Y*distance).isGrass()
1909 ++width;
1910 else if (width>3)
1911 break;
1912 else
1913 width=1;
1914
1915 if (distance*distanceWeight + width*widthWeight > maxDistance*distanceWeight + maxWidth*widthWeight) {
1916 maxDistance=distance;
1917 maxWidth=width;
1918 OffsetX=X;
1919 OffsetY=Y;
1920 }
1921 };
1922 return false;
1923 };
1924
1925 FindAdjacentCell(&PreferredDirection, bootX[team], bootY[team]);
1926
1927 dirUsed[OffsetX+1, OffsetY+1]=true;
1928 if (maxWidth<smallestWidth) {
1929 smallestWidth=maxWidth;
1930 smallestResource=res;
1931 smallestDistanceWeight=distanceWeight;
1932 smallestWidthWeight=widthWeight;
1933 };
1934
1935 maxDistance -= maxWidth/2;
1936
1937 FillAreaWithResource(bootX[team] + maxDistance*OffsetX, bootY[team] + maxDistance*OffsetY, res, amount);
1938 }
1939
1940 placeLandResource(WHEAT, 1, 1);
1941 placeLandResource(WOOD , 1, 1);
1942 placeLandResource(STONE, 1, 1);
1943 placeLandResource(WHEAT, 2, 2);
1944 if (smallestWidth<limitDistance)
1945 placeResaurce(smallestResource, smallestDistanceWeight, smallestWidthWeight);
1946
1947
1948 // There's only one sea resource, so there's no need to make a whole function just to call it once.
1949 static int amount=descriptor.resource[ALGA];
1950 if (amount) {
1951 assert(amount>0);
1952
1953 int OffsetX;
1954 int OffsetY;
1955 int maxWidth=0;
1956 int maxDistance=0;
1957
1958 const bool PreferredDirection(const Cell& C, const cell_xoffset_t X, const cell_yoffset_t Y) {
1959 if (X||Y) {
1960 for (distance=0; distance<2*limitDistance; distance++)
1961 if GetCell(bootX[team]+X*distance, bootY[team]+Y*distance).isWater()
1962 ++width;
1963 else if (width>3)
1964 break;
1965 else
1966 width=1;
1967
1968 if (distance + width < maxDistance + maxWidth) {
1969 maxWidth=width;
1970 maxDistance=distance;
1971 OffsetX=X;
1972 OffsetY=Y;
1973 }
1974 };
1975 return false;
1976 };
1977
1978 FindAdjacentCell(&PreferredDirection, bootX[team], bootY[team]);
1979
1980 maxDistance -= maxWidth/2;
1981
1982 FillAreaWithResource(bootX[team] + maxDistance*OffsetX, bootY[team] + maxDistance*OffsetY, ALGA, amount);
1983 };
1984 }
1985
1986 // smooth resources...
1987 int maxAmount=descriptor.resourch[WOOD];
1988 if (maxAmount < descriptor.resource[WHEAT]) maxAmount = descriptor.resource[WHEAT];
1989 if (maxAmount < descriptor.resource[STONE]) maxAmount = descriptor.resource[STONE];
1990 if (maxAmount < descriptor.resource[ALGA ]) maxAmount = descriptor.resource[ALGA ];
1991
1992 smoothResources(maxAmount*3);
1993
1994 return true;
1995 }
1996
1997 //! Generate several islands, then populate them with resources
1998 bool Map::makeIslandsMap(MapGenerationDescriptor &descriptor)
1999 {
2000 // ONE: fill with water
2001 inline const bool setWater(const Cell& C, const cell_xpos_t, cell_ypos_t) { C.UnderTile(WATER) };
2002 IterateOverArea(setWater);
2003
2004 // TWO: Generate initial islands, each 6x5 squares in size and at least minDistSquare squares apart
2005 int* bootX=descriptor.bootX; // Array of X co-ordinates, one per team
2006 int* bootY=descriptor.bootY; // As above, but Y co-ordinates
2007 int nbIslands=descriptor.nbTeams;
2008
2009 const unsigned int islandsSize=max(8, (int)(((w+h)*descriptor.islandsSize)/(400.0*sqrt((double)descriptor.nbTeams))))
2010 if (islandsSize<8)
2011 islandsSize=8;
2012 int minDistSquare=(w*h)/nbIslands; // Minimum distance between any two islands
2013 //printf("minDistSquare=%d.\n", minDistSquare);
2014
2015 Uint16 c=0;
2016 for (int i=0; i<nbIslands; i++)
2017 {
2018 int x=syncRand()%w;
2019 int y=syncRand()%h;
2020 int j=i+1;
2021 while (j--)
2022 if (warpDistSquare(x, y, bootX[j], bootY[j])<minDistSquare) {
2023 // After 65536 failures, Halve the minimum allowed distance - shouldn't be necessary more than once
2024 if (!++c)
2025 minDistSquare=minDistSquare>>1;
2026
2027 x=syncRand()%w;
2028 y=syncRand()%h;
2029 j=i+1;
2030 }
2031
2032 bootX[i]=x; bootY[i]=y;
2033 const bool setGrass(const Cell& C, const cell_xpos_t, cell_ypos_t) { C.UnderTile(GRASS) };
2034 IterateOverArea(setGrass, x-1, x+5, y, y+5);
2035 }
2036
2037 // THREE: expand islands
2038 for (int s=0; s<islandsSize; s++)
2039 {
2040 inline bool ConvertSquareOR(x1, y1) { if (GetCell(x+x1, y+y1).UnderTile() == GRASS || GetCell(x-x1, y-y1).UnderTile() == GRASS ) { C.UnderTile(GRASS); return true }; return false; };
2041
2042 for (int y=0; y<h; y+=2)
2043 for (int x=0; x<w; x+=2) {
2044 Cell& C = GetCell(x, y);
2045 if (C.UnderTile==GRASS)
2046 continue;
2047
2048 switch (syncRand()&15) {
2049 case 0: if (ConvertSquareOR( 1, 0)) continue else break;
2050 case 1: if (ConvertSquareOR( 0, -1)) continue else break;
2051 case 2: if (ConvertSquareOR(+1, +1)) continue else break;
2052 case 3: if (ConvertSquareOR(+1, -1)) continue else break;
2053 case 4: if (ConvertSquareOR(+2, 0)) continue else break;
2054 case 5: if (ConvertSquareOR( 0, -2)) continue else break;
2055 case 6: if (ConvertSquareOR(+2, +2)) continue else break;
2056 case 7: if (ConvertSquareOR(+2, -2)) continue else break;
2057 default: break;
2058 }
2059 };
2060 for (int y=1; y<h; y+=2)
2061 for (int x=1; x<w; x+=2)
2062 {
2063 Cell& C = GetCell(x, y);
2064 if (umt==GRASS)
2065 continue;
2066
2067 switch (syncRand()&15) {
2068 case 0: if (ConvertSquareOR(+1, 0)) continue else break;
2069 case 1: if (ConvertSquareOR( 0, -1)) continue else break;
2070 case 2: if (ConvertSquareOR(+1, +1)) continue else break;
2071 case 3: if (ConvertSquareOR(+1, -1)) continue else break;
2072 case 4: if (ConvertSquareOR(+2, 0)) continue else break;
2073 case 5: if (ConvertSquareOR( 0, -2)) continue else break;
2074 case 6: if (ConvertSquareOR(+2, +2)) continue else break;
2075 case 7: if (ConvertSquareOR(+2, -2)) continue else break;
2076 default:
2077 break;
2078 }
2079 }
2080 }
2081
2082 // FOUR: avoid too much sand. Let's smooth
2083 for (int s=0; s<2; s++)
2084 for (int y=0; y<h; y++)
2085 for (int x=0; x<w; x++)
2086 {
2087 inline bool ConvertSquareAND(x1, y1) { if (GetCell(x+x1, y+y1).UnderTile() == GRASS && GetCell(x-x1, y-y1).UnderTile() == GRASS ) { C.UnderTile(GRASS); return true }; return false; };
2088 if (ConvertSquareAND(+1, 0)) continue;
2089 if (ConvertSquareAND( 0, -1)) continue;
2090 if (ConvertSquareAND(+1, +1)) continue;
2091 if (ConvertSquareAND(+1, -1)) continue;
2092 }
2093
2094 // Put sand at the boundaries of water and grass
2095 for (cell_ypos_t y=0; y<Height; ++y)
2096 for (cell_xpos_t x=0; x<Width; ++x)
2097 GetCell(x, y).MaybeToSand(GetCell(x+1, y), GetCell(x, y+1), GetCell(x+1, y+1));
2098
2099 // Five, add some sand
2100 for (int s=0; s<descriptor.beach; s++)
2101 for (int dy=0; dy<4; dy++)
2102 for (int dx=0; dx<4; dx++)
2103 for (int y=dy; y<h; y+=4)
2104 for (int x=dx; x<w; x+=4)
2105 {
2106 // Returns true if one of (x1, x2) is water, the other sand. "^" is a bitwise XOR - if you don't know how get works, don't ask, it's a binary thing
2107 inline bool ConvertSquareSandWater(x1, y1) { if ((GetCell(x+x1, y+y1).UnderTile() ^ GetCell(x-x1, y-y1).UnderTile()) == GRASS) { C.UnderTile(SAND); return true }; return false; };
2108 inline bool ConvertSquareSand(x1, y1) { if (GetCell(x+x1, y+y1).UnderTile() == SAND && GetCell(x-x1, y-y1).UnderTile() == SAND ) { C.UnderTile(SAND); return true }; return false; };
2109
2110 int a, b;
2111 switch (syncRand()&7)
2112 {
2113 case 0:if (ConvertSquareSandWater(+1, 0)) continue else break;
2114 case 1:if (ConvertSquareSandWater( 0, -1)) continue else break;
2115 case 2:if (ConvertSquareSandWater(+1, +1)) continue else break;
2116 case 3:if (ConvertSquareSandWater(+1, -1)) continue else break;
2117
2118 case 4:if (ConvertSquareSand(+1, 0)) continue else break;
2119 case 5:if (ConvertSquareSand( 0, -1)) continue else break;
2120 case 6:if (ConvertSquareSand(+1, +1)) continue else break;
2121 case 7:if (ConvertSquareSand(+1, -1)) continue else break;
2122 }
2123 }
2124
2125
2126 regenerate();
2127
2128 /**
2129 Six: generate resources...
2130
2131 Creates groups of resources on each island (given one island per team).
2132 A group of resources is a square of length equal islandsSize/4 of the island, minus some amount specified for each resource type
2133 In theory, the modifiers are: wood==-2, wheat==0, stone==-3, least==-3, alga==0. For some reason, this isn't what you find if you actually make a map
2134 This way of calculating sizes is probably a bug: the code looks like it should be setting the size of a group as descriptor.resource[TYPE]
2135
2136 For each island (given one island per team), looking in one direction from the centre...
2137 put a wood forest roughly halfway towards the top of the island
2138 put a wheat field roughly halfway towards the left of the island
2139 put a stone pile roughly halfway towards the bottom of the island
2140 For the resource with the smallest length, put another group of that resource roughly halfway towards the bottom-right of the island
2141 Put an algae field roughly half as far again past the right edge of the island
2142
2143 There is what appears to be a bug in this algorithm: The amount of resources
2144 **/
2145
2146 const unsigned int smoothResources=islandsSize/4;
2147 // let's add resources...
2148 for (int s=0; s<descriptor.nbTeams; s++)
2149 {
2150 int distance, length;
2151 int smallestLength;
2152 int smallestResource;
2153
2154 //WOOD
2155 for (distance=0; d<islandsSize; ++distance)
2156 if (!isGrass(bootX[s], bootY[s]-distance))
2157 break;
2158 //length=descriptor.resource[WOOD]; // Is this a bug? Length is set then immediately reset
2159 if (length=d-smoothResources-2 < 1) length = 1;
2160 //if (length>0) // Is this a bug? Length is set to at least 1 then checked for positivity
2161 FillAreaWithResource(bootX[s], bootY[s]-distance+1+length/2, WOOD, length);
2162 smallestLength=length;
2163 smallestResource=WOOD;
2164
2165 //WHEAT
2166 for (distance=0; d<islandsSize; ++distance)
2167 if (!isGrass(bootX[s]-distance, bootY[s]))
2168 break;
2169 //length=descriptor.resource[WHEAT];
2170 if (length=d-smoothResources-0 < 1) length=1;
2171 //if (length>0)
2172 FillAreaWithResource(bootX[s]-distance+1+length/2, bootY[s], WHEAT, length);
2173 if (length<smallestLength) {
2174 smallestLength=length;
2175 smallestResource=WHEAT;
2176 }
2177
2178 //STONE
2179 for (distance=0; d<islandsSize; ++distance)
2180 if (!isGrass(bootX[s], bootY[s]+distance))
2181 break;
2182 //length=descriptor.resource[STONE];
2183 if (length=d-smoothResources-3 < 1) length=1;
2184 //if (length>0)
2185 FillAreaWithResource(bootX[s], bootY[s]+distance-1-length/2, STONE, length);
2186 if (length<smallestLength)
2187 {
2188 smallestLength=length;
2189 smallestResource=STONE;
2190 }
2191
2192
2193 //LEAST (make a second group for the resource with the least length)
2194 for (distance=0; d<islandsSize; ++distance)
2195 if (!isGrass(bootX[s]+distance, bootY[s]+distance))
2196 break;
2197 //length=descriptor.resource[smallestResource];
2198 if (length=d-smoothResources-3 < 1) length=1;
2199 //if (length>0)
2200 FillAreaWithResource(bootX[s]+distance-1-length/2, bootY[s]+distance-1-length/2, smallestResource, length);
2201
2202 //ALGA
2203 for (distance=0; d<2*islandsSize; ++distance)
2204 if (isWater(bootX[s]+distance, bootY[s]))
2205 break;
2206 //length=descriptor.resource[ALGA];
2207 if ((length=smoothResources) > 0)
2208 FillAreaWithResource(bootX[s]+distance+smoothResources-1+length/2, bootY[s], ALGA, length);
2209 }
2210
2211 // smooth resources...
2212 smoothResources(smoothResources*2);
2213
2214 return true;
2215 }

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26