2016-04-02 15:50:49 +00:00
/*
2009-05-08 13:28:41 +00:00
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 1998 - 2000 , Matthes Bender
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
2016-04-02 15:50:49 +00:00
* Copyright ( c ) 2009 - 2016 , The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-08 13:28:41 +00:00
*/
2016-04-02 15:50:49 +00:00
/* Handles landscape and sky */
# include "C4Include.h"
# include "landscape/C4Landscape.h"
# include <array>
# include "c4group/C4Components.h"
# include "control/C4Record.h"
# include "editor/C4ToolsDlg.h"
# include "game/C4GraphicsSystem.h"
# include "game/C4Physics.h"
# include "graphics/C4GraphicsResource.h"
# include "gui/C4GameMessage.h"
# include "landscape/fow/C4FoW.h"
# include "landscape/C4LandscapeRender.h"
# include "landscape/C4Map.h"
# include "landscape/C4MapCreatorS2.h"
# include "landscape/C4MapScript.h"
# include "landscape/C4MassMover.h"
# include "landscape/C4Material.h"
# include "landscape/C4MaterialList.h"
# include "landscape/C4PXS.h"
# include "landscape/C4Sky.h"
# include "landscape/C4SolidMask.h"
# include "landscape/C4Texture.h"
# include "landscape/C4Weather.h"
# include "lib/C4Random.h"
# include "lib/StdColors.h"
2016-04-02 17:44:44 +00:00
# include "object/C4Def.h"
2016-04-02 15:50:49 +00:00
# include "object/C4FindObject.h"
# include "object/C4GameObjects.h"
struct C4Landscape : : P
{
std : : unique_ptr < CSurface8 > Surface8 ;
std : : unique_ptr < CSurface8 > Surface8Bkg ; // Background material
std : : unique_ptr < CSurface8 > Map ;
std : : unique_ptr < CSurface8 > MapBkg ;
std : : unique_ptr < C4LandscapeRender > pLandscapeRender ;
std : : vector < uint8_t > TopRowPix , BottomRowPix ; // array size of landscape width: Filled with 0s for border pixels that are open and MCVehic for pixels that are closed
int32_t Pix2Mat [ C4M_MaxTexIndex ] , Pix2Dens [ C4M_MaxTexIndex ] , Pix2Place [ C4M_MaxTexIndex ] ;
bool Pix2Light [ C4M_MaxTexIndex ] ;
int32_t PixCntPitch = 0 ;
std : : vector < uint8_t > PixCnt ;
std : : array < C4Rect , C4LS_MaxRelights > Relights ;
mutable std : : array < std : : unique_ptr < uint8_t [ ] > , C4M_MaxTexIndex > BridgeMatConversion ; // NoSave //
LandscapeMode mode = LandscapeMode : : Undefined ;
int32_t Width = 0 , Height = 0 ;
int32_t MapWidth = 0 , MapHeight = 0 , MapZoom = 0 ;
std : : array < DWORD , C4MaxMaterial > MatCount { } ; // NoSave //
std : : array < DWORD , C4MaxMaterial > EffectiveMatCount { } ; // NoSave //
bool NoScan = false ; // ExecuteScan() disabled
int32_t ScanX = 0 , ScanSpeed = 2 ; // SyncClearance-NoSave //
int32_t LeftOpen = 0 , RightOpen = 0 , TopOpen = 0 , BottomOpen = 0 ;
C4Real Gravity = DefaultGravAccel ;
uint32_t Modulation = 0 ; // landscape blit modulation; 0 means normal
int32_t MapSeed = 0 ; // random seed for MapToLandscape
C4Sky Sky ;
std : : unique_ptr < C4MapCreatorS2 > pMapCreator ; // map creator for script-generated maps
bool fMapChanged = false ;
std : : unique_ptr < BYTE [ ] > pInitial ; // Initial landscape after creation - used for diff
std : : unique_ptr < BYTE [ ] > pInitialBkg ; // Initial bkg landscape after creation - used for diff
std : : unique_ptr < C4FoW > pFoW ;
void ClearMatCount ( ) ;
void ExecuteScan ( C4Landscape * ) ;
int32_t DoScan ( C4Landscape * , int32_t x , int32_t y , int32_t mat , int32_t dir ) ;
uint32_t ChunkyRandom ( uint32_t & iOffset , uint32_t iRange ) const ; // return static random value, according to offset and MapSeed
void DrawChunk ( C4Landscape * , int32_t tx , int32_t ty , int32_t wdt , int32_t hgt , uint8_t mcol , uint8_t mcolBkg , C4MaterialCoreShape Shape , uint32_t cro ) ;
void DrawSmoothOChunk ( C4Landscape * , int32_t tx , int32_t ty , int32_t wdt , int32_t hgt , uint8_t mcol , uint8_t mcolBkg , int flip , uint32_t cro ) ;
void ChunkOZoom ( C4Landscape * , const CSurface8 & sfcMap , const CSurface8 & sfcMapBkg , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , uint8_t iTexture , int32_t iOffX = 0 , int32_t iOffY = 0 ) ;
bool TexOZoom ( C4Landscape * , const CSurface8 & sfcMap , const CSurface8 & sfcMapBkg , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , DWORD * dwpTextureUsage , int32_t iToX = 0 , int32_t iToY = 0 ) ;
bool MapToSurface ( C4Landscape * , const CSurface8 & sfcMap , const CSurface8 & sfcMapBkg , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , int32_t iToX , int32_t iToY , int32_t iToWdt , int32_t iToHgt , int32_t iOffX , int32_t iOffY ) ;
bool MapToLandscape ( C4Landscape * d , const CSurface8 & sfcMap , const CSurface8 & sfcMapBkg , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , int32_t iOffsX = 0 , int32_t iOffsY = 0 , bool noClear = false ) ; // zoom map segment to surface (or sector surfaces)
bool InitTopAndBottomRowPix ( ) ; // init out-of-landscape pixels for bottom side
bool GetMapColorIndex ( const char * szMaterial , const char * szTexture , BYTE & rbyCol ) const ;
//bool SkyToLandscape(int32_t iToX, int32_t iToY, int32_t iToWdt, int32_t iToHgt, int32_t iOffX, int32_t iOffY);
bool CreateMap ( CSurface8 * & sfcMap , CSurface8 * & sfcMapBkg ) ; // create map by landscape attributes
bool CreateMapS2 ( C4Group & ScenFile , CSurface8 * & sfcMap , CSurface8 * & sfcMapBkg ) ; // create map by def file
bool Mat2Pal ( ) ; // assign material colors to landscape palette
void UpdatePixCnt ( const C4Landscape * , const C4Rect & Rect , bool fCheck = false ) ;
void UpdateMatCnt ( const C4Landscape * , C4Rect Rect , bool fPlus ) ;
void PrepareChange ( const C4Landscape * d , const C4Rect & BoundingBox ) ;
void FinishChange ( C4Landscape * d , C4Rect BoundingBox ) ;
bool DrawLineLandscape ( int32_t iX , int32_t iY , int32_t iGrade , uint8_t line_color , uint8_t line_color_bkg ) ;
bool DrawLineMap ( int32_t iX , int32_t iY , int32_t iRadius , uint8_t line_color , uint8_t line_color_bkg ) ;
uint8_t * GetBridgeMatConversion ( const C4Landscape * d , int32_t for_material_col ) const ;
bool SaveInternal ( const C4Landscape * d , C4Group & hGroup ) const ;
bool SaveDiffInternal ( const C4Landscape * d , C4Group & hGroup , bool fSyncSave ) const ;
int32_t ForPolygon ( C4Landscape * d , int * vtcs , int length , const std : : function < bool ( int32_t , int32_t ) > & callback ,
C4MaterialList * mats_count = NULL , uint8_t col = 0 , uint8_t colBkg = 0 , uint8_t * conversion_table = NULL ) ;
std : : unique_ptr < CSurface8 > CreateDefaultBkgSurface ( CSurface8 & sfcFg , bool msbAsIft ) const ;
void DigMaterial2Objects ( int32_t tx , int32_t ty , C4MaterialList * mat_list , C4Object * pCollect = NULL ) ;
void BlastMaterial2Objects ( int32_t tx , int32_t ty , C4MaterialList * mat_list , int32_t caused_by , int32_t str , C4ValueArray * out_objects ) ;
bool DigFreePix ( C4Landscape * d , int32_t tx , int32_t ty ) ;
bool DigFreePixNoInstability ( C4Landscape * d , int32_t tx , int32_t ty ) ;
bool BlastFreePix ( C4Landscape * d , int32_t tx , int32_t ty ) ;
bool ShakeFreePix ( C4Landscape * d , int32_t tx , int32_t ty ) ;
C4ValueArray * PrepareFreeShape ( C4Rect & BoundingBox , C4Object * by_object ) ;
void PostFreeShape ( C4ValueArray * dig_objects , C4Object * by_object ) ;
BYTE DefaultBkgMat ( BYTE fg ) const ;
} ;
2009-05-08 13:28:41 +00:00
2015-02-23 11:33:53 +00:00
namespace
{
bool ForLine ( int32_t x1 , int32_t y1 , int32_t x2 , int32_t y2 ,
2015-02-23 11:43:13 +00:00
std : : function < bool ( int32_t , int32_t ) > fnCallback ,
2015-02-23 11:33:53 +00:00
int32_t * lastx = 0 , int32_t * lasty = 0 )
{
int d , dx , dy , aincr , bincr , xincr , yincr , x , y ;
2016-04-02 15:50:49 +00:00
if ( Abs ( x2 - x1 ) < Abs ( y2 - y1 ) )
2015-02-23 11:33:53 +00:00
{
2016-04-02 15:50:49 +00:00
if ( y1 > y2 ) { std : : swap ( x1 , x2 ) ; std : : swap ( y1 , y2 ) ; }
xincr = ( x2 > x1 ) ? 1 : - 1 ;
2015-02-23 11:33:53 +00:00
dy = y2 - y1 ; dx = Abs ( x2 - x1 ) ;
d = 2 * dx - dy ; aincr = 2 * ( dx - dy ) ; bincr = 2 * dx ; x = x1 ; y = y1 ;
2015-02-23 11:43:13 +00:00
if ( ! fnCallback ( x , y ) )
2015-02-23 11:33:53 +00:00
{
if ( lastx ) * lastx = x ; if ( lasty ) * lasty = y ;
return false ;
}
for ( y = y1 + 1 ; y < = y2 ; + + y )
{
if ( d > = 0 ) { x + = xincr ; d + = aincr ; }
else d + = bincr ;
2015-02-23 11:43:13 +00:00
if ( ! fnCallback ( x , y ) )
2015-02-23 11:33:53 +00:00
{
if ( lastx ) * lastx = x ; if ( lasty ) * lasty = y ;
return false ;
}
}
}
else
{
2016-04-02 15:50:49 +00:00
if ( x1 > x2 ) { std : : swap ( x1 , x2 ) ; std : : swap ( y1 , y2 ) ; }
yincr = ( y2 > y1 ) ? 1 : - 1 ;
2015-02-23 11:33:53 +00:00
dx = x2 - x1 ; dy = Abs ( y2 - y1 ) ;
d = 2 * dy - dx ; aincr = 2 * ( dy - dx ) ; bincr = 2 * dy ; x = x1 ; y = y1 ;
2015-02-23 11:43:13 +00:00
if ( ! fnCallback ( x , y ) )
2015-02-23 11:33:53 +00:00
{
if ( lastx ) * lastx = x ; if ( lasty ) * lasty = y ;
return false ;
}
for ( x = x1 + 1 ; x < = x2 ; + + x )
{
if ( d > = 0 ) { y + = yincr ; d + = aincr ; }
else d + = bincr ;
2015-02-23 11:43:13 +00:00
if ( ! fnCallback ( x , y ) )
2015-02-23 11:33:53 +00:00
{
if ( lastx ) * lastx = x ; if ( lasty ) * lasty = y ;
return false ;
}
}
}
return true ;
}
}
2009-05-08 13:28:41 +00:00
C4Landscape : : C4Landscape ( )
2016-04-02 15:50:49 +00:00
: p ( new P )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Default ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4Landscape : : ~ C4Landscape ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Clear ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* +++++++++++++++++++++++++ Execute and display +++++++++++++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2009-05-08 13:28:41 +00:00
void C4Landscape : : Execute ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Landscape scan
2016-04-02 15:50:49 +00:00
if ( ! p - > NoScan )
p - > ExecuteScan ( this ) ;
2009-05-08 13:28:41 +00:00
// move sky
2016-04-02 15:50:49 +00:00
p - > Sky . Execute ( ) ;
2015-03-25 18:04:04 +00:00
2014-11-18 19:40:44 +00:00
// Queued Relights -- note that normally we process them before drawing every frame;
// this just makes sure relights don't accumulate over a long period of time if no
// viewport is open (developer mode).
2010-03-27 16:05:02 +00:00
if ( ! : : Game . iTick35 )
2009-05-08 13:28:41 +00:00
DoRelights ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
void C4Landscape : : P : : ExecuteScan ( C4Landscape * d )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t cy , mat ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Check: Scan needed?
2009-06-11 19:59:35 +00:00
const int32_t iTemperature = : : Weather . GetTemperature ( ) ;
2010-03-28 18:58:01 +00:00
for ( mat = 0 ; mat < : : MaterialMap . Num ; mat + + )
if ( MatCount [ mat ] )
{
if ( : : MaterialMap . Map [ mat ] . BelowTempConvertTo & &
2016-04-02 15:50:49 +00:00
iTemperature < : : MaterialMap . Map [ mat ] . BelowTempConvert )
2010-03-27 16:05:02 +00:00
break ;
2010-03-28 18:58:01 +00:00
else if ( : : MaterialMap . Map [ mat ] . AboveTempConvertTo & &
2016-04-02 15:50:49 +00:00
iTemperature > : : MaterialMap . Map [ mat ] . AboveTempConvert )
2010-03-27 16:05:02 +00:00
break ;
2010-03-28 18:58:01 +00:00
}
if ( mat > = : : MaterialMap . Num )
2010-03-27 16:05:02 +00:00
return ;
2009-05-08 13:28:41 +00:00
# ifdef DEBUGREC_MATSCAN
2013-05-25 20:38:08 +00:00
if ( Config . General . DebugRec )
AddDbgRec ( RCT_MatScan , & ScanX , sizeof ( ScanX ) ) ;
2009-05-08 13:28:41 +00:00
# endif
2016-04-02 15:50:49 +00:00
for ( int32_t cnt = 0 ; cnt < ScanSpeed ; cnt + + )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Scan landscape column: sectors down
2010-03-28 18:58:01 +00:00
int32_t last_mat = - 1 ;
2016-04-02 15:50:49 +00:00
for ( cy = 0 ; cy < Height ; cy + + )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
mat = d - > _GetMat ( ScanX , cy ) ;
2010-03-28 18:58:01 +00:00
// material change?
if ( last_mat ! = mat )
{
// upwards
if ( last_mat ! = - 1 )
2016-04-02 15:50:49 +00:00
DoScan ( d , ScanX , cy - 1 , last_mat , 1 ) ;
2010-03-28 18:58:01 +00:00
// downwards
if ( mat ! = - 1 )
2016-04-02 15:50:49 +00:00
cy + = DoScan ( d , ScanX , cy , mat , 0 ) ;
2010-03-28 18:58:01 +00:00
}
last_mat = mat ;
}
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Scan advance & rewind
ScanX + + ;
2016-04-02 15:50:49 +00:00
if ( ScanX > = Width )
ScanX = 0 ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
# define PRETTY_TEMP_CONV
2016-04-02 15:50:49 +00:00
int32_t C4Landscape : : P : : DoScan ( C4Landscape * d , int32_t cx , int32_t cy , int32_t mat , int32_t dir )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int32_t conv_to_tex = 0 ;
2009-06-11 19:59:35 +00:00
int32_t iTemperature = : : Weather . GetTemperature ( ) ;
2010-03-27 16:05:02 +00:00
// Check below conv
2010-03-28 18:58:01 +00:00
if ( : : MaterialMap . Map [ mat ] . BelowTempConvertDir = = dir )
2009-06-05 18:46:03 +00:00
if ( : : MaterialMap . Map [ mat ] . BelowTempConvertTo )
if ( iTemperature < : : MaterialMap . Map [ mat ] . BelowTempConvert )
2016-04-02 15:50:49 +00:00
conv_to_tex = : : MaterialMap . Map [ mat ] . BelowTempConvertTo ;
2010-03-27 16:05:02 +00:00
// Check above conv
2010-03-28 18:58:01 +00:00
if ( : : MaterialMap . Map [ mat ] . AboveTempConvertDir = = dir )
2009-06-05 18:46:03 +00:00
if ( : : MaterialMap . Map [ mat ] . AboveTempConvertTo )
if ( iTemperature > : : MaterialMap . Map [ mat ] . AboveTempConvert )
2016-04-02 15:50:49 +00:00
conv_to_tex = : : MaterialMap . Map [ mat ] . AboveTempConvertTo ;
2009-05-08 13:28:41 +00:00
// nothing to do?
if ( ! conv_to_tex ) return 0 ;
// find material
2009-06-05 15:09:54 +00:00
int32_t conv_to = : : TextureMap . GetEntry ( conv_to_tex ) - > GetMaterialIndex ( ) ;
2009-05-08 13:28:41 +00:00
// find mat top
2009-06-05 18:46:03 +00:00
int32_t mconv = : : MaterialMap . Map [ mat ] . TempConvStrength ,
2016-04-02 15:50:49 +00:00
mconvs = mconv ;
2009-05-08 13:28:41 +00:00
# ifdef DEBUGREC_MATSCAN
2013-05-25 20:38:08 +00:00
if ( Config . General . DebugRec )
{
C4RCMatScan rc = { cx , cy , mat , conv_to , dir , mconvs } ;
AddDbgRec ( RCT_MatScanDo , & rc , sizeof ( C4RCMatScan ) ) ;
}
2009-05-08 13:28:41 +00:00
# endif
int32_t ydir = ( dir = = 0 ? + 1 : - 1 ) , cy2 ;
# ifdef PRETTY_TEMP_CONV
// get left pixel
2016-04-02 15:50:49 +00:00
int32_t lmat = ( cx > 0 ? d - > _GetMat ( cx - 1 , cy ) : - 1 ) ;
2009-05-08 13:28:41 +00:00
// left pixel not converted? do nothing
2010-03-28 18:58:01 +00:00
if ( lmat = = mat ) return 0 ;
2009-05-08 13:28:41 +00:00
// left pixel converted? suppose it was done by a prior scan and skip check
2010-03-28 18:58:01 +00:00
if ( lmat ! = conv_to )
2009-05-08 13:28:41 +00:00
{
2015-11-15 12:53:01 +00:00
int32_t iSearchRange = std : : max < int32_t > ( 5 , mconvs ) ;
2009-05-08 13:28:41 +00:00
// search upper/lower bound
int32_t cys = cy , cxs = cx ;
2016-04-02 15:50:49 +00:00
while ( cxs < : : Landscape . GetWidth ( ) - 1 )
2009-05-08 13:28:41 +00:00
{
// one step right
cxs + + ;
2016-04-02 15:50:49 +00:00
if ( d - > _GetMat ( cxs , cys ) = = mat )
2009-05-08 13:28:41 +00:00
{
// search surface
cys - = ydir ;
2016-04-02 15:50:49 +00:00
while ( Inside < int32_t > ( cys , 0 , : : Landscape . GetHeight ( ) - 1 ) & & d - > _GetMat ( cxs , cys ) = = mat )
2009-05-08 13:28:41 +00:00
{
cys - = ydir ;
2015-11-15 12:53:01 +00:00
if ( ( mconvs = std : : min ( mconv - Abs ( cys - cy ) , mconvs ) ) < 0 )
2009-05-08 13:28:41 +00:00
return 0 ;
}
// out of bounds?
2016-04-02 15:50:49 +00:00
if ( ! Inside < int32_t > ( cys , 0 , : : Landscape . GetHeight ( ) - 1 ) ) break ;
2009-05-08 13:28:41 +00:00
// back one step
cys + = ydir ;
}
else
{
// search surface
cys + = ydir ;
2016-04-02 15:50:49 +00:00
while ( Inside < int32_t > ( cys , 0 , : : Landscape . GetHeight ( ) - 1 ) & & d - > _GetMat ( cxs , cys ) ! = mat )
2009-05-08 13:28:41 +00:00
{
cys + = ydir ;
2010-03-28 18:58:01 +00:00
if ( Abs ( cys - cy ) > iSearchRange )
2009-05-08 13:28:41 +00:00
break ;
}
// out of bounds?
2016-04-02 15:50:49 +00:00
if ( ! Inside < int32_t > ( cys , 0 , : : Landscape . GetHeight ( ) - 1 ) ) break ;
2010-03-28 18:58:01 +00:00
if ( Abs ( cys - cy ) > iSearchRange ) break ;
2009-05-08 13:28:41 +00:00
}
}
}
# endif
// Conversion
2016-04-02 15:50:49 +00:00
bool conv_to_is_solid = ( conv_to > - 1 ) & & DensitySolid ( : : MaterialMap . Map [ conv_to ] . Density ) ;
for ( cy2 = cy ; mconvs > = 0 & & Inside < int32_t > ( cy2 , 0 , : : Landscape . GetHeight ( ) - 1 ) ; cy2 + = ydir , mconvs - - )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// material changed?
2016-04-02 15:50:49 +00:00
int32_t pix = d - > _GetPix ( cx , cy2 ) ;
2010-03-28 18:58:01 +00:00
if ( PixCol2Mat ( pix ) ! = mat ) break ;
2009-05-08 13:28:41 +00:00
# ifdef PRETTY_TEMP_CONV
// get left pixel
2016-04-02 15:50:49 +00:00
int32_t lmat = ( cx > 0 ? d - > _GetMat ( cx - 1 , cy2 ) : - 1 ) ;
2009-05-08 13:28:41 +00:00
// left pixel not converted? break
2010-03-28 18:58:01 +00:00
if ( lmat = = mat ) break ;
2009-05-08 13:28:41 +00:00
# endif
2015-07-01 01:58:42 +00:00
// set mat (and keep background material)
2016-04-02 15:50:49 +00:00
d - > SetPix2 ( cx , cy2 , MatTex2PixCol ( conv_to_tex ) , Transparent ) ;
if ( ! conv_to_is_solid ) d - > CheckInstabilityRange ( cx , cy2 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// return pixel converted
return Abs ( cy2 - cy ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Landscape : : ScanSideOpen ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int32_t cy ;
2016-04-02 15:50:49 +00:00
for ( cy = 0 ; ( cy < p - > Height ) & & ! GetPix ( 0 , cy ) ; cy + + ) { }
p - > LeftOpen = cy ;
for ( cy = 0 ; ( cy < p - > Height ) & & ! GetPix ( p - > Width - 1 , cy ) ; cy + + ) { }
p - > RightOpen = cy ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
2009-05-08 13:28:41 +00:00
2012-08-19 18:35:10 +00:00
void C4Landscape : : Draw ( C4TargetFacet & cgo , C4FoWRegion * pLight )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( p - > Modulation ) pDraw - > ActivateBlitModulation ( p - > Modulation ) ;
2009-05-08 13:28:41 +00:00
// blit landscape
2015-07-15 00:44:11 +00:00
if ( : : GraphicsSystem . Show8BitSurface = = 1 )
2016-04-02 15:50:49 +00:00
pDraw - > Blit8Fast ( p - > Surface8 . get ( ) , cgo . TargetX , cgo . TargetY , cgo . Surface , cgo . X , cgo . Y , cgo . Wdt , cgo . Hgt ) ;
2015-07-15 00:44:11 +00:00
else if ( : : GraphicsSystem . Show8BitSurface = = 2 )
2016-04-02 15:50:49 +00:00
pDraw - > Blit8Fast ( p - > Surface8Bkg . get ( ) , cgo . TargetX , cgo . TargetY , cgo . Surface , cgo . X , cgo . Y , cgo . Wdt , cgo . Hgt ) ;
else if ( p - > pLandscapeRender )
2010-03-28 18:58:01 +00:00
{
2014-11-18 20:03:10 +00:00
DoRelights ( ) ;
2016-04-02 15:50:49 +00:00
p - > pLandscapeRender - > Draw ( cgo , pLight ) ;
2009-05-08 13:28:41 +00:00
}
2016-04-02 15:50:49 +00:00
if ( p - > Modulation ) pDraw - > DeactivateBlitModulation ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : DoRelights ( )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! p - > pLandscapeRender ) return true ;
2011-05-31 01:04:38 +00:00
for ( int32_t i = 0 ; i < C4LS_MaxRelights ; i + + )
2009-05-08 13:28:41 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! p - > Relights [ i ] . Wdt )
2011-05-31 01:04:38 +00:00
break ;
// Remove all solid masks in the (twice!) extended region around the change
2016-04-02 15:50:49 +00:00
C4Rect SolidMaskRect = p - > pLandscapeRender - > GetAffectedRect ( p - > Relights [ i ] ) ;
2011-05-31 01:04:38 +00:00
C4SolidMask * pSolid ;
for ( pSolid = C4SolidMask : : Last ; pSolid ; pSolid = pSolid - > Prev )
pSolid - > RemoveTemporary ( SolidMaskRect ) ;
// Perform the update
2016-04-02 15:50:49 +00:00
p - > pLandscapeRender - > Update ( p - > Relights [ i ] , this ) ;
if ( p - > pFoW ) p - > pFoW - > Ambient . UpdateFromLandscape ( * this , p - > Relights [ i ] ) ;
2011-05-31 01:04:38 +00:00
// Restore Solidmasks
for ( pSolid = C4SolidMask : : First ; pSolid ; pSolid = pSolid - > Next )
pSolid - > PutTemporary ( SolidMaskRect ) ;
C4SolidMask : : CheckConsistency ( ) ;
// Clear slot
2016-04-02 15:50:49 +00:00
p - > Relights [ i ] . Default ( ) ;
2009-05-08 13:28:41 +00:00
}
2011-05-31 01:04:38 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* +++++++++++++++++++++++ Add and destroy landscape++++++++++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2015-12-02 00:48:13 +00:00
static std : : vector < int32_t > GetRoundPolygon ( int32_t x , int32_t y , int32_t size , int32_t smoothness )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
/*
So what is this ? It ' s basically a circle with the radius ' size ' . The radius
is adjusted by two sin / cos waves . The random lies in the phase of the sin / cos
and in the factor the wave is added to the normal circle shape . smoothness from
0 to 100. 0 gives an exagerated ' explosion ' shape while 100 is almost a circle
*/
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
if ( smoothness > 100 ) smoothness = 100 ;
if ( smoothness < 0 ) smoothness = 0 ;
if ( size < = 0 ) size = 1 ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// vertex count of the polygon
2016-04-02 15:50:49 +00:00
int32_t count = 2 * size / 3 + 6 ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
std : : vector < int32_t > vertices ;
2016-04-02 15:50:49 +00:00
vertices . reserve ( count * 2 ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// varying phase of the sin/cos waves
2016-04-20 18:46:55 +00:00
C4Real begin = itofix ( 360 ) * ( int32_t ) Random ( 100 ) / 100 ;
C4Real begin2 = itofix ( 360 ) * ( int32_t ) Random ( 100 ) / 100 ;
2011-05-31 01:04:38 +00:00
// parameters:
// the bigger the factor, the smaller the divergence from a circle
2016-04-02 15:50:49 +00:00
C4Real anticircle = itofix ( 3 ) + smoothness / 16 * smoothness / 16 ;
2011-05-31 01:04:38 +00:00
// the bigger the factor the more random is the divergence from the circle
2016-04-02 15:50:49 +00:00
int random = 80 * ( 200 - smoothness ) ;
2011-05-31 01:04:38 +00:00
2016-04-02 15:50:49 +00:00
for ( int i = 0 ; i < count ; + + i )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
C4Real angle = itofix ( 360 ) * i / count ;
2011-05-31 01:04:38 +00:00
C4Real currsize = itofix ( size ) ;
2016-04-02 15:50:49 +00:00
currsize + = Sin ( angle * 3 + begin + itofix ( Random ( random ) ) / 100 ) * size / anticircle ; // +sin
currsize + = Cos ( angle * 5 + begin2 + itofix ( Random ( random ) ) / 100 ) * size / anticircle / 2 ; // +cos
2011-05-31 01:04:38 +00:00
2016-04-02 15:50:49 +00:00
vertices . push_back ( x + fixtoi ( Sin ( angle ) * currsize ) ) ;
vertices . push_back ( y - fixtoi ( Cos ( angle ) * currsize ) ) ;
2009-05-08 13:28:41 +00:00
}
2011-05-31 01:04:38 +00:00
return vertices ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-12-02 00:48:13 +00:00
static std : : vector < int32_t > GetRectangle ( int32_t tx , int32_t ty , int32_t wdt , int32_t hgt )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
std : : vector < int32_t > vertices ;
vertices . resize ( 8 ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
vertices [ 0 ] = tx ; vertices [ 1 ] = ty ;
2016-04-02 15:50:49 +00:00
vertices [ 2 ] = tx ; vertices [ 3 ] = ty + hgt ;
vertices [ 4 ] = tx + wdt ; vertices [ 5 ] = ty + hgt ;
vertices [ 6 ] = tx + wdt ; vertices [ 7 ] = ty ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
return vertices ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-12-02 00:48:13 +00:00
static C4Rect getBoundingBox ( int * vtcs , int length )
{
C4Rect BoundingBox ( vtcs [ 0 ] , vtcs [ 1 ] , 1 , 1 ) ;
for ( int32_t i = 2 ; i + 1 < length ; i + = 2 )
{
BoundingBox . Add ( C4Rect ( vtcs [ i ] , vtcs [ i + 1 ] , 1 , 1 ) ) ;
}
return BoundingBox ;
}
2011-05-31 01:04:38 +00:00
void C4Landscape : : ClearFreeRect ( int32_t tx , int32_t ty , int32_t wdt , int32_t hgt )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
std : : vector < int32_t > vertices ( GetRectangle ( tx , ty , wdt , hgt ) ) ;
2015-12-02 00:41:47 +00:00
C4Rect r ( tx , ty , wdt , hgt ) ;
2016-04-02 15:50:49 +00:00
p - > PrepareChange ( this , r ) ;
p - > ForPolygon ( this , & vertices [ 0 ] , vertices . size ( ) / 2 , [ this ] ( int32_t x , int32_t y ) { return ClearPix ( x , y ) ; } ) ;
p - > FinishChange ( this , r ) ;
2011-05-31 01:04:38 +00:00
}
2009-05-08 13:28:41 +00:00
2013-03-31 13:39:29 +00:00
int32_t C4Landscape : : DigFreeRect ( int32_t tx , int32_t ty , int32_t wdt , int32_t hgt , C4Object * by_object , bool no_dig2objects , bool no_instability_check )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
std : : vector < int32_t > vertices ( GetRectangle ( tx , ty , wdt , hgt ) ) ;
return DigFreeShape ( & vertices [ 0 ] , vertices . size ( ) , by_object , no_dig2objects , no_instability_check ) ;
2011-05-31 01:04:38 +00:00
}
2009-05-08 13:28:41 +00:00
2013-03-31 13:39:29 +00:00
int32_t C4Landscape : : DigFree ( int32_t tx , int32_t ty , int32_t rad , C4Object * by_object , bool no_dig2objects , bool no_instability_check )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
std : : vector < int32_t > vertices ( GetRoundPolygon ( tx , ty , rad , 80 ) ) ;
return DigFreeShape ( & vertices [ 0 ] , vertices . size ( ) , by_object , no_dig2objects , no_instability_check ) ;
2011-05-31 01:04:38 +00:00
}
2009-05-08 13:28:41 +00:00
2013-03-25 23:45:44 +00:00
void C4Landscape : : BlastFree ( int32_t tx , int32_t ty , int32_t rad , int32_t caused_by , C4Object * by_object , int32_t iMaxDensity )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
std : : vector < int32_t > vertices ( GetRoundPolygon ( tx , ty , rad , 30 ) ) ;
BlastFreeShape ( & vertices [ 0 ] , vertices . size ( ) , by_object , caused_by , iMaxDensity ) ;
2011-05-31 01:04:38 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : ShakeFree ( int32_t tx , int32_t ty , int32_t rad )
{
2016-04-02 15:50:49 +00:00
std : : vector < int32_t > vertices ( GetRoundPolygon ( tx , ty , rad , 50 ) ) ;
p - > ForPolygon ( this , & vertices [ 0 ] , vertices . size ( ) / 2 , [ this ] ( int32_t x , int32_t y ) { return p - > ShakeFreePix ( this , x , y ) ; } ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
C4ValueArray * C4Landscape : : P : : PrepareFreeShape ( C4Rect & BoundingBox , C4Object * by_object )
2010-03-28 18:58:01 +00:00
{
2015-10-02 02:43:01 +00:00
// Remember any in-earth objects in area
2013-02-20 20:12:31 +00:00
C4FindObjectInRect fo_inrect ( BoundingBox ) ;
C4FindObjectOCF fo_insolid ( OCF_InSolid ) ;
C4FindObjectLayer fo_layer ( by_object ? by_object - > Layer : NULL ) ;
2016-04-02 15:50:49 +00:00
C4FindObject * fo_list [ ] = { & fo_inrect , & fo_insolid , & fo_layer } ;
2015-10-02 02:43:01 +00:00
C4FindObjectAndStatic fo_srch ( 3 , fo_list ) ;
2014-01-22 20:46:50 +00:00
return fo_srch . FindMany ( : : Objects , : : Objects . Sectors ) ;
}
2016-04-02 15:50:49 +00:00
void C4Landscape : : P : : PostFreeShape ( C4ValueArray * dig_objects , C4Object * by_object )
2014-01-22 20:46:50 +00:00
{
2015-10-02 02:43:01 +00:00
// Do callbacks to digger and dug out objects for objects that are now dug free
2014-01-22 20:46:50 +00:00
if ( by_object )
{
2016-04-02 15:50:49 +00:00
for ( int32_t i = 0 ; i < dig_objects - > GetSize ( ) ; + + i )
2014-01-22 20:46:50 +00:00
{
C4Object * dig_object = dig_objects - > GetItem ( i ) . getObj ( ) ;
if ( dig_object & & ! GBackSolid ( dig_object - > GetX ( ) , dig_object - > GetY ( ) ) )
2015-10-02 02:43:01 +00:00
if ( dig_object ! = by_object )
if ( ! dig_object - > Contained & & dig_object - > Status )
{
2014-05-30 23:03:23 +00:00
C4AulParSet pars ( by_object ) ;
2015-10-02 02:43:01 +00:00
dig_object - > Call ( PSF_OnDugOut , & pars ) ;
if ( dig_object - > Status & & by_object - > Status )
{
2014-05-30 23:03:23 +00:00
C4AulParSet pars ( dig_object ) ;
2015-10-02 02:43:01 +00:00
by_object - > Call ( PSF_DigOutObject , & pars ) ;
}
}
2014-01-22 20:46:50 +00:00
}
}
}
int32_t C4Landscape : : DigFreeShape ( int * vtcs , int length , C4Object * by_object , bool no_dig2objects , bool no_instability_check )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
using namespace std : : placeholders ;
C4Rect BoundingBox = getBoundingBox ( vtcs , length ) ;
2012-04-05 01:59:45 +00:00
int32_t amount ;
2009-05-08 13:28:41 +00:00
2014-01-22 20:46:50 +00:00
// Remember any collectible objects in area
2016-04-02 15:50:49 +00:00
std : : unique_ptr < C4ValueArray > dig_objects ( p - > PrepareFreeShape ( BoundingBox , by_object ) ) ;
std : : function < bool ( int32_t , int32_t ) > callback ;
if ( no_instability_check )
callback = [ this ] ( int32_t x , int32_t y ) { return p - > DigFreePixNoInstability ( this , x , y ) ; } ;
else
callback = [ this ] ( int32_t x , int32_t y ) { return p - > DigFreePix ( this , x , y ) ; } ;
2013-02-20 20:12:31 +00:00
2016-04-02 15:50:49 +00:00
if ( by_object )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! by_object - > MaterialContents )
2011-05-31 01:04:38 +00:00
by_object - > MaterialContents = new C4MaterialList ;
2016-04-02 15:50:49 +00:00
amount = p - > ForPolygon ( this , vtcs , length / 2 , callback , by_object - > MaterialContents ) ;
2011-05-31 01:04:38 +00:00
}
else
2016-04-02 15:50:49 +00:00
amount = p - > ForPolygon ( this , vtcs , length / 2 , callback , NULL ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// create objects from the material
2016-04-02 15:50:49 +00:00
if ( ! : : Game . iTick5 )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! no_dig2objects )
if ( by_object )
if ( by_object - > MaterialContents )
2012-04-05 15:49:47 +00:00
{
int32_t tx = BoundingBox . GetMiddleX ( ) , ty = BoundingBox . GetBottom ( ) ;
2016-04-02 15:50:49 +00:00
p - > DigMaterial2Objects ( tx , ty , by_object - > MaterialContents , by_object ) ;
2012-04-05 15:49:47 +00:00
}
2011-05-31 01:04:38 +00:00
}
2013-02-20 20:12:31 +00:00
// Do callbacks to digger for objects that are now dug free
2016-04-02 15:50:49 +00:00
p - > PostFreeShape ( dig_objects . get ( ) , by_object ) ;
2013-02-20 20:12:31 +00:00
2012-04-05 01:59:45 +00:00
return amount ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-03-25 23:45:44 +00:00
void C4Landscape : : BlastFreeShape ( int * vtcs , int length , C4Object * by_object , int32_t by_player , int32_t iMaxDensity )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
C4MaterialList * MaterialContents = NULL ;
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
C4Rect BoundingBox = getBoundingBox ( vtcs , length ) ;
2009-05-08 13:28:41 +00:00
2014-01-22 20:46:50 +00:00
// Remember any collectible objects in area
2016-04-02 15:50:49 +00:00
std : : unique_ptr < C4ValueArray > dig_objects ( p - > PrepareFreeShape ( BoundingBox , by_object ) ) ;
2014-01-22 20:46:50 +00:00
2015-06-22 22:56:04 +00:00
uint8_t * pblast_tbl = NULL , blast_tbl [ C4M_MaxTexIndex ] ;
2013-03-25 23:45:44 +00:00
if ( iMaxDensity < C4M_Vehicle )
{
2016-04-02 15:50:49 +00:00
for ( int32_t i = 0 ; i < C4M_MaxTexIndex ; + + i ) blast_tbl [ i ] = ( GetPixDensity ( i ) < = iMaxDensity ) ;
2013-03-25 23:45:44 +00:00
pblast_tbl = blast_tbl ;
}
2016-04-02 15:50:49 +00:00
if ( by_object )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! by_object - > MaterialContents )
2011-05-31 01:04:38 +00:00
by_object - > MaterialContents = new C4MaterialList ;
2016-04-02 15:50:49 +00:00
p - > ForPolygon ( this , vtcs , length / 2 , [ this ] ( int32_t x , int32_t y ) { return p - > BlastFreePix ( this , x , y ) ; } , by_object - > MaterialContents , 0 , 0 , pblast_tbl ) ;
2011-05-31 01:04:38 +00:00
}
else
{
MaterialContents = new C4MaterialList ;
2016-04-02 15:50:49 +00:00
p - > ForPolygon ( this , vtcs , length / 2 , [ this ] ( int32_t x , int32_t y ) { return p - > BlastFreePix ( this , x , y ) ; } , MaterialContents , iMaxDensity ) ;
2011-05-31 01:04:38 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// create objects from the material
C4MaterialList * mat_list = NULL ;
2016-04-02 15:50:49 +00:00
if ( by_object )
2011-05-31 01:04:38 +00:00
mat_list = by_object - > MaterialContents ;
else
mat_list = MaterialContents ;
int32_t tx = BoundingBox . GetMiddleX ( ) , ty = BoundingBox . GetMiddleY ( ) ;
2016-04-02 15:50:49 +00:00
p - > BlastMaterial2Objects ( tx , ty , mat_list , by_player , ( BoundingBox . Wdt + BoundingBox . Hgt ) / 4 , dig_objects . get ( ) ) ;
2011-05-31 01:04:38 +00:00
2016-04-02 15:50:49 +00:00
if ( MaterialContents ) delete MaterialContents ;
2014-01-22 20:46:50 +00:00
// Do callbacks to digger for objects that are now dug free
2016-04-02 15:50:49 +00:00
p - > PostFreeShape ( dig_objects . get ( ) , by_object ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
void C4Landscape : : P : : BlastMaterial2Objects ( int32_t tx , int32_t ty , C4MaterialList * mat_list , int32_t caused_by , int32_t str , C4ValueArray * out_objects )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
for ( int32_t mat = 0 ; mat < : : MaterialMap . Num ; mat + + )
2011-05-31 01:04:38 +00:00
{
if ( mat_list - > Amount [ mat ] )
{
int32_t cast_strength = str ;
int32_t pxsamount = 0 , blastamount = 0 ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
if ( : : MaterialMap . Map [ mat ] . Blast2PXSRatio ! = 0 )
{
2016-04-02 15:50:49 +00:00
pxsamount = mat_list - > Amount [ mat ] / : : MaterialMap . Map [ mat ] . Blast2PXSRatio ;
: : PXS . Cast ( mat , pxsamount , tx , ty , cast_strength * 2 ) ;
2011-05-31 01:04:38 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
if ( : : MaterialMap . Map [ mat ] . Blast2Object ! = C4ID : : None )
{
if ( : : MaterialMap . Map [ mat ] . Blast2ObjectRatio ! = 0 )
{
2016-04-02 15:50:49 +00:00
blastamount = mat_list - > Amount [ mat ] / : : MaterialMap . Map [ mat ] . Blast2ObjectRatio ;
2014-01-22 20:46:50 +00:00
Game . CastObjects ( : : MaterialMap . Map [ mat ] . Blast2Object , NULL , blastamount , cast_strength , tx , ty , NO_OWNER , caused_by , out_objects ) ;
2011-05-31 01:04:38 +00:00
}
}
2009-05-08 13:28:41 +00:00
2015-11-15 12:53:01 +00:00
mat_list - > Amount [ mat ] - = std : : max ( blastamount * : : MaterialMap . Map [ mat ] . Blast2ObjectRatio ,
2016-04-02 15:50:49 +00:00
pxsamount * : : MaterialMap . Map [ mat ] . Blast2PXSRatio ) ;
2011-05-31 01:04:38 +00:00
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
void C4Landscape : : P : : DigMaterial2Objects ( int32_t tx , int32_t ty , C4MaterialList * mat_list , C4Object * pCollect )
2010-03-28 18:58:01 +00:00
{
2014-05-30 23:03:23 +00:00
C4AulParSet pars ( pCollect ) ;
2016-04-02 15:50:49 +00:00
for ( int32_t mat = 0 ; mat < : : MaterialMap . Num ; mat + + )
2011-05-31 01:04:38 +00:00
{
if ( mat_list - > Amount [ mat ] )
{
if ( : : MaterialMap . Map [ mat ] . Dig2Object ! = C4ID : : None )
if ( : : MaterialMap . Map [ mat ] . Dig2ObjectRatio ! = 0 )
2011-08-20 14:43:58 +00:00
while ( mat_list - > Amount [ mat ] > = : : MaterialMap . Map [ mat ] . Dig2ObjectRatio )
2011-05-31 01:04:38 +00:00
{
2015-01-25 13:19:39 +00:00
mat_list - > Amount [ mat ] - = : : MaterialMap . Map [ mat ] . Dig2ObjectRatio ;
2011-08-20 14:43:58 +00:00
C4Object * pObj = Game . CreateObject ( : : MaterialMap . Map [ mat ] . Dig2Object , NULL , NO_OWNER , tx , ty ) ;
2015-01-25 13:19:39 +00:00
if ( ! pObj | | ! pObj - > Status ) continue ;
2016-02-01 19:15:29 +00:00
// Set controller to the controller of the object responsible for digging out
if ( pCollect & & pCollect - > Status )
pObj - > Controller = pCollect - > Controller ;
2015-01-25 13:19:39 +00:00
// Do callbacks to dug object and digger
pObj - > Call ( PSF_OnDugOut , & pars ) ;
if ( ! pObj - > Status | | ! pCollect | | ! pCollect - > Status | | pObj - > Contained ) continue ;
C4AulParSet pars ( C4VObj ( pObj ) ) ;
pCollect - > Call ( PSF_DigOutObject , & pars ) ;
if ( ! pObj - > Status | | ! pCollect - > Status | | pObj - > Contained ) continue ;
2011-08-20 14:43:58 +00:00
// Try to collect object
2016-04-02 15:50:49 +00:00
if ( : : MaterialMap . Map [ mat ] . Dig2ObjectCollect )
if ( pCollect & & pCollect - > Status & & pObj & & pObj - > Status )
if ( ! pCollect - > Collect ( pObj ) )
2014-05-11 20:04:51 +00:00
// Collection forced? Don't generate objects
2016-04-02 15:50:49 +00:00
if ( : : MaterialMap . Map [ mat ] . Dig2ObjectCollect = = 2 )
2014-05-11 20:04:51 +00:00
{
pObj - > AssignRemoval ( ) ;
2015-01-25 13:19:39 +00:00
// Cap so we never have more than one object worth of material in the store
2014-05-11 20:04:51 +00:00
mat_list - > Amount [ mat ] = : : MaterialMap . Map [ mat ] . Dig2ObjectRatio ;
break ;
}
2011-05-31 01:04:38 +00:00
}
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : DigFreePixNoInstability ( C4Landscape * d , int32_t tx , int32_t ty )
2013-03-31 13:39:29 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t mat = d - > GetMat ( tx , ty ) ;
2013-03-31 13:39:29 +00:00
if ( MatValid ( mat ) )
if ( : : MaterialMap . Map [ mat ] . DigFree )
{
2016-04-02 15:50:49 +00:00
d - > ClearPix ( tx , ty ) ;
2013-03-31 13:39:29 +00:00
return true ;
}
return false ;
}
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : DigFreePix ( C4Landscape * d , int32_t tx , int32_t ty )
2011-01-19 22:52:46 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t mat = d - > GetMat ( tx , ty ) ;
2011-05-31 01:04:38 +00:00
if ( MatValid ( mat ) )
if ( : : MaterialMap . Map [ mat ] . DigFree )
{
2016-04-02 15:50:49 +00:00
d - > ClearPix ( tx , ty ) ;
2011-05-31 01:04:38 +00:00
// check for instable materials to start moving by the cleared space
2016-04-02 15:50:49 +00:00
d - > CheckInstabilityRange ( tx , ty ) ;
2011-05-31 01:04:38 +00:00
return true ;
}
return false ;
2011-01-19 22:52:46 +00:00
}
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : BlastFreePix ( C4Landscape * d , int32_t tx , int32_t ty )
2011-01-19 22:52:46 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t mat = d - > GetMat ( tx , ty ) ;
2011-05-31 01:04:38 +00:00
if ( MatValid ( mat ) )
{
// for blast, either shift to different material or blast free
if ( : : MaterialMap . Map [ mat ] . BlastFree )
{
2016-04-02 15:50:49 +00:00
d - > ClearPix ( tx , ty ) ;
2011-05-31 01:04:38 +00:00
// check for instable materials to start moving by the cleared space
2016-04-02 15:50:49 +00:00
d - > CheckInstabilityRange ( tx , ty ) ;
2011-05-31 01:04:38 +00:00
return true ;
}
else
if ( : : MaterialMap . Map [ mat ] . BlastShiftTo )
2016-04-02 15:50:49 +00:00
d - > SetPix2 ( tx , ty , MatTex2PixCol ( : : MaterialMap . Map [ mat ] . BlastShiftTo ) , Transparent ) ;
2011-05-31 01:04:38 +00:00
}
return false ;
}
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : ShakeFreePix ( C4Landscape * d , int32_t tx , int32_t ty )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t mat = d - > GetMat ( tx , ty ) ;
2011-05-31 01:04:38 +00:00
if ( MatValid ( mat ) )
{
if ( : : MaterialMap . Map [ mat ] . DigFree )
{
2016-04-02 15:50:49 +00:00
d - > ClearPix ( tx , ty ) ;
: : PXS . Create ( mat , itofix ( tx ) , itofix ( ty ) ) ;
2011-05-31 01:04:38 +00:00
// check for instable materials to start moving by the cleared space
2016-04-02 15:50:49 +00:00
d - > CheckInstabilityRange ( tx , ty ) ;
2011-05-31 01:04:38 +00:00
return true ;
}
}
return false ;
2011-01-19 22:52:46 +00:00
}
2011-05-31 01:04:38 +00:00
bool C4Landscape : : ClearPix ( int32_t tx , int32_t ty )
{
2015-06-17 00:58:43 +00:00
// Replace pixel with background pixel
2016-04-02 15:50:49 +00:00
BYTE bkgPix = p - > Surface8Bkg - > GetPix ( tx , ty ) ;
2015-06-17 00:58:43 +00:00
return SetPix2 ( tx , ty , bkgPix , bkgPix ) ;
2011-05-31 01:04:38 +00:00
}
2015-06-17 00:58:43 +00:00
2016-04-02 15:50:49 +00:00
void C4Landscape : : ClearPointers ( C4Object * pObj )
{
if ( p - > pFoW ) p - > pFoW - > Remove ( pObj ) ;
}
2015-06-17 00:58:43 +00:00
bool C4Landscape : : SetPix2 ( int32_t x , int32_t y , BYTE fgPix , BYTE bgPix )
{
2009-05-08 13:28:41 +00:00
// check bounds
2016-04-02 15:50:49 +00:00
if ( x < 0 | | y < 0 | | x > = GetWidth ( ) | | y > = GetHeight ( ) )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// no change?
2016-04-02 15:50:49 +00:00
if ( ( fgPix = = Transparent | | fgPix = = _GetPix ( x , y ) ) & & ( bgPix = = Transparent | | bgPix = = p - > Surface8Bkg - > _GetPix ( x , y ) ) )
2009-08-15 18:50:32 +00:00
return true ;
2009-05-08 13:28:41 +00:00
// set pixel
2015-06-17 00:58:43 +00:00
return _SetPix2 ( x , y , fgPix , bgPix ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-06-17 00:58:43 +00:00
bool C4Landscape : : _SetPix2 ( int32_t x , int32_t y , BYTE fgPix , BYTE bgPix )
2010-03-28 18:58:01 +00:00
{
2013-05-25 20:38:08 +00:00
if ( Config . General . DebugRec )
{
C4RCSetPix rc ;
2016-04-02 15:50:49 +00:00
rc . x = x ; rc . y = y ; rc . clr = fgPix ; rc . bgClr = fgPix ;
2013-05-25 20:38:08 +00:00
AddDbgRec ( RCT_SetPix , & rc , sizeof ( rc ) ) ;
}
2016-04-02 15:50:49 +00:00
assert ( x > = 0 & & y > = 0 & & x < GetWidth ( ) & & y < GetHeight ( ) ) ;
2015-06-22 22:56:04 +00:00
// get pixel and resolve transparency to already existing pixel
2010-03-27 16:05:02 +00:00
BYTE opix = _GetPix ( x , y ) ;
2015-08-05 03:15:52 +00:00
if ( fgPix = = Transparent ) fgPix = opix ;
2016-04-02 15:50:49 +00:00
if ( bgPix = = Transparent ) bgPix = p - > Surface8Bkg - > _GetPix ( x , y ) ;
2015-06-22 22:56:04 +00:00
// check pixel
2016-04-02 15:50:49 +00:00
if ( fgPix = = opix & & bgPix = = p - > Surface8Bkg - > _GetPix ( x , y ) ) return true ;
2009-05-08 13:28:41 +00:00
// count pixels
2016-04-02 15:50:49 +00:00
if ( p - > Pix2Dens [ fgPix ] )
{
if ( ! p - > Pix2Dens [ opix ] ) p - > PixCnt [ ( y / 15 ) + ( x / 17 ) * p - > PixCntPitch ] + + ;
}
2009-05-08 13:28:41 +00:00
else
2016-04-02 15:50:49 +00:00
{
if ( p - > Pix2Dens [ opix ] ) p - > PixCnt [ ( y / 15 ) + ( x / 17 ) * p - > PixCntPitch ] - - ;
}
2010-03-27 16:05:02 +00:00
// count material
2016-04-02 15:50:49 +00:00
assert ( ! fgPix | | MatValid ( p - > Pix2Mat [ fgPix ] ) ) ;
int32_t omat = p - > Pix2Mat [ opix ] , nmat = p - > Pix2Mat [ fgPix ] ;
if ( opix ) p - > MatCount [ omat ] - - ;
if ( fgPix ) p - > MatCount [ nmat ] + + ;
2010-03-27 16:05:02 +00:00
// count effective material
2010-03-28 18:58:01 +00:00
if ( omat ! = nmat )
{
2015-06-17 00:58:43 +00:00
if ( fgPix & & : : MaterialMap . Map [ nmat ] . MinHeightCount )
2010-03-27 16:05:02 +00:00
{
// Check for material above & below
int iMinHeight = : : MaterialMap . Map [ nmat ] . MinHeightCount ,
2016-04-02 15:50:49 +00:00
iBelow = GetMatHeight ( x , y + 1 , + 1 , nmat , iMinHeight ) ,
iAbove = GetMatHeight ( x , y - 1 , - 1 , nmat , iMinHeight ) ;
2010-03-27 16:05:02 +00:00
// Will be above treshold?
2010-03-28 18:58:01 +00:00
if ( iBelow + iAbove + 1 > = iMinHeight )
{
2010-03-27 16:05:02 +00:00
int iChange = 1 ;
// Check for heights below threshold
2010-03-28 18:58:01 +00:00
if ( iBelow < iMinHeight ) iChange + = iBelow ;
if ( iAbove < iMinHeight ) iChange + = iAbove ;
2010-03-27 16:05:02 +00:00
// Change
2016-04-02 15:50:49 +00:00
p - > EffectiveMatCount [ nmat ] + = iChange ;
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
if ( opix & & : : MaterialMap . Map [ omat ] . MinHeightCount )
{
2010-03-27 16:05:02 +00:00
// Check for material above & below
int iMinHeight = : : MaterialMap . Map [ omat ] . MinHeightCount ,
2016-04-02 15:50:49 +00:00
iBelow = GetMatHeight ( x , y + 1 , + 1 , omat , iMinHeight ) ,
iAbove = GetMatHeight ( x , y - 1 , - 1 , omat , iMinHeight ) ;
2010-03-27 16:05:02 +00:00
// Not already below threshold?
2010-03-28 18:58:01 +00:00
if ( iBelow + iAbove + 1 > = iMinHeight )
{
2010-03-27 16:05:02 +00:00
int iChange = 1 ;
// Check for heights that will get below threshold
2010-03-28 18:58:01 +00:00
if ( iBelow < iMinHeight ) iChange + = iBelow ;
if ( iAbove < iMinHeight ) iChange + = iAbove ;
2010-03-27 16:05:02 +00:00
// Change
2016-04-02 15:50:49 +00:00
p - > EffectiveMatCount [ omat ] - = iChange ;
2010-03-27 16:05:02 +00:00
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// set 8bpp-surface only!
2016-04-02 15:50:49 +00:00
p - > Surface8 - > SetPix ( x , y , fgPix ) ;
p - > Surface8Bkg - > SetPix ( x , y , bgPix ) ;
2015-11-08 21:33:59 +00:00
// note for relight
2016-04-02 15:50:49 +00:00
if ( p - > pLandscapeRender )
2015-11-08 21:33:59 +00:00
{
2016-04-02 15:50:49 +00:00
C4Rect CheckRect = p - > pLandscapeRender - > GetAffectedRect ( C4Rect ( x , y , 1 , 1 ) ) ;
2015-11-08 21:33:59 +00:00
for ( int32_t i = 0 ; i < C4LS_MaxRelights ; i + + )
2016-04-02 15:50:49 +00:00
if ( ! p - > Relights [ i ] . Wdt | | p - > Relights [ i ] . Overlap ( CheckRect ) | | i + 1 > = C4LS_MaxRelights )
2015-11-08 21:33:59 +00:00
{
2016-04-02 15:50:49 +00:00
p - > Relights [ i ] . Add ( CheckRect ) ;
2015-11-08 21:33:59 +00:00
break ;
}
// Invalidate FoW
2016-04-02 15:50:49 +00:00
if ( p - > pFoW )
p - > pFoW - > Invalidate ( CheckRect ) ;
2015-11-08 21:33:59 +00:00
}
2009-05-08 13:28:41 +00:00
// success
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-11-08 21:33:59 +00:00
void C4Landscape : : _SetPix2Tmp ( int32_t x , int32_t y , BYTE fgPix , BYTE bgPix )
{
// set 8bpp-surface only!
2016-04-02 15:50:49 +00:00
assert ( x > = 0 & & y > = 0 & & x < GetWidth ( ) & & y < GetHeight ( ) ) ;
if ( fgPix ! = Transparent ) p - > Surface8 - > SetPix ( x , y , fgPix ) ;
if ( bgPix ! = Transparent ) p - > Surface8Bkg - > SetPix ( x , y , bgPix ) ;
2015-11-08 21:33:59 +00:00
}
2013-02-10 17:28:48 +00:00
bool C4Landscape : : CheckInstability ( int32_t tx , int32_t ty , int32_t recursion_count )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t mat = GetMat ( tx , ty ) ;
2014-04-17 17:16:24 +00:00
if ( MatValid ( mat ) ) {
2014-08-05 15:01:37 +00:00
const C4Material & material = MaterialMap . Map [ mat ] ;
if ( material . Instable )
2016-04-02 15:50:49 +00:00
return : : MassMover . Create ( tx , ty ) ;
2013-02-10 17:28:48 +00:00
// Get rid of single pixels
2016-04-02 15:50:49 +00:00
else if ( DensitySolid ( material . Density ) & & ! material . KeepSinglePixels & & recursion_count < 10 )
if ( ( ! : : GBackSolid ( tx , ty + 1 ) ) + ( ! : : GBackSolid ( tx , ty - 1 ) ) + ( ! : : GBackSolid ( tx + 1 , ty ) ) + ( ! : : GBackSolid ( tx - 1 , ty ) ) > = 3 )
2013-02-10 17:28:48 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! ClearPix ( tx , ty ) ) return false ;
2014-08-05 15:01:37 +00:00
// Diggable material drops; other material just gets removed
2016-04-02 15:50:49 +00:00
if ( material . DigFree ) : : PXS . Create ( mat , itofix ( tx ) , itofix ( ty ) ) ;
2013-02-10 17:28:48 +00:00
// check other pixels around this
// Note this cannot lead to an endless recursion (unless you do funny stuff like e.g. set DigFree=1 in material Tunnel).
// Check recursion anyway, because very large strips of single pixel width might cause sufficient recursion to crash
2016-04-02 15:50:49 +00:00
CheckInstability ( tx + 1 , ty , + + recursion_count ) ;
CheckInstability ( tx - 1 , ty , recursion_count ) ;
CheckInstability ( tx , ty - 1 , recursion_count ) ;
CheckInstability ( tx , ty + 1 , recursion_count ) ;
2013-02-10 17:28:48 +00:00
return true ;
}
2014-04-17 17:16:24 +00:00
}
2010-03-27 16:05:02 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Landscape : : CheckInstabilityRange ( int32_t tx , int32_t ty )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! CheckInstability ( tx , ty ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
CheckInstability ( tx , ty - 1 ) ;
CheckInstability ( tx , ty - 2 ) ;
CheckInstability ( tx - 1 , ty ) ;
CheckInstability ( tx + 1 , ty ) ;
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2011-05-31 01:04:38 +00:00
void C4Landscape : : DrawMaterialRect ( int32_t mat , int32_t tx , int32_t ty , int32_t wdt , int32_t hgt )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t cx , cy ;
for ( cy = ty ; cy < ty + hgt ; cy + + )
for ( cx = tx ; cx < tx + wdt ; cx + + )
if ( ( MatDensity ( mat ) > = GetDensity ( cx , cy ) ) )
SetPix2 ( cx , cy , Mat2PixColDefault ( mat ) , p - > Surface8Bkg - > GetPix ( cx , cy ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : RaiseTerrain ( int32_t tx , int32_t ty , int32_t wdt )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t cx , cy ;
2011-05-31 01:04:38 +00:00
BYTE cpix ;
2016-04-02 15:50:49 +00:00
for ( cx = tx ; cx < tx + wdt ; cx + + )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
for ( cy = ty ; ( cy + 1 < : : Landscape . GetHeight ( ) ) & & ! GBackSolid ( cx , cy + 1 ) ; cy + + ) { }
if ( cy + 1 < : : Landscape . GetHeight ( ) ) if ( cy - ty < 20 )
{
cpix = GetPix ( cx , cy + 1 ) ;
if ( ! MatVehicle ( PixCol2Mat ( cpix ) ) )
while ( cy > = ty ) { SetPix2 ( cx , cy , cpix , GetBackPix ( cx , cy + 1 ) ) ; cy - - ; }
}
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
2015-05-01 16:04:42 +00:00
int32_t C4Landscape : : ExtractMaterial ( int32_t fx , int32_t fy , bool distant_first )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t mat = GetMat ( fx , fy ) ;
if ( mat = = MNone ) return MNone ;
FindMatTop ( mat , fx , fy , distant_first ) ;
ClearPix ( fx , fy ) ;
CheckInstabilityRange ( fx , fy ) ;
2011-05-31 01:04:38 +00:00
return mat ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-01-08 05:03:32 +00:00
bool C4Landscape : : InsertMaterialOutsideLandscape ( int32_t tx , int32_t ty , int32_t mdens )
{
// Out-of-bounds insertion considered successful if inserted into same or lower density
// This ensures pumping out of map works
// Do allow insertion into same density because it covers the case of e.g. pumping water into the upper ocean of an underwater scenario
return GetDensity ( tx , ty ) < = mdens ;
}
2013-04-28 11:54:29 +00:00
bool C4Landscape : : InsertMaterial ( int32_t mat , int32_t * tx , int32_t * ty , int32_t vx , int32_t vy , bool query_only )
2010-03-28 18:58:01 +00:00
{
2013-02-17 23:48:25 +00:00
assert ( tx ) ; assert ( ty ) ;
2011-05-31 01:04:38 +00:00
int32_t mdens ;
if ( ! MatValid ( mat ) ) return false ;
2016-04-02 15:50:49 +00:00
mdens = std : : min ( MatDensity ( mat ) , C4M_Solid ) ;
2011-05-31 01:04:38 +00:00
if ( ! mdens ) return true ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// Bounds
2016-04-02 15:50:49 +00:00
if ( ! Inside < int32_t > ( * tx , 0 , GetWidth ( ) - 1 ) | | ! Inside < int32_t > ( * ty , 0 , GetHeight ( ) ) ) return InsertMaterialOutsideLandscape ( * tx , * ty , mdens ) ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
if ( Game . C4S . Game . Realism . LandscapePushPull )
2011-05-30 22:33:35 +00:00
{
2011-05-31 01:04:38 +00:00
// Same or higher density?
2013-02-17 23:48:25 +00:00
if ( GetDensity ( * tx , * ty ) > = mdens )
2011-05-31 01:04:38 +00:00
// Push
2016-04-02 15:50:49 +00:00
if ( ! FindMatPathPush ( * tx , * ty , mdens , : : MaterialMap . Map [ mat ] . MaxSlide , ! ! : : MaterialMap . Map [ mat ] . Instable ) )
2011-05-31 01:04:38 +00:00
// Or die
return false ;
}
else
{
// Move up above same density
2016-04-02 15:50:49 +00:00
while ( mdens = = std : : min ( GetDensity ( * tx , * ty ) , C4M_Solid ) )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
( * ty ) - - ; if ( * ty < 0 ) return false ;
2011-05-31 01:04:38 +00:00
// Primitive slide (1)
2016-04-02 15:50:49 +00:00
if ( GetDensity ( * tx - 1 , * ty ) < mdens ) ( * tx ) - - ;
if ( GetDensity ( * tx + 1 , * ty ) < mdens ) ( * tx ) + + ;
2011-05-31 01:04:38 +00:00
}
// Stuck in higher density
2016-04-02 15:50:49 +00:00
if ( GetDensity ( * tx , * ty ) > mdens ) return false ;
2011-05-30 22:33:35 +00:00
}
2011-05-31 01:04:38 +00:00
// Try slide
2016-04-02 15:50:49 +00:00
while ( FindMatSlide ( * tx , * ty , + 1 , mdens , : : MaterialMap . Map [ mat ] . MaxSlide ) )
if ( GetDensity ( * tx , * ty + 1 ) < mdens )
{
if ( ! query_only ) : : PXS . Create ( mat , itofix ( * tx ) , itofix ( * ty ) , C4REAL10 ( vx ) , C4REAL10 ( vy ) ) ; return true ;
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
if ( query_only )
2013-06-02 15:58:20 +00:00
{
// since tx and ty changed, we need to re-check the bounds here
// if we really inserted it, the check is made again in InsertDeadMaterial
2016-04-02 15:50:49 +00:00
if ( ! Inside < int32_t > ( * tx , 0 , GetWidth ( ) - 1 ) | | ! Inside < int32_t > ( * ty , 0 , GetHeight ( ) ) ) return InsertMaterialOutsideLandscape ( * tx , * ty , mdens ) ;
return true ;
2013-06-02 15:58:20 +00:00
}
2009-05-08 13:28:41 +00:00
2012-12-16 17:52:32 +00:00
// Try reaction with material below and at insertion position
2011-05-31 01:04:38 +00:00
C4MaterialReaction * pReact ; int32_t tmat ;
2012-12-16 17:52:32 +00:00
int32_t check_dir = 0 ;
2016-04-02 15:50:49 +00:00
for ( int32_t i = 0 ; i < 2 ; + + i )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ( pReact = : : MaterialMap . GetReactionUnsafe ( mat , tmat = GetMat ( * tx , * ty + check_dir ) ) ) )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
C4Real fvx = C4REAL10 ( vx ) , fvy = C4REAL10 ( vy ) ;
if ( ( * pReact - > pFunc ) ( pReact , * tx , * ty , * tx , * ty + check_dir , fvx , fvy , mat , tmat , meePXSPos , NULL ) )
2012-12-16 17:52:32 +00:00
{
// the material to be inserted killed itself in some material reaction below
return true ;
}
2011-05-31 01:04:38 +00:00
}
2012-12-16 17:52:32 +00:00
if ( ! ( check_dir = Sign ( GravAccel ) ) ) break ;
2011-05-31 01:04:38 +00:00
}
2011-05-30 22:33:35 +00:00
2011-08-27 16:08:46 +00:00
// Insert as dead material
2013-02-17 23:48:25 +00:00
return InsertDeadMaterial ( mat , * tx , * ty ) ;
2011-08-27 16:08:46 +00:00
}
bool C4Landscape : : InsertDeadMaterial ( int32_t mat , int32_t tx , int32_t ty )
{
2011-10-01 17:32:16 +00:00
// Check bounds
2016-04-02 15:50:49 +00:00
if ( tx < 0 | | ty < 0 | | tx > = GetWidth ( ) | | ty > = GetHeight ( ) )
2016-01-08 05:03:32 +00:00
return InsertMaterialOutsideLandscape ( tx , ty , std : : min ( MatDensity ( mat ) , C4M_Solid ) ) ;
2011-10-01 17:32:16 +00:00
2011-08-27 16:08:46 +00:00
// Save back original material so we can insert it later
2011-05-31 01:04:38 +00:00
int omat = 0 ;
if ( Game . C4S . Game . Realism . LandscapeInsertThrust )
omat = GetMat ( tx , ty ) ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// Check surroundings for inspiration for texture to use
int n = 0 ; int pix = - 1 ;
2016-04-02 15:50:49 +00:00
if ( tx > 0 & & _GetMat ( tx - 1 , ty ) = = mat )
if ( ! Random ( + + n ) ) pix = _GetPix ( tx - 1 , ty ) ;
if ( ty > 0 & & _GetMat ( tx , ty - 1 ) = = mat )
if ( ! Random ( + + n ) ) pix = _GetPix ( tx , ty - 1 ) ;
if ( tx + 1 < GetWidth ( ) & & _GetMat ( tx + 1 , ty ) = = mat )
if ( ! Random ( + + n ) ) pix = _GetPix ( tx + 1 , ty ) ;
if ( ty + 1 < GetHeight ( ) & & _GetMat ( tx , ty + 1 ) = = mat )
if ( ! Random ( + + n ) ) pix = _GetPix ( tx , ty + 1 ) ;
if ( pix < 0 )
2011-05-31 01:04:38 +00:00
pix = Mat2PixColDefault ( mat ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Insert dead material
2016-04-02 15:50:49 +00:00
SetPix2 ( tx , ty , pix , Transparent ) ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// Search a position for the old material pixel
if ( Game . C4S . Game . Realism . LandscapeInsertThrust & & MatValid ( omat ) )
2013-02-17 17:29:44 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t tyo = ty - 1 ;
2013-02-17 23:48:25 +00:00
InsertMaterial ( omat , & tx , & tyo ) ;
2013-02-17 17:29:44 +00:00
}
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
return true ;
2011-05-30 22:33:35 +00:00
}
2015-10-09 20:24:16 +00:00
bool C4Landscape : : Incinerate ( int32_t x , int32_t y , int32_t cause_player )
2011-05-30 22:33:35 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t mat = GetMat ( x , y ) ;
2011-05-31 01:04:38 +00:00
if ( MatValid ( mat ) )
if ( : : MaterialMap . Map [ mat ] . Inflammable )
2015-10-09 20:24:16 +00:00
{
C4AulParSet pars ( C4VInt ( x ) , C4VInt ( y ) , C4VInt ( cause_player ) ) ;
: : ScriptEngine . GetPropList ( ) - > Call ( P_InflameLandscape , & pars ) ;
}
2011-05-31 01:04:38 +00:00
return false ;
2011-05-30 22:33:35 +00:00
}
2016-04-02 15:50:49 +00:00
BYTE C4Landscape : : P : : DefaultBkgMat ( BYTE fg ) const
2015-06-17 00:58:43 +00:00
{
2015-07-08 01:17:40 +00:00
return : : TextureMap . DefaultBkgMatTex ( fg ) ;
2015-06-17 00:58:43 +00:00
}
2016-04-02 15:50:49 +00:00
std : : unique_ptr < CSurface8 > C4Landscape : : P : : CreateDefaultBkgSurface ( CSurface8 & sfcFg , bool msbAsIft ) const
2015-06-22 22:56:04 +00:00
{
2016-04-02 15:50:49 +00:00
auto sfcBg = std : : make_unique < CSurface8 > ( ) ;
2015-06-22 22:56:04 +00:00
if ( ! sfcBg - > Create ( sfcFg . Wdt , sfcFg . Hgt ) )
2016-04-02 15:50:49 +00:00
{
return NULL ;
}
2015-06-22 22:56:04 +00:00
2016-04-02 15:50:49 +00:00
for ( int32_t y = 0 ; y < sfcFg . Hgt ; + + y )
2015-07-01 01:58:42 +00:00
{
2016-04-02 15:50:49 +00:00
for ( int32_t x = 0 ; x < sfcFg . Wdt ; + + x )
2015-07-01 01:58:42 +00:00
{
BYTE fgPix = sfcFg . _GetPix ( x , y ) ;
BYTE bgPix ;
// If we treat the most significant bit as the IFT flag
// (compatibility option for pre-7.0 maps), then set
// the background pixel to 0 if the foreground does not
// have IFT set, and remove the IFT flag from the
// foreground pixel.
if ( msbAsIft )
{
if ( fgPix & 0x80 )
{
fgPix & = ~ 0x80 ;
sfcFg . _SetPix ( x , y , fgPix ) ;
2016-04-02 15:50:49 +00:00
bgPix = DefaultBkgMat ( fgPix ) ;
2015-07-01 01:58:42 +00:00
}
else
{
bgPix = 0 ;
}
}
else
{
2016-04-02 15:50:49 +00:00
bgPix = DefaultBkgMat ( fgPix ) ;
2015-07-01 01:58:42 +00:00
}
sfcBg - > _SetPix ( x , y , bgPix ) ;
}
}
2015-06-22 22:56:04 +00:00
return sfcBg ;
}
2011-05-31 01:04:38 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* ++++ Polygon drawing code extracted from ALLEGRO by Shawn Hargreaves ++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2011-05-30 22:33:35 +00:00
struct CPolyEdge // An edge for the polygon drawer
{
int y ; // Current (starting at the top) y position
int bottom ; // bottom y position of this edge
int x ; // Fixed point x position
int dx ; // Fixed point x gradient
int w ; // Width of line segment
struct CPolyEdge * prev ; // Doubly linked list
struct CPolyEdge * next ;
} ;
# define POLYGON_FIX_SHIFT 16
static void fill_edge_structure ( CPolyEdge * edge , int * i1 , int * i2 )
{
if ( i2 [ 1 ] < i1 [ 1 ] ) // Swap
2016-04-02 15:50:49 +00:00
{
int * t = i1 ; i1 = i2 ; i2 = t ;
}
2011-05-30 22:33:35 +00:00
edge - > y = i1 [ 1 ] ;
edge - > bottom = i2 [ 1 ] - 1 ;
edge - > dx = ( ( i2 [ 0 ] - i1 [ 0 ] ) < < POLYGON_FIX_SHIFT ) / ( i2 [ 1 ] - i1 [ 1 ] ) ;
2016-04-02 15:50:49 +00:00
edge - > x = ( i1 [ 0 ] < < POLYGON_FIX_SHIFT ) + ( 1 < < ( POLYGON_FIX_SHIFT - 1 ) ) - 1 ;
2011-05-30 22:33:35 +00:00
edge - > prev = NULL ;
edge - > next = NULL ;
if ( edge - > dx < 0 )
2016-04-02 15:50:49 +00:00
edge - > x + = std : : min < int > ( edge - > dx + ( 1 < < POLYGON_FIX_SHIFT ) , 0 ) ;
edge - > w = std : : max < int > ( Abs ( edge - > dx ) - ( 1 < < POLYGON_FIX_SHIFT ) , 0 ) ;
2011-05-30 22:33:35 +00:00
}
static CPolyEdge * add_edge ( CPolyEdge * list , CPolyEdge * edge , int sort_by_x )
{
CPolyEdge * pos = list ;
CPolyEdge * prev = NULL ;
if ( sort_by_x )
{
2016-04-02 15:50:49 +00:00
while ( ( pos ) & & ( pos - > x + pos - > w / 2 < edge - > x + edge - > w / 2 ) )
{
prev = pos ; pos = pos - > next ;
}
2011-05-30 22:33:35 +00:00
}
else
{
while ( ( pos ) & & ( pos - > y < edge - > y ) )
2016-04-02 15:50:49 +00:00
{
prev = pos ; pos = pos - > next ;
}
2011-05-30 22:33:35 +00:00
}
edge - > next = pos ;
edge - > prev = prev ;
if ( pos ) pos - > prev = edge ;
if ( prev ) { prev - > next = edge ; return list ; }
else return edge ;
}
static CPolyEdge * remove_edge ( CPolyEdge * list , CPolyEdge * edge )
{
if ( edge - > next ) edge - > next - > prev = edge - > prev ;
if ( edge - > prev ) { edge - > prev - > next = edge - > next ; return list ; }
else return edge - > next ;
}
// Global polygon quick buffer
const int QuickPolyBufSize = 20 ;
CPolyEdge QuickPolyBuf [ QuickPolyBufSize ] ;
2016-04-02 15:50:49 +00:00
int32_t C4Landscape : : P : : ForPolygon ( C4Landscape * d , int * vtcs , int length , const std : : function < bool ( int32_t , int32_t ) > & callback ,
C4MaterialList * mats_count , uint8_t col , uint8_t colBkg , uint8_t * conversion_table )
2011-05-30 22:33:35 +00:00
{
// Variables for polygon drawer
2016-04-02 15:50:49 +00:00
int c , x1 , x2 , y ;
2011-05-30 22:33:35 +00:00
int top = INT_MAX ;
int bottom = INT_MIN ;
int * i1 , * i2 ;
CPolyEdge * edge , * next_edge , * edgebuf ;
CPolyEdge * active_edges = NULL ;
CPolyEdge * inactive_edges = NULL ;
2016-04-02 15:50:49 +00:00
bool use_qpb = false ;
2011-05-30 22:33:35 +00:00
2012-04-05 01:59:45 +00:00
// Return value
int32_t amount = 0 ;
2011-05-30 22:33:35 +00:00
// Poly Buf
2016-04-02 15:50:49 +00:00
if ( length < = QuickPolyBufSize )
{
edgebuf = QuickPolyBuf ; use_qpb = true ;
}
else if ( ! ( edgebuf = new CPolyEdge [ length ] ) ) { return 0 ; }
2011-05-30 22:33:35 +00:00
// Fill the edge table
edge = edgebuf ;
i1 = vtcs ;
2016-04-02 15:50:49 +00:00
i2 = vtcs + ( length - 1 ) * 2 ;
for ( c = 0 ; c < length ; c + + )
2010-03-28 18:58:01 +00:00
{
2011-05-30 22:33:35 +00:00
if ( i1 [ 1 ] ! = i2 [ 1 ] )
2010-03-28 18:58:01 +00:00
{
2011-05-30 22:33:35 +00:00
fill_edge_structure ( edge , i1 , i2 ) ;
if ( edge - > bottom > = edge - > y )
{
if ( edge - > y < top ) top = edge - > y ;
if ( edge - > bottom > bottom ) bottom = edge - > bottom ;
inactive_edges = add_edge ( inactive_edges , edge , false ) ;
edge + + ;
}
2010-03-28 18:58:01 +00:00
}
2011-05-30 22:33:35 +00:00
i2 = i1 ; i1 + = 2 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-30 22:33:35 +00:00
// For each scanline in the polygon...
2016-04-02 15:50:49 +00:00
for ( c = top ; c < = bottom ; c + + )
2011-05-30 22:33:35 +00:00
{
// Check for newly active edges
edge = inactive_edges ;
while ( ( edge ) & & ( edge - > y = = c ) )
{
next_edge = edge - > next ;
inactive_edges = remove_edge ( inactive_edges , edge ) ;
active_edges = add_edge ( active_edges , edge , true ) ;
edge = next_edge ;
}
2009-05-08 13:28:41 +00:00
2011-05-30 22:33:35 +00:00
// Draw horizontal line segments
edge = active_edges ;
while ( ( edge ) & & ( edge - > next ) )
{
2016-04-02 15:50:49 +00:00
x1 = edge - > x > > POLYGON_FIX_SHIFT ;
x2 = ( edge - > next - > x + edge - > next - > w ) > > POLYGON_FIX_SHIFT ;
y = c ;
2011-05-30 22:33:35 +00:00
// Fix coordinates
2016-04-02 15:50:49 +00:00
if ( x1 > x2 ) std : : swap ( x1 , x2 ) ;
2011-05-30 22:33:35 +00:00
// Set line
2016-04-02 15:50:49 +00:00
if ( callback )
2013-03-25 23:45:44 +00:00
{
2016-04-02 15:50:49 +00:00
for ( int xcnt = x2 - x1 - 1 ; xcnt > = 0 ; xcnt - - )
2011-05-30 22:33:35 +00:00
{
2016-04-02 15:50:49 +00:00
uint8_t pix = d - > GetPix ( x1 + xcnt , y ) ;
2013-03-25 23:45:44 +00:00
if ( ! conversion_table | | conversion_table [ pix ] )
{
2016-04-02 15:50:49 +00:00
int32_t mat = d - > GetPixMat ( pix ) ;
if ( callback ( x1 + xcnt , y ) )
if ( mats_count )
2013-03-25 23:45:44 +00:00
{
2016-04-02 15:50:49 +00:00
mats_count - > Add ( mat , 1 ) ;
2013-03-25 23:45:44 +00:00
amount + + ;
}
}
2011-05-30 22:33:35 +00:00
}
2013-03-25 23:45:44 +00:00
}
else if ( conversion_table )
2016-04-02 15:50:49 +00:00
for ( int xcnt = x2 - x1 - 1 ; xcnt > = 0 ; xcnt - - )
2015-06-17 00:58:43 +00:00
{
2016-04-02 15:50:49 +00:00
const uint8_t pix = conversion_table [ uint8_t ( d - > GetPix ( x1 + xcnt , y ) ) ] ;
Surface8 - > SetPix ( x1 + xcnt , y , pix ) ;
if ( colBkg ! = Transparent ) Surface8Bkg - > SetPix ( x1 + xcnt , y , colBkg ) ;
2015-06-17 00:58:43 +00:00
}
2013-03-25 23:45:44 +00:00
else
2016-04-02 15:50:49 +00:00
for ( int xcnt = x2 - x1 - 1 ; xcnt > = 0 ; xcnt - - )
2015-06-17 00:58:43 +00:00
{
2016-04-02 15:50:49 +00:00
if ( col ! = Transparent ) Surface8 - > SetPix ( x1 + xcnt , y , col ) ;
if ( colBkg ! = Transparent ) Surface8Bkg - > SetPix ( x1 + xcnt , y , colBkg ) ;
2015-06-17 00:58:43 +00:00
}
2011-05-30 22:33:35 +00:00
edge = edge - > next - > next ;
}
// Update edges, sorting and removing dead ones
edge = active_edges ;
while ( edge )
{
next_edge = edge - > next ;
if ( c > = edge - > bottom )
{
active_edges = remove_edge ( active_edges , edge ) ;
}
else
{
edge - > x + = edge - > dx ;
2016-04-02 15:50:49 +00:00
while ( ( edge - > prev ) & & ( edge - > x + edge - > w / 2 < edge - > prev - > x + edge - > prev - > w / 2 ) )
2011-05-30 22:33:35 +00:00
{
if ( edge - > next ) edge - > next - > prev = edge - > prev ;
edge - > prev - > next = edge - > next ;
edge - > next = edge - > prev ;
edge - > prev = edge - > prev - > prev ;
edge - > next - > prev = edge ;
if ( edge - > prev ) edge - > prev - > next = edge ;
else active_edges = edge ;
}
}
edge = next_edge ;
}
}
// Clear scratch memory
2016-04-02 15:50:49 +00:00
if ( ! use_qpb ) delete [ ] edgebuf ;
2012-04-05 01:59:45 +00:00
return amount ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* +++++++++++++++++++++++++ Save, Init and load +++++++++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : ScenarioInit ( )
{
// Gravity
2016-04-02 15:50:49 +00:00
p - > Gravity = C4REAL100 ( Game . C4S . Landscape . Gravity . Evaluate ( ) ) * DefaultGravAccel ;
2011-05-31 01:04:38 +00:00
// Opens
2016-04-02 15:50:49 +00:00
p - > LeftOpen = Game . C4S . Landscape . LeftOpen ;
p - > RightOpen = Game . C4S . Landscape . RightOpen ;
p - > TopOpen = Game . C4S . Landscape . TopOpen ;
p - > BottomOpen = Game . C4S . Landscape . BottomOpen ;
2011-05-31 01:04:38 +00:00
// Side open scan
if ( Game . C4S . Landscape . AutoScanSideOpen ) ScanSideOpen ( ) ;
}
2011-05-30 22:33:35 +00:00
2013-07-03 20:21:14 +00:00
void C4Landscape : : Clear ( bool fClearMapCreator , bool fClearSky , bool fClearRenderer )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
if ( fClearMapCreator ) { p - > pMapCreator . reset ( ) ; }
2011-05-31 01:04:38 +00:00
// clear sky
2016-04-02 15:50:49 +00:00
if ( fClearSky ) p - > Sky . Clear ( ) ;
2011-05-31 01:04:38 +00:00
// clear surfaces, if assigned
2016-04-02 15:50:49 +00:00
if ( fClearRenderer ) { p - > pLandscapeRender . reset ( ) ; }
p - > TopRowPix . clear ( ) ;
p - > BottomRowPix . clear ( ) ;
p - > Surface8 . reset ( ) ;
p - > Surface8Bkg . reset ( ) ;
p - > Map . reset ( ) ;
p - > MapBkg . reset ( ) ;
2011-05-31 01:04:38 +00:00
// clear initial landscape
2016-04-02 15:50:49 +00:00
p - > pInitial . reset ( ) ;
p - > pInitialBkg . reset ( ) ;
p - > pFoW . reset ( ) ;
2015-12-22 03:32:36 +00:00
// clear relight array
2016-04-02 15:50:49 +00:00
for ( auto & relight : p - > Relights )
relight . Default ( ) ;
2011-05-31 01:04:38 +00:00
// clear scan
2016-04-02 15:50:49 +00:00
p - > ScanX = 0 ;
p - > mode = LandscapeMode : : Undefined ;
2011-05-31 01:04:38 +00:00
// clear pixel count
2016-04-02 15:50:49 +00:00
p - > PixCnt . clear ( ) ;
p - > PixCntPitch = 0 ;
2011-05-31 01:04:38 +00:00
// clear bridge material conversion temp buffers
2016-04-02 15:50:49 +00:00
for ( auto & conv : p - > BridgeMatConversion )
conv . reset ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
pComp - > Value ( mkNamingAdapt ( p - > MapSeed , " MapSeed " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( p - > LeftOpen , " LeftOpen " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( p - > RightOpen , " RightOpen " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( p - > TopOpen , " TopOpen " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( p - > BottomOpen , " BottomOpen " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( mkCastIntAdapt ( p - > Gravity ) , " Gravity " , DefaultGravAccel ) ) ;
pComp - > Value ( mkNamingAdapt ( p - > Modulation , " MatModulation " , 0U ) ) ;
pComp - > Value ( mkNamingAdapt ( mkCastIntAdapt ( p - > mode ) , " Mode " , LandscapeMode : : Undefined ) ) ;
2015-04-07 00:48:59 +00:00
2016-04-02 15:50:49 +00:00
if ( pComp - > isCompiler ( ) )
2015-04-07 00:48:59 +00:00
{
int32_t ambient_brightness ;
2016-04-02 15:50:49 +00:00
pComp - > Value ( mkNamingAdapt ( ambient_brightness , " AmbientBrightness " , 255 ) ) ;
if ( p - > pFoW ) p - > pFoW - > Ambient . SetBrightness ( ambient_brightness / static_cast < double > ( 255 ) ) ;
2015-04-07 00:48:59 +00:00
}
else
{
2016-04-02 15:50:49 +00:00
if ( p - > pFoW )
2015-04-07 00:48:59 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t ambient_brightness = static_cast < int32_t > ( p - > pFoW - > Ambient . GetBrightness ( ) * 255 + 0.5 ) ;
pComp - > Value ( mkNamingAdapt ( ambient_brightness , " AmbientBrightness " , 255 ) ) ;
2015-04-07 00:48:59 +00:00
}
}
2011-05-31 01:04:38 +00:00
}
2011-05-30 22:33:35 +00:00
2016-04-02 15:50:49 +00:00
static std : : unique_ptr < CSurface8 > GroupReadSurface8 ( C4Group & hGroup , const char * szWildCard )
2011-05-31 01:04:38 +00:00
{
2012-06-10 22:09:24 +00:00
if ( ! hGroup . AccessEntry ( szWildCard ) )
return NULL ;
2011-05-31 01:04:38 +00:00
// create surface
2016-04-02 15:50:49 +00:00
auto pSfc = std : : make_unique < CSurface8 > ( ) ;
2011-05-31 01:04:38 +00:00
if ( ! pSfc - > Read ( hGroup ) )
2016-04-02 15:50:49 +00:00
{
return NULL ;
}
2011-05-31 01:04:38 +00:00
return pSfc ;
}
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : Init ( C4Group & hGroup , bool fOverloadCurrent , bool fLoadSky , bool & rfLoaded , bool fSavegame )
{
// set map seed, if not pre-assigned
2016-04-02 15:50:49 +00:00
if ( ! p - > MapSeed ) p - > MapSeed = Random ( 3133700 ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// increase max map size, since developers might set a greater one here
2016-04-02 15:50:49 +00:00
Game . C4S . Landscape . MapWdt . Max = 10000 ;
Game . C4S . Landscape . MapHgt . Max = 10000 ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// map and landscape must be initialized with fixed random, so runtime joining clients may recreate it
// with same seed
// after map/landscape creation, the seed must be fixed again, so there's no difference between clients creating
// and not creating the map
// this, however, would cause syncloss to DebugRecs
C4DebugRecOff DBGRECOFF ( ! ! Game . C4S . Landscape . ExactLandscape ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
Game . FixRandom ( Game . RandomSeed ) ;
// map is like it's loaded for regular gamestart
// but it's changed and would have to be saved if a new section is loaded
2016-04-02 15:50:49 +00:00
p - > fMapChanged = fOverloadCurrent ;
2011-05-31 01:04:38 +00:00
// don't change landscape mode in runtime joins
2016-04-02 15:50:49 +00:00
bool fLandscapeModeSet = ( p - > mode ! = LandscapeMode : : Undefined ) ;
2011-05-31 01:04:38 +00:00
2014-10-16 23:10:47 +00:00
// Make pixel maps
// Pixel maps only depend on loaded materials and textures
// They might be accessed in map scripts, so they should be ready before map creation
UpdatePixMaps ( ) ;
2011-05-31 01:04:38 +00:00
Game . SetInitProgress ( 60 ) ;
// create map if necessary
if ( ! Game . C4S . Landscape . ExactLandscape )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
std : : unique_ptr < CSurface8 > sfcMap , sfcMapBkg ;
2015-06-22 22:56:04 +00:00
2015-07-01 01:58:42 +00:00
// Static map from scenario: Old-style Map.bmp with highest bit IFT
2016-04-02 15:50:49 +00:00
if ( ( sfcMap = GroupReadSurface8 ( hGroup , C4CFN_Map ) ) )
2015-06-22 22:56:04 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! fLandscapeModeSet ) p - > mode = LandscapeMode : : Static ;
sfcMapBkg = p - > CreateDefaultBkgSurface ( * sfcMap , true ) ;
2015-07-01 01:58:42 +00:00
if ( ! sfcMapBkg ) return false ;
}
2016-04-02 15:50:49 +00:00
// Static map from scenario: New-style MapFg.bmp and MapBg.bmp with
2015-07-01 01:58:42 +00:00
// full 255 mat-tex combinations. Background map is optional, if not
// given default will be created with tunnel background for all
// semisolid pixels.
if ( ! sfcMap )
{
2016-04-02 15:50:49 +00:00
if ( ( sfcMap = GroupReadSurface8 ( hGroup , C4CFN_MapFg ) ) )
2015-07-01 01:58:42 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! fLandscapeModeSet ) p - > mode = LandscapeMode : : Static ;
2015-07-01 01:58:42 +00:00
sfcMapBkg = GroupReadSurface8 ( hGroup , C4CFN_MapBg ) ;
2016-04-02 15:50:49 +00:00
if ( ! sfcMapBkg ) sfcMapBkg = p - > CreateDefaultBkgSurface ( * sfcMap , false ) ;
2015-07-01 01:58:42 +00:00
if ( ! sfcMapBkg ) return false ;
}
2015-06-22 22:56:04 +00:00
}
2011-05-30 22:33:35 +00:00
2013-03-18 23:35:00 +00:00
// dynamic map from Landscape.txt
2016-04-02 15:50:49 +00:00
CSurface8 * rendered_map = nullptr , * rendered_bkg = nullptr ;
2011-05-31 01:04:38 +00:00
if ( ! sfcMap )
2016-04-02 15:50:49 +00:00
{
if ( p - > CreateMapS2 ( hGroup , rendered_map , rendered_bkg ) )
{
sfcMap . reset ( rendered_map ) ;
sfcMapBkg . reset ( rendered_bkg ) ;
if ( ! fLandscapeModeSet ) p - > mode = LandscapeMode : : Dynamic ;
}
}
2011-05-30 22:33:35 +00:00
2013-03-18 23:35:00 +00:00
// script may create or edit map
2016-04-03 15:23:00 +00:00
if ( MapScript . InitializeMap ( & Game . C4S . Landscape , & : : TextureMap , & : : MaterialMap , Game . StartupPlayerCount , & sfcMap , & sfcMapBkg ) )
2016-04-03 15:02:41 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! fLandscapeModeSet ) p - > mode = LandscapeMode : : Dynamic ;
2016-04-03 15:02:41 +00:00
}
2013-03-18 23:35:00 +00:00
2011-05-31 01:04:38 +00:00
// Dynamic map by scenario
if ( ! sfcMap & & ! fOverloadCurrent )
2016-04-02 15:50:49 +00:00
{
if ( p - > CreateMap ( rendered_map , rendered_bkg ) )
{
sfcMap . reset ( rendered_map ) ;
sfcMapBkg . reset ( rendered_bkg ) ;
if ( ! fLandscapeModeSet ) p - > mode = LandscapeMode : : Dynamic ;
}
}
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// No map failure
if ( ! sfcMap )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// no problem if only overloading
if ( ! fOverloadCurrent ) return false ;
2016-04-02 15:50:49 +00:00
if ( fLoadSky ) if ( ! p - > Sky . Init ( fSavegame ) ) return false ;
2011-05-30 22:33:35 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-07-08 01:17:40 +00:00
assert ( sfcMapBkg ! = NULL ) ;
2013-05-25 20:38:08 +00:00
if ( Config . General . DebugRec )
{
AddDbgRec ( RCT_Block , " |---MAP---| " , 12 ) ;
AddDbgRec ( RCT_Map , sfcMap - > Bits , sfcMap - > Pitch * sfcMap - > Hgt ) ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Store map size and calculate map zoom
int iWdt , iHgt ;
2016-04-02 15:50:49 +00:00
sfcMap - > GetSurfaceSize ( iWdt , iHgt ) ;
p - > MapWidth = iWdt ; p - > MapHeight = iHgt ;
p - > MapZoom = Game . C4S . Landscape . MapZoom . Evaluate ( ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Calculate landscape size
2016-04-02 15:50:49 +00:00
p - > Width = p - > MapZoom * p - > MapWidth ;
p - > Height = p - > MapZoom * p - > MapHeight ;
p - > Width = std : : max < int32_t > ( p - > Width , 100 ) ;
p - > Height = std : : max < int32_t > ( p - > Height , 100 ) ;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// if overloading, clear current landscape (and sections, etc.)
// must clear, of course, before new sky is eventually read
2013-07-03 20:21:14 +00:00
if ( fOverloadCurrent ) Clear ( ! Game . C4S . Landscape . KeepMapCreator , fLoadSky , false ) ;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// assign new map
2016-04-02 15:50:49 +00:00
assert ( p - > Map = = NULL ) ;
assert ( p - > MapBkg = = NULL ) ;
p - > Map = std : : move ( sfcMap ) ;
p - > MapBkg = std : : move ( sfcMapBkg ) ;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// Sky (might need to know landscape height)
if ( fLoadSky )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
Game . SetInitProgress ( 70 ) ;
2016-04-02 15:50:49 +00:00
if ( ! p - > Sky . Init ( fSavegame ) ) return false ;
2010-03-28 18:58:01 +00:00
}
2011-05-31 01:04:38 +00:00
}
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// Exact landscape from scenario (no map or exact recreation)
else /* if (Game.C4S.Landscape.ExactLandscape) */
{
C4DebugRecOff DBGRECOFF ;
// if overloading, clear current
2015-09-15 04:13:45 +00:00
if ( fOverloadCurrent ) Clear ( ! Game . C4S . Landscape . KeepMapCreator , fLoadSky , false ) ;
2011-05-31 01:04:38 +00:00
// load it
2016-04-02 15:50:49 +00:00
if ( ! fLandscapeModeSet ) p - > mode = LandscapeMode : : Exact ;
rfLoaded = true ;
2011-05-31 01:04:38 +00:00
if ( ! Load ( hGroup , fLoadSky , fSavegame ) ) return false ;
}
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// progress
2014-11-17 14:35:50 +00:00
Game . SetInitProgress ( 75 ) ;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// copy noscan-var
2016-04-02 15:50:49 +00:00
p - > NoScan = Game . C4S . Landscape . NoScan ! = 0 ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Scan settings
2016-04-02 15:50:49 +00:00
p - > ScanSpeed = Clamp ( GetWidth ( ) / 500 , 2 , 15 ) ;
2009-05-08 13:28:41 +00:00
2015-10-09 04:11:53 +00:00
// Create pixel count array before any SetPix operations may take place
// Proper pixel counts will be done later, but needs to have the arrays redy to avoid dead pointer access.
// We will use 15x17 blocks so the pixel count can't get over 255.
2016-04-02 15:50:49 +00:00
int32_t PixCntWidth = ( GetWidth ( ) + 16 ) / 17 ;
p - > PixCntPitch = ( GetHeight ( ) + 14 ) / 15 ;
p - > PixCnt . resize ( PixCntWidth * p - > PixCntPitch ) ;
2015-10-09 04:11:53 +00:00
2011-05-31 01:04:38 +00:00
// map to big surface and sectionize it
// (not for shaders though - they require continous textures)
2012-06-10 22:09:24 +00:00
if ( ! Game . C4S . Landscape . ExactLandscape )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
assert ( p - > Surface8 = = NULL ) ;
assert ( p - > Surface8Bkg = = NULL ) ;
2015-06-17 00:58:43 +00:00
2016-04-02 15:50:49 +00:00
// Create landscape surfaces
2015-06-17 00:58:43 +00:00
{
2016-04-02 15:50:49 +00:00
auto sf8 = std : : make_unique < CSurface8 > ( ) ;
auto sfb8 = std : : make_unique < CSurface8 > ( ) ;
if ( ! sf8 - > Create ( GetWidth ( ) , GetHeight ( ) ) | | ! sfb8 - > Create ( GetWidth ( ) , GetHeight ( ) ) )
return false ;
p - > Surface8 = std : : move ( sf8 ) ;
p - > Surface8Bkg = std : : move ( sfb8 ) ;
if ( ! p - > Mat2Pal ( ) )
return false ;
2012-06-10 22:09:24 +00:00
}
2009-05-08 13:28:41 +00:00
2012-06-10 22:09:24 +00:00
// Map to landscape
2013-07-03 20:21:14 +00:00
// Landscape render disabled during initial landscape zoom (will be updated later)
2016-04-02 15:50:49 +00:00
std : : unique_ptr < C4LandscapeRender > lsrender_backup ;
lsrender_backup . swap ( p - > pLandscapeRender ) ;
2013-07-03 20:21:14 +00:00
bool map2landscape_success = MapToLandscape ( ) ;
2016-04-02 15:50:49 +00:00
lsrender_backup . swap ( p - > pLandscapeRender ) ;
2013-07-03 20:21:14 +00:00
if ( ! map2landscape_success ) return false ;
2012-06-10 22:09:24 +00:00
}
2013-03-30 13:54:51 +00:00
// Init out-of-landscape pixels for bottom
2016-04-02 15:50:49 +00:00
p - > InitTopAndBottomRowPix ( ) ;
2013-03-30 13:54:51 +00:00
2014-11-17 14:35:50 +00:00
Game . SetInitProgress ( 80 ) ;
2009-05-08 13:28:41 +00:00
2013-05-25 20:38:08 +00:00
if ( Config . General . DebugRec )
{
AddDbgRec ( RCT_Block , " |---LANDSCAPE---| " , 18 ) ;
2016-04-02 15:50:49 +00:00
AddDbgRec ( RCT_Map , p - > Surface8 - > Bits , p - > Surface8 - > Pitch * p - > Surface8 - > Hgt ) ;
2015-06-17 00:58:43 +00:00
AddDbgRec ( RCT_Block , " |---LANDSCAPE BKG---| " , 22 ) ;
2016-04-02 15:50:49 +00:00
AddDbgRec ( RCT_Map , p - > Surface8Bkg - > Bits , p - > Surface8Bkg - > Pitch * p - > Surface8Bkg - > Hgt ) ;
2013-05-25 20:38:08 +00:00
}
2011-07-17 14:52:36 +00:00
2012-08-19 18:35:10 +00:00
// Create FoW
2016-04-02 15:50:49 +00:00
assert ( p - > pFoW = = NULL ) ;
2014-12-29 11:29:43 +00:00
if ( Game . C4S . Game . FoWEnabled )
2016-04-02 15:50:49 +00:00
p - > pFoW . reset ( new C4FoW ) ;
2012-08-19 18:35:10 +00:00
2011-05-31 01:04:38 +00:00
// Create renderer
# ifndef USE_CONSOLE
2016-04-02 15:50:49 +00:00
if ( ! p - > pLandscapeRender )
p - > pLandscapeRender . reset ( new C4LandscapeRenderGL ) ;
2011-05-31 01:04:38 +00:00
# endif
2016-04-02 15:50:49 +00:00
if ( p - > pLandscapeRender )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// Initialize renderer
2013-07-03 20:21:14 +00:00
if ( fOverloadCurrent )
{
2016-04-02 15:50:49 +00:00
if ( ! p - > pLandscapeRender - > ReInit ( GetWidth ( ) , GetHeight ( ) ) )
2013-07-03 20:21:14 +00:00
return false ;
}
else
{
2016-04-02 15:50:49 +00:00
if ( ! p - > pLandscapeRender - > Init ( GetWidth ( ) , GetHeight ( ) , & : : TextureMap , & : : GraphicsResource . Files ) )
2013-07-03 20:21:14 +00:00
return false ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-09-17 02:10:40 +00:00
// Save initial landscape
if ( ! SaveInitial ( ) )
return false ;
// Load diff, if existant
ApplyDiff ( hGroup ) ;
2015-10-09 04:11:53 +00:00
// Pixel count tracking from landscape zoom is incomplete, so recalculate it.
2016-04-02 15:50:49 +00:00
p - > UpdatePixCnt ( this , C4Rect ( 0 , 0 , GetWidth ( ) , GetHeight ( ) ) ) ;
p - > ClearMatCount ( ) ;
p - > UpdateMatCnt ( this , C4Rect ( 0 , 0 , GetWidth ( ) , GetHeight ( ) ) , true ) ;
2011-05-27 00:51:07 +00:00
2015-09-17 02:10:40 +00:00
// Create initial landscape render data (after applying diff so landscape is complete)
2016-04-02 15:50:49 +00:00
if ( p - > pLandscapeRender ) p - > pLandscapeRender - > Update ( C4Rect ( 0 , 0 , GetWidth ( ) , GetHeight ( ) ) , this ) ;
2015-09-17 02:10:40 +00:00
Game . SetInitProgress ( 87 ) ;
2011-05-31 01:04:38 +00:00
// after map/landscape creation, the seed must be fixed again, so there's no difference between clients creating
// and not creating the map
Game . FixRandom ( Game . RandomSeed ) ;
2009-05-08 13:28:41 +00:00
2014-11-17 14:35:50 +00:00
// Create ambient light map after landscape creation
2016-04-02 15:50:49 +00:00
if ( p - > pFoW ) p - > pFoW - > Ambient . CreateFromLandscape ( * this , 10. , 50. , 0.25 ) ;
2014-11-17 14:35:50 +00:00
Game . SetInitProgress ( 84 ) ;
2011-05-31 01:04:38 +00:00
// Success
2016-04-02 15:50:49 +00:00
rfLoaded = true ;
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
bool C4Landscape : : HasMap ( ) const
{
return p - > Map ! = NULL & & p - > MapBkg ! = NULL ;
}
2015-01-15 18:12:56 +00:00
bool C4Landscape : : Save ( C4Group & hGroup ) const
2011-05-31 01:04:38 +00:00
{
C4SolidMask : : RemoveSolidMasks ( ) ;
2016-04-02 15:50:49 +00:00
bool r = p - > SaveInternal ( this , hGroup ) ;
2011-05-31 01:04:38 +00:00
C4SolidMask : : PutSolidMasks ( ) ;
return r ;
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : SaveInternal ( const C4Landscape * d , C4Group & hGroup ) const
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// Save landscape surface
2016-04-02 15:50:49 +00:00
char szTempLandscape [ _MAX_PATH + 1 ] ;
2011-05-31 01:04:38 +00:00
SCopy ( Config . AtTempPath ( C4CFN_TempLandscape ) , szTempLandscape ) ;
MakeTempFilename ( szTempLandscape ) ;
if ( ! Surface8 - > Save ( szTempLandscape ) )
return false ;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// Move temp file to group
2016-04-02 15:50:49 +00:00
if ( ! hGroup . Move ( szTempLandscape , C4CFN_LandscapeFg ) )
2011-05-31 01:04:38 +00:00
return false ;
2010-03-27 16:05:02 +00:00
2015-06-17 00:58:43 +00:00
// Same for background surface
SCopy ( Config . AtTempPath ( C4CFN_TempLandscapeBkg ) , szTempLandscape ) ;
MakeTempFilename ( szTempLandscape ) ;
if ( ! Surface8Bkg - > Save ( szTempLandscape ) )
return false ;
2015-07-01 01:58:42 +00:00
if ( ! hGroup . Move ( szTempLandscape , C4CFN_LandscapeBg ) )
2015-06-17 00:58:43 +00:00
return false ;
2011-05-31 01:04:38 +00:00
// Save map
if ( fMapChanged & & Map )
2016-04-02 15:50:49 +00:00
if ( ! d - > SaveMap ( hGroup ) )
2011-05-31 01:04:38 +00:00
return false ;
// save textures (if changed)
2016-04-02 15:50:49 +00:00
if ( ! d - > SaveTextures ( hGroup ) )
2011-05-31 01:04:38 +00:00
return false ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-01-15 18:12:56 +00:00
bool C4Landscape : : SaveDiff ( C4Group & hGroup , bool fSyncSave ) const
2011-05-31 01:04:38 +00:00
{
C4SolidMask : : RemoveSolidMasks ( ) ;
2016-04-02 15:50:49 +00:00
bool r = p - > SaveDiffInternal ( this , hGroup , fSyncSave ) ;
2011-05-31 01:04:38 +00:00
C4SolidMask : : PutSolidMasks ( ) ;
return r ;
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : SaveDiffInternal ( const C4Landscape * d , C4Group & hGroup , bool fSyncSave ) const
2010-03-28 18:58:01 +00:00
{
2015-06-17 00:58:43 +00:00
assert ( pInitial & & pInitialBkg ) ;
if ( ! pInitial | | ! pInitialBkg ) return false ;
2010-03-27 16:05:02 +00:00
2015-06-22 22:56:04 +00:00
// If it shouldn't be sync-save: Clear all bytes that have not changed, i.e.
// set them to C4M_MaxTexIndex
2015-06-17 00:58:43 +00:00
bool fChanged = false , fChangedBkg = false ; ;
2011-05-31 01:04:38 +00:00
if ( ! fSyncSave )
for ( int y = 0 ; y < Height ; y + + )
2015-06-17 00:58:43 +00:00
for ( int x = 0 ; x < Width ; x + + )
{
if ( pInitial [ y * Width + x ] = = Surface8 - > _GetPix ( x , y ) )
2016-04-02 15:50:49 +00:00
Surface8 - > SetPix ( x , y , C4M_MaxTexIndex ) ;
2011-05-31 01:04:38 +00:00
else
fChanged = true ;
2015-06-17 00:58:43 +00:00
if ( pInitialBkg [ y * Width + x ] = = Surface8Bkg - > _GetPix ( x , y ) )
2016-04-02 15:50:49 +00:00
Surface8Bkg - > SetPix ( x , y , C4M_MaxTexIndex ) ;
2015-06-17 00:58:43 +00:00
else
fChangedBkg = true ;
2014-04-17 17:16:24 +00:00
}
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
if ( fSyncSave | | fChanged )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// Save landscape surface
if ( ! Surface8 - > Save ( Config . AtTempPath ( C4CFN_TempLandscape ) ) )
return false ;
// Move temp file to group
2016-04-02 15:50:49 +00:00
if ( ! hGroup . Move ( Config . AtTempPath ( C4CFN_TempLandscape ) ,
C4CFN_DiffLandscape ) )
2011-05-31 01:04:38 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
2015-06-17 00:58:43 +00:00
if ( fSyncSave | | fChangedBkg )
{
// Save landscape surface
if ( ! Surface8Bkg - > Save ( Config . AtTempPath ( C4CFN_TempLandscapeBkg ) ) )
return false ;
// Move temp file to group
2016-04-02 15:50:49 +00:00
if ( ! hGroup . Move ( Config . AtTempPath ( C4CFN_TempLandscapeBkg ) ,
C4CFN_DiffLandscapeBkg ) )
2015-06-17 00:58:43 +00:00
return false ;
}
2011-05-31 01:04:38 +00:00
// Restore landscape pixels
if ( ! fSyncSave )
2015-06-17 00:58:43 +00:00
for ( int y = 0 ; y < Height ; y + + )
for ( int x = 0 ; x < Width ; x + + )
{
2015-06-22 22:56:04 +00:00
if ( Surface8 - > _GetPix ( x , y ) = = C4M_MaxTexIndex )
2016-04-02 15:50:49 +00:00
Surface8 - > SetPix ( x , y , pInitial [ y * Width + x ] ) ;
2015-06-22 22:56:04 +00:00
if ( Surface8Bkg - > _GetPix ( x , y ) = = C4M_MaxTexIndex )
2016-04-02 15:50:49 +00:00
Surface8Bkg - > SetPix ( x , y , pInitialBkg [ y * Width + x ] ) ;
2015-06-17 00:58:43 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Save changed map, too
if ( fMapChanged & & Map )
2016-04-02 15:50:49 +00:00
if ( ! d - > SaveMap ( hGroup ) ) return false ;
2011-05-31 01:04:38 +00:00
// and textures (if changed)
2016-04-02 15:50:49 +00:00
if ( ! d - > SaveTextures ( hGroup ) ) return false ;
2011-05-31 01:04:38 +00:00
return true ;
}
bool C4Landscape : : SaveInitial ( )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// Create array
2016-04-02 15:50:49 +00:00
p - > pInitial = std : : make_unique < BYTE [ ] > ( GetWidth ( ) * GetHeight ( ) ) ;
p - > pInitialBkg = std : : make_unique < BYTE [ ] > ( GetWidth ( ) * GetHeight ( ) ) ;
2011-05-31 01:04:38 +00:00
// Save material data
2016-04-02 15:50:49 +00:00
for ( int y = 0 ; y < GetHeight ( ) ; y + + )
{
const int pitch = y * GetWidth ( ) ;
for ( int x = 0 ; x < GetWidth ( ) ; x + + )
2015-06-17 00:58:43 +00:00
{
2016-04-02 15:50:49 +00:00
p - > pInitial [ pitch + x ] = p - > Surface8 - > _GetPix ( x , y ) ;
p - > pInitialBkg [ pitch + x ] = p - > Surface8Bkg - > _GetPix ( x , y ) ;
2015-06-17 00:58:43 +00:00
}
2016-04-02 15:50:49 +00:00
}
2011-05-31 01:04:38 +00:00
return true ;
}
bool C4Landscape : : Load ( C4Group & hGroup , bool fLoadSky , bool fSavegame )
{
2016-04-02 15:50:49 +00:00
assert ( ! p - > Surface8 & & ! p - > Surface8Bkg ) ;
2015-06-17 00:58:43 +00:00
2011-05-31 01:04:38 +00:00
// Load exact landscape from group
2016-04-02 15:50:49 +00:00
if ( ( p - > Surface8 = GroupReadSurface8 ( hGroup , C4CFN_Landscape ) ) = = nullptr )
2015-07-01 01:58:42 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ( p - > Surface8 = GroupReadSurface8 ( hGroup , C4CFN_LandscapeFg ) ) = = nullptr ) return false ;
p - > Surface8Bkg = GroupReadSurface8 ( hGroup , C4CFN_LandscapeBg ) ;
2015-07-01 01:58:42 +00:00
2016-04-02 15:50:49 +00:00
if ( p - > Surface8Bkg )
2015-07-01 01:58:42 +00:00
{
2016-04-02 15:50:49 +00:00
if ( p - > Surface8 - > Wdt ! = p - > Surface8Bkg - > Wdt | | p - > Surface8 - > Hgt ! = p - > Surface8Bkg - > Hgt )
2015-07-01 01:58:42 +00:00
{
2016-04-02 15:50:49 +00:00
LogFatal ( FormatString ( " Landscape has different dimensions than background landscape (%dx%d vs. %dx%d) " , p - > Surface8 - > Wdt , p - > Surface8 - > Hgt , p - > Surface8Bkg - > Wdt , p - > Surface8Bkg - > Hgt ) . getData ( ) ) ;
2015-07-01 01:58:42 +00:00
return false ;
}
}
else
{
// LandscapeFg.bmp loaded: Assume full 8bit mat-tex values
// when creating background surface.
2016-04-02 15:50:49 +00:00
p - > Surface8Bkg = p - > CreateDefaultBkgSurface ( * p - > Surface8 , false ) ;
2015-07-01 01:58:42 +00:00
}
}
else
{
// Landscape.bmp loaded: Assume msb is IFT flag when creating
// background surface.
2016-04-02 15:50:49 +00:00
p - > Surface8Bkg = p - > CreateDefaultBkgSurface ( * p - > Surface8 , true ) ;
2015-07-01 01:58:42 +00:00
}
2011-05-31 01:04:38 +00:00
int iWidth , iHeight ;
2016-04-02 15:50:49 +00:00
p - > Surface8 - > GetSurfaceSize ( iWidth , iHeight ) ;
p - > Width = iWidth ; p - > Height = iHeight ;
2015-06-17 00:58:43 +00:00
2011-05-31 01:04:38 +00:00
// adjust pal
2016-04-02 15:50:49 +00:00
if ( ! p - > Mat2Pal ( ) ) return false ;
2012-06-10 22:09:24 +00:00
// Landscape should be in correct format: Make sure it is!
2016-04-02 15:50:49 +00:00
for ( int32_t y = 0 ; y < GetHeight ( ) ; + + y )
for ( int32_t x = 0 ; x < GetWidth ( ) ; + + x )
2012-06-10 22:09:24 +00:00
{
2016-04-02 15:50:49 +00:00
BYTE byPix = p - > Surface8 - > _GetPix ( x , y ) ;
2012-06-10 22:09:24 +00:00
int32_t iMat = PixCol2Mat ( byPix ) ;
2015-06-17 00:58:43 +00:00
2012-06-10 22:09:24 +00:00
if ( byPix & & ! MatValid ( iMat ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
LogFatal ( FormatString ( " Landscape loading error at (%d/%d): Pixel value %d not a valid material! " , ( int ) x , ( int ) y , ( int ) byPix ) . getData ( ) ) ;
2012-06-10 22:09:24 +00:00
return false ;
2009-05-08 13:28:41 +00:00
}
2015-06-17 00:58:43 +00:00
2016-04-02 15:50:49 +00:00
BYTE byPixBkg = p - > Surface8Bkg - > _GetPix ( x , y ) ;
2015-07-01 01:58:42 +00:00
int32_t iMatBkg = PixCol2Mat ( byPixBkg ) ;
2015-06-17 00:58:43 +00:00
2015-07-01 01:58:42 +00:00
if ( byPixBkg & & ! MatValid ( iMatBkg ) )
{
2016-04-02 15:50:49 +00:00
LogFatal ( FormatString ( " Background Landscape loading error at (%d/%d): Pixel value %d not a valid material! " , ( int ) x , ( int ) y , ( int ) byPixBkg ) . getData ( ) ) ;
2015-07-01 01:58:42 +00:00
return false ;
2015-06-17 00:58:43 +00:00
}
2012-06-10 22:09:24 +00:00
}
2015-06-17 00:58:43 +00:00
2011-05-31 01:04:38 +00:00
// Init sky
if ( fLoadSky )
{
Game . SetInitProgress ( 70 ) ;
2016-04-02 15:50:49 +00:00
if ( p - > Sky . Init ( fSavegame ) ) return false ;
2011-05-31 01:04:38 +00:00
}
// Success
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2011-05-31 01:04:38 +00:00
bool C4Landscape : : ApplyDiff ( C4Group & hGroup )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
std : : unique_ptr < CSurface8 > pDiff , pDiffBkg ;
2011-05-31 01:04:38 +00:00
// Load diff landscape from group
2016-04-02 15:50:49 +00:00
if ( ( pDiff = GroupReadSurface8 ( hGroup , C4CFN_DiffLandscape ) ) = = nullptr ) return false ;
if ( ( pDiffBkg = GroupReadSurface8 ( hGroup , C4CFN_DiffLandscapeBkg ) ) = = nullptr ) return false ;
2015-06-17 00:58:43 +00:00
2011-05-31 01:04:38 +00:00
// convert all pixels: keep if same material; re-set if different material
BYTE byPix ;
2016-04-02 15:50:49 +00:00
for ( int32_t y = 0 ; y < GetHeight ( ) ; + + y ) for ( int32_t x = 0 ; x < GetWidth ( ) ; + + x )
2015-06-17 00:58:43 +00:00
{
2015-06-22 22:56:04 +00:00
if ( pDiff - > GetPix ( x , y ) ! = C4M_MaxTexIndex )
2016-04-02 15:50:49 +00:00
if ( p - > Surface8 - > _GetPix ( x , y ) ! = ( byPix = pDiff - > _GetPix ( x , y ) ) )
2015-06-17 00:58:43 +00:00
// material has changed here: readjust with new texture
2016-04-02 15:50:49 +00:00
p - > Surface8 - > SetPix ( x , y , byPix ) ;
2015-06-22 22:56:04 +00:00
if ( pDiffBkg - > GetPix ( x , y ) ! = C4M_MaxTexIndex )
2016-04-02 15:50:49 +00:00
if ( p - > Surface8Bkg - > _GetPix ( x , y ) ! = ( byPix = pDiffBkg - > _GetPix ( x , y ) ) )
p - > Surface8Bkg - > _SetPix ( x , y , byPix ) ;
2015-06-17 00:58:43 +00:00
}
2016-04-02 15:50:49 +00:00
// done
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : Default ( )
2011-05-30 22:33:35 +00:00
{
2016-04-02 15:50:49 +00:00
p = std : : make_unique < P > ( ) ;
}
void C4Landscape : : P : : ClearMatCount ( )
{
std : : fill ( MatCount . begin ( ) , MatCount . end ( ) , 0 ) ;
std : : fill ( EffectiveMatCount . begin ( ) , EffectiveMatCount . end ( ) , 0 ) ;
2011-05-31 01:04:38 +00:00
}
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : Synchronize ( )
{
2016-04-02 15:50:49 +00:00
p - > ScanX = 0 ;
2011-05-31 01:04:38 +00:00
}
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
int32_t PixCol2Mat ( BYTE pixc )
{
// Get texture
int32_t iTex = PixCol2Tex ( pixc ) ;
if ( ! iTex ) return MNone ;
// Get material-texture mapping
const C4TexMapEntry * pTex = : : TextureMap . GetEntry ( iTex ) ;
// Return material
return pTex ? pTex - > GetMaterialIndex ( ) : MNone ;
}
2011-05-30 22:33:35 +00:00
2015-01-15 18:12:56 +00:00
bool C4Landscape : : SaveMap ( C4Group & hGroup ) const
2011-05-31 01:04:38 +00:00
{
// No map
2016-04-02 15:50:49 +00:00
if ( ! p - > Map ) return false ;
assert ( p - > MapBkg ! = NULL ) ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// Create map palette
2012-08-15 22:45:27 +00:00
CStdPalette Palette ;
2016-04-02 15:50:49 +00:00
: : TextureMap . StoreMapPalette ( & Palette , : : MaterialMap ) ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// Save map surface
2016-04-02 15:50:49 +00:00
if ( ! p - > Map - > Save ( Config . AtTempPath ( C4CFN_TempMapFg ) , & Palette ) )
2011-05-31 01:04:38 +00:00
return false ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// Move temp file to group
2015-07-01 01:58:42 +00:00
if ( ! hGroup . Move ( Config . AtTempPath ( C4CFN_TempMapFg ) ,
2016-04-02 15:50:49 +00:00
C4CFN_MapFg ) )
2011-05-31 01:04:38 +00:00
return false ;
2011-05-30 22:33:35 +00:00
2015-06-22 22:56:04 +00:00
// Save background map surface
2016-04-02 15:50:49 +00:00
if ( ! p - > MapBkg - > Save ( Config . AtTempPath ( C4CFN_TempMapBg ) , & Palette ) )
2015-06-22 22:56:04 +00:00
return false ;
// Move temp file to group
2015-07-01 01:58:42 +00:00
if ( ! hGroup . Move ( Config . AtTempPath ( C4CFN_TempMapBg ) ,
2016-04-02 15:50:49 +00:00
C4CFN_MapBg ) )
2015-06-22 22:56:04 +00:00
return false ;
2016-04-02 15:50:49 +00:00
2011-05-30 22:33:35 +00:00
// Success
return true ;
}
2015-01-15 18:12:56 +00:00
bool C4Landscape : : SaveTextures ( C4Group & hGroup ) const
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// if material-texture-combinations have been added, write the texture map
if ( : : TextureMap . fEntriesAdded )
{
C4Group * pMatGroup = new C4Group ( ) ;
2016-04-02 15:50:49 +00:00
bool fSuccess = false ;
2011-05-31 01:04:38 +00:00
// create local material group
if ( ! hGroup . FindEntry ( C4CFN_Material ) )
{
// delete previous item at temp path
EraseItem ( Config . AtTempPath ( C4CFN_Material ) ) ;
// create at temp path
if ( pMatGroup - > Open ( Config . AtTempPath ( C4CFN_Material ) , true ) )
// write to it
if ( : : TextureMap . SaveMap ( * pMatGroup , C4CFN_TexMap ) )
// close (flush)
if ( pMatGroup - > Close ( ) )
// add it
if ( hGroup . Move ( Config . AtTempPath ( C4CFN_Material ) , C4CFN_Material ) )
2016-04-02 15:50:49 +00:00
fSuccess = true ;
2011-05-31 01:04:38 +00:00
// temp group must remain for scenario file closure
// it will be deleted when the group is closed
}
else
// simply write it to the local material file
if ( pMatGroup - > OpenAsChild ( & hGroup , C4CFN_Material ) )
fSuccess = : : TextureMap . SaveMap ( * pMatGroup , C4CFN_TexMap ) ;
// close material group again
if ( pMatGroup - > IsOpen ( ) ) pMatGroup - > Close ( ) ;
delete pMatGroup ;
// fail if unsuccessful
if ( ! fSuccess ) return false ;
}
// done, success
return true ;
2010-04-20 20:38:18 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : InitTopAndBottomRowPix ( )
2013-03-30 13:54:51 +00:00
{
2016-04-02 15:50:49 +00:00
assert ( Width > 0 ) ;
2014-04-21 00:01:17 +00:00
// Init Top-/BottomRowPix array, which determines if out-of-landscape pixels on top/bottom side of the map are solid or not
// In case of Top-/BottomOpen=2, unit by map and not landscape to avoid runtime join sync losses
2013-03-30 13:54:51 +00:00
if ( ! Width ) return true ;
2016-04-02 15:50:49 +00:00
TopRowPix . clear ( ) ;
BottomRowPix . clear ( ) ;
2014-04-21 00:01:17 +00:00
// must access Game.C4S here because Landscape.TopOpen / Landscape.BottomOpen may not be initialized yet
2013-03-30 13:54:51 +00:00
// why is there a local copy of that static variable anyway?
2014-04-21 00:01:17 +00:00
int32_t top_open_flag = Game . C4S . Landscape . TopOpen ;
2013-03-30 13:54:51 +00:00
int32_t bottom_open_flag = Game . C4S . Landscape . BottomOpen ;
2014-04-21 00:01:17 +00:00
if ( top_open_flag = = 2 & & ! Map ) top_open_flag = 1 ;
2013-03-30 13:54:51 +00:00
if ( bottom_open_flag = = 2 & & ! Map ) bottom_open_flag = 1 ;
2014-04-21 00:01:17 +00:00
// Init TopRowPix
switch ( top_open_flag )
{
2016-04-02 15:50:49 +00:00
// TopOpen=0: Top is closed
case 0 : TopRowPix . assign ( Width , MCVehic ) ; break ;
// TopOpen=2: Top is open when pixel below has sky background
2014-04-21 00:01:17 +00:00
case 2 :
2016-04-02 15:50:49 +00:00
TopRowPix . resize ( Width ) ;
for ( int32_t x = 0 ; x < Width ; + + x )
2014-04-21 00:01:17 +00:00
{
2016-04-02 15:50:49 +00:00
uint8_t map_pix = MapBkg - > GetPix ( x / MapZoom , 0 ) ;
2015-06-22 22:56:04 +00:00
TopRowPix [ x ] = ( ( map_pix ! = 0 ) ? MCVehic : 0 ) ;
2014-04-21 00:01:17 +00:00
}
break ;
2016-04-02 15:50:49 +00:00
// TopOpen=1: Top is open
default : TopRowPix . assign ( Width , 0 ) ; break ;
2014-04-21 00:01:17 +00:00
}
// Init BottomRowPix
2013-03-30 13:54:51 +00:00
switch ( bottom_open_flag )
{
2016-04-02 15:50:49 +00:00
// BottomOpen=0: Bottom is closed
case 0 : BottomRowPix . assign ( Width , MCVehic ) ; break ;
// BottomOpen=2: Bottom is open when pixel above has sky background
2013-03-30 13:54:51 +00:00
case 2 :
2016-04-02 15:50:49 +00:00
BottomRowPix . resize ( Width ) ;
for ( int32_t x = 0 ; x < Width ; + + x )
2013-03-30 13:54:51 +00:00
{
2016-04-02 15:50:49 +00:00
uint8_t map_pix = MapBkg - > GetPix ( x / MapZoom , Map - > Hgt - 1 ) ;
2015-06-22 22:56:04 +00:00
BottomRowPix [ x ] = ( ( map_pix ! = 0 ) ? MCVehic : 0 ) ;
2013-03-30 13:54:51 +00:00
}
break ;
2016-04-02 15:50:49 +00:00
// BottomOpen=1: Bottom is open
default : BottomRowPix . assign ( Width , 0 ) ; break ;
2013-03-30 13:54:51 +00:00
}
return true ;
}
2011-05-31 01:04:38 +00:00
bool C4Landscape : : MapToLandscape ( )
2010-04-20 20:38:18 +00:00
{
2011-05-31 01:04:38 +00:00
// zoom map to landscape
2016-04-02 15:50:49 +00:00
return p - > MapToLandscape ( this , * p - > Map , * p - > MapBkg , 0 , 0 , p - > MapWidth , p - > MapHeight ) ;
2011-05-31 01:04:38 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
uint32_t C4Landscape : : P : : ChunkyRandom ( uint32_t & iOffset , uint32_t iRange ) const
2011-05-31 01:04:38 +00:00
{
if ( ! iRange ) return 0 ;
2011-09-02 23:22:12 +00:00
iOffset = ( iOffset * 16807 ) % 2147483647 ;
return ( iOffset ^ MapSeed ) % iRange ;
2011-05-31 01:04:38 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
void C4Landscape : : P : : DrawChunk ( C4Landscape * d , int32_t tx , int32_t ty , int32_t wdt , int32_t hgt , uint8_t mcol , uint8_t mcolBkg , C4MaterialCoreShape Shape , uint32_t cro )
2011-05-31 01:04:38 +00:00
{
2011-09-07 12:25:32 +00:00
unsigned int top_rough = 0 , side_rough = 0 , bottom_rough = 0 ;
2011-05-31 01:04:38 +00:00
// what to do?
2011-09-07 12:25:32 +00:00
switch ( Shape )
2011-05-31 01:04:38 +00:00
{
2011-09-07 12:25:32 +00:00
case C4M_Flat : case C4M_Octagon :
2015-08-05 03:15:52 +00:00
if ( mcol ! = Transparent ) Surface8 - > Box ( tx , ty , tx + wdt , ty + hgt , mcol ) ;
if ( mcolBkg ! = Transparent ) Surface8Bkg - > Box ( tx , ty , tx + wdt , ty + hgt , mcolBkg ) ;
2011-05-31 01:04:38 +00:00
return ;
case C4M_TopFlat :
2011-09-07 12:25:32 +00:00
top_rough = 0 ; side_rough = 2 ; bottom_rough = 4 ;
2011-05-31 01:04:38 +00:00
break ;
case C4M_Smooth :
2011-09-07 12:25:32 +00:00
top_rough = 2 ; side_rough = 2 ; bottom_rough = 2 ;
2011-05-31 01:04:38 +00:00
break ;
case C4M_Rough :
2011-09-07 12:25:32 +00:00
top_rough = 4 ; side_rough = 4 ; bottom_rough = 4 ;
break ;
case C4M_Smoother :
top_rough = 1 ; side_rough = 1 ; bottom_rough = 1 ;
2011-05-31 01:04:38 +00:00
break ;
}
int vtcs [ 16 ] ;
2015-11-15 12:53:01 +00:00
unsigned int rx = std : : max ( wdt / 2 , 1 ) ;
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
vtcs [ 0 ] = tx - ChunkyRandom ( cro , rx * side_rough / 4 ) ; vtcs [ 1 ] = ty - ChunkyRandom ( cro , rx * top_rough / 4 ) ;
vtcs [ 2 ] = tx - ChunkyRandom ( cro , rx * side_rough / 2 ) ; vtcs [ 3 ] = ty + hgt / 2 ;
vtcs [ 4 ] = tx - ChunkyRandom ( cro , rx * side_rough / 4 ) ; vtcs [ 5 ] = ty + hgt + ChunkyRandom ( cro , rx * bottom_rough / 4 ) ;
vtcs [ 6 ] = tx + wdt / 2 ; vtcs [ 7 ] = ty + hgt + ChunkyRandom ( cro , rx * bottom_rough / 2 ) ;
vtcs [ 8 ] = tx + wdt + ChunkyRandom ( cro , rx * side_rough / 4 ) ; vtcs [ 9 ] = ty + hgt + ChunkyRandom ( cro , rx * bottom_rough / 4 ) ;
2011-09-07 12:25:32 +00:00
vtcs [ 10 ] = tx + wdt + ChunkyRandom ( cro , rx * side_rough / 2 ) ; vtcs [ 11 ] = ty + hgt / 2 ;
vtcs [ 12 ] = tx + wdt + ChunkyRandom ( cro , rx * side_rough / 4 ) ; vtcs [ 13 ] = ty - ChunkyRandom ( cro , rx * top_rough / 4 ) ;
vtcs [ 14 ] = tx + wdt / 2 ; vtcs [ 15 ] = ty - ChunkyRandom ( cro , rx * top_rough / 2 ) ;
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
ForPolygon ( d , vtcs , 8 , NULL , NULL , mcol , mcolBkg ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
void C4Landscape : : P : : DrawSmoothOChunk ( C4Landscape * d , int32_t tx , int32_t ty , int32_t wdt , int32_t hgt , uint8_t mcol , uint8_t mcolBkg , int flip , uint32_t cro )
2010-04-20 20:38:18 +00:00
{
2011-05-31 01:04:38 +00:00
int vtcs [ 8 ] ;
2015-11-15 12:53:01 +00:00
unsigned int rx = std : : max ( wdt / 2 , 1 ) ;
2010-04-20 20:38:18 +00:00
2011-09-07 12:25:32 +00:00
vtcs [ 0 ] = tx ; vtcs [ 1 ] = ty ;
2011-09-02 23:22:12 +00:00
vtcs [ 2 ] = tx ; vtcs [ 3 ] = ty + hgt ;
vtcs [ 4 ] = tx + wdt ; vtcs [ 5 ] = ty + hgt ;
2011-09-07 12:25:32 +00:00
vtcs [ 6 ] = tx + wdt ; vtcs [ 7 ] = ty ;
2009-05-08 13:28:41 +00:00
2011-09-07 12:25:32 +00:00
switch ( flip )
{
case 0 : vtcs [ 0 ] = tx + wdt / 2 ; vtcs [ 1 ] + = hgt / 3 ; vtcs [ 7 ] - = ChunkyRandom ( cro , rx / 2 ) ; break ;
case 1 : vtcs [ 2 ] = tx + wdt / 2 ; vtcs [ 3 ] - = hgt / 3 ; vtcs [ 5 ] + = ChunkyRandom ( cro , rx / 2 ) ; break ;
case 2 : vtcs [ 4 ] = tx + wdt / 2 ; vtcs [ 5 ] - = hgt / 3 ; vtcs [ 3 ] + = ChunkyRandom ( cro , rx / 2 ) ; break ;
case 3 : vtcs [ 6 ] = tx + wdt / 2 ; vtcs [ 7 ] + = hgt / 3 ; vtcs [ 1 ] - = ChunkyRandom ( cro , rx / 2 ) ; break ;
case 4 : vtcs [ 0 ] = tx + wdt / 2 ; vtcs [ 1 ] + = hgt / 2 ; break ;
case 5 : vtcs [ 2 ] = tx + wdt / 2 ; vtcs [ 3 ] - = hgt / 2 ; break ;
case 6 : vtcs [ 4 ] = tx + wdt / 2 ; vtcs [ 5 ] - = hgt / 2 ; break ;
case 7 : vtcs [ 6 ] = tx + wdt / 2 ; vtcs [ 7 ] + = hgt / 2 ; break ;
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
ForPolygon ( d , vtcs , 4 , NULL , NULL , mcol , mcolBkg ) ;
2011-05-31 01:04:38 +00:00
}
2010-03-28 18:58:01 +00:00
2016-04-02 15:50:49 +00:00
void C4Landscape : : P : : ChunkOZoom ( C4Landscape * d , const CSurface8 & sfcMap , const CSurface8 & sfcMapBkg , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , uint8_t iTexture , int32_t iOffX , int32_t iOffY )
2011-05-31 01:04:38 +00:00
{
2015-10-09 04:11:53 +00:00
const C4TexMapEntry * entry = : : TextureMap . GetEntry ( iTexture ) ;
C4Material * pMaterial = entry - > GetMaterial ( ) ;
2011-05-31 01:04:38 +00:00
if ( ! pMaterial ) return ;
2015-10-09 04:11:53 +00:00
const char * texture_name = entry - > GetTextureName ( ) ;
C4Texture * texture = : : TextureMap . GetTexture ( texture_name ) ;
C4TextureShape * shape = texture ? texture - > GetMaterialShape ( ) : NULL ;
// Chunk type by material
2013-01-20 11:51:33 +00:00
C4MaterialCoreShape iChunkType = : : Game . C4S . Landscape . FlatChunkShapes ? C4M_Flat : pMaterial - > MapChunkType ;
2011-05-31 01:04:38 +00:00
// Get map & landscape size
2011-09-07 12:25:32 +00:00
int iMapWidth , iMapHeight ;
2016-04-02 15:50:49 +00:00
sfcMap . GetSurfaceSize ( iMapWidth , iMapHeight ) ;
2011-05-31 01:04:38 +00:00
// Clip desired map segment to map size
2015-02-12 22:05:55 +00:00
iMapX = Clamp < int32_t > ( iMapX , 0 , iMapWidth - 1 ) ;
iMapY = Clamp < int32_t > ( iMapY , 0 , iMapHeight - 1 ) ;
iMapWdt = Clamp < int32_t > ( iMapWdt , 0 , iMapWidth - iMapX ) ;
iMapHgt = Clamp < int32_t > ( iMapHgt , 0 , iMapHeight - iMapY ) ;
2011-05-31 01:04:38 +00:00
// get chunk size
2011-09-07 12:25:32 +00:00
int iChunkWidth = MapZoom , iChunkHeight = MapZoom ;
2011-05-31 01:04:38 +00:00
// Scan map lines
2011-09-07 12:25:32 +00:00
for ( int iY = iMapY ; iY < iMapY + iMapHgt ; iY + + )
2011-05-31 01:04:38 +00:00
{
2011-09-07 12:25:32 +00:00
// Landscape target coordinate vertical
int iToY = iY * iChunkHeight + iOffY ;
// Scan map line
for ( int iX = iMapX ; iX < iMapX + iMapWdt ; iX + + )
2011-05-31 01:04:38 +00:00
{
2011-09-07 12:25:32 +00:00
// Map scan line start
2016-04-02 15:50:49 +00:00
uint8_t MapPixel = sfcMap . _GetPix ( iX , iY ) ;
uint8_t MapPixelBkg = sfcMapBkg . _GetPix ( iX , iY ) ;
2011-09-07 12:25:32 +00:00
// Landscape target coordinate horizontal
int iToX = iX * iChunkWidth + iOffX ;
// Here's a chunk of the texture-material to zoom
2015-06-22 22:56:04 +00:00
if ( MapPixel = = iTexture )
2011-09-07 12:25:32 +00:00
{
// Draw chunk
2016-04-02 15:50:49 +00:00
DrawChunk ( d , iToX , iToY , iChunkWidth , iChunkHeight , MapPixel , MapPixelBkg , iChunkType , ( iX < < 16 ) + iY ) ;
2011-09-07 12:25:32 +00:00
}
// Other chunk, check for slope smoothers
else if ( iChunkType = = C4M_Smooth | | iChunkType = = C4M_Smoother | | iChunkType = = C4M_Octagon )
2011-05-31 01:04:38 +00:00
{
2011-07-16 19:50:49 +00:00
// Map scan line pixel below
2016-04-02 15:50:49 +00:00
uint8_t below = sfcMap . GetPix ( iX , iY + 1 ) ;
uint8_t above = sfcMap . GetPix ( iX , iY - 1 ) ;
uint8_t left = sfcMap . GetPix ( iX - 1 , iY ) ;
uint8_t right = sfcMap . GetPix ( iX + 1 , iY ) ;
uint8_t leftBkg = sfcMapBkg . GetPix ( iX - 1 , iY ) ;
uint8_t rightBkg = sfcMapBkg . GetPix ( iX + 1 , iY ) ;
2011-09-07 12:25:32 +00:00
// do not fill a tiny hole
if ( below = = iTexture & & above = = iTexture & & left = = iTexture & & right = = iTexture )
continue ;
int flat = iChunkType = = C4M_Octagon ? 4 : 0 ;
// Smooth chunk & same texture-material below
if ( iY < iMapHeight - 1 & & below = = iTexture )
2011-05-31 01:04:38 +00:00
{
2011-09-07 12:25:32 +00:00
// Same texture-material on left
if ( iX > 0 & & left = = iTexture )
{
// Draw smoother
2016-04-02 15:50:49 +00:00
DrawSmoothOChunk ( d , iToX , iToY , iChunkWidth , iChunkHeight , left , leftBkg , 3 + flat , ( iX < < 16 ) + iY ) ;
2011-09-07 12:25:32 +00:00
}
// Same texture-material on right
if ( iX < iMapWidth - 1 & & right = = iTexture )
{
// Draw smoother
2016-04-02 15:50:49 +00:00
DrawSmoothOChunk ( d , iToX , iToY , iChunkWidth , iChunkHeight , right , rightBkg , 0 + flat , ( iX < < 16 ) + iY ) ;
2011-09-07 12:25:32 +00:00
}
2011-07-16 19:50:49 +00:00
}
2011-09-07 12:25:32 +00:00
// Smooth chunk & same texture-material above
if ( iY > 0 & & above = = iTexture )
{
// Same texture-material on left
if ( iX > 0 & & left = = iTexture )
{
// Draw smoother
2016-04-02 15:50:49 +00:00
DrawSmoothOChunk ( d , iToX , iToY , iChunkWidth , iChunkHeight , left , leftBkg , 2 + flat , ( iX < < 16 ) + iY ) ;
2011-09-07 12:25:32 +00:00
}
// Same texture-material on right
if ( iX < iMapWidth - 1 & & right = = iTexture )
2011-05-31 01:04:38 +00:00
{
2011-09-07 12:25:32 +00:00
// Draw smoother
2016-04-02 15:50:49 +00:00
DrawSmoothOChunk ( d , iToX , iToY , iChunkWidth , iChunkHeight , right , rightBkg , 1 + flat , ( iX < < 16 ) + iY ) ;
2011-05-31 01:04:38 +00:00
}
2011-09-07 12:25:32 +00:00
}
2011-07-16 19:50:49 +00:00
}
2011-05-31 01:04:38 +00:00
}
2010-03-28 18:58:01 +00:00
}
2011-07-16 19:50:49 +00:00
// Draw custom shapes on top of regular materials
2015-10-09 04:11:53 +00:00
if ( shape & & ! : : Game . C4S . Landscape . FlatChunkShapes ) shape - > Draw ( sfcMap , sfcMapBkg , iMapX , iMapY , iMapWdt , iMapHgt , iTexture , iOffX , iOffY , MapZoom , pMaterial - > MinShapeOverlap ) ;
2011-05-31 01:04:38 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
static bool GetTexUsage ( const CSurface8 & sfcMap , const CSurface8 & sfcMapBkg , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , DWORD * dwpTextureUsage )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
int iX , iY ;
2011-05-31 01:04:38 +00:00
// No good parameters
2016-04-02 15:50:49 +00:00
if ( ! dwpTextureUsage ) return false ;
2011-05-31 01:04:38 +00:00
// Clip desired map segment to map size
2016-04-02 15:50:49 +00:00
iMapX = Clamp < int32_t > ( iMapX , 0 , sfcMap . Wdt - 1 ) ; iMapY = Clamp < int32_t > ( iMapY , 0 , sfcMap . Hgt - 1 ) ;
iMapWdt = Clamp < int32_t > ( iMapWdt , 0 , sfcMap . Wdt - iMapX ) ; iMapHgt = Clamp < int32_t > ( iMapHgt , 0 , sfcMap . Hgt - iMapY ) ;
2011-05-31 01:04:38 +00:00
// Zero texture usage list
2016-04-02 15:50:49 +00:00
for ( int32_t cnt = 0 ; cnt < C4M_MaxTexIndex ; cnt + + ) dwpTextureUsage [ cnt ] = 0 ;
2011-05-31 01:04:38 +00:00
// Scan map pixels
2016-04-02 15:50:49 +00:00
for ( iY = iMapY ; iY < iMapY + iMapHgt ; iY + + )
2011-05-31 01:04:38 +00:00
for ( iX = iMapX ; iX < iMapX + iMapWdt ; iX + + )
2013-02-11 20:00:41 +00:00
{
2015-06-22 22:56:04 +00:00
// Count texture map index
2016-04-02 15:50:49 +00:00
const int32_t tex = sfcMap . GetPix ( iX , iY ) ;
2015-06-22 22:56:04 +00:00
assert ( tex < C4M_MaxTexIndex ) ;
2013-02-11 20:00:41 +00:00
if ( ! dwpTextureUsage [ tex ] + + ) if ( tex )
{
// Check if texture actually exists
if ( ! : : TextureMap . GetEntry ( tex ) - > GetMaterial ( ) )
2016-04-02 15:50:49 +00:00
LogF ( " Map2Landscape error: Texture index %d at (%d/%d) in map not defined in texture map! " , ( int ) tex , ( int ) iX , ( int ) iY ) ;
2013-02-11 20:00:41 +00:00
// No error. Landscape is usually fine but might contain some holes where material should be
}
2015-06-22 22:56:04 +00:00
// Ignore background texture for now -- this is only used for ChunkOZoom,
// for which only the foreground texture is relevant.
/*
// Count texture map index
2016-04-02 15:50:49 +00:00
const int32_t texBkg = sfcMapBkg . GetPix ( iX , iY ) ;
2015-06-22 22:56:04 +00:00
if ( ! dwpTextureUsage [ texBkg ] + + ) if ( texBkg )
{
// Check if texture actually exists
if ( ! : : TextureMap . GetEntry ( texBkg ) - > GetMaterial ( ) )
LogF ( " Map2Landscape error: Texture index %d at (%d/%d) in background map not defined in texture map! " , ( int ) texBkg , ( int ) iX , ( int ) iY ) ;
// No error. Landscape is usually fine but might contain some holes where material should be
}
*/
2016-04-02 15:50:49 +00:00
2013-02-11 20:00:41 +00:00
}
2011-05-31 01:04:38 +00:00
// Done
return true ;
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : TexOZoom ( C4Landscape * d , const CSurface8 & sfcMap , const CSurface8 & sfcMapBkg , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , DWORD * dwpTextureUsage , int32_t iToX , int32_t iToY )
2011-05-31 01:04:38 +00:00
{
// ChunkOZoom all used textures
2016-04-02 15:50:49 +00:00
for ( auto iIndex : : : TextureMap . Order )
2015-08-10 04:34:43 +00:00
{
if ( dwpTextureUsage [ iIndex ] > 0 )
2011-05-31 01:04:38 +00:00
{
// ChunkOZoom map to landscape
2016-04-02 15:50:49 +00:00
ChunkOZoom ( d , sfcMap , sfcMapBkg , iMapX , iMapY , iMapWdt , iMapHgt , iIndex , iToX , iToY ) ;
2011-05-31 01:04:38 +00:00
}
2015-08-10 04:34:43 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Done
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : MapToSurface ( C4Landscape * d , const CSurface8 & sfcMap , const CSurface8 & sfcMapBkg , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , int32_t iToX , int32_t iToY , int32_t iToWdt , int32_t iToHgt , int32_t iOffX , int32_t iOffY )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// assign clipper
2016-04-02 15:50:49 +00:00
Surface8 - > Clip ( iToX , iToY , iToX + iToWdt - 1 , iToY + iToHgt - 1 ) ;
Surface8Bkg - > Clip ( iToX , iToY , iToX + iToWdt - 1 , iToY + iToHgt - 1 ) ;
2011-10-03 14:30:18 +00:00
pDraw - > NoPrimaryClipper ( ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Enlarge map segment for chunky rim
2016-04-02 15:50:49 +00:00
iMapX - = 2 + MaterialMap . max_shape_width / MapZoom ;
iMapY - = 2 + MaterialMap . max_shape_height / MapZoom ;
iMapWdt + = 4 + MaterialMap . max_shape_width / MapZoom * 2 ;
iMapHgt + = 4 + MaterialMap . max_shape_height / MapZoom * 2 ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Determine texture usage in map segment
DWORD dwTexUsage [ C4M_MaxTexIndex ] ;
2016-04-02 15:50:49 +00:00
if ( ! GetTexUsage ( sfcMap , sfcMapBkg , iMapX , iMapY , iMapWdt , iMapHgt , dwTexUsage ) ) return false ;
2011-05-31 01:04:38 +00:00
// Texture zoom map to landscape
2016-04-02 15:50:49 +00:00
if ( ! TexOZoom ( d , sfcMap , sfcMapBkg , iMapX , iMapY , iMapWdt , iMapHgt , dwTexUsage , iOffX , iOffY ) ) return false ;
2011-05-31 01:04:38 +00:00
// remove clipper
Surface8 - > NoClip ( ) ;
2015-06-17 00:58:43 +00:00
Surface8Bkg - > NoClip ( ) ;
2011-05-31 01:04:38 +00:00
// success
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : MapToLandscape ( C4Landscape * d , const CSurface8 & sfcMap , const CSurface8 & sfcMapBkg , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , int32_t iOffsX , int32_t iOffsY , bool noClear )
2010-03-28 18:58:01 +00:00
{
2015-06-17 00:58:43 +00:00
assert ( Surface8 & & Surface8Bkg ) ;
2011-05-31 01:04:38 +00:00
// Clip to map/landscape segment
2016-04-02 15:50:49 +00:00
int iMapWidth , iMapHeight , iLandscapeWidth , iLandscapeHeight ;
2011-05-31 01:04:38 +00:00
// Get map & landscape size
2016-04-02 15:50:49 +00:00
sfcMap . GetSurfaceSize ( iMapWidth , iMapHeight ) ;
Surface8 - > GetSurfaceSize ( iLandscapeWidth , iLandscapeHeight ) ;
2011-05-31 01:04:38 +00:00
// Clip map segment to map size
2015-02-12 22:05:55 +00:00
iMapX = Clamp < int32_t > ( iMapX , 0 , iMapWidth - 1 ) ; iMapY = Clamp < int32_t > ( iMapY , 0 , iMapHeight - 1 ) ;
iMapWdt = Clamp < int32_t > ( iMapWdt , 0 , iMapWidth - iMapX ) ; iMapHgt = Clamp < int32_t > ( iMapHgt , 0 , iMapHeight - iMapY ) ;
2011-05-31 01:04:38 +00:00
// No segment
if ( ! iMapWdt | | ! iMapHgt ) return true ;
// Get affected landscape rect
C4Rect To ;
To . x = iMapX * MapZoom + iOffsX ;
To . y = iMapY * MapZoom + iOffsY ;
To . Wdt = iMapWdt * MapZoom ;
To . Hgt = iMapHgt * MapZoom ;
2016-04-02 15:50:49 +00:00
PrepareChange ( d , To ) ;
2012-02-11 22:24:53 +00:00
2015-06-22 22:56:04 +00:00
// clear the old landscape if not supressed
2016-04-02 15:50:49 +00:00
if ( ! noClear )
2015-06-17 00:58:43 +00:00
{
2012-02-11 22:24:53 +00:00
Surface8 - > ClearBox8Only ( To . x , To . y , To . Wdt , To . Hgt ) ;
2015-06-17 00:58:43 +00:00
Surface8Bkg - > ClearBox8Only ( To . x , To . y , To . Wdt , To . Hgt ) ;
}
2012-02-11 22:24:53 +00:00
2016-04-02 15:50:49 +00:00
MapToSurface ( d , sfcMap , sfcMapBkg , iMapX , iMapY , iMapWdt , iMapHgt , To . x , To . y , To . Wdt , To . Hgt , iOffsX , iOffsY ) ;
FinishChange ( d , To ) ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : CreateMap ( CSurface8 * & sfcMap , CSurface8 * & sfcMapBkg )
2010-02-09 19:09:32 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t iWidth = 0 , iHeight = 0 ;
2011-05-31 01:04:38 +00:00
// Create map surface
2016-04-02 15:50:49 +00:00
Game . C4S . Landscape . GetMapSize ( iWidth , iHeight , Game . StartupPlayerCount ) ;
auto fg_map = std : : make_unique < CSurface8 > ( iWidth , iHeight ) ;
2011-05-31 01:04:38 +00:00
// Fill sfcMap
C4MapCreator MapCreator ;
2016-04-02 15:50:49 +00:00
MapCreator . Create ( fg_map . get ( ) ,
Game . C4S . Landscape , : : TextureMap ,
true , Game . StartupPlayerCount ) ;
2011-05-31 01:04:38 +00:00
2016-04-02 15:50:49 +00:00
auto bg_map = CreateDefaultBkgSurface ( * fg_map , false ) ;
if ( ! bg_map )
return false ;
sfcMap = fg_map . release ( ) ;
sfcMapBkg = bg_map . release ( ) ;
2015-06-22 22:56:04 +00:00
return true ;
2010-02-09 19:09:32 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : CreateMapS2 ( C4Group & ScenFile , CSurface8 * & sfcMap , CSurface8 * & sfcMapBkg )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// file present?
2015-06-22 22:56:04 +00:00
if ( ! ScenFile . AccessEntry ( C4CFN_DynLandscape ) ) return false ;
2011-05-31 01:04:38 +00:00
// create map creator
if ( ! pMapCreator )
2016-04-02 15:50:49 +00:00
pMapCreator = std : : make_unique < C4MapCreatorS2 > ( & Game . C4S . Landscape , & : : TextureMap , & : : MaterialMap , Game . StartupPlayerCount ) ;
2011-05-31 01:04:38 +00:00
// read file
pMapCreator - > ReadFile ( C4CFN_DynLandscape , & ScenFile ) ;
// render landscape
2016-04-02 15:50:49 +00:00
if ( ! pMapCreator - > Render ( NULL , sfcMap , sfcMapBkg ) )
2015-07-01 00:29:52 +00:00
return false ;
2011-05-31 01:04:38 +00:00
// keep map creator until script callbacks have been done
2015-06-22 22:56:04 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : PostInitMap ( )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// map creator present?
2016-04-02 15:50:49 +00:00
if ( ! p - > pMapCreator ) return true ;
2011-05-31 01:04:38 +00:00
// call scripts
2016-04-02 15:50:49 +00:00
p - > pMapCreator - > ExecuteCallbacks ( p - > MapZoom ) ;
2011-05-31 01:04:38 +00:00
// destroy map creator, if not needed later
2016-04-02 15:50:49 +00:00
if ( ! Game . C4S . Landscape . KeepMapCreator ) { p - > pMapCreator . reset ( ) ; }
2011-05-31 01:04:38 +00:00
// done, success
return true ;
2010-03-28 18:58:01 +00:00
}
2011-05-30 22:33:35 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* +++++++++++++++ Searching for features in the landscape +++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2015-01-15 18:12:56 +00:00
int32_t C4Landscape : : GetMatHeight ( int32_t x , int32_t y , int32_t iYDir , int32_t iMat , int32_t iMax ) const
2011-05-31 01:04:38 +00:00
{
if ( iYDir > 0 )
{
2016-04-02 15:50:49 +00:00
iMax = std : : min < int32_t > ( iMax , GetHeight ( ) - y ) ;
2011-05-31 01:04:38 +00:00
for ( int32_t i = 0 ; i < iMax ; i + + )
if ( _GetMat ( x , y + i ) ! = iMat )
return i ;
}
else
{
2015-11-15 12:53:01 +00:00
iMax = std : : min < int32_t > ( iMax , y + 1 ) ;
2011-05-31 01:04:38 +00:00
for ( int32_t i = 0 ; i < iMax ; i + + )
if ( _GetMat ( x , y - i ) ! = iMat )
return i ;
}
return iMax ;
}
2011-05-30 22:33:35 +00:00
// Nearest free above semi solid
2012-02-10 20:48:48 +00:00
bool AboveSemiSolid ( int32_t & rx , int32_t & ry )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t cy1 = ry , cy2 = ry ;
bool UseUpwardsNextFree = false , UseDownwardsNextSolid = false ;
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
while ( ( cy1 > = 0 ) | | ( cy2 < : : Landscape . GetHeight ( ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Check upwards
2016-04-02 15:50:49 +00:00
if ( cy1 > = 0 )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( GBackSemiSolid ( rx , cy1 ) ) UseUpwardsNextFree = true ;
else if ( UseUpwardsNextFree ) { ry = cy1 ; return true ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Check downwards
2016-04-02 15:50:49 +00:00
if ( cy2 < : : Landscape . GetHeight ( ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! GBackSemiSolid ( rx , cy2 ) ) UseDownwardsNextSolid = true ;
else if ( UseDownwardsNextSolid ) { ry = cy2 ; return true ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Advance
cy1 - - ; cy2 + + ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-30 22:33:35 +00:00
// Nearest free directly above solid
2012-02-10 20:48:48 +00:00
bool AboveSolid ( int32_t & rx , int32_t & ry )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t cy1 = ry , cy2 = ry ;
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
while ( ( cy1 > = 0 ) | | ( cy2 < : : Landscape . GetHeight ( ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Check upwards
2016-04-02 15:50:49 +00:00
if ( cy1 > = 0 )
if ( ! GBackSemiSolid ( rx , cy1 ) )
if ( GBackSolid ( rx , cy1 + 1 ) )
{
ry = cy1 ; return true ;
}
2009-05-08 13:28:41 +00:00
// Check downwards
2016-04-02 15:50:49 +00:00
if ( cy2 + 1 < : : Landscape . GetHeight ( ) )
if ( ! GBackSemiSolid ( rx , cy2 ) )
if ( GBackSolid ( rx , cy2 + 1 ) )
{
ry = cy2 ; return true ;
}
2009-05-08 13:28:41 +00:00
// Advance
cy1 - - ; cy2 + + ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-30 22:33:35 +00:00
// Nearest free/semi above solid
2012-02-10 20:48:48 +00:00
bool SemiAboveSolid ( int32_t & rx , int32_t & ry )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t cy1 = ry , cy2 = ry ;
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
while ( ( cy1 > = 0 ) | | ( cy2 < : : Landscape . GetHeight ( ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Check upwards
2016-04-02 15:50:49 +00:00
if ( cy1 > = 0 )
if ( ! GBackSolid ( rx , cy1 ) )
if ( GBackSolid ( rx , cy1 + 1 ) )
{
ry = cy1 ; return true ;
}
2009-05-08 13:28:41 +00:00
// Check downwards
2016-04-02 15:50:49 +00:00
if ( cy2 + 1 < : : Landscape . GetHeight ( ) )
if ( ! GBackSolid ( rx , cy2 ) )
if ( GBackSolid ( rx , cy2 + 1 ) )
{
ry = cy2 ; return true ;
}
2009-05-08 13:28:41 +00:00
// Advance
cy1 - - ; cy2 + + ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool FindLiquidHeight ( int32_t cx , int32_t & ry , int32_t hgt )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t cy1 = ry , cy2 = ry , rl1 = 0 , rl2 = 0 ;
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
while ( ( cy1 > = 0 ) | | ( cy2 < : : Landscape . GetHeight ( ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Check upwards
2016-04-02 15:50:49 +00:00
if ( cy1 > = 0 )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( GBackLiquid ( cx , cy1 ) )
{
rl1 + + ; if ( rl1 > = hgt ) { ry = cy1 + hgt / 2 ; return true ; }
}
else rl1 = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Check downwards
2016-04-02 15:50:49 +00:00
if ( cy2 + 1 < : : Landscape . GetHeight ( ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( GBackLiquid ( cx , cy2 ) )
{
rl2 + + ; if ( rl2 > = hgt ) { ry = cy2 - hgt / 2 ; return true ; }
}
else rl2 = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Advance
cy1 - - ; cy2 + + ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-10-02 22:11:00 +00:00
bool FindTunnelHeight ( int32_t cx , int32_t & ry , int32_t hgt )
{
2016-04-02 15:50:49 +00:00
int32_t cy1 = ry , cy2 = ry , rl1 = 0 , rl2 = 0 ;
2011-10-02 22:11:00 +00:00
2016-04-02 15:50:49 +00:00
while ( ( cy1 > = 0 ) | | ( cy2 < : : Landscape . GetHeight ( ) ) )
2011-10-02 22:11:00 +00:00
{
// Check upwards
2016-04-02 15:50:49 +00:00
if ( cy1 > = 0 )
2011-10-02 22:11:00 +00:00
{
2016-04-02 15:50:49 +00:00
if ( Landscape . GetBackPix ( cx , cy1 ) ! = 0 & & MatDensity ( GBackMat ( cx , cy1 ) ) < C4M_Liquid )
{
rl1 + + ; if ( rl1 > = hgt ) { ry = cy1 + hgt / 2 ; return true ; }
}
else rl1 = 0 ;
2011-10-02 22:11:00 +00:00
}
// Check downwards
2016-04-02 15:50:49 +00:00
if ( cy2 + 1 < : : Landscape . GetHeight ( ) )
2011-10-02 22:11:00 +00:00
{
2016-04-02 15:50:49 +00:00
if ( Landscape . GetBackPix ( cx , cy2 ) ! = 0 & & MatDensity ( GBackMat ( cx , cy2 ) ) < C4M_Liquid )
{
rl2 + + ; if ( rl2 > = hgt ) { ry = cy2 - hgt / 2 ; return true ; }
}
else rl2 = 0 ;
2011-10-02 22:11:00 +00:00
}
// Advance
cy1 - - ; cy2 + + ;
}
return false ;
}
2011-05-30 22:33:35 +00:00
// Starting from rx/ry, searches for a width of solid ground.
// Returns bottom center of surface space found.
2009-08-15 18:50:32 +00:00
bool FindSolidGround ( int32_t & rx , int32_t & ry , int32_t width )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
bool fFound = false ;
2010-03-27 16:05:02 +00:00
2016-04-02 15:50:49 +00:00
int32_t cx1 , cx2 , cy1 , cy2 , rl1 = 0 , rl2 = 0 ;
2010-03-27 16:05:02 +00:00
2016-04-02 15:50:49 +00:00
for ( cx1 = cx2 = rx , cy1 = cy2 = ry ; ( cx1 > 0 ) | | ( cx2 < : : Landscape . GetWidth ( ) ) ; cx1 - - , cx2 + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Left search
2016-04-02 15:50:49 +00:00
if ( cx1 > = 0 ) // Still going
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( AboveSolid ( cx1 , cy1 ) ) rl1 + + ; // Run okay
else rl1 = 0 ; // No run
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Right search
2016-04-02 15:50:49 +00:00
if ( cx2 < : : Landscape . GetWidth ( ) ) // Still going
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( AboveSolid ( cx2 , cy2 ) ) rl2 + + ; // Run okay
else rl2 = 0 ; // No run
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Check runs
2016-04-02 15:50:49 +00:00
if ( rl1 > = width ) { rx = cx1 + rl1 / 2 ; ry = cy1 ; fFound = true ; break ; }
if ( rl2 > = width ) { rx = cx2 - rl2 / 2 ; ry = cy2 ; fFound = true ; break ; }
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
2016-04-02 15:50:49 +00:00
if ( fFound ) AboveSemiSolid ( rx , ry ) ;
2010-03-27 16:05:02 +00:00
return fFound ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool FindSurfaceLiquid ( int32_t & rx , int32_t & ry , int32_t width , int32_t height )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
bool fFound = false ;
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
int32_t cx1 , cx2 , cy1 , cy2 , rl1 = 0 , rl2 = 0 , cnt ;
2009-08-15 18:50:32 +00:00
bool lokay ;
2016-04-02 15:50:49 +00:00
for ( cx1 = cx2 = rx , cy1 = cy2 = ry ; ( cx1 > 0 ) | | ( cx2 < : : Landscape . GetWidth ( ) ) ; cx1 - - , cx2 + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Left search
2016-04-02 15:50:49 +00:00
if ( cx1 > 0 ) // Still going
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! AboveSemiSolid ( cx1 , cy1 ) ) cx1 = - 1 ; // Abort left
2010-03-27 16:05:02 +00:00
else
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
for ( lokay = true , cnt = 0 ; cnt < height ; cnt + + ) if ( ! GBackLiquid ( cx1 , cy1 + 1 + cnt ) ) lokay = false ;
2009-05-08 13:28:41 +00:00
if ( lokay ) rl1 + + ; // Run okay
2016-04-02 15:50:49 +00:00
else rl1 = 0 ; // No run
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Right search
2016-04-02 15:50:49 +00:00
if ( cx2 < : : Landscape . GetWidth ( ) ) // Still going
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! AboveSemiSolid ( cx2 , cy2 ) ) cx2 = : : Landscape . GetWidth ( ) ; // Abort right
2010-03-27 16:05:02 +00:00
else
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
for ( lokay = true , cnt = 0 ; cnt < height ; cnt + + ) if ( ! GBackLiquid ( cx2 , cy2 + 1 + cnt ) ) lokay = false ;
2009-05-08 13:28:41 +00:00
if ( lokay ) rl2 + + ; // Run okay
2016-04-02 15:50:49 +00:00
else rl2 = 0 ; // No run
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Check runs
2016-04-02 15:50:49 +00:00
if ( rl1 > = width ) { rx = cx1 + rl1 / 2 ; ry = cy1 ; fFound = true ; break ; }
if ( rl2 > = width ) { rx = cx2 - rl2 / 2 ; ry = cy2 ; fFound = true ; break ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
if ( fFound ) AboveSemiSolid ( rx , ry ) ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
return fFound ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool FindLiquid ( int32_t & rx , int32_t & ry , int32_t width , int32_t height )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t cx1 , cx2 , cy1 , cy2 , rl1 = 0 , rl2 = 0 ;
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
for ( cx1 = cx2 = rx , cy1 = cy2 = ry ; ( cx1 > 0 ) | | ( cx2 < : : Landscape . GetWidth ( ) ) ; cx1 - - , cx2 + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Left search
2016-04-02 15:50:49 +00:00
if ( cx1 > 0 )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( FindLiquidHeight ( cx1 , cy1 , height ) ) rl1 + + ;
else rl1 = 0 ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Right search
2016-04-02 15:50:49 +00:00
if ( cx2 < : : Landscape . GetWidth ( ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( FindLiquidHeight ( cx2 , cy2 , height ) ) rl2 + + ;
else rl2 = 0 ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Check runs
2016-04-02 15:50:49 +00:00
if ( rl1 > = width ) { rx = cx1 + rl1 / 2 ; ry = cy1 ; return true ; }
if ( rl2 > = width ) { rx = cx2 - rl2 / 2 ; ry = cy2 ; return true ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-10-02 22:11:00 +00:00
// Starting from rx/ry, searches for tunnel background
// Tunnel background == no sky && no semi/solid material (density < 25)
bool FindTunnel ( int32_t & rx , int32_t & ry , int32_t width , int32_t height )
{
2016-04-02 15:50:49 +00:00
int32_t cx1 , cx2 , cy1 , cy2 , rl1 = 0 , rl2 = 0 ;
2011-10-02 22:11:00 +00:00
2016-04-02 15:50:49 +00:00
for ( cx1 = cx2 = rx , cy1 = cy2 = ry ; ( cx1 > 0 ) | | ( cx2 < : : Landscape . GetWidth ( ) ) ; cx1 - - , cx2 + + )
2011-10-02 22:11:00 +00:00
{
// Left search
2016-04-02 15:50:49 +00:00
if ( cx1 > 0 )
2011-10-02 22:11:00 +00:00
{
2016-04-02 15:50:49 +00:00
if ( FindTunnelHeight ( cx1 , cy1 , height ) ) rl1 + + ;
else rl1 = 0 ;
2011-10-02 22:11:00 +00:00
}
// Right search
2016-04-02 15:50:49 +00:00
if ( cx2 < : : Landscape . GetWidth ( ) )
2011-10-02 22:11:00 +00:00
{
2016-04-02 15:50:49 +00:00
if ( FindTunnelHeight ( cx2 , cy2 , height ) ) rl2 + + ;
else rl2 = 0 ;
2011-10-02 22:11:00 +00:00
}
// Check runs
2016-04-02 15:50:49 +00:00
if ( rl1 > = width ) { rx = cx1 + rl1 / 2 ; ry = cy1 ; return true ; }
if ( rl2 > = width ) { rx = cx2 - rl2 / 2 ; ry = cy2 ; return true ; }
2011-10-02 22:11:00 +00:00
}
return false ;
}
2011-05-30 22:33:35 +00:00
// Starting from rx/ry, searches for a width of solid ground. Extreme distances
// may not exceed hrange. Returns bottom center of surface found.
2009-08-15 18:50:32 +00:00
bool FindLevelGround ( int32_t & rx , int32_t & ry , int32_t width , int32_t hrange )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
bool fFound = false ;
2010-03-27 16:05:02 +00:00
2016-04-02 15:50:49 +00:00
int32_t cx1 , cx2 , cy1 , cy2 , rh1 , rh2 , rl1 , rl2 ;
2010-03-27 16:05:02 +00:00
2016-04-02 15:50:49 +00:00
cx1 = cx2 = rx ; cy1 = cy2 = ry ;
rh1 = cy1 ; rh2 = cy2 ;
rl1 = rl2 = 0 ;
2010-03-27 16:05:02 +00:00
2016-04-02 15:50:49 +00:00
for ( cx1 - - , cx2 + + ; ( cx1 > 0 ) | | ( cx2 < : : Landscape . GetWidth ( ) ) ; cx1 - - , cx2 + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Left search
2016-04-02 15:50:49 +00:00
if ( cx1 > 0 ) // Still going
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! AboveSemiSolid ( cx1 , cy1 ) ) cx1 = - 1 ; // Abort left
2010-03-27 16:05:02 +00:00
else
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( GBackSolid ( cx1 , cy1 + 1 ) & & ( Abs ( cy1 - rh1 ) < hrange ) )
2010-03-27 16:05:02 +00:00
rl1 + + ; // Run okay
else
2016-04-02 15:50:49 +00:00
{
rl1 = 0 ; rh1 = cy1 ;
} // No run
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Right search
2016-04-02 15:50:49 +00:00
if ( cx2 < : : Landscape . GetWidth ( ) ) // Still going
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! AboveSemiSolid ( cx2 , cy2 ) ) cx2 = : : Landscape . GetWidth ( ) ; // Abort right
2010-03-27 16:05:02 +00:00
else
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( GBackSolid ( cx2 , cy2 + 1 ) & & ( Abs ( cy2 - rh2 ) < hrange ) )
2010-03-27 16:05:02 +00:00
rl2 + + ; // Run okay
else
2016-04-02 15:50:49 +00:00
{
rl2 = 0 ; rh2 = cy2 ;
} // No run
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Check runs
2016-04-02 15:50:49 +00:00
if ( rl1 > = width ) { rx = cx1 + rl1 / 2 ; ry = cy1 ; fFound = true ; break ; }
if ( rl2 > = width ) { rx = cx2 - rl2 / 2 ; ry = cy2 ; fFound = true ; break ; }
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
2016-04-02 15:50:49 +00:00
if ( fFound ) AboveSemiSolid ( rx , ry ) ;
2010-03-27 16:05:02 +00:00
return fFound ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-30 22:33:35 +00:00
// Starting from rx/ry, searches for a width of solid level ground with
// structure clearance (category). Returns bottom center of surface found.
2016-01-30 13:46:14 +00:00
bool FindConSiteSpot ( int32_t & rx , int32_t & ry , int32_t wdt , int32_t hgt , int32_t hrange )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
bool fFound = false ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// No hrange limit, use standard smooth surface limit
2016-04-02 15:50:49 +00:00
if ( hrange = = - 1 ) hrange = std : : max ( wdt / 4 , 5 ) ;
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
int32_t cx1 , cx2 , cy1 , cy2 , rh1 , rh2 , rl1 , rl2 ;
2009-05-08 13:28:41 +00:00
// Left offset starting position
2016-04-02 15:50:49 +00:00
cx1 = std : : min ( rx + wdt / 2 , : : Landscape . GetWidth ( ) - 1 ) ; cy1 = ry ;
2009-05-08 13:28:41 +00:00
// No good: use centered starting position
2016-04-02 15:50:49 +00:00
if ( ! AboveSemiSolid ( cx1 , cy1 ) ) { cx1 = std : : min < int32_t > ( rx , : : Landscape . GetWidth ( ) - 1 ) ; cy1 = ry ; }
2009-05-08 13:28:41 +00:00
// Right offset starting position
2016-04-02 15:50:49 +00:00
cx2 = std : : max ( rx - wdt / 2 , 0 ) ; cy2 = ry ;
2009-05-08 13:28:41 +00:00
// No good: use centered starting position
2016-04-02 15:50:49 +00:00
if ( ! AboveSemiSolid ( cx2 , cy2 ) ) { cx2 = std : : min < int32_t > ( rx , : : Landscape . GetWidth ( ) - 1 ) ; cy2 = ry ; }
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
rh1 = cy1 ; rh2 = cy2 ; rl1 = rl2 = 0 ;
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
for ( cx1 - - , cx2 + + ; ( cx1 > 0 ) | | ( cx2 < : : Landscape . GetWidth ( ) ) ; cx1 - - , cx2 + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Left search
2016-04-02 15:50:49 +00:00
if ( cx1 > 0 ) // Still going
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! AboveSemiSolid ( cx1 , cy1 ) )
cx1 = - 1 ; // Abort left
2010-03-27 16:05:02 +00:00
else
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( GBackSolid ( cx1 , cy1 + 1 ) & & ( Abs ( cy1 - rh1 ) < hrange ) )
2010-03-27 16:05:02 +00:00
rl1 + + ; // Run okay
else
2016-04-02 15:50:49 +00:00
{
rl1 = 0 ; rh1 = cy1 ;
} // No run
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Right search
2016-04-02 15:50:49 +00:00
if ( cx2 < : : Landscape . GetWidth ( ) ) // Still going
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! AboveSemiSolid ( cx2 , cy2 ) )
cx2 = : : Landscape . GetWidth ( ) ; // Abort right
2010-03-27 16:05:02 +00:00
else
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( GBackSolid ( cx2 , cy2 + 1 ) & & ( Abs ( cy2 - rh2 ) < hrange ) )
2010-03-27 16:05:02 +00:00
rl2 + + ; // Run okay
else
2016-04-02 15:50:49 +00:00
{
rl2 = 0 ; rh2 = cy2 ;
} // No run
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Check runs & object overlap
2016-04-02 15:50:49 +00:00
if ( rl1 > = wdt ) if ( cx1 > 0 )
if ( ! Game . FindConstuctionSiteBlock ( cx1 , cy1 - hgt - 10 , wdt , hgt + 40 ) )
{
rx = cx1 + wdt / 2 ; ry = cy1 ; fFound = true ; break ;
}
if ( rl2 > = wdt ) if ( cx2 < : : Landscape . GetWidth ( ) )
if ( ! Game . FindConstuctionSiteBlock ( cx2 - wdt , cy2 - hgt - 10 , wdt , hgt + 40 ) )
{
rx = cx2 - wdt / 2 ; ry = cy2 ; fFound = true ; break ;
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
2016-04-02 15:50:49 +00:00
if ( fFound ) AboveSemiSolid ( rx , ry ) ;
2010-03-27 16:05:02 +00:00
return fFound ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
// Returns false on any solid pix in path.
2015-02-23 11:43:13 +00:00
bool PathFreePix ( int32_t x , int32_t y )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
return ! GBackSolid ( x , y ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2012-12-22 15:47:45 +00:00
bool PathFree ( int32_t x1 , int32_t y1 , int32_t x2 , int32_t y2 )
{
2016-04-02 15:50:49 +00:00
return ForLine ( x1 , y1 , x2 , y2 , & PathFreePix ) ;
2012-12-22 15:47:45 +00:00
}
2009-08-15 18:50:32 +00:00
bool PathFree ( int32_t x1 , int32_t y1 , int32_t x2 , int32_t y2 , int32_t * ix , int32_t * iy )
2010-03-28 18:58:01 +00:00
{
2012-12-22 15:47:45 +00:00
// use the standard Bresenham algorithm and just adjust it to behave correctly in the inversed case
bool reverse = false ;
bool steep = Abs ( y2 - y1 ) > Abs ( x2 - x1 ) ;
if ( steep )
{
2015-11-15 12:53:01 +00:00
std : : swap ( x1 , y1 ) ;
std : : swap ( x2 , y2 ) ;
2012-12-22 15:47:45 +00:00
}
if ( x1 > x2 )
{
2015-11-15 12:53:01 +00:00
std : : swap ( x1 , x2 ) ;
std : : swap ( y1 , y2 ) ;
2012-12-22 15:47:45 +00:00
reverse = true ;
}
if ( ! reverse )
{
int32_t deltax = x2 - x1 ;
int32_t deltay = Abs ( y2 - y1 ) ;
int32_t error = 0 ;
int32_t ystep = ( y1 < y2 ) ? 1 : - 1 ;
int32_t y = y1 ;
for ( int32_t x = x1 ; x < = x2 ; x + + )
{
if ( steep )
{
if ( GBackSolid ( y , x ) )
{
2016-04-02 15:50:49 +00:00
if ( ix ) { * ix = y ; * iy = x ; }
2012-12-22 15:47:45 +00:00
return false ;
}
}
else
{
if ( GBackSolid ( x , y ) )
{
2016-04-02 15:50:49 +00:00
if ( ix ) { * ix = x ; * iy = y ; }
2012-12-22 15:47:45 +00:00
return false ;
}
}
error + = deltay ;
if ( 2 * error > = deltax )
{
y + = ystep ;
error - = deltax ;
}
}
}
else // reverse
{
int32_t deltax = x2 - x1 ;
int32_t deltay = Abs ( y2 - y1 ) ;
int32_t error = 0 ;
int32_t ystep = ( y1 < y2 ) ? 1 : - 1 ;
int32_t y = y2 ;
// normal (inverse) routine
for ( int32_t x = x2 ; x > = x1 ; x - - )
{
if ( steep )
{
if ( GBackSolid ( y , x ) )
{
2016-04-02 15:50:49 +00:00
if ( ix ) { * ix = y ; * iy = x ; }
2012-12-22 15:47:45 +00:00
return false ;
}
}
else
{
if ( GBackSolid ( x , y ) )
2016-04-02 15:50:49 +00:00
{
if ( ix ) { * ix = x ; * iy = y ; }
2012-12-22 15:47:45 +00:00
return false ;
}
}
error - = deltay ;
if ( 2 * error < = - deltax )
{
y - = ystep ;
error + = deltax ;
}
}
}
// no solid material encountered: path free!
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-02-23 11:43:13 +00:00
bool PathFreeIgnoreVehiclePix ( int32_t x , int32_t y )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
BYTE byPix = : : Landscape . GetPix ( x , y ) ;
2009-06-05 15:20:41 +00:00
return ! byPix | | ! DensitySolid ( : : Landscape . GetPixMat ( byPix ) ) | | : : Landscape . GetPixMat ( byPix ) = = MVehic ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool PathFreeIgnoreVehicle ( int32_t x1 , int32_t y1 , int32_t x2 , int32_t y2 , int32_t * ix , int32_t * iy )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
return ForLine ( x1 , y1 , x2 , y2 , & PathFreeIgnoreVehiclePix , ix , iy ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
int32_t TrajectoryDistance ( int32_t iFx , int32_t iFy , C4Real iXDir , C4Real iYDir , int32_t iTx , int32_t iTy )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t iClosest = Distance ( iFx , iFy , iTx , iTy ) ;
2009-05-08 13:28:41 +00:00
// Follow free trajectory, take closest point distance
2010-05-04 15:35:18 +00:00
C4Real cx = itofix ( iFx ) , cy = itofix ( iFy ) ;
2009-05-08 13:28:41 +00:00
int32_t cdis ;
2016-04-02 15:50:49 +00:00
while ( Inside ( fixtoi ( cx ) , 0 , : : Landscape . GetWidth ( ) - 1 ) & & Inside ( fixtoi ( cy ) , 0 , : : Landscape . GetHeight ( ) - 1 ) & & ! GBackSolid ( fixtoi ( cx ) , fixtoi ( cy ) ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
cdis = Distance ( fixtoi ( cx ) , fixtoi ( cy ) , iTx , iTy ) ;
if ( cdis < iClosest ) iClosest = cdis ;
cx + = iXDir ; cy + = iYDir ; iYDir + = GravAccel ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return iClosest ;
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
static constexpr int32_t
Throwing_MaxVertical = 50 ,
Throwing_MaxHorizontal = 60 ;
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
bool FindThrowingPosition ( int32_t iTx , int32_t iTy , C4Real fXDir , C4Real fYDir , int32_t iHeight , int32_t & rX , int32_t & rY )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Start underneath throwing target
2016-04-02 15:50:49 +00:00
rX = iTx ; rY = iTy ; // improve: check from overhanging cliff
if ( ! SemiAboveSolid ( rX , rY ) ) return false ;
2009-05-08 13:28:41 +00:00
// Target too far above surface
2016-04-02 15:50:49 +00:00
if ( ! Inside ( rY - iTy , - Throwing_MaxVertical , + Throwing_MaxVertical ) ) return false ;
2009-05-08 13:28:41 +00:00
// Search in direction according to launch fXDir
2016-04-02 15:50:49 +00:00
int32_t iDir = + 1 ; if ( fXDir > 0 ) iDir = - 1 ;
2009-05-08 13:28:41 +00:00
// Move along surface
2016-04-02 15:50:49 +00:00
for ( int32_t cnt = 0 ; Inside < int32_t > ( rX , 0 , : : Landscape . GetWidth ( ) - 1 ) & & ( cnt < = Throwing_MaxHorizontal ) ; rX + = iDir , cnt + + )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Adjust to surface
2016-04-02 15:50:49 +00:00
if ( ! SemiAboveSolid ( rX , rY ) ) return false ;
2009-05-08 13:28:41 +00:00
// Check trajectory distance
2016-04-02 15:50:49 +00:00
int32_t itjd = TrajectoryDistance ( rX , rY - iHeight , fXDir , fYDir , iTx , iTy ) ;
2009-05-08 13:28:41 +00:00
// Hitting range: success
2016-04-02 15:50:49 +00:00
if ( itjd < = 2 ) return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Failure
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
static constexpr int32_t
Closest_MaxRange = 200 ,
Closest_Step = 10 ;
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool FindClosestFree ( int32_t & rX , int32_t & rY , int32_t iAngle1 , int32_t iAngle2 ,
2016-04-02 15:50:49 +00:00
int32_t iExcludeAngle1 , int32_t iExcludeAngle2 )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t iX , iY ;
for ( int32_t iR = Closest_Step ; iR < Closest_MaxRange ; iR + = Closest_Step )
for ( int32_t iAngle = iAngle1 ; iAngle < iAngle2 ; iAngle + = Closest_Step )
if ( ! Inside ( iAngle , iExcludeAngle1 , iExcludeAngle2 ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
iX = rX + fixtoi ( Sin ( itofix ( iAngle ) ) * iR ) ;
iY = rY - fixtoi ( Cos ( itofix ( iAngle ) ) * iR ) ;
2016-04-02 15:50:49 +00:00
if ( Inside < int32_t > ( iX , 0 , : : Landscape . GetWidth ( ) - 1 ) )
if ( Inside < int32_t > ( iY , 0 , : : Landscape . GetHeight ( ) - 1 ) )
if ( ! GBackSemiSolid ( iX , iY ) )
{
rX = iX ; rY = iY ; return true ;
}
2010-03-28 18:58:01 +00:00
}
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool ConstructionCheck ( C4PropList * PropList , int32_t iX , int32_t iY , C4Object * pByObj )
2010-03-28 18:58:01 +00:00
{
2009-04-12 12:04:28 +00:00
C4Def * ndef ;
// Check def
2016-04-02 15:50:49 +00:00
if ( ! ( ndef = PropList - > GetDef ( ) ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( pByObj ) GameMsgObjectError ( FormatString ( LoadResStr ( " IDS_OBJ_UNDEF " ) , PropList - > GetName ( ) ) . getData ( ) , pByObj ) ;
2009-08-15 18:50:32 +00:00
return false ;
2009-04-12 12:04:28 +00:00
}
// Constructable?
if ( ! ndef - > Constructable )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( pByObj ) GameMsgObjectError ( FormatString ( LoadResStr ( " IDS_OBJ_NOCON " ) , ndef - > GetName ( ) ) . getData ( ) , pByObj ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-04-12 12:04:28 +00:00
// Check area
2016-04-02 15:50:49 +00:00
int32_t rtx , rty , wdt , hgt ;
wdt = ndef - > Shape . Wdt ; hgt = ndef - > Shape . Hgt - ndef - > ConSizeOff ;
rtx = iX - wdt / 2 ; rty = iY - hgt ;
if ( : : Landscape . AreaSolidCount ( rtx , rty , wdt , hgt ) > ( wdt * hgt / 20 ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( pByObj ) GameMsgObjectError ( LoadResStr ( " IDS_OBJ_NOROOM " ) , pByObj ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2016-04-02 15:50:49 +00:00
if ( : : Landscape . AreaSolidCount ( rtx , rty + hgt , wdt , 5 ) < ( wdt * 2 ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( pByObj ) GameMsgObjectError ( LoadResStr ( " IDS_OBJ_NOLEVEL " ) , pByObj ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-04-12 12:04:28 +00:00
// Check other structures
C4Object * other ;
2016-04-02 15:50:49 +00:00
if ( ( other = Game . FindConstuctionSiteBlock ( rtx , rty , wdt , hgt ) ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( pByObj ) GameMsgObjectError ( FormatString ( LoadResStr ( " IDS_OBJ_NOOTHER " ) , other - > GetName ( ) ) . getData ( ) , pByObj ) ;
2009-08-15 18:50:32 +00:00
return false ;
2009-04-12 12:04:28 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Finds the next pixel position moving to desired slide.
2015-01-15 18:12:56 +00:00
bool C4Landscape : : FindMatPath ( int32_t & fx , int32_t & fy , int32_t ydir , int32_t mdens , int32_t mslide ) const
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
assert ( mdens < = C4M_Solid ) ; // mdens normalized in InsertMaterial
2013-03-30 13:05:12 +00:00
2011-05-31 01:04:38 +00:00
int32_t cslide ;
2016-04-02 15:50:49 +00:00
bool fLeft = true , fRight = true ;
2011-05-31 01:04:38 +00:00
// One downwards
2016-04-02 15:50:49 +00:00
if ( GetDensity ( fx , fy + ydir ) < mdens ) { fy + = ydir ; return true ; }
2011-05-31 01:04:38 +00:00
// Find downwards slide path
2016-04-02 15:50:49 +00:00
for ( cslide = 1 ; ( cslide < = mslide ) & & ( fLeft | | fRight ) ; cslide + + )
2011-05-31 01:04:38 +00:00
{
// Check left
if ( fLeft )
{
2016-04-02 15:50:49 +00:00
if ( GetDensity ( fx - cslide , fy ) > = mdens ) // Left clogged
fLeft = false ;
else if ( GetDensity ( fx - cslide , fy + ydir ) < mdens ) // Left slide okay
{
fx - - ; return true ;
}
2011-05-31 01:04:38 +00:00
}
// Check right
if ( fRight )
{
2016-04-02 15:50:49 +00:00
if ( GetDensity ( fx + cslide , fy ) > = mdens ) // Right clogged
fRight = false ;
else if ( GetDensity ( fx + cslide , fy + ydir ) < mdens ) // Right slide okay
{
fx + + ; return true ;
}
2011-05-31 01:04:38 +00:00
}
}
return false ;
2010-03-28 18:58:01 +00:00
}
2009-06-12 18:52:21 +00:00
2011-05-31 01:04:38 +00:00
// Finds the closest immediate slide position.
2015-01-15 18:12:56 +00:00
bool C4Landscape : : FindMatSlide ( int32_t & fx , int32_t & fy , int32_t ydir , int32_t mdens , int32_t mslide ) const
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
assert ( mdens < = C4M_Solid ) ; // mdens normalized in InsertMaterial and mrfInsertCheck
2011-05-31 01:04:38 +00:00
int32_t cslide ;
2016-04-02 15:50:49 +00:00
bool fLeft = true , fRight = true ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// One downwards
2016-04-02 15:50:49 +00:00
if ( GetDensity ( fx , fy + ydir ) < mdens ) { fy + = ydir ; return true ; }
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Find downwards slide path
2016-04-02 15:50:49 +00:00
for ( cslide = 1 ; ( cslide < = mslide ) & & ( fLeft | | fRight ) ; cslide + + )
2011-05-31 01:04:38 +00:00
{
// Check left
if ( fLeft )
{
2016-04-02 15:50:49 +00:00
if ( GetDensity ( fx - cslide , fy ) > = mdens & & GetDensity ( fx - cslide , fy + ydir ) > = mdens ) // Left clogged
fLeft = false ;
else if ( GetDensity ( fx - cslide , fy + ydir ) < mdens ) // Left slide okay
{
fx - = cslide ; fy + = ydir ; return true ;
}
2011-05-31 01:04:38 +00:00
}
// Check right
if ( fRight )
{
2016-04-02 15:50:49 +00:00
if ( GetDensity ( fx + cslide , fy ) > = mdens & & GetDensity ( fx + cslide , fy + ydir ) > = mdens ) // Right clogged
fRight = false ;
else if ( GetDensity ( fx + cslide , fy + ydir ) < mdens ) // Right slide okay
{
fx + = cslide ; fy + = ydir ; return true ;
}
2011-05-31 01:04:38 +00:00
}
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
return false ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Find closest point with density below mdens. Note this may return a point outside of the landscape,
// Assumption: There are no holes with smaller density inside of material with greater
// density.
2015-01-15 18:12:56 +00:00
bool C4Landscape : : FindMatPathPush ( int32_t & fx , int32_t & fy , int32_t mdens , int32_t mslide , bool liquid ) const
2011-05-31 01:04:38 +00:00
{
// Startpoint must be inside landscape
2016-04-02 15:50:49 +00:00
fx = Clamp < int32_t > ( fx , 0 , GetWidth ( ) - 1 ) ;
fy = Clamp < int32_t > ( fy , 0 , GetHeight ( ) - 1 ) ;
2011-05-31 01:04:38 +00:00
// Range to search, calculate bounds
const int32_t iPushRange = 500 ;
2016-04-02 15:50:49 +00:00
int32_t left = std : : max < int32_t > ( 0 , fx - iPushRange ) , right = std : : min < int32_t > ( GetWidth ( ) - 1 , fx + iPushRange ) ,
top = std : : max < int32_t > ( 0 , fy - iPushRange ) , bottom = std : : min < int32_t > ( GetHeight ( ) - 1 , fy + iPushRange ) ;
2011-05-31 01:04:38 +00:00
// Direction constants
const int8_t R = 0 , D = 1 , L = 2 , U = 3 ;
int8_t dir = 0 ;
int32_t x = fx , y = fy ;
// Get startpoint density
int32_t dens = GetDensity ( fx , fy ) ;
// Smaller density? We're done.
if ( dens < mdens )
return true ;
// Right density?
else if ( dens = = mdens )
{
// Find start point for border search
for ( int32_t i = 0 ; ; i + + )
if ( x - i - 1 < left | | GetDensity ( x - i - 1 , y ) ! = mdens )
2016-04-02 15:50:49 +00:00
{
x - = i ; dir = L ; break ;
}
2011-05-31 01:04:38 +00:00
else if ( y - i - 1 < top | | GetDensity ( x , y - i - 1 ) ! = mdens )
2016-04-02 15:50:49 +00:00
{
y - = i ; dir = U ; break ;
}
2011-05-31 01:04:38 +00:00
else if ( x + i + 1 > right | | GetDensity ( x + i + 1 , y ) ! = mdens )
2016-04-02 15:50:49 +00:00
{
x + = i ; dir = R ; break ;
}
2011-05-31 01:04:38 +00:00
else if ( y + i + 1 > bottom | | GetDensity ( x , y + i + 1 ) ! = mdens )
2016-04-02 15:50:49 +00:00
{
y + = i ; dir = D ; break ;
}
2011-05-31 01:04:38 +00:00
}
// Greater density
else
{
// Try to find a way out
int i = 1 ;
for ( ; i < iPushRange ; i + + )
if ( GetDensity ( x - i , y ) < = mdens )
2016-04-02 15:50:49 +00:00
{
x - = i ; dir = R ; break ;
}
2011-05-31 01:04:38 +00:00
else if ( GetDensity ( x , y - i ) < = mdens )
2016-04-02 15:50:49 +00:00
{
y - = i ; dir = D ; break ;
}
2011-05-31 01:04:38 +00:00
else if ( GetDensity ( x + i , y ) < = mdens )
2016-04-02 15:50:49 +00:00
{
x + = i ; dir = L ; break ;
}
2011-05-31 01:04:38 +00:00
else if ( GetDensity ( x , y + i ) < = mdens )
2016-04-02 15:50:49 +00:00
{
y + = i ; dir = U ; break ;
}
// Not found?
if ( i > = iPushRange ) return false ;
// Done?
if ( GetDensity ( x , y ) < mdens )
{
fx = x ; fy = y ;
return true ;
}
2011-05-31 01:04:38 +00:00
}
// Save startpoint of search
int32_t sx = x , sy = y , sdir = dir ;
// Best point so far
bool fGotBest = false ; int32_t bx = 0 , by = 0 , bdist = 0 ;
// Start searching
do
{
// We should always be in a material of same density
assert ( x > = left & & y > = top & & x < = right & & y < = bottom & & GetDensity ( x , y ) = = mdens ) ;
// Calc new position
int nx = x , ny = y ;
switch ( dir )
{
case R : nx + + ; break ;
case D : ny + + ; break ;
case L : nx - - ; break ;
case U : ny - - ; break ;
default : assert ( false ) ;
}
// In bounds?
bool fInBounds = ( nx > = left & & ny > = top & & nx < = right & & ny < = bottom ) ;
// Get density. Not this performs an SideOpen-check if outside landscape bounds.
int32_t dens = GetDensity ( nx , ny ) ;
// Flow possible?
if ( dens < mdens )
{
// Calculate "distance".
int32_t dist = Abs ( nx - fx ) + mslide * ( liquid ? fy - ny : Abs ( fy - ny ) ) ;
// New best point?
if ( ! fGotBest | | dist < bdist )
{
// Save it
bx = nx ; by = ny ; bdist = dist ; fGotBest = true ;
// Adjust borders: We can obviously safely ignore anything at greater distance
2015-11-15 12:53:01 +00:00
top = std : : max < int32_t > ( top , fy - dist / mslide - 1 ) ;
2011-05-31 01:04:38 +00:00
if ( ! liquid )
{
2015-11-15 12:53:01 +00:00
bottom = std : : min < int32_t > ( bottom , fy + dist / mslide + 1 ) ;
left = std : : max < int32_t > ( left , fx - dist - 1 ) ;
right = std : : min < int32_t > ( right , fx + dist + 1 ) ;
2011-05-31 01:04:38 +00:00
}
// Set new startpoint
sx = x ; sy = y ; sdir = dir ;
}
}
// Step?
if ( fInBounds & & dens = = mdens )
{
// New point
x = nx ; y = ny ;
// Turn left
( dir + = 3 ) % = 4 ;
}
// Otherwise: Turn right
else
2014-04-15 12:58:54 +00:00
{
+ + dir ;
dir % = 4 ;
}
2016-04-02 15:50:49 +00:00
} while ( x ! = sx | | y ! = sy | | dir ! = sdir ) ;
2011-05-31 01:04:38 +00:00
// Nothing found?
if ( ! fGotBest ) return false ;
// Return it
fx = bx ; fy = by ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-01-15 18:12:56 +00:00
int32_t C4Landscape : : AreaSolidCount ( int32_t x , int32_t y , int32_t wdt , int32_t hgt ) const
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t cx , cy , ascnt = 0 ;
for ( cy = y ; cy < y + hgt ; cy + + )
for ( cx = x ; cx < x + wdt ; cx + + )
if ( GBackSolid ( cx , cy ) )
2011-05-31 01:04:38 +00:00
ascnt + + ;
return ascnt ;
}
2015-05-01 16:04:42 +00:00
void C4Landscape : : FindMatTop ( int32_t mat , int32_t & x , int32_t & y , bool distant_first ) const
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
int32_t mslide , cslide , tslide , distant_x = 0 ;
bool fLeft , fRight ;
2011-05-31 01:04:38 +00:00
if ( ! MatValid ( mat ) ) return ;
2016-04-02 15:50:49 +00:00
mslide = : : MaterialMap . Map [ mat ] . MaxSlide ;
2011-05-31 01:04:38 +00:00
do
2010-03-28 18:58:01 +00:00
{
2015-05-01 16:04:42 +00:00
// Catch most common case: Walk upwards until material changes
2016-04-02 15:50:49 +00:00
while ( GetMat ( x , y - 1 ) = = mat ) - - y ;
2011-05-31 01:04:38 +00:00
// Find upwards slide
2016-04-02 15:50:49 +00:00
fLeft = true ; fRight = true ; tslide = 0 ; distant_x = x ;
for ( cslide = 1 ; ( cslide < = mslide ) & & ( fLeft | | fRight ) ; cslide + + )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// Left
if ( fLeft )
{
2016-04-02 15:50:49 +00:00
if ( GetMat ( x - cslide , y ) ! = mat ) fLeft = false ;
2015-05-01 16:04:42 +00:00
else
{
2016-04-02 15:50:49 +00:00
distant_x = x - cslide ;
if ( GetMat ( distant_x , y - 1 ) = = mat ) { tslide = - cslide ; break ; }
2015-05-01 16:04:42 +00:00
}
2011-05-31 01:04:38 +00:00
}
// Right
if ( fRight )
{
2016-04-02 15:50:49 +00:00
if ( GetMat ( x + cslide , y ) ! = mat ) fRight = false ;
2015-05-01 16:04:42 +00:00
else
{
2016-04-02 15:50:49 +00:00
distant_x = x + cslide ;
if ( GetMat ( distant_x , y - 1 ) = = mat ) { tslide = + cslide ; break ; }
2015-05-01 16:04:42 +00:00
}
2011-05-31 01:04:38 +00:00
}
2010-03-28 18:58:01 +00:00
}
2011-05-31 01:04:38 +00:00
// Slide
2016-04-02 15:50:49 +00:00
if ( tslide ) { x + = tslide ; y - - ; }
2011-05-31 01:04:38 +00:00
2016-04-02 15:50:49 +00:00
} while ( tslide ) ;
2011-05-31 01:04:38 +00:00
2015-05-01 16:04:42 +00:00
// return top pixel max slide away from center if desired
if ( distant_first ) x = distant_x ;
2010-03-28 18:58:01 +00:00
}
2011-05-31 01:04:38 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* ++++++++++++++ Editor mode (draw landscape with brush)+++++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
void C4Landscape : : SetMode ( LandscapeMode mode )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
p - > mode = mode ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
LandscapeMode C4Landscape : : GetMode ( ) const
{
return p - > mode ;
}
bool C4Landscape : : P : : GetMapColorIndex ( const char * szMaterial , const char * szTexture , BYTE & rbyCol ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Sky
2016-04-02 15:50:49 +00:00
if ( SEqual ( szMaterial , C4TLS_MatSky ) )
rbyCol = 0 ;
2009-05-08 13:28:41 +00:00
// Material-Texture
else
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
rbyCol = : : TextureMap . GetIndex ( szMaterial , szTexture ) ;
if ( ! rbyCol ) return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Found
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-07-15 02:37:12 +00:00
bool C4Landscape : : DrawBrush ( int32_t iX , int32_t iY , int32_t iGrade , const char * szMaterial , const char * szTexture , const char * szBackMaterial , const char * szBackTexture )
2010-03-28 18:58:01 +00:00
{
2015-07-15 02:37:12 +00:00
BYTE byCol , byColBkg ;
2011-07-16 19:50:49 +00:00
// Get map color index by material-texture
2016-04-02 15:50:49 +00:00
if ( ! p - > GetMapColorIndex ( szMaterial , szTexture , byCol ) ) return false ;
if ( ! p - > GetMapColorIndex ( szBackMaterial , szBackTexture , byColBkg ) ) return false ;
2011-07-16 19:50:49 +00:00
// Get material shape size
2015-10-09 04:11:53 +00:00
C4Texture * texture = : : TextureMap . GetTexture ( szTexture ) ;
2016-04-02 15:50:49 +00:00
int32_t shape_wdt = 0 , shape_hgt = 0 ;
2015-10-09 04:11:53 +00:00
if ( texture & & texture - > GetMaterialShape ( ) )
2011-07-16 19:50:49 +00:00
{
2016-04-02 15:50:49 +00:00
shape_wdt = texture - > GetMaterialShape ( ) - > GetMaxPolyWidth ( ) / p - > MapZoom ;
shape_hgt = texture - > GetMaterialShape ( ) - > GetMaxPolyHeight ( ) / p - > MapZoom ;
2011-07-16 19:50:49 +00:00
}
// Draw
2016-04-02 15:50:49 +00:00
switch ( p - > mode )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Dynamic: ignore
2016-04-02 15:50:49 +00:00
case LandscapeMode : : Dynamic :
2010-03-28 18:58:01 +00:00
break ;
2009-05-08 13:28:41 +00:00
// Static: draw to map by material-texture-index, chunk-o-zoom to landscape
2016-04-02 15:50:49 +00:00
case LandscapeMode : : Static :
{
// Draw to map
int32_t iRadius = std : : max < int32_t > ( 2 * iGrade / p - > MapZoom , 1 ) ;
if ( iRadius = = 1 )
{
p - > Map - > SetPix ( iX / p - > MapZoom , iY / p - > MapZoom , byCol ) ;
p - > MapBkg - > SetPix ( iX / p - > MapZoom , iY / p - > MapZoom , byColBkg ) ;
}
else
{
p - > Map - > Circle ( iX / p - > MapZoom , iY / p - > MapZoom , iRadius , byCol ) ;
p - > MapBkg - > Circle ( iX / p - > MapZoom , iY / p - > MapZoom , iRadius , byColBkg ) ;
}
// Update landscape
p - > MapToLandscape ( this , * p - > Map , * p - > MapBkg , iX / p - > MapZoom - iRadius - 1 - shape_wdt , iY / p - > MapZoom - iRadius - 1 - shape_hgt , 2 * iRadius + 2 + shape_wdt * 2 , 2 * iRadius + 2 + shape_hgt * 2 ) ;
SetMapChanged ( ) ;
}
2010-03-28 18:58:01 +00:00
break ;
2009-05-08 13:28:41 +00:00
// Exact: draw directly to landscape by color & pattern
2016-04-02 15:50:49 +00:00
case LandscapeMode : : Exact :
C4Rect BoundingBox ( iX - iGrade - 1 , iY - iGrade - 1 , iGrade * 2 + 2 , iGrade * 2 + 2 ) ;
2010-03-28 18:58:01 +00:00
// Draw to landscape
2016-04-02 15:50:49 +00:00
p - > PrepareChange ( this , BoundingBox ) ;
p - > Surface8 - > Circle ( iX , iY , iGrade , byCol ) ;
p - > Surface8Bkg - > Circle ( iX , iY , iGrade , byColBkg ) ;
p - > FinishChange ( this , BoundingBox ) ;
2010-03-28 18:58:01 +00:00
break ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : DrawLineLandscape ( int32_t iX , int32_t iY , int32_t iGrade , uint8_t line_color , uint8_t line_color_bkg )
2010-03-28 18:58:01 +00:00
{
2015-02-23 11:43:13 +00:00
Surface8 - > Circle ( iX , iY , iGrade , line_color ) ;
2015-06-22 22:56:04 +00:00
Surface8Bkg - > Circle ( iX , iY , iGrade , line_color_bkg ) ;
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : DrawLineMap ( int32_t iX , int32_t iY , int32_t iRadius , uint8_t line_color , uint8_t line_color_bkg )
2010-03-28 18:58:01 +00:00
{
2015-02-23 11:43:13 +00:00
if ( ! Map ) return false ;
if ( iRadius = = 1 )
2016-04-02 15:50:49 +00:00
{
Map - > SetPix ( iX , iY , line_color ) ; MapBkg - > SetPix ( iX , iY , line_color_bkg ) ;
}
2015-02-23 11:43:13 +00:00
else
2016-04-02 15:50:49 +00:00
{
Map - > Circle ( iX , iY , iRadius , line_color ) ; MapBkg - > Circle ( iX , iY , iRadius , line_color_bkg ) ;
}
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-07-15 02:37:12 +00:00
bool C4Landscape : : DrawLine ( int32_t iX1 , int32_t iY1 , int32_t iX2 , int32_t iY2 , int32_t iGrade , const char * szMaterial , const char * szTexture , const char * szBackMaterial , const char * szBackTexture )
2010-03-28 18:58:01 +00:00
{
2011-07-16 19:50:49 +00:00
// Get map color index by material-texture
2015-07-15 02:37:12 +00:00
uint8_t line_color , line_color_bkg ;
2016-04-02 15:50:49 +00:00
if ( ! p - > GetMapColorIndex ( szMaterial , szTexture , line_color ) ) return false ;
if ( ! p - > GetMapColorIndex ( szBackMaterial , szBackTexture , line_color_bkg ) ) return false ;
2011-07-16 19:50:49 +00:00
// Get material shape size
2015-10-09 04:11:53 +00:00
C4Texture * texture = : : TextureMap . GetTexture ( szTexture ) ;
int32_t shape_wdt = 0 , shape_hgt = 0 ;
if ( texture & & texture - > GetMaterialShape ( ) )
2011-07-16 19:50:49 +00:00
{
2016-04-02 15:50:49 +00:00
shape_wdt = texture - > GetMaterialShape ( ) - > GetMaxPolyWidth ( ) / p - > MapZoom ;
shape_hgt = texture - > GetMaterialShape ( ) - > GetMaxPolyHeight ( ) / p - > MapZoom ;
2011-07-16 19:50:49 +00:00
}
// Draw
2016-04-02 15:50:49 +00:00
switch ( p - > mode )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Dynamic: ignore
2016-04-02 15:50:49 +00:00
case LandscapeMode : : Dynamic :
2010-03-28 18:58:01 +00:00
break ;
2009-05-08 13:28:41 +00:00
// Static: draw to map by material-texture-index, chunk-o-zoom to landscape
2016-04-02 15:50:49 +00:00
case LandscapeMode : : Static :
{
// Draw to map
int32_t iRadius = std : : max < int32_t > ( 2 * iGrade / p - > MapZoom , 1 ) ;
iX1 / = p - > MapZoom ; iY1 / = p - > MapZoom ; iX2 / = p - > MapZoom ; iY2 / = p - > MapZoom ;
ForLine ( iX1 , iY1 , iX2 , iY2 , [ this , line_color , line_color_bkg , iRadius ] ( int32_t x , int32_t y ) { return p - > DrawLineMap ( x , y , iRadius , line_color , line_color_bkg ) ; } ) ;
// Update landscape
int iUpX = std : : min ( iX1 , iX2 ) - iRadius - 1 ;
int iUpY = std : : min ( iY1 , iY2 ) - iRadius - 1 ;
int iUpWdt = Abs ( iX2 - iX1 ) + 2 * iRadius + 2 ;
int iUpHgt = Abs ( iY2 - iY1 ) + 2 * iRadius + 2 ;
p - > MapToLandscape ( this , * p - > Map , * p - > MapBkg , iUpX - shape_wdt , iUpY - shape_hgt , iUpWdt + shape_wdt * 2 , iUpHgt + shape_hgt * 2 ) ;
SetMapChanged ( ) ;
}
2010-03-28 18:58:01 +00:00
break ;
2009-05-08 13:28:41 +00:00
// Exact: draw directly to landscape by color & pattern
2016-04-02 15:50:49 +00:00
case LandscapeMode : : Exact :
2010-03-28 18:58:01 +00:00
// Set texture pattern & get material color
2016-04-02 15:50:49 +00:00
C4Rect BoundingBox ( iX1 - iGrade , iY1 - iGrade , iGrade * 2 + 1 , iGrade * 2 + 1 ) ;
BoundingBox . Add ( C4Rect ( iX2 - iGrade , iY2 - iGrade , iGrade * 2 + 1 , iGrade * 2 + 1 ) ) ;
2010-03-28 18:58:01 +00:00
// Draw to landscape
2016-04-02 15:50:49 +00:00
p - > PrepareChange ( this , BoundingBox ) ;
ForLine ( iX1 , iY1 , iX2 , iY2 , [ this , line_color , line_color_bkg , iGrade ] ( int32_t x , int32_t y ) { return p - > DrawLineLandscape ( x , y , iGrade , line_color , line_color_bkg ) ; } ) ;
p - > FinishChange ( this , BoundingBox ) ;
2010-03-28 18:58:01 +00:00
break ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
2015-07-15 02:37:12 +00:00
bool C4Landscape : : DrawBox ( int32_t iX1 , int32_t iY1 , int32_t iX2 , int32_t iY2 , int32_t iGrade , const char * szMaterial , const char * szTexture , const char * szBackMaterial , const char * szBackTexture )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get upper-left/lower-right - corners
2016-04-02 15:50:49 +00:00
int32_t iX0 = std : : min ( iX1 , iX2 ) ; int32_t iY0 = std : : min ( iY1 , iY2 ) ;
iX2 = std : : max ( iX1 , iX2 ) ; iY2 = std : : max ( iY1 , iY2 ) ; iX1 = iX0 ; iY1 = iY0 ;
2015-07-15 02:37:12 +00:00
BYTE byCol , byColBkg ;
2011-07-16 19:50:49 +00:00
// Get map color index by material-texture
2016-04-02 15:50:49 +00:00
if ( ! p - > GetMapColorIndex ( szMaterial , szTexture , byCol ) ) return false ;
if ( ! p - > GetMapColorIndex ( szBackMaterial , szBackTexture , byColBkg ) ) return false ;
2011-07-16 19:50:49 +00:00
// Get material shape size
2015-10-09 04:11:53 +00:00
C4Texture * texture = : : TextureMap . GetTexture ( szTexture ) ;
int32_t shape_wdt = 0 , shape_hgt = 0 ;
if ( texture & & texture - > GetMaterialShape ( ) )
2011-07-16 19:50:49 +00:00
{
2016-04-02 15:50:49 +00:00
shape_wdt = texture - > GetMaterialShape ( ) - > GetMaxPolyWidth ( ) / p - > MapZoom ;
shape_hgt = texture - > GetMaterialShape ( ) - > GetMaxPolyHeight ( ) / p - > MapZoom ;
2011-07-16 19:50:49 +00:00
}
// Draw
2016-04-02 15:50:49 +00:00
switch ( p - > mode )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Dynamic: ignore
2016-04-02 15:50:49 +00:00
case LandscapeMode : : Dynamic :
2010-03-28 18:58:01 +00:00
break ;
2009-05-08 13:28:41 +00:00
// Static: draw to map by material-texture-index, chunk-o-zoom to landscape
2016-04-02 15:50:49 +00:00
case LandscapeMode : : Static :
2010-03-28 18:58:01 +00:00
// Draw to map
2016-04-02 15:50:49 +00:00
iX1 / = p - > MapZoom ; iY1 / = p - > MapZoom ; iX2 / = p - > MapZoom ; iY2 / = p - > MapZoom ;
p - > Map - > Box ( iX1 , iY1 , iX2 , iY2 , byCol ) ;
p - > MapBkg - > Box ( iX1 , iY1 , iX2 , iY2 , byColBkg ) ;
2010-03-28 18:58:01 +00:00
// Update landscape
2016-04-02 15:50:49 +00:00
p - > MapToLandscape ( this , * p - > Map , * p - > MapBkg , iX1 - 1 - shape_wdt , iY1 - 1 - shape_hgt , iX2 - iX1 + 3 + shape_wdt * 2 , iY2 - iY1 + 3 + shape_hgt * 2 ) ;
2010-03-28 18:58:01 +00:00
SetMapChanged ( ) ;
break ;
2009-05-08 13:28:41 +00:00
// Exact: draw directly to landscape by color & pattern
2016-04-02 15:50:49 +00:00
case LandscapeMode : : Exact :
C4Rect BoundingBox ( iX1 , iY1 , iX2 - iX1 + 1 , iY2 - iY1 + 1 ) ;
2010-03-28 18:58:01 +00:00
// Draw to landscape
2016-04-02 15:50:49 +00:00
p - > PrepareChange ( this , BoundingBox ) ;
p - > Surface8 - > Box ( iX1 , iY1 , iX2 , iY2 , byCol ) ;
p - > Surface8Bkg - > Box ( iX1 , iY1 , iX2 , iY2 , byColBkg ) ;
p - > FinishChange ( this , BoundingBox ) ;
2010-03-28 18:58:01 +00:00
break ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Landscape : : DrawChunks ( int32_t tx , int32_t ty , int32_t wdt , int32_t hgt , int32_t icntx , int32_t icnty , const char * szMaterial , const char * szTexture , bool bIFT )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
BYTE byColor ;
2016-04-02 15:50:49 +00:00
if ( ! p - > GetMapColorIndex ( szMaterial , szTexture , byColor ) ) return false ;
int32_t iMaterial = : : MaterialMap . Get ( szMaterial ) ;
if ( ! MatValid ( iMaterial ) )
return false ;
2009-05-08 13:28:41 +00:00
2013-01-20 11:51:33 +00:00
C4MaterialCoreShape shape = : : Game . C4S . Landscape . FlatChunkShapes ? C4M_Flat : : : MaterialMap . Map [ iMaterial ] . MapChunkType ;
2009-05-08 13:28:41 +00:00
C4Rect BoundingBox ( tx - 5 , ty - 5 , wdt + 10 , hgt + 10 ) ;
2016-04-02 15:50:49 +00:00
p - > PrepareChange ( this , BoundingBox ) ;
2009-05-08 13:28:41 +00:00
// assign clipper
2016-04-02 15:50:49 +00:00
p - > Surface8 - > Clip ( BoundingBox . x , BoundingBox . y , BoundingBox . x + BoundingBox . Wdt , BoundingBox . y + BoundingBox . Hgt ) ;
p - > Surface8Bkg - > Clip ( BoundingBox . x , BoundingBox . y , BoundingBox . x + BoundingBox . Wdt , BoundingBox . y + BoundingBox . Hgt ) ;
2011-10-03 14:30:18 +00:00
pDraw - > NoPrimaryClipper ( ) ;
2009-05-08 13:28:41 +00:00
// draw all chunks
int32_t x , y ;
2010-03-28 18:58:01 +00:00
for ( x = 0 ; x < icntx ; x + + )
for ( y = 0 ; y < icnty ; y + + )
2016-04-02 15:50:49 +00:00
p - > DrawChunk ( this , tx + wdt * x / icntx , ty + hgt * y / icnty , wdt / icntx , hgt / icnty , byColor , bIFT ? p - > DefaultBkgMat ( byColor ) : 0 , shape , Random ( 1000 ) ) ;
2009-05-08 13:28:41 +00:00
// remove clipper
2016-04-02 15:50:49 +00:00
p - > Surface8 - > NoClip ( ) ;
p - > Surface8Bkg - > NoClip ( ) ;
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
p - > FinishChange ( this , BoundingBox ) ;
2009-05-08 13:28:41 +00:00
// success
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-07-14 01:02:38 +00:00
bool C4Landscape : : DrawPolygon ( int * vtcs , int length , const char * szMaterial , const char * szBackMaterial , bool fDrawBridge )
2010-02-09 19:09:32 +00:00
{
2016-04-02 15:50:49 +00:00
if ( length < 6 ) return false ;
if ( length % 2 = = 1 ) return false ;
2009-05-08 13:28:41 +00:00
// get texture
2009-06-05 15:09:54 +00:00
int32_t iMatTex = : : TextureMap . GetIndexMatTex ( szMaterial ) ;
2010-03-28 18:58:01 +00:00
if ( ! iMatTex ) return false ;
2015-06-22 22:56:04 +00:00
uint8_t mcol = MatTex2PixCol ( iMatTex ) ;
2015-07-14 01:02:38 +00:00
// get background texture
uint8_t mcolBkg = 0 ;
if ( szBackMaterial ! = NULL )
{
const int32_t iBackMatTex = : : TextureMap . GetIndexMatTex ( szBackMaterial ) ;
if ( ! iBackMatTex ) return false ;
mcolBkg = MatTex2PixCol ( iBackMatTex ) ;
}
2010-02-09 19:09:32 +00:00
// do bridging?
uint8_t * conversion_map = NULL ;
if ( fDrawBridge )
{
2016-04-02 15:50:49 +00:00
conversion_map = p - > GetBridgeMatConversion ( this , MatTex2PixCol ( iMatTex ) ) ;
2015-08-05 03:15:52 +00:00
mcolBkg = Transparent ;
2010-02-09 19:09:32 +00:00
}
2011-05-29 20:37:40 +00:00
// prepare pixel count update
2016-04-02 15:50:49 +00:00
C4Rect BoundingBox = getBoundingBox ( vtcs , length ) ;
2011-05-29 20:37:40 +00:00
// draw polygon
2016-04-02 15:50:49 +00:00
p - > PrepareChange ( this , BoundingBox ) ;
p - > ForPolygon ( this , vtcs , length / 2 , NULL , NULL , mcol , mcolBkg , conversion_map ) ;
p - > FinishChange ( this , BoundingBox ) ;
2011-05-29 20:37:40 +00:00
return true ;
}
2016-04-02 15:50:49 +00:00
CStdPalette * C4Landscape : : GetPal ( ) const
{
return p - > Surface8 ? p - > Surface8 - > pPal : NULL ;
}
int32_t C4Landscape : : GetWidth ( ) const
{
return p - > Width ;
}
int32_t C4Landscape : : GetHeight ( ) const
{
return p - > Height ;
}
int32_t C4Landscape : : GetMapZoom ( ) const
{
return p - > MapZoom ;
}
C4Real C4Landscape : : GetGravity ( ) const
{
return p - > Gravity ;
}
void C4Landscape : : SetGravity ( C4Real g )
{
p - > Gravity = g ;
}
BYTE C4Landscape : : _GetPix ( int32_t x , int32_t y ) const
{
# ifdef _DEBUG
2016-04-10 07:48:42 +00:00
if ( x < 0 | | y < 0 | | x > = p - > Width | | y > = p - > Height ) { BREAKPOINT_HERE ; }
2016-04-02 15:50:49 +00:00
# endif
return p - > Surface8 - > _GetPix ( x , y ) ;
}
BYTE C4Landscape : : GetPix ( int32_t x , int32_t y ) const // get landscape pixel (bounds checked)
{
extern BYTE MCVehic ;
// Border checks
if ( x < 0 )
{
if ( y < p - > LeftOpen ) return 0 ;
else return MCVehic ;
}
if ( static_cast < uint32_t > ( x ) > = static_cast < uint32_t > ( p - > Width ) )
{
if ( y < p - > RightOpen ) return 0 ;
else return MCVehic ;
}
if ( y < 0 )
{
return p - > TopRowPix [ x ] ;
}
if ( static_cast < uint32_t > ( y ) > = static_cast < uint32_t > ( p - > Height ) )
{
return p - > BottomRowPix [ x ] ;
}
return p - > Surface8 - > _GetPix ( x , y ) ;
}
int32_t C4Landscape : : _GetMat ( int32_t x , int32_t y ) const
{
return p - > Pix2Mat [ _GetPix ( x , y ) ] ;
}
int32_t C4Landscape : : _GetDensity ( int32_t x , int32_t y ) const // get landscape density (bounds not checked)
{
return p - > Pix2Dens [ _GetPix ( x , y ) ] ;
}
int32_t C4Landscape : : _GetPlacement ( int32_t x , int32_t y ) const // get landscape material placement (bounds not checked)
{
return p - > Pix2Place [ _GetPix ( x , y ) ] ;
}
int32_t C4Landscape : : GetMat ( int32_t x , int32_t y ) const // get landscape material (bounds checked)
{
return p - > Pix2Mat [ GetPix ( x , y ) ] ;
}
int32_t C4Landscape : : GetDensity ( int32_t x , int32_t y ) const // get landscape density (bounds checked)
{
return p - > Pix2Dens [ GetPix ( x , y ) ] ;
}
int32_t C4Landscape : : GetPlacement ( int32_t x , int32_t y ) const // get landscape material placement (bounds checked)
{
return p - > Pix2Place [ GetPix ( x , y ) ] ;
}
BYTE C4Landscape : : _GetBackPix ( int32_t x , int32_t y ) const // get landscape pixel (bounds not checked)
{
# ifdef _DEBUG
2016-04-10 07:48:42 +00:00
if ( x < 0 | | y < 0 | | x > = p - > Width | | y > = p - > Height ) { BREAKPOINT_HERE ; }
2016-04-02 15:50:49 +00:00
# endif
return p - > Surface8Bkg - > _GetPix ( x , y ) ;
}
BYTE C4Landscape : : GetBackPix ( int32_t x , int32_t y ) const // get landscape pixel (bounds checked)
{
// Border checks
if ( x < 0 )
{
if ( y < p - > LeftOpen ) return 0 ;
else return Mat2PixColDefault ( MTunnel ) ;
}
if ( static_cast < uint32_t > ( x ) > = static_cast < uint32_t > ( GetWidth ( ) ) )
{
if ( y < p - > RightOpen ) return 0 ;
else return Mat2PixColDefault ( MTunnel ) ;
}
if ( y < 0 )
{
return p - > DefaultBkgMat ( p - > TopRowPix [ x ] ) ;
}
if ( static_cast < uint32_t > ( y ) > = static_cast < uint32_t > ( GetHeight ( ) ) )
{
return p - > DefaultBkgMat ( p - > BottomRowPix [ x ] ) ;
}
return p - > Surface8Bkg - > _GetPix ( x , y ) ;
}
int32_t C4Landscape : : _GetBackMat ( int32_t x , int32_t y ) const // get landscape material (bounds not checked)
{
return p - > Pix2Mat [ _GetBackPix ( x , y ) ] ;
}
int32_t C4Landscape : : _GetBackDensity ( int32_t x , int32_t y ) const // get landscape density (bounds not checked)
{
return p - > Pix2Dens [ _GetBackPix ( x , y ) ] ;
}
int32_t C4Landscape : : _GetBackPlacement ( int32_t x , int32_t y ) const // get landscape material placement (bounds not checked)
{
return p - > Pix2Place [ _GetBackPix ( x , y ) ] ;
}
int32_t C4Landscape : : GetBackMat ( int32_t x , int32_t y ) const // get landscape material (bounds checked)
{
return p - > Pix2Mat [ GetBackPix ( x , y ) ] ;
}
int32_t C4Landscape : : GetBackDensity ( int32_t x , int32_t y ) const // get landscape density (bounds checked)
{
return p - > Pix2Dens [ GetBackPix ( x , y ) ] ;
}
int32_t C4Landscape : : GetBackPlacement ( int32_t x , int32_t y ) const // get landscape material placement (bounds checked)
{
return p - > Pix2Place [ GetBackPix ( x , y ) ] ;
}
bool C4Landscape : : GetLight ( int32_t x , int32_t y )
{
return GetBackPix ( x , y ) = = 0 | | p - > Pix2Light [ GetPix ( x , y ) ] ;
}
bool C4Landscape : : _GetLight ( int32_t x , int32_t y )
{
return _GetBackPix ( x , y ) = = 0 | | p - > Pix2Light [ _GetPix ( x , y ) ] ;
}
bool C4Landscape : : _FastSolidCheck ( int32_t x , int32_t y ) const // checks whether there *might* be something solid at the point
{
return p - > PixCnt [ ( x / 17 ) * p - > PixCntPitch + ( y / 15 ) ] > 0 ;
}
int32_t C4Landscape : : FastSolidCheckNextX ( int32_t x )
{
return ( x / 17 ) * 17 + 17 ;
}
int32_t C4Landscape : : GetPixMat ( BYTE byPix ) const { return p - > Pix2Mat [ byPix ] ; }
int32_t C4Landscape : : GetPixDensity ( BYTE byPix ) const { return p - > Pix2Dens [ byPix ] ; }
bool C4Landscape : : _PathFree ( int32_t x , int32_t y , int32_t x2 , int32_t y2 ) const
{
x / = 17 ; y / = 15 ; x2 / = 17 ; y2 / = 15 ;
while ( x ! = x2 & & y ! = y2 )
{
if ( p - > PixCnt [ x * p - > PixCntPitch + y ] )
return false ;
if ( x > x2 ) x - - ; else x + + ;
if ( y > y2 ) y - - ; else y + + ;
}
if ( x ! = x2 )
do
{
if ( p - > PixCnt [ x * p - > PixCntPitch + y ] )
return false ;
if ( x > x2 ) x - - ; else x + + ;
} while ( x ! = x2 ) ;
else
while ( y ! = y2 )
{
if ( p - > PixCnt [ x * p - > PixCntPitch + y ] )
return false ;
if ( y > y2 ) y - - ; else y + + ;
}
return ! p - > PixCnt [ x * p - > PixCntPitch + y ] ;
}
uint8_t * C4Landscape : : P : : GetBridgeMatConversion ( const C4Landscape * d , int32_t for_material_col ) const
2011-05-31 01:04:38 +00:00
{
// safety
2016-04-02 15:50:49 +00:00
int32_t for_material = d - > GetPixMat ( for_material_col ) ;
2011-05-31 01:04:38 +00:00
if ( for_material < 0 | | for_material > = MaterialMap . Num ) return NULL ;
// query map. create if not done yet
2016-04-02 15:50:49 +00:00
if ( ! BridgeMatConversion [ for_material_col ] )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
auto conv_map = std : : make_unique < uint8_t [ ] > ( C4M_MaxTexIndex ) ;
for ( int32_t i = 0 ; i < C4M_MaxTexIndex ; + + i )
2011-05-31 01:04:38 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ( MatDensity ( for_material ) > = d - > GetPixDensity ( i ) ) )
2011-05-31 01:04:38 +00:00
{
2015-06-22 22:56:04 +00:00
// bridge pixel OK here. change pixel.
conv_map [ i ] = for_material_col ;
2011-05-31 01:04:38 +00:00
}
else
{
// bridge pixel not OK - keep current pixel
conv_map [ i ] = i ;
}
}
2016-04-02 15:50:49 +00:00
BridgeMatConversion [ for_material_col ] = std : : move ( conv_map ) ;
2011-05-31 01:04:38 +00:00
}
2016-04-02 15:50:49 +00:00
return BridgeMatConversion [ for_material_col ] . get ( ) ;
2011-05-31 01:04:38 +00:00
}
2015-07-14 01:02:38 +00:00
bool C4Landscape : : DrawQuad ( int32_t iX1 , int32_t iY1 , int32_t iX2 , int32_t iY2 , int32_t iX3 , int32_t iY3 , int32_t iX4 , int32_t iY4 , const char * szMaterial , const char * szBackMaterial , bool fDrawBridge )
2011-05-29 20:37:40 +00:00
{
2009-05-08 13:28:41 +00:00
// set vertices
2011-05-29 20:37:40 +00:00
int32_t vtcs [ 8 ] ;
2009-05-08 13:28:41 +00:00
vtcs [ 0 ] = iX1 ; vtcs [ 1 ] = iY1 ;
vtcs [ 2 ] = iX2 ; vtcs [ 3 ] = iY2 ;
vtcs [ 4 ] = iX3 ; vtcs [ 5 ] = iY3 ;
vtcs [ 6 ] = iX4 ; vtcs [ 7 ] = iY4 ;
2015-07-14 01:02:38 +00:00
return DrawPolygon ( vtcs , 8 , szMaterial , szBackMaterial , fDrawBridge ) ;
2010-02-09 19:09:32 +00:00
}
2009-05-08 13:28:41 +00:00
2015-01-15 18:12:56 +00:00
BYTE C4Landscape : : GetMapIndex ( int32_t iX , int32_t iY ) const
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
if ( ! p - > Map ) return 0 ;
return p - > Map - > GetPix ( iX , iY ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-07-01 01:58:42 +00:00
BYTE C4Landscape : : GetBackMapIndex ( int32_t iX , int32_t iY ) const
{
2016-04-02 15:50:49 +00:00
if ( ! p - > MapBkg ) return 0 ;
return p - > MapBkg - > GetPix ( iX , iY ) ;
2015-07-01 01:58:42 +00:00
}
2016-04-02 15:50:49 +00:00
void C4Landscape : : P : : PrepareChange ( const C4Landscape * d , const C4Rect & BoundingBox )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// move solidmasks out of the way
C4Rect SolidMaskRect = BoundingBox ;
if ( pLandscapeRender )
SolidMaskRect = pLandscapeRender - > GetAffectedRect ( pLandscapeRender - > GetAffectedRect ( SolidMaskRect ) ) ;
for ( C4SolidMask * pSolid = C4SolidMask : : Last ; pSolid ; pSolid = pSolid - > Prev )
{
pSolid - > RemoveTemporary ( SolidMaskRect ) ;
}
2016-04-02 15:50:49 +00:00
UpdateMatCnt ( d , BoundingBox , false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
void C4Landscape : : P : : FinishChange ( C4Landscape * d , C4Rect BoundingBox )
2010-03-28 18:58:01 +00:00
{
2015-01-06 10:47:25 +00:00
// Intersect bounding box with landscape
BoundingBox . Intersect ( C4Rect ( 0 , 0 , Width , Height ) ) ;
2015-01-25 17:23:43 +00:00
if ( ! BoundingBox . Wdt | | ! BoundingBox . Hgt ) return ;
2011-05-31 01:04:38 +00:00
// update render
2016-04-02 15:50:49 +00:00
if ( pLandscapeRender )
pLandscapeRender - > Update ( BoundingBox , d ) ;
UpdateMatCnt ( d , BoundingBox , true ) ;
2011-05-31 01:04:38 +00:00
// Restore Solidmasks
C4Rect SolidMaskRect = BoundingBox ;
if ( pLandscapeRender )
SolidMaskRect = pLandscapeRender - > GetAffectedRect ( pLandscapeRender - > GetAffectedRect ( SolidMaskRect ) ) ;
for ( C4SolidMask * pSolid = C4SolidMask : : First ; pSolid ; pSolid = pSolid - > Next )
2009-05-08 13:28:41 +00:00
{
2011-05-31 01:04:38 +00:00
pSolid - > Repair ( SolidMaskRect ) ;
2010-03-27 16:05:02 +00:00
}
2011-05-31 01:04:38 +00:00
C4SolidMask : : CheckConsistency ( ) ;
2016-04-02 15:50:49 +00:00
UpdatePixCnt ( d , BoundingBox ) ;
2012-08-19 18:35:10 +00:00
// update FoW
if ( pFoW )
2014-11-18 20:42:00 +00:00
{
2012-08-19 18:35:10 +00:00
pFoW - > Invalidate ( BoundingBox ) ;
2016-04-02 15:50:49 +00:00
pFoW - > Ambient . UpdateFromLandscape ( * d , BoundingBox ) ;
2014-11-18 20:42:00 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* ++++++++++++++++++ Functions for Script interface +++++++++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2012-02-10 20:48:48 +00:00
bool C4Landscape : : DrawMap ( int32_t iX , int32_t iY , int32_t iWdt , int32_t iHgt , const char * szMapDef , bool ignoreSky )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
2009-08-15 18:50:32 +00:00
if ( ! szMapDef ) return false ;
2009-05-08 13:28:41 +00:00
// clip to landscape size
2009-08-15 18:50:32 +00:00
if ( ! ClipRect ( iX , iY , iWdt , iHgt ) ) return false ;
2009-05-08 13:28:41 +00:00
// get needed map size
2016-04-02 15:50:49 +00:00
int32_t iMapWdt = ( iWdt - 1 ) / p - > MapZoom + 1 ;
int32_t iMapHgt = ( iHgt - 1 ) / p - > MapZoom + 1 ;
C4SLandscape FakeLS = Game . C4S . Landscape ;
2009-05-08 13:28:41 +00:00
FakeLS . MapWdt . Set ( iMapWdt , 0 , iMapWdt , iMapWdt ) ;
FakeLS . MapHgt . Set ( iMapHgt , 0 , iMapHgt , iMapHgt ) ;
// create map creator
2009-06-05 18:46:03 +00:00
C4MapCreatorS2 MapCreator ( & FakeLS , & : : TextureMap , & : : MaterialMap , Game . StartupPlayerCount ) ;
2009-05-08 13:28:41 +00:00
// read file
MapCreator . ReadScript ( szMapDef ) ;
// render map
2015-07-01 00:29:52 +00:00
CSurface8 * sfcMap = NULL ;
CSurface8 * sfcMapBkg = NULL ;
if ( ! MapCreator . Render ( NULL , sfcMap , sfcMapBkg ) )
return false ;
2009-05-08 13:28:41 +00:00
// map it to the landscape
2016-04-02 15:50:49 +00:00
bool fSuccess = p - > MapToLandscape ( this , * sfcMap , * sfcMapBkg , 0 , 0 , iMapWdt , iMapHgt , iX , iY , ignoreSky ) ;
2009-05-08 13:28:41 +00:00
// cleanup
delete sfcMap ;
2015-07-01 00:29:52 +00:00
delete sfcMapBkg ;
2009-05-08 13:28:41 +00:00
// return whether successful
return fSuccess ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2012-02-10 20:48:48 +00:00
bool C4Landscape : : DrawDefMap ( int32_t iX , int32_t iY , int32_t iWdt , int32_t iHgt , const char * szMapDef , bool ignoreSky )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
2016-04-02 15:50:49 +00:00
if ( ! szMapDef | | ! p - > pMapCreator ) return false ;
2009-05-08 13:28:41 +00:00
// clip to landscape size
2009-08-15 18:50:32 +00:00
if ( ! ClipRect ( iX , iY , iWdt , iHgt ) ) return false ;
2009-05-08 13:28:41 +00:00
// get needed map size
2016-04-02 15:50:49 +00:00
int32_t iMapWdt = ( iWdt - 1 ) / p - > MapZoom + 1 ;
int32_t iMapHgt = ( iHgt - 1 ) / p - > MapZoom + 1 ;
bool fSuccess = false ;
2009-05-08 13:28:41 +00:00
// render map
2016-04-02 15:50:49 +00:00
C4MCMap * pMap = p - > pMapCreator - > GetMap ( szMapDef ) ;
2009-08-15 18:50:32 +00:00
if ( ! pMap ) return false ;
2009-05-08 13:28:41 +00:00
pMap - > SetSize ( iMapWdt , iMapHgt ) ;
2015-07-01 00:29:52 +00:00
CSurface8 * sfcMap = NULL ;
CSurface8 * sfcMapBkg = NULL ;
2016-04-02 15:50:49 +00:00
if ( p - > pMapCreator - > Render ( szMapDef , sfcMap , sfcMapBkg ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// map to landscape
2016-04-02 15:50:49 +00:00
fSuccess = p - > MapToLandscape ( this , * sfcMap , * sfcMapBkg , 0 , 0 , iMapWdt , iMapHgt , iX , iY , ignoreSky ) ;
2009-05-08 13:28:41 +00:00
// cleanup
delete sfcMap ;
2015-07-01 00:29:52 +00:00
delete sfcMapBkg ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// done
return fSuccess ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
// creates and draws a map section using MapCreatorS2 and a map from the loaded Landscape.txt
bool C4Landscape : : SetModulation ( DWORD dwWithClr ) // adjust the way the landscape is blitted
{
p - > Modulation = dwWithClr ;
return true ;
}
DWORD C4Landscape : : GetModulation ( ) const { return p - > Modulation ; }
2015-01-15 18:12:56 +00:00
bool C4Landscape : : ClipRect ( int32_t & rX , int32_t & rY , int32_t & rWdt , int32_t & rHgt ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// clip by bounds
2016-04-02 15:50:49 +00:00
if ( rX < 0 ) { rWdt + = rX ; rX = 0 ; }
if ( rY < 0 ) { rHgt + = rY ; rY = 0 ; }
2009-05-08 13:28:41 +00:00
int32_t iOver ;
2016-04-02 15:50:49 +00:00
iOver = rX + rWdt - GetWidth ( ) ;
if ( iOver > 0 )
rWdt - = iOver ;
iOver = rY + rHgt - GetHeight ( ) ;
if ( iOver > 0 )
rHgt - = iOver ;
2009-05-08 13:28:41 +00:00
// anything left inside the bounds?
2016-04-02 15:50:49 +00:00
return rWdt > 0 & & rHgt > 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Landscape : : ReplaceMapColor ( BYTE iOldIndex , BYTE iNewIndex )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// find every occurance of iOldIndex in map; replace it by new index
2016-04-02 15:50:49 +00:00
if ( ! p - > Map ) return false ;
2009-05-08 13:28:41 +00:00
int iPitch , iMapWdt , iMapHgt ;
2016-04-02 15:50:49 +00:00
BYTE * pMap = p - > Map - > Bits ;
iMapWdt = p - > Map - > Wdt ;
iMapHgt = p - > Map - > Hgt ;
iPitch = p - > Map - > Pitch ;
2009-05-08 13:28:41 +00:00
if ( ! pMap ) return false ;
2016-04-02 15:50:49 +00:00
for ( int32_t y = 0 ; y < iMapHgt ; + + y )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
for ( int32_t x = 0 ; x < iMapWdt ; + + x )
2010-03-28 18:58:01 +00:00
{
2015-06-22 22:56:04 +00:00
if ( * pMap = = iOldIndex )
* pMap = iNewIndex ;
2009-05-08 13:28:41 +00:00
+ + pMap ;
}
2010-03-28 18:58:01 +00:00
pMap + = iPitch - iMapWdt ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Landscape : : SetTextureIndex ( const char * szMatTex , BYTE iNewIndex , bool fInsert )
2010-03-28 18:58:01 +00:00
{
2015-06-22 22:56:04 +00:00
if ( ( ( ! szMatTex | | ! * szMatTex ) & & ! fInsert ) | | ! Inside < int > ( iNewIndex , 1 , C4M_MaxTexIndex - 1 ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
DebugLogF ( " Cannot insert new texture %s to index %d: Invalid parameters. " , ( const char * ) szMatTex , ( int ) iNewIndex ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// get last mat index - returns zero for not found (valid for insertion mode)
StdStrBuf Material , Texture ;
Material . CopyUntil ( szMatTex , ' - ' ) ; Texture . Copy ( SSearch ( szMatTex , " - " ) ) ;
2009-08-15 18:50:32 +00:00
BYTE iOldIndex = ( szMatTex & & * szMatTex ) ? : : TextureMap . GetIndex ( Material . getData ( ) , Texture . getData ( ) , false ) : 0 ;
2009-05-08 13:28:41 +00:00
// insertion mode?
if ( fInsert )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// there must be room to move up to
BYTE byLastMoveIndex = C4M_MaxTexIndex - 1 ;
2009-06-05 15:09:54 +00:00
while ( : : TextureMap . GetEntry ( byLastMoveIndex ) )
2009-05-08 13:28:41 +00:00
if ( - - byLastMoveIndex = = iNewIndex )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
DebugLogF ( " Cannot insert new texture %s to index %d: No room for insertion. " , ( const char * ) szMatTex , ( int ) iNewIndex ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// then move up all other textures first
// could do this in one loop, but it's just a developement call anyway, so move one index at a time
while ( - - byLastMoveIndex > = iNewIndex )
2009-06-05 15:09:54 +00:00
if ( : : TextureMap . GetEntry ( byLastMoveIndex ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
ReplaceMapColor ( byLastMoveIndex , byLastMoveIndex + 1 ) ;
: : TextureMap . MoveIndex ( byLastMoveIndex , byLastMoveIndex + 1 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// new insertion desired?
if ( szMatTex & & * szMatTex )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// move from old or create new
if ( iOldIndex )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
ReplaceMapColor ( iOldIndex , iNewIndex ) ;
2009-06-05 15:09:54 +00:00
: : TextureMap . MoveIndex ( iOldIndex , iNewIndex ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
StdStrBuf Material , Texture ;
Material . CopyUntil ( szMatTex , ' - ' ) ; Texture . Copy ( SSearch ( szMatTex , " - " ) ) ;
// new insertion
2009-06-05 15:09:54 +00:00
if ( ! : : TextureMap . AddEntry ( iNewIndex , Material . getData ( ) , Texture . getData ( ) ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
LogF ( " Cannot insert new texture %s to index %d: Texture map entry error " , ( const char * ) szMatTex , ( int ) iNewIndex ) ;
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// done, success
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// new index must not be occupied
const C4TexMapEntry * pOld ;
2009-06-05 15:09:54 +00:00
if ( ( pOld = : : TextureMap . GetEntry ( iNewIndex ) ) & & ! pOld - > isNull ( ) )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
DebugLogF ( " Cannot move texture %s to index %d: Index occupied by %s-%s. " , ( const char * ) szMatTex , ( int ) iNewIndex , pOld - > GetMaterialName ( ) , pOld - > GetTextureName ( ) ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// must only move existing textures
if ( ! iOldIndex )
2010-03-28 18:58:01 +00:00
{
2016-04-02 15:50:49 +00:00
DebugLogF ( " Cannot move texture %s to index %d: Texture not found. " , ( const char * ) szMatTex , ( int ) iNewIndex ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// update map
ReplaceMapColor ( iOldIndex , iNewIndex ) ;
// change to new index in texmap
2009-06-05 15:09:54 +00:00
: : TextureMap . MoveIndex ( iOldIndex , iNewIndex ) ;
2009-05-08 13:28:41 +00:00
// done, success
2009-08-15 18:50:32 +00:00
return true ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
// change color index of map texture, or insert a new one
void C4Landscape : : SetMapChanged ( ) { p - > fMapChanged = true ; }
2011-05-31 01:04:38 +00:00
void C4Landscape : : RemoveUnusedTexMapEntries ( )
{
// check usage in landscape
2015-06-22 22:56:04 +00:00
bool fTexUsage [ C4M_MaxTexIndex ] ;
2011-05-31 01:04:38 +00:00
int32_t iMatTex ;
2015-06-22 22:56:04 +00:00
for ( iMatTex = 0 ; iMatTex < C4M_MaxTexIndex ; + + iMatTex )
fTexUsage [ iMatTex ] = false ;
2016-04-02 15:50:49 +00:00
for ( int32_t y = 0 ; y < GetHeight ( ) ; + + y )
for ( int32_t x = 0 ; x < GetWidth ( ) ; + + x )
2015-06-17 00:58:43 +00:00
{
2016-04-02 15:50:49 +00:00
const BYTE pix = p - > Surface8 - > GetPix ( x , y ) ;
const BYTE backPix = p - > Surface8Bkg - > GetPix ( x , y ) ;
2015-06-22 22:56:04 +00:00
assert ( pix < C4M_MaxTexIndex ) ;
assert ( backPix < C4M_MaxTexIndex ) ;
fTexUsage [ pix ] = true ;
fTexUsage [ backPix ] = true ;
2015-06-17 00:58:43 +00:00
}
2011-05-31 01:04:38 +00:00
// check usage by materials
for ( int32_t iMat = 0 ; iMat < : : MaterialMap . Num ; + + iMat )
{
C4Material * pMat = : : MaterialMap . Map + iMat ;
2015-06-22 22:56:04 +00:00
if ( pMat - > BlastShiftTo > = 0 ) fTexUsage [ pMat - > BlastShiftTo ] = true ;
if ( pMat - > BelowTempConvertTo > = 0 ) fTexUsage [ pMat - > BelowTempConvertTo ] = true ;
if ( pMat - > AboveTempConvertTo > = 0 ) fTexUsage [ pMat - > AboveTempConvertTo ] = true ;
if ( pMat - > DefaultMatTex > = 0 ) fTexUsage [ pMat - > DefaultMatTex ] = true ;
2011-05-31 01:04:38 +00:00
}
// remove unused
for ( iMatTex = 1 ; iMatTex < C4M_MaxTexIndex ; + + iMatTex )
if ( ! fTexUsage [ iMatTex ] )
: : TextureMap . RemoveEntry ( iMatTex ) ;
// flag rewrite
: : TextureMap . fEntriesAdded = true ;
}
2016-04-02 15:50:49 +00:00
C4Sky & C4Landscape : : GetSky ( )
{
return p - > Sky ;
}
bool C4Landscape : : HasFoW ( ) const
{
return p - > pFoW ! = nullptr ;
}
C4FoW * C4Landscape : : GetFoW ( )
{
return p - > pFoW . get ( ) ;
}
int32_t C4Landscape : : GetMatCount ( int material ) const
{
assert ( material > 0 & & material < p - > MatCount . size ( ) ) ;
return p - > MatCount [ material ] ;
}
int32_t C4Landscape : : GetEffectiveMatCount ( int material ) const
{
assert ( material > 0 & & material < p - > EffectiveMatCount . size ( ) ) ;
return p - > EffectiveMatCount [ material ] ;
}
2011-05-31 01:04:38 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* +++++++++++++++++++++++++++ Update functions ++++++++++++++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2009-05-08 13:28:41 +00:00
void C4Landscape : : HandleTexMapUpdate ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Pixel maps must be update
UpdatePixMaps ( ) ;
// Update landscape palette
2016-04-02 15:50:49 +00:00
p - > Mat2Pal ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Landscape : : UpdatePixMaps ( )
2010-02-09 19:09:32 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t i ;
2016-04-02 15:50:49 +00:00
for ( i = 0 ; i < C4M_MaxTexIndex ; i + + ) p - > Pix2Mat [ i ] = PixCol2Mat ( i ) ;
for ( i = 0 ; i < C4M_MaxTexIndex ; i + + ) p - > Pix2Dens [ i ] = MatDensity ( p - > Pix2Mat [ i ] ) ;
for ( i = 0 ; i < C4M_MaxTexIndex ; i + + ) p - > Pix2Place [ i ] = MatValid ( p - > Pix2Mat [ i ] ) ? : : MaterialMap . Map [ p - > Pix2Mat [ i ] ] . Placement : 0 ;
for ( i = 0 ; i < C4M_MaxTexIndex ; i + + ) p - > Pix2Light [ i ] = MatValid ( p - > Pix2Mat [ i ] ) & & ( : : MaterialMap . Map [ p - > Pix2Mat [ i ] ] . Light > 0 ) ;
p - > Pix2Place [ 0 ] = 0 ;
2010-02-09 19:09:32 +00:00
// clear bridge mat conversion buffers
2016-04-02 15:50:49 +00:00
std : : fill ( p - > BridgeMatConversion . begin ( ) , p - > BridgeMatConversion . end ( ) , nullptr ) ;
2010-02-09 19:09:32 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
bool C4Landscape : : P : : Mat2Pal ( )
2010-03-28 18:58:01 +00:00
{
2015-06-17 00:58:43 +00:00
if ( ! Surface8 | | ! Surface8Bkg ) return false ;
2009-05-08 13:28:41 +00:00
// set landscape pal
2012-12-22 23:11:08 +00:00
int32_t tex ;
2016-04-02 15:50:49 +00:00
for ( tex = 0 ; tex < C4M_MaxTexIndex ; tex + + )
2010-03-28 18:58:01 +00:00
{
2009-06-05 15:09:54 +00:00
const C4TexMapEntry * pTex = : : TextureMap . GetEntry ( tex ) ;
2010-03-28 18:58:01 +00:00
if ( ! pTex | | pTex - > isNull ( ) )
2009-05-08 13:28:41 +00:00
continue ;
// colors
2009-07-24 21:50:04 +00:00
DWORD dwPix = pTex - > GetPattern ( ) . PatternClr ( 0 , 0 ) ;
2012-08-15 22:45:27 +00:00
Surface8 - > pPal - > Colors [ MatTex2PixCol ( tex ) ] = dwPix ;
2015-06-17 00:58:43 +00:00
Surface8Bkg - > pPal - > Colors [ MatTex2PixCol ( tex ) ] = dwPix ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// success
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
void C4Landscape : : P : : UpdatePixCnt ( const C4Landscape * d , const C4Rect & Rect , bool fCheck )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t PixCntWidth = ( Width + 16 ) / 17 ;
2015-11-15 12:53:01 +00:00
for ( int32_t y = std : : max < int32_t > ( 0 , Rect . y / 15 ) ; y < std : : min < int32_t > ( PixCntPitch , ( Rect . y + Rect . Hgt + 14 ) / 15 ) ; y + + )
for ( int32_t x = std : : max < int32_t > ( 0 , Rect . x / 17 ) ; x < std : : min < int32_t > ( PixCntWidth , ( Rect . x + Rect . Wdt + 16 ) / 17 ) ; x + + )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int iCnt = 0 ;
2015-11-15 12:53:01 +00:00
for ( int32_t x2 = x * 17 ; x2 < std : : min < int32_t > ( x * 17 + 17 , Width ) ; x2 + + )
for ( int32_t y2 = y * 15 ; y2 < std : : min < int32_t > ( y * 15 + 15 , Height ) ; y2 + + )
2016-04-02 15:50:49 +00:00
if ( d - > _GetDensity ( x2 , y2 ) )
2009-05-08 13:28:41 +00:00
iCnt + + ;
2010-03-28 18:58:01 +00:00
if ( fCheck )
2009-05-08 13:28:41 +00:00
assert ( iCnt = = PixCnt [ x * PixCntPitch + y ] ) ;
PixCnt [ x * PixCntPitch + y ] = iCnt ;
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
2016-04-02 15:50:49 +00:00
void C4Landscape : : P : : UpdateMatCnt ( const C4Landscape * d , C4Rect Rect , bool fPlus )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
Rect . Intersect ( C4Rect ( 0 , 0 , Width , Height ) ) ;
2010-03-28 18:58:01 +00:00
if ( ! Rect . Hgt | | ! Rect . Wdt ) return ;
2010-03-27 16:05:02 +00:00
// Multiplicator for changes
const int32_t iMul = fPlus ? + 1 : - 1 ;
// Count pixels
2010-03-28 18:58:01 +00:00
for ( int32_t x = 0 ; x < Rect . Wdt ; x + + )
{
2010-03-27 16:05:02 +00:00
int iHgt = 0 ;
2010-03-28 18:58:01 +00:00
int32_t y ;
for ( y = 1 ; y < Rect . Hgt ; y + + )
{
2016-04-02 15:50:49 +00:00
int32_t iMat = d - > _GetMat ( Rect . x + x , Rect . y + y - 1 ) ;
2010-03-27 16:05:02 +00:00
// Same material? Count it.
2016-04-02 15:50:49 +00:00
if ( iMat = = d - > _GetMat ( Rect . x + x , Rect . y + y ) )
2010-03-27 16:05:02 +00:00
iHgt + + ;
else
2010-03-28 18:58:01 +00:00
{
if ( iMat > = 0 )
2010-03-27 16:05:02 +00:00
{
// Normal material counting
MatCount [ iMat ] + = iMul * ( iHgt + 1 ) ;
// Effective material counting enabled?
2010-03-28 18:58:01 +00:00
if ( int32_t iMinHgt = : : MaterialMap . Map [ iMat ] . MinHeightCount )
{
2010-03-27 16:05:02 +00:00
// First chunk? Add any material above when checking chunk height
int iAddedHeight = 0 ;
2010-03-28 18:58:01 +00:00
if ( Rect . y & & iHgt + 1 = = y )
2016-04-02 15:50:49 +00:00
iAddedHeight = d - > GetMatHeight ( Rect . x + x , Rect . y - 1 , - 1 , iMat , iMinHgt ) ;
2010-03-27 16:05:02 +00:00
// Check the chunk height
2010-03-28 18:58:01 +00:00
if ( iHgt + 1 + iAddedHeight > = iMinHgt )
{
2010-03-27 16:05:02 +00:00
EffectiveMatCount [ iMat ] + = iMul * ( iHgt + 1 ) ;
2010-03-28 18:58:01 +00:00
if ( iAddedHeight < iMinHgt )
2010-03-27 16:05:02 +00:00
EffectiveMatCount [ iMat ] + = iMul * iAddedHeight ;
}
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Next chunk of material
iHgt = 0 ;
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Check last pixel
2016-04-02 15:50:49 +00:00
int32_t iMat = d - > _GetMat ( Rect . x + x , Rect . y + Rect . Hgt - 1 ) ;
2010-03-28 18:58:01 +00:00
if ( iMat > = 0 )
{
2010-03-27 16:05:02 +00:00
// Normal material counting
MatCount [ iMat ] + = iMul * ( iHgt + 1 ) ;
// Minimum height counting?
2010-03-28 18:58:01 +00:00
if ( int32_t iMinHgt = : : MaterialMap . Map [ iMat ] . MinHeightCount )
{
2010-03-27 16:05:02 +00:00
int iAddedHeight1 = 0 , iAddedHeight2 = 0 ;
// Add any material above for chunk size check
2010-03-28 18:58:01 +00:00
if ( Rect . y & & iHgt + 1 = = Rect . Hgt )
2016-04-02 15:50:49 +00:00
iAddedHeight1 = d - > GetMatHeight ( Rect . x + x , Rect . y - 1 , - 1 , iMat , iMinHgt ) ;
2010-03-27 16:05:02 +00:00
// Add any material below for chunk size check
2016-04-02 15:50:49 +00:00
if ( Rect . y + y < Height )
iAddedHeight2 = d - > GetMatHeight ( Rect . x + x , Rect . y + Rect . Hgt , 1 , iMat , iMinHgt ) ;
2010-03-27 16:05:02 +00:00
// Chunk tall enough?
2010-03-28 18:58:01 +00:00
if ( iHgt + 1 + iAddedHeight1 + iAddedHeight2 > = : : MaterialMap . Map [ iMat ] . MinHeightCount )
{
2010-03-27 16:05:02 +00:00
EffectiveMatCount [ iMat ] + = iMul * ( iHgt + 1 ) ;
2010-03-28 18:58:01 +00:00
if ( iAddedHeight1 < iMinHgt )
2010-03-27 16:05:02 +00:00
EffectiveMatCount [ iMat ] + = iMul * iAddedHeight1 ;
2010-03-28 18:58:01 +00:00
if ( iAddedHeight2 < iMinHgt )
2010-03-27 16:05:02 +00:00
EffectiveMatCount [ iMat ] + = iMul * iAddedHeight2 ;
}
}
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-06-05 15:20:41 +00:00
C4Landscape Landscape ;