00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00031
00032
00033
00034
00035
00036 #include "stratagus.h"
00037 #include "player.h"
00038 #include "unittype.h"
00039 #include "unit.h"
00040 #include "unit_cache.h"
00041 #include "map.h"
00042 #include "ui.h"
00043 #include "../video/intern_video.h"
00044
00045
00046
00047
00048
00049 static int FogOfWarOpacity = 128;
00050 CGraphic *CMap::FogGraphic;
00051
00055 static const int FogTable[16] = {
00056 0,11,10, 2, 13, 6, 14, 3, 12, 15, 4, 1, 8, 9, 7, 0,
00057 };
00058
00059 unsigned char *VisionTable[3];
00060 int *VisionLookup;
00061
00062 static unsigned short *VisibleTable;
00063
00064 static SDL_Surface *OnlyFogSurface;
00065 static CGraphic *AlphaFogG;
00066
00067
00068
00069
00070
00081 unsigned short CMap::IsTileVisible(const CPlayer *player, int x, int y) const
00082 {
00083 unsigned short visiontype;
00084 unsigned short *visible;
00085
00086 visible = this->Field(x, y)->Visible;
00087 visiontype = visible[player->Index];
00088
00089 if (visiontype > 1) {
00090 return visiontype;
00091 }
00092 if (!player->SharedVision) {
00093 if (visiontype) {
00094 return visiontype + (this->NoFogOfWar ? 1 : 0);
00095 }
00096 return 0;
00097 }
00098
00099 for (int i = 0; i < PlayerMax ; ++i) {
00100 if (player->SharedVision & (1 << i) &&
00101 (Players[i].SharedVision & (1 << player->Index))) {
00102 if (visible[i] > 1) {
00103 return 2;
00104 }
00105 visiontype |= visible[i];
00106 }
00107 }
00108 if (visiontype) {
00109 return visiontype + (this->NoFogOfWar ? 1 : 0);
00110 }
00111 return 0;
00112 }
00113
00124 int MapFogFilterFlags(CPlayer *player, int x, int y, int mask)
00125 {
00126 int nunits;
00127 int unitcount;
00128 int fogmask;
00129 CUnit *table[UnitMax];
00130
00131
00132 if (x < 0 || y < 0 || x >= Map.Info.MapWidth || y >= Map.Info.MapHeight) {
00133 return mask;
00134 }
00135
00136 nunits = UnitCache.Select(x, y, table, UnitMax);
00137 fogmask = -1;
00138 unitcount = 0;
00139 while (unitcount < nunits) {
00140 if (!table[unitcount]->IsVisibleAsGoal(player)) {
00141 fogmask &= ~table[unitcount]->Type->FieldFlags;
00142 }
00143 ++unitcount;
00144 }
00145 return mask & fogmask;
00146 }
00147
00155 void MapMarkTileSight(const CPlayer *player, int x, int y)
00156 {
00157 Assert(0 <= x && x < Map.Info.MapWidth);
00158 Assert(0 <= y && y < Map.Info.MapHeight);
00159
00160 unsigned short *v;
00161
00162 v = &Map.Field(x, y)->Visible[player->Index];
00163 if (*v == 0 || *v == 1) {
00164
00165 if (!Map.NoFogOfWar || *v == 0) {
00166 UnitsOnTileMarkSeen(player, x, y);
00167 }
00168 *v = 2;
00169 return;
00170 }
00171 Assert(*v != 65535);
00172 ++*v;
00173 }
00174
00182 void MapUnmarkTileSight(const CPlayer *player, int x, int y)
00183 {
00184 Assert(0 <= x && x < Map.Info.MapWidth);
00185 Assert(0 <= y && y < Map.Info.MapHeight);
00186
00187 unsigned short *v;
00188
00189 v = &Map.Field(x, y)->Visible[player->Index];
00190 switch (*v) {
00191 case 0:
00192 case 1:
00193
00194 Assert(0);
00195 break;
00196 case 2:
00197
00198 if (!Map.NoFogOfWar) {
00199 UnitsOnTileUnmarkSeen(player, x, y);
00200 }
00201
00202 default:
00203 --*v;
00204 break;
00205 }
00206 }
00207
00219 void MapSight(const CPlayer *player, int x, int y, int w, int h, int range,
00220 MapMarkerFunc *marker)
00221 {
00222 int mx;
00223 int my;
00224 int cx[4];
00225 int cy[4];
00226 int steps;
00227 int cycle;
00228 int p;
00229
00230
00231 if (!range) {
00232 return;
00233 }
00234
00235 p = player->Index;
00236
00237
00238 for (mx = x - range; mx < x + range + w; ++mx) {
00239 for (my = y; my < y + h; ++my) {
00240 if (mx >= 0 && mx < Map.Info.MapWidth) {
00241 marker(player, mx, my);
00242 }
00243 }
00244 }
00245
00246
00247 for (my = y - range; my < y; ++my) {
00248 for (mx = x; mx < x + w; ++mx) {
00249 if (my >= 0 && my < Map.Info.MapHeight) {
00250 marker(player, mx, my);
00251 }
00252 }
00253 }
00254
00255
00256 for (my = y + h; my < y + range + h; ++my) {
00257 for (mx = x; mx < x + w; ++mx) {
00258 if (my >= 0 && my < Map.Info.MapHeight) {
00259 marker(player, mx, my);
00260 }
00261 }
00262 }
00263
00264
00265 steps = 0;
00266 while (VisionTable[0][steps] <= range) {
00267
00268 cx[0] = x + w - 1;
00269 cy[0] = y - VisionTable[0][steps];
00270
00271 cx[1] = x;
00272 cy[1] = y - VisionTable[0][steps];
00273
00274 cx[2] = x;
00275 cy[2] = y + VisionTable[0][steps] + h - 1;
00276
00277 cx[3] = x + w - 1;
00278 cy[3] = y + VisionTable[0][steps] + h - 1;
00279
00280 ++steps;
00281 while (VisionTable[1][steps] != 0 || VisionTable[2][steps] != 0) {
00282
00283 cycle = 0;
00284 while (cycle++ < VisionTable[0][steps]) {
00285 cx[0] += VisionTable[1][steps];
00286 cy[0] += VisionTable[2][steps];
00287 cx[1] -= VisionTable[1][steps];
00288 cy[1] += VisionTable[2][steps];
00289 cx[2] -= VisionTable[1][steps];
00290 cy[2] -= VisionTable[2][steps];
00291 cx[3] += VisionTable[1][steps];
00292 cy[3] -= VisionTable[2][steps];
00293 if (cx[0] < Map.Info.MapWidth && cy[0] >= 0) {
00294 marker(player, cx[0], cy[0]);
00295 }
00296 if (cx[1] >= 0 && cy[1] >= 0) {
00297 marker(player, cx[1], cy[1]);
00298 }
00299 if (cx[2] >= 0 && cy[2] < Map.Info.MapHeight) {
00300 marker(player, cx[2], cy[2]);
00301 }
00302 if (cx[3] < Map.Info.MapWidth && cy[3] < Map.Info.MapHeight) {
00303 marker(player, cx[3], cy[3]);
00304 }
00305 }
00306 ++steps;
00307 }
00308 }
00309 }
00310
00314 void UpdateFogOfWarChange(void)
00315 {
00316
00317
00318
00319 for (int x = 0; x < NumUnits; ++x) {
00320 UnitCountSeen(Units[x]);
00321 }
00322 }
00323
00324
00325
00326
00327
00334 void VideoDrawOnlyFog(int x, int y)
00335 {
00336 if (!UseOpenGL) {
00337 int oldx;
00338 int oldy;
00339 SDL_Rect srect;
00340 SDL_Rect drect;
00341
00342 srect.x = 0;
00343 srect.y = 0;
00344 srect.w = OnlyFogSurface->w;
00345 srect.h = OnlyFogSurface->h;
00346
00347 oldx = x;
00348 oldy = y;
00349 CLIP_RECTANGLE(x, y, srect.w, srect.h);
00350 srect.x += x - oldx;
00351 srect.y += y - oldy;
00352
00353 drect.x = x;
00354 drect.y = y;
00355
00356 SDL_BlitSurface(OnlyFogSurface, &srect, TheScreen, &drect);
00357 } else {
00358 Video.FillRectangleClip(Video.MapRGBA(0, 0, 0, 0, FogOfWarOpacity),
00359 x, y, TileSizeX, TileSizeY);
00360 }
00361 }
00362
00363
00364
00365
00366
00375 static void DrawFogOfWarTile(int sx, int sy, int dx, int dy)
00376 {
00377 int w;
00378 int tile;
00379 int tile2;
00380 int x;
00381 int y;
00382
00383 #define IsMapFieldExploredTable(x, y) \
00384 (VisibleTable[(y) * Map.Info.MapWidth + (x)])
00385 #define IsMapFieldVisibleTable(x, y) \
00386 (VisibleTable[(y) * Map.Info.MapWidth + (x)] > 1)
00387
00388 w = Map.Info.MapWidth;
00389 tile = tile2 = 0;
00390 x = sx - sy;
00391 y = sy / Map.Info.MapWidth;
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401 if (sy) {
00402 if (sx != sy) {
00403 if (!IsMapFieldExploredTable(x - 1, y - 1)) {
00404 tile2 |= 2;
00405 tile |= 2;
00406 } else if (!IsMapFieldVisibleTable(x - 1, y - 1)) {
00407 tile |= 2;
00408 }
00409 }
00410 if (!IsMapFieldExploredTable(x, y - 1)) {
00411 tile2 |= 3;
00412 tile |= 3;
00413 } else if (!IsMapFieldVisibleTable(x, y - 1)) {
00414 tile |= 3;
00415 }
00416 if (sx != sy + w - 1) {
00417 if (!IsMapFieldExploredTable(x + 1, y - 1)) {
00418 tile2 |= 1;
00419 tile |= 1;
00420 } else if (!IsMapFieldVisibleTable(x + 1, y - 1)) {
00421 tile |= 1;
00422 }
00423 }
00424 }
00425
00426 if (sx != sy) {
00427 if (!IsMapFieldExploredTable(x - 1, y)) {
00428 tile2 |= 10;
00429 tile |= 10;
00430 } else if (!IsMapFieldVisibleTable(x - 1, y)) {
00431 tile |= 10;
00432 }
00433 }
00434 if (sx != sy + w - 1) {
00435 if (!IsMapFieldExploredTable(x + 1, y)) {
00436 tile2 |= 5;
00437 tile |= 5;
00438 } else if (!IsMapFieldVisibleTable(x + 1, y)) {
00439 tile |= 5;
00440 }
00441 }
00442
00443 if (sy + w < Map.Info.MapHeight * w) {
00444 if (sx != sy) {
00445 if (!IsMapFieldExploredTable(x - 1, y + 1)) {
00446 tile2 |= 8;
00447 tile |= 8;
00448 } else if (!IsMapFieldVisibleTable(x - 1, y + 1)) {
00449 tile |= 8;
00450 }
00451 }
00452 if (!IsMapFieldExploredTable(x, y + 1)) {
00453 tile2 |= 12;
00454 tile |= 12;
00455 } else if (!IsMapFieldVisibleTable(x, y + 1)) {
00456 tile |= 12;
00457 }
00458 if (sx != sy + w - 1) {
00459 if (!IsMapFieldExploredTable(x + 1, y + 1)) {
00460 tile2 |= 4;
00461 tile |= 4;
00462 } else if (!IsMapFieldVisibleTable(x + 1, y + 1)) {
00463 tile |= 4;
00464 }
00465 }
00466 }
00467
00468 tile = FogTable[tile];
00469 tile2 = FogTable[tile2];
00470
00471 if (ReplayRevealMap) {
00472 tile2 = 0;
00473 tile = 0;
00474 }
00475
00476 if (IsMapFieldVisibleTable(x, y) || ReplayRevealMap) {
00477 if (tile && tile != tile2) {
00478 if (UseOpenGL) {
00479 Map.FogGraphic->DrawFrameClipTrans(tile, dx, dy, FogOfWarOpacity);
00480 } else {
00481 AlphaFogG->DrawFrameClip(tile, dx, dy);
00482 }
00483 }
00484 } else {
00485 VideoDrawOnlyFog(dx, dy);
00486 }
00487 if (tile2) {
00488 Map.FogGraphic->DrawFrameClip(tile2, dx, dy);
00489 }
00490
00491 #undef IsMapFieldExploredTable
00492 #undef IsMapFieldVisibleTable
00493 }
00494
00498 void CViewport::DrawMapFogOfWar() const
00499 {
00500 int sx, sy;
00501 int dx, dy;
00502 int ex, ey;
00503 int p;
00504 int mx, my;
00505
00506
00507 if (ReplayRevealMap) {
00508 return;
00509 }
00510 p = ThisPlayer->Index;
00511
00512 sx = std::max(MapX - 1, 0);
00513 ex = std::min(MapX + MapWidth + 1, Map.Info.MapWidth);
00514 my = std::max(MapY - 1, 0);
00515 ey = std::min(MapY + MapHeight + 1, Map.Info.MapHeight);
00516
00517
00518
00519 for (; my < ey; ++my) {
00520 for (mx = sx; mx < ex; ++mx) {
00521 VisibleTable[my * Map.Info.MapWidth + mx] = Map.IsTileVisible(ThisPlayer, mx, my);
00522 }
00523 }
00524
00525 ex = EndX;
00526 sy = MapY * Map.Info.MapWidth;
00527 dy = Y - OffsetY;
00528 ey = EndY;
00529
00530 while (dy <= ey) {
00531 sx = MapX + sy;
00532 dx = X - OffsetX;
00533 while (dx <= ex) {
00534 mx = (dx - X + OffsetX) / TileSizeX + MapX;
00535 my = (dy - Y + OffsetY) / TileSizeY + MapY;
00536 if (VisibleTable[my * Map.Info.MapWidth + mx]) {
00537 DrawFogOfWarTile(sx, sy, dx, dy);
00538 } else {
00539 Video.FillRectangleClip(ColorBlack, dx, dy, TileSizeX, TileSizeY);
00540 }
00541 ++sx;
00542 dx += TileSizeX;
00543 }
00544 sy += Map.Info.MapWidth;
00545 dy += TileSizeY;
00546 }
00547 }
00548
00553 void CMap::InitFogOfWar(void)
00554 {
00555 Uint8 r, g, b;
00556 Uint32 color;
00557 SDL_Surface *s;
00558
00559 FogGraphic->Load();
00560
00561 if (!UseOpenGL) {
00562 if (!AlphaFogG) {
00563
00564
00565
00566 s = SDL_CreateRGBSurface(SDL_SWSURFACE, TileSizeX, TileSizeY,
00567 32, RMASK, GMASK, BMASK, AMASK);
00568
00569 SDL_GetRGB(ColorBlack, TheScreen->format, &r, &g, &b);
00570 color = Video.MapRGB(s->format, r, g, b);
00571
00572 SDL_FillRect(s, NULL, color);
00573 OnlyFogSurface = SDL_DisplayFormat(s);
00574 SDL_SetAlpha(OnlyFogSurface, SDL_SRCALPHA | SDL_RLEACCEL, FogOfWarOpacity);
00575 SDL_FreeSurface(s);
00576
00577
00578
00579
00580 if (FogGraphic->Surface->format->BytesPerPixel == 1) {
00581 s = SDL_DisplayFormat(FogGraphic->Surface);
00582 SDL_SetAlpha(s, SDL_SRCALPHA | SDL_RLEACCEL, FogOfWarOpacity);
00583 } else {
00584 int i;
00585 int j;
00586 Uint32 c;
00587 Uint8 a;
00588 SDL_PixelFormat *f;
00589
00590
00591 f = FogGraphic->Surface->format;
00592 s = SDL_CreateRGBSurface(SDL_SWSURFACE, FogGraphic->Surface->w, TileSizeY,
00593 f->BitsPerPixel, f->Rmask, f->Gmask, f->Bmask, f->Amask);
00594 SDL_LockSurface(s);
00595 SDL_LockSurface(FogGraphic->Surface);
00596 for (i = 0; i < s->h; ++i) {
00597 memcpy((Uint8 *)s->pixels + i * s->pitch,
00598 (Uint8 *)FogGraphic->Surface->pixels + i * FogGraphic->Surface->pitch,
00599 FogGraphic->Surface->w * f->BytesPerPixel);
00600 }
00601 SDL_UnlockSurface(s);
00602 SDL_UnlockSurface(FogGraphic->Surface);
00603
00604
00605 SDL_LockSurface(s);
00606 for (j = 0; j < s->h; ++j) {
00607 for (i = 0; i < s->w; ++i) {
00608 c = *(Uint32 *)&((Uint8*)s->pixels)[i * 4 + j * s->pitch];
00609 Video.GetRGBA(c, s->format, &r, &g, &b, &a);
00610 if (a) {
00611 c = Video.MapRGBA(s->format, r, g, b, FogOfWarOpacity);
00612 *(Uint32 *)&((Uint8*)s->pixels)[i * 4 + j * s->pitch] = c;
00613 }
00614
00615 }
00616 }
00617 SDL_UnlockSurface(s);
00618 }
00619 AlphaFogG = CGraphic::New("");
00620 AlphaFogG->Surface = s;
00621 AlphaFogG->Width = TileSizeX;
00622 AlphaFogG->Height = TileSizeY;
00623 AlphaFogG->GraphicWidth = s->w;
00624 AlphaFogG->GraphicHeight = s->h;
00625 AlphaFogG->NumFrames = 1;
00626 }
00627 }
00628
00629 delete[] VisibleTable;
00630 VisibleTable = new unsigned short[Info.MapWidth * Info.MapHeight];
00631 }
00632
00636 void CMap::CleanFogOfWar()
00637 {
00638 delete[] VisibleTable;
00639 VisibleTable = NULL;
00640
00641 CGraphic::Free(Map.FogGraphic);
00642 FogGraphic = NULL;
00643
00644 if (!UseOpenGL) {
00645 if (OnlyFogSurface) {
00646 SDL_FreeSurface(OnlyFogSurface);
00647 OnlyFogSurface = NULL;
00648 }
00649 CGraphic::Free(AlphaFogG);
00650 AlphaFogG = NULL;
00651 }
00652 }
00653
00657 void InitVisionTable(void)
00658 {
00659 int *visionlist;
00660 int maxsize;
00661 int sizex;
00662 int sizey;
00663 int maxsearchsize;
00664 int i;
00665 int VisionTablePosition;
00666 int marker;
00667 int direction;
00668 int right;
00669 int up;
00670 int repeat;
00671
00672
00673 VisionTable[0] = new unsigned char[MaxMapWidth * MaxMapWidth];
00674 VisionTable[1] = new unsigned char[MaxMapWidth * MaxMapWidth];
00675 VisionTable[2] = new unsigned char[MaxMapWidth * MaxMapWidth];
00676
00677 VisionLookup = new int[MaxMapWidth + 2];
00678
00679 visionlist = new int[MaxMapWidth * MaxMapWidth];
00680
00681
00682 maxsize = MaxMapWidth;
00683 maxsearchsize = MaxMapWidth;
00684
00685 for (sizex = 0; sizex < maxsize; ++sizex) {
00686 for (sizey = 0; sizey < maxsize; ++sizey) {
00687 visionlist[sizey * maxsize + sizex] = isqrt(sizex * sizex + sizey * sizey);
00688 }
00689 }
00690
00691 VisionLookup[0] = 0;
00692 i = 1;
00693 VisionTablePosition = 0;
00694 while (i < maxsearchsize) {
00695
00696 VisionLookup[i] = VisionTablePosition;
00697
00698 VisionTable[0][VisionTablePosition] = i;
00699 VisionTable[1][VisionTablePosition] = 0;
00700 VisionTable[2][VisionTablePosition] = 0;
00701 ++VisionTablePosition;
00702
00703
00704
00705 marker = maxsize * i;
00706 direction = 0;
00707 right = 0;
00708 up = 0;
00709
00710
00711 do {
00712 repeat = 0;
00713 do {
00714
00715
00716 if ((repeat == 0 || direction == 1) && visionlist[marker + 1] == i) {
00717 right = 1;
00718 up = 0;
00719 ++repeat;
00720 direction = 1;
00721 ++marker;
00722 } else if ((repeat == 0 || direction == 2) && visionlist[marker - maxsize] == i) {
00723 up = 1;
00724 right = 0;
00725 ++repeat;
00726 direction = 2;
00727 marker = marker - maxsize;
00728 } else if ((repeat == 0 || direction == 3) && visionlist[marker + 1 - maxsize] == i &&
00729 visionlist[marker - maxsize] != i && visionlist[marker + 1] != i) {
00730 up = 1;
00731 right = 1;
00732 ++repeat;
00733 direction = 3;
00734 marker = marker + 1 - maxsize;
00735 } else {
00736 direction = 0;
00737 break;
00738 }
00739
00740
00741
00742
00743 } while (direction && marker > (maxsize * 2));
00744 if (right || up) {
00745 VisionTable[0][VisionTablePosition] = repeat;
00746 VisionTable[1][VisionTablePosition] = right;
00747 VisionTable[2][VisionTablePosition] = up;
00748 ++VisionTablePosition;
00749 }
00750 } while (marker > (maxsize * 2));
00751 ++i;
00752 }
00753
00754 delete[] visionlist;
00755 }
00756
00760 void FreeVisionTable(void)
00761 {
00762
00763 delete[] VisionTable[0];
00764 VisionTable[0] = NULL;
00765 delete[] VisionTable[1];
00766 VisionTable[1] = NULL;
00767 delete[] VisionTable[2];
00768 VisionTable[2] = NULL;
00769 delete[] VisionLookup;
00770 VisionLookup = NULL;
00771 }