📄 magic_process.cpp
字号:
// Magic.cpp: implementation of the CMagic class.
//
//////////////////////////////////////////////////////////////////////
#include "AllMsg.h"
#include "GameObj.h"
#include "Magic.h"
#include "MapGroup.h"
#include "StatusOnce.h"
#include "StatusMore.h"
#include "MapTrap.h"
/*/ 4超级的特殊状态,及超级回复
3500 3500 0002 回复术
3501 3501 0006 钢铁皮肤
3502 3502 0006 魔法护盾
3503 3503 0006 神圣祈祷
3504 3504 0006 魔力加持
*/
const int SUPER_MAGIC_RECRUIT = 3500;
const int SUPER_MAGIC_DEFENCE = 3501;
const int SUPER_MAGIC_MGC_DEFENCE = 3502;
const int SUPER_MAGIC_ATTACK = 3503;
const int SUPER_MAGIC_MGC_ATTACK = 3504;
const int THROW_WEAPON_DROP_RANGE = 1; // 扔武器攻击可掉物品的范围
//////////////////////////////////////////////////////////////////////
void MovePos(POINT* pPos, int nDir)
{
nDir %= 8;
pPos->x += _DELTA_X[nDir];
pPos->y += _DELTA_X[nDir];
}
//////////////////////////////////////////////////////////////////////
void DDALine(int x0, int y0, int x1, int y1, int nRange, vector<POINT>& vctPoint)
{
if (x0 == x1 && y0 == y1)
return;
float scale = 1.0f*nRange/sqrt((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0));
x1 = int(0.5f+scale*(x1-x0)+x0);
y1 = int(0.5f+scale*(y1-y0)+y0);
::DDALineEx(x0, y0, x1, y1, vctPoint);
}
//////////////////////////////////////////////////////////////////////
// launch
//////////////////////////////////////////////////////////////////////
int CMagic::Launch()
{
if(!m_pMagic)
return 0;
if(!m_pOwner->IsAlive())
{
ShowMiss();
return 0;
}
int ret = 0;
switch(m_pMagic->GetInt(MAGICDATA_SORT))
{
case MAGICSORT_ATTACK:
ret = ProcessAttack();
break;
case MAGICSORT_RECRUIT:
ret = ProcessRecruit();
break;
case MAGICSORT_CROSS:
ret = ProcessCross();
break;
case MAGICSORT_LINE:
case MAGICSORT_LINE_PENETRABLE:
ret = ProcessLine();
break;
case MAGICSORT_FAN:
ret = ProcessFan();
break;
case MAGICSORT_BOMB:
ret = ProcessBomb();
break;
case MAGICSORT_BOMB_LOCKALL:
ret = ProcessBombLockAll();
break;
case MAGICSORT_ATTACHSTATUS:
case MAGICSORT_TEAM_MAGIC:
ret = ProcessAttach();
break;
case MAGICSORT_DETACHSTATUS:
ret = ProcessDetach();
break;
case MAGICSORT_SQUARE:
ret = ProcessSquare();
break;
case MAGICSORT_JUMPATTACK:
ret = ProcessJumpAtk();
break;
case MAGICSORT_RANDOMTRANS:
ret = ProcessRandomTrans();
break;
case MAGICSORT_DISPATCHXP:
ret = ProcessDispatchXP();
break;
case MAGICSORT_COLLIDE:
ret = ProcessCollide();
break;
case MAGICSORT_ATKSTATUS:
ret = ProcessAtkStatus();
break;
case MAGICSORT_CALLTEAMMEMBER:
ret = ProcessCallTeamMember();
break;
case MAGICSORT_RECORDTRANSSPELL:
ret = ProcessRecordTransSpell();
break;
case MAGICSORT_TRANSFORM:
ret = ProcessTransform();
break;
case MAGICSORT_ADDMANA:
ret = ProcessAddMana();
break;
case MAGICSORT_LAYTRAP:
ret = ProcessLayTrap();
break;
case MAGICSORT_CALLPET:
ret = ProcessCallPet();
break;
case MAGICSORT_DECLIFE:
ret = ProcessDecLife();
break;
case MAGICSORT_GROUNDSTING:
ret = ProcessGroundSting();
break;
case MAGICSORT_REBORN:
ret = ProcessReborn();
break;
case MAGICSORT_SORB_SOUL:
ret = ProcessSorbSoul();
break;
case MAGICSORT_STEAL:
ret = ProcessSteal();
break;
/////////////////////////////////////////////////
// 新增幻兽魔法类型
case MAGICSORT_BLAST_THUNDER:
ret = ProcessBlastThunder();
break;
case MAGICSORT_MULTI_ATTACHSTATUS:
ret = ProcessMultiAttach();
break;
case MAGICSORT_MULTI_DETACHSTATUS:
ret = ProcessMultiDetach();
break;
case MAGICSORT_MULTI_CURE:
ret = ProcessMultiCure();
break;
case MAGICSORT_STEAL_MONEY:
ret = ProcessStealMoney();
break;
case MAGICSORT_KO:
ret = ProcessKO();
break;
case MAGICSORT_ESCAPE:
ret = ProcessEscape();
break;
/////////////////////////////////////////////////
default:
ASSERT(!"switch magic sort");
}
return ret;
}
//////////////////////////////////////////////////////////////////////
// magic process
//////////////////////////////////////////////////////////////////////
bool CMagic::ProcessAttack()
{
CHECKF(m_pMagic);
CHECKF(m_pOwner);
/*
// check syn of user
if (!m_pOwner->SynPosition(m_pos.x, m_pos.y))
{
UserManager()->KickOutSocket(m_pOwner->GetSocketID(), "SynPosition");
return false;
}
*/
m_setTargetLocked.clear();
IRole* pTarget = m_pOwner->FindAroundRole(m_idTarget);
if(!pTarget || !pTarget->IsAlive())
return false;
// if(m_pOwner->GetDistance(pTarget->GetPosX(), pTarget->GetPosY()) > m_pMagic->GetInt(MAGICDATA_DISTANCE))
// return false;
if (this->IsImmunity(pTarget))
return false;
if (m_pMagic->GetInt(MAGICDATA_FLOOR_ATTR)) // 0: need not check
{
int nAttr = m_pOwner->GetMap()->GetFloorAttr(pTarget->GetPosX(), pTarget->GetPosY());
if(m_pMagic->GetInt(MAGICDATA_FLOOR_ATTR) != nAttr)
return false;
}
m_setTargetLocked.push_back(pTarget->GetID());
if (m_pMagic->GetSTrackAmount() > 0)
LockTarget(true);
int nTotalExp = 0;
for (int k=0; k<m_nApplyTimes; k++)
{
int nPower = CBattleSystem::CalcPower(HitByMagic(), m_pOwner, pTarget, GetPower(k));
// 广播法术效果
CMsgMagicEffect msg;
IF_OK(msg.Create(m_pOwner->GetID(), m_pMagic->GetInt(MAGICDATA_TYPE), m_pMagic->GetInt(MAGICDATA_LEVEL), m_idTarget, nPower, m_pOwner->GetDir()))
m_pOwner->BroadcastRoomMsg(&msg, INCLUDE_SELF);
// set crime status
CheckCrime(pTarget);
if (nPower)
{
int nLifeLost = nPower;
if (pTarget->TransferShield(HitByMagic(), m_pOwner, nPower))
{
}
else
{
nLifeLost = __min(pTarget->GetLife(), nPower);
pTarget->AddAttrib(_USERATTRIB_LIFE, -1*nLifeLost, SYNCHRO_TRUE);
pTarget->BeAttack(HitByMagic(), m_pOwner, nPower);
}
nTotalExp += nLifeLost;
IStatus* pStatus = m_pOwner->QueryStatus(STATUS_DMG2LIFE);
if (pStatus)
{
int nLifeGot = ::CutTrail(0, MulDiv(nPower, pStatus->GetPower(), 100));
if (nLifeGot > 0)
m_pOwner->AddAttrib(_USERATTRIB_LIFE, nLifeGot, SYNCHRO_TRUE);
}
}
if (m_pMagic->GetSTrackAmount() > 0)
AdjustPosByTrack(k);
}
if (nTotalExp > 0)
AwardExpOfLife(pTarget, nTotalExp);
m_pos.x = pTarget->GetPosX();
m_pos.y = pTarget->GetPosY();
// if (!pTarget->IsAlive())
// m_pOwner->Kill(pTarget, GetDieMode());
//? 未增加武器熟练度,也未损耗双方装备。
// drop weapon in weapon skill
if(m_pMagic->GetInt(MAGICDATA_USE_XP) == TYPE_KONGFU && m_pMagic->GetInt(MAGICDATA_DROPWEAPON) == THROW_WERPONR_TARGET)
{
CItem* pWeapon = m_pOwner->GetWeaponR();
IF_OK(pWeapon)
{
POINT pos;
pos.x = pTarget->GetPosX();
pos.y = pTarget->GetPosY();
m_pOwner->GetMap()->FindDropItemCell(THROW_WEAPON_DROP_RANGE, &pos);
m_pOwner->DropItem(pWeapon->GetID(), pos.x, pos.y); // 没找到CELL也扔,但会重叠。
}
}
return true;
}
bool CMagic::ProcessAtkStatus()
{
CHECKF(m_pMagic);
// vector<OBJID> setLastLocked;
// if (!m_setTargetLocked.empty())
// copy(m_setTargetLocked.begin(), m_setTargetLocked.end(), back_inserter(setLastLocked));
m_setTargetLocked.clear();
IRole* pTarget = m_pOwner->FindAroundRole(m_idTarget);
if(!pTarget || !pTarget->IsAlive())
return false;
// if(m_pOwner->GetDistance(pTarget->GetPosX(), pTarget->GetPosY()) > m_pMagic->GetInt(MAGICDATA_DISTANCE))
// return false;
if (this->IsImmunity(pTarget))
return false;
// m_setTargetLocked.push_back(pTarget->GetID());
int nPower = 0;
bool bAttachStatus = false;
int nStatusPower = 0;
int nSecs = 0;
int nTimes = 0;
DWORD nStatus = 0;
if(HitByWeapon()) // && !CBattleSystem::IsTargetDodged(m_pOwner, pTarget))
{
int nAdjust = 0;
switch(m_pMagic->GetInt(MAGICDATA_STATUS))
{
case STATUS_ATTACK:
{
int nAdjustAtk = GetPower();
nPower = CBattleSystem::CalcAttackPower(m_pOwner, pTarget, &nAdjustAtk, 0);
}
break;
case STATUS_DEFENCE1:
case STATUS_DEFENCE2:
case STATUS_DEFENCE3:
{
int nAdjustDef = GetPower();
nPower = CBattleSystem::CalcAttackPower(m_pOwner, pTarget, 0, &nAdjustDef);
}
break;
// case STATUS_WEAPONDAMAGE:
// {
// int nAdjustDmg = GetPower();
// nPower = CBattleSystem::CalcAttackPower(m_pOwner, pTarget);
// nPower = ::CutRange(m_pOwner->AdjustData(nPower, nAdjustDmg, pTarget->GetLife()), 0, (int)pTarget->GetMaxLife()*9/10);
// }
// break;
case STATUS_ATKSPEED:
{
int nPause = GetPower();
nPower = CBattleSystem::CalcAttackPower(m_pOwner, pTarget);
pTarget->SetFightPause(nPause);
}
break;
// 根据策划要求,取消这个状态以避免MAGICDATA_PERCENT的使用冲突
// case STATUS_STOP:
// {
// int nAdjustAtk = GetPower();
// int nMilliSecs = m_pMagic->GetInt(MAGICDATA_STEP);
// nPower = CBattleSystem::CalcAttackPower(m_pOwner, pTarget, &nAdjustAtk);
// if(pTarget->IsMonster() && ::RandGet(100) < m_pMagic->GetInt(MAGICDATA_PERCENT))
// {
// CMsgAction msg;
// IF_OK(msg.Create(pTarget->GetID(), pTarget->GetPosX(), pTarget->GetPosY(), pTarget->GetDir(), actionMoveStop, nMilliSecs))
// pTarget->SendMsg(&msg);
// }
// }
// break;
case STATUS_VAMPIRE:
{
int nAdjustAtk = GetPower();
int nAwardPercent = m_pMagic->GetInt(MAGICDATA_WIDTH);
CHECKF(nAwardPercent >= 0 && nAwardPercent <= 100);
nPower = CBattleSystem::CalcAttackPower(m_pOwner, pTarget, &nAdjustAtk);
int nAddLife = MulDiv(::CutTrail((int)pTarget->GetLife(), nPower), nAwardPercent, 100);
if(nAddLife > 0 && m_pOwner->GetLife() < m_pOwner->GetMaxLife() && m_pOwner->IsAlive())
m_pOwner->AddAttrib(_USERATTRIB_LIFE, nAddLife, UPDATE_TRUE);
}
break;
case STATUS_NORMAL:
break;
default: // other status
{
if (::RandGet(100) < m_pMagic->GetInt(MAGICDATA_STATUS_CHANCE))
{
bAttachStatus = true;
nStatusPower = GetPower();
nSecs = m_pMagic->GetInt(MAGICDATA_STEP);
nTimes = m_pMagic->GetInt(MAGICDATA_TIMES);
nStatus = m_pMagic->GetInt(MAGICDATA_STATUS);
ASSERT(nStatusPower > 0);
// CRole::AttachStatus(pTarget, nStatus, nStatusPower, nSecs, nTimes);
}
nPower = CBattleSystem::CalcAttackPower(m_pOwner, pTarget);
}
break;
}
}
// 广播法术效果
CMsgMagicEffect msg;
IF_OK(msg.Create(m_pOwner->GetID(), m_pMagic->GetInt(MAGICDATA_TYPE), m_pMagic->GetInt(MAGICDATA_LEVEL), m_idTarget, nPower, m_pOwner->GetDir()))
m_pOwner->BroadcastRoomMsg(&msg, INCLUDE_SELF);
// set crime status
CheckCrime(pTarget);
if (nPower)
{
CNpc* pNpc = NULL;
int nLifeLost = nPower;
if (pTarget->TransferShield(HitByMagic(), m_pOwner, nPower))
{
}
else
{
nLifeLost = __min(pTarget->GetLife(), nPower);
pTarget->AddAttrib(_USERATTRIB_LIFE, -1*nLifeLost, SYNCHRO_TRUE);
CUser* pTargetUser=NULL;
if(pTarget->QueryObj(OBJ_USER, IPP_OF(pTargetUser)))
pTargetUser->BroadcastTeamLife();
if(pTarget->QueryObj(OBJ_NPC, IPP_OF(pNpc)) && pNpc->IsAwardScore())
m_pOwner->AwardSynWarScore(pNpc, nLifeLost);
pTarget->BeAttack(HitByMagic(), m_pOwner, nPower);
}
int nExp = 0;
if (pTarget->IsMonster() || pNpc && pNpc->IsGoal() && m_pOwner->GetLev() >= pNpc->GetLev())
{
nExp += m_pOwner->AdjustExp(pTarget, nLifeLost);
if (!pTarget->IsAlive())
{
// 有组队,并且队伍中有其他队员,则奖励其他队员经验
int nBonusExp = pTarget->GetMaxLife()*KILLBONUS_PERCENT/100;
OtherMemberAwardExp(pTarget, nBonusExp);
nExp += m_pOwner->AdjustExp(pTarget, nBonusExp, true);
}
}
// 必须在分配组队经验之后杀死
if (!pTarget->IsAlive())
m_pOwner->Kill(pTarget, GetDieMode());
IStatus* pStatus = m_pOwner->QueryStatus(STATUS_DMG2LIFE);
if (pStatus)
{
int nLifeGot = ::CutTrail(0, MulDiv(nPower, pStatus->GetPower(), 100));
if (nLifeGot > 0)
m_pOwner->AddAttrib(_USERATTRIB_LIFE, nLifeGot, SYNCHRO_TRUE);
}
this->AwardExp(nExp);
}
// 把原来的先加状态后算攻击修改为先算攻击后加状态
// 原因是例如冰冻之类的魔法会在BeAttack的时候解除,因此必须在BeAttack之后调用加状态
if (bAttachStatus)
{
if(pTarget->IsAlive())
CRole::AttachStatus(pTarget, nStatus, nStatusPower, nSecs, nTimes);
}
//? 未增加武器熟练度,也未损耗双方装备。
return true;
}
//////////////////////////////////////////////////////////////////////
bool CMagic::ProcessRecruit()
{
CHECKF(m_pMagic);
m_setTargetLocked.clear();
vector<IRole*> setRole;
vector<int> setPower;
CTeam* pTeam = m_pOwner->GetTeam();
if(pTeam && m_pMagic->GetInt(MAGICDATA_MULTI))
{
for(int i = 0; i < pTeam->GetMemberAmount(); i++)
{
OBJID idTarget = pTeam->GetMemberByIndex(i);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -