2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2009-06-05 13:41:20 +00:00
* Copyright ( c ) 1998 - 2000 , 2007 Matthes Bender
2011-09-01 14:58:52 +00:00
* Copyright ( c ) 2001 - 2002 , 2005 - 2007 , 2011 Sven Eberhardt
2009-06-05 13:41:20 +00:00
* Copyright ( c ) 2006 - 2007 Peter Wortmann
2013-01-09 23:23:06 +00:00
* Copyright ( c ) 2006 - 2007 , 2009 , 2011 - 2012 G ü nther Brammer
2011-09-01 14:58:52 +00:00
* Copyright ( c ) 2010 - 2011 Nicolas Hake
2013-01-09 23:23:06 +00:00
* Copyright ( c ) 2012 Armin Burgmeier
2009-05-08 13:28:41 +00:00
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk .
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
* See isc_license . txt for full license and disclaimer .
*
* " Clonk " is a registered trademark of Matthes Bender .
* See clonk_trademark_license . txt for full license .
*/
/* Material definitions used by the landscape */
# include <C4Include.h>
# include <C4Material.h>
# include <C4Components.h>
# include <C4Group.h>
2009-06-05 18:00:23 +00:00
# include <C4PXS.h>
2009-05-08 13:28:41 +00:00
# include <C4Random.h>
# include <C4ToolsDlg.h> // For C4TLS_MatSky...
2009-06-12 18:52:21 +00:00
# include <C4Texture.h>
# include <C4Aul.h>
# include <C4Landscape.h>
# include <C4SoundSystem.h>
2012-04-27 17:04:43 +00:00
# include <C4Effect.h>
2009-06-12 18:52:21 +00:00
# include <C4Log.h>
2009-05-08 13:28:41 +00:00
# include <C4Physics.h> // For GravAccel
2011-01-08 17:21:46 +00:00
int32_t MVehic = MNone , MTunnel = MNone , MWater = MNone , MEarth = MNone ;
2009-06-12 18:52:21 +00:00
BYTE MCVehic = 0 ;
2009-05-08 13:28:41 +00:00
// -------------------------------------- C4MaterialReaction
struct ReactionFuncMapEntry { const char * szRFName ; C4MaterialReactionFunc pFunc ; } ;
2010-03-28 18:58:01 +00:00
const ReactionFuncMapEntry ReactionFuncMap [ ] =
{
2009-05-08 13:28:41 +00:00
{ " Script " , & C4MaterialMap : : mrfScript } ,
{ " Convert " , & C4MaterialMap : : mrfConvert } ,
{ " Poof " , & C4MaterialMap : : mrfPoof } ,
{ " Corrode " , & C4MaterialMap : : mrfCorrode } ,
{ " Insert " , & C4MaterialMap : : mrfInsert } ,
2010-03-28 18:58:01 +00:00
{ NULL , & C4MaterialReaction : : NoReaction }
} ;
2009-05-08 13:28:41 +00:00
void C4MaterialReaction : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pComp - > isCompiler ( ) ) pScriptFunc = NULL ;
// compile reaction func ptr
StdStrBuf sReactionFuncName ;
int32_t i = 0 ; while ( ReactionFuncMap [ i ] . szRFName & & ( ReactionFuncMap [ i ] . pFunc ! = pFunc ) ) + + i ;
sReactionFuncName = ReactionFuncMap [ i ] . szRFName ;
2012-12-16 17:52:32 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sReactionFuncName , StdCompiler : : RCT_IdtfAllowEmpty ) , " Type " , StdCopyStrBuf ( ) ) ) ;
2009-05-08 13:28:41 +00:00
i = 0 ; while ( ReactionFuncMap [ i ] . szRFName & & ! SEqual ( ReactionFuncMap [ i ] . szRFName , sReactionFuncName . getData ( ) ) ) + + i ;
pFunc = ReactionFuncMap [ i ] . pFunc ;
// compile the rest
2012-12-16 17:52:32 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( TargetSpec , StdCompiler : : RCT_All ) , " TargetSpec " , StdCopyStrBuf ( ) ) ) ;
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( ScriptFunc , StdCompiler : : RCT_IdtfAllowEmpty ) , " ScriptFunc " , StdCopyStrBuf ( ) ) ) ;
2009-05-08 13:28:41 +00:00
pComp - > Value ( mkNamingAdapt ( iExecMask , " ExecMask " , ~ 0u ) ) ;
pComp - > Value ( mkNamingAdapt ( fReverse , " Reverse " , false ) ) ;
pComp - > Value ( mkNamingAdapt ( fInverseSpec , " InverseSpec " , false ) ) ;
pComp - > Value ( mkNamingAdapt ( fInsertionCheck , " CheckSlide " , true ) ) ;
pComp - > Value ( mkNamingAdapt ( iDepth , " Depth " , 0 ) ) ;
2012-12-16 17:52:32 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sConvertMat , StdCompiler : : RCT_IdtfAllowEmpty ) , " ConvertMat " , StdCopyStrBuf ( ) ) ) ;
2009-05-08 13:28:41 +00:00
pComp - > Value ( mkNamingAdapt ( iCorrosionRate , " CorrosionRate " , 100 ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MaterialReaction : : ResolveScriptFuncs ( const char * szMatName )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get script func for script-defined behaviour
if ( pFunc = = & C4MaterialMap : : mrfScript )
2011-10-15 00:11:57 +00:00
{
pScriptFunc = : : ScriptEngine . GetPropList ( ) - > GetFunc ( this - > ScriptFunc . getData ( ) ) ;
if ( ! pScriptFunc )
DebugLogF ( " Error getting function \" %s \" for Material reaction of \" %s \" " , this - > ScriptFunc . getData ( ) , szMatName ) ;
}
2009-05-08 13:28:41 +00:00
else
pScriptFunc = NULL ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-07-16 19:50:49 +00:00
// -------------------------------------- C4MaterialShape
C4MaterialShape : : C4MaterialShape ( ) : prepared_for_zoom ( 0 )
{
wdt = hgt = overlap_left = overlap_top = overlap_right = overlap_bottom = 0 ;
max_poly_width = max_poly_height = 0 ;
}
bool C4MaterialShape : : Load ( C4Group & group , const char * filename )
{
// Material shapes: Currently, shapes are loaded as a list polygons derived from vectorizing a binary image
// In the future, vectorization of the image could be put directly into the engine (if we get a free* library to do it)
// load file contents into buffer
StdStrBuf source ;
if ( ! group . LoadEntryString ( filename , & source ) ) return false ;
// parse buffer
StdStrBuf name = group . GetFullName ( ) + DirSep + filename ;
if ( ! CompileFromBuf_LogWarn < StdCompilerINIRead > ( * this , source , name . getData ( ) ) ) return false ;
// Compute shape centers/mins/maxs and maximum overlap
max_poly_width = max_poly_height = 0 ;
overlap_left = 0 ; overlap_top = 0 ; overlap_right = 0 ; overlap_bottom = 0 ;
for ( PolyVec : : iterator i = polys . begin ( ) ; i ! = polys . end ( ) ; + + i )
{
int32_t n = 0 ; Pt center ( 0 , 0 ) , min ( 0 , 0 ) , max ( 0 , 0 ) ;
for ( Poly : : iterator j = i - > begin ( ) ; j ! = i - > end ( ) ; + + j )
{
center . x + = j - > x ; center . y + = j - > y ;
if ( n + + )
{
min . x = Min ( min . x , j - > x ) ; max . x = Max ( max . x , j - > x ) ;
min . y = Min ( min . y , j - > y ) ; max . y = Max ( max . y , j - > y ) ;
}
else
{
min = max = * j ;
}
if ( j - > x < - overlap_left ) overlap_left = - j - > x ;
if ( j - > y < - overlap_top ) overlap_top = - j - > y ;
if ( j - > x > wdt + overlap_right ) overlap_right = j - > x - wdt ;
if ( j - > y > hgt + overlap_bottom ) overlap_bottom = j - > y - hgt ;
}
center . x / = n ; center . y / = n ;
i - > center = center ; i - > min = min ; i - > max = max ;
max_poly_width = Max ( max_poly_width , max . x - min . x ) ;
max_poly_height = Max ( max_poly_height , max . y - min . y ) ;
}
// Overlap data not calculated yet
prepared_for_zoom = 0 ;
return true ;
}
void C4MaterialShape : : CompileFunc ( StdCompiler * comp )
{
if ( comp - > Name ( " Shape " ) )
{
comp - > Value ( mkNamingAdapt ( wdt , " Width " ) ) ;
comp - > Value ( mkNamingAdapt ( hgt , " Height " ) ) ;
comp - > Value ( mkNamingAdapt ( mkSTLContainerAdapt ( polys , StdCompiler : : SEP_SEP2 ) , " Shape " ) ) ;
comp - > NameEnd ( ) ;
}
}
bool C4MaterialShape : : DoPrepareForZoom ( int32_t zoom )
{
// calculate map pixel overlaps from polygons
// only works if shape size is a multiple of the map zoom!
if ( ( wdt % zoom ) | | ( hgt % zoom ) ) return false ;
for ( PolyVec : : iterator i = polys . begin ( ) ; i ! = polys . end ( ) ; + + i )
i - > PrepareForZoom ( zoom ) ;
// done; mark cache for zoom
prepared_for_zoom = zoom ;
return true ;
}
void C4MaterialShape : : Poly : : CompileFunc ( StdCompiler * comp )
{
comp - > Value ( mkSTLContainerAdapt ( * this , StdCompiler : : SEP_SEP ) ) ;
}
void C4MaterialShape : : Poly : : PrepareForZoom ( int32_t zoom )
{
overlaps . clear ( ) ;
// center is always contained and always first in list (for IFT)
Pt center_map ( center . x / zoom , center . y / zoom ) ;
overlaps . push_back ( center_map ) ;
// walk from min to max; check if center or some corner point is in poly and add if this is the case
for ( int32_t y = min . y / zoom ; y < = max . y / zoom ; + + y )
for ( int32_t x = min . x / zoom ; x < = max . x / zoom ; + + x )
if ( x ! = center_map . x | | y ! = center_map . y )
for ( int32_t ty = 0 ; ty < = zoom ; ty + = 3 )
for ( int32_t tx = 0 ; tx < = zoom ; tx + = 3 )
if ( IsPtContained ( x * zoom + tx , y * zoom + ty ) )
{
overlaps . push_back ( Pt ( x , y ) ) ;
tx = zoom + 1 ; break ;
}
}
bool C4MaterialShape : : Poly : : IsPtContained ( int32_t x , int32_t y ) const
{
// point is contained if it crosses an off number of borders
int crossings = 0 ;
for ( size_t i = 0 ; i < size ( ) ; + + i )
{
Pt pt1 = ( * this ) [ i ] ;
Pt pt2 = ( * this ) [ ( i + 1 ) % size ( ) ] ;
if ( ( pt1 . y < y ) ! = ( pt2 . y < y ) ) // crossing vertically?
{
// does line pt1-pt2 intersecti line (x,y)-(inf,y)?
crossings + = ( ( pt1 . x - ( pt1 . y - y ) * ( pt2 . x - pt1 . x ) / ( pt2 . y - pt1 . y ) ) > x ) ;
}
}
return ( crossings % 2 ) = = 1 ;
}
void C4MaterialShape : : Pt : : CompileFunc ( StdCompiler * comp )
{
comp - > Value ( x ) ;
comp - > Separator ( ) ;
comp - > Value ( y ) ;
}
2009-05-08 13:28:41 +00:00
// -------------------------------------- C4MaterialCore
C4MaterialCore : : C4MaterialCore ( )
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
void C4MaterialCore : : Clear ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
CustomReactionList . clear ( ) ;
sTextureOverlay . Clear ( ) ;
sPXSGfx . Clear ( ) ;
sBlastShiftTo . Clear ( ) ;
sInMatConvert . Clear ( ) ;
sInMatConvertTo . Clear ( ) ;
sBelowTempConvertTo . Clear ( ) ;
sAboveTempConvertTo . Clear ( ) ;
* Name = ' \0 ' ;
2011-09-07 12:25:32 +00:00
MapChunkType = C4M_Flat ;
2011-07-16 19:50:49 +00:00
ShapeTexture . Clear ( ) ;
2009-05-08 13:28:41 +00:00
Density = 0 ;
Friction = 0 ;
DigFree = 0 ;
BlastFree = 0 ;
2010-01-25 03:14:52 +00:00
Dig2Object = C4ID : : None ;
2009-05-08 13:28:41 +00:00
Dig2ObjectRatio = 0 ;
2011-08-20 14:43:58 +00:00
Dig2ObjectCollect = 0 ;
2010-01-25 03:14:52 +00:00
Blast2Object = C4ID : : None ;
2009-05-08 13:28:41 +00:00
Blast2ObjectRatio = 0 ;
Blast2PXSRatio = 0 ;
Instable = 0 ;
MaxAirSpeed = 0 ;
MaxSlide = 0 ;
WindDrift = 0 ;
Inflammable = 0 ;
Incindiary = 0 ;
Extinguisher = 0 ;
Corrosive = 0 ;
Corrode = 0 ;
Soil = 0 ;
Placement = 0 ;
OverlayType = 0 ;
PXSGfxRt . Default ( ) ;
PXSGfxSize = 0 ;
InMatConvertDepth = 0 ;
BelowTempConvert = 0 ;
BelowTempConvertDir = 0 ;
AboveTempConvert = 0 ;
AboveTempConvertDir = 0 ;
ColorAnimation = 0 ;
TempConvStrength = 0 ;
MinHeightCount = 0 ;
2010-03-27 16:05:02 +00:00
SplashRate = 10 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MaterialCore : : Default ( )
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
2009-08-15 18:50:32 +00:00
bool C4MaterialCore : : Load ( C4Group & hGroup ,
2010-03-28 18:58:01 +00:00
const char * szEntryName )
{
2009-05-08 13:28:41 +00:00
StdStrBuf Source ;
2011-03-05 01:44:26 +00:00
if ( ! hGroup . LoadEntryString ( szEntryName , & Source ) )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
StdStrBuf Name = hGroup . GetFullName ( ) + DirSep + szEntryName ;
2010-03-28 18:58:01 +00:00
if ( ! CompileFromBuf_LogWarn < StdCompilerINIRead > ( * this , Source , Name . getData ( ) ) )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// adjust placement, if not specified
if ( ! Placement )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( DensitySolid ( Density ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Placement = 30 ;
if ( ! DigFree ) Placement + = 20 ;
if ( ! BlastFree ) Placement + = 10 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if ( DensityLiquid ( Density ) )
Placement = 10 ;
else Placement = 5 ;
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
void C4MaterialCore : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pComp - > isCompiler ( ) ) Clear ( ) ;
pComp - > Name ( " Material " ) ;
2011-09-07 12:25:32 +00:00
pComp - > Value ( mkNamingAdapt ( toC4CStr ( Name ) , " Name " , " " ) ) ;
pComp - > Value ( mkNamingAdapt ( ColorAnimation , " ColorAnimation " , 0 ) ) ;
const StdEnumEntry < C4MaterialCoreShape > Shapes [ ] =
{
{ " Flat " , C4M_Flat } ,
{ " TopFlat " , C4M_TopFlat } ,
{ " Smooth " , C4M_Smooth } ,
{ " Rough " , C4M_Rough } ,
{ " Octagon " , C4M_Octagon } ,
{ " Smoother " , C4M_Smoother } ,
{ NULL , C4M_Flat }
} ;
pComp - > Value ( mkNamingAdapt ( mkEnumAdaptT < uint8_t > ( MapChunkType , Shapes ) ,
" Shape " , C4M_Flat ) ) ;
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( ShapeTexture , StdCompiler : : RCT_All ) ,
" ShapeTexture " , " " ) ) ;
pComp - > Value ( mkNamingAdapt ( Density , " Density " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Friction , " Friction " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( DigFree , " DigFree " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( BlastFree , " BlastFree " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Blast2Object , " Blast2Object " , C4ID : : None ) ) ;
pComp - > Value ( mkNamingAdapt ( Dig2Object , " Dig2Object " , C4ID : : None ) ) ;
pComp - > Value ( mkNamingAdapt ( Dig2ObjectRatio , " Dig2ObjectRatio " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Dig2ObjectCollect , " Dig2ObjectCollect " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Blast2ObjectRatio , " Blast2ObjectRatio " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Blast2PXSRatio , " Blast2PXSRatio " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Instable , " Instable " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( MaxAirSpeed , " MaxAirSpeed " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( MaxSlide , " MaxSlide " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( WindDrift , " WindDrift " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Inflammable , " Inflammable " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Incindiary , " Incindiary " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Corrode , " Corrode " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Corrosive , " Corrosive " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Extinguisher , " Extinguisher " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Soil , " Soil " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( Placement , " Placement " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sTextureOverlay , StdCompiler : : RCT_IdtfAllowEmpty ) ,
" TextureOverlay " , " " ) ) ;
pComp - > Value ( mkNamingAdapt ( OverlayType , " OverlayType " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sPXSGfx , StdCompiler : : RCT_IdtfAllowEmpty ) ,
" PXSGfx " , " " ) ) ;
pComp - > Value ( mkNamingAdapt ( PXSGfxRt , " PXSGfxRt " , TargetRect0 ) ) ;
pComp - > Value ( mkNamingAdapt ( PXSGfxSize , " PXSGfxSize " , PXSGfxRt . Wdt ) ) ;
pComp - > Value ( mkNamingAdapt ( TempConvStrength , " TempConvStrength " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sBlastShiftTo , StdCompiler : : RCT_IdtfAllowEmpty ) ,
" BlastShiftTo " , " " ) ) ;
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sInMatConvert , StdCompiler : : RCT_IdtfAllowEmpty ) ,
" InMatConvert " , " " ) ) ;
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sInMatConvertTo , StdCompiler : : RCT_IdtfAllowEmpty ) ,
" InMatConvertTo " , " " ) ) ;
pComp - > Value ( mkNamingAdapt ( InMatConvertDepth , " InMatConvertDepth " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( AboveTempConvert , " AboveTempConvert " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( AboveTempConvertDir , " AboveTempConvertDir " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sAboveTempConvertTo , StdCompiler : : RCT_IdtfAllowEmpty ) ,
" AboveTempConvertTo " , " " ) ) ;
pComp - > Value ( mkNamingAdapt ( BelowTempConvert , " BelowTempConvert " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( BelowTempConvertDir , " BelowTempConvertDir " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sBelowTempConvertTo , StdCompiler : : RCT_IdtfAllowEmpty ) ,
" BelowTempConvertTo " , " " ) ) ;
pComp - > Value ( mkNamingAdapt ( MinHeightCount , " MinHeightCount " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( SplashRate , " SplashRate " , 10 ) ) ;
2009-05-08 13:28:41 +00:00
pComp - > NameEnd ( ) ;
// material reactions
2011-09-07 12:25:32 +00:00
pComp - > Value ( mkNamingAdapt ( mkSTLContainerAdapt ( CustomReactionList ) ,
" Reaction " , std : : vector < C4MaterialReaction > ( ) ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// -------------------------------------- C4Material
C4Material : : C4Material ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
BlastShiftTo = 0 ;
InMatConvertTo = MNone ;
BelowTempConvertTo = 0 ;
AboveTempConvertTo = 0 ;
2011-07-16 19:50:49 +00:00
CustomShape = NULL ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Material : : UpdateScriptPointers ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
for ( uint32_t i = 0 ; i < CustomReactionList . size ( ) ; + + i )
CustomReactionList [ i ] . ResolveScriptFuncs ( Name ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// -------------------------------------- C4MaterialMap
C4MaterialMap : : C4MaterialMap ( ) : DefReactConvert ( & mrfConvert ) , DefReactPoof ( & mrfPoof ) , DefReactCorrode ( & mrfCorrode ) , DefReactIncinerate ( & mrfIncinerate ) , DefReactInsert ( & mrfInsert )
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
C4MaterialMap : : ~ C4MaterialMap ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
Clear ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MaterialMap : : Clear ( )
2010-03-28 18:58:01 +00:00
{
2010-12-04 03:31:25 +00:00
if ( Map ) delete [ ] Map ; Map = NULL ; Num = 0 ;
2009-05-08 13:28:41 +00:00
delete [ ] ppReactionMap ; ppReactionMap = NULL ;
2011-07-16 19:50:49 +00:00
Shapes . clear ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-09-21 04:00:57 +00:00
int32_t C4MaterialMap : : Load ( C4Group & hGroup )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
char entryname [ 256 + 1 ] ;
2010-03-27 16:05:02 +00:00
// Determine number of materials in files
int32_t mat_num = hGroup . EntryCount ( C4CFN_MaterialFiles ) ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Allocate new map
2009-05-08 13:28:41 +00:00
C4Material * pNewMap = new C4Material [ mat_num + Num ] ;
2010-03-28 18:58:01 +00:00
if ( ! pNewMap ) return 0 ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Load material cores to map
hGroup . ResetSearch ( ) ; int32_t cnt = 0 ;
2009-05-08 13:28:41 +00:00
while ( hGroup . FindNextEntry ( C4CFN_MaterialFiles , entryname ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Load mat
if ( ! pNewMap [ cnt ] . Load ( hGroup , entryname ) )
{ delete [ ] pNewMap ; return 0 ; }
// A new material?
2010-03-28 18:58:01 +00:00
if ( Get ( pNewMap [ cnt ] . Name ) = = MNone )
2009-05-08 13:28:41 +00:00
cnt + + ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Take over old materials.
2010-03-28 18:58:01 +00:00
for ( int32_t i = 0 ; i < Num ; i + + )
{
2009-05-08 13:28:41 +00:00
pNewMap [ cnt + i ] = Map [ i ] ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
delete [ ] Map ;
Map = pNewMap ;
// set material number
Num + = cnt ;
2011-07-16 19:50:49 +00:00
// Load material shapes
hGroup . ResetSearch ( ) ;
while ( hGroup . FindNextEntry ( C4CFN_MaterialShapeFiles , entryname ) )
{
C4MaterialShape shape ;
if ( shape . Load ( hGroup , entryname ) )
{
Shapes [ StdCopyStrBuf ( entryname ) ] = shape ;
}
else
{
DebugLogF ( " Error loading material shape %s from %s. " , entryname , hGroup . GetFullName ( ) . getData ( ) ) ;
}
}
2010-03-27 16:05:02 +00:00
return cnt ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4MaterialMap : : HasMaterials ( C4Group & hGroup ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
return ! ! hGroup . EntryCount ( C4CFN_MaterialFiles ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
int32_t C4MaterialMap : : Get ( const char * szMaterial )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int32_t cnt ;
for ( cnt = 0 ; cnt < Num ; cnt + + )
if ( SEqualNoCase ( szMaterial , Map [ cnt ] . Name ) )
return cnt ;
return MNone ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2013-01-08 22:41:20 +00:00
bool C4MaterialMap : : CrossMapMaterials ( const char * szEarthMaterial ) // Called after load
2010-03-28 18:58:01 +00:00
{
2009-06-12 18:52:21 +00:00
// Check material number
if ( : : MaterialMap . Num > C4MaxMaterial )
{ LogFatal ( LoadResStr ( " IDS_PRC_TOOMANYMATS " ) ) ; return false ; }
2009-05-08 13:28:41 +00:00
// build reaction function map
delete [ ] ppReactionMap ;
typedef C4MaterialReaction * C4MaterialReactionPtr ;
ppReactionMap = new C4MaterialReactionPtr [ ( Num + 1 ) * ( Num + 1 ) ] ;
for ( int32_t iMatPXS = - 1 ; iMatPXS < Num ; iMatPXS + + )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Material * pMatPXS = ( iMatPXS + 1 ) ? Map + iMatPXS : NULL ;
for ( int32_t iMatLS = - 1 ; iMatLS < Num ; iMatLS + + )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4MaterialReaction * pReaction = NULL ;
C4Material * pMatLS = ( iMatLS + 1 ) ? Map + iMatLS : NULL ;
// natural stuff: material conversion here?
if ( pMatPXS & & pMatPXS - > sInMatConvert . getLength ( ) & & SEqualNoCase ( pMatPXS - > sInMatConvert . getData ( ) , pMatLS ? pMatLS - > Name : C4TLS_MatSky ) )
pReaction = & DefReactConvert ;
// the rest is happening for same/higher densities only
else if ( ( MatDensity ( iMatPXS ) < = MatDensity ( iMatLS ) ) & & pMatPXS & & pMatLS )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// incindiary vs extinguisher
if ( ( pMatPXS - > Incindiary & & pMatLS - > Extinguisher ) | | ( pMatPXS - > Extinguisher & & pMatLS - > Incindiary ) )
pReaction = & DefReactPoof ;
// incindiary vs inflammable
else if ( ( pMatPXS - > Incindiary & & pMatLS - > Inflammable ) | | ( pMatPXS - > Inflammable & & pMatLS - > Incindiary ) )
pReaction = & DefReactIncinerate ;
// corrosive vs corrode
else if ( pMatPXS - > Corrosive & & pMatLS - > Corrode )
pReaction = & DefReactCorrode ;
// otherwise, when hitting same or higher density: Material insertion
else
pReaction = & DefReactInsert ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// assign the function; or NULL for no reaction
SetMatReaction ( iMatPXS , iMatLS , pReaction ) ;
}
2010-03-28 18:58:01 +00:00
}
2011-07-16 19:50:49 +00:00
// reset max shape size
max_shape_width = max_shape_height = 0 ;
2009-05-08 13:28:41 +00:00
// material-specific initialization
int32_t cnt ;
for ( cnt = 0 ; cnt < Num ; cnt + + )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4Material * pMat = Map + cnt ;
const char * szTextureOverlay = NULL ;
// newgfx: init pattern
if ( Map [ cnt ] . sTextureOverlay . getLength ( ) )
2009-06-05 15:09:54 +00:00
if ( : : TextureMap . GetTexture ( Map [ cnt ] . sTextureOverlay . getLength ( ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
szTextureOverlay = Map [ cnt ] . sTextureOverlay . getData ( ) ;
// backwards compatibility: if a pattern was specified although the no-pattern flag was set, overwrite that flag
if ( Map [ cnt ] . OverlayType & C4MatOv_None )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
DebugLogF ( " Error in overlay of material %s: Flag C4MatOv_None ignored because a custom overlay (%s) was specified! " , Map [ cnt ] . Name , szTextureOverlay ) ;
Map [ cnt ] . OverlayType & = ~ C4MatOv_None ;
}
2010-03-28 18:58:01 +00:00
}
2011-08-27 16:10:31 +00:00
// default to first texture in texture map
int iTexMapIx ;
if ( ! szTextureOverlay & & ( iTexMapIx = : : TextureMap . GetIndex ( Map [ cnt ] . Name , NULL , false ) ) )
szTextureOverlay = TextureMap . GetEntry ( iTexMapIx ) - > GetTextureName ( ) ;
2009-05-08 13:28:41 +00:00
// default to smooth
if ( ! szTextureOverlay )
2011-08-29 21:41:41 +00:00
szTextureOverlay = " none " ;
2009-05-08 13:28:41 +00:00
// search/create entry in texmap
2009-08-15 18:50:32 +00:00
Map [ cnt ] . DefaultMatTex = : : TextureMap . GetIndex ( Map [ cnt ] . Name , szTextureOverlay , true ,
2010-03-28 18:58:01 +00:00
FormatString ( " DefaultMatTex of mat %s " , Map [ cnt ] . Name ) . getData ( ) ) ;
2009-05-08 13:28:41 +00:00
// init PXS facet
2011-10-03 14:07:07 +00:00
C4Surface * sfcTexture ;
2009-05-08 13:28:41 +00:00
C4Texture * Texture ;
if ( Map [ cnt ] . sPXSGfx . getLength ( ) )
2010-01-25 04:00:59 +00:00
if ( ( Texture = : : TextureMap . GetTexture ( Map [ cnt ] . sPXSGfx . getData ( ) ) ) )
if ( ( sfcTexture = Texture - > Surface32 ) )
2009-05-08 13:28:41 +00:00
Map [ cnt ] . PXSFace . Set ( sfcTexture , Map [ cnt ] . PXSGfxRt . x , Map [ cnt ] . PXSGfxRt . y , Map [ cnt ] . PXSGfxRt . Wdt , Map [ cnt ] . PXSGfxRt . Hgt ) ;
2011-07-16 19:50:49 +00:00
// init shape
if ( Map [ cnt ] . ShapeTexture . getLength ( ) )
{
C4MaterialShape * shape = GetShapeByName ( Map [ cnt ] . ShapeTexture . getData ( ) ) ;
Map [ cnt ] . CustomShape = shape ;
if ( ! shape )
{
DebugLogF ( " Custom shape texture (%s) for material %s not found! " , Map [ cnt ] . ShapeTexture . getData ( ) , Map [ cnt ] . Name ) ;
}
else
{
// adjust max shape overlap
max_shape_width = Max ( max_shape_width , shape - > max_poly_width ) ;
max_shape_height = Max ( max_shape_height , shape - > max_poly_height ) ;
}
}
else
Map [ cnt ] . CustomShape = NULL ;
2009-05-08 13:28:41 +00:00
// evaluate reactions for that material
for ( unsigned int iRCnt = 0 ; iRCnt < pMat - > CustomReactionList . size ( ) ; + + iRCnt )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4MaterialReaction * pReact = & ( pMat - > CustomReactionList [ iRCnt ] ) ;
if ( pReact - > sConvertMat . getLength ( ) ) pReact - > iConvertMat = Get ( pReact - > sConvertMat . getData ( ) ) ; else pReact - > iConvertMat = - 1 ;
// evaluate target spec
int32_t tmat ;
if ( MatValid ( tmat = Get ( pReact - > TargetSpec . getData ( ) ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// single material target
if ( pReact - > fInverseSpec )
for ( int32_t cnt2 = - 1 ; cnt2 < Num ; cnt2 + + ) if ( cnt2 ! = tmat ) SetMatReaction ( cnt , cnt2 , pReact ) ;
2010-03-28 18:58:01 +00:00
else
SetMatReaction ( cnt , tmat , pReact ) ;
}
2009-05-08 13:28:41 +00:00
else if ( SEqualNoCase ( pReact - > TargetSpec . getData ( ) , " All " ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// add to all materials, including sky
if ( ! pReact - > fInverseSpec ) for ( int32_t cnt2 = - 1 ; cnt2 < Num ; cnt2 + + ) SetMatReaction ( cnt , cnt2 , pReact ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if ( SEqualNoCase ( pReact - > TargetSpec . getData ( ) , " Solid " ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// add to all solid materials
if ( pReact - > fInverseSpec ) SetMatReaction ( cnt , - 1 , pReact ) ;
for ( int32_t cnt2 = 0 ; cnt2 < Num ; cnt2 + + ) if ( DensitySolid ( Map [ cnt2 ] . Density ) ! = pReact - > fInverseSpec ) SetMatReaction ( cnt , cnt2 , pReact ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if ( SEqualNoCase ( pReact - > TargetSpec . getData ( ) , " SemiSolid " ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// add to all semisolid materials
if ( pReact - > fInverseSpec ) SetMatReaction ( cnt , - 1 , pReact ) ;
for ( int32_t cnt2 = 0 ; cnt2 < Num ; cnt2 + + ) if ( DensitySemiSolid ( Map [ cnt2 ] . Density ) ! = pReact - > fInverseSpec ) SetMatReaction ( cnt , cnt2 , pReact ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if ( SEqualNoCase ( pReact - > TargetSpec . getData ( ) , " Background " ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// add to all BG materials, including sky
if ( ! pReact - > fInverseSpec ) SetMatReaction ( cnt , - 1 , pReact ) ;
for ( int32_t cnt2 = 0 ; cnt2 < Num ; cnt2 + + ) if ( ! Map [ cnt2 ] . Density ! = pReact - > fInverseSpec ) SetMatReaction ( cnt , cnt2 , pReact ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if ( SEqualNoCase ( pReact - > TargetSpec . getData ( ) , " Sky " ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// add to sky
if ( ! pReact - > fInverseSpec )
SetMatReaction ( cnt , - 1 , pReact ) ;
else
for ( int32_t cnt2 = 0 ; cnt2 < Num ; cnt2 + + ) SetMatReaction ( cnt , cnt2 , pReact ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if ( SEqualNoCase ( pReact - > TargetSpec . getData ( ) , " Incindiary " ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// add to all incendiary materials
if ( pReact - > fInverseSpec ) SetMatReaction ( cnt , - 1 , pReact ) ;
for ( int32_t cnt2 = 0 ; cnt2 < Num ; cnt2 + + ) if ( ! Map [ cnt2 ] . Incindiary = = pReact - > fInverseSpec ) SetMatReaction ( cnt , cnt2 , pReact ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if ( SEqualNoCase ( pReact - > TargetSpec . getData ( ) , " Extinguisher " ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// add to all incendiary materials
if ( pReact - > fInverseSpec ) SetMatReaction ( cnt , - 1 , pReact ) ;
for ( int32_t cnt2 = 0 ; cnt2 < Num ; cnt2 + + ) if ( ! Map [ cnt2 ] . Extinguisher = = pReact - > fInverseSpec ) SetMatReaction ( cnt , cnt2 , pReact ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if ( SEqualNoCase ( pReact - > TargetSpec . getData ( ) , " Inflammable " ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// add to all incendiary materials
if ( pReact - > fInverseSpec ) SetMatReaction ( cnt , - 1 , pReact ) ;
for ( int32_t cnt2 = 0 ; cnt2 < Num ; cnt2 + + ) if ( ! Map [ cnt2 ] . Inflammable = = pReact - > fInverseSpec ) SetMatReaction ( cnt , cnt2 , pReact ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if ( SEqualNoCase ( pReact - > TargetSpec . getData ( ) , " Corrosive " ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// add to all incendiary materials
if ( pReact - > fInverseSpec ) SetMatReaction ( cnt , - 1 , pReact ) ;
for ( int32_t cnt2 = 0 ; cnt2 < Num ; cnt2 + + ) if ( ! Map [ cnt2 ] . Corrosive = = pReact - > fInverseSpec ) SetMatReaction ( cnt , cnt2 , pReact ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if ( SEqualNoCase ( pReact - > TargetSpec . getData ( ) , " Corrode " ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// add to all incendiary materials
if ( pReact - > fInverseSpec ) SetMatReaction ( cnt , - 1 , pReact ) ;
for ( int32_t cnt2 = 0 ; cnt2 < Num ; cnt2 + + ) if ( ! Map [ cnt2 ] . Corrode = = pReact - > fInverseSpec ) SetMatReaction ( cnt , cnt2 , pReact ) ;
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// second loop (DefaultMatTex is needed by GetIndexMatTex)
2010-03-27 16:05:02 +00:00
for ( cnt = 0 ; cnt < Num ; cnt + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( Map [ cnt ] . sBlastShiftTo . getLength ( ) )
2009-08-15 18:50:32 +00:00
Map [ cnt ] . BlastShiftTo = : : TextureMap . GetIndexMatTex ( Map [ cnt ] . sBlastShiftTo . getData ( ) , NULL , true , FormatString ( " BlastShiftTo of mat %s " , Map [ cnt ] . Name ) . getData ( ) ) ;
2010-03-27 16:05:02 +00:00
if ( Map [ cnt ] . sInMatConvertTo . getLength ( ) )
Map [ cnt ] . InMatConvertTo = Get ( Map [ cnt ] . sInMatConvertTo . getData ( ) ) ;
if ( Map [ cnt ] . sBelowTempConvertTo . getLength ( ) )
Map [ cnt ] . BelowTempConvertTo = : : TextureMap . GetIndexMatTex ( Map [ cnt ] . sBelowTempConvertTo . getData ( ) , NULL , true , FormatString ( " BelowTempConvertTo of mat %s " , Map [ cnt ] . Name ) . getData ( ) ) ;
if ( Map [ cnt ] . sAboveTempConvertTo . getLength ( ) )
Map [ cnt ] . AboveTempConvertTo = : : TextureMap . GetIndexMatTex ( Map [ cnt ] . sAboveTempConvertTo . getData ( ) , NULL , true , FormatString ( " AboveTempConvertTo of mat %s " , Map [ cnt ] . Name ) . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
#if 0
int32_t i = 0 ;
2010-03-28 18:58:01 +00:00
while ( ReactionFuncMap [ i ] . szRFName ) { printf ( " %s: %p \n " , ReactionFuncMap [ i ] . szRFName , ReactionFuncMap [ i ] . pFunc ) ; + + i ; }
2009-05-08 13:28:41 +00:00
for ( int32_t cnt = - 1 ; cnt < Num ; cnt + + )
for ( int32_t cnt2 = - 1 ; cnt2 < Num ; cnt2 + + )
if ( ppReactionMap [ ( cnt2 + 1 ) * ( Num + 1 ) + cnt + 1 ] )
printf ( " %s -> %s: %p \n " , Map [ cnt ] . Name , Map [ cnt2 ] . Name , ppReactionMap [ ( cnt2 + 1 ) * ( Num + 1 ) + cnt + 1 ] - > pFunc ) ;
# endif
2013-01-08 22:41:20 +00:00
2009-06-12 18:52:21 +00:00
// Get hardcoded system material indices
2013-01-08 22:41:20 +00:00
const C4TexMapEntry * earth_entry = : : TextureMap . GetEntry ( : : TextureMap . GetIndexMatTex ( szEarthMaterial ) ) ;
2012-02-19 18:33:35 +00:00
if ( ! earth_entry )
2013-01-08 22:41:20 +00:00
{ LogFatal ( FormatString ( " Earth material \" %s \" not found! " , szEarthMaterial ) . getData ( ) ) ; return false ; }
2012-02-19 18:33:35 +00:00
2009-06-12 18:52:21 +00:00
MVehic = Get ( " Vehicle " ) ; MCVehic = Mat2PixColDefault ( MVehic ) ;
MTunnel = Get ( " Tunnel " ) ;
MWater = Get ( " Water " ) ;
2012-02-19 18:33:35 +00:00
MEarth = Get ( earth_entry - > GetMaterialName ( ) ) ;
2009-06-12 18:52:21 +00:00
if ( ( MVehic = = MNone ) | | ( MTunnel = = MNone ) )
{ LogFatal ( LoadResStr ( " IDS_PRC_NOSYSMATS " ) ) ; return false ; }
2013-01-08 22:41:20 +00:00
2009-06-12 18:52:21 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MaterialMap : : SetMatReaction ( int32_t iPXSMat , int32_t iLSMat , C4MaterialReaction * pReact )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// evaluate reaction swap
if ( pReact & & pReact - > fReverse ) Swap ( iPXSMat , iLSMat ) ;
// set it
ppReactionMap [ ( iLSMat + 1 ) * ( Num + 1 ) + iPXSMat + 1 ] = pReact ;
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 C4MaterialMap : : SaveEnumeration ( C4Group & hGroup )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
char * mapbuf = new char [ 1000 ] ;
mapbuf [ 0 ] = 0 ;
SAppend ( " [Enumeration] " , mapbuf ) ; SAppend ( LineFeed , mapbuf ) ;
2010-03-27 16:05:02 +00:00
for ( int32_t cnt = 0 ; cnt < Num ; cnt + + )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
SAppend ( Map [ cnt ] . Name , mapbuf ) ;
SAppend ( LineFeed , mapbuf ) ;
}
2010-03-28 18:58:01 +00:00
return hGroup . Add ( C4CFN_MatMap , mapbuf , SLen ( mapbuf ) , false , true ) ;
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4MaterialMap : : LoadEnumeration ( C4Group & hGroup )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Load enumeration map (from savegame), succeed if not present
StdStrBuf mapbuf ;
2011-03-05 01:44:26 +00:00
if ( ! hGroup . LoadEntryString ( C4CFN_MatMap , & mapbuf ) ) return true ;
2009-05-08 13:28:41 +00:00
// Sort material array by enumeration map, fail if some missing
const char * csearch ;
char cmatname [ C4M_MaxName + 1 ] ;
int32_t cmat = 0 ;
2009-08-15 18:50:32 +00:00
if ( ! ( csearch = SSearch ( mapbuf . getData ( ) , " [Enumeration] " ) ) ) { return false ; }
2009-05-08 13:28:41 +00:00
csearch = SAdvanceSpace ( csearch ) ;
while ( IsIdentifier ( * csearch ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
SCopyIdentifier ( csearch , cmatname , C4M_MaxName ) ;
if ( ! SortEnumeration ( cmat , cmatname ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Output error message!
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
cmat + + ;
csearch + = SLen ( cmatname ) ;
csearch = SAdvanceSpace ( csearch ) ;
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 true ;
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 C4MaterialMap : : SortEnumeration ( int32_t iMat , const char * szMatName )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Not enough materials loaded
2009-08-15 18:50:32 +00:00
if ( iMat > = Num ) return false ;
2009-05-08 13:28:41 +00:00
// Find requested mat
int32_t cmat ;
for ( cmat = iMat ; cmat < Num ; cmat + + )
if ( SEqual ( szMatName , Map [ cmat ] . Name ) )
break ;
// Not found
2009-08-15 18:50:32 +00:00
if ( cmat > = Num ) return false ;
2009-05-08 13:28:41 +00:00
// already the same?
2009-08-15 18:50:32 +00:00
if ( cmat = = iMat ) return true ;
2009-05-08 13:28:41 +00:00
// Move requested mat to indexed position
C4Material mswap ;
mswap = Map [ iMat ] ;
Map [ iMat ] = Map [ cmat ] ;
Map [ cmat ] = mswap ;
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
void C4MaterialMap : : Default ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
Num = 0 ;
Map = NULL ;
2009-05-08 13:28:41 +00:00
ppReactionMap = NULL ;
2011-07-16 19:50:49 +00:00
max_shape_width = max_shape_height = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4MaterialReaction * C4MaterialMap : : GetReaction ( int32_t iPXSMat , int32_t iLandscapeMat )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
if ( ! ppReactionMap ) return NULL ;
if ( ! Inside < int32_t > ( iPXSMat , - 1 , Num - 1 ) ) return NULL ;
if ( ! Inside < int32_t > ( iLandscapeMat , - 1 , Num - 1 ) ) return NULL ;
// values OK; get func!
return GetReactionUnsafe ( iPXSMat , iLandscapeMat ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
bool mrfInsertCheck ( int32_t & iX , int32_t & iY , C4Real & fXDir , C4Real & fYDir , int32_t & iPxsMat , int32_t iLsMat , bool * pfPosChanged )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// always manipulating pos/speed here
if ( pfPosChanged ) * pfPosChanged = true ;
// Rough contact? May splash
if ( fYDir > itofix ( 1 ) )
2009-06-05 18:46:03 +00:00
if ( : : MaterialMap . Map [ iPxsMat ] . SplashRate & & ! Random ( : : MaterialMap . Map [ iPxsMat ] . SplashRate ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
fYDir = - fYDir / 8 ;
2010-05-19 03:19:49 +00:00
fXDir = fXDir / 8 + C4REAL100 ( Random ( 200 ) - 100 ) ;
2009-05-08 13:28:41 +00:00
if ( fYDir ) return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Contact: Stop
fYDir = 0 ;
// Incindiary mats smoke on contact even before doing their slide
2009-06-05 18:46:03 +00:00
if ( : : MaterialMap . Map [ iPxsMat ] . Incindiary )
2012-11-17 15:30:12 +00:00
if ( ! Random ( 25 ) )
{
Smoke ( iX , iY , 4 + Random ( 3 ) ) ;
}
2009-05-08 13:28:41 +00:00
// Move by mat path/slide
int32_t iSlideX = iX , iSlideY = iY ;
2009-06-05 18:46:03 +00:00
if ( : : Landscape . FindMatSlide ( iSlideX , iSlideY , Sign ( GravAccel ) , : : MaterialMap . Map [ iPxsMat ] . Density , : : MaterialMap . Map [ iPxsMat ] . MaxSlide ) )
2010-03-28 18:58:01 +00:00
{
if ( iPxsMat = = iLsMat )
2009-05-08 13:28:41 +00:00
{ iX = iSlideX ; iY = iSlideY ; fXDir = 0 ; return false ; }
// Accelerate into the direction
2010-05-19 03:19:49 +00:00
fXDir = ( fXDir * 10 + Sign ( iSlideX - iX ) ) / 11 + C4REAL10 ( Random ( 5 ) - 2 ) ;
2009-05-08 13:28:41 +00:00
// Slide target in range? Move there directly.
2010-03-28 18:58:01 +00:00
if ( Abs ( iX - iSlideX ) < = Abs ( fixtoi ( fXDir ) ) )
{
2009-05-08 13:28:41 +00:00
iX = iSlideX ;
iY = iSlideY ;
2010-03-28 18:58:01 +00:00
if ( fYDir < = 0 ) fXDir = 0 ;
}
2009-05-08 13:28:41 +00:00
// Continue existance
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// insertion OK
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
bool mrfUserCheck ( C4MaterialReaction * pReaction , int32_t & iX , int32_t & iY , int32_t iLSPosX , int32_t iLSPosY , C4Real & fXDir , C4Real & fYDir , int32_t & iPxsMat , int32_t iLsMat , MaterialInteractionEvent evEvent , bool * pfPosChanged )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check execution mask
if ( ( 1 < < evEvent ) & ~ pReaction - > iExecMask ) return false ;
// do splash/slide check, if desired
if ( pReaction - > fInsertionCheck & & evEvent = = meePXSMove )
if ( ! mrfInsertCheck ( iX , iY , fXDir , fYDir , iPxsMat , iLsMat , pfPosChanged ) )
return false ;
// checks OK; reaction may be applied
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
bool C4MaterialMap : : mrfConvert ( C4MaterialReaction * pReaction , int32_t & iX , int32_t & iY , int32_t iLSPosX , int32_t iLSPosY , C4Real & fXDir , C4Real & fYDir , int32_t & iPxsMat , int32_t iLsMat , MaterialInteractionEvent evEvent , bool * pfPosChanged )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pReaction - > fUserDefined ) if ( ! mrfUserCheck ( pReaction , iX , iY , iLSPosX , iLSPosY , fXDir , fYDir , iPxsMat , iLsMat , evEvent , pfPosChanged ) ) return false ;
switch ( evEvent )
2010-03-28 18:58:01 +00:00
{
case meePXSMove : // PXS movement
// for hardcoded stuff: only InMatConvert is Snow in Water, which does not have any collision proc
if ( ! pReaction - > fUserDefined ) break ;
// user-defined conversions may also convert upon hitting materials
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
case meePXSPos : // PXS check before movement
{
// Check depth
int32_t iDepth = pReaction - > fUserDefined ? pReaction - > iDepth : : : MaterialMap . Map [ iPxsMat ] . InMatConvertDepth ;
if ( ! iDepth | | GBackMat ( iX , iY - iDepth ) = = iLsMat )
{
// Convert
iPxsMat = pReaction - > fUserDefined ? pReaction - > iConvertMat : : : MaterialMap . Map [ iPxsMat ] . InMatConvertTo ;
if ( ! MatValid ( iPxsMat ) )
// Convert failure (target mat not be loaded, or target may be C4TLS_MatSky): Kill Pix
return true ;
// stop movement after conversion
fXDir = fYDir = 0 ;
if ( pfPosChanged ) * pfPosChanged = true ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
break ;
case meeMassMove : // MassMover-movement
// Conversion-transfer to PXS
: : PXS . Create ( iPxsMat , itofix ( iX ) , itofix ( iY ) ) ;
return true ;
}
2009-05-08 13:28:41 +00:00
// not handled
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
bool C4MaterialMap : : mrfPoof ( C4MaterialReaction * pReaction , int32_t & iX , int32_t & iY , int32_t iLSPosX , int32_t iLSPosY , C4Real & fXDir , C4Real & fYDir , int32_t & iPxsMat , int32_t iLsMat , MaterialInteractionEvent evEvent , bool * pfPosChanged )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pReaction - > fUserDefined ) if ( ! mrfUserCheck ( pReaction , iX , iY , iLSPosX , iLSPosY , fXDir , fYDir , iPxsMat , iLsMat , evEvent , pfPosChanged ) ) return false ;
switch ( evEvent )
2010-03-28 18:58:01 +00:00
{
case meeMassMove : // MassMover-movement
case meePXSPos : // PXS check before movement: Kill both landscape and PXS mat
: : Landscape . ExtractMaterial ( iLSPosX , iLSPosY ) ;
2011-01-02 03:05:21 +00:00
if ( ! Random ( 3 ) ) Smoke ( iX , iY , 3 ) ;
if ( ! Random ( 3 ) ) StartSoundEffectAt ( " Pshshsh " , iX , iY ) ;
2010-03-28 18:58:01 +00:00
return true ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
case meePXSMove : // PXS movement
// incindiary/extinguisher/corrosives are always same density proc; so do insertion check first
if ( ! pReaction - > fUserDefined )
if ( ! mrfInsertCheck ( iX , iY , fXDir , fYDir , iPxsMat , iLsMat , pfPosChanged ) )
// either splash or slide prevented interaction
return false ;
// Always kill both landscape and PXS mat
: : Landscape . ExtractMaterial ( iLSPosX , iLSPosY ) ;
2011-01-02 03:05:21 +00:00
if ( ! Random ( 3 ) ) Smoke ( iX , iY , 3 ) ;
if ( ! Random ( 3 ) ) StartSoundEffectAt ( " Pshshsh " , iX , iY ) ;
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
// not handled
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
bool C4MaterialMap : : mrfCorrode ( C4MaterialReaction * pReaction , int32_t & iX , int32_t & iY , int32_t iLSPosX , int32_t iLSPosY , C4Real & fXDir , C4Real & fYDir , int32_t & iPxsMat , int32_t iLsMat , MaterialInteractionEvent evEvent , bool * pfPosChanged )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pReaction - > fUserDefined ) if ( ! mrfUserCheck ( pReaction , iX , iY , iLSPosX , iLSPosY , fXDir , fYDir , iPxsMat , iLsMat , evEvent , pfPosChanged ) ) return false ;
switch ( evEvent )
2010-03-28 18:58:01 +00:00
{
case meePXSPos : // PXS check before movement
// No corrosion - it would make acid incredibly effective
break ;
case meeMassMove : // MassMover-movement
{
// evaluate corrosion percentage
2012-11-17 15:30:12 +00:00
bool fDoCorrode ; int d100 = Random ( 100 ) ;
2010-03-28 18:58:01 +00:00
if ( pReaction - > fUserDefined )
2012-11-17 15:30:12 +00:00
fDoCorrode = ( d100 < pReaction - > iCorrosionRate ) ;
2010-03-28 18:58:01 +00:00
else
2012-11-17 15:30:12 +00:00
fDoCorrode = ( d100 < : : MaterialMap . Map [ iPxsMat ] . Corrosive ) & & ( d100 < : : MaterialMap . Map [ iLsMat ] . Corrode ) ;
2010-03-28 18:58:01 +00:00
if ( fDoCorrode )
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
ClearBackPix ( iLSPosX , iLSPosY ) ;
//::Landscape.CheckInstabilityRange(iLSPosX,iLSPosY); - more correct, but makes acid too effective as well
2012-11-17 15:30:12 +00:00
if ( ! Random ( 5 ) )
{
Smoke ( iX , iY , 3 + Random ( 3 ) ) ;
}
2010-03-28 18:58:01 +00:00
if ( ! Random ( 20 ) ) StartSoundEffectAt ( " Corrode " , iX , iY ) ;
2009-05-08 13:28:41 +00:00
return true ;
}
}
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
case meePXSMove : // PXS movement
2009-05-08 13:28:41 +00:00
{
2010-03-28 18:58:01 +00:00
// corrodes to corrosives are always same density proc; so do insertion check first
if ( ! pReaction - > fUserDefined )
2009-05-08 13:28:41 +00:00
if ( ! mrfInsertCheck ( iX , iY , fXDir , fYDir , iPxsMat , iLsMat , pfPosChanged ) )
// either splash or slide prevented interaction
return false ;
2010-03-28 18:58:01 +00:00
// evaluate corrosion percentage
2012-11-17 15:30:12 +00:00
bool fDoCorrode ; int d100 = Random ( 100 ) ;
2010-03-28 18:58:01 +00:00
if ( pReaction - > fUserDefined )
2012-11-17 15:30:12 +00:00
fDoCorrode = ( d100 < pReaction - > iCorrosionRate ) ;
2010-03-28 18:58:01 +00:00
else
2012-11-17 15:30:12 +00:00
fDoCorrode = ( d100 < : : MaterialMap . Map [ iPxsMat ] . Corrosive ) & & ( d100 < : : MaterialMap . Map [ iLsMat ] . Corrode ) ;
2010-03-28 18:58:01 +00:00
if ( fDoCorrode )
{
ClearBackPix ( iLSPosX , iLSPosY ) ;
: : Landscape . CheckInstabilityRange ( iLSPosX , iLSPosY ) ;
2012-11-17 15:30:12 +00:00
if ( ! Random ( 5 ) )
{
Smoke ( iX , iY , 3 + Random ( 3 ) ) ;
}
2010-03-28 18:58:01 +00:00
if ( ! Random ( 20 ) ) StartSoundEffectAt ( " Corrode " , iX , iY ) ;
2009-05-08 13:28:41 +00:00
return true ;
}
2010-03-28 18:58:01 +00:00
// Else: dead. Insert material here
: : Landscape . InsertMaterial ( iPxsMat , iX , iY ) ;
return true ;
}
}
2009-05-08 13:28:41 +00:00
// not handled
return false ;
2010-03-28 18:58:01 +00:00
}
2010-05-04 15:35:18 +00:00
bool C4MaterialMap : : mrfIncinerate ( C4MaterialReaction * pReaction , int32_t & iX , int32_t & iY , int32_t iLSPosX , int32_t iLSPosY , C4Real & fXDir , C4Real & fYDir , int32_t & iPxsMat , int32_t iLsMat , MaterialInteractionEvent evEvent , bool * pfPosChanged )
2010-03-28 18:58:01 +00:00
{
// not available as user reaction
assert ( ! pReaction - > fUserDefined ) ;
switch ( evEvent )
{
case meeMassMove : // MassMover-movement
case meePXSPos : // PXS check before movement
if ( : : Landscape . Incinerate ( iX , iY ) ) return true ;
break ;
case meePXSMove : // PXS movement
// incinerate to inflammables are always same density proc; so do insertion check first
if ( ! mrfInsertCheck ( iX , iY , fXDir , fYDir , iPxsMat , iLsMat , pfPosChanged ) )
// either splash or slide prevented interaction
return false ;
// evaluate inflammation (should always succeed)
if ( : : Landscape . Incinerate ( iX , iY ) ) return true ;
// Else: dead. Insert material here
: : Landscape . InsertMaterial ( iPxsMat , iX , iY ) ;
return true ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
// not handled
return false ;
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
bool C4MaterialMap : : mrfInsert ( C4MaterialReaction * pReaction , int32_t & iX , int32_t & iY , int32_t iLSPosX , int32_t iLSPosY , C4Real & fXDir , C4Real & fYDir , int32_t & iPxsMat , int32_t iLsMat , MaterialInteractionEvent evEvent , bool * pfPosChanged )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( pReaction - > fUserDefined ) if ( ! mrfUserCheck ( pReaction , iX , iY , iLSPosX , iLSPosY , fXDir , fYDir , iPxsMat , iLsMat , evEvent , pfPosChanged ) ) return false ;
switch ( evEvent )
2010-03-28 18:58:01 +00:00
{
case meePXSPos : // PXS check before movement
break ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
case meePXSMove : // PXS movement
{
// check for bounce/slide
if ( ! pReaction - > fUserDefined )
if ( ! mrfInsertCheck ( iX , iY , fXDir , fYDir , iPxsMat , iLsMat , pfPosChanged ) )
// continue existing
return false ;
// Else: dead. Insert material here
: : Landscape . InsertMaterial ( iPxsMat , iX , iY ) ;
return true ;
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
case meeMassMove : // MassMover-movement
break ;
}
2009-05-08 13:28:41 +00:00
// not handled
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
bool C4MaterialMap : : mrfScript ( C4MaterialReaction * pReaction , int32_t & iX , int32_t & iY , int32_t iLSPosX , int32_t iLSPosY , C4Real & fXDir , C4Real & fYDir , int32_t & iPxsMat , int32_t iLsMat , MaterialInteractionEvent evEvent , bool * pfPosChanged )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// do generic checks for user-defined reactions
if ( ! mrfUserCheck ( pReaction , iX , iY , iLSPosX , iLSPosY , fXDir , fYDir , iPxsMat , iLsMat , evEvent , pfPosChanged ) )
return false ;
// check script func
if ( ! pReaction - > pScriptFunc ) return false ;
// OK - let's call it!
// 0 1 2 3 4 5 6 7 8
int32_t iXDir1 , iYDir1 , iXDir2 , iYDir2 ;
C4AulParSet pars ( C4VInt ( iX ) , C4VInt ( iY ) , C4VInt ( iLSPosX ) , C4VInt ( iLSPosY ) , C4VInt ( iXDir1 = fixtoi ( fXDir , 100 ) ) , C4VInt ( iYDir1 = fixtoi ( fYDir , 100 ) ) , C4VInt ( iPxsMat ) , C4VInt ( iLsMat ) , C4VInt ( evEvent ) ) ;
if ( ! ! pReaction - > pScriptFunc - > Exec ( NULL , & pars , false ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// PXS shall be killed!
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// PXS shall exist further: write back parameters
iPxsMat = pars [ 6 ] . getInt ( ) ;
int32_t iX2 = pars [ 0 ] . getInt ( ) , iY2 = pars [ 1 ] . getInt ( ) ;
iXDir2 = pars [ 4 ] . getInt ( ) ; iYDir2 = pars [ 5 ] . getInt ( ) ;
if ( iX ! = iX2 | | iY ! = iY2 | | iXDir1 ! = iXDir2 | | iYDir1 ! = iYDir2 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// changes to pos/speed detected
if ( pfPosChanged ) * pfPosChanged = true ;
iX = iX2 ; iY = iY2 ;
2010-05-19 03:19:49 +00:00
fXDir = C4REAL100 ( iXDir2 ) ;
fYDir = C4REAL100 ( iYDir2 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// OK; done
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4MaterialMap : : UpdateScriptPointers ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// update in all materials
for ( int32_t i = 0 ; i < Num ; + + i ) Map [ i ] . UpdateScriptPointers ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-07-16 19:50:49 +00:00
C4MaterialShape * C4MaterialMap : : GetShapeByName ( const char * name )
{
C4MaterialShapeMap : : iterator i = Shapes . find ( StdCopyStrBuf ( name ) ) ;
if ( i = = Shapes . end ( ) ) return NULL ;
return & ( i - > second ) ;
}
2009-06-05 18:46:03 +00:00
C4MaterialMap MaterialMap ;