www.pudn.com > GameEngine_src.rar > CAliveSprite.cpp
#include "normal.h"
#include "CAliveSprite.h"
#include "CMap.h"
#include "CPathSeeker.h"
#include "BaseUtil.h"
#include "CHero.h"
#include "CSpriteFactory.h"
#include "CItemFactory.h"
#include "CMagic.h"
#include "EasyScript.h"
extern CHero theHero;
extern CMap theMap;
extern CPathSeeker thePathSeeker;
extern CSpriteFactory theSpriteFactory;
extern CItemFactory theItemFactory;
extern PEASYDRAW g_pEasyDraw;
//***********************************************MONSTER_CLASS构造与析构*************************************************
MONSTER_CLASS::MONSTER_CLASS()
{
NameSurface = NULL;
MagicIDArray= NULL;
memset( &EPGArray, 0, sizeof(AS_EPG_ARRAY) );
memset( &SoundArray, 0, sizeof(AS_SOUND_ARRAY) );
}
MONSTER_CLASS::~MONSTER_CLASS()
{
if ( NameSurface )
g_pEasyDraw->DeleteSurface( NameSurface );
if ( MagicIDArray )
delete [] MagicIDArray;
}
//***************************************************CCAliveSprite类定义*******************************************************
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
CAliveSprite::CAliveSprite()
{
}
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
CAliveSprite::~CAliveSprite()
{
//Free();
}
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
bool CAliveSprite::SetState( enum SPRITE_STATE state )
{
ALIVE_SPRITE_EPG &epg = m_pClass->EPGArray.epg_array[state];
if ( epg.pPG != NULL && epg.pSPG != NULL )
{
m_cur_pg = epg.pPG;
m_cur_shadow_pg = epg.pSPG;
m_State = state;
m_Frame = 0;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
bool CAliveSprite::Init( MONSTER_CLASS *pClass, const POINT &base, SPRITE_TYPE SpriteType )
{
m_pEnemy = NULL;
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_pClass = pClass;
m_SpriteType = SpriteType;
m_BasePoint.x = base.x;
m_BasePoint.y = base.y;
m_LastTime = timeGetTime();
CalcPriority();
CalcMonsterInfo();
if ( SpriteType == ST_MONSTER || 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;
SetState( SS_WAIT );
}
else if ( SpriteType == ST_N_B )
{
ALIVE_SPRITE_EPG &epg = m_pClass->EPGArray.epg_array[SS_WAIT];
m_cur_pg = epg.pPG;
m_cur_shadow_pg = epg.pSPG;
if ( epg.pSPG->GetNumFrame() == 0 )
m_cur_shadow_pg = NULL;
}
return true;
}
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
void CAliveSprite::Free()
{
}
////////////////////////////////////////////////////////////////////////
//更新精灵的状态,包围矩形,帧
//如果精灵死亡,移位则返回false
////////////////////////////////////////////////////////////////////////
bool CAliveSprite::UpdateSprite()
{
bool re = true;
bool bNextFrame = false; //是否更新下一帧
bool bUpdate = 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;
//怪物不需更新MANA..............
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 ( bUpdate )
{
int n = rand() % 128; //随机进入空闲或乱走状态
if ( n > 64 )
{
SetState(SS_IDLE);
bNextFrame = false;
}
else if ( n > 32 )
{
SetDirection( (n % 8) + 1 );
}
else
{
CELL cell;
theMap.PointToCell( m_BasePoint, cell );
n = ( n % 8 ) - 4;
cell.row += n;
cell.col += n;
if ( GetPath( cell ) )
bNextFrame = false;
}
}
else
{
SetEnemy( &theHero );
if ( m_pEnemy->IsAlive() ) //如果敌人活着,决定攻击方式和距离
{
if ( m_pClass->MagicIDArray != NULL ) //如果有魔法
{
int n = rand() % 128;
if ( m_pClass->EPGArray.epg_melee.pPG == NULL ||
( m_pClass->EPGArray.epg_melee.pPG != NULL && n > 100 ) ) //如果既有魔法,也可近战
{
m_pMagic = m_pClass->MagicIDArray[n%m_pClass->NumMagic].pMagic;
m_Distance = m_pMagic->GetDistance();
}
}
else
{
m_pMagic = NULL;
m_Distance = 1;
}
if ( CalcDistance( m_BasePoint, m_pEnemy->GetBasePoint() ) <= m_Distance )
{
if ( m_pMagic == NULL )
SetState( SS_MELEE );
else
m_pMagic->OnSpell( this, m_pEnemy );
GetNextDirection( m_pEnemy->GetBasePoint() );
bNextFrame = false;
}
else
{
if ( GetPath(m_pEnemy->GetBasePoint()) )
bNextFrame = false;
}
}
}
}
else if ( m_State == SS_WALK ) //行走状态
{
if ( bUpdate ) //如果完成了一步
{
if ( m_pEnemy != NULL && m_pEnemy->IsAlive() ) //如果敌人活着,判断与敌人的距离
{
if ( CalcDistance( m_BasePoint, m_pEnemy->GetBasePoint() ) <= m_Distance )
{
if ( m_pMagic == NULL )
SetState( SS_MELEE );
else
m_pMagic->OnSpell( this, m_pEnemy );
GetNextDirection( m_pEnemy->GetBasePoint() );
bNextFrame = false;
goto _exit;
}
else
{
GetPath( m_pEnemy->GetBasePoint() ); //如果不在距离之内,重新寻路
}
}
if ( m_PathStack.Pop( m_NextCell ) ) //如果还没走完,获取下一步
{
POINT p;
theMap.CellToPoint( m_NextCell, p );
GetNextDirection( p ); //获取下一步方向
}
else
{
SetState( SS_WAIT ); //如果已经走完,进入静止状态
bNextFrame = 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;
goto _exit;
}
PTILE old_tile = theMap.GetTile( m_BasePoint.x, m_BasePoint.y );
PTILE new_tile = theMap.GetTile( m_NextCell.col * CELL_WIDTH, m_NextCell.row * CELL_HEIGHT );
if ( old_tile != new_tile )
{ //如果精灵不在原来的TILE里,则把精灵移到MovingSpritePool
if ( theMap.AddMovingSprite( (CBaseSprite *)this ) )
{
re = false; //设置返回值为false,这样精灵将会被从TILE的链表中删除
}
else
{
SetState( SS_WAIT );
bNextFrame = 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(); //重新计算优先级
PEASYSOUND sound = m_pClass->SoundArray.walkSound;
if ( sound != NULL ) sound->Play();
}
}
else if ( m_State == SS_IDLE || m_State == SS_HURT ) //空闲或受伤状态
{
if ( bUpdate )
{
SetState( SS_WAIT );
bNextFrame = false;
}
}
else if ( m_State == SS_DEAD ) //死亡状态
{
if ( bUpdate )
{
bNextFrame = false; //死亡后,不再更新动作
if ( m_SpriteType != ST_BODY )
{
theHero.AddHeroXp( m_pClass->SpriteInfo.m_Xp ); //增加英雄经验
theMap.NoHoldCell( m_BasePoint.y / CELL_HEIGHT, m_BasePoint.x / CELL_WIDTH );
theItemFactory.CreateItemOnGround( m_BasePoint, m_pClass->SpriteInfo.m_Level,
thisTick + m_BasePoint.x + m_BasePoint.y );
m_SpriteType = ST_BODY;
CalcPriority(); //重新计算优先级,尸体的优先级要更低
ClearMagicState();
}
else if ( thisTick - m_move_frame > 30000 ) //死亡后,m_move_frame存储的是死亡时的时间
{
theSpriteFactory.DeleteMonster( this );
return false;
}
}
}
else if ( m_State >= SS_MELEE ) //战斗状态
{
if ( m_Frame == m_pClass->EPGArray.GetMiddleFrame( m_State ) )
{
if ( CalcDistance( m_BasePoint, m_pEnemy->GetBasePoint() ) <= m_Distance )
{
GetNextDirection( m_pEnemy->GetBasePoint() );
if ( m_pMagic == NULL )
m_pEnemy->Hurt( m_PlusInfo.m_Damage, this );
else
m_pMagic->OnEffect( this, m_pEnemy );
}
PEASYSOUND sound = m_pClass->SoundArray.meleeSound;
if ( sound != NULL ) sound->Play();
}
else if ( bUpdate )
{
if ( m_pMagic == NULL && m_pEnemy->IsAlive() )
{
if ( CalcDistance( m_BasePoint, m_pEnemy->GetBasePoint() ) > m_Distance )
{
if ( GetPath(m_pEnemy->GetBasePoint()) == false )
SetState( SS_WAIT );
bNextFrame = false;
}
}
else
{
SetState( SS_WAIT ); //进入静止状态再作反应
bNextFrame = false;
}
}
}
_exit:
//更新当前帧与RECT
m_pg_frame = m_cur_pg->UpdateAliveSprite( bNextFrame, m_Frame, m_Direction,
m_BasePoint, m_RenderPoint, m_Rect );
return re;
}
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
void CAliveSprite::DrawSprite()
{
#ifdef ALPHA_SHADOW
if ( m_SpriteType != ST_BODY )
m_cur_shadow_pg->DrawShadow( m_pg_frame, m_BasePoint );
#endif
if ( m_bSelected )
{
m_cur_pg->DrawContour( m_pg_frame, m_RenderPoint.x, m_RenderPoint.y );
POINT render;
render.x = m_BasePoint.x;
render.y = m_BasePoint.y - m_pClass->MaxHeight;
theMap.MapToClient( render );
theSpriteFactory.DrawBloodBar( render.x, render.y, m_Life, m_pClass->SpriteInfo.m_MaxLife, m_pClass->NameSurface );
m_bSelected = false;
}
else
m_cur_pg->DrawFrame( m_pg_frame, m_RenderPoint.x, m_RenderPoint.y );
DrawMSE();
}
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
void CAliveSprite::DrawShadow()
{
if ( m_cur_shadow_pg != NULL )
m_cur_shadow_pg->DrawFrame( m_pg_frame, m_BasePoint );
}
////////////////////////////////////////////////////////////////////////
//绘制魔法状态动画:
////////////////////////////////////////////////////////////////////////
void CAliveSprite::DrawMSE()
{
for ( int i = m_MSEArray.GetLength()-1; i >=0; --i )
{
MAGIC_STATE_EPG &mse = m_MSEArray[i];
int h = m_Rect.bottom - m_Rect.top;
h = h >> (int)mse.drawType; //动画位置可能在怪物的上,中,下
POINT render;
render.x = (m_Rect.right + m_Rect.left)>>1;
render.y = m_Rect.bottom - h;
mse.pEPG->DrawFrame( mse.curFrame, render );
}
}
/*////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
bool CAliveSprite::IsSelected( int x, int y )
{
if ( x > m_Rect.left && x < m_Rect.right )
{
if ( y > m_Rect.top && y < m_Rect.bottom )
{
return true; //m_cur_pg->GetSurface(m_pg_frame)->IsSurfaceSelected( x-m_Rect.left, y-m_Rect.top );
}
}
return false;
}*/
//////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////
void CAliveSprite::GetNextDirection( const POINT &next )
{
int x_odds = next.x - m_BasePoint.x;
int y_odds = next.y - m_BasePoint.y;
if ( x_odds > 0 )
{
if ( y_odds == 0 ) m_Direction = 1;
else if ( y_odds > 0 ) m_Direction = 2;
else m_Direction = 8;
}
else if ( x_odds == 0 )
{
if ( y_odds > 0 ) m_Direction = 3;
else m_Direction = 7;
}
else
{
if ( y_odds == 0 ) m_Direction = 5;
else if ( y_odds > 0 ) m_Direction = 4;
else m_Direction = 6;
}
}
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
bool CAliveSprite::GetPath( CELL &dest )
{
CELL cell;
theMap.PointToCell( m_BasePoint, cell );
bool re = false;
if ( thePathSeeker.SeekPath( m_PathStack, cell, dest, m_SpriteType ) == true )
{
if ( SetState( SS_WALK ) )
{
m_Frame = m_pClass->EPGArray.GetLastFrame(SS_WALK);
m_NextCell.row = m_BasePoint.y * CELL_HEIGHT;
m_NextCell.col = m_BasePoint.x * CELL_WIDTH;
re = true;
}
}
else
{
if ( m_SpriteType == ST_HERO )
m_PathStack.Clear();
}
return re;
}
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
bool CAliveSprite::GetPath( const POINT &p )
{
CELL cell;
theMap.PointToCell( p, cell );
return GetPath( cell );
}
////////////////////////////////////////////////////////////////////////
//被攻击
//参数:攻击者的伤害值, 攻击者的指针
////////////////////////////////////////////////////////////////////////
void CAliveSprite::Hurt( int damage, CAliveSprite *sprite )
{
//rand()%敌人的命中 > 自己的回避率
if ( GetRandomNum(sprite->m_PlusInfo.m_Accuracy) > m_PlusInfo.m_Resistance )
{
int hurt = damage - m_PlusInfo.m_Armor;
if ( hurt <= 0 )
hurt = 1;
if ( m_Life > 0 )
{
m_Life -= hurt;
PEASYSOUND sound = m_pClass->SoundArray.hurtSound;
if ( m_Life <= 0 && m_State != SS_DEAD )
{
m_Life = 0;
SetState( SS_DEAD );
ClearMagicState();
m_move_frame = m_LastTick; //死亡后,m_move_frame存储死亡的时间
sound = m_pClass->SoundArray.deadSound;
}
else if ( (int)m_State <= 1 || ( m_State == SS_WALK && m_Frame == 0 ) )
{
SetEnemy( sprite );
SetState( SS_HURT );
}
//必须重新计算m_pg_frame 因为可能不会调用UpdateSprite
m_pg_frame = m_cur_pg->UpdateAliveSprite( false, m_Frame, m_Direction,
m_BasePoint, m_RenderPoint, m_Rect );
if ( sound != NULL )
sound->Play();
}
}
}
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
inline int CAliveSprite::GetRandomNum( int size )
{
srand( m_LastTick );
return rand() % size;
}
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
int CAliveSprite::GetInfo( int index )
{
debug_assert( index >= SI_END && index <= SI_BEGIN );
int re = 0;
if ( index >= SI_THUNDER )
{
re = m_pClass->SpriteInfo.baseInfo[(-index) + SI_BEGIN];
}
else if ( index <= SI_MP )
{
re = m_PlusInfo.plusInfo[(-index) + SI_MP];
}
else if ( index == SI_HP )
{
re = m_Life;
}
return re;
}
////////////////////////////////////////////////////////////////////////
//改变某一属性的值,不能是生命
////////////////////////////////////////////////////////////////////////
void CAliveSprite::AddInfo( int index, int value )
{
debug_assert( index >= SI_END && index <= SI_BEGIN );
if ( index >= SI_THUNDER ) //-27
{
m_pClass->SpriteInfo.baseInfo[(-index) + SI_BEGIN] += value;
if ( m_Life > m_pClass->SpriteInfo.m_MaxLife ) m_Life = m_pClass->SpriteInfo.m_MaxLife;
}
else if ( index <= SI_MP ) //-30
{
m_PlusInfo.plusInfo[(-index) + SI_MP] += value;
}
else
debug_assert( false );
}
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
void CAliveSprite::MagicHurt( int magicClass, int damage, CAliveSprite *enemy )
{
debug_assert( magicClass >= MC_END && magicClass <= MC_BEGIN );
if ( magicClass != MI_PHYSICS )
{
int rs = m_PlusInfo.m_Armor;
if ( magicClass != MI_SWORD )
rs = m_pClass->SpriteInfo.baseInfo[(-magicClass)-33];
damage -= rs;
if ( damage <= 0 ) damage = 1;
if ( m_Life > 0 )
{
m_Life -= damage;
PEASYSOUND sound = m_pClass->SoundArray.hurtSound;
if ( m_Life <= 0 && m_State != SS_DEAD )
{
m_Life = 0;
SetState( SS_DEAD );
ClearMagicState();
m_move_frame = m_LastTick; //死亡后,m_move_frame存储死亡的时间
sound = m_pClass->SoundArray.deadSound;
if ( sound ) sound->Play();
}
else if ( (int)m_State <= 1 )
{
SetState( SS_HURT );
if ( sound ) sound->Play();
}
//必须重新计算m_pg_frame 因为可能不会调用UpdateSprite
m_pg_frame = m_cur_pg->UpdateAliveSprite( false, m_Frame, m_Direction,
m_BasePoint, m_RenderPoint, m_Rect );
}
}
else
{
Hurt( damage, enemy ); //物理伤害还要计算命中和回避
}
}
////////////////////////////////////////////////////////////////////////
//删除所有魔法状态和魔法状态动画
////////////////////////////////////////////////////////////////////////
void CAliveSprite::ClearMagicState()
{
for ( int i = m_MagicStateArray.GetLength()-1; i >= 0; --i ) //更新魔法状态
{
MAGIC_STATE &ms = m_MagicStateArray[i];
AddInfo( ms.effectIndex, -ms.effectValue ); //还原作用值
}
m_MagicStateArray.Free();
m_MSEArray.Free();
}
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
void CAliveSprite::CalcInfo()
{
}
////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////
void CAliveSprite::CalcMonsterInfo()
{
ZeroMemory( &m_PlusInfo, sizeof(m_PlusInfo) );
AS_BASE_INFO &baseInfo = m_pClass->SpriteInfo;
//计算最大生命值 生命=智力
baseInfo.m_MaxLife = baseInfo.m_Intelligence;
//最大魔法值 = 智力 * 4 + 级别
baseInfo.m_MaxMana = baseInfo.m_Intelligence * 4 + baseInfo.m_Level;
//计算命中率 = 敏捷
m_PlusInfo.m_Accuracy = baseInfo.m_Agility;
//计算回避率 = 敏捷 / 2
m_PlusInfo.m_Resistance = baseInfo.m_Agility / 2;
//计算防御 = 力量
m_PlusInfo.m_Armor = baseInfo.m_Strength / 2;
//伤害 = 力量
m_PlusInfo.m_Damage = baseInfo.m_Strength;
m_Life = baseInfo.m_MaxLife;
m_PlusInfo.m_Mana = baseInfo.m_MaxMana;
}