2897 lines
85 KiB
C++
2897 lines
85 KiB
C++
#include "StdAfx.h"
|
||
#include "SkillSubSystem.h"
|
||
#include "SkillCondition.h"
|
||
|
||
//处理网络消息
|
||
void CSkillSubSystem::ProcessNetData(INT_PTR nCmd,CDataPacketReader &packet )
|
||
{
|
||
if(m_pEntity == NULL)
|
||
{
|
||
return;
|
||
}
|
||
WORD nSkillID = 0;
|
||
EntityHandle handle;
|
||
WORD nPosX=0, nPosY=0;
|
||
BYTE bDir,bFlag;
|
||
INT_PTR nErrorCode = tpNoError;
|
||
BYTE bType = 0;
|
||
BYTE bUseYB = 0;
|
||
if (m_pEntity == NULL || m_pEntity->IsDeath())
|
||
{
|
||
m_pEntity->SetCommonOpNextTime(900, false, false);
|
||
((CActor *)m_pEntity)->SendOperateResult(true, 0, 0, false);
|
||
return;
|
||
}
|
||
switch(nCmd)
|
||
{
|
||
//这个留着,下发已经学习的技能列表
|
||
case cGetSkill:
|
||
{
|
||
SendLearnSkill();
|
||
}
|
||
break;
|
||
//近身攻击
|
||
case cNearAttack:
|
||
{
|
||
packet >> handle >> bDir;
|
||
m_pEntity->SetTarget(handle);
|
||
|
||
m_pEntity->SetDir(bDir & 7);
|
||
|
||
const float normal_attack_interval = 750;//ms 客户端是900
|
||
float attack_accelerate_per = 1 + (((float)m_pEntity->GetProperty<int>(PROP_ACTOR_NORMAL_ATK_ACC)) / 10000);
|
||
int final_interval = static_cast<int>(normal_attack_interval / attack_accelerate_per);
|
||
//近身攻击CD ,时间过短的玩家可能是用的挂
|
||
if(!((CActor *)m_pEntity)->CheckAttackOpTick())
|
||
{
|
||
const float attack_interval = 900;//ms 客户端是900
|
||
int normal_interval = static_cast<int>(attack_interval / attack_accelerate_per);
|
||
|
||
//使用挂 或者发包机
|
||
OutputMsg(rmWaning,"[WG] 玩家 = %d Actorname=%s, Attack for speed check, normal:%d", ((CActor*)m_pEntity)->GetId(), m_pEntity->GetEntityName(), (int)normal_interval);
|
||
|
||
m_pEntity->SetCommonOpNextTime(final_interval, false, false);
|
||
|
||
((CActor *)m_pEntity)->SendOperateResult(true, 0, 0, false);
|
||
break;
|
||
}
|
||
|
||
//特殊处理:检测战士相关的技能
|
||
CEntity * pEntity = GetEntityFromHandle(m_pEntity->GetTarget());
|
||
if(CheckNextSkillFlag(pEntity))
|
||
{
|
||
nErrorCode = NearAttack(handle,0,0); //有2个参数无效,需要重新计算
|
||
}
|
||
|
||
// const float normal_attack_interval = 750;//ms 客户端是900
|
||
// float attack_accelerate_per = 1 + (((float)m_pEntity->GetProperty<int>(PROP_ACTOR_NORMAL_ATK_ACC)) / 10000);
|
||
// int final_interval = static_cast<int>(normal_attack_interval / attack_accelerate_per);
|
||
|
||
if(nErrorCode)
|
||
{
|
||
//m_pEntity->SetCommonOpNextTime((INT_PTR)(1.6* m_pEntity->GetProperty<unsigned int>(PROP_CREATURE_ATTACK_SPEED)),false,false,0,0,true,true,false );
|
||
m_pEntity->SetCommonOpNextTime(final_interval,false,false,0,0,true,true,false );
|
||
((CActor *)m_pEntity)->SendOperateResult(false, 0, 0, false);
|
||
}
|
||
else
|
||
{
|
||
//m_pEntity->SetCommonOpNextTime((INT_PTR)(1.6* m_pEntity->GetProperty<unsigned int>(PROP_CREATURE_ATTACK_SPEED)),false,false );
|
||
m_pEntity->SetCommonOpNextTime(final_interval, false, false);
|
||
((CActor *)m_pEntity)->SendOperateResult(true, 0, 0, false);
|
||
//m_pEntity->SetCommonOpNextTime( 1.6* m_pEntity->GetProperty<unsigned int>(PROP_CREATURE_ATTACK_SPEED),true,true );
|
||
}
|
||
}
|
||
break;
|
||
//开启技能
|
||
case cOpenSkill :
|
||
{
|
||
packet >> nSkillID;
|
||
SwitchSkill(nSkillID,1);
|
||
}
|
||
break;
|
||
//关闭技能
|
||
case cCloseSkill :
|
||
{
|
||
packet >> nSkillID;
|
||
SwitchSkill(nSkillID,0);
|
||
}
|
||
break;
|
||
//使用技能
|
||
case cUseSkill :
|
||
{
|
||
packet >> nSkillID;
|
||
packet >> handle >> nPosX >> nPosY >> bDir;//句柄坐标方向都是目标的
|
||
|
||
//是否为及时技能
|
||
CBuffProvider::BUFFCONFIG* pBuffConf = GetLogicServer()->GetDataProvider()->GetBuffProvider().GetBuffBySkillId(nSkillID);
|
||
if(pBuffConf != NULL)
|
||
{
|
||
nErrorCode = tpSkillConfigError;
|
||
}
|
||
else
|
||
{
|
||
nErrorCode = CheckSpellTarget(nSkillID, handle, nPosX, nPosY, bDir);//设置目标,设置方向
|
||
}
|
||
|
||
if (tpNoError == nErrorCode)
|
||
{
|
||
nErrorCode = LaunchSkill(nSkillID,nPosX,nPosY);
|
||
}
|
||
if (nErrorCode)
|
||
{
|
||
((CActor *)m_pEntity)->SendOperateResult(false,0,0,false);
|
||
}
|
||
else
|
||
{
|
||
((CActor *)m_pEntity)->SendOperateResult(true,0,0,false);
|
||
}
|
||
|
||
}
|
||
break;
|
||
//升级技能
|
||
case cTrainSkill :
|
||
{
|
||
packet >> nSkillID;
|
||
nErrorCode = LearnSkill(nSkillID, GetSkillLevel(nSkillID) + 1); //学习下一级的技能
|
||
if(nErrorCode){
|
||
((CActor *)m_pEntity)->SendTipmsgWithId(tmItemCantLearnSkill,tstUI);
|
||
}
|
||
|
||
}
|
||
break;
|
||
//同步CD
|
||
case cGetCd:
|
||
packet >> nSkillID;
|
||
OnGetCd(nSkillID);
|
||
break;
|
||
//设置默认技能
|
||
case cSetDefaultSkill:
|
||
packet >> nSkillID;
|
||
SetDefaultSkill(nSkillID);
|
||
break;
|
||
|
||
case cStartGather:
|
||
{
|
||
packet >> handle >> nPosX >> nPosY >> bDir;
|
||
GatherMonster(handle, nPosX, nPosY, bDir);
|
||
return;
|
||
}
|
||
case cSetSkillOpen: //设置技能开启
|
||
{
|
||
packet >> nSkillID >> bFlag ;
|
||
|
||
HandSetSkillOpen(nSkillID,bFlag);
|
||
return;
|
||
}
|
||
}
|
||
|
||
// if( nErrorCode != tpNoError)
|
||
// {
|
||
// if(cTrainSkill == nCmd)
|
||
// {
|
||
// ((CActor *)m_pEntity)->SendTipmsgFormatWithId(nErrorCode, tstUI);
|
||
// }
|
||
// else
|
||
// {
|
||
// if(nErrorCode != tpSkillSpellNoTarget)
|
||
// {
|
||
// ((CActor *)m_pEntity)->SendTipmsgFormatWithId(nErrorCode,tstUI);
|
||
// }
|
||
// }
|
||
// }
|
||
}
|
||
|
||
void CSkillSubSystem::HandStartSkillCD(INT_PTR nSkillId)
|
||
{
|
||
PSKILLDATA pSkillData = GetSkillInfoPtr(nSkillId);
|
||
if(pSkillData ==NULL )return;
|
||
|
||
TICKCOUNT nCurTick = GetGlobalLogicEngine()->getTickCount();
|
||
TICKCOUNT nOldTick = pSkillData->tick;
|
||
if( nOldTick >= nCurTick )
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
void CSkillSubSystem::DelSkillCdTemporary(INT_PTR nSkill)
|
||
{
|
||
if (!m_pEntity) return;
|
||
PSKILLDATA pSkillData = GetSkillInfoPtr(nSkill);
|
||
if(pSkillData ==NULL )return;
|
||
//如果本身的cd就已经转到了,就不需要发数据包给客户端处理了
|
||
if(pSkillData->tick > GetGlobalLogicEngine()->getTickCount())
|
||
{
|
||
pSkillData->nCd =0;
|
||
pSkillData->tick =0; //直接删除一个技能的CD
|
||
if(m_pEntity->GetType() ==enActor ) //如果本身是一个玩家的话
|
||
{
|
||
CActorPacket pack;
|
||
CDataPacket & data = ((CActor*)m_pEntity)->AllocPacket(pack);
|
||
data << (BYTE) enSkillSystemID << (BYTE) sSendSkillCd;
|
||
data << (WORD) nSkill ;
|
||
data << (int) 0;
|
||
pack.flush();
|
||
}
|
||
}
|
||
}
|
||
|
||
INT_PTR CSkillSubSystem::CheckSpellTarget(INT_PTR nSkillID,EntityHandle nTarget, WORD& nDestX, WORD& nDestY, INT_PTR nDir)
|
||
{
|
||
if (!m_pEntity) return tpSkillConfigError;
|
||
int nX, nY;
|
||
|
||
//检查common操作时间
|
||
const OneSkillData * pData = GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(nSkillID);
|
||
if (!pData)
|
||
{
|
||
return tpSkillConfigError;//没有学习技能
|
||
}
|
||
|
||
//检测特殊的buff是否存在
|
||
if(INT_PTR nErrorID = CheckSpecialBuff(pData))
|
||
{
|
||
return nErrorID;
|
||
}
|
||
|
||
//打断正在准备的技能
|
||
if (nTarget != 0 && nTarget != m_pEntity->GetHandle())
|
||
{
|
||
//检查目标是否有效
|
||
CEntity *pTarget = GetEntityFromHandle(nTarget);
|
||
if (!pTarget)
|
||
{
|
||
//如果是玩家的目标为空的话,应该是没有向客户端下发实体消失的消息,向其下发一个
|
||
if(m_pEntity->GetType() == enActor)
|
||
{
|
||
m_pEntity->GetObserverSystem()->EntityDisappear(nTarget);
|
||
}
|
||
return tpSkillSpellNoTarget;//无效的目标
|
||
}
|
||
|
||
//是否处于同一场景判断
|
||
if ( !pTarget->GetFuBen() || !m_pEntity->GetFuBen() || pTarget->GetFuBen()->GetFbId() != m_pEntity->GetFuBen()->GetFbId()
|
||
|| !pTarget->GetScene() || !m_pEntity->GetScene() || pTarget->GetScene()->GetSceneId() != m_pEntity->GetScene()->GetSceneId())
|
||
{
|
||
return tpSkillSpellNoTarget;//无效的目标
|
||
}
|
||
|
||
//检查目标距离
|
||
pTarget->GetPosition(nX, nY);
|
||
//有目标选择时,坐标重置成目标当前位置
|
||
nDestX = nX;
|
||
nDestY = nY;
|
||
|
||
if (abs(nX - nDestX) >MOVE_GRID_ROW_RADIO || abs(nY - nDestY) > MOVE_GRID_ROW_RADIO)
|
||
{
|
||
return tpSkillTrainDistance;//与目标距离太远
|
||
}
|
||
m_pEntity->SetTarget(nTarget);
|
||
}
|
||
else
|
||
{
|
||
EntityHandle curTarget = m_pEntity->GetTarget();
|
||
|
||
if(nTarget != curTarget)
|
||
{
|
||
m_pEntity->SetTarget(nTarget);
|
||
}
|
||
|
||
// 特殊处理(治愈术,若目标为空地,则目标设为自己)
|
||
if (nSkillID == 22 && nTarget == 0)
|
||
{
|
||
m_pEntity->SetTarget(m_pEntity->GetHandle());
|
||
}
|
||
|
||
//是否处于同一场景判断
|
||
CEntity *pTarget = GetEntityFromHandle(m_pEntity->GetTarget());
|
||
if ( pTarget )
|
||
{
|
||
if ( !pTarget->GetFuBen() || !m_pEntity->GetFuBen() || pTarget->GetFuBen()->GetFbId() != m_pEntity->GetFuBen()->GetFbId()
|
||
|| !pTarget->GetScene() || !m_pEntity->GetScene() || pTarget->GetScene()->GetSceneId() != m_pEntity->GetScene()->GetSceneId() )
|
||
{
|
||
return tpSkillSpellNoTarget;//无效的目标
|
||
}
|
||
}
|
||
|
||
m_pEntity->GetPosition(nX, nY);
|
||
|
||
//施法位置是自己的位置,设置朝向为客户端决定的朝向
|
||
if (nDestX == nX && nDestY == nY)
|
||
{
|
||
m_pEntity->SetDir(nDir & 7);
|
||
}
|
||
else
|
||
{
|
||
if ( pData->btClientDir == 0 )
|
||
{
|
||
//定点施法,设置朝向为施法点的方向
|
||
if(nDestX !=0 || nDestY !=0 )
|
||
{
|
||
nDir = CEntity::GetDir(nX, nY, nDestX, nDestY);
|
||
}
|
||
}
|
||
|
||
if(nDir >=0 && nDir < DIR_STOP )
|
||
{
|
||
m_pEntity->SetDir(nDir);
|
||
}
|
||
}
|
||
}
|
||
|
||
return tpNoError;
|
||
}
|
||
|
||
void CSkillSubSystem::SetDefaultSkill(INT_PTR nSkillID)
|
||
{
|
||
if (!m_pEntity) return;
|
||
if(nSkillID ==0) return ;
|
||
m_pEntity->SetProperty<unsigned int>(PROP_ACTOR_DEFAULT_SKILL, (UINT)nSkillID);
|
||
}
|
||
|
||
//近身攻击目标
|
||
INT_PTR CSkillSubSystem::NearAttack(EntityHandle targetHandle, INT_PTR nActionID ,INT_PTR nEffectID)
|
||
{
|
||
if (!m_pEntity) return tpSkillTrainWithBuff;
|
||
//检测特殊的buff是否存在
|
||
CBuffSystem *pBuff = m_pEntity->GetBuffSystem();
|
||
//麻痹
|
||
INT_PTR ndizzy = m_pEntity->GetProperty<int>(PROP_CREATURE_DIZZY_STATUS);
|
||
if(pBuff && (pBuff->Exists( aDizzy ) || pBuff->Exists(aSlient)) || ndizzy)
|
||
{
|
||
return tpSkillTrainWithBuff;
|
||
}
|
||
|
||
if (m_pEntity->GetType() == enActor)
|
||
{
|
||
if(! m_pEntity->CheckCommonOpTick(((CActor*)m_pEntity)->GetGateNetWorkTickCount() + 50, false) )
|
||
{
|
||
return tpSkillSellCDLimited;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if(! m_pEntity->CheckCommonOpTick( GetLogicCurrTickCount() ) )
|
||
{
|
||
return tpSkillSellCDLimited;
|
||
}
|
||
}
|
||
|
||
BroadSpellSkill(0,nActionID,m_pEntity->GetProperty<unsigned int>(PROP_ENTITY_DIR),nEffectID);
|
||
|
||
CEntity * pEntity = GetEntityFromHandle(m_pEntity->GetTarget());
|
||
if(pEntity ==NULL || !pEntity->isAnimal()) return tpSkillSpellNoTarget;
|
||
|
||
//是否处于同一场景判断
|
||
if ( !pEntity->GetFuBen() || !m_pEntity->GetFuBen() || pEntity->GetFuBen()->GetFbId() != m_pEntity->GetFuBen()->GetFbId()
|
||
|| !pEntity->GetScene() || !m_pEntity->GetScene() || pEntity->GetScene()->GetSceneId() != m_pEntity->GetScene()->GetSceneId())
|
||
{
|
||
return tpSkillSpellNoTarget;
|
||
}
|
||
|
||
//目标不可攻击
|
||
GAMEATTRVALUE value;
|
||
value.nValue = 1;
|
||
if( !m_targetCondition.CanAttack(m_pEntity,(CAnimal*)pEntity,value ) )
|
||
{
|
||
//OutputMsg(rmTip, _T("不能攻击,但临时改为可攻击。"));
|
||
// if (m_pEntity->GetType() == enActor)
|
||
// {
|
||
// ((CActor *)m_pEntity)->SendTipmsgWithId(tmTarCantAttack,tstFigthing);
|
||
// }
|
||
return tpNoError;
|
||
}
|
||
|
||
//攻击距离限制
|
||
if( GetAttackDistance(m_pEntity,pEntity) > 2 )
|
||
{
|
||
return tpSkillTrainDistance;
|
||
}
|
||
|
||
SKILLRESULT result; //技能的结果
|
||
result.nDelay = 300;
|
||
result.nValue =0;
|
||
result.nId = 10000; //都是100攻击
|
||
result.nResultType = srSkillResultPhysicAttack;
|
||
|
||
SKILLRESULTPARAM param;
|
||
|
||
param.pSrcEntity = m_pEntity;
|
||
param.pTargetEntity = (CAnimal*)pEntity;
|
||
param.pSkillResult =& result;
|
||
m_skillResult.DoResult(¶m); //释放肉搏技能
|
||
|
||
return tpNoError;
|
||
}
|
||
|
||
//通知一个技能数据
|
||
void CSkillSubSystem::NoticeOneSkillData(PSKILLDATA pSkillData)
|
||
{
|
||
if (!m_pEntity)
|
||
{
|
||
return;
|
||
}
|
||
if(pSkillData == NULL)
|
||
{
|
||
return;
|
||
}
|
||
|
||
|
||
if(((CActor*)m_pEntity)->OnGetIsSimulator() || ((CActor*)m_pEntity)->OnGetIsTestSimulator())
|
||
{
|
||
return;
|
||
}
|
||
// 通知更新开启关闭
|
||
CActorPacket pack;
|
||
CDataPacket &data = ((CActor*)m_pEntity)->AllocPacket(pack);
|
||
data << (BYTE)enSkillSystemID << (BYTE)sTrainSkillResult << (WORD)(pSkillData->nSkillID) << (BYTE)(pSkillData->nLevel);
|
||
int nLeftTick = (int)(pSkillData->tick - GetGlobalLogicEngine()->getTickCount());
|
||
if(nLeftTick <0) nLeftTick =0;
|
||
data << (int)nLeftTick;
|
||
data << (BYTE)(!pSkillData->nIsClosed);
|
||
data << (BYTE)pSkillData->bIsClose;
|
||
pack.flush();
|
||
}
|
||
|
||
//开启/关闭战士的附加技能
|
||
void CSkillSubSystem::SwitchSkill(INT_PTR nSkillID, bool nFlag)
|
||
{
|
||
if(m_pEntity ==NULL) return;
|
||
if (m_pEntity->GetType() != enActor) return;
|
||
|
||
CBuffSystem * bufSystem = ((CActor*)m_pEntity)->GetBuffSystem();
|
||
if(!bufSystem) return;
|
||
|
||
SKILLDATA * pSkillData = GetSkillInfoPtr(nSkillID);
|
||
if(pSkillData == NULL) return;
|
||
|
||
//判断区域能否使用技能
|
||
if(CScene* pScene = m_pEntity->GetScene())
|
||
{
|
||
int x,y;
|
||
m_pEntity->GetPosition(x,y);
|
||
if (m_pEntity->GetType() ==enActor && pScene->HasMapAttribute(x,y,aaNotSkillAttri))
|
||
{
|
||
return;
|
||
}
|
||
if (pScene->HasMapAttribute(x,y,aaNotSkillId, (int)nSkillID))
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
//判断是否为 "战士延次技能的标志" 的技能
|
||
CBuffProvider::BUFFCONFIG* pBuffConf = GetLogicServer()->GetDataProvider()->GetBuffProvider().GetBuffBySkillId(nSkillID);
|
||
if(pBuffConf == NULL) return;
|
||
|
||
//技能cd时间判断
|
||
TICKCOUNT nCurTick = GetGlobalLogicEngine()->getTickCount();
|
||
if(nFlag && pSkillData->tick > nCurTick)
|
||
{
|
||
//((CActor *)m_pEntity)->SendTipmsgWithId(tmInSkillCD, ttFlyTip);
|
||
return;
|
||
}
|
||
|
||
//技能的配置
|
||
const OneSkillData * pSkillConf =GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(nSkillID);
|
||
if(pSkillConf ==NULL) return;
|
||
|
||
//技能等级配置
|
||
const SKILLONELEVEL * pSLevelConf = GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillLevelData(nSkillID, pSkillData->nLevel);
|
||
if( pSLevelConf == NULL) return;
|
||
|
||
//对于可控开启关闭的技能,检查是否已开启关闭.
|
||
if(!pSkillConf->bIsSwitch) return;
|
||
if (pSkillData->nIsClosed != (BYTE) nFlag) //重复操作了,检查一次buff与技能开关标志是否同步
|
||
{
|
||
if (pSkillData->nIsClosed && !bufSystem->Exists(pBuffConf->nId))
|
||
{
|
||
return;
|
||
}
|
||
else if (!pSkillData->nIsClosed && bufSystem->Exists(pBuffConf->nId))
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
//技能使用的条件的判断
|
||
const DataList<SKILLTRAINSPELLCONDITION> & spellConditions = pSLevelConf->spellConditions ;
|
||
INT_PTR nConditionCount = spellConditions.count;
|
||
for (INT_PTR i =0; i< nConditionCount ; i++ )
|
||
{
|
||
INT_PTR nUseErrorCode = m_targetCondition.CheckSpellContion(m_pEntity,nSkillID,spellConditions[i],false);
|
||
if(nUseErrorCode != tpNoError)
|
||
{
|
||
return;
|
||
}
|
||
}
|
||
|
||
//设置技能cd时间
|
||
int nSelfCd = pSkillData->nCoolDownTime; //自己的冷却时间
|
||
if(GetEnableCD() && nSelfCd >0)
|
||
{
|
||
TICKCOUNT nCurTick = GetGlobalLogicEngine()->getTickCount();
|
||
pSkillData->tick = nCurTick + nSelfCd; //设置自己的cd
|
||
OnGetCd(nSkillID);
|
||
}
|
||
|
||
int nTipMsg = 0;
|
||
switch (nSkillID)
|
||
{
|
||
case 3:
|
||
nTipMsg = nFlag?tmOpenSkill_3:tmCloseSkill_3;
|
||
break;
|
||
case 4:
|
||
nTipMsg = nFlag?tmOpenSkill_4:tmCloseSkill_4;
|
||
break;
|
||
case 6:
|
||
nTipMsg = tmPrepSkill_6;
|
||
break;
|
||
case 8:
|
||
nTipMsg = tmPrepSkill_8;
|
||
break;
|
||
}
|
||
|
||
// 增加/删除buff 及 技能开关标志
|
||
if(nFlag) {
|
||
//OutputMsg(rmTip,_T("\n【%s】开启技能:SwitchSkill %d !!"), m_pEntity->GetEntityName(),
|
||
// nSkillID
|
||
//);
|
||
pSkillData->nIsClosed = 0;
|
||
if (!bufSystem->Exists(pBuffConf->nId))
|
||
{
|
||
bufSystem->Append(pBuffConf->nId);
|
||
}
|
||
} else {
|
||
//OutputMsg(rmTip,_T("\n【%s】关闭技能:SwitchSkill %d !!"), m_pEntity->GetEntityName(),
|
||
// nSkillID
|
||
//);
|
||
pSkillData->nIsClosed = 1;
|
||
bufSystem->RemoveById(pBuffConf->nId,false);
|
||
}
|
||
|
||
//存储记录并发提示
|
||
SetDataModifyFlag(true);
|
||
((CActor *)m_pEntity)->SendTipmsgWithId(nTipMsg, tstFigthing);
|
||
|
||
//更新下一击附加技能标记
|
||
UpdateNextSkillFlag();
|
||
|
||
//通知一个技能数据
|
||
NoticeOneSkillData(pSkillData);
|
||
}
|
||
|
||
void CSkillSubSystem::InitNextSkillFlag()
|
||
{
|
||
if (!m_pEntity) return;
|
||
const OneSkillData * pSkillConf;
|
||
CSkillProvider* provider = GetLogicServer()->GetDataProvider()->GetSkillProvider();
|
||
CBuffSystem * bufSystem = ((CActor*)m_pEntity)->GetBuffSystem();
|
||
for(INT_PTR i=0;i < m_skillList.count(); i++)
|
||
{
|
||
pSkillConf = provider->GetSkillData(m_skillList[i].nSkillID);
|
||
if(pSkillConf)
|
||
{
|
||
//判断是否为 "战士延次技能的标志" 的技能
|
||
CBuffProvider::BUFFCONFIG* pBuffConf = GetLogicServer()->GetDataProvider()->GetBuffProvider().GetBuffBySkillId(m_skillList[i].nSkillID);
|
||
if(pBuffConf)
|
||
{
|
||
if (m_skillList[i].bIsPassive)
|
||
{
|
||
if (!bufSystem->Exists(pBuffConf->nId))
|
||
{
|
||
bufSystem->Append(pBuffConf->nId);
|
||
}
|
||
}
|
||
else if (pSkillConf->bIsSwitch)
|
||
{
|
||
if (m_skillList[i].nIsClosed && bufSystem->Exists(pBuffConf->nId))
|
||
{
|
||
bufSystem->RemoveById(pBuffConf->nId,false);
|
||
}
|
||
else if (!m_skillList[i].nIsClosed && !bufSystem->Exists(pBuffConf->nId))
|
||
{
|
||
bufSystem->Append(pBuffConf->nId);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//检测战士的下一击附加技能,并执行,并更新下一击附加技能标记
|
||
INT_PTR CSkillSubSystem::CheckNextSkillFlag(CEntity* pTargetEntity)
|
||
{
|
||
INT_PTR nErrorCode = tpSkillCannotSpell;
|
||
if(m_pEntity ==NULL ) return tpSkillCannotSpell;
|
||
if (m_pEntity->GetType() != enActor) return tpSkillCannotSpell;
|
||
CBuffSystem * bufSystem = ((CActor*)m_pEntity)->GetBuffSystem();
|
||
if(bufSystem == NULL) return tpSkillCannotSpell;
|
||
|
||
//特殊处理:攻杀,刺杀,半月,烈火,逐日
|
||
union
|
||
{
|
||
struct
|
||
{
|
||
unsigned short nSkillId;
|
||
unsigned short nSkillLevel;
|
||
}sub;
|
||
int Flag;
|
||
} nNextSkillFlag;
|
||
|
||
nNextSkillFlag.Flag = (INT_PTR)(m_pEntity->GetProperty<int>(PROP_ACTOR_NEXT_SKILL_FLAG));
|
||
if (nNextSkillFlag.Flag != 0)
|
||
{
|
||
//玩家附加技能数据触发
|
||
int nSkillID = nNextSkillFlag.sub.nSkillId;
|
||
PSKILLDATA pNextSkillData = GetSkillInfoPtr(nSkillID);
|
||
if(pNextSkillData == NULL) return tpSkillCannotSpell;
|
||
if (pTargetEntity && nNextSkillFlag.Flag)
|
||
{
|
||
//是否处于同一场景判断
|
||
if ( !pTargetEntity->GetFuBen() || !m_pEntity->GetFuBen() || pTargetEntity->GetFuBen()->GetFbId() != m_pEntity->GetFuBen()->GetFbId()
|
||
|| !pTargetEntity->GetScene() || !m_pEntity->GetScene() || pTargetEntity->GetScene()->GetSceneId() != m_pEntity->GetScene()->GetSceneId())
|
||
{
|
||
return tpSkillCannotSpell;
|
||
}
|
||
|
||
CScene* pScene = m_pEntity->GetScene();
|
||
int nCurPosX,nCurPosY;
|
||
m_pEntity->GetPosition(nCurPosX,nCurPosY);
|
||
INT_PTR nDir = m_pEntity->GetProperty<unsigned int>(PROP_ENTITY_DIR);
|
||
|
||
//技能的配置
|
||
const OneSkillData * pNextSkillConf = GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(nNextSkillFlag.sub.nSkillId);
|
||
if(pNextSkillConf ==NULL) return tpSkillCannotSpell;
|
||
|
||
//技能等级配置
|
||
const SKILLONELEVEL * pNextSLevelConf = GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillLevelData(nNextSkillFlag.sub.nSkillId, pNextSkillData->nLevel);
|
||
if( pNextSLevelConf == NULL) return tpSkillCannotSpell;
|
||
|
||
//触发消耗(先前已判断过是否足够消耗)
|
||
const DataList<SKILLTRAINSPELLCONDITION> & spellConditions = pNextSLevelConf->spellConditions ;
|
||
INT_PTR nConditionCount = spellConditions.count;
|
||
for (INT_PTR i =0; i< nConditionCount; i++ )
|
||
{
|
||
if(spellConditions[i].bConsumed == false || spellConditions[i].nValue ==0) continue; //如果不需要消耗就不消耗
|
||
m_targetCondition.CheckSpellContion( m_pEntity,nSkillID,spellConditions[i],true ); //去消耗
|
||
}
|
||
|
||
//遍历范围效果列表
|
||
for(INT_PTR rangeID=0; rangeID < pNextSLevelConf->pranges.count; rangeID++)
|
||
{
|
||
PSKILLONERANGE pRangeConf = pNextSLevelConf->pranges[rangeID];
|
||
if(pRangeConf ==NULL) continue;
|
||
|
||
if (pRangeConf->nDelay > 0)
|
||
{
|
||
CEntityMsg msg(CEntityMsg::emSkillApplyOneRange,m_pEntity->GetHandle());
|
||
msg.dwDelay = pRangeConf->nDelay;
|
||
msg.nParam1 = nNextSkillFlag.sub.nSkillId;
|
||
msg.pParam2 = pNextSkillData;
|
||
msg.pParam3 = pRangeConf;
|
||
msg.pParam4 = pTargetEntity;
|
||
msg.pParam5 = pScene;
|
||
msg.nParam6 = nCurPosX;
|
||
msg.nParam7 = nCurPosY;
|
||
msg.nParam8 = 0;
|
||
msg.nParam9 = 0;
|
||
msg.nParam10 = nDir;
|
||
m_pEntity->PostEntityMsg(msg);
|
||
}
|
||
else
|
||
{
|
||
INT_PTR nError = SkillApplyOneRange((int)nNextSkillFlag.sub.nSkillId,pNextSkillData,pRangeConf,pTargetEntity,pScene,nCurPosX,nCurPosY,0,0,nDir);
|
||
if (nError > tpNoError)
|
||
{
|
||
return nError;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 使用之后要删除buff(无限时buff不删)
|
||
CBuffProvider::BUFFCONFIG* buffConf = GetLogicServer()->GetDataProvider()->GetBuffProvider().GetBuffBySkillId(nNextSkillFlag.sub.nSkillId);
|
||
if (buffConf && buffConf->nTimes != -1)
|
||
{
|
||
pNextSkillData->nIsClosed = 1;
|
||
SetDataModifyFlag(true);
|
||
bufSystem->RemoveById(buffConf->nId,false);
|
||
}
|
||
|
||
nErrorCode = tpNoError;
|
||
|
||
//通知一个技能数据
|
||
NoticeOneSkillData(pNextSkillData);
|
||
|
||
//播放攻击
|
||
BroadSpellSkill(0,0,m_pEntity->GetProperty<unsigned int>(PROP_ENTITY_DIR),0);
|
||
}
|
||
|
||
// 更新下一击附加技能标记
|
||
UpdateNextSkillFlag();
|
||
|
||
return nErrorCode;
|
||
}
|
||
|
||
//更新下一击附加技能标记
|
||
void CSkillSubSystem::UpdateNextSkillFlag()
|
||
{
|
||
if (!m_pEntity) return;
|
||
CBuffSystem * pBufSystem = ((CActor*)m_pEntity)->GetBuffSystem();
|
||
if (!pBufSystem) return;
|
||
|
||
//特殊处理:攻杀,刺杀,半月,烈火,逐日
|
||
union
|
||
{
|
||
struct
|
||
{
|
||
unsigned short nSkillId;
|
||
unsigned short nSkillLevel;
|
||
}sub;
|
||
int Flag;
|
||
} nNextSkillFlag;
|
||
nNextSkillFlag.Flag = 0;
|
||
|
||
// 战士技能附加技能标志更新
|
||
int priority = 0;
|
||
CVector<CDynamicBuff>& AllBuff = pBufSystem->GetAllBuff();
|
||
for (size_t i = 0; i < AllBuff.count(); i++)
|
||
{
|
||
CDynamicBuff& buff = AllBuff[i];
|
||
int skillid = (int)(buff.pConfig->dValue);
|
||
int nRate10000 = 0;
|
||
|
||
// 获取触发概率万分比
|
||
CBuffProvider::BUFFCONFIG* pBuffConf = GetLogicServer()->GetDataProvider()->GetBuffProvider().GetBuffBySkillId(skillid);
|
||
SKILLONELEVEL *pLevelSkill = GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillLevelData(skillid,GetSkillLevel(skillid));
|
||
if (pBuffConf && pLevelSkill)
|
||
{
|
||
// 获取概率
|
||
for(INT_PTR rangeID=0; rangeID < pLevelSkill->pranges.count; rangeID++)
|
||
{
|
||
PSKILLONERANGE pRange = pLevelSkill->pranges[rangeID];
|
||
INT_PTR nResultCount = pRange->skillResults.count;
|
||
for(INT_PTR resultID =0; resultID < nResultCount; resultID++)
|
||
{
|
||
PSKILLRESULT pResult = &(pRange->skillResults[resultID]);
|
||
if(pResult->nResultType != srSkillResultPhysicAttack ) continue;
|
||
nRate10000 = pResult->nParam2;
|
||
}
|
||
if (nRate10000) break;
|
||
}
|
||
|
||
// 触发
|
||
if(buff.pConfig->nType == aNextSkillFlag && (nRate10000?nRate10000:10000) > wrand(10000))
|
||
{
|
||
|
||
PSKILLDATA pSkill = GetSkillInfoPtr(skillid);
|
||
|
||
if (pSkill && priority < pSkill->bPriority)
|
||
{
|
||
nNextSkillFlag.sub.nSkillId = skillid;
|
||
nNextSkillFlag.sub.nSkillLevel = pSkill->nLevel;
|
||
priority = pSkill->bPriority;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
m_pEntity->SetProperty<int>(PROP_ACTOR_NEXT_SKILL_FLAG, nNextSkillFlag.Flag);
|
||
m_pEntity->GetObserverSystem()->UpdateActorEntityProp();
|
||
#ifdef _DEBUG_GATEMSG
|
||
OutputMsg(rmTip,_T("\n【%s】检查更新技能标志:UpdateNextSkillFlag (%d , %d)"), m_pEntity->GetEntityName(),
|
||
nNextSkillFlag.sub.nSkillId, nNextSkillFlag.sub.nSkillLevel
|
||
);
|
||
#endif
|
||
}
|
||
|
||
//技能标记的BUff过期回调
|
||
INT_PTR CSkillSubSystem::OnBuffExpire(CDynamicBuff *pBuff)
|
||
{
|
||
//玩家技能数据
|
||
int nSkillId = (int)(pBuff->pConfig->dValue);
|
||
PSKILLDATA pSkillData = GetSkillInfoPtr(nSkillId);
|
||
if(pSkillData == NULL) return tpNoError;
|
||
|
||
// 关闭技能
|
||
pSkillData->nIsClosed = 1;
|
||
SetDataModifyFlag(true);
|
||
|
||
// 更新下一击附加技能标记
|
||
UpdateNextSkillFlag();
|
||
|
||
// 更新数据信息
|
||
NoticeOneSkillData(pSkillData);
|
||
}
|
||
|
||
//发射技能
|
||
INT_PTR CSkillSubSystem::LaunchSkill(INT_PTR nSkillID,INT_PTR nPosX, INT_PTR nPosY, bool bNoCd)
|
||
{
|
||
if(m_pEntity ==NULL ) return tpSkillCannotSpell;
|
||
|
||
//场景
|
||
CScene *pScene = m_pEntity->GetScene();
|
||
if(pScene == NULL) //出现了比较严重的错误
|
||
{
|
||
OutputMsg(rmWaning,_T("释放技能失败,场景为空,技能ID=%d"),nSkillID);
|
||
return tpNoError;
|
||
}
|
||
|
||
//SKILLDATA skillData;
|
||
|
||
//判断是否为 "战士延次技能的标志" 的技能
|
||
CBuffProvider::BUFFCONFIG* pBuffConf = GetLogicServer()->GetDataProvider()->GetBuffProvider().GetBuffBySkillId(nSkillID);
|
||
if(pBuffConf != NULL)
|
||
{
|
||
// TODO 提示
|
||
OutputMsg(rmWaning,_T("技能使用错误!"));
|
||
return tpNoError;
|
||
}
|
||
|
||
//玩家技能数据
|
||
PSKILLDATA pSkillData = GetSkillInfoPtr(nSkillID);
|
||
if(pSkillData == NULL) return tpSkillSpellNotLeared; //技能不存在
|
||
if(pSkillData->bIsClose) return tpSkillIsClosed; //该技能已经关闭了
|
||
|
||
//技能的配置
|
||
const OneSkillData * pSkillConf =GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(nSkillID);
|
||
if(pSkillConf ==NULL) return tpSkillConfigError;
|
||
|
||
//检测特殊的buff是否存在
|
||
CBuffSystem *pBuff = m_pEntity->GetBuffSystem();
|
||
//麻痹
|
||
if(pSkillConf->nSkillType != stTransferSkill) {
|
||
|
||
INT_PTR ndizzy = m_pEntity->GetProperty<int>(PROP_CREATURE_DIZZY_STATUS);
|
||
if(pBuff && (pBuff->Exists( aDizzy ) || pBuff->Exists(aSlient)) || ndizzy)
|
||
{
|
||
OutputMsg(rmWaning,_T("麻痹或沉默中,无法使用技能!"));
|
||
return tpSkillTrainWithBuff;
|
||
}
|
||
}
|
||
|
||
|
||
//技能等级配置
|
||
const SKILLONELEVEL * pSLevelConf = GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillLevelData(nSkillID, pSkillData->nLevel);
|
||
if( pSLevelConf == NULL)
|
||
{
|
||
OutputMsg(rmWaning,_T("技能配置错误!"));
|
||
return tpSkillSpellNotLeared;
|
||
}
|
||
|
||
//判断区域能否使用技能
|
||
if(CScene* pScene = m_pEntity->GetScene())
|
||
{
|
||
int x,y;
|
||
m_pEntity->GetPosition(x,y);
|
||
if (m_pEntity->GetType() == enActor && pScene->HasMapAttribute(x,y,aaNotSkillAttri))
|
||
{
|
||
OutputMsg(rmWaning,_T("该区域禁止使用任何技能!"));
|
||
return tpSkillCannotSpell;
|
||
}
|
||
if (pScene->HasMapAttribute(x,y,aaNotSkillId, (int)nSkillID))
|
||
{
|
||
OutputMsg(rmWaning,_T("该区域禁止使用该技能技能!"));
|
||
return tpSkillCannotSpell;
|
||
}
|
||
}
|
||
|
||
//对于玩家/怪物/宠物的相关限制
|
||
INT_PTR nType = m_pEntity->GetType();
|
||
if(nType == enMonster)
|
||
{
|
||
if(pSkillConf->bSkillClass != scSkillClassMonster )
|
||
{
|
||
return tpSkillCannotSpell;
|
||
}
|
||
}
|
||
else if(nType == enActor )
|
||
{
|
||
if ( pSkillConf->bSkillClass == scSkillClassMonster )
|
||
{
|
||
return tpSkillTrainCoinLimited;
|
||
}
|
||
|
||
//被动技能和生活技能无法释放
|
||
if(pSkillConf->nSkillType == stPassiveSkill || pSkillConf->nSkillType == stLifeSkill)
|
||
{
|
||
return tpSkillCannotSpell;
|
||
}
|
||
else if(pSkillConf->nSkillType != stOtherSpecialSkill && pSkillConf->bSkillClass != scSkillHideAttach && pSkillConf->nSkillType != stTransferSkill) //特殊技能不检查cd的
|
||
{
|
||
TICKCOUNT commTickCheck = ((CActor*)m_pEntity)->GetGateNetWorkTickCount() +50;
|
||
// 这里打个补丁
|
||
((CActor*)m_pEntity)->CheckCommonOpTickBefore(commTickCheck);
|
||
////因存在移动后进入使用技能时会出现公共CD没到而技能使用不出来的情况,所以这里改为允许30毫秒的误差
|
||
if (!bNoCd && !((CActor*)m_pEntity)->CheckCommonOpTick(commTickCheck,false))
|
||
{
|
||
return tpSkillSellCDLimited; //攻击速度
|
||
}
|
||
}
|
||
}
|
||
else if(nType == enPet)
|
||
{
|
||
if(pSkillConf->nSkillType == stPassiveSkill )
|
||
{
|
||
return tpSkillCannotSpell;
|
||
}
|
||
}
|
||
|
||
//技能冷却判断
|
||
TICKCOUNT nCurTick = GetGlobalLogicEngine()->getTickCount();
|
||
if(!bNoCd && pSkillData->tick > nCurTick )
|
||
{
|
||
return tpSkillSellCDLimited;
|
||
}
|
||
|
||
//技能使用的条件的判断
|
||
const DataList<SKILLTRAINSPELLCONDITION> & spellConditions = pSLevelConf->spellConditions ;
|
||
INT_PTR nConditionCount= spellConditions.count;
|
||
for (INT_PTR i =0; i< nConditionCount ; i++ )
|
||
{
|
||
INT_PTR nUseErrorCode = m_targetCondition.CheckSpellContion(m_pEntity,nSkillID,spellConditions[i],false);
|
||
if(nUseErrorCode != tpNoError)
|
||
{
|
||
return nUseErrorCode;
|
||
}
|
||
}
|
||
|
||
//广播开始释放技能
|
||
BroadSpellSkill(nSkillID, pSkillData->nLevel, m_pEntity->GetProperty<unsigned int>(PROP_ENTITY_DIR), m_pEntity->GetTarget(), nPosX, nPosY);
|
||
|
||
//下面进行技能的目标筛选
|
||
INT_PTR nSkillType = pSkillConf->nSkillType; //技能的类型
|
||
CEntity * pTargetEntity = GetEntityFromHandle(m_pEntity->GetTarget()); //目标实体指针
|
||
|
||
int nCurPosX,nCurPosY;
|
||
m_pEntity->GetPosition(nCurPosX,nCurPosY); //当前的坐标
|
||
INT_PTR nDir = m_pEntity->GetProperty<unsigned int>(PROP_ENTITY_DIR);
|
||
|
||
//广播施法,特殊的技能是不能广播的,比如队伍的辐射光环buff
|
||
if(nSkillType != stOtherSpecialSkill)
|
||
{
|
||
//特殊的技能不影响
|
||
if(m_pEntity->GetType() == enActor)
|
||
{
|
||
((CActor*)m_pEntity)->SetCommonOpNextTime( m_pEntity->GetProperty<unsigned int> (PROP_CREATURE_ATTACK_SPEED),true,true);
|
||
}
|
||
}
|
||
|
||
//发射技能(或延时)
|
||
if (pSLevelConf->nSingTime > 0)
|
||
{
|
||
CEntityMsg msg(CEntityMsg::emRealLaunchSkill,m_pEntity->GetHandle());
|
||
msg.dwDelay = pSLevelConf->nSingTime;
|
||
msg.nParam1 = nSkillID;
|
||
msg.pParam2 = pScene;
|
||
msg.nParam3 = nDir;
|
||
msg.nParam4 = nCurPosX;
|
||
msg.nParam5 = nCurPosY;
|
||
msg.pParam6 = pTargetEntity;
|
||
msg.nParam7 = nPosX;
|
||
msg.nParam8 = nPosY;
|
||
m_pEntity->PostEntityMsg(msg);
|
||
}
|
||
else
|
||
{
|
||
INT_PTR nError = RealLaunchSkill(nSkillID, pScene, nDir, nCurPosX, nCurPosY, pTargetEntity, nPosX, nPosY);
|
||
if (nError > tpNoError) return nError;
|
||
}
|
||
|
||
//触发消耗(先前已判断过是否足够消耗)
|
||
for (INT_PTR i =0; i< nConditionCount; i++ )
|
||
{
|
||
if(spellConditions[i].bConsumed == false || spellConditions[i].nValue ==0) continue; //如果不需要消耗就不消耗
|
||
m_targetCondition.CheckSpellContion( m_pEntity,nSkillID,spellConditions[i],true ); //去消耗
|
||
}
|
||
|
||
//技能cd时间
|
||
int nSelfCd = pSkillData->nCoolDownTime; //自己的冷却时间
|
||
if(/*nType == enActor && */GetEnableCD() && nSelfCd >0)
|
||
{
|
||
TICKCOUNT nCurTick = GetGlobalLogicEngine()->getTickCount();
|
||
pSkillData->tick = nCurTick + nSelfCd; //设置自己的cd
|
||
if (nType == enActor)
|
||
{
|
||
OnGetCd(nSkillID);
|
||
}
|
||
}
|
||
|
||
//触发了公共的cd
|
||
int nCommonCd = pSkillConf->nCommonCdTime ;
|
||
if(nCommonCd >0 && m_pEntity->GetType()!=enHero)
|
||
{
|
||
ULONGLONG nextTick = nCommonCd + GetGlobalLogicEngine()->getTickCount(); //获取下次公告cd的时间
|
||
for (INT_PTR i=0; i < m_skillList.count(); i++ )
|
||
{
|
||
if(((ULONGLONG)m_skillList[i].tick < nextTick) && m_skillList[i].nSkillType != stTransferSkill)
|
||
{
|
||
m_skillList[i].tick = nextTick;
|
||
}
|
||
}
|
||
}
|
||
return tpNoError;
|
||
}
|
||
|
||
//实际发射技能
|
||
INT_PTR CSkillSubSystem::RealLaunchSkill(INT_PTR nSkillID,
|
||
CScene* pScene, INT_PTR nDir, INT_PTR nCurPosX, INT_PTR nCurPosY,
|
||
CEntity* pTargetEntity, INT_PTR nMousesPosX, INT_PTR nMousesPosY)
|
||
{
|
||
//玩家技能数据
|
||
PSKILLDATA pSkillData = GetSkillInfoPtr(nSkillID);
|
||
if(pSkillData == NULL) return tpSkillSpellNotLeared;
|
||
|
||
//技能的配置
|
||
const OneSkillData * pSkillConf = GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(nSkillID);
|
||
if(pSkillConf ==NULL) return tpSkillConfigError;
|
||
|
||
//技能等级配置
|
||
const SKILLONELEVEL * pSLevelConf = GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillLevelData(nSkillID, pSkillData->nLevel);
|
||
if( pSLevelConf == NULL) return tpSkillSpellNotLeared;
|
||
|
||
//场景特效(一般是群体技能)
|
||
if (pSLevelConf->isSceneEffect != 0)
|
||
{
|
||
CEntityMsg msg(CEntityMsg::emShowSceneEffect);
|
||
msg.nSender = m_pEntity->GetHandle();
|
||
msg.nParam1 = pSLevelConf->nHitId;
|
||
msg.nParam2 = nMousesPosX;
|
||
msg.nParam3 = nMousesPosY;
|
||
m_pEntity->PostEntityMsg(msg); //施法者自己发送消息,稍候广播
|
||
}
|
||
else if(!pTargetEntity && pSkillConf->bSingleEmptyEffect)//单体无目标,则空地发射
|
||
{
|
||
CEntityMsg msg(CEntityMsg::emShowSceneEffect);
|
||
msg.nSender = m_pEntity->GetHandle();
|
||
msg.nParam1 = pSLevelConf->nHitId;
|
||
msg.nParam2 = nMousesPosX;
|
||
msg.nParam3 = nMousesPosY;
|
||
m_pEntity->PostEntityMsg(msg);
|
||
}
|
||
|
||
//遍历范围效果列表
|
||
for(INT_PTR rangeID=0; rangeID < pSLevelConf->pranges.count; rangeID++)
|
||
{
|
||
PSKILLONERANGE pRangeConf = pSLevelConf->pranges[rangeID];
|
||
if(pRangeConf ==NULL) continue;
|
||
|
||
if (pRangeConf->nDelay > 0)
|
||
{
|
||
CEntityMsg msg(CEntityMsg::emSkillApplyOneRange,m_pEntity->GetHandle());
|
||
msg.dwDelay = pRangeConf->nDelay;
|
||
msg.nParam1 = nSkillID;
|
||
msg.pParam2 = pSkillData;
|
||
msg.pParam3 = pRangeConf;
|
||
msg.pParam4 = pTargetEntity;
|
||
msg.pParam5 = pScene;
|
||
msg.nParam6 = nCurPosX;
|
||
msg.nParam7 = nCurPosY;
|
||
msg.nParam8 = nMousesPosX;
|
||
msg.nParam9 = nMousesPosY;
|
||
msg.nParam10 = nDir;
|
||
m_pEntity->PostEntityMsg(msg);
|
||
}
|
||
else
|
||
{
|
||
INT_PTR nError = SkillApplyOneRange((int)nSkillID,pSkillData,pRangeConf,pTargetEntity,pScene,nCurPosX,nCurPosY,(int)nMousesPosX,(int)nMousesPosY,nDir);
|
||
if (nError > tpNoError)
|
||
{
|
||
return nError;
|
||
}
|
||
}
|
||
}
|
||
|
||
return tpNoError;
|
||
}
|
||
|
||
INT_PTR CSkillSubSystem::SkillApplyOneRange(int nSkillID, PSKILLDATA pSkillData,PSKILLONERANGE pRange,
|
||
CEntity* pTargetEntity,CScene* pScene,int nCurPosX,int nCurPosY,int nMousesPosX, int nMousesPosY, int nSpellDir)
|
||
{
|
||
//设置中心点,及朝向
|
||
INT_PTR nCenterPosX = 0; //技能中心点的X的位置
|
||
INT_PTR nCenterPosY = 0; //技能中心点的Y的位置
|
||
INT_PTR nDir = DIR_STOP; //获取本身的朝向
|
||
switch(pRange->rangeCenter)
|
||
{
|
||
//以主角为中心
|
||
case stSkillActorCenter:
|
||
{
|
||
nCenterPosX = m_pEntity->GetProperty<unsigned int>(PROP_ENTITY_POSX);
|
||
nCenterPosY = m_pEntity->GetProperty<unsigned int>(PROP_ENTITY_POSY);
|
||
nDir = m_pEntity->GetProperty< int>(PROP_ENTITY_DIR);
|
||
break;
|
||
}
|
||
//以目标为中心
|
||
case stSkillTargetCenter:
|
||
{
|
||
if(pTargetEntity)
|
||
{
|
||
nCenterPosX = pTargetEntity->GetProperty<unsigned int>(PROP_ENTITY_POSX);
|
||
nCenterPosY = pTargetEntity->GetProperty<unsigned int>(PROP_ENTITY_POSY);
|
||
nDir = pTargetEntity->GetProperty<int>(PROP_ENTITY_DIR);
|
||
}
|
||
else
|
||
{
|
||
return tpSkillSpellNoTarget;
|
||
}
|
||
break;
|
||
}
|
||
//以施法点为中心
|
||
case stSkillSpellPointCenter:
|
||
{
|
||
if(nMousesPosX >0 && nMousesPosY > 0)
|
||
{
|
||
nCenterPosX = (int)nMousesPosX;
|
||
nCenterPosY = (int)nMousesPosY;
|
||
nDir = DIR_LEFT; //随便搞个方向,这个没意义
|
||
}
|
||
else
|
||
{
|
||
return tpSkillSpellNoTarget;
|
||
}
|
||
break;
|
||
}
|
||
//以主角瞬时坐标方向为中心
|
||
case stSkillActorCenterDir:
|
||
{
|
||
nCenterPosX = nCurPosX;
|
||
nCenterPosY = nCurPosY;
|
||
nDir = nSpellDir;
|
||
break;
|
||
}
|
||
}
|
||
|
||
//攻击实例列表
|
||
EntityVector& entityList = *(CFuBenManager::m_pVisibleList);
|
||
entityList.clear();
|
||
|
||
//技能方位调整及落实技能效果
|
||
INT_PTR nRangeType = pRange->rangeType;
|
||
if(stSkillRangeSingle == nRangeType)
|
||
{ //单体目标不用筛选
|
||
if(pTargetEntity)
|
||
{
|
||
entityList.add(m_pEntity->GetTarget());
|
||
}else
|
||
{
|
||
entityList.add(m_pEntity->GetHandle());
|
||
}
|
||
SkillApplyOneGrid(pRange,entityList,nCenterPosX,nCenterPosY,nSkillID,pSkillData,nCurPosX,nCurPosY);
|
||
}
|
||
else if(stSkillRangeNoTarget == nRangeType)
|
||
{
|
||
INT_PTR nNewPosX , nNewPosY;
|
||
for(INT_PTR nRelPosX = pRange->nStartX; nRelPosX <= pRange->nEndX; nRelPosX ++ )
|
||
{
|
||
SKILLRESULTPARAM param;
|
||
param.nSkillID = nSkillID;
|
||
param.pSrcEntity = m_pEntity;
|
||
for(INT_PTR nRelPosY = pRange->nStartY; nRelPosY <= pRange->nEndY; nRelPosY ++ )
|
||
{
|
||
nNewPosX = nCenterPosX + nRelPosX;
|
||
nNewPosY = nCenterPosY + nRelPosY;
|
||
param.nTargetPosX = (WORD)nNewPosX;
|
||
param.nTargetPosY = (WORD)nNewPosY;
|
||
|
||
//直接技能的结果
|
||
INT_PTR nResultCount= pRange->skillResults.count;
|
||
for(INT_PTR resultID = 0; resultID < nResultCount; resultID ++)
|
||
{
|
||
param.pSkillResult = &(pRange->skillResults[resultID]);
|
||
m_skillResult.DoResult(¶m);
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
else
|
||
{ //群体目标一一筛选
|
||
INT_PTR nNewPosX , nNewPosY;
|
||
for(INT_PTR nRelPosX = pRange->nStartX; nRelPosX <= pRange->nEndX; nRelPosX ++ )
|
||
{
|
||
for(INT_PTR nRelPosY = pRange->nStartY; nRelPosY <= pRange->nEndY; nRelPosY ++ )
|
||
{
|
||
entityList.clear();
|
||
|
||
if(stSkillRangeRotationSingle == nRangeType || stSkillRangeRotationGroup == nRangeType)
|
||
{
|
||
PositionRotation(0,0,nRelPosX,nRelPosY,nDir,nNewPosX,nNewPosY);
|
||
nNewPosX += nCenterPosX;
|
||
nNewPosY += nCenterPosY;
|
||
pScene->GetVisibleList((int)nNewPosX,(int)nNewPosY,entityList,0,0,0,0);
|
||
SkillApplyOneGrid(pRange,entityList,nNewPosX,nNewPosY,nSkillID,pSkillData,nCurPosX,nCurPosY);
|
||
}
|
||
else if(stSkillRangeAccurateRotation == nRangeType)
|
||
{
|
||
//以中心点与鼠标的位置的连线作为旋转轴旋转,比线性旋转更精确,用于法师的火球术
|
||
//int nNewRotatePosX=0, nNewRotatePosY =0; //新的旋转相对中心点
|
||
|
||
INT_PTR nMPosRelX = nMousesPosX- nCenterPosX;
|
||
INT_PTR nMPosRelY = nMousesPosY- nCenterPosY;
|
||
AccurateRotation(nMPosRelX,nMPosRelY,nRelPosX,nRelPosY,nNewPosX,nNewPosY);
|
||
nNewPosX += nCenterPosX;
|
||
nNewPosY += nCenterPosY;
|
||
if(nNewPosX <0) nNewPosX =0;
|
||
if(nNewPosY <0) nNewPosY =0;
|
||
pScene->GetVisibleList((int)nNewPosX,(int)nNewPosY,entityList,0,0,0,0);
|
||
SkillApplyOneGrid(pRange,entityList,nNewPosX,nNewPosY,nSkillID,pSkillData,nCurPosX,nCurPosY);
|
||
}
|
||
else if(stSkillRangePointCenter == nRangeType)
|
||
{
|
||
nNewPosX = nCenterPosX + nRelPosX;
|
||
nNewPosY = nCenterPosY + nRelPosY;
|
||
pScene->GetVisibleList((int)nNewPosX,(int)nNewPosY,entityList,0,0,0,0);
|
||
//if (entityList.count() > 0)
|
||
SkillApplyOneGrid(pRange,entityList,nCenterPosX,nCenterPosY,nSkillID,pSkillData,nCurPosX,nCurPosY);
|
||
}
|
||
else
|
||
{
|
||
nNewPosX = nCenterPosX + nRelPosX;
|
||
nNewPosY = nCenterPosY + nRelPosY;
|
||
pScene->GetVisibleList((int)nNewPosX,(int)nNewPosY,entityList,0,0,0,0);
|
||
SkillApplyOneGrid(pRange,entityList,nNewPosX,nNewPosY,nSkillID,pSkillData,nCurPosX,nCurPosY);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return tpNoError;
|
||
}
|
||
|
||
void CSkillSubSystem::SkillApplyOneGrid(PSKILLONERANGE pRange, EntityVector& entityList,
|
||
INT_PTR nPosX,INT_PTR nPosY,INT_PTR nSkillID,PSKILLDATA pSkillData,int nCurPosX,int nCurPosY)
|
||
{
|
||
if(m_pEntity == NULL) return;
|
||
|
||
SKILLRESULTPARAM param;
|
||
param.nSkillID = nSkillID;
|
||
param.nTargetPosX = (WORD)nPosX;
|
||
param.nTargetPosY = (WORD)nPosY;
|
||
param.pSrcEntity = m_pEntity;
|
||
|
||
//技能的配置
|
||
const OneSkillData * pSkillConf = GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(nSkillID);
|
||
if(pSkillConf ==NULL) return;
|
||
|
||
//技能等级配置
|
||
const SKILLONELEVEL * pSLevelConf = GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillLevelData(nSkillID, pSkillData->nLevel);
|
||
if( pSLevelConf == NULL) return;
|
||
|
||
//遍历这些实体
|
||
INT_PTR nEntityCount = entityList.count();
|
||
for(INT_PTR nEnityIndex = 0; nEnityIndex < nEntityCount;)
|
||
{
|
||
CEntity * pEntity = GetEntityFromHandle(entityList[nEnityIndex++]) ;
|
||
if(pEntity == NULL )
|
||
{
|
||
continue; //实体已经删除
|
||
}
|
||
|
||
if(pEntity->GetType() == enNpc || pEntity->GetType() == enDropItem || pEntity->GetType() == enFire || pEntity->GetType() == enTransfer)
|
||
{
|
||
continue;
|
||
}
|
||
//怪物不能被攻击的情况
|
||
// if(m_pEntity->GetType() == enActor && pEntity->GetType() == enMonster && m_pEntity->CanAttack((CAnimal*)pEntity) == false)
|
||
// {
|
||
// if (stSkillRangeRotationSingle == pRange->rangeType && m_pEntity->GetType() == enActor)
|
||
// {
|
||
// ((CActor*)m_pEntity)->SendTipmsgFormatWithId(tmTarCantAttack, tstFigthing);
|
||
// }
|
||
// continue;
|
||
// }
|
||
|
||
//目标死亡状态的处理
|
||
if (((CAnimal *)pEntity)->HasState(esStateDeath) && pEntity != m_pEntity ) // fix bug: 解决怪物打不死的问题。后面考虑增加一个SkillCondition
|
||
{
|
||
// if (stSkillRangeRotationSingle == pRange->rangeType && m_pEntity->GetType() == enActor)
|
||
// {
|
||
// ((CActor*)m_pEntity)->SendTipmsgFormatWithId(tmTarCantAttack, tstFigthing);
|
||
// }
|
||
continue;
|
||
}
|
||
|
||
//目标条件筛选
|
||
if(INT_PTR nCondCount = pRange->targetConditions.count)
|
||
{
|
||
bool flag = false;
|
||
for(INT_PTR nCondIndex = 0; nCondIndex < nCondCount; nCondIndex ++)
|
||
{
|
||
TARGETSELCONDITION &condition = pRange->targetConditions[nCondIndex];
|
||
INT_PTR nEntityType = pEntity->GetType();
|
||
if( enFire == nEntityType || enNpc == nEntityType || enDropItem == nEntityType || enTransfer == nEntityType
|
||
|| !m_targetCondition.Check(m_pEntity,(CAnimal *)pEntity,condition) )
|
||
{
|
||
|
||
// if (stSkillRangeRotationSingle == pRange->rangeType && m_pEntity->GetType() == enActor && condition.nKey != 15) //策划要求野蛮冲撞 目标等级大于自身等级 无tip
|
||
// {
|
||
// ((CActor*)m_pEntity)->SendTipmsgFormatWithId(tmTarCantAttack, tstFigthing);
|
||
// }
|
||
|
||
flag = true;
|
||
break;
|
||
}
|
||
}
|
||
if (flag) continue;
|
||
}
|
||
|
||
//单体特效
|
||
if ((m_pEntity != pEntity) && pSLevelConf->isSceneEffect == 0)
|
||
{
|
||
if (pEntity && pSLevelConf->nHitId)
|
||
{
|
||
CEntityMsg msg(CEntityMsg::emShowEntityEffect, m_pEntity->GetHandle());
|
||
msg.nParam1 = pSLevelConf->nHitId;
|
||
pEntity->PostEntityMsg(msg);
|
||
}
|
||
}
|
||
// 对方在安全区,受限制
|
||
int x = 0, y = 0;
|
||
CScene* pScene = pEntity->GetScene();
|
||
pEntity->GetPosition(x,y);
|
||
if ((pScene && pScene->HasMapAttribute(x,y,aaSaft)) && m_pEntity->GetType() == enPet) continue;
|
||
// {
|
||
// ((CActor*)m_pEntity)->SendTipmsg(_T("对方在安全区中,不能攻击"),tstFigthing);
|
||
// return false;
|
||
//这里是技能的结果
|
||
// }
|
||
|
||
INT_PTR nResultCount= pRange->skillResults.count;
|
||
param.pTargetEntity = (CAnimal*)pEntity;
|
||
for(INT_PTR resultID = 0; resultID < nResultCount; resultID ++)
|
||
{
|
||
param.pSkillResult = &(pRange->skillResults[resultID]);
|
||
m_skillResult.DoResult(¶m);
|
||
}
|
||
|
||
|
||
//单体技能只能攻击1人
|
||
if (stSkillRangeRotationSingle == pRange->rangeType || stSkillRangeSingle == pRange->rangeType)
|
||
break;
|
||
}
|
||
}
|
||
|
||
//检测技能在特殊的buff下能够使用
|
||
INT_PTR CSkillSubSystem::CheckSpecialBuff(const OneSkillData * pSkill)
|
||
{
|
||
if(pSkill)
|
||
{
|
||
if(pSkill->bSpecialBuffCond == stSkillSpecialBuffAll) //在任何的封断都能够使用
|
||
{
|
||
return tpNoError;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return tpNoError; //普通攻击不受这个影响
|
||
}
|
||
CBuffSystem *pBuff = m_pEntity->GetBuffSystem();
|
||
if(pBuff ==NULL) return tpNoError;
|
||
//麻痹
|
||
INT_PTR ndizzy = m_pEntity->GetProperty<int>(PROP_CREATURE_DIZZY_STATUS);
|
||
if( pBuff->Exists( aDizzy ) || pBuff->Exists(aSlient) || ndizzy)
|
||
{
|
||
if(pSkill->bSpecialBuffCond == stSkillSpecialBuffDizzy) //在晕眩的时候可以用
|
||
{
|
||
return tpNoError;
|
||
}
|
||
else
|
||
{
|
||
return tpSkillTrainWithBuff;
|
||
}
|
||
}
|
||
/*
|
||
if( pBuff->Exists( GAMEATTRTYPE(aInnnerSkillForbid) ) )//被封了
|
||
{
|
||
if(pSkill->nSkillType == stInnerSingleAttackSkill || pSkill->nSkillType == stInnerGroupAttackSkill) //如果被封断了
|
||
{
|
||
if(pSkill->bSpecialBuffCond == stSkillSpecialBuffFengDuan) //在封的时候可以用
|
||
{
|
||
return tpNoError;
|
||
}
|
||
else
|
||
{
|
||
return tpSkillTrainWithBuff;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
if( pBuff->Exists( GAMEATTRTYPE(aOutSkillForbid) ) )
|
||
{
|
||
if(pSkill->nSkillType == stOutSingleAttackSkill || pSkill->nSkillType == stOutGroupAttackSkill) //如果被封断了
|
||
{
|
||
if(pSkill->bSpecialBuffCond == stSkillSpecialBuffFengDuan) //在封的时候可以用
|
||
{
|
||
return tpNoError;
|
||
}
|
||
else
|
||
{
|
||
return tpSkillTrainWithBuff;
|
||
}
|
||
}
|
||
}
|
||
*/
|
||
|
||
return tpNoError;
|
||
}
|
||
|
||
// void CSkillSubSystem::AutoLearnSkill()
|
||
// {
|
||
// if(m_pEntity->GetType() != enActor) return;
|
||
|
||
// int nVocation = m_pEntity->GetProperty<int>(PROP_ACTOR_VOCATION);//玩家的职业
|
||
|
||
// CSkillProvider * pProvider =GetLogicServer()->GetDataProvider()->GetSkillProvider();
|
||
// for(INT_PTR i=1; i< pProvider->count(); i++)
|
||
// {
|
||
// const OneSkillData *pData= pProvider->GetSkillData(i);
|
||
// if(pData)
|
||
// {
|
||
// if (pData->bVocation == nVocation && pData->nSkillType == stPassiveSkill &&
|
||
// pData->boNotAutoLearn ) //能自动升级本职业的被动技能(必须配置自动学习)
|
||
// {
|
||
// INT_PTR nSkillLevel = GetSkillLevel(i);
|
||
// for(INT_PTR j=nSkillLevel+1; j <= pData->levels.count; j++)
|
||
// {
|
||
// if(tpNoError != LearnSkill( i, j ))
|
||
// {
|
||
// break;
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
// }
|
||
// //pProvider->[]
|
||
// }
|
||
|
||
void CSkillSubSystem::AutoLearnVocSkill(int nLevel)
|
||
{
|
||
if (m_pEntity->GetType() != enActor) return;
|
||
|
||
int nVocation = m_pEntity->GetProperty<int>(PROP_ACTOR_VOCATION);//玩家的职业
|
||
|
||
CSkillProvider *pProvider = GetLogicServer()->GetDataProvider()->GetSkillProvider();
|
||
for (INT_PTR i = 1; i < pProvider->count(); i++)
|
||
{
|
||
const OneSkillData *pData= pProvider->GetSkillData(i);
|
||
if(pData)
|
||
{
|
||
if(pData->bVocation == nVocation &&
|
||
(pData->bSkillClass == scSkillClassVocBasic))
|
||
{
|
||
// if (pData->nSkillType == stPassiveSkill)
|
||
// {
|
||
// nLevel = 3;
|
||
// }
|
||
INT_PTR nError = LearnSkill(pData->nSkillID, nLevel, false, true);
|
||
if (nError != 0 )
|
||
{
|
||
OutputMsg(rmWaning,_T("Learnskill:%d,error:%d"),pData->nSkillID,nError);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//获取cd
|
||
void CSkillSubSystem::OnGetCd(INT_PTR nSkillID)
|
||
{
|
||
|
||
PSKILLDATA pSkillInfo = GetSkillInfoPtr(nSkillID);
|
||
if( NULL == pSkillInfo ) return ;
|
||
if (m_pEntity->GetType() != enActor) return;
|
||
|
||
if ( ((CActor*)m_pEntity)->OnGetIsTestSimulator()
|
||
|| ((CActor*)m_pEntity)->OnGetIsSimulator())
|
||
{
|
||
return;
|
||
}
|
||
|
||
CActorPacket pack;
|
||
CDataPacket & data = ((CActor*)m_pEntity)->AllocPacket(pack);
|
||
data << (BYTE) enSkillSystemID << (BYTE) sSendSkillCd;
|
||
data << (WORD) nSkillID ;
|
||
int nLeftTick = (int)(pSkillInfo->tick - GetGlobalLogicEngine()->getTickCount());
|
||
if(nLeftTick <0) nLeftTick =0;
|
||
data << (int) nLeftTick;
|
||
pack.flush();
|
||
}
|
||
|
||
//初始化技能数据
|
||
bool CSkillSubSystem::Initialize(void *data,SIZE_T size)
|
||
{
|
||
|
||
if(m_pEntity ==NULL ) return false;
|
||
bool bIsUser = m_pEntity->GetHandle().GetType() == enActor;
|
||
|
||
if(bIsUser)
|
||
{
|
||
if(data ==NULL) return false;
|
||
PACTORDBDATA pActorData = (ACTORDBDATA *)data;
|
||
if(pActorData ==NULL || size != sizeof(ACTORDBDATA))
|
||
{
|
||
OutputMsg(rmError,_T("data len error len=%d ,correct len=%d"),size, sizeof(ACTORDBDATA));
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
//判断是否启用技能CD
|
||
inline bool CSkillSubSystem::GetEnableCD()
|
||
{
|
||
return !m_pEntity->HasState(esDisableSkillCD);
|
||
}
|
||
|
||
//设置技能CD启用与否
|
||
void CSkillSubSystem::SetEnableCD(bool boEnable)
|
||
{
|
||
boEnable ? m_pEntity->RemoveState(esDisableSkillCD) : m_pEntity->AddState(esDisableSkillCD);
|
||
}
|
||
|
||
//
|
||
void CSkillSubSystem::ResetSkillCd(PSKILLDATA pSkill,const SKILLONELEVEL * pLevel)
|
||
{
|
||
if(pSkill ==NULL || pLevel ==NULL) return;
|
||
INT_PTR nTime = pLevel->nCooldownTimes; //技能的冷却时间
|
||
if(nTime != pSkill->nCoolDownTime)
|
||
{
|
||
if(m_pEntity->GetType() ==enActor ) //如果本身是一个玩家的话
|
||
{
|
||
CActorPacket pack;
|
||
CDataPacket & data = ((CActor*)m_pEntity)->AllocPacket(pack);
|
||
data << (BYTE) enSkillSystemID << (BYTE) sSetSkillCdTime;
|
||
data << (WORD) pSkill->nSkillID ;
|
||
data <<(BYTE) pSkill->nLevel;
|
||
data << (int) nTime;
|
||
pack.flush();
|
||
}
|
||
pSkill->nCoolDownTime = (int)nTime;
|
||
}
|
||
}
|
||
|
||
VOID CSkillSubSystem::OnTimeCheck(TICKCOUNT nTick)
|
||
{
|
||
if (!m_pEntity)
|
||
{
|
||
return;
|
||
}
|
||
if(m_currentSingSkillID ==0 ) return;
|
||
|
||
if(m_singTimer.Check(nTick))
|
||
{
|
||
if(m_currentSingSkillID == GATHER_SKILL_ID) //如果是采集怪
|
||
{
|
||
//到时间了就杀死这个怪物
|
||
CMonster *pMonster =(CMonster *) GetEntityFromHandle(m_hSingTarget);
|
||
if(pMonster !=NULL && !pMonster->IsDeath())
|
||
{
|
||
bool boResult = true;
|
||
int nMonsterType = pMonster->GetMonsterType();
|
||
if ( nMonsterType == MONSTERCONFIG::mtFubenCollect)
|
||
{
|
||
CActor * pActor = (CActor *)m_pEntity;
|
||
static int nItemId = GetLogicServer()->GetDataProvider()->GetGlobalConfig().nHammerItemId;
|
||
CUserItemContainer::ItemOPParam itemPara;
|
||
itemPara.wItemId = nItemId;
|
||
itemPara.wCount = 1;//设置一个大的数字,不用先看背包有多少这个物品
|
||
itemPara.btStrong = -1;
|
||
itemPara.btQuality = -1;
|
||
if (pActor->GetBagSystem().GetItemCount(nItemId, -1,-1, 1) > 0 )
|
||
{
|
||
itemPara.btBindFlag = 1;
|
||
}
|
||
else
|
||
itemPara.btBindFlag = -1;
|
||
|
||
if(pActor->GetBagSystem().DeleteItem(itemPara,m_pEntity->GetEntityName(),GameLog::clFubenCollectRemItem) <= 0)
|
||
{
|
||
pActor->SendOldTipmsgWithId(tpFubenCollectNotItem, ttFlyTip);
|
||
boResult = false;
|
||
}
|
||
}
|
||
else if(nMonsterType == MONSTERCONFIG::mtCollectOnce)
|
||
{
|
||
unsigned int nMyId = m_pEntity->GetId();
|
||
CMiscMgr & miscMgr = GetGlobalLogicEngine()->GetMiscMgr();
|
||
pMonster->SetBeAttackActorList(nMyId);
|
||
}
|
||
if (boResult)
|
||
{
|
||
pMonster->SetVestEntity(m_pEntity->GetHandle());
|
||
pMonster->SetVestAttackTime(GetGlobalLogicEngine()->getTickCount());
|
||
if (pMonster->GetAttriFlag().boShowVestEntityName)
|
||
{
|
||
pMonster->SetVestEntityName(m_pEntity->GetEntityName());
|
||
}
|
||
pMonster->ChangeHP (-1 *pMonster->GetProperty<int>(PROP_CREATURE_HP));
|
||
if( pMonster->GetProperty<unsigned int>(PROP_CREATURE_HP) ==0)
|
||
{
|
||
pMonster->OnKilledByEntity(m_pEntity);
|
||
}
|
||
else
|
||
{
|
||
if (nMonsterType == MONSTERCONFIG::mtGirl || nMonsterType == MONSTERCONFIG::mtCollectOnce)
|
||
{
|
||
pMonster->OnKilledByEntity(m_pEntity);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
OutputMsg(rmWaning,_T("Gath is not SingskillId"));
|
||
}
|
||
m_currentSingSkillID =0;
|
||
m_pEntity->RemoveState(esStateSing);
|
||
}
|
||
|
||
}
|
||
|
||
void CSkillSubSystem::EndSingSpell(bool isPositive)
|
||
{
|
||
//结束吟唱
|
||
if( m_pEntity->HasState(esStateSing) ==false) return;
|
||
|
||
CActorPacket pack;
|
||
CDataPacket & data = ((CActor*)m_pEntity)->AllocPacket(pack);
|
||
data << (BYTE) enSkillSystemID << (BYTE) sGatherMonsterProgress;
|
||
|
||
data << (BYTE)m_pEntity->GetProperty<unsigned int>(PROP_ENTITY_DIR);
|
||
data << (int) 0;
|
||
|
||
pack.flush();
|
||
m_pEntity->RemoveState(esStateSing);
|
||
m_currentSingSkillID =0;
|
||
}
|
||
|
||
INT_PTR CSkillSubSystem::GetSpellTargetDistance( INT_PTR nSkillID, INT_PTR nSkillLevel)
|
||
{
|
||
const SKILLONELEVEL * pLevel = GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillLevelData(nSkillID,nSkillLevel);
|
||
if( pLevel == NULL)
|
||
{
|
||
return 0;
|
||
}
|
||
const DataList<SKILLTRAINSPELLCONDITION> & spellConditions = pLevel->spellConditions ;
|
||
INT_PTR nConditionCount= spellConditions.count;
|
||
|
||
for (INT_PTR i =0; i< nConditionCount ; i++ )
|
||
{
|
||
if(spellConditions[i].nConditionID == scSkillConditionTargetDistance)
|
||
{
|
||
return spellConditions[i].nValue;
|
||
}
|
||
}
|
||
return -1; //没有距离限制
|
||
|
||
}
|
||
|
||
void CSkillSubSystem::BroadSpellSkill(INT_PTR nSkillID,INT_PTR nLevel,INT_PTR nDir,INT_PTR nAuxParam, unsigned short nX, unsigned short nY)
|
||
{
|
||
//播放怪物声音
|
||
int nMusicId =0; //播放的声音
|
||
|
||
if(m_pEntity->IsMonster())
|
||
{
|
||
if(m_attackMusicRate ==BYTE(-1))
|
||
{
|
||
const PMONSTERCONFIG pMonster= GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(m_pEntity->GetProperty<int>(PROP_ENTITY_ID));
|
||
if( pMonster !=NULL )
|
||
{
|
||
m_attackMusicRate = pMonster->bAttackMusicRate;
|
||
m_attackMusicID = pMonster->bAttackMusicId;
|
||
}
|
||
}
|
||
if(m_attackMusicID !=0 && m_attackMusicRate !=0)
|
||
{
|
||
//需要播放声音了
|
||
if(m_attackMusicRate >= wrand(101))
|
||
{
|
||
nMusicId = m_attackMusicID;
|
||
}
|
||
}
|
||
}
|
||
|
||
char buff[128];
|
||
CDataPacket pack(buff,sizeof(buff));
|
||
pack << (BYTE) enDefaultEntitySystemID ;
|
||
if(nSkillID) //这个是释放技能,如果是0表示是普通攻击
|
||
{
|
||
pack << (BYTE) sStartSpellSkill;
|
||
pack << (Uint64) m_pEntity->GetHandle() << (WORD) nSkillID << (BYTE) nLevel << (BYTE) nDir << nAuxParam << nX << nY;
|
||
}
|
||
else //肉搏
|
||
{
|
||
pack << (BYTE) sNearAttack;
|
||
pack << (Uint64) m_pEntity->GetHandle() << (BYTE) nLevel << (BYTE) nDir <<(WORD)nAuxParam <<nMusicId;
|
||
}
|
||
m_pEntity->GetObserverSystem()->BroadCast(pack.getMemoryPtr(),pack.getPosition(),true);
|
||
}
|
||
|
||
void CSkillSubSystem::CheckSkillOnConditionChange(INT_PTR nSkillClass)
|
||
{
|
||
if(m_pEntity ==NULL || m_pEntity->GetType() != enActor) return;
|
||
|
||
|
||
CSkillProvider* pProvider = GetLogicServer()->GetDataProvider()->GetSkillProvider();
|
||
INT_PTR nCount = pProvider->count(); //技能的数量
|
||
|
||
|
||
for (INT_PTR i =1 ; i < nCount ; i ++)
|
||
{
|
||
const OneSkillData *pSkill = pProvider->GetSkillData(i);
|
||
if(pSkill ==NULL ) continue; //如果这个技能已经删除的话也不能学习
|
||
|
||
INT_PTR nSkillId =pSkill->nSkillID; //技能的ID
|
||
|
||
SKILLONELEVEL * pLevel = pProvider->GetSkillLevelData(nSkillId,1);
|
||
if(pLevel ==NULL) continue;
|
||
|
||
if(pSkill->bSkillClass == nSkillClass) //技能的分类是一样的
|
||
{
|
||
PSKILLDATA pSkillLevel= GetSkillInfoPtr(nSkillId);
|
||
bool isInvalid =true;
|
||
for(INT_PTR j=0; j< pLevel->trainConditions.count; j++ ) //检查有哪些条件无法满足了,不满足的就要遗忘技能
|
||
{
|
||
PSKILLTRAINSPELLCONDITION pCondition = pLevel->trainConditions.pData +j;
|
||
//条件不满足了
|
||
if(tpNoError != m_targetCondition.CheckUpGradeContion((CActor*)m_pEntity,nSkillId,*pCondition,false))
|
||
{
|
||
isInvalid =false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if(isInvalid ==false ) //该技能可以遗忘了
|
||
{
|
||
if(pSkillLevel != NULL)
|
||
{
|
||
ForgetSkill(nSkillId); //遗忘这个技能了
|
||
}
|
||
}
|
||
else //能够学习这个技能了
|
||
{
|
||
//这些技能都只有1级
|
||
if( pSkillLevel ==NULL)
|
||
{
|
||
LearnSkill(nSkillId,1); //学习1级技能
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//遗忘一个技能
|
||
bool CSkillSubSystem::ForgetSkill(INT_PTR nSkillId)
|
||
{
|
||
bool bResult = false;
|
||
int nSkillLevel = 0;
|
||
for (INT_PTR i =0 ; i< m_skillList.count();i ++)
|
||
{
|
||
if(m_skillList[i].nSkillID ==nSkillId )
|
||
{
|
||
nSkillLevel = m_skillList[i].nLevel;
|
||
m_skillList.remove(i);
|
||
bResult = true;
|
||
break;
|
||
}
|
||
}
|
||
if(bResult)
|
||
{
|
||
const OneSkillData * pSkill =GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(nSkillId);
|
||
if(pSkill ==NULL ) return false;
|
||
if(m_pEntity->GetType() == enActor)
|
||
{
|
||
((CActor *)m_pEntity)->SendOldTipmsgFormatWithId(tpSkillForgetSkill,ttFlyTip, pSkill->sSkillName);
|
||
//通知客户端已经遗忘了一个技能
|
||
CActorPacket pack;
|
||
CDataPacket &data=((CActor*)m_pEntity)->AllocPacket(pack);
|
||
data << (BYTE)(enSkillSystemID) << (BYTE)sForgetSkill << (WORD) nSkillId ;
|
||
pack.flush();
|
||
}
|
||
if(pSkill->nSkillType == stPassiveSkill || pSkill->bBeedCalPassiveProperty) //如果是被动技能需要刷属性
|
||
{
|
||
//设置角色刷新属性的标记
|
||
m_pEntity->CollectOperate(CEntityOPCollector::coRefAbility);
|
||
OnForgetPassSkill(pSkill,nSkillLevel);
|
||
}
|
||
|
||
SetDataModifyFlag(true); //数据发生了改变
|
||
}
|
||
|
||
return bResult;
|
||
}
|
||
|
||
bool CSkillSubSystem::ForgetSkillByClass(INT_PTR nSkillClass)
|
||
{
|
||
if(m_pEntity ==NULL || m_pEntity->GetType() != enActor) return false;
|
||
|
||
CSkillProvider *pProvider = GetLogicServer()->GetDataProvider()->GetSkillProvider();
|
||
INT_PTR nCount = pProvider->count();
|
||
|
||
for (INT_PTR i = 0; i < nCount; i++)
|
||
{
|
||
const OneSkillData *pSkill = pProvider->GetSkillData(i);
|
||
if(pSkill == NULL ) continue; //如果这个技能已经删除的话也不能学习
|
||
|
||
INT_PTR nSkillId = pSkill->nSkillID; //技能的ID
|
||
|
||
SKILLONELEVEL *pLevel = pProvider->GetSkillLevelData(nSkillId,1);
|
||
if(pLevel == NULL) continue;
|
||
|
||
if(pSkill->bSkillClass == nSkillClass) //技能的分类是一样的
|
||
{
|
||
PSKILLDATA pSkillLevel= GetSkillInfoPtr(nSkillId);
|
||
if(pSkillLevel != NULL ) //已经删除的技能,铁定要删除的
|
||
{
|
||
ForgetSkill(nSkillId); //遗忘这个技能
|
||
}
|
||
}
|
||
}
|
||
SetDataModifyFlag(true); //数据发生了改变
|
||
return true;
|
||
}
|
||
|
||
|
||
//下发已经学习的技能列表
|
||
void CSkillSubSystem::SendLearnSkill()
|
||
{
|
||
if(m_pEntity ==NULL) return;
|
||
CActorPacket pack;
|
||
CDataPacket &data=((CActor*)m_pEntity)->AllocPacket(pack);
|
||
|
||
//初始化玩家的技能 BYTE:count,( WORD:nSkillID,char:nLevel,unsigned char:nLearnedSecretSauce,unsigned int nExpOrCd) count个
|
||
data << (BYTE)(enSkillSystemID) << (BYTE)sInitUserSkill;
|
||
INT_PTR nCountOffer = data.getPosition();
|
||
data << (BYTE) m_skillList.count();
|
||
int nCount = 0;
|
||
|
||
for (INT_PTR i = 0 ; i < m_skillList.count(); i++)
|
||
{
|
||
SKILLDATA& skillData = m_skillList[i];
|
||
TICKCOUNT nLeftTick = skillData.tick - GetGlobalLogicEngine()->getTickCount() ;
|
||
if(nLeftTick <0) nLeftTick = 0;
|
||
|
||
const OneSkillData * pSkill =GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(skillData.nSkillID);
|
||
if (pSkill->boIsDelete) continue;
|
||
|
||
data << (WORD)skillData.nSkillID << (BYTE)skillData.nLevel;
|
||
data << (int)nLeftTick;
|
||
BYTE nActiveState = 0;//技能是否激活可用
|
||
nActiveState = !skillData.nIsClosed;
|
||
data << (BYTE)nActiveState;
|
||
data << (BYTE)skillData.bIsClose;
|
||
nCount++;
|
||
}
|
||
INT_PTR nFinishOffer = data.getPosition();
|
||
data.setPosition(nCountOffer);
|
||
data << (BYTE)nCount;
|
||
data.setPosition(nFinishOffer);
|
||
pack.flush();
|
||
|
||
UpdateNextSkillFlag();
|
||
}
|
||
|
||
void CSkillSubSystem::SendPetSkillCountChange(INT_PTR nSkillId, INT_PTR nCount)
|
||
{
|
||
if (m_pEntity == NULL || !m_pEntity->IsInited())
|
||
{
|
||
return;
|
||
}
|
||
CActorPacket pack;
|
||
CDataPacket &data=((CActor*)m_pEntity)->AllocPacket(pack);
|
||
data << (BYTE)(enSkillSystemID) << (BYTE)sSkillSystemPetCountChange <<(WORD)nSkillId <<(BYTE)nCount;
|
||
pack.flush();
|
||
}
|
||
|
||
void CSkillSubSystem::OnLevelUp(int nLevel)
|
||
{
|
||
if (m_pEntity->GetType() == enActor)
|
||
{
|
||
int nVocation = m_pEntity->GetProperty<int>(PROP_ACTOR_VOCATION);//玩家的职业
|
||
CSkillProvider * pProvider = GetLogicServer()->GetDataProvider()->GetSkillProvider();
|
||
|
||
// 检测职业技能
|
||
{
|
||
std::vector<OneSkillData*>& skills = pProvider->GetVocationSKills(nVocation);
|
||
int nCount = skills.size();
|
||
for(INT_PTR i=0; i< nCount; i++)
|
||
{
|
||
const OneSkillData *pData= skills[i];
|
||
if(pData)
|
||
{
|
||
if (pData->bIsAutoLearn && (pData->bVocation == nVocation))
|
||
{
|
||
if (nLevel >= pData->nAutoLearnSkillLvl)
|
||
{
|
||
INT_PTR nSkillLevel = GetSkillLevel(pData->nSkillID);
|
||
if(nSkillLevel == 0 && tpNoError != LearnSkill( pData->nSkillID, 1 ))
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 检测非职业技能
|
||
{
|
||
std::vector<OneSkillData*>& skills = pProvider->GetVocationSKills(0);
|
||
int nCount = skills.size();
|
||
for(INT_PTR i=0; i< nCount; i++)
|
||
{
|
||
const OneSkillData *pData= skills[i];
|
||
if(pData)
|
||
{
|
||
if (pData->bIsAutoLearn && (pData->bVocation == 0))
|
||
{
|
||
if (nLevel >= pData->nAutoLearnSkillLvl)
|
||
{
|
||
INT_PTR nSkillLevel = GetSkillLevel(pData->nSkillID);
|
||
if(nSkillLevel == 0 && tpNoError != LearnSkill(pData->nSkillID, 1 ))
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void CSkillSubSystem::OnEnterGame()
|
||
{
|
||
const SKILLONELEVEL * pLevel;
|
||
CSkillProvider* provider = GetLogicServer()->GetDataProvider()->GetSkillProvider();
|
||
for(INT_PTR i=0;i < m_skillList.count(); i++)
|
||
{
|
||
pLevel= provider->GetSkillLevelData(m_skillList[i].nSkillID, m_skillList[i].nLevel);
|
||
if(pLevel)
|
||
{
|
||
ResetSkillCd(&m_skillList[i], pLevel);
|
||
}
|
||
}
|
||
|
||
if (((CActor*)m_pEntity)->m_isFirstLogin)
|
||
{
|
||
int nVocation = m_pEntity->GetProperty<int>(PROP_ACTOR_VOCATION);//玩家的职业
|
||
int nLevel = m_pEntity->GetProperty<int>(PROP_CREATURE_LEVEL);//玩家等级
|
||
CSkillProvider * pProvider =GetLogicServer()->GetDataProvider()->GetSkillProvider();
|
||
for(INT_PTR i=1; i< pProvider->count(); i++)
|
||
{
|
||
const OneSkillData *pData= pProvider->GetSkillData(i);
|
||
if(pData)
|
||
{
|
||
if (pData->bIsAutoLearn && (pData->bVocation == 0 || pData->bVocation == nVocation))
|
||
{
|
||
if (nLevel >= pData->nAutoLearnSkillLvl)
|
||
{
|
||
INT_PTR nSkillLevel = GetSkillLevel(i);
|
||
for(INT_PTR j=nSkillLevel+1; j <= pData->levels.count; j++)
|
||
{
|
||
if(tpNoError != LearnSkill( i, j ))
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 新创建角色,默认技能快捷键
|
||
int maxidx = 10;
|
||
int maxidxApp = 4;
|
||
std::vector<int>& skillList = GetLogicServer()->GetDataProvider()->GetFirstLoginKeySet();
|
||
for (size_t i = 0; i < skillList.size() && i <= maxidx; i++)
|
||
{
|
||
int skillid = skillList[i];
|
||
((CActor*)m_pEntity)->GetGameSetsSystem().DoUpdateGameSetsData(1,maxidx--,skillid,-1);
|
||
((CActor*)m_pEntity)->GetGameSetsSystem().DoUpdateGameSetsDataApp(1,maxidxApp--,skillid,-1);
|
||
}
|
||
}
|
||
}
|
||
|
||
//1表示启用,0表示不启用就是停止
|
||
void CSkillSubSystem::HandSetSkillOpen(INT_PTR nSkillId,INT_PTR nFlag)
|
||
{
|
||
PSKILLDATA pSkill= GetSkillInfoPtr(nSkillId);
|
||
if(pSkill ==NULL) return;
|
||
//技能的配置的数据
|
||
const OneSkillData * pSkillData= GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(nSkillId);
|
||
if(pSkillData ==NULL) return ; //压根就没有这个技能
|
||
//if(pSkillData->bSkillClass != scSkillClassJianghuMulti) return; //不是在江湖绝学无法开启
|
||
|
||
if( pSkill->nIsClosed != (BYTE) nFlag) return; //状态本来就是对的
|
||
|
||
if(nFlag)
|
||
{
|
||
pSkill->nIsClosed =0;
|
||
}
|
||
else
|
||
{
|
||
pSkill->nIsClosed =1; //关闭
|
||
}
|
||
CActorPacket pack;
|
||
CDataPacket &data=((CActor*)m_pEntity)->AllocPacket(pack);
|
||
data << (BYTE)(enSkillSystemID) << (BYTE)sSetSkillOpen <<(WORD)nSkillId <<(BYTE)nFlag;
|
||
pack.flush();
|
||
}
|
||
|
||
int qsortSkillCmp(const void *a ,const void *b)
|
||
{
|
||
CSkillSubSystem::SKILLDATA *SkillA = (CSkillSubSystem::SKILLDATA*)a;
|
||
CSkillSubSystem::SKILLDATA *SkillB= (CSkillSubSystem::SKILLDATA*)b;
|
||
if(SkillA->nCoolDownTime < SkillB->nCoolDownTime)
|
||
return -1;
|
||
else if (SkillA->nCoolDownTime == SkillB->nCoolDownTime)
|
||
return 0;
|
||
return 1;
|
||
}
|
||
|
||
//学习技能
|
||
INT_PTR CSkillSubSystem::LearnSkill(INT_PTR nSkillID, INT_PTR nLevelID,bool bIsClose, bool bForce ,bool bSort)
|
||
{
|
||
INT_PTR nErrorCode = GetLearnSkillErrorCode(nSkillID ,nLevelID, bForce) ;
|
||
if(nErrorCode == tpNoError)
|
||
{
|
||
StartRealLearnSkill(nSkillID,nLevelID,bIsClose);
|
||
}
|
||
if(bSort)
|
||
{
|
||
INT_PTR nCount = m_skillList.count();
|
||
qsort(&m_skillList[0], nCount, sizeof(m_skillList[0]),qsortSkillCmp);
|
||
}
|
||
return nErrorCode;
|
||
}
|
||
|
||
|
||
/*正式开始学习技能
|
||
扣除需要的资源
|
||
*/
|
||
void CSkillSubSystem::StartRealLearnSkill(INT_PTR nSkillID, INT_PTR nLevelID, bool bIsClose)
|
||
{
|
||
CSkillProvider *provider= GetLogicServer()->GetDataProvider()->GetSkillProvider();
|
||
const OneSkillData * pSkillData = provider->GetSkillData(nSkillID);
|
||
const SKILLONELEVEL * pLevel = provider->GetSkillLevelData(nSkillID,nLevelID);
|
||
if(pLevel ==NULL || pSkillData==NULL ) return;
|
||
|
||
DataList<SKILLTRAINSPELLCONDITION> const& spellConditions = pLevel->trainConditions ;
|
||
bool isActor = m_pEntity->GetHandle().GetType() == enActor;
|
||
INT_PTR nNewLevel = 1;
|
||
|
||
//升级消耗
|
||
if(isActor)
|
||
{
|
||
if (pSkillData->bSkillClass == scSkillClassMonster )
|
||
{
|
||
return;
|
||
}
|
||
//是否删除
|
||
if (pSkillData->boIsDelete)
|
||
{
|
||
return;
|
||
}
|
||
for(INT_PTR i = 0; i< spellConditions.count; i++)
|
||
{
|
||
if(spellConditions[i].bConsumed ==false || spellConditions[i].nValue ==0) continue; //如果不需要消耗就不消耗
|
||
m_targetCondition.CheckUpGradeContion(m_pEntity,nSkillID,spellConditions[i],true ); //去消耗
|
||
}
|
||
}
|
||
|
||
//以前是否学习过这个技能
|
||
bool hasLearned = false;
|
||
for (INT_PTR i =0 ; i< m_skillList.count();i ++)
|
||
{
|
||
if(m_skillList[i].nSkillID == nSkillID )
|
||
{
|
||
m_skillList[i].nLevel =(int)nLevelID;
|
||
m_skillList[i].bIsClose = bIsClose ?1:0;
|
||
nNewLevel = m_skillList[i].nLevel;
|
||
m_skillList[i].nCoolDownTime = pLevel->nCooldownTimes;
|
||
hasLearned = true;
|
||
break;
|
||
}
|
||
}
|
||
if(hasLearned == false)
|
||
{
|
||
BYTE bConfigPriority = pSkillData->bPriority; //优先级
|
||
|
||
if(nLevelID <=0)
|
||
{
|
||
nLevelID =1;
|
||
}
|
||
SKILLDATA data;
|
||
data.nSkillID =(WORD) nSkillID;
|
||
data.nLevel = (BYTE)nLevelID;
|
||
data.nCd =0;
|
||
data.nIsClosed = 1;
|
||
data.tick = GetGlobalLogicEngine()->getTickCount();
|
||
data.nExp =0;
|
||
data.nMijiExpiredTime=0;
|
||
data.bMjMask =0;
|
||
data.nMijiId =0;
|
||
data.bEvent =0;
|
||
data.bPriority =bConfigPriority;
|
||
data.nCoolDownTime = pLevel->nCooldownTimes; //冷却时间
|
||
data.nLastDbCd = 0;
|
||
data.bIsClose = bIsClose ?1:0;
|
||
data.bIsPassive = ((pSkillData->nSkillType == stPassiveSkill)?1:0);
|
||
data.nSkillType = pSkillData->nSkillType;
|
||
|
||
if(bConfigPriority >0)
|
||
{
|
||
INT_PTR nPos =0;
|
||
for(INT_PTR i=0; i < m_skillList.count(); i++)
|
||
{
|
||
if( bConfigPriority >= m_skillList[i].bPriority )
|
||
{
|
||
nPos =i;
|
||
break;
|
||
}
|
||
}
|
||
m_skillList.insert(nPos,data);
|
||
}
|
||
else
|
||
{
|
||
m_skillList.add(data); //学习一个技能成功
|
||
}
|
||
|
||
if(pSkillData->nSkillType != stPassiveSkill && (pSkillData->bSkillClass == scSkillClassVocBasic) && (m_pEntity->GetHandle().GetType() == enActor) ) //学习技能自动补位
|
||
((CActor*)m_pEntity)->GetGameSetsSystem().AutoGameSetSkill(1, nSkillID);
|
||
}
|
||
|
||
//向玩家发送数据包,技能学习成功
|
||
if( m_pEntity->GetHandle().GetType() == enActor ) //如果是一个玩家的话,还需要发条消息到客户端
|
||
{
|
||
CActorPacket pack;
|
||
CActor *pActor = ((CActor*)m_pEntity) ;
|
||
CDataPacket &data = pActor->AllocPacket(pack);
|
||
data << (BYTE)enSkillSystemID << (BYTE)sTrainSkillResult << (WORD)nSkillID << (BYTE)nLevelID;
|
||
data << (int)(pLevel->nCooldownTimes);
|
||
SKILLDATA * pSkill = GetSkillInfoPtr(nSkillID);
|
||
data << (BYTE)(!pSkill->nIsClosed);
|
||
data << (BYTE)pSkill->bIsClose;
|
||
pack.flush();
|
||
//pActor->GetQuestSystem()->OnEvent(CQuestData::qtSkillLevel,nSkillID,nNewLevel);
|
||
if(nNewLevel ==1) //通知玩家成功学习一个技能
|
||
{
|
||
((CActor *)m_pEntity)->SendTipmsgFormatWithId(tmSuccLearnSkill,tstUI,pSkillData->sSkillName);
|
||
}
|
||
else
|
||
{
|
||
//技能等级提升
|
||
((CActor *)m_pEntity)->SendTipmsgFormatWithId(tmSuccUpgrSkill,tstUI,pSkillData->sSkillName,nNewLevel);
|
||
}
|
||
}
|
||
|
||
//如果是被动技能需要刷属性
|
||
if(pSkillData->nSkillType == stPassiveSkill || pSkillData->bBeedCalPassiveProperty)
|
||
{
|
||
//设置角色刷新属性的标记
|
||
m_pEntity->CollectOperate(CEntityOPCollector::coRefAbility);
|
||
}
|
||
|
||
//技能发生了改变
|
||
SetDataModifyFlag(true);
|
||
|
||
//累计技能等级
|
||
if(isActor)
|
||
{
|
||
((CActor*)m_pEntity)->GetQuestSystem()->OnQuestEvent(CQuestData::qtSkillLv, nLevelID,nSkillID);
|
||
// CActor *pActor = ((CActor*)m_pEntity) ;
|
||
// int nTotalSkillLevel = 0;
|
||
// for (INT_PTR i =0 ; i< m_skillList.count();i ++)
|
||
// {
|
||
// const OneSkillData * pSkill =GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(m_skillList[i].nSkillID);
|
||
// if(pSkill != NULL && pSkill->bSkillClass == scSkillClassVocBasic) //技能的分类是一样的
|
||
// {
|
||
// nTotalSkillLevel += m_skillList[i].nLevel;
|
||
// }
|
||
//
|
||
|
||
// }
|
||
}
|
||
|
||
//强制开启半月
|
||
if (nSkillID == 4 || nSkillID == 3)
|
||
{
|
||
SwitchSkill(nSkillID,1);
|
||
}
|
||
|
||
// //技高一筹
|
||
// OneNewTitleConfig* pConfig = GetLogicServer()->GetDataProvider()->GetNewTitlesConfig().GetNetTitleConfig(MAX_TOP_TITLE_SKILL);
|
||
// if(pConfig == NULL || pConfig->nConditionCount < 1 || !isActor)
|
||
// {
|
||
// return;
|
||
// }
|
||
|
||
// //技惊四座
|
||
// OneNewTitleConfig* pConfig2 = GetLogicServer()->GetDataProvider()->GetNewTitlesConfig().GetNetTitleConfig(MAX_TOP_TITLE_SKILL_2);
|
||
// if(pConfig2 == NULL || pConfig2->nConditionCount < 1 || !isActor)
|
||
// {
|
||
// return;
|
||
// }
|
||
|
||
// //技能头衔
|
||
// const int maxSkillNum = 6;
|
||
// if(maxSkillNum <= m_skillList.count())
|
||
// {
|
||
// int count = 0;
|
||
// int count2 = 0;
|
||
// for (INT_PTR i =0 ; i< m_skillList.count();i ++)
|
||
// {
|
||
// if( pConfig->ConditionList[0].value.nValue <= m_skillList[i].nLevel)
|
||
// {
|
||
// const OneSkillData * pSkill =GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(m_skillList[i].nSkillID);
|
||
// if(pSkill != NULL && pSkill->bSkillClass == scSkillClassVocBasic) //技能的分类是一样的
|
||
// {
|
||
// count++;
|
||
// }
|
||
// }
|
||
// if( pConfig2->ConditionList[0].value.nValue <= m_skillList[i].nLevel)
|
||
// {
|
||
// const OneSkillData * pSkill =GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(m_skillList[i].nSkillID);
|
||
// if(pSkill != NULL && pSkill->bSkillClass == scSkillClassVocBasic) //技能的分类是一样的
|
||
// {
|
||
// count2++;
|
||
// }
|
||
// }
|
||
// }
|
||
// if(maxSkillNum <= count && ((CActor*)m_pEntity)->GetNewTitleSystem().IsHaveNewTitle(MAX_TOP_TITLE_SKILL) < 0 )
|
||
// {
|
||
// ((CActor*)m_pEntity)->GetNewTitleSystem().addNewTitle(MAX_TOP_TITLE_SKILL);
|
||
// }
|
||
// if(maxSkillNum <= count2 && ((CActor*)m_pEntity)->GetNewTitleSystem().IsHaveNewTitle(MAX_TOP_TITLE_SKILL_2) < 0)
|
||
// {
|
||
// ((CActor*)m_pEntity)->GetNewTitleSystem().addNewTitle(MAX_TOP_TITLE_SKILL_2);
|
||
// }
|
||
|
||
// }
|
||
|
||
////////////////////////////////////////////////////////////////////////////////////
|
||
}
|
||
|
||
bool CSkillSubSystem::HasLongCdSkill()
|
||
{
|
||
LONGLONG tick = GetGlobalLogicEngine()->getTickCount(); //当前的时间
|
||
unsigned int nCurrentTime = GetGlobalLogicEngine()->getMiniDateTime(); //当前的时间
|
||
size_t count = m_skillList.count();
|
||
for (UINT_PTR i=0; i<count; i ++ )
|
||
{
|
||
|
||
LONGLONG nLeftCdTime = m_skillList[i].tick - tick ; //还剩余多少时间
|
||
|
||
if(nLeftCdTime > 5000 ) //只有CD时间离当前的时间比较长的时候才需要这么做
|
||
{
|
||
if( m_skillList[i].nLastDbCd < nCurrentTime )
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
return false;
|
||
|
||
}
|
||
|
||
//存盘
|
||
void CSkillSubSystem::Save(PACTORDBDATA/* pData*/)
|
||
{
|
||
if(m_pEntity ==NULL || m_pEntity->GetType() != enActor) return;
|
||
if(HasDbDataInit() ==false)return; //如果DB数据没有初始化就不存盘
|
||
if(HasDataModified() || HasLongCdSkill())
|
||
{
|
||
size_t count = m_skillList.count();
|
||
//if(count <=0) return;
|
||
CDataPacket& dataPacket =GetLogicServer()->GetDbClient()->allocProtoPacket(jxInterSrvComm::DbServerProto::dcSaveSkill);
|
||
dataPacket << ((CActor *)m_pEntity)->GetRawServerIndex() << GetLogicServer()->GetServerIndex();
|
||
dataPacket <<(unsigned int ) m_pEntity->GetProperty<unsigned int>(PROP_ENTITY_ID); //玩家ID
|
||
INT_PTR pos = dataPacket.getPosition();
|
||
dataPacket << (int)0; //玩家技能的数量
|
||
int nSaveCount = 0;
|
||
ULONGLONG tick = GetGlobalLogicEngine()->getTickCount(); //当前的时间
|
||
unsigned int nCurrentTime= GetGlobalLogicEngine()->getMiniDateTime() ;
|
||
//玩家的技能的冷却是需要存盘的,根据当前的tickcount,然后算出还有多长时间过期
|
||
for (UINT_PTR i=0; i<count; i ++ )
|
||
{
|
||
|
||
const OneSkillData * pData =GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(m_skillList[i].nSkillID);
|
||
if (!pData || pData->bSkillClass == scSkillClassMonster)
|
||
{
|
||
continue;
|
||
}
|
||
LONGLONG nLeftCdTime = m_skillList[i].tick - tick ; //还剩余多少时间
|
||
if(nLeftCdTime >0 )
|
||
{
|
||
m_skillList[i].nCd =nCurrentTime+ (int)(nLeftCdTime/1000) ; //获取当前的时间
|
||
}
|
||
else
|
||
{
|
||
m_skillList[i].nCd =0;
|
||
}
|
||
m_skillList[i].nLastDbCd = m_skillList[i].nCd;
|
||
dataPacket.writeBuf(&m_skillList[i],sizeof( ONESKILLDBDATA) ); //只保持db需要的那部分
|
||
nSaveCount++;
|
||
}
|
||
int *pCount = (int *)dataPacket.getPositionPtr(pos);
|
||
*pCount = (int)nSaveCount;
|
||
GetLogicServer()->GetDbClient()->flushProtoPacket(dataPacket);
|
||
SetDataModifyFlag(false);
|
||
}
|
||
}
|
||
|
||
void CSkillSubSystem::SetSkillClose(INT_PTR nSkillID, bool isClose)
|
||
{
|
||
PSKILLDATA pData = GetSkillInfoPtr(nSkillID);
|
||
if(pData)
|
||
{
|
||
pData->bIsClose = isClose ?1:0;
|
||
}
|
||
}
|
||
|
||
//DB装载技能
|
||
VOID CSkillSubSystem::OnDbRetData(INT_PTR nCmd,INT_PTR nErrorCode,CDataPacketReader & reader )
|
||
{
|
||
if(m_pEntity ==NULL )
|
||
{
|
||
OutputMsg(rmError,_T("装载玩家技能的数据出错,实体指针为MULL"));
|
||
return;
|
||
}
|
||
//技能的配置的读取器
|
||
CSkillProvider *pSkillProvider = GetLogicServer()->GetDataProvider()->GetSkillProvider(); //技能数据读取器
|
||
CStdItemProvider & itemProvider = GetLogicServer()->GetDataProvider()->GetStdItemProvider(); //物品配置器
|
||
|
||
if(nCmd ==jxInterSrvComm::DbServerProto::dcLoadSkill && nErrorCode == jxInterSrvComm::DbServerProto::reSucc)
|
||
{
|
||
if(Inherid::HasDbDataInit()) return; //已经装载了这个技能数据
|
||
|
||
int count = 0;
|
||
reader >> count;
|
||
//if(count <=0) return;
|
||
//如果已经有数据,可能出现了一点问题
|
||
if(m_skillList.count() >0)
|
||
{
|
||
m_skillList.clear();
|
||
}
|
||
|
||
//这里写玩家的技能数据
|
||
if(count >0)
|
||
{
|
||
m_skillList.reserve(count);
|
||
|
||
unsigned int nCurrentTime = GetGlobalLogicEngine()->getMiniDateTime(); //当前的时间
|
||
ULONGLONG tick = GetGlobalLogicEngine()->getTickCount(); //获取当前的逻辑的tick
|
||
|
||
SKILLDATA data;
|
||
for(INT_PTR i=0; i <count; i++)
|
||
{
|
||
reader.readBuf(&data,sizeof(ONESKILLDBDATA) );
|
||
data.bEvent =0;
|
||
data.bMjMask =0;
|
||
const SKILLONELEVEL * pLevel = pSkillProvider->GetSkillLevelData(data.nSkillID, data.nLevel);
|
||
const OneSkillData *pConfig = pSkillProvider->GetSkillData(data.nSkillID);
|
||
if(pLevel ==NULL || pConfig ==NULL) continue;
|
||
|
||
if(pLevel)
|
||
{
|
||
data.nCoolDownTime = pLevel->nCooldownTimes; //冷却时间
|
||
}
|
||
else
|
||
{
|
||
continue;
|
||
}
|
||
if(data.nCd > nCurrentTime)
|
||
{
|
||
data.tick = tick + (data.nCd - nCurrentTime) * 1000; //这个是新的冷却时间
|
||
|
||
}
|
||
else
|
||
{
|
||
data.tick =0;
|
||
data.nCd =0;
|
||
|
||
}
|
||
data.nLastDbCd = data.nCd;
|
||
|
||
if(data.nMijiId) //如果镶嵌了秘籍
|
||
{
|
||
bool isInvalid = false;
|
||
if(data.nMijiExpiredTime > GetGlobalLogicEngine()->getMiniDateTime()) //如果秘籍还有效的话
|
||
{
|
||
const CStdItem* pStdItem = itemProvider.GetStdItem(data.nMijiId);
|
||
if(pStdItem )
|
||
{
|
||
isInvalid =true;
|
||
data.bMjMask = (BYTE)pStdItem->m_wSuitID; //这个是真正生效的秘籍的效果
|
||
}
|
||
}
|
||
if(!isInvalid)
|
||
{
|
||
data.nMijiId =0;
|
||
data.nMijiExpiredTime =0; //已经过期了
|
||
}
|
||
}
|
||
|
||
data.bIsPassive = ((pConfig->nSkillType == stPassiveSkill)?1:0);
|
||
data.bPriority = pConfig->bPriority;
|
||
data.nSkillType = pConfig->nSkillType;
|
||
m_skillList.add(data);
|
||
}
|
||
|
||
}
|
||
Inherid::OnDbInitData();
|
||
((CActor*)m_pEntity)->OnFinishOneInitStep(eMSG_USR_LOGIN_DATA_SKILL_SYSTEM); //完成一个步骤
|
||
}
|
||
else if(nCmd ==jxInterSrvComm::DbServerProto::dcLoadSkill && nErrorCode != jxInterSrvComm::DbServerProto::reSucc)
|
||
{
|
||
OutputMsg(rmError,_T("装载玩家[%s]的技能的数据出错,actorid=%d"),((CActor*)m_pEntity)->GetEntityName(),m_pEntity->GetProperty<int>(PROP_ENTITY_ID));
|
||
}
|
||
}
|
||
|
||
|
||
INT_PTR CSkillSubSystem::GetLearnSkillErrorCode(INT_PTR nSkillID, INT_PTR nLevelID, bool bForce)
|
||
{
|
||
if( GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillData(nSkillID) == NULL)
|
||
{
|
||
return tpSkillConfigError;
|
||
}
|
||
SKILLONELEVEL * pLevel = GetLogicServer()->GetDataProvider()->GetSkillProvider()->GetSkillLevelData(nSkillID,nLevelID);
|
||
if(GetSkillLevel(nSkillID) >= nLevelID) return tpSkillTrainHasLearned; //已经学习过这个技能了
|
||
if(pLevel ==NULL) return tpSkillIsUpMostLevel; //已经是最高等级了
|
||
if( m_pEntity->GetHandle().GetType() !=enActor ) return tpNoError; //怪物的话不需要判断条件
|
||
if (bForce) return tpNoError; //强制学习
|
||
INT_PTR nErrorCode = tpNoError;
|
||
DataList<SKILLTRAINSPELLCONDITION> & conditions = pLevel->trainConditions ;
|
||
for(INT_PTR i = 0; i< conditions.count; i++)
|
||
{
|
||
nErrorCode = m_targetCondition.CheckUpGradeContion(m_pEntity,nSkillID,conditions[i],false);
|
||
if(nErrorCode != tpNoError) return nErrorCode;
|
||
}
|
||
return nErrorCode; //没有错误
|
||
}
|
||
|
||
/*计算一个技能的属性
|
||
skill_x_x.txt的配置,如
|
||
results =
|
||
{
|
||
{ resultType = 7, delay = 200, id = 119, value = 0.1, param = 0 },
|
||
{ resultType = 7, delay = 200, id = 120, value = 0.25, param = 0 },
|
||
{ resultType = 7, delay = 200, id = 109, value = 0.03, param = 0 },
|
||
},
|
||
*/
|
||
VOID CSkillSubSystem::CalcOneSkillAttr(INT_PTR nSkillID,INT_PTR nLevel,CAttrCalc &calc)
|
||
{
|
||
CSkillProvider *pProvider = GetLogicServer()->GetDataProvider()->GetSkillProvider();
|
||
if ( !pProvider )
|
||
{
|
||
return;
|
||
}
|
||
const OneSkillData * pData = pProvider->GetSkillData(nSkillID);
|
||
if(pData ==NULL) return;
|
||
|
||
if(pData->nSkillType != stPassiveSkill && pData->bBeedCalPassiveProperty ==false) return;
|
||
|
||
|
||
if(nLevel <=0 )return;
|
||
SKILLONELEVEL * pLevel = pProvider->GetSkillLevelData(nSkillID,nLevel);
|
||
if(pLevel ==NULL) return;
|
||
GAMEATTR attr;
|
||
for(INT_PTR rangeID=0; rangeID < pLevel->pranges.count; rangeID++)
|
||
{
|
||
PSKILLONERANGE pRange = pLevel->pranges[rangeID];
|
||
INT_PTR nResultCount= pRange->skillResults.count;
|
||
for(INT_PTR resultID =0; resultID < nResultCount; resultID ++)
|
||
{
|
||
PSKILLRESULT pResult = &(pRange->skillResults[resultID]);
|
||
if(pResult->nResultType != srSkillResultChangeProperty ) continue;
|
||
attr.type = (BYTE)pResult->nId; //属性的ID
|
||
|
||
//属性计算
|
||
if(pResult->nParam1 == ptValueTypeFloat ) //如果是浮点数的
|
||
{
|
||
attr.value.fValue = (float)pResult->nValue /10000; // 万分之1
|
||
calc << attr;
|
||
}
|
||
else if(pResult->nParam1 == ptValueTypeInt)
|
||
{
|
||
attr.value.nValue = pResult->nValue; //是整数
|
||
calc << attr;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
void CSkillSubSystem::OnForgetPassSkill(const OneSkillData* pSkill, int nSkillLevel)
|
||
{
|
||
if (!m_pEntity) return;
|
||
if (!pSkill)
|
||
{
|
||
return;
|
||
}
|
||
CSkillProvider *pProvider = GetLogicServer()->GetDataProvider()->GetSkillProvider();
|
||
if ( !pProvider )
|
||
{
|
||
return;
|
||
}
|
||
SKILLONELEVEL * pLevel = pProvider->GetSkillLevelData(pSkill->nSkillID, nSkillLevel);
|
||
if (!pLevel)
|
||
{
|
||
return;
|
||
}
|
||
for(INT_PTR rangeID=0; rangeID < pLevel->pranges.count; rangeID++)
|
||
{
|
||
PSKILLONERANGE pRange = pLevel->pranges[rangeID];
|
||
|
||
INT_PTR nResultCount= pRange->skillResults.count;
|
||
for(INT_PTR resultID =0; resultID < nResultCount; resultID ++)
|
||
{
|
||
PSKILLRESULT pResult = &(pRange->skillResults[resultID]);
|
||
if(pResult->nResultType != srSkillResultChangeProperty ) continue;
|
||
if (pResult->nParam1 == ptValueTypeSkillAddBuff)
|
||
{
|
||
if (m_pEntity->GetBuffSystem()->Exists(pResult->nValue))
|
||
{
|
||
m_pEntity->GetBuffSystem()->RemoveById(pResult->nValue,false);
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
VOID CSkillSubSystem::CalcAttributes(CAttrCalc &calc)
|
||
{
|
||
if(m_pEntity ==NULL) return ;
|
||
|
||
size_t count = m_skillList.count();
|
||
if(count <=0) return;
|
||
|
||
for( size_t i=0; i<count; i ++ )
|
||
{
|
||
INT_PTR nSkillID= m_skillList[i].nSkillID;
|
||
INT_PTR nLevel = m_skillList[i].nLevel;
|
||
CalcOneSkillAttr(nSkillID, nLevel, calc); //计算技能再results中配置的属性
|
||
}
|
||
}
|
||
|
||
|
||
bool CSkillSubSystem::CheckGather(CMonster *pTarget, int nPosX, int nPosY, BYTE nDir)
|
||
{
|
||
if (!m_pEntity || m_pEntity->GetType() != enActor || !pTarget || pTarget->GetType() != enGatherMonster)
|
||
return false;
|
||
CActor* pActor = (CActor*)m_pEntity;
|
||
const PMONSTERCONFIG pConfig = GetLogicServer()->GetDataProvider()->GetMonsterConfig().GetMonsterData(pTarget->GetId());
|
||
if ( pConfig && pConfig->nGatherLevel > 0)
|
||
{
|
||
if (!pActor->CheckLevel(pConfig->nGatherLevel,0))
|
||
{
|
||
pActor->SendOldTipmsgFormatWithId(tpLevelNotEnoughGather, ttFlyTip, pConfig->nGatherLevel);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
if( pActor->GetBagSystem().availableMinCount() <= 0 ) //背包满了,不能采集
|
||
{
|
||
((CActor*)m_pEntity)->SendOldTipmsgWithId(tpBagFullCantGather,ttFlyTip);
|
||
return false;
|
||
}
|
||
|
||
int nTargetMonsterType = pTarget->GetMonsterType();
|
||
unsigned int nOnwerActorId = pTarget->GetOwnerActorId() ;
|
||
if(nOnwerActorId) //自己的actorid
|
||
{
|
||
if(nTargetMonsterType == MONSTERCONFIG::mtCollectOnce )
|
||
{
|
||
if(pTarget->InBeAttackActorList(m_pEntity->GetId()))
|
||
{
|
||
((CActor *)m_pEntity)->SendOldTipmsgWithId(tpOnlyCollectOnce, ttFlyTip);
|
||
return false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if( m_pEntity->GetProperty<unsigned int>(PROP_ENTITY_ID) != nOnwerActorId )
|
||
{
|
||
((CActor*)m_pEntity)->SendOldTipmsgWithId(tpGatherNotOwner,ttFlyTip);
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ( nTargetMonsterType != MONSTERCONFIG::mtGirl)
|
||
{
|
||
EntityHandle hd=pTarget->GetVestEntity();
|
||
|
||
if(!hd.IsNull() && GetEntityFromHandle(hd) != NULL && hd != m_pEntity->GetHandle())
|
||
{
|
||
((CActor*)m_pEntity)->SendOldTipmsgWithId(tpGatherNotOwner,ttFlyTip);
|
||
return false;
|
||
}
|
||
if(nTargetMonsterType == MONSTERCONFIG::mtFubenCollect)
|
||
{
|
||
static int nItemId = GetLogicServer()->GetDataProvider()->GetGlobalConfig().nHammerItemId;
|
||
CActor * pActor = (CActor *)m_pEntity;
|
||
if(pActor->GetBagSystem().GetItemCount(nItemId) <= 0)
|
||
{
|
||
pActor->SendOldTipmsgWithId(tpFubenCollectNotItem, ttFlyTip);
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//pTarget->OnAttacked(m_pEntity);
|
||
|
||
//if(pTarget->Getw)
|
||
// 检测公共操作定时器
|
||
if (!m_pEntity->CheckCommonOpTick(((CActor *)m_pEntity)->GetGateNetWorkTickCount()+50, false))
|
||
return false;
|
||
|
||
// 检测采集距离和朝向
|
||
int nSelfX = 0, nSelfY = 0;
|
||
m_pEntity->GetPosition(nSelfX, nSelfY);
|
||
if (abs(nSelfX - nPosX) > 1 || abs(nSelfY - nPosY) > 1)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
m_pEntity->SetTarget(pTarget->GetHandle());
|
||
INT_PTR nNewDir = CEntity::GetDir(nSelfX, nSelfY, nPosX, nPosY);
|
||
m_pEntity->SetDir(nNewDir);
|
||
return true;
|
||
}
|
||
|
||
bool CSkillSubSystem::GathMonsterCallBack(CEntity* pMonster)
|
||
{
|
||
bool boReslut = false;
|
||
if ( !m_pEntity || m_pEntity->GetType() != enActor || !pMonster || pMonster->GetType() != enGatherMonster)
|
||
{
|
||
return boReslut;
|
||
}
|
||
CScriptValueList paramList, retParamList;
|
||
paramList << (CActor*)m_pEntity;
|
||
paramList << (CMonster*)pMonster;
|
||
CNpc * pNpc = GetGlobalLogicEngine()->GetGlobalNpc();
|
||
if (pNpc != NULL)
|
||
{
|
||
if(!pNpc->GetScript().Call("OnGatherMonster", paramList, retParamList))
|
||
{
|
||
const RefString & s = pNpc->GetScript().getLastErrorDesc();
|
||
((CActor*)m_pEntity)->SendTipmsg((LPCSTR)s, ttDialog);
|
||
return boReslut;
|
||
}
|
||
}
|
||
if (retParamList.count() > 0)
|
||
{
|
||
boReslut = (bool)retParamList[retParamList.count() - 1];
|
||
}
|
||
return boReslut;
|
||
}
|
||
|
||
|
||
void CSkillSubSystem::GatherMonster(EntityHandle hTarget, int nPosX, int nPosY, BYTE nDir)
|
||
{
|
||
if (!m_pEntity || m_pEntity->GetType() != enActor)
|
||
return;
|
||
CMonster *pMonster = (CMonster *)GetEntityFromHandle(hTarget);
|
||
|
||
//需要告诉玩家不能采集
|
||
|
||
//检查采集条件
|
||
if (!CheckGather(pMonster, nPosX, nPosY, nDir))
|
||
{
|
||
((CActor*)m_pEntity)->SendOperateResult(false);
|
||
return;
|
||
}
|
||
|
||
//被别人踩死了
|
||
int nMonsterHP = pMonster->GetProperty<int>(PROP_CREATURE_HP);
|
||
if(nMonsterHP <=0)
|
||
{
|
||
((CActor*)m_pEntity)->SendOperateResult(false);
|
||
return;
|
||
}
|
||
int nGatherVal = 1;
|
||
|
||
if(nGatherVal ==0) return ;
|
||
|
||
m_pEntity->SetCommonOpNextTime(m_pEntity->GetProperty<unsigned int>(PROP_CREATURE_ATTACK_SPEED), false, true);
|
||
|
||
m_hSingTarget = pMonster->GetHandle(); //保存这个目标的handle
|
||
m_currentSingSkillID = GATHER_SKILL_ID ; //正在采集
|
||
|
||
int nMaxHp = pMonster->GetProperty<int>(PROP_CREATURE_MAXHP);
|
||
unsigned int nSingTime =1000 * ( nMaxHp/ nGatherVal );
|
||
|
||
m_singTimer.SetNextHitTimeFromNow(nSingTime);
|
||
|
||
CActorPacket pack;
|
||
CDataPacket & data = ((CActor*)m_pEntity)->AllocPacket(pack);
|
||
data << (BYTE) enSkillSystemID << (BYTE) sGatherMonsterProgress;
|
||
data << (BYTE)m_pEntity->GetProperty<unsigned int>(PROP_ENTITY_DIR);
|
||
data << (int) nSingTime;
|
||
m_pEntity->AddState(esStateSing);//开始吟唱
|
||
pack.flush();
|
||
}
|
||
|
||
void CSkillSubSystem::BroadGather()
|
||
{
|
||
char buff[128];
|
||
CDataPacket pack(buff,sizeof(buff));
|
||
|
||
|
||
int nSelfX, nSelfY;
|
||
m_pEntity->GetPosition(nSelfX, nSelfY);
|
||
|
||
pack << (BYTE) enDefaultEntitySystemID ;
|
||
pack << (BYTE) sGather;
|
||
pack << (Uint64) m_pEntity->GetHandle();
|
||
pack << (unsigned short)nSelfX;
|
||
pack << (unsigned short)nSelfY;
|
||
pack << (BYTE)m_pEntity->GetProperty<unsigned int>(PROP_ENTITY_DIR) ;
|
||
|
||
m_pEntity->GetObserverSystem()->BroadCast(pack.getMemoryPtr(), pack.getPosition(), false);
|
||
}
|
||
|
||
void CSkillSubSystem::SetInitiativeAttack(CEntity * myEntity,CEntity * pEntity)
|
||
{
|
||
if(myEntity == NULL || pEntity == NULL) return;
|
||
|
||
if(pEntity->IsDeath()) return;
|
||
|
||
if(myEntity->GetType() == enActor && pEntity->GetType() == enActor)
|
||
{
|
||
INT_PTR nPkMode = ((CActor *)myEntity)->GetProperty<int>(PROP_ACTOR_PK_MOD);
|
||
|
||
if(nPkMode == fpPeaceful) return;
|
||
|
||
if(((CActor *)pEntity)->GetNameColorData() < 2 && ((CActor *)myEntity)->GetNameColorData() != 3)
|
||
{
|
||
if (myEntity != pEntity)
|
||
{
|
||
((CActor *)myEntity)->SetAttackOthersFlag(true);
|
||
((CActor *)myEntity)->GetObserverSystem()->UpdateActorEntityProp();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void CSkillSubSystem::StopGather()
|
||
{
|
||
if (m_pEntity != NULL && m_currentSingSkillID == GATHER_SKILL_ID)
|
||
{
|
||
m_currentSingSkillID = 0;
|
||
m_pEntity->RemoveState(esStateSing);
|
||
}
|
||
}
|
||
|
||
//跨服相关数据
|
||
void CSkillSubSystem::SendMsg2CrossServer(int nType) {
|
||
if(!m_pEntity) return;
|
||
if(m_pEntity->GetType() != enActor)
|
||
{
|
||
OutputMsg(rmError,_T("跨服非玩家技能的数据"));
|
||
return;
|
||
}
|
||
CLocalCrossClient *pCrossClient = GetLogicServer()->GetCrossClient();
|
||
CDataPacket &packet = pCrossClient->allocProtoPacket(jxInterSrvComm::CrossServerProto::cSendCrossData);
|
||
int nServerId = GetLogicServer()->GetCrossServerId();
|
||
unsigned int nActorID = m_pEntity->GetId();
|
||
packet << nServerId << nActorID;
|
||
packet <<(BYTE)nType;
|
||
packet << ((CActor*)m_pEntity)->GetCrossActorId();
|
||
packet << ((CActor*)m_pEntity)->GetAccountID();
|
||
//数据
|
||
OutputMsg(rmTip,_T("[CrossLogin 8] SendMsg2CrossServer type:%d nActorID:%d "),nType,nActorID);
|
||
packet << (int)(m_skillList.count());
|
||
for(int i = 0; i < m_skillList.count(); i++) {
|
||
packet << m_skillList[i];
|
||
}
|
||
pCrossClient->flushProtoPacket(packet);
|
||
}
|
||
|
||
|
||
//跨服初始化
|
||
VOID CSkillSubSystem::OnCrossInitData(std::vector<CSkillSubSystem::SKILLDATA>& skillData)
|
||
{
|
||
if(m_pEntity ==NULL )
|
||
{
|
||
OutputMsg(rmError,_T("装载玩家技能的数据出错,实体指针为MULL"));
|
||
return;
|
||
}
|
||
if(m_pEntity->GetType() != enActor)
|
||
{
|
||
OutputMsg(rmError,_T("装载非玩家技能的数据出错"));
|
||
return;
|
||
}
|
||
//技能的配置的读取器
|
||
CSkillProvider *pSkillProvider = GetLogicServer()->GetDataProvider()->GetSkillProvider(); //技能数据读取器
|
||
CStdItemProvider & itemProvider = GetLogicServer()->GetDataProvider()->GetStdItemProvider(); //物品配置器
|
||
|
||
if(Inherid::HasDbDataInit()) return; //已经装载了这个技能数据
|
||
|
||
int count = skillData.size();
|
||
// reader >> count;
|
||
//如果已经有数据,可能出现了一点问题
|
||
if(m_skillList.count() >0)
|
||
{
|
||
m_skillList.clear();
|
||
}
|
||
|
||
//这里写玩家的技能数据
|
||
if(count >0)
|
||
{
|
||
m_skillList.reserve(count);
|
||
|
||
unsigned int nCurrentTime = GetGlobalLogicEngine()->getMiniDateTime(); //当前的时间
|
||
ULONGLONG tick = GetGlobalLogicEngine()->getTickCount(); //获取当前的逻辑的tick
|
||
|
||
SKILLDATA data;
|
||
for(INT_PTR i=0; i <count; i++)
|
||
{
|
||
// reader.readBuf(&data,sizeof(ONESKILLDBDATA) );
|
||
data = skillData[i];
|
||
data.bEvent =0;
|
||
data.bMjMask =0;
|
||
const SKILLONELEVEL * pLevel = pSkillProvider->GetSkillLevelData(data.nSkillID, data.nLevel);
|
||
const OneSkillData *pConfig = pSkillProvider->GetSkillData(data.nSkillID);
|
||
if(pLevel ==NULL || pConfig ==NULL) continue;
|
||
|
||
if(pLevel)
|
||
{
|
||
data.nCoolDownTime = pLevel->nCooldownTimes; //冷却时间
|
||
}
|
||
else
|
||
{
|
||
continue;
|
||
}
|
||
if(data.nCd > nCurrentTime)
|
||
{
|
||
data.tick = tick + (data.nCd - nCurrentTime) * 1000; //这个是新的冷却时间
|
||
|
||
}
|
||
else
|
||
{
|
||
data.tick =0;
|
||
data.nCd =0;
|
||
|
||
}
|
||
data.nLastDbCd = data.nCd;
|
||
|
||
if(data.nMijiId) //如果镶嵌了秘籍
|
||
{
|
||
bool isInvalid = false;
|
||
if(data.nMijiExpiredTime > GetGlobalLogicEngine()->getMiniDateTime()) //如果秘籍还有效的话
|
||
{
|
||
const CStdItem* pStdItem = itemProvider.GetStdItem(data.nMijiId);
|
||
if(pStdItem )
|
||
{
|
||
isInvalid =true;
|
||
data.bMjMask = (BYTE)pStdItem->m_wSuitID; //这个是真正生效的秘籍的效果
|
||
}
|
||
}
|
||
if(!isInvalid)
|
||
{
|
||
data.nMijiId =0;
|
||
data.nMijiExpiredTime =0; //已经过期了
|
||
}
|
||
}
|
||
|
||
data.bIsPassive = ((pConfig->nSkillType == stPassiveSkill)?1:0);
|
||
data.bPriority = pConfig->bPriority;
|
||
data.nSkillType = pConfig->nSkillType;
|
||
OutputMsg(rmTip,_T("OnCrossInitData CSkillSubSystem nActorID:%d nSkillID:%d,nLevel:%d"),
|
||
m_pEntity->GetId(),data.nSkillID, data.nLevel);
|
||
m_skillList.add(data);
|
||
}
|
||
|
||
}
|
||
Inherid::OnDbInitData();
|
||
//存储记录并发提示
|
||
SetDataModifyFlag(true);
|
||
((CActor*)m_pEntity)->OnCrossFinishOneInitStep(MSG_CSKILL); //完成一个步骤
|
||
} |