📄 ainpc.cpp
字号:
CGameMap* pMap = this->GetMap();
if (pMap && m_pOwner)
{
// crime
if (!pTarget->IsEvil() // 只有pk白名才闪蓝
&& !pMap->IsDeadIsland()) // 死亡岛杀人不闪蓝
{
if (!m_pOwner->QueryStatus(STATUS_CRIME))
m_pOwner->SetCrimeStatus();
}
}
IStatus* pStatus = QueryStatus(STATUS_DMG2LIFE);
if (pStatus)
{
int nLifeGot = ::CutTrail(0, MulDiv(nDamage, pStatus->GetPower(), 100));
if (nLifeGot > 0)
this->AddAttrib(_USERATTRIB_LIFE, nLifeGot, SYNCHRO_TRUE);
}
return nDamage;
}
//////////////////////////////////////////////////////////////////////
bool CMonster::BeAttack(bool bMagic, IRole* pTarget, int nPower, bool bReflectEnable/*=true*/)
{
if (m_pType->GetInt(NPCTYPEDATA_MAGIC_TYPE) == SIMPLEMAGIC_RECRUIT && !m_tAddLife.IsActive())
m_tAddLife.Startup(RECRUITMAGIC_SECS);
CRole::DetachStatus(this->QueryRole(), STATUS_FREEZE);
if (QueryStatus(STATUS_SORB_REFLECT))
m_nTotalDamage += nPower;
return true;
}
//////////////////////////////////////////////////////////////////////
void CMonster::Kill(IRole* pTarget, DWORD dwDieWay)
{
CHECK(pTarget);
CMsgInteract msg;
if(msg.Create(INTERACT_KILL, this->GetID(), pTarget->GetID(), pTarget->GetPosX(), pTarget->GetPosY(), dwDieWay))
pTarget->BroadcastRoomMsg(&msg, true);
#ifdef LOCAL_DEBUG
CMonster* pMonster;
if(pTarget->QueryObj(OBJ_NPC, IPP_OF(pMonster)))
LOGERROR("怪物[%s][%d]在[%d,%d]杀死了[%s][%d]", GetName(), GetType(),
GetPosX(), GetPosY(), pMonster->GetName(), pMonster->GetType());
#endif
if(m_pOwner)
{
CUser* pTargetUser=NULL;
if(pTarget->QueryObj(OBJ_USER, IPP_OF(pTargetUser)))
m_pOwner->ProcessPk(pTargetUser);
}
if (QueryStatus(STATUS_FRENZY2))
++m_nKillNum;
if (this->IsEudemon())
{
++m_nKillNum4Potential;
if (m_nKillNum4Potential >= ADD_POTENTIAL_KILLNUM)
{
m_nKillNum4Potential = 0;
AddAttrib(_USERATTRIB_POTENTIAL, ADD_POTENTIAL_PER_KILLNUM, SYNCHRO_TRUE);
}
++m_nKillNum4RelationShip;
if (m_nKillNum4RelationShip >= ADD_RELATIONSHIP_KILLNUM)
{
// TODO: 增加/减少关系值
if (QueryOwnerUser())
{
UCHAR setDivine[10];
memset(setDivine, 0, sizeof(setDivine));
for (int i=0; i<m_pOwner->GetEudemonAmount(); i++)
{
CMonster* pEudemon = m_pOwner->QueryEudemonByIndex(i);
if (pEudemon && pEudemon->GetID() != this->GetID())
{
OBJID idDivine = pEudemon->GetDivineID();
++setDivine[idDivine];
}
}
for (i=1; i<=8; i++)
{
if (setDivine[i] > 0)
{
if (::RandGet(1000) < 10)
this->AddRelationShip(i, ADD_RELATIONSHIP_PER_TIME);
}
else
{
if (::RandGet(1000) < 5)
this->AddRelationShip(i, -1*ADD_RELATIONSHIP_PER_TIME);
}
}
}
}
}
pTarget->BeKill((IRole*)this);
}
//////////////////////////////////////////////////////////////////////
void CMonster::BeKill(IRole* pRole /*= NULL*/)
{
if(IsDeleted())
return ;
// pet
if(m_pData)
{
m_pData->SetInt(PETDATA_LIFE, 0); // set flag to die
}
// 幻兽死亡扣亲密度,并且加仇人
if (this->IsEudemon() && m_pEudemonItem && m_pOwner)
{
int nFidelity = __max(0, m_pEudemonItem->GetInt(ITEMDATA_FIDELITY) - EUDEMON_DEC_FIDELITY_WHEN_DIE);
m_pEudemonItem->SetInt(ITEMDATA_FIDELITY, nFidelity, true);
CMsgItemAttrib msg;
if (msg.Create(m_pEudemonItem->GetID(), _ITEMATTRIB_FIDELITY, m_pEudemonItem->GetInt(ITEMDATA_FIDELITY)))
m_pOwner->SendMsg(&msg);
// 被别人或者别人的幻兽杀死,加入主人的仇人名单
CUser* pAtkUser = NULL;
CMonster* pMonster = NULL;
if (pRole->QueryObj(OBJ_MONSTER, IPP_OF(pMonster)) && pMonster->IsEudemon())
pAtkUser = pMonster->QueryOwnerUser();
else
pRole->QueryObj(OBJ_USER, IPP_OF(pAtkUser));
if (pAtkUser && pAtkUser->GetID() != m_pOwner->GetID())
{
m_pOwner->QueryEnemy()->Add(pAtkUser->GetID(), pAtkUser->GetName(), SYNCHRO_TRUE, UPDATE_TRUE);
}
}
CUser* pActionUser = NULL;
if(pRole)
pActionUser = pRole->QueryOwnerUser(); // pActionUser for call action
OBJID idMapItemOwner = NULL; // idMapItemOwner for map item owner
if(pActionUser)
idMapItemOwner = pActionUser->GetID();
// bomb
if((IsCallPet()/* || IsEudemon()*/) && IsMagicAtk() && m_pMagicType && m_pMagicType->GetInt(MAGICTYPEDATA_SORT) == MAGICSORT_BOMB)
{
DEBUG_TRY
ProcessBomb();
DEBUG_CATCH("CMonster::ProcessBomb()")
}
////////////////////////////////////////////////////////////////////
// 怪物死亡后掉宝规则修改:
// 取消原来的掉钱或者掉药品代码,改用新的掉物品规则
// 若Action不存在,则根据cq_dropitemrule表中相应的规则掉宝
//
// 冷紫龙 2003-11-13
////////////////////////////////////////////////////////////////////
IStatus * pStatus = pRole->QueryStatus(STATUS_ADJUST_DROPMONEY);
//drop money
int nChanceAdjust = 100;
CUser* pUser = NULL;
// 玩家攻击绿名则掉钱/爆钱率调整为原来的20%
if (pRole->QueryObj(OBJ_USER, IPP_OF(pUser)) && (NAME_GREEN == CMonster::GetNameType(pRole->GetLev(), this->GetLev())))
nChanceAdjust = 20;
if (::RandGet(100) < (m_pType->GetInt(NPCTYPEDATA_DROP_MONEY_CHANCE)*nChanceAdjust/100))
{
DWORD dwMoneyMin = m_pType->GetInt(NPCTYPEDATA_DROPMONEY_MIN);
DWORD dwMoneyMax = m_pType->GetInt(NPCTYPEDATA_DROPMONEY_MAX);
DWORD dwMoney = dwMoneyMin + ::RandGet(dwMoneyMax - dwMoneyMin + 1);
//---jinggy---begin
//玩家特殊状态调节掉钱数量
if (pStatus)
dwMoney = ::CutTrail(0, AdjustData(dwMoney, pStatus->GetPower()));
//---jinggy---end
this->DropMoney(dwMoney, idMapItemOwner);
}
//---jinggy---暴钱---begin
if (::RandGet(100) < (EXPLODEMONEY_RATE*nChanceAdjust/100))
{
DWORD dwMoneyMin = m_pType->GetInt(NPCTYPEDATA_DROPMONEY_MIN);
DWORD dwMoneyMax = m_pType->GetInt(NPCTYPEDATA_DROPMONEY_MAX);
DWORD dwMoney = (dwMoneyMin + ::RandGet(dwMoneyMax - dwMoneyMin + 1)) * EXPLODEMONEY_DOUBLE;
//玩家特殊状态调节掉钱数量
if (pStatus)
dwMoney = ::CutTrail(0, AdjustData(dwMoney, pStatus->GetPower()));
int nHeapNum = 5 + ::RandGet(4); //堆数
DWORD dwMoneyAve = dwMoney / nHeapNum;
for(int i=0; i<nHeapNum; i++)
{
DWORD dwMoneyTmp = MulDiv(dwMoneyAve, 90 + RandGet(21), 100);
this->DropMoney(dwMoneyTmp, idMapItemOwner);
}
}
//---jinggy---暴钱---end
// do action...
if (m_pType->GetInt(NPCTYPEDATA_ACTION))
{
GameAction()->ProcessAction(m_pType->GetInt(NPCTYPEDATA_ACTION), pActionUser, this);
}
// else
{
// TODO: 增加采用新规则计算掉物品金钱代码
/////////// 如果Action不存在,则采用新规则计算掉物品、金钱 <- Action用于其他用途,因此Action与掉物品并行执行
// 冷紫龙 2003-11-13
OBJID idRuleGroup = m_pType->GetInt(NPCTYPEDATA_DROP_ITEM_RULE);
CDropRuleGroup* pDropRuleGroup = NULL;
if ((ID_NONE != idRuleGroup) && (pDropRuleGroup = DropRuleMap()->GetObjByIndex(idRuleGroup)))
{
int nDropNum = 0;
int nAtkLev = this->GetLev();
if(pRole)
nAtkLev = pRole->GetLev();
int nRate = ::RandGet(10000);
//需要根据等级调整实际的掉宝几率
int nChance = CBattleSystem::AdjustDrop(m_pType->GetInt(NPCTYPEDATA_EXPLODE_ITEM_CHANCE3), nAtkLev, this->GetLev());
if (nRate < __min(10000, nChance))
{
nDropNum = 10 + ::RandGet(6); //大爆drop 10 ~ 15 item
} else {
nChance += CBattleSystem::AdjustDrop(m_pType->GetInt(NPCTYPEDATA_EXPLODE_ITEM_CHANCE2), nAtkLev, this->GetLev());
if (nRate < __min(10000, nChance))
{
nDropNum = 6 + ::RandGet(4); //中爆drop 6 ~ 9 item
} else {
nChance += CBattleSystem::AdjustDrop(m_pType->GetInt(NPCTYPEDATA_EXPLODE_ITEM_CHANCE1), nAtkLev, this->GetLev());
if (nRate < __min(10000, nChance))
{
nDropNum = 2 + ::RandGet(4); //小爆drop 2 ~ 5 item
} else {
nChance += CBattleSystem::AdjustDrop(m_pType->GetInt(NPCTYPEDATA_DROP_ITEM_CHANCE), nAtkLev, this->GetLev());
if (nRate < __min(10000, nChance))
nDropNum = 1; //普通drop 1 item
}
}
}
//??如果掉物品规则不是百分百掉,则实际掉的物品数有可能少于nDropNum
for (int i=0; i<nDropNum; i++)
{
OBJID idItemType = pDropRuleGroup->GetDropItem();
if (idItemType != ID_NONE)
{
int nAddLuck = 0;
int nAddAtk = 0;
/*
if (CItem::IsEquipment(idItemType) && !CItem::IsMount(idItemType) && !CItem::IsSprite(idItemType))
{
//仅对除了座骑、精灵以外的其他装备加成
int nRate = ::RandGet(1000);
if (nRate < 1) // 0.10% chance +3 luck
nAddLuck = 3;
else if (nRate < 5+1) // 0.50% chance +2 luck
nAddLuck = 2;
else if (nRate < 25+5+1) // 2.50% chance +1 luck
nAddLuck = 1;
if (::RandGet(1000) < 25) // 2.50% chance + atk/def
{
CItemTypeData* pType = ItemType()->QueryItemType(idItemType);
if(!pType)
{
LOGWARNING("怪物掉物品错误:错误的item_type[%u]!", idItemType);
break;
}
int nLev = pType->GetInt(ITEMTYPEDATA_LEVEL);
nAddAtk = __min(99, nLev*10) - (int)sqrt(::RandGet(__min(9801, nLev*nLev*100)));
ASSERT(nAddAtk > 0 && nAddAtk < 100);
}
}
*/
int nUserLuck = 0;
if(pRole)
nUserLuck = pRole->GetLuck();
if (!this->DropItem(idItemType, idMapItemOwner, nAddLuck, nAddAtk, nUserLuck,true))
break;
}
}
}
}
this->SetStatus(STATUS_DIE);
if (this->IsEudemon() && m_pEudemonItem)
m_pOwner->CallBackEudemon(m_pEudemonItem->GetID(), false);
else
DelMonster();
DEBUG_TRY
if(IsInsteadMagic() && m_pOwner)
{
m_pOwner->BeKill(); // BeKill(pRole)
}
DEBUG_CATCH("instead kill!")
}
//////////////////////////////////////////////////////////////////////
void CMonster::DelMonster(bool bNow/*=false*/) // call this mast !IsDeleted()
{
CHECK(!IsDeleted());
// 必须设置为NULL,否则如果是角色离线,将导致后面的取属性异常
if (m_pEudemonItem)
m_pEudemonItem = NULL;
// 因为打开了WITH_BLOCK开关,为了在死亡后尸体允许穿透,需要减地图上的角色数
//if (GetMap() && !this->IsAlive())
if (!m_bDecRole)
{
m_bDecRole = true;
GetMap()->DecRole(this->GetPosX(), this->GetPosY());
}
// pet
if(m_pData)
{
m_pData->SetInt(PETDATA_LIFE, 0); // set flag to die
}
// synchro npc server to del npc object
if(bNow)
{
m_tDie.Startup(0);
SendLeaveFromBlock();
ClrBroadcastSet();
}
else
// die status
m_tDie.Startup(NPCDIEDELAY_SECS);
}
//////////////////////////////////////////////////////////////////////
void CMonster::SendDamageMsg(OBJID idTarget, int nDamage)
{
if(IsSimpleMagicAtk())
{
CMsgMagicEffect msg;
IF_OK(msg.Create(GetID(), m_pType->GetInt(NPCTYPEDATA_MAGIC_TYPE), 0, idTarget, nDamage, GetDir()))
BroadcastRoomMsg(&msg, INCLUDE_SELF);
}
else if(IsBowman())
{
CMsgInteract msg;
IF_OK(msg.Create(INTERACT_SHOOT, GetID(), idTarget, GetPosX(), GetPosY(), nDamage))
BroadcastRoomMsg(&msg, INCLUDE_SELF);
}
else
{
CMsgInteract msg;
IF_OK(msg.Create(INTERACT_ATTACK, GetID(), idTarget, GetPosX(), GetPosY(), nDamage))
BroadcastRoomMsg(&msg, INCLUDE_SELF);
}
}
////////////////////////////////////////////////////////////////////////////////////
DWORD CMonster::GetDropMoneyAvg()
{
DWORD dwMoneyMin = m_pType->GetInt(NPCTYPEDATA_DROPMONEY_MIN);
DWORD dwMoneyMax = m_pType->GetInt(NPCTYPEDATA_DROPMONEY_MAX);
return (dwMoneyMin+dwMoneyMax)/2;
}
////////////////////////////////////////////////////////////////////////////////////
// drop
////////////////////////////////////////////////////////////////////////////////////
bool CMonster::DropMoney(DWORD dwMoney, OBJID idOwner)
{
if (dwMoney <= 0)
return true;
if (this->GetLev() >= 80 && dwMoney <= 10)
return true;
#ifdef _DEBUG
// temp code
FILE* fp = fopen("money.ini", "a+");
if (fp)
{
fprintf(fp, "monster:%03u money ,%06u\n",
this->GetID(), dwMoney);
}
fclose(fp);
#endif
POINT pos;
pos.x = GetPosX();
pos.y = GetPosY();
if(GetMap()->FindDropItemCell(MONSTERDROPITEM_RANGE, &pos))
{
CMapItem* pMapItem = CMapItem::CreateNew();
if(pMapItem)
{
if(pMapItem->CreateMoney(MapManager()->SpawnMapItemID(), GetMap(), pos, dwMoney, idOwner))
{
MapManager()->QueryMapItemSet()->AddObj(pMapItem);
return true;
}
else
pMapItem->ReleaseByOwner();
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////
bool CMonster::DropItem(OBJID idItemType, OBJID idOwner, int nMagic2, int nMagic3, int nUserLuck,bool bIsAllowDropUnident)
{
if (idItemType == ID_NONE)
return true;
POINT pos;
pos.x = GetPosX();
pos.y = GetPosY();
if(GetMap()->FindDropItemCell(MONSTERDROPITEM_RANGE, &pos))
{
CMapItem* pMapItem = CMapItem::CreateNew();
if(pMapItem)
{
bool bUnIdent = false,bSetIdentFlag=false;
//---判断是否进行转换为未鉴定的判断---begin
if(bIsAllowDropUnident)
{
int nSort = CItem::GetItemSort(idItemType);
int nType = CItem::GetItemType(idItemType);
if(nSort==IETMSORT_FINERY)
{
if(nType==ITEMTYPE_HELMET || nType ==ITEMTYPE_NECKLACE || nType ==ITEMTYPE_ARMOR
||nType ==ITEMTYPE_BANGLE || nType == ITEMTYPE_SHOES)
{
bSetIdentFlag=true;
}
}
else if(nSort == ITEMSORT_WEAPON1 )
{
bSetIdentFlag=true;
}
//转变为未鉴定物品
if (bSetIdentFlag)
{
//根据品质计算转换为鉴定的成功概率
int nQuality = CItem::GetQuality(idItemType);
int nRate=0;
if(nQuality==QUALITY_ZERO)
nRate = 5;
else if(nQuality==QUALITY_ONE)
nRate = 30;
else if(nQuality==QUALITY_TWO)
nRate = 50;
else if(nQuality==QUALITY_THREE)
nRate = 70;
else if(nQuality==QUALITY_FOUR)
nRate = 80;
if(::RandGet(100) < nRate)
{
bUnIdent = true;
}
}
}
//---判断是否进行转换为未鉴定的判断---end
// bool bUnIdent = (nQuality <= NORMAL_QUALITY && ::RandGet(100) < UNIDENT_PERCENT && !CItem::IsMedicine(idItemType) && !CItem::IsArrowSort(idItemType)
// || nQuality > NORMAL_QUALITY || nMagic2 || nMagic3);
if(pMapItem->Create(MapManager()->SpawnMapItemID(), GetMap(), pos, idItemType, idOwner, nMagic2, nMagic3, bUnIdent, nUserLuck))
{
MapManager()->QueryMapItemSet()->AddObj(pMapItem);
return true;
}
else
pMapItem->ReleaseByOwner();
}
}
#ifdef _DEBUG
// temp code
FILE* fp = fopen("item.ini", "a+");
if (fp)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -