Files
Sun1602/Server/GameServer/SelfDestructionAbility.cpp
T
2022-10-26 12:25:11 +08:00

198 lines
6.0 KiB
C++

#include "StdAfx.h"
#include ".\selfdestructionability.h"
#include "Monster.h"
#include "MovingPlanner.h"
#include "SkillSystem/CSSyncTuner.h"
bool SelfDestructionAbility::CanExecute(
Character* attacker, Character* target, DWORD main_target_key, WzVector main_target_pos)
{
if (Ability::CanExecute(attacker, target, main_target_key, main_target_pos) == false)
{
return false;
}
const BASE_ABILITYINFO* const ability_info = GetBaseAbilityInfo();
if (ability_info == NULL)
{
return false;
}
const int kill_ratio = ability_info->m_iParam[0] / 10;
if (kill_ratio == 0)
{
return false;
}
const int waste_hp_ratio = ability_info->m_iParam[1];
if (waste_hp_ratio == 0)
{
return false;
}
#if !defined(_NA_000000_20130417_SELFDISTRUCTIONABILITY_MODIFY)
const DWORD waste_hp =
(DWORD)((float)attacker->GetMaxHP() * ((float)waste_hp_ratio / 1000.0f));
if (attacker->GetHP() <= waste_hp)
{
return false;
}
if (attacker->IsEqualObjectKind(PLAYER_OBJECT) == false)
{
return false;
}
const bool is_valid_target_kind =
(target->IsEqualObjectKind(PLAYER_OBJECT) || target->IsEqualObjectKind(NPC_OBJECT));
if (is_valid_target_kind == false)
{
return false;
}
if (target->IsEqualObjectKind(NPC_OBJECT))
{
const NPC* const npc = (NPC*)target;
const int npc_grade = npc->GetBaseInfo()->m_byGrade;
if (npc_grade == eNPC_BOSS ||
npc_grade == eNPC_MIDDLEBOSS ||
npc_grade == eNPC_LUCKY_MONSTER ||
npc_grade == eNPC_CRYSTAL_WARP ||
npc_grade == eNPC_DOMINATION_MAPOBJECT_NPC)
{
return false;
}
}
enum { kMaxLevelDiff = 10 };
const int level_diff = target->GetLevel() - attacker->GetLevel();
if (level_diff >= kMaxLevelDiff)
{
return false;
}
#endif
return true;
}
bool SelfDestructionAbility::Execute(Character* target, BYTE* msg, WORD& msg_size)
{
if (Ability::Execute(target, msg, msg_size) == false)
{
return false;
}
Character* const attacker = GetAttacker();
if (attacker == NULL)
{
return false;
}
GameField* const game_field = attacker->GetField();
if (game_field == NULL || game_field != target->GetField())
{
return false;
}
if (attacker->IsEqualObjectKind(PLAYER_OBJECT) == false)
{
return false;
}
const bool is_valid_target_kind =
(target->IsEqualObjectKind(PLAYER_OBJECT) || target->IsEqualObjectKind(NPC_OBJECT));
if (is_valid_target_kind == false)
{
return false;
}
const BASE_ABILITYINFO* const ability_info = GetBaseAbilityInfo();
const int kill_ratio = ability_info->m_iParam[0] / 10;
if (kill_ratio == 0)
{
return false;
}
const int waste_hp_ratio = ability_info->m_iParam[1];
if (waste_hp_ratio == 0)
{
return false;
}
const DWORD waste_hp =
(DWORD)((float)attacker->GetMaxHP() * ((float)waste_hp_ratio / 1000.0f));
if (attacker->GetHP() <= waste_hp)
{
return false;
}
const DWORD remain_hp = attacker->GetHP() - waste_hp;
if (remain_hp < 1)
{
return false;
}
// CHANGES: f110823.3L, prevent forced moved state problem without tile attributes check
// CHANGES: f111011.4L, fixed calculation to apply C/S strict moving synchronization.
//1. 먼저 앞으로 위치 이동하고.
const WzVector& attacker_pos = *attacker->GetPosPtr();
const WzVector& target_pos = *target->GetPosPtr();
WzVector distance = target_pos;
; distance -= attacker_pos;
WzVector direction; // nomalized vector
VectorNormalize(&direction, &distance);
WzVector offset = direction;
; offset *= 2.0f;
WzVector destination = attacker_pos;
; destination += (distance - offset);
const WORD kFilteredAttr = (PTA_NO_WALK);
if (game_field->GetMovingPlanner()->PathPlan_FastMoved(
attacker, destination, kFilteredAttr, &destination) != false)
{
if (attacker->IsEqualObjectKind(PLAYER_OBJECT))
{
static_cast<Player*>(attacker)->GetSyncTuner()->OnFastMoved(destination);
}
}
attacker->SetPos(&destination);
const bool is_success_kill = (random(0, 100) <= kill_ratio);
if (is_success_kill)
{
if (target->IsEqualObjectKind(PLAYER_OBJECT))
{
#ifdef _NA_006728_20130520_SKILL_BALANCE_MODIFY
DamageArgs damage_args(attacker, eATTACK_TYPE_MELEE, GetSkillCode());
#else
DamageArgs damage_args(attacker, eATTACK_TYPE_MELEE);
#endif // _NA_006728_20130520_SKILL_BALANCE_MODIFY
{
damage_args.damage_ = target->GetMaxHP();
}
target->SetHP(1);
target->Damaged(&damage_args);
MSGSUB_SKILL_PERIODIC_DAMAGE_BRD msg_brd;
{
msg_brd.Clear();
msg_brd.m_dwAttackerKey = attacker->GetObjectKey();
msg_brd.m_SkillCode = GetSkillCode();
msg_brd.m_byNumberOfTargets = 1;
DAMAGE_INFO& damage_info = msg_brd.m_DamageInfo[0];
{
damage_info.m_dwTargetKey = target->GetObjectKey();
damage_info.m_wDamage = damage_args.damage_;
damage_info.m_dwTargetHP = target->GetHP();
}
}
#ifdef _NA_008804_20160502_COMBAT_LOG
time_t t;
util::TimeSync::time(&t);
msg_brd.m_SvrTime = t;
#endif //(_NA_008804_20160502_COMBAT_LOG)
target->SendPacketAroundForSync(&msg_brd);
}
else
{
game_field->KillNPC(static_cast<Player*>(attacker), static_cast<NPC*>(target), true);
}
}
attacker->SetHP(remain_hp);
SKILL_RESULT_SELF_DESTRUCTION* const damage_msg = (SKILL_RESULT_SELF_DESTRUCTION*)msg;
damage_msg->m_dwHP = attacker->GetHP();
damage_msg->m_dwTargetHP = target->GetHP();
msg_size = damage_msg->GetSize();
return true;
}