mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2025-12-16 12:08:36 +00:00
805 lines
20 KiB
C++
805 lines
20 KiB
C++
#include "ht.h"
|
|
|
|
namespace wi {
|
|
|
|
FogMap::FogMap()
|
|
{
|
|
m_pbMap = NULL;
|
|
m_panidWalls = NULL;
|
|
memset(m_aptbm, 0, sizeof(m_aptbm));
|
|
memset(m_aptbmGalax, 0, sizeof(m_aptbmGalax));
|
|
|
|
// Each tile holds 4 bits. 0 is right most, 1 is top most, 2 is bottom most,
|
|
// 3 is left most
|
|
//
|
|
// Init the pattern results. The only reason a table exists
|
|
// (rather than using mask exclusively) is to disallow
|
|
// unwanted results. 1001 and 0110 are the only two illegal
|
|
// results with the current scheme.
|
|
|
|
for (byte bSrc = 0; bSrc < 16; bSrc++) {
|
|
for (byte bDst = 0; bDst < 16; bDst++) {
|
|
byte bRes = ~(~bDst & ~bSrc) & 0xf;
|
|
if (bRes == 9 || bRes == 6)
|
|
bRes = 0;
|
|
m_mpSrcDstResult[(((~bSrc) & 0xf) << 4) | bDst] = bRes;
|
|
}
|
|
}
|
|
}
|
|
|
|
FogMap::~FogMap()
|
|
{
|
|
delete m_panidWalls;
|
|
delete[] m_pbMap;
|
|
int n;
|
|
for (n = 0; n < 16; n++)
|
|
delete m_aptbm[n];
|
|
|
|
for (n = 0; n < 9; n++)
|
|
delete m_aptbmGalax[n];
|
|
}
|
|
|
|
bool FogMap::Init(Size *psizTile, Size *psizMap)
|
|
{
|
|
m_cxTile = psizTile->cx;
|
|
m_cyTile = psizTile->cy;
|
|
m_ctxMap = psizMap->cx / m_cxTile;
|
|
m_ctyMap = psizMap->cy / m_cyTile;
|
|
|
|
// Alloc the map and make it all "fogged" and Galaxite-free
|
|
|
|
int cb = m_ctxMap * m_ctyMap;
|
|
m_pbMap = new byte[cb];
|
|
Assert(m_pbMap != NULL, "out of memory!");
|
|
if (m_pbMap == NULL)
|
|
return false;
|
|
memset(m_pbMap, kbOpaque, cb);
|
|
|
|
// Load the edges
|
|
|
|
m_aptbm[15] = NULL;
|
|
m_aptbm[14] = LoadTBitmap("fog0001.tbm");
|
|
m_aptbm[13] = LoadTBitmap("fog0010.tbm");
|
|
m_aptbm[12] = LoadTBitmap("fog0011.tbm");
|
|
m_aptbm[11] = LoadTBitmap("fog0100.tbm");
|
|
m_aptbm[10] = LoadTBitmap("fog0101.tbm");
|
|
m_aptbm[9] = NULL;
|
|
m_aptbm[8] = LoadTBitmap("fog0111.tbm");
|
|
m_aptbm[7] = LoadTBitmap("fog1000.tbm");
|
|
m_aptbm[6] = NULL;
|
|
m_aptbm[5] = LoadTBitmap("fog1010.tbm");
|
|
m_aptbm[4] = LoadTBitmap("fog1011.tbm");
|
|
m_aptbm[3] = LoadTBitmap("fog1100.tbm");
|
|
m_aptbm[2] = LoadTBitmap("fog1101.tbm");
|
|
m_aptbm[1] = LoadTBitmap("fog1110.tbm");
|
|
m_aptbm[0] = LoadTBitmap("fog1111.tbm");
|
|
|
|
int c = 0;
|
|
int n;
|
|
for (n = 0; n < 16; n++) {
|
|
if (m_aptbm[n] == NULL)
|
|
c++;
|
|
}
|
|
if (c != 3)
|
|
return false;
|
|
|
|
m_aptbmGalax[0] = LoadTBitmap("galax1a.tbm");
|
|
m_aptbmGalax[1] = LoadTBitmap("galax1b.tbm");
|
|
m_aptbmGalax[2] = LoadTBitmap("galax1c.tbm");
|
|
m_aptbmGalax[3] = LoadTBitmap("galax2a.tbm");
|
|
m_aptbmGalax[4] = LoadTBitmap("galax2b.tbm");
|
|
m_aptbmGalax[5] = LoadTBitmap("galax2c.tbm");
|
|
m_aptbmGalax[6] = LoadTBitmap("galax3a.tbm");
|
|
m_aptbmGalax[7] = LoadTBitmap("galax3b.tbm");
|
|
m_aptbmGalax[8] = LoadTBitmap("galax3c.tbm");
|
|
|
|
|
|
for (n = 0; n < 9; n++) {
|
|
if (m_aptbmGalax[n] == NULL) {
|
|
Assert("Failed to load one of the Galaxite bitmaps");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Load the wall bitmaps
|
|
|
|
m_panidWalls = LoadAnimationData("walls.anir");
|
|
if (m_panidWalls == NULL) {
|
|
Assert("Failed to load wall.anir");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#define knVerFogMapState 4
|
|
bool FogMap::LoadState(Stream *pstm)
|
|
{
|
|
// Note at this point the fogmap has already been "initialized" from
|
|
// level constants so we just need to load in the contents of the map
|
|
// which includes both fog and galaxite state
|
|
|
|
byte nVer = pstm->ReadByte();
|
|
if (nVer != knVerFogMapState)
|
|
return false;
|
|
pstm->ReadBytesRLE(m_pbMap, m_ctxMap * m_ctyMap);
|
|
return pstm->IsSuccess();
|
|
}
|
|
|
|
bool FogMap::SaveState(Stream *pstm)
|
|
{
|
|
pstm->WriteByte(knVerFogMapState);
|
|
pstm->WriteBytesRLE(m_pbMap, m_ctxMap * m_ctyMap);
|
|
return pstm->IsSuccess();
|
|
}
|
|
|
|
bool FogMap::IsCovered(TRect *ptrc)
|
|
{
|
|
TRect trcMap;
|
|
trcMap.left = 0;
|
|
trcMap.top = 0;
|
|
trcMap.right = m_ctxMap;
|
|
trcMap.bottom = m_ctyMap;
|
|
TRect trcT = *ptrc;
|
|
if (!trcT.Intersect(&trcT, &trcMap)) {
|
|
return false;
|
|
}
|
|
|
|
for (int ty = trcT.top; ty < trcT.bottom; ty++) {
|
|
for (int tx = trcT.left; tx < trcT.right; tx++) {
|
|
byte bFog = m_pbMap[ty * m_ctxMap + tx] & kbfFogMask;
|
|
if (bFog != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void FogMap::RevealAll(UpdateMap *pupd)
|
|
{
|
|
byte *pbT = m_pbMap;
|
|
byte *pbEnd = m_pbMap + (m_ctxMap * m_ctyMap);
|
|
while (pbT < pbEnd) {
|
|
// *pbT++ = (*pbT & ~kbfFogMask) | kbEmpty;
|
|
// BUGBUG: if we post-increment pbT as above the CodeWarrior ARM compiler
|
|
// screws it up such that the RHS pbT is one byte ahead of the LHS pbT,
|
|
// the end result being that all the Galaxite in the map gets shifted one
|
|
// tile to the left!
|
|
|
|
*pbT = (*pbT & ~kbfFogMask) | kbEmpty;
|
|
pbT++;
|
|
}
|
|
|
|
// Invalidate the whole update map
|
|
|
|
pupd->InvalidateRect();
|
|
|
|
// Redraw the whole minimap
|
|
|
|
gpmm->Redraw();
|
|
}
|
|
|
|
void FogMap::Reveal(TRect *ptrc, UpdateMap *pupd, WCoord wxView, WCoord wyView)
|
|
{
|
|
int ctxT = ptrc->Width();
|
|
|
|
// Top row and corners
|
|
|
|
byte *pbDst = &m_pbMap[(ptrc->top * m_ctxMap) + ptrc->left];
|
|
int ctx = ctxT - 2;
|
|
*pbDst = *pbDst | (15 - 10);
|
|
pbDst++;
|
|
while (ctx-- > 0) {
|
|
// *pbDst++ = *pbDst | (15 - 2);
|
|
// BUGBUG: if we post-increment pbDst as above the CodeWarrior ARM compiler
|
|
// screws it up such that the RHS pbDst is one byte ahead of the LHS pbDst,
|
|
// the end result being that defog pattern isn't applied properly.
|
|
*pbDst = *pbDst | (15 - 2);
|
|
pbDst++;
|
|
}
|
|
*pbDst = *pbDst | (15 - 3);
|
|
|
|
// Bottom row and corners
|
|
|
|
pbDst = &m_pbMap[((ptrc->bottom - 1) * m_ctxMap) + ptrc->left];
|
|
ctx = ctxT - 2;
|
|
*pbDst = *pbDst | (15 - 12);
|
|
pbDst++;
|
|
while (ctx-- > 0) {
|
|
// *pbDst++ = *pbDst | (15 - 4);
|
|
// BUGBUG: if we post-increment pbDst as above the CodeWarrior ARM compiler
|
|
// screws it up such that the RHS pbDst is one byte ahead of the LHS pbDst,
|
|
// the end result being that defog pattern isn't applied properly.
|
|
*pbDst = *pbDst | (15 - 4);
|
|
pbDst++;
|
|
}
|
|
*pbDst = *pbDst | (15 - 5);
|
|
|
|
// Left column
|
|
|
|
pbDst = &m_pbMap[((ptrc->top + 1) * m_ctxMap) + ptrc->left];
|
|
ctx = ptrc->Height() - 2;
|
|
while (ctx-- > 0) {
|
|
// *pbDst++ = *pbDst | (15 - 8);
|
|
// BUGBUG: if we post-increment pbDst as above the CodeWarrior ARM compiler
|
|
// screws it up such that the RHS pbDst is one byte ahead of the LHS pbDst,
|
|
// the end result being that defog pattern isn't applied properly.
|
|
*pbDst = *pbDst | (15 - 8);
|
|
pbDst += m_ctxMap;
|
|
}
|
|
|
|
// Right column
|
|
|
|
pbDst = &m_pbMap[((ptrc->top + 1) * m_ctxMap) + ptrc->right - 1];
|
|
ctx = ptrc->Height() - 2;
|
|
while (ctx-- > 0) {
|
|
// *pbDst++ = *pbDst | (15 - 1);
|
|
// BUGBUG: if we post-increment pbDst as above the CodeWarrior ARM compiler
|
|
// screws it up such that the RHS pbDst is one byte ahead of the LHS pbDst,
|
|
// the end result being that defog pattern isn't applied properly.
|
|
*pbDst = *pbDst | (15 - 1);
|
|
pbDst += m_ctxMap;
|
|
}
|
|
|
|
// Interior
|
|
|
|
TRect trcT;
|
|
trcT = *ptrc;
|
|
trcT.Inflate(-1, -1);
|
|
ctxT = trcT.Width();
|
|
|
|
pbDst = &m_pbMap[(trcT.top * m_ctxMap) + trcT.left];
|
|
int cty = trcT.Height();
|
|
while (cty-- > 0) {
|
|
ctx = ctxT;
|
|
while (ctx-- > 0) {
|
|
*pbDst = *pbDst | kbEmpty;
|
|
pbDst++;
|
|
}
|
|
pbDst += m_ctxMap - ctxT;
|
|
}
|
|
|
|
// Invalidate
|
|
|
|
gpmm->RedrawTRect(ptrc);
|
|
Rect rcT;
|
|
rcT.FromTileRect(ptrc);
|
|
int xView = PcFromWc(wxView) & 0xfffe;
|
|
int yView = PcFromWc(wyView) & 0xfffe;
|
|
rcT.Offset(-xView, -yView);
|
|
pupd->InvalidateRect(&rcT);
|
|
}
|
|
|
|
void FogMap::Reveal(TCoord txMap, TCoord tyMap, RevealPattern *prvlp, UpdateMap *pupd, WCoord wxView, WCoord wyView)
|
|
{
|
|
Assert(txMap >= 0 && txMap < m_ctxMap && tyMap >= 0 && tyMap < m_ctyMap);
|
|
|
|
// RevealPattern is centered around txMap and tyMap
|
|
|
|
int ctx = prvlp->ctx;
|
|
int cty = prvlp->cty;
|
|
int tx = txMap - ctx / 2;
|
|
int ty = tyMap - cty / 2;
|
|
|
|
// Clip to map edges
|
|
|
|
int txPattern = 0;
|
|
int tyPattern = 0;
|
|
|
|
if (tx < 0) {
|
|
ctx = tx + ctx;
|
|
txPattern = -tx;
|
|
tx = 0;
|
|
}
|
|
if (ty < 0) {
|
|
cty = ty + cty;
|
|
tyPattern = -ty;
|
|
ty = 0;
|
|
}
|
|
if (tx + ctx > m_ctxMap)
|
|
ctx = m_ctxMap - tx;
|
|
if (ty + cty > m_ctyMap)
|
|
cty = m_ctyMap - ty;
|
|
|
|
Assert(ctx > 0 && ctx <= prvlp->ctx && cty > 0 && cty <= prvlp->cty);
|
|
|
|
// Reveal
|
|
|
|
int cbNextSrc = prvlp->ctx - ctx;
|
|
int cbNextDst = m_ctxMap - ctx;
|
|
byte *pbDst = &m_pbMap[ty * m_ctxMap + tx];
|
|
byte *pbSrc = &prvlp->ab[tyPattern * prvlp->ctx + txPattern];
|
|
bool fChanged = false;
|
|
for (int tyT = ty; tyT < ty + cty; tyT++) {
|
|
for (int txT = tx; txT < tx + ctx; txT++) {
|
|
byte bDst = *pbDst;
|
|
byte bDstNew = (*pbDst & ~kbfFogMask) | m_mpSrcDstResult[((*pbSrc) << 4) | (*pbDst & kbfFogMask)];
|
|
if (bDst != bDstNew) {
|
|
*pbDst = bDstNew;
|
|
pupd->InvalidateTile(txT, tyT);
|
|
gpmm->RedrawTile(txT, tyT);
|
|
}
|
|
pbDst++;
|
|
pbSrc++;
|
|
}
|
|
pbSrc += cbNextSrc;
|
|
pbDst += cbNextDst;
|
|
}
|
|
}
|
|
|
|
void FogMap::Draw(DibBitmap *pbm, int xMap, int yMap, UpdateMap *pupd)
|
|
{
|
|
Size siz;
|
|
pbm->GetSize(&siz);
|
|
Rect rcDib;
|
|
rcDib.left = 0;
|
|
rcDib.top = 0;
|
|
rcDib.right = siz.cx;
|
|
rcDib.bottom = siz.cy;
|
|
|
|
int tx = xMap / gcxTile;
|
|
int ty = yMap / gcyTile;
|
|
int ctx = (siz.cx + (gcxTile - 1)) / gcxTile + 1;
|
|
if (tx + ctx > m_ctxMap)
|
|
ctx = m_ctxMap - tx;
|
|
int cty = (siz.cy + (gcyTile - 1)) / gcyTile + 1;
|
|
if (ty + cty > m_ctyMap)
|
|
cty = m_ctyMap - ty;
|
|
Color clrBlack = GetColor(kiclrBlack);
|
|
|
|
bool *pfInvalid = pupd->GetInvalidMap();
|
|
Size sizMap;
|
|
pupd->GetMapSize(&sizMap);
|
|
int cfInvalidNextScan = sizMap.cx - ctx;
|
|
Assert(sizMap.cx >= ctx && sizMap.cy >= cty);
|
|
|
|
byte *pbDib = pbm->GetBits();
|
|
byte *pbMapT = &m_pbMap[ty * m_ctxMap + tx];
|
|
int cbNextScan = m_ctxMap - ctx;
|
|
int xTile = tx * gcxTile - xMap;
|
|
int yTile = ty * gcyTile - yMap;
|
|
int xTileStart = xTile;
|
|
for (int tyT = ty; tyT < ty + cty; tyT++) {
|
|
int cEmpty = 0;
|
|
int xStart;
|
|
for (int txT = tx; txT < tx + ctx; txT++) {
|
|
byte bFog = *pbMapT++ & kbfFogMask;
|
|
if (*pfInvalid++ == false)
|
|
bFog = kbEmpty;
|
|
|
|
// Opaque?
|
|
|
|
if (bFog == kbOpaque) {
|
|
if (cEmpty == 0)
|
|
xStart = xTile;
|
|
cEmpty++;
|
|
xTile += gcxTile;
|
|
continue;
|
|
}
|
|
|
|
// Not opaque; fill block if there is one
|
|
|
|
if (cEmpty != 0) {
|
|
pbm->Fill(xStart, yTile, cEmpty * gcxTile, gcyTile, clrBlack);
|
|
cEmpty = 0;
|
|
#ifdef PIL
|
|
if (gfOS5Pa1Device)
|
|
HostSoundServiceProc();
|
|
#endif
|
|
}
|
|
|
|
// Not opaque; draw unique tile
|
|
|
|
TBitmap *ptbm = m_aptbm[bFog];
|
|
if (ptbm == NULL) {
|
|
xTile += gcxTile;
|
|
continue;
|
|
}
|
|
|
|
ptbm->BltTo(pbm, xTile, yTile);
|
|
xTile += gcxTile;
|
|
}
|
|
if (cEmpty != 0) {
|
|
pbm->Fill(xStart, yTile, cEmpty * gcxTile, gcyTile, clrBlack);
|
|
cEmpty = 0;
|
|
|
|
#ifdef PIL
|
|
if (gfOS5Pa1Device)
|
|
HostSoundServiceProc();
|
|
#endif
|
|
}
|
|
|
|
pbMapT += cbNextScan;
|
|
pfInvalid += cfInvalidNextScan;
|
|
yTile += gcxTile;
|
|
xTile = xTileStart;
|
|
}
|
|
}
|
|
|
|
byte s_abGxTranslate[] = { 0, 2, 1, 1, 0, 0, 5, 4, 4, 3, 3, 8, 7, 7, 6, 6 };
|
|
byte s_abGxInc[] = { 0, 2, 3, 4, 5, 5, 7, 8, 9, 10, 10, 12, 13, 14, 15, 15 };
|
|
byte s_abGxDec[] = { 0, 0, 1, 2, 3, 4, 0, 6, 7, 8, 9, 0, 11, 12, 13, 14 };
|
|
|
|
void FogMap::DrawGalaxite(DibBitmap *pbm, int xMap, int yMap, UpdateMap *pupd, byte *pbTrMap)
|
|
{
|
|
Size siz;
|
|
pbm->GetSize(&siz);
|
|
Rect rcDib;
|
|
rcDib.left = 0;
|
|
rcDib.top = 0;
|
|
rcDib.right = siz.cx;
|
|
rcDib.bottom = siz.cy;
|
|
|
|
int tx = xMap / gcxTile;
|
|
int ty = yMap / gcyTile;
|
|
int ctx = (siz.cx + (gcxTile - 1)) / gcxTile + 1;
|
|
if (tx + ctx > m_ctxMap)
|
|
ctx = m_ctxMap - tx;
|
|
int cty = (siz.cy + (gcyTile - 1)) / gcyTile + 1;
|
|
if (ty + cty > m_ctyMap)
|
|
cty = m_ctyMap - ty;
|
|
byte *pbDib = pbm->GetBits();
|
|
byte *pbMapT = &m_pbMap[ty * m_ctxMap + tx];
|
|
int cbNextScan = m_ctxMap - ctx;
|
|
int xTile = tx * gcxTile - xMap;
|
|
int yTile = ty * gcyTile - yMap;
|
|
int xTileStart = xTile;
|
|
|
|
bool *pfInvalid = pupd->GetInvalidMap();
|
|
Size sizMap;
|
|
pupd->GetMapSize(&sizMap);
|
|
int cfInvalidNextScan = sizMap.cx - ctx;
|
|
Assert(sizMap.cx >= ctx && sizMap.cy >= cty);
|
|
int nServiceSfx = 0;
|
|
|
|
for (int tyT = ty; tyT < ty + cty; tyT++) {
|
|
for (int txT = tx; txT < tx + ctx; txT++, pbMapT++) {
|
|
byte b = *pbMapT;
|
|
if (*pfInvalid++ == false) {
|
|
xTile += gcxTile;
|
|
continue;
|
|
}
|
|
|
|
// Is no Galaxite/Wall present or is this tile completely obscured by fog?
|
|
|
|
byte *ptt = &pbTrMap[pbMapT - m_pbMap];
|
|
if (((b & kbfGalaxiteMask) == 0 && *ptt != kttWall) || IsFogOpaque(b)) {
|
|
xTile += gcxTile;
|
|
continue;
|
|
}
|
|
|
|
// Galaxite?
|
|
|
|
if (HasGalaxite(b)) {
|
|
// Galaxite
|
|
|
|
TBitmap *ptbm = m_aptbmGalax[s_abGxTranslate[(b & kbfGalaxiteMask) >> kcGalaxiteShift]];
|
|
ptbm->BltTo(pbm, xTile, yTile);
|
|
|
|
#ifdef PIL
|
|
if (gfOS5Pa1Device) {
|
|
nServiceSfx++;
|
|
if ((nServiceSfx & 31) == 0)
|
|
HostSoundServiceProc();
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
// Wall?
|
|
|
|
if (*ptt == kttWall) {
|
|
|
|
#define HasWall(tt) ((tt) == kttWall)
|
|
|
|
// Check neighbor cells for walls to decide what shape this
|
|
// segment should take.
|
|
|
|
int ifrm = 0;
|
|
if (tyT > 0) {
|
|
if (HasWall(*(ptt - m_ctxMap)))
|
|
ifrm |= 1;
|
|
}
|
|
if (txT < m_ctxMap - 1) {
|
|
if (HasWall(*(ptt + 1)))
|
|
ifrm |= 2;
|
|
}
|
|
if (tyT < m_ctyMap - 1) {
|
|
if (HasWall(*(ptt + m_ctxMap)))
|
|
ifrm |= 4;
|
|
}
|
|
if (txT > 0) {
|
|
if (HasWall(*(ptt - 1)))
|
|
ifrm |= 8;
|
|
}
|
|
|
|
// The kwfWallMask >> 1 test makes walls with less than half their health
|
|
// draw from the 'damaged' strip.
|
|
|
|
// m_panidWalls->DrawFrame(w <= (kwfWallMask >> 1) ? 1 : 0, ifrm, pbm, xTile, yTile, ksideNeutral);
|
|
m_panidWalls->DrawFrame(0, ifrm, pbm, xTile, yTile, ksideNeutral);
|
|
|
|
#ifdef PIL
|
|
if (gfOS5Pa1Device) {
|
|
nServiceSfx++;
|
|
if ((nServiceSfx & 31) == 0)
|
|
HostSoundServiceProc();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
xTile += gcxTile;
|
|
}
|
|
|
|
pfInvalid += cfInvalidNextScan;
|
|
pbMapT += cbNextScan;
|
|
yTile += gcxTile;
|
|
xTile = xTileStart;
|
|
}
|
|
}
|
|
|
|
void FogMap::SetGalaxite(int nGx, TCoord tx, TCoord ty)
|
|
{
|
|
Assert(tx >= 0 && ty >= 0 && tx < m_ctxMap && ty < m_ctyMap);
|
|
|
|
byte *pb = &m_pbMap[(ty * m_ctxMap) + tx];
|
|
*pb = (*pb & ~kbfGalaxiteMask) | (nGx << kcGalaxiteShift);
|
|
}
|
|
|
|
int FogMap::GetGalaxite(TCoord tx, TCoord ty)
|
|
{
|
|
// Any attempt to look for Galaxite off the edge of the map returns none
|
|
|
|
if (tx < 0 || ty < 0 || tx >= m_ctxMap || ty >= m_ctyMap)
|
|
return 0;
|
|
|
|
byte *pb = &m_pbMap[(ty * m_ctxMap) + tx];
|
|
int nGx = (*pb & kbfGalaxiteMask) >> kcGalaxiteShift;
|
|
|
|
#ifdef MP_DEBUG
|
|
// MpTrace("GetGalaxite:%d,%d amount %d", tx, ty, nGx);
|
|
#endif
|
|
|
|
return nGx;
|
|
}
|
|
|
|
void FogMap::IncGalaxite(TCoord tx, TCoord ty)
|
|
{
|
|
Assert(tx >= 0 && ty >= 0 && tx < m_ctxMap && ty < m_ctyMap);
|
|
|
|
byte *pb = &m_pbMap[(ty * m_ctxMap) + tx];
|
|
*pb = (*pb & ~kbfGalaxiteMask) | (s_abGxInc[(*pb & kbfGalaxiteMask) >> kcGalaxiteShift] << kcGalaxiteShift);
|
|
|
|
// Cause this tile to redraw
|
|
|
|
if (gptrcMapOpaque == NULL || !gptrcMapOpaque->PtIn(tx, ty))
|
|
gpupdSim->InvalidateTile(tx, ty);
|
|
if (gpmm != NULL)
|
|
gpmm->RedrawTile(tx, ty);
|
|
}
|
|
|
|
bool FogMap::DecGalaxite(TCoord tx, TCoord ty)
|
|
{
|
|
Assert(tx >= 0 && ty >= 0 && tx < m_ctxMap && ty < m_ctyMap);
|
|
|
|
byte *pb = &m_pbMap[(ty * m_ctxMap) + tx];
|
|
byte bNew = s_abGxDec[(*pb & kbfGalaxiteMask) >> kcGalaxiteShift] << kcGalaxiteShift;
|
|
*pb = (*pb & ~kbfGalaxiteMask) | bNew;
|
|
#ifdef MP_DEBUG
|
|
// MpTrace("DecGalaxite:%d,%d now %d", tx, ty, bNew >> kcGalaxiteShift);
|
|
#endif
|
|
|
|
// Cause this tile to redraw
|
|
|
|
if (gptrcMapOpaque == NULL || !gptrcMapOpaque->PtIn(tx, ty))
|
|
gpupdSim->InvalidateTile(tx, ty);
|
|
if (gpmm != NULL)
|
|
gpmm->RedrawTile(tx, ty);
|
|
|
|
return bNew != 0;
|
|
}
|
|
|
|
bool FogMap::FindNearestGalaxite(TCoord txOrigin, TCoord tyOrigin, TPoint *ptpt, bool fIgnoreFog)
|
|
{
|
|
Assert(txOrigin >= 0 && tyOrigin >= 0 && txOrigin < m_ctxMap && tyOrigin < m_ctyMap);
|
|
|
|
#if 1
|
|
TPoint *atptGx = (TPoint *)gpbScratch;
|
|
#else
|
|
TPoint atptT[sizeof(TPoint) * ktcMax * 4]; // 1024 bytes, these days
|
|
TPoint *atptGx = atptT;
|
|
#endif
|
|
TPoint *ptptGx = atptGx;
|
|
int ctptGx;
|
|
|
|
int nMax1 = _max((int)txOrigin, m_ctxMap - txOrigin);
|
|
int nMax2 = _max((int)tyOrigin, m_ctyMap - tyOrigin);
|
|
int nRadiusMax = _max(nMax1, nMax2);
|
|
|
|
for (int nRadius = 1; nRadius < nRadiusMax; nRadius++) {
|
|
|
|
// We treat Galaxite directly under the Miner as being
|
|
// the equivalent of 2.5 tiles away.
|
|
|
|
if (nRadius == 3) {
|
|
byte *pb = &m_pbMap[(tyOrigin * m_ctxMap) + txOrigin];
|
|
if (HasGalaxite(*pb)) {
|
|
ptpt->tx = txOrigin;
|
|
ptpt->ty = tyOrigin;
|
|
// MpTrace(" -- found %d, %d", txOrigin, tyOrigin);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// look for galaxite across the top
|
|
|
|
TCoord txMin = txOrigin - nRadius;
|
|
if (txMin < 0)
|
|
txMin = 0;
|
|
TCoord txMax = txOrigin + nRadius;
|
|
if (txMax > m_ctxMap)
|
|
txMax = m_ctxMap;
|
|
|
|
TCoord tx, ty;
|
|
ty = tyOrigin - nRadius;
|
|
if (ty >= 0) {
|
|
byte *pb = &m_pbMap[(ty * m_ctxMap) + txMin];
|
|
for (tx = txMin; tx < txMax; tx++, pb++) {
|
|
if (!HasGalaxite(*pb)) // Galaxite?
|
|
continue; // no
|
|
if (IsFogOpaque(*pb) && !fIgnoreFog) // Fogged?
|
|
continue; // yes
|
|
// MpTrace(" t %d, %d, 0x%lx", tx, ty, ptptGx);
|
|
ptptGx->tx = tx;
|
|
ptptGx->ty = ty;
|
|
ptptGx++;
|
|
}
|
|
}
|
|
|
|
// look for galaxite across the bottom
|
|
|
|
txMax += 1;
|
|
if (txMax > m_ctxMap)
|
|
txMax = m_ctxMap;
|
|
txMin = txOrigin - nRadius + 1;
|
|
if (txMin < 0)
|
|
txMin = 0;
|
|
|
|
ty = tyOrigin + nRadius;
|
|
if (ty < m_ctyMap) {
|
|
byte *pb = &m_pbMap[(ty * m_ctxMap) + txMin];
|
|
for (tx = txMin; tx < txMax; tx++, pb++) {
|
|
if (!HasGalaxite(*pb))
|
|
continue;
|
|
if (IsFogOpaque(*pb) && !fIgnoreFog)
|
|
continue;
|
|
// MpTrace(" b %d, %d, 0x%lx", tx, ty, ptptGx);
|
|
ptptGx->tx = tx;
|
|
ptptGx->ty = ty;
|
|
ptptGx++;
|
|
}
|
|
}
|
|
|
|
// look for galaxite down the right side
|
|
|
|
TCoord tyMin = tyOrigin - nRadius;
|
|
if (tyMin < 0)
|
|
tyMin = 0;
|
|
TCoord tyMax = tyOrigin + nRadius;
|
|
if (tyMax > m_ctyMap)
|
|
tyMax = m_ctyMap;
|
|
|
|
tx = txOrigin + nRadius;
|
|
if (tx < m_ctxMap) {
|
|
byte *pb = &m_pbMap[(tyMin * m_ctxMap) + tx];
|
|
for (ty = tyMin; ty < tyMax; ty++, pb += m_ctxMap) {
|
|
if (!HasGalaxite(*pb))
|
|
continue;
|
|
if (IsFogOpaque(*pb) && !fIgnoreFog)
|
|
continue;
|
|
// MpTrace(" r %d, %d, 0x%lx", tx, ty, ptptGx);
|
|
ptptGx->tx = tx;
|
|
ptptGx->ty = ty;
|
|
ptptGx++;
|
|
}
|
|
}
|
|
|
|
// look for galaxite down the left side
|
|
|
|
tyMin = tyOrigin - nRadius + 1;
|
|
if (tyMin < 0)
|
|
tyMin = 0;
|
|
tyMax += 1;
|
|
if (tyMax > m_ctyMap)
|
|
tyMax = m_ctyMap;
|
|
|
|
tx = txOrigin - nRadius;
|
|
if (tx >= 0) {
|
|
byte *pb = &m_pbMap[(tyMin * m_ctxMap) + tx];
|
|
for (ty = tyMin; ty < tyMax; ty++, pb += m_ctxMap) {
|
|
if (!HasGalaxite(*pb))
|
|
continue;
|
|
if (IsFogOpaque(*pb) && !fIgnoreFog)
|
|
continue;
|
|
// MpTrace(" l %d, %d, 0x%lx", tx, ty, ptptGx);
|
|
ptptGx->tx = tx;
|
|
ptptGx->ty = ty;
|
|
ptptGx++;
|
|
}
|
|
}
|
|
|
|
// If Galaxite has been found at this radius randomly pick one
|
|
// of the found locations and return it.
|
|
|
|
if (ptptGx != atptGx) {
|
|
ctptGx = (int)(ptptGx - atptGx);
|
|
int i = GetRandom() % ctptGx;
|
|
*ptpt = atptGx[i];
|
|
// MpTrace(" -- found %d, %d, 0x%lx [%d of %d]", ptpt->tx, ptpt->ty, &atptGx[i], i, ctptGx);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// MpTrace(" -- found none");
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Wall methods
|
|
//
|
|
|
|
#if 0
|
|
int FogMap::GetWallHealth(TCoord tx, TCoord ty)
|
|
{
|
|
// Any attempt to look for wall off the edge of the map returns none
|
|
|
|
if (tx < 0 || ty < 0 || tx >= m_ctxMap || ty >= m_ctyMap)
|
|
return 0;
|
|
|
|
word *pw = &m_pwMap[(ty * m_ctxMap) + tx];
|
|
return (*pw & kwfWallMask) >> kcWallShift;
|
|
}
|
|
|
|
void FogMap::SetWallHealth(int nHealth, TCoord tx, TCoord ty)
|
|
{
|
|
// If state changes between existing and not existing then the N/S/E/W
|
|
// neighbor cells need to be invalidated if they also contain a wall
|
|
// segment.
|
|
|
|
Assert(tx >= 0 && ty >= 0 && tx < m_ctxMap && ty < m_ctyMap);
|
|
|
|
word *pw = &m_pwMap[(ty * m_ctxMap) + tx];
|
|
word wOld = *pw;
|
|
word wNew = (wOld & ~kwfWallMask) | (word)(nHealth << kcWallShift);
|
|
|
|
if (wNew != wOld) {
|
|
*pw = wNew;
|
|
|
|
// UNDONE: whoa! Spaghetti! FogMap should not be reaching out to sim/level/etc
|
|
TerrainMap *ptrmap = gsim.GetLevel()->GetTerrainMap();
|
|
if (nHealth == 0)
|
|
ptrmap->ClearFlags(tx, ty, 1, 1, kbfStructure);
|
|
else
|
|
ptrmap->SetFlags(tx, ty, 1, 1, kbfStructure);
|
|
|
|
#if 0
|
|
// UNDONE: right now there is no dynamic changing of a wall's health so we don't
|
|
// need this stuff. If we allow damaging/destroying walls or give the player the
|
|
// ability to create walls we'll need to deal with this.
|
|
|
|
// Cause this tile to redraw
|
|
|
|
if (gptrcMapOpaque == NULL || !gptrcMapOpaque->PtIn(tx, ty))
|
|
gpupdSim->InvalidateTile(tx, ty);
|
|
if (gpmm != NULL)
|
|
gpmm->RedrawTile(tx, ty);
|
|
|
|
// UNDONE: deal with neighbors
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
} // namespace wi
|