Files
2026-02-02 04:50:13 +01:00

826 lines
25 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/str.h"
#include "common/textconsole.h"
#include "scumm/he/moonbase/map_mif.h"
namespace Scumm {
static const byte waterTileMap[] = {
0x44, 0x40, 0x32, 0x32, 0x3C, 0x38, 0x32, 0x32, // 0x00
0x2C, 0x2C, 0x26, 0x26, 0x2A, 0x2A, 0x26, 0x26,
0x2F, 0x2D, 0x27, 0x27, 0x2F, 0x2D, 0x27, 0x27, // 0x10
0x1B, 0x1B, 0x49, 0x49, 0x1B, 0x1B, 0x49, 0x49,
0x42, 0x3E, 0x30, 0x30, 0x3A, 0x36, 0x30, 0x30, // 0x20
0x2C, 0x2C, 0x26, 0x26, 0x2A, 0x2A, 0x26, 0x26,
0x2E, 0x22, 0x1E, 0x1E, 0x2E, 0x22, 0x1E, 0x1E, // 0x30
0x1B, 0x1B, 0x49, 0x49, 0x1B, 0x1B, 0x49, 0x49,
0x35, 0x33, 0x1C, 0x1C, 0x34, 0x24, 0x1C, 0x1C, // 0x40
0x28, 0x28, 0x4B, 0x4B, 0x1F, 0x1F, 0x4B, 0x4B,
0x29, 0x20, 0x4C, 0x4C, 0x29, 0x20, 0x4C, 0x4C, // 0x50
0x48, 0x48, 0x4A, 0x4A, 0x48, 0x48, 0x4A, 0x4A,
0x35, 0x33, 0x1C, 0x1C, 0x34, 0x24, 0x1C, 0x1C, // 0x60
0x28, 0x28, 0x4B, 0x4B, 0x1F, 0x1F, 0x4B, 0x4B,
0x29, 0x20, 0x4C, 0x4C, 0x29, 0x20, 0x4C, 0x4C, // 0x70
0x48, 0x48, 0x4A, 0x4A, 0x48, 0x48, 0x4A, 0x4A,
0x43, 0x3F, 0x31, 0x31, 0x3B, 0x37, 0x31, 0x31, // 0x80
0x2B, 0x2B, 0x1D, 0x1D, 0x21, 0x21, 0x1D, 0x1D,
0x2F, 0x2D, 0x27, 0x27, 0x2F, 0x2D, 0x27, 0x27, // 0x90
0x1B, 0x1B, 0x49, 0x49, 0x1B, 0x1B, 0x49, 0x49,
0x41, 0x3D, 0x23, 0x23, 0x39, 0x25, 0x23, 0x23, // 0xA0
0x2B, 0x2B, 0x1D, 0x1D, 0x21, 0x21, 0x1D, 0x1D,
0x2E, 0x22, 0x1E, 0x1E, 0x2E, 0x22, 0x1E, 0x1E, // 0xB0
0x1B, 0x1B, 0x49, 0x49, 0x1B, 0x1B, 0x49, 0x49,
0x35, 0x33, 0x1C, 0x1C, 0x34, 0x24, 0x1C, 0x1C, // 0xC0
0x28, 0x28, 0x4B, 0x4B, 0x1F, 0x1F, 0x4B, 0x4B,
0x29, 0x20, 0x4C, 0x4C, 0x29, 0x20, 0x4C, 0x4C, // 0xD0
0x48, 0x48, 0x4A, 0x4A, 0x48, 0x48, 0x4A, 0x4A,
0x35, 0x33, 0x1C, 0x1C, 0x34, 0x24, 0x1C, 0x1C, // 0xE0
0x28, 0x28, 0x4B, 0x4B, 0x1F, 0x1F, 0x4B, 0x4B,
0x29, 0x20, 0x4C, 0x4C, 0x29, 0x20, 0x4C, 0x4C, // 0xF0
0x48, 0x48, 0x4A, 0x4A, 0x48, 0x48, 0x4A, 0x4A
};
static int magic(int x, int y) {
static const byte matrix[8][8] = {
{ 2, 0, 2, 1, 3, 0, 3, 1 } ,
{ 3, 1, 0, 3, 2, 1, 0, 2 } ,
{ 0, 2, 1, 2, 0, 3, 1, 3 } ,
{ 1, 3, 0, 3, 1, 2, 0, 2 } ,
{ 2, 0, 1, 2, 3, 0, 1, 3 } ,
{ 3, 1, 3, 0, 2, 1, 2, 0 } ,
{ 0, 2, 0, 1, 3, 0, 3, 2 } ,
{ 1, 3, 0, 3, 2, 1, 2, 0 }
};
return matrix[y % 8][x % 8];
}
MIF::MIF() {
}
void MIF::generateMap(MapFile *map) {
map->terrainDimX = _dimension;
map->terrainDimY = _dimension;
map->mapType = _mapType;
Common::strlcpy(map->name, _name, 17);
int x, y;
for (y = 0; y < _dimension; ++y) {
for (x = 0; x < _dimension; ++x) {
map->terrainStates[x][y] = findTileFor(x, y);
}
}
defineEnergyPools(map);
defineStartLocations(map);
makeCraters(map);
}
void MIF::defineStartLocations(MapFile *map) {
int x, y;
for (y = 0; y < _dimension; ++y) {
for (x = 0; x < _dimension; ++x) {
int8 ch = _centerMap[x][y];
if (ch < 0) {
int i;
ch = -ch;
if (ch & 1) {
// 4 player start
i = 0;
while (i < 4) {
if (map->fourPlayerPoints[i].x == 0xFFFF) {
map->fourPlayerPoints[i].x = x * 60;
map->fourPlayerPoints[i].y = y * 60;
break;
}
++i;
}
}
ch = ch >> 1;
if (ch & 1) {
// 3 player start
i = 0;
while (i < 3) {
if (map->threePlayerPoints[i].x == 0xFFFF) {
map->threePlayerPoints[i].x = x * 60;
map->threePlayerPoints[i].y = y * 60;
break;
}
++i;
}
}
ch = ch >> 1;
if (ch & 1) {
// 2 player start
i = 0;
while (i < 2) {
if (map->twoPlayerPoints[i].x == 0xFFFF) {
map->twoPlayerPoints[i].x = x * 60;
map->twoPlayerPoints[i].y = y * 60;
break;
}
++i;
}
}
ch = ch >> 1;
if (ch & 1) {
// 2v2 player start
i = 0;
while (i < 4) {
if (map->twoVTwoPoints[i].x == 0xFFFF) {
map->twoVTwoPoints[i].x = x * 60;
map->twoVTwoPoints[i].y = y * 60;
break;
}
++i;
}
}
ch = ch >> 1;
if (ch & 1) {
// 1v3 player start
i = 0;
while (i < 4) {
if (map->oneVThreePoints[i].x == 0xFFFF) {
map->oneVThreePoints[i].x = x * 60;
map->oneVThreePoints[i].y = y * 60;
break;
}
++i;
}
}
ch = ch >> 1;
if (ch & 1) {
// 1v2 player start
i = 0;
while (i < 3) {
if (map->oneVTwoPoints[i].x == 0xFFFF) {
map->oneVTwoPoints[i].x = x * 60;
map->oneVTwoPoints[i].y = y * 60;
break;
}
++i;
}
}
}
}
}
}
void MIF::defineEnergyPools(MapFile *map) {
int x, y;
for (y = 0; y < _dimension; ++y) {
for (x = 0; x < _dimension; ++x) {
char ch = _centerMap[x][y];
if ('S' == ch || 'M' == ch || 'L' == ch) {
// Verify legal position
if (!((tlCorner(x, y) == trCorner(x, y)) && (blCorner(x, y) == brCorner(x, y)) &&
(tlCorner(x, y) == blCorner(x, y)) && (trCorner(x, y) == brCorner(x, y)))) {
error("small and medium energy pools must be on a flat tile (%d, %d)", x, y);
}
if ('L' == ch) {
byte nHeight;
nHeight = blCorner(x, y);
if (!(tlCorner(x, y) == nHeight && ttlCorner(x, y) == nHeight && ttrCorner(x, y) == nHeight && trCorner(x, y) == nHeight && brCorner(x, y) == nHeight)) {
error("large energy pools must be on the lower of two flat tiles (%d, %d)", x, y);
}
}
int xLoc;
int yLoc;
if ('S' == ch) {
xLoc = 60 * x + 30 + 20000;
yLoc = 60 * y + 30;
} else if ('M' == ch) {
xLoc = 60 * x + 30 + 10000;
yLoc = 60 * y + 30;
} else {
xLoc = 60 * x + 30;
yLoc = 60 * y;
}
if (map->numEnergyPools < 49) {
map->poolLocs[map->numEnergyPools].location.x = xLoc;
map->poolLocs[map->numEnergyPools].location.y = yLoc;
++map->numEnergyPools;
} else if (map->numEnergyPools == 49) {
map->lastPool.x = xLoc;
map->lastPool.y = yLoc;
++map->numEnergyPools;
} else {
error("only 50 energy pools are allowed, this is the 51st (%d, %d)", x, y);
}
}
}
}
}
void MIF::makeCraters(MapFile *map) {
// squarenumber, type, x, y (offset from top left (abs y)). x/y = 9 if none of that type
static const byte locations[8][3][2] = {
{ {1, 1}, {5, 2}, {3, 5} },
{ {6, 1}, {1, 6}, {2, 0} },
{ {0, 4}, {3, 2}, {6, 5} },
{ {4, 4}, {5, 0}, {9, 9} },
{ {3, 6}, {9, 9}, {2, 1} },
{ {9, 9}, {3, 3}, {0, 2} },
{ {2, 4}, {0, 0}, {5, 3} },
{ {4, 1}, {0, 3}, {5, 6} }
};
// I made up the crater patterns for sizes larger than SAI
// This will work for maps up to 80x80
static byte const largegrid[10][10] = {
{0, 1, 2, 3, 4, 5, 6, 7, 0, 1},
{2, 3, 4, 5, 6, 7, 0, 1, 2, 3},
{4, 5, 6, 7, 0, 1, 2, 3, 4, 5},
{3, 0, 1, 2, 6, 4, 5, 7, 3, 0},
{1, 2, 3, 4, 5, 6, 7, 0, 1, 2},
{3, 4, 5, 6, 7, 0, 1, 2, 3, 4},
{6, 3, 0, 1, 2, 7, 4, 5, 6, 3},
{5, 6, 7, 0, 1, 2, 3, 4, 5, 6},
{0, 1, 2, 3, 4, 5, 6, 7, 0, 1},
{2, 3, 4, 5, 6, 7, 0, 1, 2, 3}
};
for (int i = 0; i < _dimension / 8; i++) {
for (int j = 0; j < _dimension / 8; j++) {
for (int nCrater = 0; nCrater < 3; nCrater++) {
if (9 == locations[largegrid[j][i]][nCrater][0]) {
continue;
}
int x = locations[largegrid[j][i]][nCrater][0] + i * 8;
int y = locations[largegrid[j][i]][nCrater][1] + j * 8;
byte nLevel = tlCorner(x, y);
if ((tlCorner(x, y) == nLevel) && (trCorner(x, y) == nLevel) && (trrCorner(x, y) == nLevel) &&
(_centerMap[x][y] != 'W') && (_centerMap[x + 1][y] != 'W') &&
(blCorner(x, y) == nLevel) && (brCorner(x, y) == nLevel) && (brrCorner(x, y) == nLevel) &&
(_centerMap[x][y + 1] != 'W') && (_centerMap[x + 1][y + 1] != 'W') &&
(bblCorner(x, y) == nLevel) && (bbrCorner(x, y) == nLevel) && (bbrrCorner(x, y) == nLevel)) {
// The tile values follow a predictable pattern, level one craters in order, etc.
int16 nBase = 0xA6 + (tlCorner(x, y) * 12) + (nCrater * 4);
map->terrainStates[x][y] = nBase;
map->terrainStates[x + 1][y] = nBase + 1;
map->terrainStates[x][y + 1] = nBase + 2;
map->terrainStates[x + 1][y + 1] = nBase + 3;
}
}
}
}
}
uint16 MIF::findTileFor(int x, int y) {
int index;
int8 ch;
byte aLowBlanks[] = {0x93, 0x94, 0x00, 0x96};
byte aMedBlanks[] = {0x97, 0x99, 0x0D, 0x9A};
byte aHiBlanks[] = {0x9B, 0x9C, 0x1A, 0x9D};
ch = _centerMap[x][y];
debug(5, "MIF: Tile for %d, %d is %c", x, y, ch);
if ('S' == ch || 'M' == ch || 'L' == ch || '.' == ch || ch < 0) {
// Do the easy cases, things with no transitions.
if (0 == tlCorner(x, y) && 0 == trCorner(x, y) && 0 == blCorner(x, y) && 0 == brCorner(x, y))
return aLowBlanks[magic(x, y)];
if (1 == tlCorner(x, y) && 1 == trCorner(x, y) && 1 == blCorner(x, y) && 1 == brCorner(x, y))
return aMedBlanks[magic(x, y)];
if (2 == tlCorner(x, y) && 2 == trCorner(x, y) && 2 == blCorner(x, y) && 2 == brCorner(x, y))
return aHiBlanks[magic(x, y)];
//
// Low to med transitions
//
if (0 == tlCorner(x, y) || 0 == trCorner(x, y) || 0 == blCorner(x, y) || 0 == brCorner(x, y)) {
// Corner cases
int cornerSum = tlCorner(x, y) + trCorner(x, y) + blCorner(x, y) + brCorner(x, y);
if (1 == cornerSum) {
if (tlCorner(x, y)) {
if (tllCorner(x, y) > 0 && ttlCorner(x, y) > 0)
return 0x03;
else
return 0x89;
} else if (trCorner(x, y)) {
if (trrCorner(x, y) > 0 && ttrCorner(x, y) > 0)
return 0x04;
else
return 0x8C;
} else if (blCorner(x, y)) {
if (bllCorner(x, y) > 0 && bblCorner(x, y) > 0)
return 0x02;
else
return 0x86;
} else // brCorner
{
if (brrCorner(x, y) > 0 && bbrCorner(x, y) > 0)
return 0x01;
else
return 0x83;
}
}
// Straight edges
// edge on bottom
if (tlCorner(x, y) == 0 && trCorner(x, y) == 0 && blCorner(x, y) == 1 && brCorner(x, y) == 1) {
bool bLeftEased = (bllCorner(x, y) == 0 && bblCorner(x, y) == 1);
bool bRightEased = (brrCorner(x, y) == 0 && bbrCorner(x, y) == 1);
if (bLeftEased && bRightEased)
return 0x0A;
if (!bLeftEased && bRightEased)
return 0x54;
if (bLeftEased && !bRightEased)
return 0x55;
if (!bLeftEased && !bRightEased)
return (magic(x, y) & 0x01) ? 0x9F : 0x56;
}
// edge on top
else if (tlCorner(x, y) == 1 && trCorner(x, y) == 1 && blCorner(x, y) == 0 && brCorner(x, y) == 0) {
bool bLeftEased = (tllCorner(x, y) == 0 && ttlCorner(x, y) == 1);
bool bRightEased = (trrCorner(x, y) == 0 && ttrCorner(x, y) == 1);
if (bLeftEased && bRightEased)
return 0x0C;
if (!bLeftEased && bRightEased)
return 0x52;
if (bLeftEased && !bRightEased)
return 0x51;
if (!bLeftEased && !bRightEased)
return (magic(x, y) & 0x01) ? 0xA1 : 0x53;
}
// edge on right
if (tlCorner(x, y) == 0 && blCorner(x, y) == 0 && trCorner(x, y) == 1 && brCorner(x, y) == 1) {
bool bTopEased = (ttrCorner(x, y) == 0 && trrCorner(x, y) == 1);
bool bBotEased = (bbrCorner(x, y) == 0 && brrCorner(x, y) == 1);
if (bTopEased && bBotEased)
return 0x09;
if (!bTopEased && bBotEased)
return 0x5B;
if (bTopEased && !bBotEased)
return 0x5A;
if (!bTopEased && !bBotEased)
return (magic(x, y) & 0x01) ? 0x9E : 0x5C;
}
// edge on left
if (tlCorner(x, y) == 1 && blCorner(x, y) == 1 && trCorner(x, y) == 0 && brCorner(x, y) == 0) {
bool bTopEased = (ttlCorner(x, y) == 0 && tllCorner(x, y) == 1);
bool bBotEased = (bblCorner(x, y) == 0 && bllCorner(x, y) == 1);
if (bTopEased && bBotEased)
return 0x0B;
if (!bTopEased && bBotEased)
return 0x57;
if (bTopEased && !bBotEased)
return 0x58;
if (!bTopEased && !bBotEased)
return (magic(x, y) & 0x01) ? 0xA0 : 0x59;
}
// Three corner cases
// 0 1 1 1 0 0 0 0 0 0
// 0 1 1 0x5F 0 1 1 0x5E 0 1 1 0x62 0 1 1 0x60
// 0 0 0 0 0 0 0 1 1 1
//
// 0 1 1 1 0 0 1 0 0 1
// 0 1 1 0x5D 0 1 1 0x06 0 1 1 0x61 0 1 1 0x07
// 0 0 1 0 0 1 0 1 1 1
//
//
// 0 0 0 1 0 0 1 0 1 1
// 1 1 0 0x65 1 1 0 0x63 1 1 0 0x68 1 1 0 0x66
// 1 0 1 0 0 0 0 0 0 0
//
// 0 0 0 1 0 0 1 0 1 1
// 1 1 0 0x64 1 1 0 0x08 1 1 0 0x67 1 1 0 0x05
// 1 1 1 1 1 0 0 1 0 0
// corner in upper left
if (blCorner(x, y) == 1 && tlCorner(x, y) == 1 && trCorner(x, y) == 1) {
bool BLDiag = (bllCorner(x, y) > 0 && bblCorner(x, y) == 0);
bool TRDiag = (ttrCorner(x, y) > 0 && trrCorner(x, y) == 0);
if (!BLDiag && !TRDiag)
return 0x62;
else if (!BLDiag && TRDiag)
return 0x61;
else if (BLDiag && !TRDiag)
return 0x60;
else
return 0x07;
}
// corner in upper right
if (tlCorner(x, y) == 1 && trCorner(x, y) == 1 && brCorner(x, y) == 1) {
bool TLDiag = (ttlCorner(x, y) > 0 && tllCorner(x, y) == 0);
bool BRDiag = (brrCorner(x, y) > 0 && bbrCorner(x, y) == 0);
if (!TLDiag && !BRDiag)
return 0x65;
else if (!TLDiag && BRDiag)
return 0x64;
else if (TLDiag && !BRDiag)
return 0x63;
else
return 0x08;
}
// corner in bottom right
if (trCorner(x, y) == 1 && brCorner(x, y) == 1 && blCorner(x, y) == 1) {
bool TRDiag = (trrCorner(x, y) > 0 && ttrCorner(x, y) == 0);
bool BLDiag = (bblCorner(x, y) > 0 && bllCorner(x, y) == 0);
if (!TRDiag && !BLDiag)
return 0x68;
else if (!TRDiag && BLDiag)
return 0x67;
else if (TRDiag && !BLDiag)
return 0x66;
else
return 0x05;
}
// corner in bottom left
if (brCorner(x, y) == 1 && blCorner(x, y) == 1 && tlCorner(x, y) == 1) {
bool TLDiag = (tllCorner(x, y) > 0 && ttlCorner(x, y) == 0);
bool BRDiag = (bbrCorner(x, y) > 0 && brrCorner(x, y) == 0);
if (!TLDiag && !BRDiag)
return 0x5F;
else if (!TLDiag && BRDiag)
return 0x5D;
else if (TLDiag && !BRDiag)
return 0x5E;
else
return 0x06;
}
// Opposing corner cases
if (tlCorner(x, y) == 1 && brCorner(x, y) == 1) {
// There are four cases, big big, big small, small big, small small
// big big
if (tllCorner(x, y) > 0 && ttlCorner(x, y) > 0 && brrCorner(x, y) > 0 && bbrCorner(x, y) > 0)
return 0x4D;
// big small
if (tllCorner(x, y) > 0 && ttlCorner(x, y) > 0)
return 0x81;
// small big
if (brrCorner(x, y) > 0 && bbrCorner(x, y) > 0)
return 0x82;
// small small
return 0x84;
}
if (trCorner(x, y) == 1 && blCorner(x, y) == 1) {
// There are four cases, big big, big small, small big, small small
// big big
if (trrCorner(x, y) > 0 && ttrCorner(x, y) > 0 && bllCorner(x, y) > 0 && bblCorner(x, y) > 0)
return 0x4E;
// big small
if (trrCorner(x, y) > 0 && ttrCorner(x, y) > 0)
return 0x85;
// small big
if (bllCorner(x, y) > 0 && bblCorner(x, y) > 0)
return 0x87;
// small small
return 0x88;
}
}
//
// Med to high transitions
//
if (1 == tlCorner(x, y) || 1 == trCorner(x, y) || 1 == blCorner(x, y) || 1 == brCorner(x, y)) {
// Corner cases
int cornerSum = (tlCorner(x, y) == 2) + (trCorner(x, y) == 2) + (blCorner(x, y) == 2) + (brCorner(x, y) == 2);
if (1 == cornerSum) {
if (tlCorner(x, y) == 2) {
if (tllCorner(x, y) == 2 && ttlCorner(x, y) == 2)
return 0x10;
else
return 0x95;
} else if (trCorner(x, y) == 2) {
if (trrCorner(x, y) == 2 && ttrCorner(x, y) == 2)
return 0x11;
else
return 0x98;
} else if (blCorner(x, y) == 2) {
if (bllCorner(x, y) == 2 && bblCorner(x, y) == 2)
return 0x0F;
else
return 0x92;
} else // brCorner
{
if (brrCorner(x, y) == 2 && bbrCorner(x, y) == 2)
return 0x0E;
else
return 0x8F;
}
}
// Straight edges
// edge on bottom
if (tlCorner(x, y) < 2 && trCorner(x, y) < 2 && blCorner(x, y) == 2 && brCorner(x, y) == 2) {
bool bLeftEased = (bllCorner(x, y) < 2 && bblCorner(x, y) == 2);
bool bRightEased = (brrCorner(x, y) < 2 && bbrCorner(x, y) == 2);
if (bLeftEased && bRightEased)
return 0x17;
if (!bLeftEased && bRightEased)
return 0x6C;
if (bLeftEased && !bRightEased)
return 0x6D;
if (!bLeftEased && !bRightEased)
return (magic(x, y) & 0x01) ? 0xA3 : 0x6E;
}
// edge on top
else if (tlCorner(x, y) == 2 && trCorner(x, y) == 2 && blCorner(x, y) < 2 && brCorner(x, y) < 2) {
bool bLeftEased = (tllCorner(x, y) < 2 && ttlCorner(x, y) == 2);
bool bRightEased = (trrCorner(x, y) < 2 && ttrCorner(x, y) == 2);
if (bLeftEased && bRightEased)
return 0x19;
if (!bLeftEased && bRightEased)
return 0x6A;
if (bLeftEased && !bRightEased)
return 0x69;
if (!bLeftEased && !bRightEased)
return (magic(x, y) & 0x01) ? 0xA5 : 0x6B;
}
// edge on right
if (tlCorner(x, y) < 2 && blCorner(x, y) < 2 && trCorner(x, y) == 2 && brCorner(x, y) == 2) {
bool bTopEased = (ttrCorner(x, y) < 2 && trrCorner(x, y) == 2);
bool bBotEased = (bbrCorner(x, y) < 2 && brrCorner(x, y) == 2);
if (bTopEased && bBotEased)
return 0x16;
if (!bTopEased && bBotEased)
return 0x73;
if (bTopEased && !bBotEased)
return 0x72;
if (!bTopEased && !bBotEased)
return (magic(x, y) & 0x01) ? 0xA2 : 0x74;
}
// edge on left
if (tlCorner(x, y) == 2 && blCorner(x, y) == 2 && trCorner(x, y) < 2 && brCorner(x, y) < 2) {
bool bTopEased = (ttlCorner(x, y) < 2 && tllCorner(x, y) == 2);
bool bBotEased = (bblCorner(x, y) < 2 && bllCorner(x, y) == 2);
if (bTopEased && bBotEased)
return 0x18;
if (!bTopEased && bBotEased)
return 0x6F;
if (bTopEased && !bBotEased)
return 0x70;
if (!bTopEased && !bBotEased)
return (magic(x, y) & 0x01) ? 0xA4 : 0x71;
}
// edge on bottom
if (tlCorner(x, y) == 1 && trCorner(x, y) == 1 && blCorner(x, y) == 2 && brCorner(x, y) == 2) {
// no other high corners
if (bllCorner(x, y) < 2 && brrCorner(x, y) < 2)
return 0x17;
// high corner on left
if (bllCorner(x, y) == 2 && brrCorner(x, y) < 2)
return 0x6C;
// high corner on right
if (bllCorner(x, y) < 2 && brrCorner(x, y) == 2)
return 0x6D;
// both neighbor corners high
if (bllCorner(x, y) == 2 && brrCorner(x, y) == 2)
return (magic(x, y) & 0x01) ? 0xA3 : 0x6E;
}
// edge on top
else if (tlCorner(x, y) == 2 && trCorner(x, y) == 2 && blCorner(x, y) == 1 && brCorner(x, y) == 1) {
// no other high corners
if (tllCorner(x, y) < 2 && trrCorner(x, y) < 2)
return 0x19;
// high corner on left
if (tllCorner(x, y) == 2 && trrCorner(x, y) < 2)
return 0x6A;
// high corner on right
if (tllCorner(x, y) < 2 && trrCorner(x, y) == 2)
return 0x69;
// both neighbor corners high
if (tllCorner(x, y) == 2 && trrCorner(x, y) == 2)
return (magic(x, y) & 0x01) ? 0xA5 : 0x6B;
}
// edge on right
if (tlCorner(x, y) == 1 && blCorner(x, y) == 1 && trCorner(x, y) == 2 && brCorner(x, y) == 2) {
// no high neighbor corners
if (ttrCorner(x, y) < 2 && bbrCorner(x, y) < 2)
return 0x16;
// high neighbor corner on top
if (ttrCorner(x, y) == 2 && bbrCorner(x, y) < 2)
return 0x73;
// high neighbor corner on bottom
if (ttrCorner(x, y) < 2 && bbrCorner(x, y) == 2)
return 0x72;
// both neighbor corners high
if (ttrCorner(x, y) == 2 && bbrCorner(x, y) == 2)
return (magic(x, y) & 0x01) ? 0xA2 : 0x74;
}
// edge on left
if (tlCorner(x, y) == 2 && blCorner(x, y) == 2 && trCorner(x, y) == 1 && brCorner(x, y) == 1) {
// no high neighbor corners
if (ttlCorner(x, y) < 2 && bblCorner(x, y) < 2)
return 0x18;
// high neighbor corner on top
if (ttlCorner(x, y) == 2 && bblCorner(x, y) < 2)
return 0x6F;
// high neighbor corner on bottom
if (ttlCorner(x, y) < 2 && bblCorner(x, y) == 2)
return 0x70;
// both neighbor corners high
if (ttlCorner(x, y) == 2 && bblCorner(x, y) == 2)
return (magic(x, y) & 0x01) ? 0xA4 : 0x71;
}
// Three corner cases
// Three corner cases
// 0 1 1 1 0 0 0 0 0 0
// 0 1 1 0x77 0 1 1 0x76 0 1 1 0x7A 0 1 1 0x78
// 0 0 0 0 0 0 0 1 1 1
//
// 0 1 1 1 0 0 1 0 0 1
// 0 1 1 0x75 0 1 1 0x13 0 1 1 0x79 0 1 1 0x14
// 0 0 1 0 0 1 0 1 1 1
//
//
// 0 0 0 1 0 0 1 0 1 1
// 1 1 0 0x7D 1 1 0 0x7B 1 1 0 0x80 1 1 0 0x7E
// 1 0 1 0 0 0 0 0 0 0
//
// 0 0 0 1 0 0 1 0 1 1
// 1 1 0 0x7C 1 1 0 0x15 1 1 0 0x7F 1 1 0 0x12
// 1 1 1 1 1 0 0 1 0 0
// corner in upper left
if (blCorner(x, y) == 2 && tlCorner(x, y) == 2 && trCorner(x, y) == 2) {
bool BLDiag = (bllCorner(x, y) > 1 && bblCorner(x, y) < 2);
bool TRDiag = (ttrCorner(x, y) > 1 && trrCorner(x, y) < 2);
if (!BLDiag && !TRDiag)
return 0x7A;
else if (!BLDiag && TRDiag)
return 0x79;
else if (BLDiag && !TRDiag)
return 0x78;
else
return 0x14;
}
// corner in upper right
if (tlCorner(x, y) == 2 && trCorner(x, y) == 2 && brCorner(x, y) == 2) {
bool TLDiag = ((ttlCorner(x, y) > 1) && (tllCorner(x, y) < 2));
bool BRDiag = ((brrCorner(x, y) > 1) && (bbrCorner(x, y) < 2));
if (!TLDiag && !BRDiag)
return 0x7D;
else if (!TLDiag && BRDiag)
return 0x7C;
else if (TLDiag && !BRDiag)
return 0x7B;
else
return 0x15;
}
// corner in bottom right
if (trCorner(x, y) == 2 && brCorner(x, y) == 2 && blCorner(x, y) == 2) {
bool TRDiag = (trrCorner(x, y) > 1 && ttrCorner(x, y) < 2);
bool BLDiag = (bblCorner(x, y) > 1 && bllCorner(x, y) < 2);
if (!TRDiag && !BLDiag)
return 0x80;
else if (!TRDiag && BLDiag)
return 0x7F;
else if (TRDiag && !BLDiag)
return 0x7E;
else
return 0x12;
}
// corner in bottom left
if (brCorner(x, y) == 2 && blCorner(x, y) == 2 && tlCorner(x, y) == 2) {
bool TLDiag = (tllCorner(x, y) > 1 && ttlCorner(x, y) < 2);
bool BRDiag = (bbrCorner(x, y) > 1 && brrCorner(x, y) < 2);
if (!TLDiag && !BRDiag)
return 0x77;
else if (!TLDiag && BRDiag)
return 0x75;
else if (TLDiag && !BRDiag)
return 0x76;
else
return 0x13;
}
// Opposing corner cases
if (tlCorner(x, y) == 2 && brCorner(x, y) == 2) {
// There are four cases, big big, big small, small big, small small
// big big
if (tllCorner(x, y) == 2 && ttlCorner(x, y) == 2 && brrCorner(x, y) == 2 && bbrCorner(x, y) == 2)
return 0x4F;
// big small
if (tllCorner(x, y) == 2 && ttlCorner(x, y) == 2)
return 0x8A;
// small big
if (brrCorner(x, y) == 2 && bbrCorner(x, y) == 2)
return 0x8B;
// small small
return 0x8D;
}
if (trCorner(x, y) == 2 && blCorner(x, y) == 2) {
// There are four cases, big big, big small, small big, small small
// big big
if (trrCorner(x, y) == 2 && ttrCorner(x, y) == 2 && bllCorner(x, y) == 2 && bblCorner(x, y) == 2)
return 0x50;
// big small
if (trrCorner(x, y) == 2 && ttrCorner(x, y) == 2)
return 0x8E;
// small big
if (bllCorner(x, y) == 2 && bblCorner(x, y) == 2)
return 0x90;
// small small
return 0x91;
}
}
error("illegal corner height arrangement (%d, %d)", x, y);
} else if ('W' == ch) {
// Check to make sure that we're on ground level
if (tlCorner(x, y) > 0 || trCorner(x, y) > 0 || blCorner(x, y) > 0 || brCorner(x, y) > 0)
error("water must be on a flat tile (%d, %d)", x, y);
index = (('W' != tlCenter(x, y)) << 7) |
(('W' != tCenter(x, y)) << 6) |
(('W' != trCenter(x, y)) << 5) |
(('W' != lCenter(x, y)) << 4) |
(('W' != rCenter(x, y)) << 3) |
(('W' != blCenter(x, y)) << 2) |
(('W' != bCenter(x, y)) << 1) |
('W' != brCenter(x, y));
uint16 nWaterTile = waterTileMap[index];
if (0x44 == nWaterTile) {
uint16 aWaterBlanks[] = {0x45, 0x46, 0x44, 0x47};
nWaterTile = aWaterBlanks[magic(x, y)];
}
return nWaterTile;
} else
error("illegal tile character (%d, %d)", x, y);
error("unknown tile find error (%d, %d)", x, y);
}
} // End of namespace Scumm