1 // Copyright (C) 2007, 2008, 2009 Ben Asselstine
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 3 of the License, or
6 // (at your option) any later version.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU Library General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 #include "playerlist.h"
25 #include "xmlhelper.h"
26 #include "GameScenarioOptions.h"
28 std::string FogMap::d_tag = "fogmap";
32 //#define debug(x) {std::cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<std::endl<<flush;}
36 FogMap::FogMap(int width, int height)
42 d_fogmap = new FogType[d_width*d_height];
43 shademap = new ShadeType[d_width*d_height];
48 FogMap::FogMap(XML_Helper* helper)
52 helper->getData(d_width, "width");
53 helper->getData(d_height, "height");
54 helper->getData(types, "map");
57 d_fogmap = new FogType[d_width*d_height];
59 for (int y = 0; y < d_height; y++)
61 for (int x = 0; x < d_width; x++)
63 //due to the circumstances, types is a long stream of
64 //numbers, so read it character for character (no \n's or so)
65 d_fogmap[y*d_width + x] = FogType(types[y*d_width + x] - '0');
68 shademap = new ShadeType[d_width*d_height];
72 FogMap::FogMap(const FogMap& fogmap)
73 :d_width(fogmap.d_width), d_height(fogmap.d_height)
76 d_fogmap = new FogType[d_width*d_height];
78 for (int y = 0; y < d_height; y++)
80 for (int x = 0; x < d_width; x++)
82 d_fogmap[y*d_width + x] = fogmap.d_fogmap[y*d_width + x];
85 shademap = new ShadeType[d_width*d_height];
86 for (int y = 0; y < d_height; y++)
88 for (int x = 0; x < d_width; x++)
90 shademap[y*d_width + x] = fogmap.shademap[y*d_width + x];
101 bool FogMap::fill(FogType type)
103 for (int i = 0; i < d_width*d_height; i++)
110 bool FogMap::save(XML_Helper* helper) const
114 retval &= helper->openTag(FogMap::d_tag);
115 retval &= helper->saveData("width", d_width);
116 retval &= helper->saveData("height", d_height);
118 std::stringstream types;
120 for (int y = 0; y < d_height; y++)
122 for (int x = 0; x < d_width; x++)
124 types << static_cast<int>(d_fogmap[y*d_width + x]);
129 retval &= helper->saveData("map", types.str());
130 retval &= helper->closeTag();
135 FogMap::FogType FogMap::getFogTile(Vector<int> pos) const
137 return d_fogmap[pos.y * d_width + pos.x];
140 FogMap::ShadeType FogMap::getShadeTile(Vector<int> pos) const
142 return shademap[pos.y * d_width + pos.x];
145 void FogMap::alterFogRadius(Vector<int> pt, int radius, FogType new_type)
147 // this doesn't draw a circle, it draws a square
148 // it isn't a bug, except for being badly named
149 int x = pt.x - radius;
150 int y = pt.y - radius;
151 int size = 2 * radius + 1;
152 for (int i = 0; i < size; i++)
154 for (int j = 0; j < size; j++)
156 if ((x+i) < 0 || (y+j) < 0 || (x+i) >= d_width || (y+j) >= d_height)
158 d_fogmap[(y+j)*d_width + (x+i)] = new_type;
164 void FogMap::alterFogRectangle(Vector<int> pt, int height, int width, FogType new_type)
168 for (int i = 0; i < height; i++)
170 for (int j = 0; j < width; j++)
172 if ((x+i) < 0 || (y+j) < 0 || (x+i) >= d_width || (y+j) >= d_height)
174 d_fogmap[(y+j)*d_width + (x+i)] = new_type;
180 bool FogMap::isCompletelyObscuredFogTile(Vector<int> pos) const
182 if (shademap[pos.y * d_width + pos.x] == ALL)
189 bool FogMap::isLoneFogTile(Vector<int> pos)
191 bool west_open = false;
192 bool east_open = false;
193 //are east-west adjacent squares open?
194 if (pos.x + 1 >= d_width || d_fogmap[pos.y*d_width + pos.x + 1] == OPEN)
196 if (pos.x - 1 < 0 || d_fogmap[pos.y*d_width + pos.x - 1] == OPEN)
198 bool north_open = false;
199 bool south_open = false;
200 //are north-south adjacent squares open?
201 if (pos.y + 1 >= d_height || d_fogmap[(pos.y+1)*d_width + pos.x] == OPEN)
203 if (pos.y - 1 < 0 || d_fogmap[(pos.y-1)*d_width + pos.x] == OPEN)
205 if (east_open && west_open)
207 if (north_open && south_open)
212 void FogMap::smooth()
214 for (int y = 0; y < d_height; y++)
216 for (int x = 0; x < d_width; x++)
218 if (d_fogmap[y*d_width + x] == CLOSED)
223 if (isLoneFogTile (pos))
224 d_fogmap[y*d_width + x] = OPEN;
233 bool FogMap::isFogged(Vector <int> pos)
235 if (getFogTile(pos) == FogMap::CLOSED)
238 if (isLoneFogTile(pos) == true)
244 bool FogMap::isClear(Vector <int> pos, Player *player)
246 //is this tile visible, or not?
247 FogMap *fogmap = player->getFogMap();
248 if (fogmap->getFogTile(pos) == FogMap::OPEN)
254 void FogMap::alterFog(SightMap *sightmap)
256 return alterFogRectangle(sightmap->pos, sightmap->h, sightmap->w, OPEN);
260 * fog display algorithm
262 * smallmap shows fog placement
263 * - it is a peek into the data model
265 * bigmap shows a rendering of that
266 * if a tile on the bigmap is partially fogged, then it is completely fogged on the small map.
268 * this means that partially fogged tiles depend on adjacent tiles being fogged
269 * completely fogged tiles depends on adjacent tiles being fogged
271 * when one tile is fogged and is not surrounded by adjacent fogged tiles it is shown as not fogged on the bigmap, while it is shown as fogged on the small map. it is then marked as defogged at the start of the next turn.
273 * every tile has 4 faces:
274 * it can connect to an adjacent tile darkly, lightly, or not at all
275 * a dark face means the whole side is black
276 * a light face means the side is a gradient *
281 * 1 = light corner se: connects lightly to south and east
282 * 2 = light corner sw: connects lightly to south and west
283 * 3 = light corner nw: connects lightly to north and west
284 * 4 = light corner ne: connects lightly to north and east
285 * 5 = dark corner nw: connects darkly to north and west, lightly to south and east
286 * 6 = dark corner ne: connects darkly to north and east, lightly to south and west
287 * 7 = dark corner se: connects darkly to east and south, lightly to north and west
288 * 8 = dark corner sw: connects darkly to south and west, lightly to north and east
289 * 9 = bottom to top: connects darkly to south, connects lightly to east and west
290 * 10 = top to bottom: connects darkly to north, connects lightly to east and west
291 * 11 = right to left: connects darkly to west, connects lightly to north and south
292 * 12 = left to right: connects darkly to east, connects lightly to north and south
293 * 13 = all black: connects darkly to north, south, east and west
295 * bigmap tile processing algorithm:
296 * for each tile currently being shown, examine each tile in normal order
298 * here are the cases that we can handle for fogging a tile:
299 * the sets are read as follows:
302 * 5x4 = (fog tile type)
306 * the most significant bit is in the 1st position, and the least sigificant bit
307 * is in the 8th position
309 * we check each position and if it's a fogged tile, then we add a 1 to that
315 * (255) (all 8 bits on is 255)
318 * 1x1 = 5 1x1 = 6 1x1 = 7 1x1 = 8
320 * (127) (223) (254) (251) (e.g. 251 == 11111011)
323 * 1x1 = 9 1x0 = 12 1x1 =10 0x1 = 11
325 * (253) (239) (191) (247) (e.g. 247 == 11110111)
328 * 1x1 = 9 1x1 = 10 1x1 = 9 1x1 = 10
330 * (252) (159) (249) (63)
333 * 0x1 = 11 0x1 = 11 1x0 =12 1x0 = 12
335 * (246) (215) (235) (111)
338 * 0x1 = 1 1x0 = 2 1x0 = 3 0x1 = 4
340 * (208) (104) (11) (22)
344 * 1x1 = 9 1x1 = 10 0x1 = 11 1x0 = 12
346 * (248) (31) (214) (107)
350 * 0x1 = 1 0x1 = 4 1x0 = 2 1x0 = 3
352 * (244) (151) (233) (47)
355 * 0x1 = 1 0x1 = 4 1x0 = 2 1x0 = 3
357 * (240) (150) (232) (15)
360 * 1x0 = 2 1x0 = 3 0x1 = 1 0x1 = 4
362 * (105) (43) (232) (15)
370 *none of these sets contain a so-called "lone" tile.
371 *a lone tile is a fogged tile surrounded by two unfogged tiles on either side.
373 FogMap::ShadeType FogMap::calculateShade(Vector<int> tile)
378 for (int i = tile.x - 1; i <= tile.x + 1; i++)
379 for (int j = tile.y - 1; j <= tile.y + 1; j++)
382 if (i == tile.x && j == tile.y)
384 if (i < 0 || j < 0 || i >= d_width || j >= d_height)
391 foggyTile = isFogged(pos);
397 case 0: idx += 1; break;
398 case 1: idx += 2; break;
399 case 2: idx += 4; break;
400 case 3: idx += 8; break;
401 case 4: idx += 16; break;
402 case 5: idx += 32; break;
403 case 6: idx += 64; break;
404 case 7: idx += 128; break;
411 //now idx relates to a particular fog picture
412 ShadeType type = NONE;
415 case 208: case 212: case 240: case 244: case 242: case 216: case 220: case 210: case 217: case 211: case 218: case 209: type = LIGHTLY_TO_SOUTH_AND_EAST; break;
416 case 104: case 105: case 232: case 233: case 121: case 120: case 110: case 106: case 122: case 124: case 234: case 108: type = LIGHTLY_TO_SOUTH_AND_WEST; break;
417 case 11: case 15: case 43: case 47: case 59: case 27: case 79: case 75: case 155: case 203: case 139: case 91: type = LIGHTLY_TO_NORTH_AND_WEST; break;
418 case 22: case 150: case 151: case 23: case 87: case 86: case 158: case 118:case 94: case 30: case 62: case 54: type = LIGHTLY_TO_NORTH_AND_EAST; break;
419 case 127: type = DARKLY_TO_NORTH_AND_WEST_LIGHTLY_TO_SOUTH_AND_EAST; break;
420 case 223: type = DARKLY_TO_NORTH_AND_EAST_LIGHTLY_TO_SOUTH_AND_WEST; break;
421 case 254: type = DARKLY_TO_SOUTH_AND_EAST_LIGHTLY_TO_NORTH_AND_WEST; break;
422 case 251: type = DARKLY_TO_SOUTH_AND_WEST_LIGHTLY_TO_NORTH_AND_EAST; break;
423 case 248: case 249: case 252: case 253: case 250: type = DARKLY_TO_SOUTH_LIGHTLY_TO_EAST_AND_WEST; break;
424 case 31: case 63: case 159: case 191: case 95: type = DARKLY_TO_NORTH_LIGHTLY_TO_EAST_AND_WEST; break;
425 case 214: case 215: case 246: case 247: case 222: type = DARKLY_TO_WEST_LIGHTLY_TO_NORTH_AND_SOUTH; break;
426 case 107: case 111: case 235: case 239: case 123: type = DARKLY_TO_EAST_LIGHTLY_TO_NORTH_AND_SOUTH; break;
427 case 126: type = DARKLY_TO_SOUTH_AND_WEST_DARKLY_TO_NORTH_AND_EAST; break;
428 case 219: type = DARKLY_TO_NORTH_AND_WEST_DARKLY_TO_SOUTH_AND_EAST; break;
429 case 255: type = ALL; break;
433 switch (type) //fixme: figure out why this flipping is necessary!
435 case DARKLY_TO_EAST_LIGHTLY_TO_NORTH_AND_SOUTH:
436 type = DARKLY_TO_NORTH_LIGHTLY_TO_EAST_AND_WEST; break;
437 case DARKLY_TO_NORTH_LIGHTLY_TO_EAST_AND_WEST:
438 type = DARKLY_TO_EAST_LIGHTLY_TO_NORTH_AND_SOUTH; break;
439 case DARKLY_TO_SOUTH_LIGHTLY_TO_EAST_AND_WEST:
440 type = DARKLY_TO_WEST_LIGHTLY_TO_NORTH_AND_SOUTH; break;
441 case DARKLY_TO_WEST_LIGHTLY_TO_NORTH_AND_SOUTH:
442 type = DARKLY_TO_SOUTH_LIGHTLY_TO_EAST_AND_WEST; break;
443 case DARKLY_TO_NORTH_AND_EAST_LIGHTLY_TO_SOUTH_AND_WEST:
444 type = DARKLY_TO_SOUTH_AND_WEST_LIGHTLY_TO_NORTH_AND_EAST; break;
445 case DARKLY_TO_SOUTH_AND_WEST_LIGHTLY_TO_NORTH_AND_EAST:
446 type = DARKLY_TO_NORTH_AND_EAST_LIGHTLY_TO_SOUTH_AND_WEST; break;
447 case LIGHTLY_TO_SOUTH_AND_WEST:
448 type = LIGHTLY_TO_NORTH_AND_EAST; break;
449 case LIGHTLY_TO_NORTH_AND_EAST:
450 type = LIGHTLY_TO_SOUTH_AND_WEST; break;
457 void FogMap::calculateShadeMap()
459 for (int i = 0; i < d_width; i++)
460 for (int j = 0; j < d_height; j++)
461 shademap[j * d_width + i] = calculateShade(Vector<int>(i,j));
463 for (int i = 0; i < d_width; i++)
464 for (int j = 0; j < d_height; j++)
465 if (isFogged(Vector<int>(i,j)) == false)
466 shademap[j * d_width + i] = NONE;