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

Contents of /glob2/src/Map.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.137.2.1 - (show annotations) (download)
Wed Jul 6 23:06:48 2005 UTC (18 years, 10 months ago) by andrew_sayers
Changes since 1.137: +562 -488 lines
File MIME type: text/plain
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 /*! \file Map.h
21 \brief The class (and sub-classes) that define the squares making up the map itself. It is made up of 32x32 pixel cells
22
23 Map can be called as:
24 Map[x, y] to get the cell at (x, y), or
25 Map(x, y) to get the sector at (x, y)
26
27 By extension, you can do:
28 Map[x, y][TeamNumber] to get the TeamCellData at a given point
29 Map[x, y][TeamNumber][ElevationNumber] to get the given type of elevation
30
31 All functions are wrap-safe, unless otherwise specified.
32 */
33
34 #ifndef __MAP_H
35 #define __MAP_H
36
37 #include <list>
38 #include <assert.h>
39
40 #include "Building.h"
41 #include "Sector.h"
42 #include "Team.h"
43 #include "TerrainType.h"
44 #include "BitArray.h"
45
46 class Unit;
47
48 class Map;
49 class Game;
50 class MapGenerationDescriptor;
51 class SessionGame;
52
53 //! Since water and grass clash but sand doesn't it's useful that bitwise ANDing any two resources tells you whether there's a clash
54 typedef undertile_t enum { NO_RESOURCE=0, WATER=1, GRASS=2, SAND=3 };
55 const int undertile_total = 4;
56 typedef terrain_t Uint8;
57 typedef terrain_variant_t Uint8;
58 const terrain_variant_t terrain_variant_t_max = 255;
59
60 typedef cell_xpos_t int;
61 typedef cell_ypos_t int;
62 typedef cell_pos_t unsigned int;
63 typedef cell_width_t unsigned int;
64 typedef cell_height_t unsigned int;
65 typedef cell_size_t unsigned int;
66 typedef cell_length_t unsigned int;
67
68
69 typedef sector_xpos_t int;
70 typedef sector_ypos_t int;
71 typedef sector_width_t unsigned int;
72 typedef sector_height_t unsigned int;
73 typedef sector_size_t unsigned int;
74
75 typedef pixel_xpos_t int;
76 typedef pixel_ypos_t int;
77 typedef pixel_width_t unsigned int;
78 typedef pixel_height_t unsigned int;
79 typedef pixel_size_t unsigned int;
80
81 typedef team_ID_t unsigned int;
82 typedef team_count_t unsigned int;
83
84 typedef elevation_t Uint8;
85 typedef elevation_sum_t Uint32; // Can hold the sum of two elevations
86 typedef elevation_offset_t Sint8;
87 typedef elevation_max 255;
88 typedef elevation_min 3; // Least interesting elevation
89 typedef elevation_index_t enum { FORBIDDEN_SWIM=0; FORBIDDEN_NOSWIM=1 GUARD_SWIM=2; GUARD_NOSWIM=3; RESOURCE_SWIM=4; RESOURCE_NOSWIM=RESOURCE_SWIM + MAX_NB_RESOURCES };
90 static const elevation_index_t TotalElevations = RESOURCE_NOSWIM + MAX_NB_RESOURCES;
91
92 typedef resource_enum_t enum { WOOD=0; WHEAT=1; PAPYRUS=2; STONE=3; ALGA=4; NO_RES_TYPE=0xFF };
93 typedef resource_t Uint8;
94 const resource_t resource_t_max = 255;
95 typedef resource_variety_t Uint8;
96 const resource_t resource_variety_t_max = 255;
97 typedef resource_amount_t Uint8;
98 const resource_t resource_amount_t_max = 255;
99 typedef resource_animation_t Uint8;
100 const resource_t resource_animation_t_max = 255;
101 const resource_t resource_t_count = 5;
102 const resource_t resource_t_max = 8;
103 const resource_t resource_t_absolute_max = 15;
104 const resource_t happiness_base = resource_t_count;
105 const resource_t happiness_count = resource_t_max - resource_t_count;
106
107 //! This should go in Team.h or somewhere more appropriate eventually
108 class TeamCellData : friend Map {
109 private:
110 Forbidden : 1;
111 Guarded : 1;
112 Cleared : 1;
113 Discovered : 1;
114 FogOfWarA : 1;
115 FogOfWarB : 1;
116
117 elevation_t Elevations[TotalElevations];
118
119 public:
120
121 const elevation_t& GetElevation(const elevation_index_t g) const { assert(g<TotalElevations); return Elevations[g] };
122 const elevation_t& operator[] (const elevation_index_t g) const { return GetElevation(g) };
123
124 const elevation_t ResourceAvailable(const resource_enum_t R, const bool CanSwim) const
125 { return Elevations[(CanSwim?RESOURCE_SWIM:RESOURCE_NOSWIM) + R]>1?Elevations[(CanSwim?RESOURCE_SWIM:RESOURCE_NOSWIM) + R]:0 };
126
127 protected:
128
129 TeamCellData() : Forbidden(), Guarded(), Cleared(), Discovered(), FogOfWarA(), FogOfWarB() { for (elevation_index_t n=0; n<TotalElevations; ++n) Elevations[n] = 0 };
130 TeamCellData(const TeamCellData& M) : Forbidden(M.Forbidden), Guarded(M.Guarded), Cleared(M.Gleared), Discovered(M.Discovered), FogOfWarA(M.FogOfWarA), FogOfWarB(M.FogOfWarB)
131 { for (elevation_index_t n=0; n<TotalElevations; ++n) Elevations[n] = M.Elevations[n] };
132 TeamCellData(const GAGCore::InputStream *stream, const SessionGame *const sessionGame, const Game *const game=NULL);
133 void save(GAGCore::OutputStream *stream);
134
135 const bool Forbidden() const { return Forbidden; };
136 const bool Guarded() const { return Guarded; };
137 const bool Cleared() const { return Cleared; };
138 const bool Discovered() const { return Discovered; };
139 const bool Fog(const bool which) const { return which?FogOfWarA:FogOfWarB; };
140
141 const bool Forbidden(const bool F) { return Forbidden = F; };
142 const bool Guarded(const bool G) { return Guarded = G; };
143 const bool Cleared(const bool C) { return Cleared = C; };
144 const bool Discovered(const bool D) { return Discovered = D; };
145 const bool Fog(const bool which, const bool F) { return which?FogOfWarA=F:FogOfWarB=F };
146
147 const bool FlipForbidden() { return Forbidden = !Forbidden; };
148 const bool FlipGuarded() { return Guarded = !Guarded; };
149 const bool FlipCleared() { return Cleared = !Cleared; };
150 const bool FlipDiscovered() { return Discovered = !Discovered; };
151 const bool Fog(const bool which) { return which?FogOfWarA = !FogOfWarA:FogOfWarB = !FogOfWarB; };
152
153 };
154
155 template<cell_width_t CellWidth, cell_height_t CellHeight, bool verbose> class Map {
156
157 public:
158 /** The Map::Cell class defines all information about a single 32x32 pixel piece of the map
159 That includes what terrain, underterrain, resources, elevations, folbidden/guarded/clearing/etc. state, and the ground unit/air unit/building on the tile.
160 **/
161 class Cell {
162
163 private:
164 // Terrain is based on the underterrain types for the tiles immediately below-right, below-left, above-left, and above-right the current tile
165 // Underterrain types are not stored explicitly - each cell is considered to hold the canonical version of its top-left subtile
166 terrain_t Terrain;
167 terrain_variant_t TerrainVariant;
168
169 // Resources
170 resource_t ResourceType;
171 resource_amount_t ResourceAmount;
172 resource_variety_t ResourceVariety;
173 resource_animation_t ResourceAnimation;
174
175 Unit* groundUnit;
176 Unit* AirUnit;
177 Building* Building;
178
179 std::Vector<TeamCellData> TeamData;
180
181 public:
182
183 Cell(const std::Vector<TeamCellData>::size_type Teams=0, terrain_t T=WATER,
184 const resource_t RT=NO_RES_TYPE, const resource_amount_t RAM=resource_amount_max, const resource_variety_t RV=resource_variety_max, const resource_animation_t RAN=resource_animation_max)
185 : Terrain(T), TerrainSubType(SyncRand%(terrain_variant_max+1)), Resource(), GroundUnit(), AirUnit(), Building(), TeamData(Teams),
186 ResourceType(RT), ResourceVariety(RV), ResourceAmount(RAM), ResourceAnimation(RAN) {};
187 Cell(const Cell& M) : UnderTile(M.UnderTile), TerrainSubType(M.UnderTile), TerrainType(M.TerrainType), Resource(M.Resource),
188 GroundUnit(M.GroundUnit), AirUnit(M.AirUnit), Building(M.Building), TeamData(M.TeamData) {};
189 Cell(const GAGCore::InputStream *stream, const SessionGame *const sessionGame, const Game *const game=NULL);
190 void save(GAGCore::OutputStream *stream);
191
192 //! Simple resource functions
193 const bool HasResource() const { return ResourceType != NO_RES_TYPE };
194 const resource_t ResourceType() const { return ResourceType };
195 const resource_amount_t ResourceAmount() const { return ResourceAmount };
196 const resource_variety_t ResourceVariety() const { return ResourceVariety };
197 const resource_animation_t ResourceAnimation() const { return ResourceAnimation };
198 protected:
199 void incResource() { ++ResourceAmount };
200 void decResource() { --ResourceAmount };
201 public:
202 Uint32 Resource() { return animation | (amount<<8) | (variety<<16) | (type<<24); }
203 void Resource(const resource_t RT, const resource_amount_t RAM, const resource_variety_t RV=resource_variety_max, const resource_animation_t RAN=resource_animation_max) { if (!GroundUnit && Resource::Compatible(r, Terrain)) { ResourceType=RT; ResourceAmount=RAM; ResourceAmount=0; ResourceVariety=RV; ResourceAnimation=RAN };
204
205 //! Simple terrain functions
206 const terrain_t UnderTileBR(const undertile_t br) { return (Terrain &= 0x3F) |= (br << 6) };
207 const terrain_t UnderTileBL(const undertile_t bl) { return (Terrain &= 0xCF) |= (bl << 4) };
208 const terrain_t UnderTileTR(const undertile_t tr) { return (Terrain &= 0xF3) |= (tr << 2) };
209 const terrain_t UnderTileTL(const undertile_t tl) { return (Terrain &= 0xFC) |= (tl << 0); };
210 const terrain_t UnderTile (const undertile_t t) { return UnderTileTL(t); }; // top-left undertile
211 const terrain_t UnderTile() const { return Terrain & 0x03; }; // top-left undertile
212
213 const terrain_t Terrain(const undertile_t br, const undertile_t bl, const undertile_t tr) { Terrain = (br << 6) | (bl << 4) | (tr << 2) | UnderTile() };
214 const terrain_t Terrain(const Cell& br , const Cell& bl , const Cell& tr ) { Terrain = (br.Terrain << 6) | (bl.UnderTile() << 4) | (tr.UnderTile() << 2) | UnderTile() };
215 const terrain_t Terrain(const terrain_t T) { return Terrain = T; };
216 const terrain_t Terrain() const { return Terrain };
217
218 const terrain_variant_t TerrainVariant(const terrain_variant_t V) { return TerrainVariant = V };
219 const terrain_variant_t TerrainVariant() { return TerrainVariant };
220
221 //! Complex terrain functions
222
223 //! Is the undertile of this cell allowed next to something? (water is not allowed next to grass)
224 const bool AllowedNextTo(const undertile_t t) const { return Undertile() & t };
225 const bool AllowedNextTo(const Cell& c) const { return Undertile() & c.UnderTile() };
226 void MaybeToSand(const undertile_t t) { if (!AllowedNextTo(t)) Undertile(SAND) };
227 void MaybeToSand(const Cell& c) { if (!AllowedNextTo(c.UnderTile())) Undertile(SAND) };
228 void MaybeToSand(const Cell& c1, const Cell& c2, const Cell& c3)
229 { if !(AllowedNextTo(c1) && AllowedNextTo(c2) && AllowedNextTo(c3) && AllowedNextTo(c3)) Undertile(SAND) };
230 void MaybeToSand(const undertile_t t1, const undertile_t t2, const undertile_t t3)
231 { if !(AllowedNextTo(t1) && AllowedNextTo(t2) && AllowedNextTo(t3) && AllowedNextTo(t3)) Undertile(SAND) };
232 //! Constants defining the "proper" terrain types, where all the surrounding undertiles are of the same type
233 static const terrain_t Water = (WATER << 6) | (WATER << 4) | (WATER << 2 ) | WATER;
234 static const terrain_t Sand = (SAND << 6) | (SAND << 4) | (SAND << 2 ) | SAND ;
235 static const terrain_t Grass = (GRASS << 6) | (GRASS << 4) | (GRASS << 2 ) | GRASS;
236 //! Check "Proper" types of terrain
237 const bool isWater() const { return !HasResource() && Terrain == Water; };
238 const bool isSand () const { return !HasResource() && Terrain == Sand ; };
239 const bool isGrass() const { return !HasResource() && Terrain == Grass; };
240 //! do any of the surrounding undertiles disagree?
241 const bool isTransitional() const { return Terrain != Water && Terrain != Sand && Terrain != Grass };
242 //! Is at least one of the surrounding undertiles of the given type?
243 const bool isWatery() const { return (Terrain&0xC0 == WATER<<6) || (Terrain&0x30 == WATER<<4) || (Terrain&0x0C == WATER<<2) || (Terrain&0x03 == WATER<<0) };
244 const bool isSandy () const { return (Terrain&0xC0 == SAND <<6) || (Terrain&0x30 == SAND <<4) || (Terrain&0x0C == SAND <<2) || (Terrain&0x03 == SAND <<0) };
245 const bool isGrassy() const { return (Terrain&0xC0 == GRASS<<6) || (Terrain&0x30 == GRASS<<4) || (Terrain&0x0C == GRASS<<2) || (Terrain&0x03 == GRASS<<0) };
246 //! Which is the most frequent undertile type?
247 const bool isMostlyWater() {
248 int totals[undertile_total]; totals[WATER]==0; totals[SAND]==0; totals[GRASS]==0;
249 ++totals[UnderTileBR]; ++totals[UnderTileBL]; ++totals[UnderTileTR]; ++totals[UnderTileTL];
250 return totals[WATER] > totals[SAND]; // Note: water can't border on grass
251 };
252 const bool isMostlySand() {
253 int totals[undertile_total]; totals[WATER]==0; totals[SAND]==0; totals[GRASS]==0;
254 ++totals[UnderTileBR]; ++totals[UnderTileBL]; ++totals[UnderTileTR]; ++totals[UnderTileTL];
255 return totals[SAND] > totals[WATER] && totals[SAND] > totals[GRASS];
256 };
257 const bool isMostlyGrass() {
258 int totals[undertile_total]; totals[WATER]==0; totals[SAND]==0; totals[GRASS]==0;
259 ++totals[UnderTileBR]; ++totals[UnderTileBL]; ++totals[UnderTileTR]; ++totals[UnderTileTL];
260 return totals[GRASS] > totals[SAND]; // Note: water can't border on grass
261 };
262 const terrain_t isMostly() {
263 int totals[undertile_total]; totals[WATER]==0; totals[SAND]==0; totals[GRASS]==0;
264 ++totals[UnderTileBR]; ++totals[UnderTileBL]; ++totals[UnderTileTR]; ++totals[UnderTileTL];
265 if (totals[WATER] > totals[SAND ]) return WATER;
266 if (totals[GRASS] > totals[SAND ]) return GRASS;
267 if (totals[SAND ] > totals[WATER] && totals[SAND ] > totals[GRASS]) return SAND;
268 return NO_RESOURCE;
269 };
270
271 // Accessing other members
272 const Unit* groundUnit() const { return groundUnit };
273 const Unit* airUnit() const { return airUnit };
274 const Building* Building() const { return Building };
275
276 const Unit* groundUnit(Unit* g) { return groundUnit = g };
277 const Unit* airUnit(Unit* a) { return airUnit = a };
278
279 const Building *const Building() const { return Building };
280 const Building *const Building(Building* b) { return Building = b };
281
282 const TeamCellData& teamCellData(team_ID_t Team) const { assert(Team<Teams); return TeamCellData[Team]; };
283 const TeamCellData& operator[](team_ID_t Team) const { return teamCellData(Team); };
284
285 bool isResourceAllowed(const resource_enum_t type) { return UnderTile()==globalContainer->resourcesTypes.get(type)->terrain };
286
287 //! Return true if unit can go to position (x,y)
288 bool isFreeForGroundUnit(bool canSwim, team_ID_t Team) const
289 { return !(Building || groundUnit || Resource.hasResource || TeamData[Team].Forbidden()) && (canSwim || !isWater); };
290 bool isFreeForGroundUnitNoForbidden(bool canSwim) const
291 { return !(Building || groundUnit || Resource.hasResource) && (canSwim || !isWater); };
292 //! i.e. It's free if you don't count other ground units
293 bool isFreeForGroundUnitNoGroundUnits(bool canSwim, team_ID_t Team) const
294 { return !(Building || Resource.hasResource || TeamData[Team].Forbidden()) && (canSwim || !isWater); };
295
296 bool isFreeForAirUnit() { return airUnit; };
297 bool isFreeForBuilding() { return !(Building || GroundUnit || Resource.hasResource) && isGrass() }
298 bool isFreeForBuildingNoGroundUnits() { return !(Building || Resource.hasResource) && isGrass() }
299
300 bool checkSum(Uint32& cs) {
301 for (TeamValue P=0; P<Teams; ++P) { TeamData[P].checkSum(cs) };
302 cs += (Terrain<<4) + TerrainSubType + Building->GID + resource.getUint32() + (groundUnit?groundUnit->GID:0) + (airUnit?airUnit->GID:0);
303 cs = (cs<<1)|(cs>>31);
304 };
305 };
306
307 //! Basic lengths and widths
308 static const sector_width_t SectorWidth = Width / 16;
309 static const sector_height_t SectorHeight = CellHeight / 16;
310 static const sector_size_t SectorSize = SectorWidth * SectorHeight;
311 static const cell_size_t CellSize = CellWidth * CellHeight;
312
313 //! Conversion functions
314 static const pixel_xpos_t ToPixelXpos(const cell_xpos_t X) { return X * 32 };
315 static const pixel_ypos_t ToPixelYPos(const cell_ypos_t Y) { return Y * 32 };
316 static const pixel_xpos_t ToDisplayableXpos(cell_xpos_t X, const cell_xpos_t ViewportX) { return (X -= viewportX)>(CellWidth /2)?X-CellWidth :X };
317 static const pixel_ypos_t ToDisplayableYpos(cell_ypos_t Y, const cell_ypos_t ViewportY) { return (Y -= viewportY)>(CellHeight/2)?Y-CellHeight:Y };
318
319 static const cell_xpos_t ToXposAligned (const pixel_xpos_t X, const cell_xpos_t ViewportX) { return ((X>>5) +ViewportX) % CellWidth };
320 static const cell_ypos_t ToYposAligned (const pixel_ypos_t Y, const cell_ypos_t ViewportY) { return ((Y>>5) +ViewportY) % CellHeight };
321 static const cell_xpos_t ToXposUnaligned(const pixel_xpos_t X, const cell_xpos_t ViewportX) { return (((X+16)>>5) +ViewportX) % CellWidth };
322 static const cell_ypos_t ToYposUnaligned(const pixel_ypos_t Y, const cell_ypos_t ViewportY) { return (((X+16)Y>>5)+ViewportY) % CellHeight };
323
324 static const cell_xpos_t ToBuildingXpos(const pixel_xpos_t X, const pixel_width_t W, const cell_xpos_t ViewportX) { return (((X + (W&1)?0:16) >> 5) + ViewportX) % Xpos ; };
325 static const cell_ypos_t ToBuildingYpos(const pixel_ypos_t Y, const pixel_height_t H, const cell_ypos_t ViewportY) { return (((Y + (H&1)?0:16) >> 5) + ViewportY) % Ypos; };
326
327 static const cell_xpos_t ToCursorXpos(const pixel_xpos_t X, const pixel_Xpos_t W, const cell_xpos_t ViewportX) { return ToDisplayableXpos(X, ViewportX) + W*16; };
328 static const cell_ypos_t ToCursorYpos(const pixel_ypos_t Y, const pixel_Ypos_t H, const cell_ypos_t ViewportY) { return ToDisplayableYpos(Y, ViewportY) + H*16; };
329
330 //! Information about grid positions
331 static const cell_length_t const warpDistSquare(cell_xpos_t X1, cell_ypos_t Y1, const cell_xpos_t X2, const cell_ypos_t Y2) { //! The distance between (px, py) and (qx, qy), warp-safe, but not rooted.
332 return ((X1 = abs(X1-X2) % CellWidth )>(CellWidth /2)?(X1 = CellWidth - X1) * X1 : X1*X1)
333 +
334 ((Y1 = abs(Y1-Y2) % CellHeight)>(CellHeight/2)?(Y1 = CellHeight - Y1) * Y1 : Y1*Y1);
335 };
336 static const cell_length_t const warpDistMax(cell_xpos_t X1, cell_ypos_t Y1, const cell_xpos_t X2, const cell_ypos_t Y2) { //! The max distance on x or y axis, between (px, py) and (qx, qy), warp-safe.
337 return ((X1 = abs(X1-X2) % CellWidth )>(CellWidth /2)?X1 = abs(CellWidth - X1) : X1)
338 >
339 ((Y1 = abs(Y1-Y2) % CellHeight)>(CellHeight/2)?Y1 = abs(CellHeight - Y1) : Y1)
340 ?X1:Y1;
341 };
342 static const bool const isInLocalElevation(const cell_xpos_t uX, const cell_ypos_t uY, const cell_xpos_t bX, const cell_ypos_t bY) { //! Return true if the unit @(ux, uy) is close enough to building @(bx, by).
343 cell_xpos_t dX = abs(uX-bX) % CellWidth;
344 cell_ypos_t dY = abs(uY-bY) % CellHeight;
345 if ((dX>(CellWidth /2)?dX = abs(CellWidth - dX) : dX)
346 >
347 (dY>(CellHeight/2)?dY = abs(CellWidth - dY) : dY))
348 return (dX==15)?((bX + 15) % Width) == (uX % Width):dX<15;
349 else if (dX < dY)
350 return (dY==15)?((bY + 15) % Width) == (uY % Width):dY<15;
351 else
352 return (((bX + 15) % Width) == (uX % Width)) && (((bY + 15) % Width) == (uY % Width));
353 };
354
355 private:
356 Cell Cells[CellWidth, CellHeight];
357 Sector Sectors[SectorWidth * SectorHeight];
358 FILE *logFile;
359 team_count_t MaxTeams; // The highest number of teams that have been seen
360
361 //! Elevations to be dirtied - note that individual resources can be dirtied, or the whole lot can be dirtied at once
362 bool DirtyResource[Teams][MAX_NB_RESOURCES];
363 bool DirtyResources[Teams];
364 bool DirtyForbidden[Teams];
365 bool DirtyGuarded[Teams];
366 bool DirtyBuildings;
367
368 bool FogOfWarAB;
369
370 // computationals pathfinding statistics:
371 int resourceAvailableCount[16][MAX_RESOURCES];
372 int resourceAvailableCountSuccess[16][MAX_RESOURCES];
373 int resourceAvailableCountFailure[16][MAX_RESOURCES];
374
375 // Profiling variables - used to show how much each function is called, and what it tends to return
376 int pathToResourceCountTot;
377 int pathToResourceCountSuccess;
378 int pathToResourceCountFailure;
379
380 int localResourcesUpdateCount;
381
382 int pathfindLocalResourceCount;
383 int pathfindLocalResourceCountWait;
384 int pathfindLocalResourceCountSuccessBase;
385 int pathfindLocalResourceCountSuccessLocked;
386 int pathfindLocalResourceCountSuccessUpdate;
387 int pathfindLocalResourceCountSuccessUpdateLocked;
388 int pathfindLocalResourceCountFailureUnusable;
389 int pathfindLocalResourceCountFailureNone;
390 int pathfindLocalResourceCountFailureBad;
391
392 int pathToBuildingCountTot;
393
394 int pathToBuildingCountClose;
395 int pathToBuildingCountCloseSuccessStand;
396 int pathToBuildingCountCloseSuccessBase;
397 int pathToBuildingCountCloseSuccessUpdated;
398 int pathToBuildingCountCloseFailureLocked;
399 int pathToBuildingCountCloseFailureEnd;
400
401 int pathToBuildingCountIsFar;
402 int pathToBuildingCountFar;
403 int pathToBuildingCountFarIsNew;
404 int pathToBuildingCountFarOldSuccess;
405 int pathToBuildingCountFarOldFailureLocked;
406 int pathToBuildingCountFarOldFailureBad;
407 int pathToBuildingCountFarOldFailureRepeat;
408 int pathToBuildingCountFarOldFailureUnusable;
409 int pathToBuildingCountFarUpdateSuccess;
410 int pathToBuildingCountFarUpdateFailureLocked;
411 int pathToBuildingCountFarUpdateFailureVirtual;
412 int pathToBuildingCountFarUpdateFailureBad;
413
414 int localBuildingElevationUpdate;
415 int localBuildingElevationUpdateLocked;
416 int globalBuildingElevationUpdate;
417 int globalBuildingElevationUpdateLocked;
418
419 int buildingAvailableCountTot;
420
421 int buildingAvailableCountClose;
422 int buildingAvailableCountCloseSuccessFast;
423 int buildingAvailableCountCloseSuccessAround;
424 int buildingAvailableCountCloseSuccessUpdate;
425 int buildingAvailableCountCloseSuccessUpdateAround;
426 int buildingAvailableCountCloseFailureLocked;
427 int buildingAvailableCountCloseFailureEnd;
428
429 int buildingAvailableCountIsFar;
430 int buildingAvailableCountFar;
431 int buildingAvailableCountFarNew;
432 int buildingAvailableCountFarNewSuccessFast;
433 int buildingAvailableCountFarNewSuccessClosely;
434 int buildingAvailableCountFarNewFailureLocked;
435 int buildingAvailableCountFarNewFailureVirtual;
436 int buildingAvailableCountFarNewFailureEnd;
437 int buildingAvailableCountFarOld;
438 int buildingAvailableCountFarOldSuccessFast;
439 int buildingAvailableCountFarOldSuccessAround;
440 int buildingAvailableCountFarOldFailureLocked;
441 int buildingAvailableCountFarOldFailureEnd;
442
443 int pathfindForbiddenCount;
444 int pathfindForbiddenCountSuccess;
445 int pathfindForbiddenCountFailure;
446
447 //Used for scheduling computation time.
448 bool elevationUpdated[Teams][MAX_NB_RESOURCES][2];
449
450 public:
451 //! Create a new map
452 Map(team_count_t Teams=0, terrain_t T = WATER);
453 //! Copy another map
454 Map(const Map<CellWidth, CellHeight>& M);
455 //! Map destructor
456 ~Map(void);
457
458 //! Load a map from a stream and relink with associated game
459 bool load(const GAGCore::InputStream *stream, const SessionGame *const sessionGame, const Game *const game=0)
460 //! Save a map
461 void save(GAGCore::OutputStream *stream);
462
463 //! Map generation functions
464 bool makeRandomMap(MapGenerationDescriptor &descriptor);
465 void addResourcesRandomMap(MapGenerationDescriptor &descriptor);
466 bool makeIslandsMap(MapGenerationDescriptor &descriptor);
467 void addResourcesIslandsMap(MapGenerationDescriptor &descriptor);
468
469 //! Get/set values
470 const Cell& GetCell (const cell_xpos_t x, const cell_ypos_t y) const { y += x / CellWidth; return Cells[x % CellWidth, y % CellHeight] }; // If X overruns, we go onto the next line
471 const Cell& operator[](const cell_xpos_t x, const cell_ypos_t y) const { return GetCell(x, y) };
472 const Cell& GetCell (const cell_pos_t p) const { return Cells[p % CellWidth, (p / Width) % cellHeight] };
473 const Cell& operator[](const cell_pos_t p) const { return GetCell(p) };
474 const Cell& GetCell (const Unit& U) const { return Cells[U.posX % CellWidth, U.posY % CellHeight] };
475 const Cell& operator[](const Unit& U) const { return GetCell(U) };
476
477 void newBullet(const sector_xpos_t x, const sector_ypos_t y, Sint32 px, Sint32 py, Sint32 speedX, Sint32 speedY, Sint32 ticksLeft, Sint32 shootDamage, Sint32 targetX, Sint32 targetY, Sint32 revealX, Sint32 revealY, Sint32 revealW, Sint32 revealH) {
478 Sectors[wSector*((y%Width)>>4)+((x%Width)>>4)].bullets.push_front(new Bullet(px, py, speedX, speedY, ticksLeft, shootDamage, targetX, targetY, revealX, revealY, revealW, revealH));
479 };
480 std::list<Bullet*>::const_iterator GetBullets(sector_pos_t i) { return Sectors[i].bullets.begin() };
481 std::list<Bullet*>::const_iterator GetBulletsEnd(sector_pos_t i) { return Sectors[i].explosions.begin() };
482 std::list<BulletExplosion*>::const_iterator GetExplosions(sector_pos_t i) { return Sectors[i].bullets.begin() };
483 std::list<BulletExplosion*>::const_iterator GetExplosionsEnd(sector_pos_t i) { return Sectors[i].explosions.begin() };
484
485 const Cell& GetAdjacentCell(const cell_xpos_t x, const cell_ypos_t y) const { return Cells[(x - 1 + (syncRand()&3)) % CellWidth, (y - 1 + (syncRand()&3)) % CellHeight] };
486
487 void RemoveTeam() {}; // In the current implementation, we don't need to do anything when a team is removed
488 void Map::addTeam(const team_length_t NewMaximum);
489
490
491 //! Call the specified function on each of a rectangle of cells, returning if the function returns false (returns true/false)
492 typedef const bool (*CellIterator)(const Cell&, const cell_xpos_t, cell_ypos_t);
493 bool IterateOverArea(const CellIterator& f, cell_xpos_t X=0, const cell_xpos_t XMax=Width-1, const cell_ypos_t Y=0, const cell_ypos_t YMax=Height-1) const
494 {
495 cell_xpos_t XStart = X;
496 while (Y <= YMax) {
497 while (X <= XMax) { if (!f(GetCell(X, Y), X, Y)) { return false; }; ++X };
498 X = XStart;
499 ++Y;
500 };
501 return true;
502 }
503 //! Call the specified function on each of a rectangle of cells, returning if the function returns true ( returns a pointer to cell that triggered success)
504 typedef const bool (*CellFinder)(const Cell&, const cell_xoffset_t, const cell_yoffset_t);
505 const bool FindAdjacentCell(const CellFunction& f, const cell_xpos_t X, const cell_ypos_t Y, cell_xpos_t& DirectionX, cell_ypos_t& DirectionY) const {
506 for (cell_xoffset_t OffsetX=-1; OffsetX<2; ++x)
507 for (cell_yoffset_t OffsetY=-1; OffsetY<2; ++y)
508 if (f(GetCell(X++, Y), OffsetX, OffsetY)) {
509 DirectionX = OffsetX;
510 DirectionY = OffsetY;
511 return true;
512 };
513 return false;
514 };
515 const bool FindAdjacentCell(const CellFunction& f, const cell_xpos_t X, const cell_ypos_t Y) const {
516 for (cell_xoffset_t OffsetX=-1; OffsetX<2; ++x)
517 for (cell_yoffset_t OffsetY=-1; OffsetY<2; ++y)
518 if (f(GetCell(X++, Y), OffsetX, OffsetY))
519 return true;
520 return false;
521 };
522
523 /**
524 This rather clunky syntax for changing cell values allows the map to monitor when the values are changed,
525 so it can dirty the elevations that are affected by the change
526
527 All elevations for a given team are dirtied when:
528 * A forbidden area for a given team is created/destroyed
529 * resource type is changed from/to no resource
530 * Building type is changed to/from NULL
531
532 "resources" elevations should also be dirtied when:
533 * resource type is changed from/to the specified type
534
535 "Guard" elevations should also be changed when:
536 * A guard area for a given team is created/destroyed
537
538 **/
539
540 const bool Forbidden (cell_xpos_t x, cell_ypos_t y, team_ID_t p) const { return GetCell(x, y)[p].Forbidden(); };
541 const bool Guarded (cell_xpos_t x, cell_ypos_t y, team_ID_t p) const { return GetCell(x, y)[p].Guarded(); };
542 const bool Discovered (cell_xpos_t x, cell_ypos_t y, team_ID_t p) const { return GetCell(x, y)[p].Discovered(); };
543 const bool Fog (cell_xpos_t x, cell_ypos_t y, team_ID_t p) const { return GetCell(x, y)[p].Fog(FogOfWarAB); };
544
545 const bool FlipForbidden (cell_xpos_t x, cell_ypos_t y, team_ID_t p) const {
546 DirtyForbidden[p] = DirtyResources[p] = DirtyGuarded[p] = DirtyBuildings = 1;
547 return GetCell(x, y)[p].FlipForbidden();
548 };
549 const bool FlipGuarded (cell_xpos_t x, cell_ypos_t y, team_ID_t p) const {
550 DirtyGuarded[p] = 1;
551 return GetCell(x, y)[p].FlipGuarded();
552 };
553 const bool FlipDiscovered (cell_xpos_t x, cell_ypos_t y, team_ID_t p) const {
554 return GetCell(x, y)[p].FilpDiscovered();
555 };
556 const bool FlipFog (cell_xpos_t x, cell_ypos_t y, team_ID_t p) const { return GetCell(x, y)[p].FlipFog(FogOfWarAB); };
557
558 const bool Forbidden (cell_xpos_t x, cell_ypos_t y, team_ID_t p, const bool B) const { return (Forbidden (x, y, p) == B)?B:FlipForbidden (x, y, p) };
559 const bool Guarded (cell_xpos_t x, cell_ypos_t y, team_ID_t p, const bool B) const { return (Guarded (x, y, p) == B)?B:FlipGuarded (x, y, p) };
560 const bool Discovered (cell_xpos_t x, cell_ypos_t y, team_ID_t p, const bool B) const { return (Discovered (x, y, p) == B)?B:FlipDiscovered(x, y, p) };
561 const bool Fog (cell_xpos_t x, cell_ypos_t y, team_ID_t p, const bool B) const { return (Fog (x, y, p) == B)?B:FlipFog (x, y, p) };
562
563 //! Since a building covers several cells, we need to set it for each one
564 void setBuilding(int XMin, int XMax, int YMin, int YMax, Building* B) {
565 const bool setCell(Cell& C, cell_xpos_t, cell_ypos_t) {
566 if (C.Building() != B) {
567 DirtyBuildings = 1; if (B || C.Building()) DirtyForbidden[p] = DirtyResources[p] = DirtyGuarded[p] = 1;
568 C.setBuilding(B);
569 };
570 return true;
571 };
572 IterateOverArea(&setCell, XMin, XMax, YMin, Ymax);
573 }
574
575 const resource_enum_t Resource(cell_xpos_t x, cell_ypos_t y) const { return GetCell(x, y)[p].Resource().type };
576 const resource_enum_t Resource(cell_xpos_t x, cell_ypos_t y, Resource_enum T ) {
577 if (GetCell(x, y)[p].Resource().type == T) { return T };
578 if ((T == NO_RES_TYPE) || (GetCell(x, y)[p].Resource().type == NO_RES_TYPE)) {
579 DirtyForbidden[p] = DirtyResources[p] = DirtyGuarded[p] = DirtyBuildings = 1;
580 } else {
581 DirtyResource[p][T] = DirtyResource[p][GetCell(x, y)[p].Resource().type] = 1;
582 };
583 return GetCell(x, y)[p].Resource().type = T;
584 };
585
586 //! Checks to see if a building can go in a particular area
587 bool FreeAreaForBuilding(cell_xpos_t XMin, cell_xpos_t XMax, cell_ypos_t YMin, cell_ypos_t YMax) { return IterateOverArea(&isFreeForBuilding, x, y, x+w, y+h) };
588 bool FreeAreaForBuildingGID(cell_xpos_t XMin, cell_xpos_t XMax, cell_ypos_t YMin, cell_ypos_t YMax, Building* B) {
589 bool isFreeForBuildingOrMe(const Cell& C, cell_xpos_t, cell_ypos_t) { return !((Building && Building != B) || GroundUnit || Resource.hasResource) && isGrass() };
590 return IterateOverArea(&isFreeForBuildingOrMe, x, y, x+w, y+h);
591 };
592 bool FreeAreaForBuildingNoGroundUnits(cell_xpos_t XMin, cell_xpos_t XMax, cell_ypos_t YMin, cell_ypos_t YMax) { return IterateOverArea(&isFreeForBuildingNoGroundUnits, x, y, x+w, y+h) };
593 bool FreeAreaForBuildingGIDNoGroundUnits(cell_xpos_t XMin, cell_xpos_t XMax, cell_ypos_t YMin, cell_ypos_t YMax, Building* B) {
594 bool isFreeForBuildingOrMe(const Cell& C, cell_xpos_t, cell_ypos_t) { return !((C.Building && C.Building != B) || C.Resource.hasResource) && C.isGrass() };
595 return IterateOverArea(&isFreeForBuildingOrMe, x, y, x+w, y+h);
596 };
597
598 //! Do a step associated with the map (grow resources and process bullets)
599 void syncStep(Uint32 stepCounter, const Game& game);
600 //! For some reason, we need two fogs of war, which are switched occasionally in a syncStep
601 void switchFogOfWar() { FogOfWarAB = !FogOfWarAB };
602
603 const Uint32 checkSum(bool heavy) {
604 Uint32 cs=size;
605 if (heavy)
606 for (int y=0; y<Height; y++)
607 for (int x=0; x<Width; x++)
608 Cells[x, y].checkSum(cs);
609 return cs;
610 };
611
612 const bool resourceAvailable(const team_ID_t Team, const resource_enum_t 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;
613
614 Yes //! Starting from position (x, y) using elevation, returns the elevation destination in (targetX, targetY)
615 static const int MaxHillclimbIterations = 256;
616 bool Map::getElevationDestination(cell_xpos_t& x, cell_ypos_t& y, const team_ID_t p, const elevation_index_t i);
617
618 //! Regenerate actual map tiles from undermap tiles
619 void Map::regenerate(cell_xpos_t x=0, cell_ypos_t y=0, cell_width_t w=Width-1, cell_height_t h=Height-1) {
620 const bool regenerateCell(const Cell& C, const cell_xpos_t x, cell_ypos_t y) { C.Terrain(GetCell(x+1, y+1), GetCell(x, y+1), GetCell(x+1, y)) }
621 IterateOverArea(&regenerateCell, x, x+w, y, y+h);
622 }
623
624
625 //! Elevation functions
626 elevation_t getElevation(team_ID_t team, resource_t resourceType, bool canSwim, int x, int y) { return GetCell(x, y)[team][(canSwim?RESOURCE_SWIM:RESOURCE_NOSWIM)+resourceType] }
627
628 void updateResourcesElevation(int teamNumber, Uint8 resourceType, bool canSwim);
629 bool directionFromMinigrad(Uint8 miniGrad[25], int *dx, int *dy, const bool strict);
630 bool directionByMinigrad(Uint32 teamMask, bool canSwim, int x, int y, int *dx, int *dy, Uint8 *elevation, bool strict);
631 bool directionByMinigrad(Uint32 teamMask, bool canSwim, int x, int y, int bx, int by, int *dx, int *dy, Uint8 localElevation[1024], bool strict);
632 bool pathfindResource(int teamNumber, Uint8 resourceType, bool canSwim, int x, int y, int *dx, int *dy, bool *stopWork);
633 void pathfindRandom(Unit *unit);
634
635 void updateLocalElevation(Building *building, bool canSwim); //The 32*32 elevation
636 void updateGlobalElevation(Building *building, bool canSwim); //The full-sized elevation
637 //!A special elevation for clearing flags. Returns false if there is nothing to clear.
638 bool updateLocalResources(Building *building, bool canSwim);
639 void expandLocalElevation(Uint8 *elevation);
640
641 bool buildingAvailable(Building *building, bool canSwim, int x, int y, int *dist);
642 bool pathfindBuilding(Building *building, bool canSwim, int x, int y, int *dx, int *dy);
643 bool pathfindLocalResource(Building *building, bool canSwim, int x, int y, int *dx, int *dy); // Used for all resources mixed in clearing flags.
644
645 //! Make local elevation dirty in the area. Wrap-safe on x,y
646 void dirtyAllBuildingElevations(int x, int y, int wl, int hl, int teamNumber);
647 bool pathfindForbidden(Uint8 *optionElevation, int teamNumber, bool canSwim, int x, int y, int *dx, int *dy);
648 //! Find the best direction toward gaurd area, return true if one has been found, false otherwise
649 bool pathfindGuardArea(int teamNumber, bool canSwim, int x, int y, int *dx, int *dy);
650 //! Update the forbidden elevation,
651 void updateForbiddenElevation(int teamNumber, bool canSwim);
652 void updateForbiddenElevation(int teamNumber);
653 //! Update the guard area elevation
654 void updateGuardAreasElevation(int teamNumber, bool canSwim);
655 void updateGuardAreasElevation(int teamNumber);
656
657 private:
658 void PropagateElevation(const team_ID_t p, const elevation_index_t i);
659
660 void smoothResources(int times);
661
662 };
663
664 #endif
665

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