📄 ainpc.cpp
字号:
// AINpc.cpp: implementation of the CMonster class.
//
//////////////////////////////////////////////////////////////////////
#include "AllMsg.h"
#include "GameMap.h"
#include "AINpc.h"
#include "MapGroup.h"
#include "MapItem.h"
#include "basefunc.h"
#include "ActionDefine.h"
#include "MapTrap.h"
#include "UserTable.h"
#include "Item.h"
#include "DeadLoop.h"
#include "DropRuleMap.h" //add by zlong 2003-11-15
//////////////////////////////////////////////////////////////////////
const int RECRUITMAGIC_SECS = 10; // 每10秒使用一次加血魔法
const int DEFAULT_MONSTER_MAGIC_LEVEL = 0;
const int UNIDENT_PERCENT = 20; // 掉普通物品时,未鉴定的比率
const int AUTO_INC_LIFE_SECS = 10; // 每10秒自动增长生命
const int AUTO_INC_LIFE_PERCENT = 10; // 每次增长最大生命的一半
const int SORB_REFLECT_SECS = 6; // 吸收反射状态每隔6秒作用一次
//////////////////////////////////////////////////////////////////////
//---jinggy---begin
#define EXPLODEMONEY_RATE 4 //暴钱几率
#define EXPLODEMONEY_DOUBLE 15 //暴钱时的倍数
//---jinggy---end
//////////////////////////////////////////////////////////////////////
MYHEAP_IMPLEMENTATION(CMonster,s_heap)
char szPetTable[] = _TBL_PET;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMonster::CMonster()
{
SetObjType(OBJ_MONSTER);
m_pType = NULL;
m_idNpc = ID_NONE;
m_pBattleSystem = NULL;
m_pData = NULL;
m_tFootPrint = 0;
m_posFootPrint.x = 0;
m_posFootPrint.y = 0;
m_link.Init(this);
m_pMagicType = NULL;
m_pMagic = NULL;
m_pEudemonItem = NULL;
// memset(&m_AddInfo, 0, sizeof(m_AddInfo));
m_nPotential = DEFAULT_EUDEMON_POTENTIAL;
m_dwMaskData = 0;
m_bDecRole = false;
m_nKillNum = 0;
m_nKillNum4Potential = 0;
m_nKillNum4RelationShip = 0;
m_nAtkMode = EATK_MODE_NONE; // 默认攻击类型为无
}
//////////////////////////////////////////////////////////////////////
CMonster::~CMonster()
{
if(m_pData)
{
if(IsSynPet())
MapManager()->RecyclePetID(GetID());
else if(IsCallPet())
MapManager()->RecycleCallPetID(GetID());
if(m_pData->GetInt(PETDATA_LIFE) > 0) // flag to die
SaveInfo();
else
m_pData->DeleteRecord();
m_pData->Release();
}
if(m_idNpc != ID_NONE)
{
LeaveMapGroup();
m_idNpc = ID_NONE;
}
if (m_pBattleSystem)
{
delete m_pBattleSystem;
m_pBattleSystem = NULL;
}
if (m_pMagic)
m_pMagic->ReleaseByOwner();
SAFE_RELEASE (m_setStatus);
}
//////////////////////////////////////////////////////////////////////
bool CMonster::Create(PROCESS_ID idProcess, IRecordset* pRes)
{
m_idProcess = idProcess;
ASSERT(!m_pData);
m_pData = CPetData::CreateNew();
CHECKF(m_pData);
IF_NOT(m_pData->Create(pRes))
return false;
OBJID idType = m_pData->GetInt(PETDATA_TYPE);
m_pType = MonsterType()->GetObj(idType);
CHECKF(m_pType);
m_nDir = ::RandGet(8);
m_pMap = MapManager()->GetGameMap(m_pData->GetInt(PETDATA_MAPID), false); // false: not load dynamic map
if(!m_pMap)
{
m_pData->Release();
m_pData = NULL;
return false; // not this map group, or in dynamic map
}
m_idNpc = MapManager()->SpawnNewPetID(); //? mast follow m_pMap
m_nPosX = m_pData->GetInt(PETDATA_RECORD_X);
m_nPosY = m_pData->GetInt(PETDATA_RECORD_Y);
// m_dwStatus = STATUS_NORMAL;
m_i64Effect = KEEPEFFECT_NORMAL;
// if((m_pType->GetInt(NPCTYPEDATA_ATKUSER) & ATKUSER_WING))
// m_i64Effect = KEEPEFFECT_WING;
m_nPose = POSE_STAND;
m_idGen = m_pData->GetInt(PETDATA_GENID);
m_nCurrLife = m_pData->GetInt(PETDATA_LIFE);
m_nCurrMana = m_pData->GetInt(PETDATA_MANA);
m_tFight.SetInterval(m_pType->GetInt(NPCTYPEDATA_ATKSPEED));
m_tFight.Update();
m_tSorbReflect.Clear();
m_nTotalDamage = 0;
m_pBattleSystem = new CBattleSystem(this->m_idProcess, this);
CHECKF(m_pBattleSystem);
m_setStatus = CStatusSet::CreateNew(true);
CHECKF(m_setStatus);
// synchro
ST_CREATENEWNPC info;
memset(&info, 0, sizeof(ST_CREATENEWNPC));
info.id = GetID();
info.usAction = MSGAINPCINFO_CREATENEW;
info.usType = GetType();
info.ucOwnerType = m_pData->GetInt(PETDATA_OWNERTYPE);
info.idOwner = m_pData->GetInt(PETDATA_OWNERID);
info.idMap = GetMap()->GetID();
info.usPosX = GetPosX();
info.usPosY = GetPosY();
info.idData = m_pData->GetInt(PETDATA_GENID);
info.nData = GetData();
CMsgMonsterInfo msg;
IF_OK(msg.Create(&info))
this->SendMsg(&msg);
return true;
}
//////////////////////////////////////////////////////////////////////
bool CMonster::Create(PROCESS_ID idProcess, CNpcType* pType, const ST_CREATENEWNPC* pInfo, CUser* pUser, OBJID idItem)
{
CHECKF(pType && pInfo && pUser);
IF_OK(Create(idProcess, pType, pInfo, pUser->GetName()))
{
CHECKF(IsCallPet() || IsEudemon());
if(IsMagicAtk())
{
m_pMagicType = CMagic::FindMagicType(GetMagicType(), DEFAULT_MONSTER_MAGIC_LEVEL);
IF_NOT(m_pMagicType)
{
LOGERROR("Can't find magic type [%d] in monster type [%d]", GetMagicType(), pType->GetID());
return false;
}
}
m_pMagic = CMagic::CreateNew(idProcess, this->QueryRole());
if (!m_pMagic || !m_pMagic->CreateAll())
return false;
// synchro
CMsgCallPetInfo msg;
IF_OK(msg.Create(GetID(), GetLookFace(), pType->GetInt(NPCTYPEDATA_AITYPE), GetPosX(), GetPosY(), idItem))
pUser->SendMsg(&msg);
m_pOwner = pUser->QueryLink();
if (IsEudemon())
{
CMsgUserAttrib msg;
if (msg.Create(this->GetID(), _USERATTRIB_POTENTIAL, this->GetPotential()))
this->SendMsg(&msg);
}
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////
bool CMonster::Create(PROCESS_ID idProcess, CNpcType* pType, const ST_CREATENEWNPC* pInfo, LPCTSTR pszName/*=NULL*/)
{
m_idProcess = idProcess;
CHECKF(pType);
m_idNpc = pInfo->id;
m_nDir = ::RandGet(8);
m_pMap = MapManager()->GetGameMap(pInfo->idMap);
m_nPosX = pInfo->usPosX;
m_nPosY = pInfo->usPosY;
// m_dwStatus = STATUS_NORMAL;
m_i64Effect = KEEPEFFECT_NORMAL;
m_nPose = POSE_STAND;
m_idGen = pInfo->idData;
m_pType = pType;
m_nCurrLife = m_pType->GetInt(NPCTYPEDATA_LIFE);
m_nCurrMana = m_pType->GetInt(NPCTYPEDATA_MANA);
m_tFight.SetInterval(m_pType->GetInt(NPCTYPEDATA_ATKSPEED));
m_tFight.Update();
if(!m_pMap)
return false;
m_pBattleSystem = new CBattleSystem(this->m_idProcess, this);
CHECKF(m_pBattleSystem);
m_setStatus = CStatusSet::CreateNew(true);
CHECKF(m_setStatus);
if(!IsCallPet() && !IsEudemon()) // synchro outside
{
CMsgMonsterInfo msg;
IF_OK(msg.Create(pInfo))
this->SendMsg(&msg);
}
if(!IsSynPet() || pInfo->idOwner == ID_NONE) // need not save to database
return true;
/////////////////////////////////////////////////////////////////////////
// create record
m_pData = CPetData::CreateNew();
IF_OK(m_pData)
{
IF_OK(m_pData->Create(GameDataDefault()->GetPetData(), ID_NONE))
{
m_pData->SetInt(PETDATA_OWNERID, pInfo->idOwner);
m_pData->SetInt(PETDATA_OWNERTYPE, pInfo->ucOwnerType);
m_pData->SetInt(PETDATA_GENID, pInfo->idData);
m_pData->SetInt(PETDATA_TYPE, pInfo->usType);
if(pszName)
m_pData->SetStr(PETDATA_NAME, pszName, _MAX_NAMESIZE);
else
m_pData->SetStr(PETDATA_NAME, pType->GetStr(NPCTYPEDATA_NAME), _MAX_NAMESIZE);
m_pData->SetInt(PETDATA_LIFE, m_nCurrLife);
m_pData->SetInt(PETDATA_MANA, m_nCurrMana);
m_pData->SetInt(PETDATA_MAPID, pInfo->idMap);
m_pData->SetInt(PETDATA_RECORD_X, pInfo->usPosX);
m_pData->SetInt(PETDATA_RECORD_Y, pInfo->usPosY);
m_pData->SetInt(PETDATA_DATA, pInfo->nData);
OBJID idPet = m_pData->InsertRecord();
return idPet != ID_NONE;
}
else
{
SAFE_RELEASE(m_pData);
}
}
return false;
}
//////////////////////////////////////////////////////////////////////
void CMonster::OnTimer(time_t tCurr)
{
if(!this->IsAlive() && !m_bLeaveMap)
{
if ((m_tDie.IsActive() && m_tDie.GetRemain() < NPCDIEDELAY_SECS/2) //
&& !(m_i64Effect & KEEPEFFECT_DISAPPEARING) // 已经设置了尸体消失状态,避免重复设置
&& !this->QueryStatus(STATUS_LOCK)) // 如果处于锁定状态则不消失
{
this->SetStatus(STATUS_DISAPPEARING);
}
}
if(IsDeleted())
return ; // no timer
// add life ------------------------------------------------------
DEBUG_TRY
if (IsAlive() && m_pType->GetInt(NPCTYPEDATA_MAGIC_TYPE) == SIMPLEMAGIC_RECRUIT && m_tAddLife.IsActive() && m_tAddLife.ToNextTime(RECRUITMAGIC_SECS))
{
if(GetLife() < GetMaxLife())
{
int nAddLife = GetMaxLife() * GetRecruitMagicPercent() / 100;
int nLoseLife = ::CutRange((int)GetMaxLife() - (int)GetLife(), (int)0, (int)GetMaxLife());
nAddLife = ::CutOverflow(nAddLife, nLoseLife);
AddAttrib(_USERATTRIB_LIFE, nAddLife, SYNCHRO_TRUE);
// synchro
CMsgMagicEffect msg;
IF_OK(msg.Create(GetID(), SIMPLEMAGIC_RECRUIT, 0, GetID(), nAddLife, GetDir()))
BroadcastRoomMsg(&msg, EXCLUDE_SELF);
m_nFightPause += 1000; // delay
}
else
{
m_tAddLife.Clear();
}
}
DEBUG_CATCH("CMonster add life");
// 幻兽生命自动回复 -----------------------------------------------
DEBUG_TRY
if (IsAlive() && IsEudemon() && m_pEudemonItem)
{
if (!m_tIncLife.IsActive())
m_tIncLife.Startup(AUTO_INC_LIFE_SECS);
else
{
if (m_tIncLife.ToNextTime() && GetLife() < GetMaxLife())
{
int nAddLife = GetMaxLife()*AUTO_INC_LIFE_PERCENT/100;
AddAttrib(_USERATTRIB_LIFE, nAddLife, SYNCHRO_TRUE);
}
}
}
DEBUG_CATCH("CMonster increase life");
// 吸收伤害反射 -------------------------------------------------
DEBUG_TRY
if (m_tSorbReflect.IsActive() && m_tSorbReflect.ToNextTime())
{
if (m_pBattleSystem && m_pBattleSystem->IsActived() && m_nTotalDamage>0)
{
IRole* pTarget = this->FindAroundRole(m_pBattleSystem->GetTargetID());
if (pTarget)
{
int nLifeLost = __min(m_nTotalDamage, pTarget->GetLife());
pTarget->AddAttrib(_USERATTRIB_LIFE, -1*nLifeLost, SYNCHRO_TRUE);
pTarget->BeAttack(BY_WEAPON, this, nLifeLost);
if (!pTarget->IsAlive())
this->Kill(pTarget, DIE_NORMAL);
}
}
m_nTotalDamage = 0; // 无论成功与否,一定要记得清0
}
DEBUG_CATCH("CMonster sorb reflect timer crash.")
// 自动攻击 ------------------------------------------------------
DEBUG_TRY
if (m_pBattleSystem && m_pBattleSystem->IsActived()
&& m_tFight.ToNextTick(GetInterAtkRate() + m_nFightPause)
&& (!QueryMagic() || !QueryMagic()->IsActive()))
{
m_pBattleSystem->ProcAttack_Hand2Hand();
m_nFightPause = 0;
}
DEBUG_CATCH("CMonster ProcAttack_Hand2Hand");
if (m_pMagic)
{
DEBUG_TRY
DEADLOOP_CHECK(PID, "QueryMagic()->OnTimer")
m_pMagic->OnTimer(tCurr);
DEBUG_CATCH("CMonster magic timer crash.")
}
// status --------------------------------------------------------
DEBUG_TRY
// 以下增加部分代码用于判断是否解除结界系统状态
// bDetachTeamStatus = true 表示需要解除所有与结界相关的状态
bool bDetachTeamStatus = true;
bool bDetachAddExpStatus = true; // 是否解除STATUS_ADD_EXP
if (IsAlive())
{
if (m_pOwner)
{
CTeam* pTeam = m_pOwner->GetTeam();
if (pTeam)
{
CUser* pLeader = UserManager()->GetUser(pTeam->GetLeader());
if (pLeader && pLeader->IsAlive()
&& this->GetMap()->GetID() == pLeader->GetMap()->GetID()
&& this->GetDistance(pLeader->QueryMapThing()) <= _RANGE_TEAM_STATUS)
{
bDetachTeamStatus = false;
}
if (pLeader && pLeader->QueryStatus(STATUS_ADD_EXP))
bDetachAddExpStatus = false;
}
}
}
for(int i = QueryStatusSet()->GetAmount()-1; i >= 0; i--)
{
IStatus* pStatus = QueryStatusSet()->GetObjByIndex(i);
if(pStatus)
{
pStatus->OnTimer(tCurr);
if(!pStatus->IsValid()
|| (bDetachTeamStatus && pStatus->GetID() >= STATUS_TEAM_BEGIN && pStatus->GetID() <= STATUS_TEAM_END)
|| (bDetachAddExpStatus && pStatus->GetID() == STATUS_ADD_EXP))
{
QueryStatusSet()->DelObj(pStatus->GetID());
}
}
}
DEBUG_CATCH("monster magic poison")
// 死亡 -----------------------------------------------------
DEBUG_TRY
if((IsCallPet() || IsEudemon()) && m_pOwner == NULL)
{
if(!IsDeleted())
{
LOGERROR("Call pet don't find owner! del self.");
DelMonster(DEL_NOW);
}
}
DEBUG_CATCH("RoleManager()->QuerySet()->DelObj")
}
//////////////////////////////////////////////////////////////////////
void CMonster::ClearAllStatus()
{
for(int i = QueryStatusSet()->GetAmount() - 1; i >= 0; i--)
{
IStatus* pStatus = QueryStatusSet()->GetObjByIndex(i);
if(pStatus)
QueryStatusSet()->DelObj(pStatus->GetID());
}
}
//////////////////////////////////////////////////////////////////////
/*
int CMonster::AdjustData(int nData, int nAdjust, int nMaxData/ *=0* /)
{
if(nAdjust>=ADJUST_PERCENT)
return MulDiv(nData, nAdjust-ADJUST_PERCENT, 100);
if(nAdjust<=ADJUST_SET)
return -1*nAdjust + ADJUST_SET;
if(nAdjust==ADJUST_FULL)
{
ASSERT(nMaxData != 0);
return nMaxData;
}
return nData + nAdjust;
}
*/
//////////////////////////////////////////////////////////////////////
bool CMonster::SendMsg(CNetMsg* pMsg)
{
if ((this->IsEudemon() || this->IsCallPet()) && m_pOwner)
return m_pOwner->SendMsg(pMsg);
else
return MapGroup(PID)->QueryIntraMsg()->SendNpcMsg(m_idNpc, pMsg);
}
//////////////////////////////////////////////////////////////////////
void CMonster::BroadcastRoomMsg(CNetMsg* pMsg, bool bSendSelf /*= false*/)
{
CRole::BroadcastRoomMsg(pMsg, bSendSelf);
}
//////////////////////////////////////////////////////////////////////
void CMonster::BroadcastRoomMsg(LPCTSTR szMsg, bool bSendSelf /*= false*/)
{
CMsgTalk msg;
if(msg.Create(GetName(), ALLUSERS_NAME, szMsg, NULL, 0xff0000, _TXTATR_SYSTEM))
this->BroadcastRoomMsg(&msg, bSendSelf);
}
//////////////////////////////////////////////////////////////////////
void CMonster::BroadcastMapMsg(CNetMsg* pMsg, bool bSendSelf /*= false*/)
{
CMapPtr pMap = this->GetMap();
if(pMap)
UserManager()->BroadcastMapMsg(pMap->GetID(), pMsg);
if(bSendSelf)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -