📄 cbmap.cpp
字号:
void MAP_FillRegion( POINT pt, int nPlayer )
{
// set current point
struct MAP_REGION_CODE_STRUCT stctR;
WORD code;
stctR.nPlayer = nPlayer;
stctR.nShadow = MAP_SHADOW_NONE;
stctR.nShadowEx = MAP_SHADOW_NONE;
code = MAP_RegionEnCode( stctR );
MAP_SetRegionData( pt.x, pt.y, code );
MAP_nRegionStack++; // stack counter
POINT ptNext;
for( int i=0; i<4; i++ )
{
// get next point
int bOdd = pt.y&1; // TRUE if Odd
ptNext.x = pt.x + MAP_ptSenser[bOdd][0][i*2+1].x;
ptNext.y = pt.y + MAP_ptSenser[bOdd][0][i*2+1].y;
if( EYE_IfOutOfRange( ptNext.x, ptNext.y ) )
continue;
code = MAP_GetGroundData( 0, ptNext.x, ptNext.y );
if( code == MAP_DATA_NONE ) continue;
struct MAP_GROUND_CODE_STRUCT stctG;
MAP_GroundDeCode( code, &stctG );
// if it is on the correct ground type
if( stctG.nFile == 2 && stctG.nCol == 12 && MAP_nRegionStack<MAP_REGION_STACK_MAX )
{
code = MAP_GetRegionData( ptNext.x, ptNext.y );
MAP_RegionDeCode( code, &stctR );
// if has filled
if( stctR.nPlayer != nPlayer )
MAP_FillRegion( ptNext, nPlayer );
}
}
MAP_nRegionStack--;
}
// 清除区域
// 只有地图编辑器使用
// pt : 填充点种子,格子为单位
void MAP_ClearRegion( POINT pt )
{
// set current point
struct MAP_UNIT_CODE_STRUCT stctU;
DWORD codeU;
codeU = MAP_GetUnitData( pt.x, pt.y );
if( codeU != MAP_DATA_NONE )
{
::MAP_UnitDeCode( codeU, &stctU );
// if it is flag
//if( stctU.nFile == 3 && stctU.nCol == 0 )
// 只有地图编辑器使用
int nType = MAP_Lib.Unit[stctU.nFile].nType;
if( nType == MAP_UNIT_TYPE_FLAG )
{
// reset to zero
MAP_SetUnitData( 0, pt.x, pt.y, MAP_DATA_NONE );
}
}
// set region to none
WORD code;
code = MAP_GetRegionData( pt.x, pt.y );
struct MAP_REGION_CODE_STRUCT stctR;
MAP_RegionDeCode( code, &stctR );
stctR.nPlayer = MAP_PLAYER_NONE; // custom value
code = MAP_RegionEnCode( stctR );
MAP_SetRegionData( pt.x, pt.y, code );
MAP_nRegionStack++; // stack counter
POINT ptNext;
for( int i=0; i<4; i++ )
{
// find next point
int bOdd = pt.y&1; // TRUE if Odd
ptNext.x = pt.x + MAP_ptSenser[bOdd][0][i*2+1].x;
ptNext.y = pt.y + MAP_ptSenser[bOdd][0][i*2+1].y;
code = MAP_GetGroundData( 0, ptNext.x, ptNext.y );
if( code == MAP_DATA_NONE ) continue;
struct MAP_GROUND_CODE_STRUCT stctG;
MAP_GroundDeCode( code, &stctG );
// if it is the correct ground type
if( stctG.nFile == 2 && stctG.nCol == 12 && MAP_nRegionStack<MAP_REGION_STACK_MAX )
{
code = MAP_GetRegionData( ptNext.x, ptNext.y );
MAP_RegionDeCode( code, &stctR );
// if has been cleared
if( stctR.nPlayer != MAP_PLAYER_NONE )
MAP_ClearRegion( ptNext );
}
}
MAP_nRegionStack--;
}
// 直接将压缩后的代码设置到区域数组中
// nCol : 列号
// nRow : 行号
// codeR : 区域数据代码(压缩)
inline void MAP_SetRegionData( int nCol, int nRow, int codeR )
{
MAP_wRegionData[nCol][nRow] = codeR;
}
// 直接从区域数组中取出数据
// nCol : 列号
// nRow : 行号
// return value : 区域数据代码(压缩)
inline WORD MAP_GetRegionData( int nCol, int nRow )
{
return MAP_wRegionData[nCol][nRow];
}
// 检测是否可以在此片地域上修建建筑,return 10 if successful
// nLayer : 层号
// pt : 测试点,格子为单位
// codeU : 建筑代码(压缩)
// codeUEx : 出发点的单元,检测时可以取得此点,MAP_DATA_NONE时无效
// return value : 错误代码,见上
int MAP_TestRegion( int nLayer, POINT pt, DWORD codeU, WORD codeUEx/*=MAP_DATA_NONE*/ )
{
if( codeU == MAP_DATA_NONE ) return 10;
// should be built on one special ground type
struct MAP_UNIT_CODE_STRUCT stctU;
::MAP_UnitDeCode( codeU, &stctU );
//int nType = MAP_Lib.Unit[stctU.nFile].nType;
// set locations
int nLocationSize = MAP_Lib.Unit[stctU.nFile].nLocationSize;
POINT ptNext;
int retrns[16];
int i;
int bOdd = pt.y&1; // TRUE if Odd
for( i=0; i<MAP_nLocationNum[nLocationSize]; i++ )
{
ptNext.x = pt.x + MAP_ptLocation[bOdd][i].x;
ptNext.y = pt.y + MAP_ptLocation[bOdd][i].y;
if( EYE_IfOutOfRange( ptNext.x, ptNext.y ) )
{
retrns[i] = MAP_REGION_ERROR_OUT;
}
else
retrns[i] = MAP_testPointRegion( nLayer, ptNext, codeU, codeUEx );
if( retrns[i] != MAP_REGION_SUCCESS )
return retrns[i];
}
return MAP_REGION_SUCCESS;
}
// only called by MAP_TestRegion()
// 检测是否可以在点上修建建筑,return 10 if successful
// nLayer : 层号
// pt : 测试点,格子为单位
// codeU : 建筑代码(压缩)
// codeUEx : 出发点的单元,检测时可以取得此点,MAP_DATA_NONE时无效
// return value : 错误代码,见上
int MAP_testPointRegion( int nLayer, POINT pt, DWORD codeU, WORD codeUEx/*=MAP_DATA_NONE*/ )
{
WORD codeG1;
for(;;)
{
// 没有地形图素而且在最底层,错误返回
// cannot build below ground
codeG1 = MAP_GetGroundData( nLayer, pt.x, pt.y );
if( codeG1 != MAP_DATA_NONE )
break;
if( nLayer == 0 && codeG1 == MAP_DATA_NONE )
{
return MAP_REGION_ERROR_UNDER;
}
nLayer--;
}
Assert( nLayer >= 0 );
struct MAP_UNIT_CODE_STRUCT stctU;
::MAP_UnitDeCode( codeU, &stctU );
int nType = MAP_Lib.Unit[stctU.nFile].nType;
// cannot build building on other unit
WORD cUEx = ::MAP_GetUnitDataEx( pt.x, pt.y );
// if( cUEx != MAP_DATA_NONE && codeUEx != cUEx )
// return MAP_REGION_ERROR_CANNOT;
if( cUEx != MAP_DATA_NONE )
return MAP_REGION_ERROR_CANNOT;
// cannot build on resources
struct MAP_GROUND_CODE_STRUCT stctG;
MAP_GroundDeCode( codeG1, &stctG );
if( stctG.nAttr != MAP_SPECIAL_NONE
&& stctG.nAttr != MAP_SPECIAL_CUT_WOOD
&& stctG.nAttr != MAP_SPECIAL_CUT_WHEAT ) // cannot move in Forest and Field
return MAP_REGION_ERROR_RES;
// cannot build on other layers
if( nLayer <MAP_DATA_THICK-1 )
{
WORD codeG2 = MAP_GetGroundData( nLayer+1, pt.x, pt.y );
if( codeG2 != MAP_DATA_NONE ) return MAP_REGION_ERROR_CANNOT;
}
// should be built on one special ground type
if( nType == MAP_UNIT_TYPE_SHIPYARD ) // shipyard
{
WORD codeG = MAP_GetGroundData( nLayer, pt.x, pt.y );
struct MAP_GROUND_CODE_STRUCT stctG;
::MAP_GroundDeCode( codeG, &stctG );
if( !(stctG.nFile == 3 && stctG.nCol == 12) )
{ // shipyard can only be placed in water
return MAP_REGION_ERROR_SHIPYARD;
}
}
else if( nType == MAP_UNIT_TYPE_SHIP
|| nType == MAP_UNIT_TYPE_SGEN ) // sailer
{
WORD codeG = MAP_GetGroundData( nLayer, pt.x, pt.y );
struct MAP_GROUND_CODE_STRUCT stctG;
::MAP_GroundDeCode( codeG, &stctG );
if( !(stctG.nFile == 3 && stctG.nCol == 12) )
{ // ships can only be placed in water
return MAP_REGION_ERROR_SHIP;
}
}
else
{ // 陆上单元
WORD codeG = MAP_GetGroundData( nLayer, pt.x, pt.y );
struct MAP_GROUND_CODE_STRUCT stctG;
::MAP_GroundDeCode( codeG, &stctG );
if( stctG.nFile == 3 && stctG.nCol == 12 )
return MAP_REGION_ERROR_WATER; // 不能建在水中
if( nType == MAP_UNIT_TYPE_BUILDING ||
nType == MAP_UNIT_TYPE_FLAG ) // generic building
{
if( !(stctG.nFile == 2 && stctG.nCol == 12) )
{ // generic building can only be placed on TUDI
return MAP_REGION_ERROR_TUDI; // 只能建在土地上
}
}
}
#ifdef _MAP_EDIT_
if( nType == MAP_UNIT_TYPE_FLAG ) // if it is flag
{
// clear region
MAP_nRegionStack=0;
::MAP_ClearRegion( pt );
// set region to this flag
MAP_nRegionStack=0;
::MAP_FillRegion( pt, stctU.nPlayer );
}
else if( nType == MAP_UNIT_TYPE_BUILDING ) // other unit data
{
// must be placed with the same flag
WORD codeR = MAP_GetRegionData( pt.x, pt.y );
struct MAP_REGION_CODE_STRUCT stctR;
MAP_RegionDeCode( codeR, &stctR );
if( stctR.nPlayer == MAP_PLAYER_NONE )
{
// set flag first
return MAP_REGION_ERROR_FLAG;
}
else
{ // change the flag of the unit to the same as the region
stctU.nPlayer = stctR.nPlayer;
codeU = MAP_UnitEnCode( stctU );
}
}
#endif // _MAP_EDIT_
return MAP_REGION_SUCCESS;
}
// 自动找到一个可以放置该单元的位置,在MAP_SENSER_MAX格范围内寻找
// nZ, nX, nY : 开始的坐标
// codeU : 该单元的压缩代码
// codeUEx : 出发点的单元,检测时可以取得此点,MAP_DATA_NONE时无效
// return : (-1,-1)时为没有找到
POINT MAP_FindRegion( int nZ, int nX, int nY, DWORD codeU, WORD codeUEx/*=MAP_DATA_NONE*/ )
{
POINT pt;
int ret;
int bOdd;
// test for the current position
pt.x = nX, pt.y = nY;
ret = MAP_TestRegion( nZ, pt, codeU, codeUEx );
if( ret == MAP_REGION_SUCCESS )
{
Assert( MAP_GetUnitData( pt.x, pt.y ) == MAP_DATA_NONE );
return pt;
}
// test for the positions around the current one
bOdd = nY%2;
for( int i=0; i< MAP_SENSER_MAX; i++ )
for( int j=0; j< ((i+1)<<3); j++ )
{
pt.x = nX + MAP_ptSenser[bOdd][i][j].x;
pt.y = nY + MAP_ptSenser[bOdd][i][j].y;
if( EYE_IfOutOfRange( pt.x, pt.y ) )
continue;
ret = MAP_TestRegion( nZ, pt, codeU, codeUEx );
if( ret == MAP_REGION_SUCCESS )
{
Assert( MAP_GetUnitDataEx( pt.x, pt.y ) == MAP_DATA_NONE
|| MAP_GetUnitDataEx( pt.x, pt.y ) == codeUEx );
return pt;
}
}
pt.x = -1, pt.y = -1;
return pt;
}
///////////
///////////
// 只有在CBBuild.cpp中使用,建造建筑时用
// 检测是否可以在此片地域上修建建筑
// nLayer : 输入,层号
// pt : 输入,测试点,格子为单位
// codeU : 输入,建筑代码(压缩)
// pnRet : 输出,返回值数组
// nRetNum : 输入,数组的内容的个数
void MAP_TestRegionBuild( int nLayer, POINT pt, DWORD codeU, int *pnRet, int nRetNum )
{
if( codeU == MAP_DATA_NONE ) return;
POINT ptNext;
int retrns[16];
int i;
int bOdd = pt.y&1; // TRUE if Odd
for( i=0; i<nRetNum; i++ )
{
ptNext.x = pt.x + MAP_ptLocation[bOdd][i].x;
ptNext.y = pt.y + MAP_ptLocation[bOdd][i].y;
if( EYE_IfOutOfRange( ptNext.x, ptNext.y ) )
{
retrns[i] = MAP_REGION_ERROR_OUT;
}
else
{
// 如果被阴影遮挡则不能建造
WORD codeR = MAP_GetRegionData( ptNext.x, ptNext.y );
struct MAP_REGION_CODE_STRUCT stctR;
MAP_RegionDeCode( codeR, &stctR );
if( stctR.nShadow == MAP_SHADOW_NONE )
retrns[i] = MAP_REGION_ERROR_SHADOW;
else
{
retrns[i] = MAP_testPointRegion( nLayer, ptNext, codeU );
}
}
}
// 重新计算船坞是否靠着岸边
BOOL bSuccess = TRUE;
for( i=0; i<nRetNum; i++ )
{
if( retrns[i] != MAP_REGION_SUCCESS )
{
bSuccess = FALSE;
break;
}
}
// 如果可以成功建造
if( bSuccess == TRUE )
{
WORD codeG = MAP_GetGroundData( nLayer, pt.x, pt.y );
if( codeG != MAP_DATA_NONE )
{
struct MAP_GROUND_CODE_STRUCT stctG;
MAP_GroundDeCode( codeG, &stctG );
if( stctG.nFile == 3 ) // 是水
{ // 只能在水边才能建造船坞,所以肯定是要建造船坞
bSuccess = EYE_IfNearBank( nLayer, pt.x, pt.y, 2 );
}
}
if( bSuccess == FALSE )
{ // 地点周围没有岸,失败
for( i=0; i<nRetNum; i++ )
{
retrns[i] = MAP_REGION_ERROR_BANK;
}
}
}
memcpy( pnRet, retrns, nRetNum*sizeof( int ) );
return;
}
///////////
///////////
// 计算其它数据的矩形区域
// ptOff : 屏幕左上角相对于整个战场的坐标
// nLayer, nCol, nRow : 在战场的三维坐标
// nFile : 其它数据结构的文件号
// return : 相对于屏幕的点坐标和范围
RECT MAP_GetOtherRect( CONST POINT ptOff, int nLayer, int nCol, int nRow, int nFile )
{
int left, top;
int widthG = MAP_Lib.szItem.cx;
int heightG = MAP_Lib.szItem.cy;
int width = MAP_Lib.Other[nFile].szItem.cx;
int height = MAP_Lib.Other[nFile].szItem.cy;
RECT rect;
// calc top-left position on screen
top = nRow*(heightG>>1) + heightG - height; // 底边与格子对齐
if( (nRow&1) == 0 )
{
left = nCol*widthG+(widthG>>1)-(width>>1);
}
else
{
left = (nCol+1)*widthG-(width>>1);
}
// re-adjust coords
left -= ptOff.x;
top -= ptOff.y;
rect.left = left, rect.top = top,
rect.right = left+width, rect.bottom = top + height;
return rect;
}
///////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -