www.pudn.com > GameEngine_src.rar > CSpriteFactory.cpp


 
#include "CSpriteFactory.h" 
#include "CEasyAudio.h" 
#include "CMagicFactory.h" 
#include "CMap.h" 
#include "normal.h" 
#include  
#include  
#include  
 
 
extern PEASYDRAW		g_pEasyDraw; 
extern PEASYAUDIO		g_pEasyAudio; 
extern CMap				theMap; 
extern CMagicFactory	theMagicFactory; 
 
////////////////////////////////////////////////////////////// 
//SI文件中的EPG文件名数组 
////////////////////////////////////////////////////////////// 
struct EPG_NAME_ARRAY 
{ 
	union { 
		struct { 
			char epg_wait_name[32]; 
			char epg_idle_name[32]; 
			char epg_walk_name[32]; 
			char epg_hurt_name[32]; 
			char epg_dead_name[32]; 
			char epg_melee_name[32]; 
			char epg_spell_name[32]; 
		}; 
		char epg_name_array[7][32]; 
	}; 
}; 
 
 
//////////////////////////////////////////////////////////////// 
//声音ID数组 
//////////////////////////////////////////////////////////////// 
struct SOUND_ID_ARRAY 
{ 
	union { 
		struct { 
			int walk_sound_id; 
			int hurt_sound_id; 
			int dead_sound_id; 
			int melee_sound_id; 
			int spell_sound_id; 
		}; 
		int sound_id[5]; 
	}; 
}; 
 
//si文件的文件头 
struct SI_FILE_HEADER 
{ 
	union { 
		struct { 
			int		siMask;					//异或摭码,用于加密 
			int		siFileType;				//文件标识 
			SPRITE_TYPE	siSpriteType;		//精灵种类 
			bool	siIsHaveES;				//是否有脚本 
			char	siName[16];				//精灵名字 
			int		siNumMagic;				//精灵魔法技能数量 
			int		rev[3]; 
		}; 
		int siHeader[16]; 
	}; 
}; 
 
const SI_FILE = 'SI'; 
 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
CSpriteFactory::CSpriteFactory() 
{ 
	m_MonsterCreateInterval = 3000;			//5 seconds 
	m_MaxNumOfMonster		= 60; 
	m_pEPK = NULL; 
} 
 
CSpriteFactory::~CSpriteFactory() 
{ 
 
} 
 
 
////////////////////////////////////////////////////////////////////// 
//初始化各个对象池,这只在程序开始时调用 
////////////////////////////////////////////////////////////////////// 
bool CSpriteFactory::Init() 
{ 
	if ( m_MonsterPool.Init( 128 ) == false ) 
		return false; 
 
	m_BloodBarWidth = g_pEasyDraw->GetCharWidth() * 8;		//必被4整除 
	 
	m_BloodBarHeight = g_pEasyDraw->GetCharHeight(); 
 
	m_BloodBarSurface1 = g_pEasyDraw->CreateSurfaceEx( NULL, m_BloodBarWidth, m_BloodBarHeight, true, 0, 0 ); 
	if ( m_BloodBarSurface1 == NULL )	return false; 
 
	m_BloodBarSurface2 = g_pEasyDraw->CreateSurfaceEx( NULL, m_BloodBarWidth, m_BloodBarHeight, true, 0, 0 ); 
	if ( m_BloodBarSurface2 == NULL )	return false; 
 
	m_BloodBarSurface2->ClearSurface( 0x7bef, 0 ); 
	return true; 
} 
 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CSpriteFactory::Free() 
{ 
	m_NpcArray.Free(); 
	m_NpcClassArray.Free(); 
	m_MonsterPool.Free(); 
	m_MonsterClassArray.Free(); 
	m_EPGDataArray.Free(); 
	g_pEasyDraw->DeleteSurface( m_BloodBarSurface1 ); 
	g_pEasyDraw->DeleteSurface( m_BloodBarSurface2 ); 
} 
 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
/*void CSpriteFactory::CreateNpc() 
{ 
	for ( int i = 0; i < m_NpcArray.GetLength(); ++i ) 
	{ 
		CNpc &npc = m_NpcArray[i]; 
		MONSTER_CLASS &mc = m_NpcClassArray[i]; 
 
		npc.Init( &(mc.EPGArray), &(mc.SpriteInfo), m_NpcInfoArray[i].BasePoint, ST_N_B ); 
		if ( theMap.AddAliveSprite( &npc ) == false ) 
		{ 
			assert(false); 
		} 
	} 
}*/ 
 
////////////////////////////////////////////////////////////////////// 
//随机的产生怪物 
////////////////////////////////////////////////////////////////////// 
void CSpriteFactory::CreateMonster() 
{ 
	unsigned int ThisTick = timeGetTime(); 
	BYTE HoldMask = HOLD_MASK | SAVE_MASK; 
 
	for ( int i = 0; i < m_MonsterInfoArray.GetLength(); ++i ) 
	{ 
		MONSTER_INFO &mi = m_MonsterInfoArray[i]; 
		if ( ThisTick - mi.LastTick > mi.Interval && mi.NumMonster <= mi.MaxNum )  
		{ 
			int max_row = theMap.GetHeight() * 4; 
			int max_col = theMap.GetWidth() * 4; 
			srand( ThisTick ); 
			int row = ( rand() + m_LastCell.col ) % max_row;		//随机产生怪物位置 
			int col = ( rand() + m_LastCell.row ) % max_col; 
 
			if ( theMap.IsCellHold( row, col, HoldMask ) == false ) 
			{ 
				CAliveSprite *monster = m_MonsterPool.Alloc(); 
				if ( monster != NULL ) 
				{ 
					MONSTER_CLASS &mc= m_MonsterClassArray[i]; 
 
					CELL cell(row, col); 
					POINT base; 
					theMap.CellToPoint( cell, base ); 
					monster->Init( &mc, base, ST_MONSTER ); 
					monster->SetDirection( ThisTick % 8 + 1 );			//随机设置怪物方向 
					monster->SetClassIndex( i );						//设置怪物的种类索引 
					if ( theMap.AddAliveSprite( monster ) == false ) 
						m_MonsterPool.Free( monster ); 
					else 
					{ 
						mi.NumMonster++; 
						mi.LastTick = ThisTick; 
					} 
				} 
			} 
		} 
	} 
} 
 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CSpriteFactory::DeleteMonster( CAliveSprite *monster ) 
{ 
	int i = monster->GetClassIndex(); 
	m_MonsterInfoArray[i].NumMonster -= 1; 
	m_MonsterPool.Free( monster ); 
} 
 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CSpriteFactory::DrawBloodBar( int x, int y, int hp, int max_hp, PSURFACE nameSurf ) 
{ 
	float f = float(hp) / float(max_hp) * float(m_BloodBarWidth); 
	RECT rc = { 0, 0, int(f), m_BloodBarHeight }; 
 
	m_BloodBarSurface1->ClearSurface( 0x0000, 0 ); 
	m_BloodBarSurface2->BltTo( 0, 0, m_BloodBarSurface1, &rc ); 
 
#ifdef ALPHA_SHADOW 
	m_BloodBarSurface1->DrawAlphaMMX( x, y ); 
#else 
	m_BloodBarSurface1->DrawAutoClip( x, y ); 
#endif 
 
	nameSurf->DrawAutoClip( x, y ); 
} 
 
 
////////////////////////////////////////////////////////////////////// 
//载入SI文件,获取要载入的EPG文件名 
////////////////////////////////////////////////////////////////////// 
void CSpriteFactory::OnFreeLvl() 
{ 
	for ( int i = 0; i < m_MonsterClassArray.GetLength(); ++i ) 
	{ 
		AS_SOUND_ARRAY &sound = m_MonsterClassArray[i].SoundArray; 
		for ( int j = 0; j < 5; ++j ) 
		{ 
			if ( sound.asSound[j] != NULL ) 
				g_pEasyAudio->DeleteSoundBuffer( sound.asSound[j] ); 
		} 
	} 
 
	SaveTmp(); 
 
	m_MonsterPool.Clear(); 
	m_MonsterClassArray.Clear(); 
	m_MonsterInfoArray.Clear(); 
 
	m_NpcArray.Clear(); 
	m_NpcClassArray.Clear(); 
 
	m_EPGDataArray.Clear(); 
} 
 
////////////////////////////////////////////////////////////////////// 
//从地图文件中载入NPC和怪物的信息 
////////////////////////////////////////////////////////////////////// 
void CSpriteFactory::OnLoadMap( FILE *fp, int NumNpc, int NumMonster ) 
{ 
	for ( int i = 0; i < NumNpc; ++i ) 
	{ 
		NPC_INFO *pni = m_NpcInfoArray.CreateOneElement(); 
		fread( pni, sizeof(NPC_INFO), 1, fp ); 
	} 
 
	for ( i = 0; i < NumMonster; ++i ) 
	{ 
		MONSTER_INFO *pmi = m_MonsterInfoArray.CreateOneElement(); 
		fread( pmi, sizeof(MONSTER_INFO), 1, fp ); 
	} 
} 
 
