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


// CHero.cpp: implementation of the CHero class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "CHero.h" 
#include "normal.h" 
#include "CMap.h" 
#include "CEPKFile.h" 
#include "CEasyAudio.h" 
#include "CDInput.h" 
#include "CProgressBar.h" 
#include "EasyScript.h" 
#include "CMessageManager.h" 
#include "CItem.h" 
#include "CItemFactory.h" 
#include "CMagic.h" 
#include "CMagicFactory.h" 
#include "CGameManager.h" 
#include  
 
extern CMap		theMap; 
extern PEASYDRAW	g_pEasyDraw; 
extern PEASYAUDIO	g_pEasyAudio; 
extern CDIMouse		theMouse; 
extern CMessageManager theMsgMgr; 
extern CItemBox		theItemBag; 
extern CItemBox		theEquipmentBox;		//装备栏 
extern CMagicFactory	theMagicFactory; 
extern CItemFactory	theItemFactory; 
extern CGameManager	theGameManager;	 
 
 
/////////////////////////////////////////////////////////////////////// 
//英雄数据文件的文件头 
/////////////////////////////////////////////////////////////////////// 
struct HD_FILE_HEADER 
{ 
	union { 
	/******************************************************** 
	*为了保护游戏资源,此处内容省略 
	********************************************************/ 
		int data[27]; 
	}; 
}; 
 
char *HERO_EPG_NAME_ARRAY[7] = { "hero%d_wait.epg", "hero%d_idle.epg", "hero%d_walk.epg", 
			 "hero%d_hurt.epg", "hero%d_dead.epg", "hero%d_melee.epg", "hero%d_spell.epg" }; 
 
////////////////////////////////////////////////////////////////////// 
// 
////////////////////////////////////////////////////////////////////// 
CHero::CHero() 
{ 
	m_HeroEPGArray = NULL; 
	m_NextDest.row = -1; 
	m_cp_pg = NULL; 
} 
 
CHero::~CHero() 
{ 
 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
bool CHero::Init() 
{ 
	m_HeroEPGArray = new EPG_DATA[7]; 
	m_pClass = new MONSTER_CLASS; 
	m_HeroSkillArray = new HERO_SKILL[10];			//初始化技能数组 
	if ( m_HeroEPGArray == NULL || m_pClass == NULL && m_HeroSkillArray == NULL ) 
		return false; 
	 
	ZeroMemory( m_pClass, sizeof(MONSTER_CLASS) );						 
	ZeroMemory( m_HeroSkillArray, 10 * sizeof(HERO_SKILL) ); 
 
	m_TempSurface = g_pEasyDraw->CreateSurfaceEx( 0, g_pEasyDraw->GetCharWidth() * 8, 
												g_pEasyDraw->GetCharHeight(), true, true, 0 ); 
	if ( m_TempSurface == NULL ) 
		return false; 
 
	m_NextCell.row = 0; 
	m_NextCell.col = 0; 
	m_pMagic = NULL; 
	m_Distance = 1; 
	m_LastTick = 0; 
	m_pg_frame = 0; 
	m_Direction = 1; 
 
	m_SpriteType = ST_HERO; 
	return true; 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::Free() 
{ 
	SafeDeleteArray( m_HeroEPGArray ); 
	SafeDeleteArray( m_HeroSkillArray ); 
	SafeDelete( m_cp_pg ); 
	SafeDelete( m_pClass ); 
} 
 
//////////////////////////////////////////////////////////////////////// 
//载入通用资源,包括角色动画,血条,行动指针 
//其中血条,行动指针只在游戏初始化载入,游戏结束时自动释放 
//////////////////////////////////////////////////////////////////////// 
bool CHero::LoadHeroRes( HERO_CLASS heroClass ) 
{ 
	CEPKFile epk; 
	int indexClass = (int)heroClass; 
 
	if ( false == epk.Open( "..\\data\\common.epk", EPK_IN ) ) 
		return false; 
 
	//载入血条 
	BYTE *buf = epk.Read( "hp_bk.ecp" );		 
	debug_assert( buf != NULL ); 
	PSURFACE bk_surf = g_pEasyDraw->CreateSurfaceFromMemory( buf ); 
 
	buf = epk.Read( "hp_ft.ecp" ); 
	debug_assert( buf != NULL ); 
	PSURFACE ft_surf = g_pEasyDraw->CreateSurfaceFromMemory( buf ); 
	m_HPBar.Init( bk_surf, ft_surf, 28, 5 ); 
 
	//载入魔条 
	buf = epk.Read( "mp_bk.ecp" ); 
	debug_assert( buf != NULL ); 
	bk_surf = g_pEasyDraw->CreateSurfaceFromMemory( buf ); 
 
	buf = epk.Read( "mp_ft.ecp" ); 
	debug_assert( buf != NULL ); 
	ft_surf = g_pEasyDraw->CreateSurfaceFromMemory( buf ); 
	m_MPBar.Init( bk_surf, ft_surf, 27, 0 ); 
 
	//载入信息窗口 
	buf = epk.Read( "info_dlg.ecp" ); 
	debug_assert( buf != NULL ); 
	m_InfoSurface = g_pEasyDraw->CreateSurfaceFromMemory( buf ); 
 
	//载入控制面板页面 
	buf = epk.Read( "gui.ecp" ); 
	debug_assert( buf != NULL ); 
	m_GuiSurface = g_pEasyDraw->CreateSurfaceFromMemory( buf ); 
 
	//载入技能恢复条 
	buf = epk.Read( "sb_bk.ecp" ); 
	debug_assert( buf != NULL ); 
	bk_surf = g_pEasyDraw->CreateSurfaceFromMemory( buf ); 
	buf = epk.Read( "sb_ft.ecp" ); 
	debug_assert( buf != NULL ); 
	ft_surf = g_pEasyDraw->CreateSurfaceFromMemory( buf ); 
	m_SkillBar.Init( bk_surf, ft_surf, 0, 0 ); 
 
	//载入行动指针 
	buf = epk.Read( "cell_pointer.epg" ); 
	debug_assert( buf != NULL ); 
	m_cp_pg = new CPictureGroup; 
	debug_assert( m_cp_pg != NULL ); 
	m_cp_pg->LoadEPG( (char*)buf, false, 0, 0, 0 ); 
 
	//载入英雄动画 
	for ( int i = 0; i < 7; ++i ) 
	{ 
		char sz[32]; 
		wsprintf( sz, HERO_EPG_NAME_ARRAY[i], indexClass ); 
		buf = epk.Read( sz ); 
		m_HeroEPGArray[i].LoadEPGFromMemory( (char*)buf ); 
	} 
 
	//载入声音 
	for ( i = 1; i <= 3; ++i ) 
	{ 
		char sz[16]; 
		wsprintf( sz, "%d.wav", indexClass * 10 + i ); 
		buf = epk.Read( sz ); 
		m_pClass->SoundArray.asSound[i] = g_pEasyAudio->CreateSoundBuffer( (char*)buf, false ); 
	} 
 
	//载入技能卡页面 
	int j = indexClass * 10; 
	for ( i = 0; i < 10; ++i ) 
	{ 
		char sz[12]; 
		wsprintf( sz, "c%d.ecp", i + j ); 
		buf = epk.Read( sz ); 
		debug_assert( buf != NULL ); 
		m_HeroSkillArray[i].cardSurface = g_pEasyDraw->CreateSurfaceFromMemory(buf); 
	} 
 
	epk.Close(); 
 
	//载入英雄魔法 
	j = indexClass * 10; 
	for ( i = 0; i < 10; ++i ) 
	{ 
		theMagicFactory.OnLoadSI( i + j ); 
	} 
 
	for ( i = 0; i < 7; ++i ) 
	{ 
		m_pClass->EPGArray.epg_array[i].pPG = m_HeroEPGArray[i].GetAnimation(); 
		m_pClass->EPGArray.epg_array[i].pSPG= m_HeroEPGArray[i].GetShadow(); 
	} 
 
	int frame_per_direction = m_pClass->EPGArray.epg_walk.pPG->GetFramePerDirection(); 
	if ( frame_per_direction % 2 == 0 ) 
		m_move_frame = frame_per_direction / 2 - 1; 
	else 
		m_move_frame = frame_per_direction / 2; 
	SetState( SS_WAIT ); 
	return true; 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::OnInitLvl() 
{ 
	int j = (int)m_HeroClass * 10; 
	int n = m_pClass->SpriteInfo.m_Agility * 128; 
	for ( int i = 0; i < 10; ++i ) 
	{ 
		HERO_SKILL &skill = m_HeroSkillArray[i]; 
		skill.pMagic = theMagicFactory.FindMagic( i + j ); 
		int temp = skill.pMagic->GetInterval() - n; 
		if ( temp < 0 ) 
			temp = 0; 
		skill.interval = temp; 
	} 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
bool CHero::UpdateSprite() 
{ 
	bool re = true; 
	bool bNextFrame = false;		//是否更新下一帧 
	bool bUpdate = false;			//是否完成一个动作 
	bool bMoveMap = false; 
	unsigned int thisTick = timeGetTime(); 
 
	//更新生命,魔法值,魔法状态与魔法状态动画 
	if ( thisTick - m_LastTime > 100 ) 
	{	 
		m_LastTime = thisTick; 
		m_Life += m_PlusInfo.m_AddLife; 
		if ( m_Life <= 0 && m_State != SS_DEAD ) 
		{ 
			SetState( SS_DEAD ); 
			ClearMagicState(); 
			m_move_frame = m_LastTick; 
		} 
		if ( m_Life > m_pClass->SpriteInfo.m_MaxLife )	m_Life = m_pClass->SpriteInfo.m_MaxLife; 
 
		m_PlusInfo.m_Mana += m_PlusInfo.m_AddMana;				 
		if ( m_PlusInfo.m_Mana < 0 ) m_PlusInfo.m_Mana = 0; 
		if ( m_PlusInfo.m_Mana > m_pClass->SpriteInfo.m_MaxMana ) m_PlusInfo.m_Mana = m_pClass->SpriteInfo.m_MaxMana; 
		 
		for ( int i = m_MagicStateArray.GetLength()-1; i >= 0; --i )	//更新魔法状态 
		{ 
			MAGIC_STATE &ms = m_MagicStateArray[i]; 
			if ( thisTick > ms.endTime )						//如果魔法状态已经到结束时间 
			{ 
				AddInfo( ms.effectIndex, -ms.effectValue );		//还原作用值 
				m_MagicStateArray.Delete(i);					//删除状态 
			} 
		} 
		 
		for ( i = m_MSEArray.GetLength()-1; i >= 0; --i )		//更新魔法状态动画 
		{ 
			MAGIC_STATE_EPG &mse = m_MSEArray[i]; 
			if ( thisTick > mse.endTime )						 
			{ 
				m_MSEArray.Delete(i);							//如果动画过期,则删除 
			} 
			else 
			{ 
				mse.curFrame++;									//否则更新帧 
				mse.curFrame = mse.curFrame % mse.pEPG->GetNumFrame(); 
			} 
		} 
	} 
 
	//更新动画帧时间 
	if ( thisTick - m_LastTick > m_cur_pg->GetDelayTime() - m_PlusInfo.m_Speed )	//speed控制更新速度 
	{ 
		bNextFrame = true; 
		m_LastTick = thisTick; 
		if ( m_Frame == m_pClass->EPGArray.GetLastFrame(m_State) ) 
			bUpdate = true;				//如果到了动作的最后一帧 
	} 
	else 
		goto _exit;						//如果不需要更新,则跳转到结束 
 
	//判断各个状态,并相应的更新 
	if ( m_State == SS_WAIT )			//静止状态 
	{ 
		if ( m_Frame == 0 ) 
		{ 
			if ( m_HeroState == HS_GOTO_FIGHT ) 
			{ 
				goto _goto_fight; 
			} 
		} 
		if ( bUpdate ) 
		{ 
			//如果没有攻击目标,则随机的进入空闲状态 
			m_pEnemy = NULL; 
			if ( m_LastTick % 128 > 100 ) 
			{ 
				SetState(SS_IDLE); 
				bNextFrame = false; 
			} 
		} 
	} 
	else if ( m_State == SS_WALK )			//行走状态 
	{ 
		bMoveMap = true; 
		if ( bUpdate )						//如果完成了一步 
		{ 
			if ( m_NextDest.row > -1 )		//如果用户改变了目的地			 
			{ 
				GetPath( m_NextDest ); 
				m_NextDest.row = -1;			 
			} 
			else if ( m_HeroState == HS_GOTO_FIGHT )	//如果敌人活着,判断与敌人的距离 
			{ 
_goto_fight: 
				POINT p = m_SpellPoint; 
				if ( m_pEnemy != NULL ) 
				{ 
					if ( m_pEnemy->IsAlive() ) 
						p = m_pEnemy->GetBasePoint(); 
					else  
						goto _no_walk; 
				} 
 
				if ( CalcDistance( m_BasePoint, p ) <= m_Distance ) 
				{ 
					GetNextDirection( p ); 
					if ( m_pMagic != NULL ) 
					{ 
						Spell( m_pEnemy, p ); 
					} 
					else 
						SetState( SS_MELEE ); 
 
					m_HeroState = HS_FIGHTING; 
					bNextFrame = false; 
					bMoveMap = false; 
					goto _exit; 
				} 
				else 
				{ 
					GetPath( p ); 
				}	 
			} 
 
 
			if ( m_PathStack.Pop( m_NextCell ) )			//如果还没走完,获取下一步 
			{ 
				if ( theMap.IsCellHold( m_NextCell.row, m_NextCell.col ) ) 
				{ 
					goto _no_walk; 
				} 
				POINT p; 
				theMap.CellToPoint( m_NextCell, p ); 
				GetNextDirection( p );		//获取下一步方向 
			} 
			else 
			{ 
				if ( m_HeroState == HS_PICK ) 
				{ 
					PickItem( 0 ); 
					m_HeroState = HS_NORMAL; 
				} 
 
_no_walk:		SetState( SS_WAIT );					//如果已经走完,进入静止状态 
				bNextFrame = false; 
				bMoveMap = false; 
				goto _exit; 
			} 
		} 
		else if ( m_Frame == m_move_frame )				//到了移位帧,移动精灵到下一个CELL中 
		{ 
			if ( theMap.IsCellHold( m_NextCell.row, m_NextCell.col ) ) 
			{ 
				SetState( SS_WAIT );					//如果下一个CELL已被占据,则不继续移动 
				bNextFrame = false; 
				bMoveMap = false; 
				goto _exit; 
			} 
			 
			//解除原来CELL的占据,并占据下一个CELL 
			theMap.NoHoldCell( m_BasePoint.y / CELL_HEIGHT, m_BasePoint.x / CELL_WIDTH ); 
			theMap.HoldCell( m_NextCell.row, m_NextCell.col ); 
			theMap.CellToPoint( m_NextCell, m_BasePoint ); 
			CalcPriority();								//重新计算优先级 
		} 
	} 
	else if ( m_State == SS_IDLE || m_State == SS_HURT )						//空闲或受伤状态 
	{ 
		if ( bUpdate ) 
		{	 
			SetState( SS_WAIT ); 
			bNextFrame = false; 
		} 
	} 
	else if ( m_State == SS_DEAD )						//死亡状态 
	{ 
		if ( m_SpriteType != ST_BODY ) 
		{ 
			m_HeroState = HS_DEAD; 
			m_pEnemy = NULL; 
			theMap.NoHoldCell( m_BasePoint.y / CELL_HEIGHT, m_BasePoint.x / CELL_WIDTH ); 
			m_SpriteType = ST_BODY; 
			CalcPriority();							//重新计算优先级,尸体的优先级要更低 
			ClearMagicState(); 
			theMsgMgr.AddMessage( "角色死亡" ); 
			theMsgMgr.AddMessage( "五秒后复活" ); 
		} 
		else if ( bUpdate  ) 
		{ 
			bNextFrame = false;							//死亡后,不再更新动作 
			if ( thisTick - m_move_frame > 15000 )	//死亡后,m_move_frame存储的是死亡时的时间 
			{ 
				GotoRevival(); 
				Cure(); 
			} 
		} 
	} 
	else if ( m_State >= SS_MELEE )				//博斗或施法状态 
	{ 
		if ( m_Frame == m_pClass->EPGArray.GetMiddleFrame( m_State ) ) 
		{ 
			if ( m_pMagic != NULL ) 
			{ 
				m_pMagic->OnHeroEffect( this, m_pEnemy ); 
			} 
			else 
			{ 
				if ( m_pEnemy != NULL && m_pEnemy->IsAlive() ) 
				{ 
					if ( CalcDistance( m_BasePoint, m_pEnemy->GetBasePoint() ) <= m_Distance ) 
					{ 
						GetNextDirection( m_pEnemy->GetBasePoint() ); 
						m_pEnemy->Hurt( m_PlusInfo.m_Damage, this );	//敌人受到伤害 
						m_pClass->SoundArray.meleeSound->Play(); 
					} 
				} 
			} 
		} 
		else if ( bUpdate ) 
		{ 
			m_HeroState = HS_END_FIGHT; 
			ClearCurMagic(); 
		} 
	} 
 
_exit: 
	if ( bMoveMap )	MoveMap(); 
	m_pg_frame = m_cur_pg->UpdateAliveSprite( bNextFrame, m_Frame, m_Direction,  
											  m_BasePoint, m_RenderPoint, m_Rect ); 
	return re; 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::DrawSprite() 
{ 
	if ( m_PathStack.IsEmpty() == false && m_State == SS_WALK ) 
	{ 
		CELL cell = m_PathStack.GetStack()[0]; 
		POINT p; 
		theMap.CellToPoint( cell, p ); 
 
		m_cp_pg->UpdateFrame( m_cp_frame, m_cp_last_tick ); 
		m_cp_pg->DrawFrame( m_cp_frame, p ); 
	} 
 
#ifdef ALPHA_SHADOW 
	m_cur_shadow_pg->DrawShadow( m_pg_frame, m_BasePoint ); 
#endif 
 
	m_cur_pg->DrawFrame( m_pg_frame, m_RenderPoint.x, m_RenderPoint.y ); 
	DrawMSE(); 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::DrawBloodBar() 
{ 
	//画血条,魔条: 
	m_HPBar.Draw( 0, 0, m_Life, m_pClass->SpriteInfo.m_MaxLife ); 
	m_MPBar.Draw( 0, 25, m_PlusInfo.m_Mana, m_pClass->SpriteInfo.m_MaxMana ); 
} 
 
const int MOVE_X = 8; 
const int MOVE_Y = 4; 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::MoveMap() 
{ 
	const RECT &view = theMap.GetViewer(); 
	int half_w = view.left + (view.right-view.left) / 2; 
	int half_h = view.top + (view.bottom-view.top) / 2; 
 
	switch ( m_Direction ) 
	{ 
	case 1: 
		if ( m_BasePoint.x >= half_w-64 ) 
			theMap.MoveMap( MOVE_X, 0 ); 
		break; 
					 
	case 2: 
		if ( m_BasePoint.y >= half_h-32 || m_BasePoint.x >= half_w-64 ) 
			theMap.MoveMap( MOVE_X, MOVE_Y ); 
		break; 
					 
	case 3: 
		if ( m_BasePoint.y >= half_h-32 ) 
			theMap.MoveMap( 0, MOVE_Y); 
		break; 
 
	case 4: 
		if ( m_BasePoint.x <= half_w+64 || m_BasePoint.y >= half_h-32 ) 
			theMap.MoveMap( -MOVE_X, MOVE_Y ); 
		break; 
 
	case 5: 
		if ( m_BasePoint.x <= half_w+64 ) 
			theMap.MoveMap( -MOVE_X, 0 ); 
		break; 
 
	case 6: 
		if ( m_BasePoint.x <= half_w+64 || m_BasePoint.y <= half_h+32 ) 
			theMap.MoveMap( -MOVE_X, -MOVE_Y ); 
		break; 
 
	case 7: 
		if ( m_BasePoint.y <= half_h+32 ) 
			theMap.MoveMap( 0, -MOVE_Y ); 
		break; 
 
	case 8: 
		if ( m_BasePoint.x >= half_w-64 || m_BasePoint.y <= half_h+32 ) 
			theMap.MoveMap( MOVE_X, -MOVE_Y ); 
		break; 
	} 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::Cure() 
{ 
	m_Life = m_pClass->SpriteInfo.m_MaxLife; 
	m_PlusInfo.m_Mana = m_pClass->SpriteInfo.m_MaxMana; 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
bool CHero::AddLife( int add ) 
{ 
	bool re = false; 
	if ( m_Life < m_pClass->SpriteInfo.m_MaxLife && m_State != SS_DEAD ) 
	{ 
		MAGIC_STATE ms; 
		ms.effectIndex = SI_ADDLIFE; 
		ms.effectValue = add; 
		ms.endTime = timeGetTime() + 2000; 
		AddMagicState( ms ); 
		m_PlusInfo.m_AddLife += add; 
		re = true; 
	} 
	return re; 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
bool CHero::AddMana( int add ) 
{ 
	bool re = false; 
	if ( m_PlusInfo.m_Mana < m_pClass->SpriteInfo.m_MaxMana && m_State != SS_DEAD ) 
	{ 
		MAGIC_STATE ms; 
		ms.effectIndex = SI_ADDMANA; 
		ms.effectValue = add; 
		ms.endTime = timeGetTime() + 2000; 
		AddMagicState( ms ); 
		m_PlusInfo.m_AddMana += add; 
		re = true; 
	} 
	return re; 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
bool CHero::ChangeMoney( int value ) 
{ 
	if ( m_Money + value <= 2000000000 && m_Money + value >= 0 ) 
	{ 
		m_Money += value; 
		return true; 
	} 
	return false; 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::AddHeroXp( int xp ) 
{ 
	int &heroXp = m_pClass->SpriteInfo.m_Xp; 
	short &lvl = m_pClass->SpriteInfo.m_Level; 
	heroXp += xp; 
	if ( heroXp >= m_NextLvlXp ) 
	{ 
		heroXp = 0; 
		m_NextLvlXp = lvl * ( 16 * ((lvl/4)+1) * ((lvl/8)+1) * ((lvl/32)+1) * ((lvl/32)+1) );; 
		lvl += 1; 
		m_RestPoint += 3; 
		theEquipmentBox.OnCloseEquipment();		//重新计算各项属性 
		theMsgMgr.AddMessage( "升级了" ); 
		theMsgMgr.AddMessage( "可以分配剩余点数" ); 
		Cure(); 
	} 
} 
 
//////////////////////////////////////////////////////////////////////// 
//拾取物品,distance为物品与英雄的距离 
//////////////////////////////////////////////////////////////////////// 
void CHero::PickItem( int distance ) 
{ 
	PTILE tile = theMap.GetTile( m_BasePoint.x, m_BasePoint.y ); 
	debug_assert( tile != NULL ); 
 
	CPool &pool = tile->m_APool; 
	for ( pool.Begin(); pool.IsNotNull(); pool.MoveNext() ) 
	{ 
		CBaseSprite *sprite = *(pool.GetCur()); 
		if ( sprite->GetSpriteType() == ST_ITEM ) 
		{ 
			if ( CalcDistance( m_BasePoint, sprite->GetBasePoint() ) <= distance ) 
			{ 
				bool b = theItemBag.AddItem( (CItem *)sprite ); 
			} 
		} 
	} 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::ClearItemInfo() 
{ 
	AS_BASE_INFO &baseInfo = m_pClass->SpriteInfo; 
	for ( int i = 0; i < 12; ++i ) 
		baseInfo.baseInfo[i] -= m_ItemBaseInfo.baseInfo[i];	//先把装备的属性减去 
 
	memset( &m_ItemBaseInfo, 0, sizeof(AS_BASE_INFO) ); 
	memset( &m_ItemPlusInfo, 0, sizeof(AS_PLUS_INFO) ); 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::AddHeroInfo( int index, int value ) 
{ 
	debug_assert( index >= SI_END && index <= SI_BEGIN ); 
 
	if ( index >= SI_THUNDER ) 
	{ 
		m_ItemBaseInfo.baseInfo[(-index) + SI_BEGIN] += value; 
	} 
	else if ( index <= SI_MP ) 
	{ 
		m_ItemPlusInfo.plusInfo[(-index) + SI_MP] += value; 
	} 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::CalcHeroInfo() 
{ 
	AS_BASE_INFO &baseInfo = m_pClass->SpriteInfo; 
	 
	for ( int i = 0; i < 12; ++i ) 
		baseInfo.baseInfo[i] += m_ItemBaseInfo.baseInfo[i];	//先把装备的属性加到基本属性上 
 
	int mana = m_PlusInfo.m_Mana; 
	ZeroMemory( &m_PlusInfo, sizeof(m_PlusInfo) ); 
	//计算最大生命值 生命=力量*4 + 敏捷*2 + 智力 + 等级*4 
	baseInfo.m_MaxLife = baseInfo.m_Strength * 4 + baseInfo.m_Agility * 2  
							+ baseInfo.m_Intelligence + baseInfo.m_Level * 4; 
 
	 
	baseInfo.m_MaxMana = baseInfo.m_Intelligence * 4 + baseInfo.m_Level;	//最大魔法值 = 智力 * 4 + 级别 
	m_PlusInfo.m_Accuracy = baseInfo.m_Agility + baseInfo.m_Level;			//计算命中率 = 敏捷 + 级别 
	m_PlusInfo.m_Resistance = baseInfo.m_Agility / 2 + baseInfo.m_Level / 4;//计算回避率 = 敏捷 / 2 + 级别 / 4 
	m_PlusInfo.m_Armor = baseInfo.m_Strength / 4 + baseInfo.m_Level / 4;	//计算防御 = 力量 / 4 + 级别/4 
 
	if ( m_HeroClass == SC_FENCER ) 
		m_PlusInfo.m_Damage = baseInfo.m_Strength / 2 + baseInfo.m_Level / 2;//伤害 = 力量 / 2 + 级别 / 2; 
	else 
		m_PlusInfo.m_Damage = baseInfo.m_Intelligence/ 2 + baseInfo.m_Level / 2; 
		 
	m_PlusInfo.m_Mana = mana; 
 
	baseInfo.baseInfo[1] += m_ItemBaseInfo.baseInfo[1];		//最大生命值 
	baseInfo.baseInfo[2] += m_ItemBaseInfo.baseInfo[2]; 
 
	for ( i = 0; i < 8; ++i ) 
		m_PlusInfo.plusInfo[i] += m_ItemPlusInfo.plusInfo[i];//附加属性 
 
	for ( i = 0; i < m_MagicStateArray.GetLength(); ++i ) 
	{ 
		MAGIC_STATE &state = m_MagicStateArray[i]; 
		AddInfo( state.effectIndex, state.effectValue );	//加上魔法状态的属性 
	} 
} 
 
//信息面版上各个属性显示的位置偏移 
//顺序:名字,等级,最大生命,最大魔法,力量,敏捷,知识,毒抗,诅抗,火抗,水抗,电抗,伤害,防御,回避,命中,经验,剩余点 
const POINT INFO_OFFSET[19] = { {62, 16}, {220, 15}, {229, 78}, {230, 110}, {62, 79}, {62, 112}, {63, 145}, {230, 143}, {230, 176}, {230, 208}, {230, 241}, {230, 272},  
{63, 176}, {63, 206}, {64, 239}, {64, 272}, {221, 46}, {63, 49}, {101, 300}}; 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::ShowHeroInfo() 
{ 
	if ( !m_isInfoDlgOpen ) return; 
 
	int x = ( g_pEasyDraw->GetDeviceWidth() - m_InfoSurface->GetWidth() ) / 2; 
	int y = ( g_pEasyDraw->GetDeviceHeight()- m_InfoSurface->GetHeight()) / 2; 
	m_InfoSurface->DrawSurface( x, y, 0 );				//绘制信息窗口在屏幕中央 
	 
	char sz[8]; 
	m_TempSurface->ClearSurface( 0, 0 ); 
	m_TempSurface->WriteText( m_HeroName, strlen(m_HeroName), 0, 0, 0xffffff ); 
	m_TempSurface->DrawSurface( x + INFO_OFFSET[0].x, y + INFO_OFFSET[0].y, 0 );		//绘制英雄名字 
 
	for ( int i = 0; i < 11; ++i )	//绘制等级,生,魔,力,敏,智,毒,诅,火,水,电 
	{ 
		wsprintf( sz, "%d", m_pClass->SpriteInfo.baseInfo[i] ); 
		m_TempSurface->ClearSurface( 0, 0 ); 
		m_TempSurface->WriteText( sz, strlen(sz), 0, 0, 0xffffff ); 
		m_TempSurface->DrawSurface( x + INFO_OFFSET[i+1].x, y + INFO_OFFSET[i+1].y, 0 ); 
	} 
 
	wsprintf( sz, "%d", m_pClass->SpriteInfo.m_Xp );			//经验 
	m_TempSurface->ClearSurface( 0, 0 ); 
	m_TempSurface->WriteText( sz, strlen(sz), 0, 0, 0xffffff ); 
	m_TempSurface->DrawSurface( x + INFO_OFFSET[16].x, y + INFO_OFFSET[16].y, 0 ); 
 
	wsprintf( sz, "%d", m_RestPoint );							//剩余点数 
	m_TempSurface->ClearSurface( 0, 0 ); 
	m_TempSurface->WriteText( sz, strlen(sz), 0, 0, 0xffffff ); 
	m_TempSurface->DrawSurface( x + INFO_OFFSET[17].x, y + INFO_OFFSET[17].y, 0 ); 
 
	for ( i = 1; i < 5; ++i ) 
	{ 
		wsprintf( sz, "%d", m_PlusInfo.plusInfo[i] ); 
		m_TempSurface->ClearSurface( 0, 0 ); 
		m_TempSurface->WriteText( sz, strlen(sz), 0, 0, 0xffffff ); 
		m_TempSurface->DrawSurface( x + INFO_OFFSET[i+11].x, y + INFO_OFFSET[i+11].y, 0 ); 
	} 
 
	wsprintf( sz, "%d", m_NextLvlXp );				//下一级经验值 
	m_TempSurface->ClearSurface( 0, 0 ); 
	m_TempSurface->WriteText( sz, strlen(sz), 0, 0, 0xffffff ); 
	m_TempSurface->DrawSurface( x + INFO_OFFSET[18].x, y + INFO_OFFSET[18].y, 0 ); 
} 
 
const RECT INFO_BUTTON[3] = { {127, 74, 150, 97}, {127, 107, 150, 130}, {127, 140, 150, 163}, }; 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
int CHero::UpdateInfoDlg() 
{ 
	if ( !m_isInfoDlgOpen ) return 0; 
 
	RECT rc; 
	rc.left = ( g_pEasyDraw->GetDeviceWidth() - m_InfoSurface->GetWidth() ) / 2; 
	rc.top = ( g_pEasyDraw->GetDeviceHeight()- m_InfoSurface->GetHeight()) / 2; 
	rc.right = rc.left + m_InfoSurface->GetWidth(); 
	rc.bottom= rc.top +  m_InfoSurface->GetHeight(); 
 
	int mx= theMouse.GetX(); 
	int my= theMouse.GetY(); 
 
	int re = 0; 
	 
	if ( mx >= rc.left && mx < rc.right  ) 
	{ 
		if ( my >= rc.top && my < rc.bottom ) 
		{ 
			re = 1; 
			if ( theMouse.IsLPress() ) 
			{ 
				if ( m_RestPoint > 0 ) 
				{ 
					for ( int i = 0; i < 3; ++i ) 
					{ 
						if ( mx >= rc.left + INFO_BUTTON[i].left && mx < rc.left + INFO_BUTTON[i].right ) 
						{ 
							if ( my >= rc.top + INFO_BUTTON[i].top && my < rc.top + INFO_BUTTON[i].bottom ) 
							{ 
								m_pClass->SpriteInfo.baseInfo[i+3]+=1; 
								m_RestPoint--; 
								theEquipmentBox.OnCloseEquipment(); 
								break; 
							} 
						} 
					} 
				} 
				if ( mx >= rc.left + 277 && mx < rc.right + 310 ) 
				{ 
					if ( my >= rc.top + 304 && my < rc.top + 337 ) 
						m_isInfoDlgOpen = false; 
				} 
			} 
		} 
	} 
 
	return re; 
} 
 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::SetCurMagic( int index ) 
{ 
	debug_assert( index >= 1 && index <= 10 ); 
	m_pCurSkill = &m_HeroSkillArray[index-1]; 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
bool CHero::Spell( CAliveSprite *pTarget, POINT &p ) 
{ 
	bool re = false; 
 
	if ( m_pCurSkill != NULL ) 
	{ 
		DWORD thisTime = timeGetTime(); 
		if ( thisTime - m_pCurSkill->lastTime > m_pCurSkill->interval ) 
		{ 
			m_pMagic = m_pCurSkill->pMagic; 
			m_pEnemy = pTarget; 
			m_Distance = m_pMagic->GetDistance(); 
			POINT dest = p; 
			if ( m_pMagic->IsSelf() ) 
			{ 
				pTarget = (CAliveSprite *)this; 
			} 
			else if ( m_pMagic->IsTarget() ) 
			{ 
				if ( pTarget == NULL ) 
				{ 
					m_pMagic = NULL; 
					return false; 
				} 
				else 
					dest = pTarget->GetBasePoint(); 
			} 
 
			if ( m_PlusInfo.m_Mana - m_pMagic->GetMana() > 0 ) 
			{ 
				re = true; 
 
				if ( CalcDistance( m_BasePoint, dest ) <= m_Distance ) 
				{ 
					GetNextDirection( dest ); 
					m_pMagic->OnHeroSpell( this, pTarget, dest ); 
					m_PlusInfo.m_Mana -= m_pMagic->GetMana(); 
					m_pCurSkill->lastTime = thisTime; 
					m_HeroState = HS_FIGHTING;	 
				} 
				else 
				{ 
					GetPath( dest ); 
					m_SpellPoint = dest; 
					m_HeroState = HS_GOTO_FIGHT; 
				} 
			} 
			else 
			{ 
				theMsgMgr.AddMessage( "精力不足" ); 
				m_pMagic = NULL; 
			} 
		} 
		else 
			theMsgMgr.AddMessage( "魔法尚未恢复" ); 
	} 
 
	return re; 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::ShowControlPanel() 
{ 
	int x = g_pEasyDraw->GetDeviceWidth() - m_GuiSurface->GetWidth(); 
	int y = g_pEasyDraw->GetDeviceHeight()- m_GuiSurface->GetHeight(); 
 
	m_GuiSurface->DrawSurface( x, y, 0 ); 
 
	//绘制技能卡片 
	if ( m_pCurSkill != NULL ) 
	{ 
		m_pCurSkill->cardSurface->DrawSurface( x + 27, y + 8, 0 ); 
		 
		unsigned int curTime = m_pCurSkill->interval - ( timeGetTime() - m_pCurSkill->lastTime ); 
		m_SkillBar.Draw( x + 67, y + 11, curTime, m_pCurSkill->interval ); 
	} 
} 
 
const RECT GUI_BUTTON[6] = { {19,62,41,85}, {47,62,70,85}, {76,62,100,85}, {19,91,41,114,}, {47,91,70,114}, {76,91,100,114} }; 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
int CHero::UpdateControlPanel( int re ) 
{ 
	if ( re == 0 ) 
	{ 
		int x = g_pEasyDraw->GetDeviceWidth() - m_GuiSurface->GetWidth(); 
		int y = g_pEasyDraw->GetDeviceHeight()- m_GuiSurface->GetHeight(); 
		int mx = theMouse.GetX(); 
		int my = theMouse.GetY(); 
 
		if ( mx >= x && mx < g_pEasyDraw->GetDeviceWidth() ) 
		{ 
			if ( my >= y && my < g_pEasyDraw->GetDeviceHeight() ) 
			{ 
				re = 1; 
				 
				if ( theMouse.IsLPress() ) 
				{ 
					if ( mx >= x + GUI_BUTTON[0].left && mx < x + GUI_BUTTON[0].right ) 
					{ 
						if ( my >= y + GUI_BUTTON[0].top && my < y + GUI_BUTTON[0].bottom ) 
							theItemBag.ChangeState(); 
					} 
					else if ( mx >= x + GUI_BUTTON[1].left && mx < x + GUI_BUTTON[1].right ) 
					{ 
						if ( my >= y + GUI_BUTTON[1].top && my < y + GUI_BUTTON[1].bottom ) 
							theEquipmentBox.ChangeState(); 
					} 
					else if ( mx >= x + GUI_BUTTON[2].left && mx < x + GUI_BUTTON[2].right ) 
					{ 
						if ( my >= y + GUI_BUTTON[2].top && my < y + GUI_BUTTON[2].bottom ) 
							ChangeInfoDlg(); 
					} 
				} 
			} 
		} 
	} 
 
	return re; 
} 
 
const CELL ROUND_CELL[8] = { CELL(0,1), CELL(1,1), CELL(1,0), CELL(1,-1), CELL(0,-1), CELL(-1,-1), CELL(-1,0), CELL(-1,1) }; 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::MoveHeroTo( const POINT &to ) 
{ 
	CELL dest, base; 
	theMap.PointToCell( to, dest ); 
	theMap.PointToCell( m_BasePoint, base ); 
 
	if ( theMap.IsCellHold( dest.row, dest.col ) ) 
	{ 
		bool b = false; 
		int dir = CalcDirection( dest, base )-1; 
		for ( int i = 0; i < 8; ++i ) 
		{ 
			dest.row += ROUND_CELL[dir].row; 
			dest.col += ROUND_CELL[dir].col; 
 
			if ( theMap.IsCellHold( dest.row, dest.col ) == false ) 
			{ 
				b = true; 
				break; 
			} 
 
			++dir; 
			dir %= 8; 
		} 
 
		if ( !b ) return;			//如果周围CELL无一可走	 
	} 
 
	theMap.NoHoldCell( base.row, base.col ); 
	theMap.HoldCell( dest.row, dest.col ); 
	theMap.CellToPoint( dest, m_BasePoint ); 
	CalcPriority(); 
	theMap.CalcViewerRect( m_BasePoint.x, m_BasePoint.y ); 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::SetRevival( const char *name ) 
{ 
	ZeroMemory( m_RevivalMapName, 32 ); 
	strcpy( m_RevivalMapName, name ); 
	theMsgMgr.AddMessage( "复活位置指定" ); 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::GotoRevival() 
{ 
	theGameManager.GotoMap( m_RevivalMapName, 1 ); 
	m_SpriteType = ST_HERO; 
	int frame_per_direction = m_pClass->EPGArray.epg_walk.pPG->GetFramePerDirection(); 
	if ( frame_per_direction % 2 == 0 ) 
		m_move_frame = frame_per_direction / 2 - 1; 
	else 
		m_move_frame = frame_per_direction / 2; 
} 
 
//////////////////////////////////////////////////////////////////////// 
//新建某职业的英雄 
//////////////////////////////////////////////////////////////////////// 
void CHero::NewHero( const char *heroName, HERO_CLASS heroClass ) 
{ 
	strcpy( m_HeroName, heroName ); 
	SetRevival( "zen_en.map" ); 
	m_HeroClass = heroClass; 
	AS_BASE_INFO &baseInfo = m_pClass->SpriteInfo; 
	ZeroMemory( &baseInfo, sizeof(baseInfo) ); 
	ZeroMemory( &m_ItemBaseInfo, sizeof(m_ItemBaseInfo) ); 
	ZeroMemory( &m_ItemPlusInfo, sizeof(m_ItemPlusInfo) ); 
	baseInfo.m_Level = 1; 
 
	if ( m_HeroClass == SC_FENCER ) 
	{ 
		baseInfo.m_Strength = 15; 
		baseInfo.m_Agility	= 10; 
		baseInfo.m_Intelligence=5; 
	} 
	else 
	{ 
		baseInfo.m_Strength = 5; 
		baseInfo.m_Agility	= 10; 
		baseInfo.m_Intelligence=15; 
	} 
 
	m_NextLvlXp = 16; 
	m_RestPoint = 0; 
	m_Money = 1000; 
	m_HeroState = HS_NORMAL; 
	m_pCurSkill = NULL; 
 
	CalcHeroInfo(); 
	Cure(); 
 
	LoadHeroRes( heroClass ); 
	theMap.SetNextMap( "..\\data\\zen_en.map" ); 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::SaveHero() 
{ 
	/******************************************************** 
	*为了保护游戏资源,此函数内容省略 
	********************************************************/ 
} 
 
//////////////////////////////////////////////////////////////////////// 
// 
//////////////////////////////////////////////////////////////////////// 
void CHero::LoadHero( const char *heroName ) 
{ 
	/******************************************************** 
	*为了保护游戏资源,此函数内容省略 
	********************************************************/ 
}