| 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(®enerateCell, 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 |
|