////////////////////////////////////////////////////////////////////// 
//载入SI文件,并获取EPG文件名 
//SI文件结构: 
//文件头+基本属性结构+EPG名数组+声音ID数组+魔法ID数组+脚本 
////////////////////////////////////////////////////////////////////// 
void CSpriteFactory::LoadSIHelp( unsigned char *buf ) 
{ 
	SI_FILE_HEADER sfh; 
	EPG_NAME_ARRAY epgName; 
	sfh = READ_MEMORY( buf, SI_FILE_HEADER );				//读取文件头 
	buf += sizeof(SI_FILE_HEADER); 
 
	for ( int i = 1; i < 16; ++i ) 
		sfh.siHeader[i] ^= sfh.siMask;						//解密文件头 
 
	debug_assert( sfh.siFileType == SI_FILE ); 
	MONSTER_CLASS *pMonsterClass = 0; 
 
	if ( sfh.siSpriteType == ST_N_B ) 
		pMonsterClass = m_NpcClassArray.CreateOneElement(); 
	else if ( sfh.siSpriteType == ST_MONSTER ) 
		pMonsterClass = m_MonsterClassArray.CreateOneElement(); 
	else 
		assert(false); 
 
	ZeroMemory( pMonsterClass, sizeof(MONSTER_CLASS) ); 
	pMonsterClass->NameSurface = g_pEasyDraw->CreateSurfaceEx( NULL, m_BloodBarWidth, m_BloodBarHeight, true, true, 0 ); 
	unsigned int color = 0xff; 
	if ( sfh.siSpriteType == ST_N_B )	 
		color = 0xff00; 
	pMonsterClass->NameSurface->WriteTextCenter( sfh.siName, color );	//创建名字页面,并写上名字 
 
	pMonsterClass->SpriteInfo = READ_MEMORY( buf, AS_BASE_INFO );	//读取基本属性 
	buf += sizeof(AS_BASE_INFO); 
 
	for ( i = 0; i < 6; ++i ) 
		pMonsterClass->SpriteInfo.IntInfo[i] ^= sfh.siMask;			//解密基本属性 
 
	epgName = READ_MEMORY( buf, EPG_NAME_ARRAY );					//读取EPG文件名 
	buf += sizeof(EPG_NAME_ARRAY); 
 
	for ( i = 0; i < 7; ++i ) 
	{ 
		if ( epgName.epg_name_array[i][0] != '\0' ) 
		{ 
			string str = epgName.epg_name_array[i]; 
			m_EPGNameArray.Add( str );					//EPG文件名存入列表,而EPG数组存放索引,索引从1开始 
			pMonsterClass->EPGArray.epg_array[i].NameIndex = m_EPGNameArray.GetLength(); 
		} 
	} 
 
	pMonsterClass->SoundArray = READ_MEMORY( buf, AS_SOUND_ARRAY );	//读取精灵的声音 
	buf += sizeof(AS_SOUND_ARRAY); 
 
	if ( sfh.siNumMagic > 0 ) 
	{ 
		pMonsterClass->MagicIDArray = new AS_MAGIC[sfh.siNumMagic]; 
		assert( pMonsterClass->MagicIDArray != NULL ); 
		memcpy( pMonsterClass->MagicIDArray, buf, sfh.siNumMagic * 4 );//读取魔法ID 
		pMonsterClass->NumMagic = sfh.siNumMagic; 
		buf += sfh.siNumMagic * 4; 
		for ( int j = 0; j < sfh.siNumMagic; ++j ) 
			theMagicFactory.OnLoadSI( pMonsterClass->MagicIDArray[j].magicID );//将魔法ID提交给魔法工厂 
	} 
 
	if ( sfh.siSpriteType == ST_N_B && sfh.siIsHaveES ) 
	{ 
		CNpc *pNpc = m_NpcArray.CreateOneElement();			//创建一个NPC对象 
		pNpc->LoadESFromMemory( (char *)buf, 0 );					//载入脚本 
	} 
} 
 
