2015-07-26 21:39:49 +00:00
# include "CScriptLoader.h"
# include "../script/CMasterTemplate.h"
# include <Core/CResCache.h>
# include <Core/Log.h>
# include <iostream>
# include <sstream>
CScriptLoader : : CScriptLoader ( )
{
mpObj = nullptr ;
}
2015-09-18 05:53:53 +00:00
CPropertyStruct * CScriptLoader : : LoadStructMP1 ( CInputStream & SCLY , CStructTemplate * pTemp )
2015-07-26 21:39:49 +00:00
{
2015-09-18 05:53:53 +00:00
u32 structStart = SCLY . Tell ( ) ;
CPropertyStruct * propStruct = new CPropertyStruct ( ) ;
propStruct - > mpTemplate = pTemp ;
2015-07-26 21:39:49 +00:00
// Verify property count
2015-09-18 05:53:53 +00:00
u32 propCount = pTemp - > Count ( ) ;
if ( ! pTemp - > IsSingleProperty ( ) )
2015-07-26 21:39:49 +00:00
{
2015-09-18 05:53:53 +00:00
u32 filePropCount = SCLY . ReadLong ( ) ;
if ( propCount ! = filePropCount )
Log : : FileWarning ( SCLY . GetSourceString ( ) , structStart , " Struct \" " + pTemp - > Name ( ) + " \" template prop count doesn't match file " ) ;
2015-07-26 21:39:49 +00:00
}
// Parse properties
2015-09-18 05:53:53 +00:00
propStruct - > Reserve ( propCount ) ;
2015-07-26 21:39:49 +00:00
2015-09-18 05:53:53 +00:00
for ( u32 iProp = 0 ; iProp < propCount ; iProp + + )
2015-07-26 21:39:49 +00:00
{
2015-09-18 05:53:53 +00:00
CPropertyBase * pProp = nullptr ;
CPropertyTemplate * pPropTmp = pTemp - > PropertyByIndex ( iProp ) ;
EPropertyType type = pPropTmp - > Type ( ) ;
2015-07-26 21:39:49 +00:00
switch ( type )
{
case eBoolProperty : {
bool v = ( SCLY . ReadByte ( ) = = 1 ) ;
2015-09-18 05:53:53 +00:00
pProp = new CBoolProperty ( v ) ;
2015-07-26 21:39:49 +00:00
break ;
}
case eByteProperty : {
char v = SCLY . ReadByte ( ) ;
2015-09-18 05:53:53 +00:00
pProp = new CByteProperty ( v ) ;
2015-07-26 21:39:49 +00:00
break ;
}
case eShortProperty : {
short v = SCLY . ReadShort ( ) ;
2015-09-18 05:53:53 +00:00
pProp = new CShortProperty ( v ) ;
2015-07-26 21:39:49 +00:00
break ;
}
case eLongProperty : {
long v = SCLY . ReadLong ( ) ;
2015-09-18 05:53:53 +00:00
pProp = new CLongProperty ( v ) ;
2015-07-26 21:39:49 +00:00
break ;
}
2015-10-25 23:43:11 +00:00
case eBitfieldProperty : {
long v = SCLY . ReadLong ( ) ;
pProp = new CBitfieldProperty ( v ) ;
// Validate
u32 mask = 0 ;
CBitfieldTemplate * pBitfieldTemp = static_cast < CBitfieldTemplate * > ( pPropTmp ) ;
for ( u32 iMask = 0 ; iMask < pBitfieldTemp - > NumFlags ( ) ; iMask + + )
mask | = pBitfieldTemp - > FlagMask ( iMask ) ;
u32 check = v & ~ mask ;
if ( check ! = 0 ) Log : : FileWarning ( SCLY . GetSourceString ( ) , SCLY . Tell ( ) - 4 , " Bitfield property \" " + pBitfieldTemp - > Name ( ) + " \" in struct \" " + pTemp - > Name ( ) + " \" has flags set that aren't in the template: " + StringUtil : : ToHexString ( check , true , true , 8 ) ) ;
break ;
}
2015-10-19 10:35:05 +00:00
case eEnumProperty : {
2015-10-25 22:44:25 +00:00
CEnumTemplate * pEnumTemp = static_cast < CEnumTemplate * > ( pPropTmp ) ;
u32 ID = SCLY . ReadLong ( ) ;
u32 index = pEnumTemp - > EnumeratorIndex ( ID ) ;
if ( index = = - 1 ) Log : : FileError ( SCLY . GetSourceString ( ) , SCLY . Tell ( ) - 4 , " Enum property \" " + pEnumTemp - > Name ( ) + " \" in struct \" " + pTemp - > Name ( ) + " \" has invalid enumerator value: " + StringUtil : : ToHexString ( ID , true , true , 8 ) ) ;
2015-10-19 10:35:05 +00:00
pProp = new CEnumProperty ( index ) ;
break ;
}
2015-07-26 21:39:49 +00:00
case eFloatProperty : {
float v = SCLY . ReadFloat ( ) ;
2015-09-18 05:53:53 +00:00
pProp = new CFloatProperty ( v ) ;
2015-07-26 21:39:49 +00:00
break ;
}
case eStringProperty : {
std : : string v = SCLY . ReadString ( ) ;
2015-09-18 05:53:53 +00:00
pProp = new CStringProperty ( v ) ;
2015-07-26 21:39:49 +00:00
break ;
}
case eVector3Property : {
CVector3f v ( SCLY ) ;
2015-09-18 05:53:53 +00:00
pProp = new CVector3Property ( v ) ;
2015-07-26 21:39:49 +00:00
break ;
}
case eColorProperty : {
CVector4f color ( SCLY ) ;
CColor v ( color . x , color . y , color . z , color . w ) ;
2015-09-18 05:53:53 +00:00
pProp = new CColorProperty ( v ) ;
2015-07-26 21:39:49 +00:00
break ;
}
case eFileProperty : {
u32 ResID = SCLY . ReadLong ( ) ;
2015-09-18 05:53:53 +00:00
const CStringList & Extensions = static_cast < CFileTemplate * > ( pPropTmp ) - > Extensions ( ) ;
2015-07-26 21:39:49 +00:00
CResource * pRes = nullptr ;
for ( auto it = Extensions . begin ( ) ; it ! = Extensions . end ( ) ; it + + )
{
const std : : string & ext = * it ;
if ( ( ext ! = " MREA " ) & & ( ext ! = " MLVL " ) ) // Let's avoid recursion please
pRes = gResCache . GetResource ( ResID , ext ) ;
if ( pRes ) break ;
}
2015-09-18 05:53:53 +00:00
pProp = new CFileProperty ( pRes ) ;
2015-07-26 21:39:49 +00:00
break ;
}
case eStructProperty : {
2015-09-18 05:53:53 +00:00
CStructTemplate * StructTmp = pTemp - > StructByIndex ( iProp ) ;
pProp = LoadStructMP1 ( SCLY , StructTmp ) ;
2015-07-26 21:39:49 +00:00
break ;
}
2015-09-21 10:30:24 +00:00
case eAnimParamsProperty : {
pProp = new CAnimParamsProperty ( CAnimationParameters ( SCLY , mVersion ) ) ;
break ;
}
2015-09-18 05:53:53 +00:00
default :
pProp = new CUnknownProperty ( ) ;
break ;
2015-07-26 21:39:49 +00:00
}
2015-09-18 05:53:53 +00:00
if ( pProp )
2015-07-26 21:39:49 +00:00
{
2015-09-18 05:53:53 +00:00
pProp - > mpTemplate = pPropTmp ;
propStruct - > mProperties . push_back ( pProp ) ;
2015-07-26 21:39:49 +00:00
}
}
2015-09-18 05:53:53 +00:00
return propStruct ;
2015-07-26 21:39:49 +00:00
}
CScriptObject * CScriptLoader : : LoadObjectMP1 ( CInputStream & SCLY )
{
2015-09-18 05:53:53 +00:00
u32 objStart = SCLY . Tell ( ) ;
2015-07-26 21:39:49 +00:00
u8 type = SCLY . ReadByte ( ) ;
u32 size = SCLY . ReadLong ( ) ;
u32 end = SCLY . Tell ( ) + size ;
2015-09-18 05:53:53 +00:00
CScriptTemplate * pTemp = mpMaster - > TemplateByID ( ( u32 ) type ) ;
if ( ! pTemp )
2015-07-26 21:39:49 +00:00
{
// No valid template for this object; can't load
2015-09-18 05:53:53 +00:00
Log : : FileError ( SCLY . GetSourceString ( ) , objStart , " Invalid object ID encountered: " + StringUtil : : ToHexString ( type ) ) ;
2015-07-26 21:39:49 +00:00
SCLY . Seek ( end , SEEK_SET ) ;
return nullptr ;
}
2015-09-18 05:53:53 +00:00
mpObj = new CScriptObject ( mpArea , mpLayer , pTemp ) ;
2015-07-26 21:39:49 +00:00
mpObj - > mInstanceID = SCLY . ReadLong ( ) ;
// Load connections
2015-09-18 05:53:53 +00:00
u32 numLinks = SCLY . ReadLong ( ) ;
mpObj - > mOutConnections . reserve ( numLinks ) ;
2015-07-26 21:39:49 +00:00
2015-09-18 05:53:53 +00:00
for ( u32 iLink = 0 ; iLink < numLinks ; iLink + + )
2015-07-26 21:39:49 +00:00
{
2015-09-18 05:53:53 +00:00
SLink link ;
link . State = SCLY . ReadLong ( ) ;
link . Message = SCLY . ReadLong ( ) ;
link . ObjectID = SCLY . ReadLong ( ) ;
mpObj - > mOutConnections . push_back ( link ) ;
2015-07-26 21:39:49 +00:00
}
// Load object...
2015-09-18 05:53:53 +00:00
u32 count = SCLY . PeekLong ( ) ;
CStructTemplate * pBase = pTemp - > BaseStructByCount ( count ) ;
if ( ! pBase ) {
Log : : Error ( pTemp - > TemplateName ( ) + " template doesn't match file property count ( " + StringUtil : : ToString ( count ) + " ) " ) ;
pBase = pTemp - > BaseStructByIndex ( 0 ) ;
}
mpObj - > mpProperties = LoadStructMP1 ( SCLY , pBase ) ;
2015-07-26 21:39:49 +00:00
// Cleanup and return
SCLY . Seek ( end , SEEK_SET ) ;
2015-09-18 05:53:53 +00:00
mpObj - > EvaluateProperties ( ) ;
2015-07-26 21:39:49 +00:00
return mpObj ;
}
CScriptLayer * CScriptLoader : : LoadLayerMP1 ( CInputStream & SCLY )
{
u32 LayerStart = SCLY . Tell ( ) ;
SCLY . Seek ( 0x1 , SEEK_CUR ) ; // One unknown byte at the start of each layer
u32 NumObjects = SCLY . ReadLong ( ) ;
mpLayer = new CScriptLayer ( ) ;
mpLayer - > Reserve ( NumObjects ) ;
for ( u32 iObj = 0 ; iObj < NumObjects ; iObj + + )
{
CScriptObject * pObj = LoadObjectMP1 ( SCLY ) ;
if ( pObj )
mpLayer - > AddObject ( pObj ) ;
}
// Layer sizes are always a multiple of 32 - skip end padding before returning
u32 remaining = 32 - ( ( SCLY . Tell ( ) - LayerStart ) & 0x1F ) ;
SCLY . Seek ( remaining , SEEK_CUR ) ;
return mpLayer ;
}
void CScriptLoader : : LoadStructMP2 ( CInputStream & SCLY , CPropertyStruct * pStruct , CStructTemplate * pTemp )
{
// Verify property count
2015-09-21 10:30:24 +00:00
u32 propCount = pTemp - > Count ( ) ;
2015-07-26 21:39:49 +00:00
if ( ! pTemp - > IsSingleProperty ( ) )
{
2015-09-18 05:53:53 +00:00
u16 numProperties = SCLY . ReadShort ( ) ;
2015-09-21 10:30:24 +00:00
if ( ( numProperties ! = propCount ) & & ( mVersion < eReturns ) )
2015-07-26 21:39:49 +00:00
Log : : FileWarning ( SCLY . GetSourceString ( ) , SCLY . Tell ( ) - 2 , " Struct \" " + pTemp - > Name ( ) + " \" template property count doesn't match file " ) ;
2015-09-21 10:30:24 +00:00
propCount = numProperties ;
2015-07-26 21:39:49 +00:00
}
// Parse properties
2015-09-18 05:53:53 +00:00
pStruct - > Reserve ( propCount ) ;
2015-07-26 21:39:49 +00:00
2015-09-18 05:53:53 +00:00
for ( u32 iProp = 0 ; iProp < propCount ; iProp + + )
2015-07-26 21:39:49 +00:00
{
CPropertyBase * pProp ;
CPropertyTemplate * pPropTemp ;
2015-09-18 05:53:53 +00:00
u32 propertyStart = SCLY . Tell ( ) ;
u32 propertyID = - 1 ;
2015-07-26 21:39:49 +00:00
u16 PropertyLength = 0 ;
u32 NextProperty = 0 ;
if ( pTemp - > IsSingleProperty ( ) )
{
2015-09-18 05:53:53 +00:00
pProp = pStruct - > PropertyByIndex ( iProp ) ;
pPropTemp = pTemp - > PropertyByIndex ( iProp ) ;
2015-07-26 21:39:49 +00:00
}
else
{
2015-09-18 05:53:53 +00:00
propertyID = SCLY . ReadLong ( ) ;
2015-07-26 21:39:49 +00:00
PropertyLength = SCLY . ReadShort ( ) ;
NextProperty = SCLY . Tell ( ) + PropertyLength ;
2015-09-18 05:53:53 +00:00
pProp = pStruct - > PropertyByID ( propertyID ) ;
pPropTemp = pTemp - > PropertyByID ( propertyID ) ;
2015-07-26 21:39:49 +00:00
}
if ( ! pPropTemp )
2015-09-18 05:53:53 +00:00
Log : : FileError ( SCLY . GetSourceString ( ) , propertyStart , " Can't find template for property " + StringUtil : : ToHexString ( propertyID ) + " - skipping " ) ;
2015-07-26 21:39:49 +00:00
else
{
switch ( pPropTemp - > Type ( ) )
{
case eBoolProperty : {
CBoolProperty * pBoolCast = static_cast < CBoolProperty * > ( pProp ) ;
pBoolCast - > Set ( ( SCLY . ReadByte ( ) ! = 0 ) ) ;
break ;
}
case eByteProperty : {
CByteProperty * pByteCast = static_cast < CByteProperty * > ( pProp ) ;
pByteCast - > Set ( SCLY . ReadByte ( ) ) ;
break ;
}
case eShortProperty : {
CShortProperty * pShortCast = static_cast < CShortProperty * > ( pProp ) ;
pShortCast - > Set ( SCLY . ReadShort ( ) ) ;
break ;
}
case eLongProperty : {
CLongProperty * pLongCast = static_cast < CLongProperty * > ( pProp ) ;
pLongCast - > Set ( SCLY . ReadLong ( ) ) ;
break ;
}
2015-10-25 23:43:11 +00:00
case eBitfieldProperty : {
CBitfieldProperty * pBitfieldCast = static_cast < CBitfieldProperty * > ( pProp ) ;
pBitfieldCast - > Set ( SCLY . ReadLong ( ) ) ;
// Validate
u32 mask = 0 ;
CBitfieldTemplate * pBitfieldTemp = static_cast < CBitfieldTemplate * > ( pPropTemp ) ;
for ( u32 iMask = 0 ; iMask < pBitfieldTemp - > NumFlags ( ) ; iMask + + )
mask | = pBitfieldTemp - > FlagMask ( iMask ) ;
u32 check = pBitfieldCast - > Get ( ) & ~ mask ;
if ( check ! = 0 ) Log : : FileWarning ( SCLY . GetSourceString ( ) , SCLY . Tell ( ) - 4 , " Bitfield property \" " + pBitfieldTemp - > Name ( ) + " \" in struct \" " + pTemp - > Name ( ) + " \" has flags set that aren't in the template: " + StringUtil : : ToHexString ( check , true , true , 8 ) ) ;
break ;
}
2015-10-19 10:35:05 +00:00
case eEnumProperty : {
CEnumProperty * pEnumCast = static_cast < CEnumProperty * > ( pProp ) ;
2015-10-25 22:44:25 +00:00
CEnumTemplate * pEnumTemp = static_cast < CEnumTemplate * > ( pPropTemp ) ;
u32 ID = SCLY . ReadLong ( ) ;
u32 index = pEnumTemp - > EnumeratorIndex ( ID ) ;
if ( index = = - 1 ) Log : : FileError ( SCLY . GetSourceString ( ) , SCLY . Tell ( ) - 4 , " Enum property \" " + pEnumTemp - > Name ( ) + " \" in struct \" " + pTemp - > Name ( ) + " \" has invalid enumerator value: " + StringUtil : : ToHexString ( ID , true , true , 8 ) ) ;
2015-10-19 10:35:05 +00:00
pEnumCast - > Set ( index ) ;
break ;
}
2015-07-26 21:39:49 +00:00
case eFloatProperty : {
CFloatProperty * pFloatCast = static_cast < CFloatProperty * > ( pProp ) ;
pFloatCast - > Set ( SCLY . ReadFloat ( ) ) ;
break ;
}
case eStringProperty : {
CStringProperty * pStringCast = static_cast < CStringProperty * > ( pProp ) ;
pStringCast - > Set ( SCLY . ReadString ( ) ) ;
break ;
}
case eVector3Property : {
CVector3Property * pVector3Cast = static_cast < CVector3Property * > ( pProp ) ;
pVector3Cast - > Set ( CVector3f ( SCLY ) ) ;
break ;
}
case eColorProperty : {
CColorProperty * pColorCast = static_cast < CColorProperty * > ( pProp ) ;
CVector4f Color ( SCLY ) ;
pColorCast - > Set ( CColor ( Color . x , Color . y , Color . z , Color . w ) ) ;
break ;
}
case eFileProperty : {
CFileProperty * pFileCast = static_cast < CFileProperty * > ( pProp ) ;
CUniqueID ResID = ( mVersion < eCorruptionProto ? SCLY . ReadLong ( ) : SCLY . ReadLongLong ( ) ) ;
const CStringList & Extensions = static_cast < CFileTemplate * > ( pPropTemp ) - > Extensions ( ) ;
CResource * pRes = nullptr ;
// Check for each extension individually until we find a match
// This could be done better with a function to fetch the extension given the resource ID
// and a "does resource exist" function, but this will do for now
bool hasIgnoredExt = false ;
if ( ResID . IsValid ( ) )
{
for ( auto it = Extensions . begin ( ) ; it ! = Extensions . end ( ) ; it + + )
{
const std : : string & ext = * it ;
if ( ( ext ! = " MREA " ) & & ( ext ! = " MLVL " ) ) {
pRes = gResCache . GetResource ( ResID , ext ) ;
if ( pRes ) break ;
}
else
hasIgnoredExt = true ;
}
}
// Property may have an incorrect extension listed - print error
if ( ( ! pRes ) & & ( CUniqueID ( ResID ) . IsValid ( ) ) & & ( ! hasIgnoredExt ) )
{
std : : string ExtList ;
for ( auto it = Extensions . begin ( ) ; it ! = Extensions . end ( ) ; it + + )
{
if ( it ! = Extensions . begin ( ) ) ExtList + = " / " ;
ExtList + = * it ;
}
2015-09-18 05:53:53 +00:00
Log : : FileWarning ( SCLY . GetSourceString ( ) , " Incorrect resource type? " + ExtList + " " + StringUtil : : ToHexString ( propertyID ) ) ;
2015-07-26 21:39:49 +00:00
}
pFileCast - > Set ( pRes ) ;
break ;
}
case eUnknownProperty : {
CUnknownProperty * pUnknownCast = static_cast < CUnknownProperty * > ( pProp ) ;
std : : vector < u8 > buf ( PropertyLength ) ;
SCLY . ReadBytes ( buf . data ( ) , buf . size ( ) ) ;
pUnknownCast - > Set ( buf ) ;
break ;
}
case eStructProperty : {
CPropertyStruct * pStructCast = static_cast < CPropertyStruct * > ( pProp ) ;
LoadStructMP2 ( SCLY , pStructCast , static_cast < CStructTemplate * > ( pPropTemp ) ) ;
break ;
}
2015-09-18 05:53:53 +00:00
case eArrayProperty : {
CArrayProperty * pArrayCast = static_cast < CArrayProperty * > ( pProp ) ;
std : : vector < u8 > buf ( PropertyLength ) ;
SCLY . ReadBytes ( buf . data ( ) , buf . size ( ) ) ;
pArrayCast - > Set ( buf ) ;
break ;
}
2015-09-21 10:30:24 +00:00
case eAnimParamsProperty : {
CAnimParamsProperty * pAnimCast = static_cast < CAnimParamsProperty * > ( pProp ) ;
pAnimCast - > Set ( CAnimationParameters ( SCLY , mVersion ) ) ;
break ;
}
2015-07-26 21:39:49 +00:00
}
}
if ( NextProperty > 0 )
SCLY . Seek ( NextProperty , SEEK_SET ) ;
}
}
CScriptObject * CScriptLoader : : LoadObjectMP2 ( CInputStream & SCLY )
{
u32 ObjStart = SCLY . Tell ( ) ;
u32 ObjectID = SCLY . ReadLong ( ) ;
u16 ObjectSize = SCLY . ReadShort ( ) ;
u32 ObjEnd = SCLY . Tell ( ) + ObjectSize ;
CScriptTemplate * pTemplate = mpMaster - > TemplateByID ( ObjectID ) ;
if ( ! pTemplate )
{
Log : : FileError ( SCLY . GetSourceString ( ) , ObjStart , " Invalid object ID encountered: " + CFourCC ( ObjectID ) . ToString ( ) ) ;
SCLY . Seek ( ObjEnd , SEEK_SET ) ;
return nullptr ;
}
2015-09-18 05:53:53 +00:00
mpObj = new CScriptObject ( mpArea , mpLayer , pTemplate ) ;
2015-07-26 21:39:49 +00:00
mpObj - > mpTemplate = pTemplate ;
mpObj - > mInstanceID = SCLY . ReadLong ( ) ;
// Load connections
u32 NumConnections = SCLY . ReadShort ( ) ;
mpObj - > mOutConnections . reserve ( NumConnections ) ;
for ( u32 iCon = 0 ; iCon < NumConnections ; iCon + + )
{
SLink con ;
con . State = SCLY . ReadLong ( ) ;
con . Message = SCLY . ReadLong ( ) ;
con . ObjectID = SCLY . ReadLong ( ) ;
mpObj - > mOutConnections . push_back ( con ) ;
}
// Load object
SCLY . Seek ( 0x6 , SEEK_CUR ) ; // Skip base struct ID + size
2015-09-18 05:53:53 +00:00
u16 numProps = SCLY . PeekShort ( ) ;
mpObj - > CopyFromTemplate ( pTemplate , ( u32 ) numProps ) ;
CStructTemplate * pBase = pTemplate - > BaseStructByCount ( numProps ) ;
2015-07-26 21:39:49 +00:00
LoadStructMP2 ( SCLY , mpObj - > mpProperties , pBase ) ;
2015-09-18 05:53:53 +00:00
// Cleanup and return
2015-07-26 21:39:49 +00:00
SCLY . Seek ( ObjEnd , SEEK_SET ) ;
2015-09-18 05:53:53 +00:00
mpObj - > EvaluateProperties ( ) ;
2015-07-26 21:39:49 +00:00
return mpObj ;
}
CScriptLayer * CScriptLoader : : LoadLayerMP2 ( CInputStream & SCLY )
{
CFourCC SCLY_Magic ( SCLY ) ;
if ( SCLY_Magic = = " SCLY " ) SCLY . Seek ( 0x6 , SEEK_CUR ) ;
else if ( SCLY_Magic = = " SCGN " ) SCLY . Seek ( 0x2 , SEEK_CUR ) ;
else
{
Log : : FileError ( SCLY . GetSourceString ( ) , SCLY . Tell ( ) - 4 , " Invalid script layer magic: " + StringUtil : : ToHexString ( ( u32 ) SCLY_Magic . ToLong ( ) ) ) ;
return nullptr ;
}
u32 NumObjects = SCLY . ReadLong ( ) ;
mpLayer = new CScriptLayer ( ) ;
mpLayer - > Reserve ( NumObjects ) ;
for ( u32 iObj = 0 ; iObj < NumObjects ; iObj + + )
{
CScriptObject * pObj = LoadObjectMP2 ( SCLY ) ;
if ( pObj )
mpLayer - > AddObject ( pObj ) ;
}
if ( SCLY_Magic = = " SCGN " )
{
mpLayer - > SetName ( " Generated " ) ;
mpLayer - > SetActive ( true ) ;
}
return mpLayer ;
}
CScriptLayer * CScriptLoader : : LoadLayer ( CInputStream & SCLY , CGameArea * pArea , EGame version )
{
if ( ! SCLY . IsValid ( ) ) return nullptr ;
CScriptLoader Loader ;
Loader . mVersion = version ;
Loader . mpMaster = CMasterTemplate : : GetMasterForGame ( version ) ;
Loader . mpArea = pArea ;
if ( ! Loader . mpMaster )
{
Log : : Write ( " This game doesn't have a master template; couldn't load script layer " ) ;
return nullptr ;
}
if ( version < = ePrime )
return Loader . LoadLayerMP1 ( SCLY ) ;
else
return Loader . LoadLayerMP2 ( SCLY ) ;
}