////////////////////////////////////////////////////////////////////// 
//载入关卡所有需要的SI文件 
////////////////////////////////////////////////////////////////////// 
bool CSpriteFactory::OnLoadLvl() 
{ 
	CEPKFile epk; 
	if ( false == epk.Open( "..\\data\\si.epk", EPK_IN ) ) 
		assert(false); 
 
	CDynamicArray	magicIDArray; 
	 
	bool re = true; 
 
	for ( int i = 0; i < m_NpcInfoArray.GetLength(); ++i ) 
	{ 
		BYTE *buf = epk.Read( m_NpcInfoArray[i].siFileName ); 
		if ( buf == 0 ) 
		{ 
			re = false; 
			goto _exit; 
		} 
 
		LoadSIHelp( buf ); 
	} 
 
	for ( i = 0; i < m_MonsterInfoArray.GetLength(); ++i ) 
	{ 
		BYTE *buf = epk.Read( m_MonsterInfoArray[i].siFileName ); 
		if ( buf == NULL ) 
		{ 
			re = false; 
			goto _exit; 
		} 
 
		LoadSIHelp( buf ); 
	} 
 
_exit: 
	epk.Close(); 
 
	if ( re ) 
	{ 
		SafeDelete( m_pEPK ); 
		m_pEPK = new CEPKFile;				//创建EPK对象 
		assert( m_pEPK != NULL ); 
		if ( false == m_pEPK->Open( "..\\data\\animation.epk", EPK_IN ) ) 
			re = false; 
		m_IndexEPGLoading = 0; 
	} 
	return re; 
} 
 
////////////////////////////////////////////////////////////////////// 
//载入关卡中所需要的EPG 
//一次游戏循环中载入一个,如果全部载入完,返回true 
////////////////////////////////////////////////////////////////////// 
bool CSpriteFactory::OnLoadingLvl() 
{ 
	if ( m_IndexEPGLoading < m_EPGNameArray.GetLength() ) 
	{ 
		BYTE *data = m_pEPK->Read( m_EPGNameArray[m_IndexEPGLoading].c_str() ); 
		debug_assert( data != NULL );					//如果找不到所要的EPG,则是游戏设计的错误 
		 
		EPG_DATA *pEPGData = m_EPGDataArray.CreateOneElement(); 
		if ( false == pEPGData->LoadEPGFromMemory( (char *)data ) ) 
		{ 
			debug_assert( false ); 
			return false; 
		} 
		 
		m_IndexEPGLoading++; 
		return false; 
	} 
	else  
	{ 
		m_pEPK->Close(); 
 
		//载入声音: 
		if ( m_pEPK->Open( "..\\data\\sound.epk", EPK_IN ) == false ) 
			assert(false); 
 
		for ( int i = 0; i < m_MonsterClassArray.GetLength(); ++i ) 
		{ 
			AS_SOUND_ARRAY &sound = m_MonsterClassArray[i].SoundArray; 
			for ( int j = 0; j < 5; ++j ) 
			{ 
				if ( sound.soundId[j] > 0 ) 
				{ 
					char sz[8]; 
					wsprintf( sz, "%d.wav", sound.soundId[j] ); 
					BYTE *buf = m_pEPK->Read( sz ); 
					debug_assert( buf != NULL ); 
					sound.asSound[j] = g_pEasyAudio->CreateSoundBuffer( (char *)buf, false, 4 ); 
				} 
			} 
		} 
		m_pEPK->Close(); 
		delete m_pEPK; 
		m_pEPK = NULL; 
		return true; 
	} 
} 
 
////////////////////////////////////////////////////////////////////// 
//初始化关卡 
////////////////////////////////////////////////////////////////////// 
void CSpriteFactory::InitClassHelp( CDynamicArray &classArray ) 
{ 
	for ( int i = 0; i < classArray.GetLength(); ++i ) 
	{	//按EPG索引获取EPG指针,如果索引为0则没有指针 
		MONSTER_CLASS &monsterClass = classArray[i]; 
		for ( int j = 0; j < 7; ++j ) 
		{ 
			ALIVE_SPRITE_EPG &asEPG = monsterClass.EPGArray.epg_array[j]; 
			int index = asEPG.NameIndex; 
			if ( index > 0 ) 
			{ 
				asEPG.pPG = m_EPGDataArray[index-1].GetAnimation(); 
				asEPG.pSPG= m_EPGDataArray[index-1].GetShadow(); 
 
				int h = asEPG.pPG->GetMaxHeight();			//计算最大高度值,用于绘制血条 
				if ( h > monsterClass.MaxHeight ) 
					monsterClass.MaxHeight = h; 
			} 
		} 
		//按魔法ID向魔法工厂索要魔法指针 
		for ( j = 0; j < monsterClass.NumMagic; ++j ) 
		{ 
			monsterClass.MagicIDArray[j].pMagic = theMagicFactory.FindMagic(monsterClass.MagicIDArray[j].magicID); 
			debug_assert( monsterClass.MagicIDArray[j].pMagic != NULL ); 
		} 
	} 
} 
 
////////////////////////////////////////////////////////////////////// 
//初始化关卡 
////////////////////////////////////////////////////////////////////// 
void CSpriteFactory::OnInitLvl() 
{ 
	InitClassHelp( m_NpcClassArray ); 
	InitClassHelp( m_MonsterClassArray ); 
 
	//创建NPC: 
	for ( int i = 0; i < m_NpcArray.GetLength(); ++i ) 
	{ 
		CNpc &npc = m_NpcArray[i]; 
		MONSTER_CLASS &mc = m_NpcClassArray[i]; 
 
		npc.Init( &mc, m_NpcInfoArray[i].BasePoint, ST_N_B ); 
		theMap.AddAliveSprite( &npc ); 
	} 
 
	//初始化怪物信息 
	for ( i = 0; i < m_MonsterInfoArray.GetLength(); ++i ) 
	{ 
		m_MonsterInfoArray[i].LastTick = 0; 
		m_MonsterInfoArray[i].NumMonster = 0; 
	} 
 
	m_NpcInfoArray.Free();		//npc info数组已经没用,释放内存 
	m_EPGNameArray.Free();		//EPG名字数组释放 
 
	LoadTmp(); 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CSpriteFactory::SaveTmp() 
{ 
	if ( m_MonsterPool.IsEmpty() ) 
		return; 
 
	char *fileName = new char[64]; 
	if ( fileName == NULL ) 
		return; 
 
	memset( fileName, 0, 64 ); 
	strcpy( fileName, "..\\data\\" ); 
	strcat( fileName, theMap.GetCurMapName() ); 
	strcat( fileName, ".tmp" ); 
 
	FILE *fp = fopen( fileName, "wb+" ); 
	if ( fp == NULL ) 
	{ 
		delete [] fileName; 
		return; 
	} 
 
	int sum = 0; 
	fseek( fp, 4, SEEK_SET ); 
 
	for ( m_MonsterPool.Begin(); m_MonsterPool.IsNotNull(); m_MonsterPool.MoveNext() ) 
	{ 
		CAliveSprite *monster = m_MonsterPool.GetCur(); 
		if ( monster->IsAlive() ) 
		{ 
			int n = monster->GetClassIndex(); 
			fwrite( &n, 4, 1, fp ); 
 
			n = monster->GetLife(); 
			fwrite( &n, 4, 1, fp ); 
 
			POINT p = monster->GetBasePoint(); 
			fwrite( &p, 8, 1, fp ); 
			sum++; 
		} 
	} 
 
	fseek( fp, 0, SEEK_SET ); 
	fwrite( &sum, 4, 1, fp ); 
 
	fclose(fp); 
	delete [] fileName; 
} 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
void CSpriteFactory::LoadTmp() 
{ 
	char *fileName = new char[64]; 
	if ( fileName == NULL ) 
		return; 
 
	memset( fileName, 0, 64 ); 
	strcpy( fileName, theMap.GetNextMapName() ); 
	strcat( fileName, ".tmp" ); 
 
	FILE *fp = fopen( fileName, "rb" ); 
	if ( fp == NULL ) 
	{ 
		delete [] fileName; 
		return; 
	} 
 
	int sum, index, life; 
	POINT point; 
	BYTE HoldMask = HOLD_MASK | SAVE_MASK; 
	DWORD ThisTick = timeGetTime(); 
	fread( &sum, 4, 1, fp ); 
 
	for ( int i = 0; i < sum; ++i ) 
	{ 
		fread( &index, 4, 1, fp ); 
		fread( &life, 4, 1, fp ); 
		fread( &point, 8, 1, fp ); 
		 
		CAliveSprite *monster = m_MonsterPool.Alloc(); 
		if ( monster != NULL ) 
		{ 
			MONSTER_CLASS &mc= m_MonsterClassArray[index]; 
			monster->Init( &mc, point, ST_MONSTER ); 
			monster->SetClassIndex( index );						//设置怪物的种类索引 
			monster->SetLife( life ); 
			if ( theMap.AddAliveSprite( monster ) == false ) 
				m_MonsterPool.Free( monster ); 
			else 
			{ 
				MONSTER_INFO &mi = m_MonsterInfoArray[index]; 
				mi.NumMonster++; 
				mi.LastTick = ThisTick; 
			} 
		} 
	} 
 
	fclose( fp ); 
	delete [] fileName; 
}