Files
2022-10-26 12:25:11 +08:00

391 lines
12 KiB
C++

#include "stdafx.h"
#include "BombEffect.h"
#include "SkillInfoParser.h"
#include "CharacterFormula.h"
#include "StatusManager.h"
#include "Skill.h"
#include "AbilityFactory.h"
#include "Ability.h"
#include "StateInfoParser.h"
VOID BombEffect::End()
{
if (m_pField == NULL) {
return;
};
Character* const owner = GetOwner();
if (owner == NULL)
{
return;
}
// TODO: need 'm_pOwner' validation check
//_NA000000_110210_ENHANCED_TARGET_SEARCH_ALGORITHM
SkillInfo temp_skill_info;
const SkillInfoParser* skill_parser = SkillInfoParser::Instance();
const SkillScriptInfo* base_skill_info = skill_parser->GetSkillInfo(m_SkillCode);
if (base_skill_info == NULL) {
return;
}
// 주기 데미지 어빌리티가 있는지 체크
const BASE_ABILITYINFO* ability_interval_damage = \
base_skill_info->GetAbilityInfo(eABILITY_DAMAGE_PER_TIME);
// 디버프 어빌리티가 있는지 체크
const BASE_ABILITYINFO* ability_debuff = \
base_skill_info->GetAbilityInfo(eABILITY_STATUS_HEAL);
// 최대 마리수 제한
const int max_number_of_targets
= (base_skill_info->m_byMaxTargetNo)
? base_skill_info->m_byMaxTargetNo
: MAX_TARGET_NUM;
ns_object::SearchResult::SingleSearch search_result;
;{
ns_object::SearchOption::SingleSearch search_option(
max_number_of_targets,//int max_number_of_selected_characters,
owner, //Character* input_actor,
NULL, //Character* input_main_target_if_exist_it,
&m_vCurPos, //const WzVector* input_specific_application_center_pos_if_main_target_is_not_used_to_pos,
//
0.0f, //float attack_ranges,
m_fRadius, //float ranges_of_application,
SRF_FOWARD_360); //eSKILL_AREA_TYPE forms_of_application
bool success = m_pField->FindTargetsUsingSingleSearch(search_option, &search_result);
if (success == false) {
return;
};
};
//
if (search_result.number_of_selected_chars == 0) {
return;
}
//
MSGSUB_SKILL_EFFECT_BOMB_BRD msg_brd;
;{
msg_brd.Clear();
msg_brd.m_dwAttackerKey = owner->GetObjectKey();
msg_brd.m_SkillCode = m_SkillCode;
};
// f100908.1L
DamageArgs damage_args(owner, eATTACK_TYPE_MELEE);
;{
//damage_args.option_.is_critical_;
//damage_args.option_.is_mirror_;
//damage_args.limit_hp_;
damage_args.attack_regist_kind_ = eATTACK_RESIST_SKILL;
StateInfoParser* state_parser = StateInfoParser::Instance();
const BASE_STATEINFO* base_state_info = state_parser->GetStateInfo(GetStateID());
if (base_state_info) {
damage_args.sd_apply_ = static_cast<eSD_APPLY>(base_state_info->m_bySDApply);
}
//damage_args.damage_ = wResultDamage;
//damage_args.damage_sd_;
};
AbilityFactory* const ability_factory = AbilityFactory::Instance();
int number_of_hit_targets = 0;
const int number_of_targets = search_result.number_of_selected_chars;
for (int i = 0; i < number_of_targets; ++i)
{
Character* character = search_result.targets[i];
// PK 공격이라면 관련처리를 한다.
owner->ForcedAttack(character);
// 데미지 처리
BYTE skill_effects = 0;
// TODO: f110106.2L, do check a 'skill attack power'
damage_args.damage_ = ep2::CalcSkillDamage(owner, character,
eATTACK_TYPE_MELEE, true, 0, &skill_effects,
eATTACK_TYPE_MELEE, 0, m_fSkillPercentDamage);
;{
// f100908.1L
damage_args.option_.is_critical_ = (skill_effects & SKILL_EFFECT_CRITICAL) != 0;
};
owner->Damaged(&damage_args);
EFFECT_BOMB_INFO* const effect_info = &msg_brd.m_DamageInfo[number_of_hit_targets];
//
if (ability_interval_damage)
{
// 타겟에 걸리는 주기 데미지 처리
Ability* periodic_ability = ability_factory->AllocAbility(
ability_interval_damage->m_wAbilityID, SKILL_TYPE_ACTIVE);
periodic_ability->InitDetailed(owner,
m_SkillCode, &temp_skill_info, 0, ability_interval_damage);
AbilityStatus* ability_status_for_debug =
character->GetStatusManager()->AllocAbilityStatus(owner, periodic_ability);
__TOUCHED(ability_status_for_debug);
effect_info->m_wStateID = ability_interval_damage->m_wStateID;
// delete
{
AbilityFactory::Instance()->FreeAbility(periodic_ability);
periodic_ability = NULL;
}
}
// 디버프 처리
if (ability_debuff)
{
Ability* cure_ability = ability_factory->AllocAbility(
ability_debuff->m_wAbilityID, SKILL_TYPE_ACTIVE);
cure_ability->InitDetailed(owner, m_SkillCode, &temp_skill_info, 0, ability_debuff);
AbilityStatus* ability_status_for_debug =
character->GetStatusManager()->AllocAbilityStatus(owner, cure_ability);
__TOUCHED(ability_status_for_debug);
// delete
{
AbilityFactory::Instance()->FreeAbility(cure_ability);
cure_ability = NULL;
}
}
// 패킷에 데미지 정보 셋팅
effect_info->m_dwTargetKey = character->GetObjectKey();
effect_info->m_wDamage = damage_args.damage_;
effect_info->m_dwTargetHP = character->GetHP();
++number_of_hit_targets;
}
msg_brd.m_byNumberOfTargets = static_cast<uint8_t>(number_of_hit_targets);
if (number_of_hit_targets) {
m_pField->SendPacketAroundForSync(m_dwSectorIndex, &msg_brd); // ...
}
//
BaseEffect::End();
}
VOID
SelfDestructionDamageEffect::SetInformation( Character* const /*pAttacker*/, GameField* const pGameField, const SelfDestructionDamage_info_t* const pDamaged_char_info )
{
m_pField = pGameField;
m_eStep = eStep_Init;
m_DamagedCharInfo = *pDamaged_char_info;
m_ExecutableLifetime.SetTimer(TIMEOUT_LIFE_TIME);
}
BOOL
SelfDestructionDamageEffect::Update( DWORD /*curTick*/ )
{
//switch( m_eStep )
//{
//case eStep_Init:
//case eStep_Execute:
//case eStep_Executed:
//case eStep_Release:
// return FALSE;
//};
if( (eStep_Release == m_eStep) || (GetOwner() == NULL))
return FALSE;
if( eStep_Execute == m_eStep )
{
Start();
return TRUE;
}
if( eStep_Executed == m_eStep )
{
End();
return FALSE;
}
if( m_ExecutableLifetime.IsExpired() )
{
return FALSE;
}
return TRUE;
//if( m_bNeedClose || !m_pOwner )
// return FALSE;
//GameField* const pGameField = m_pOwner->GetField();
//if( !(pGameField && pGameField == m_pField) )
// return FALSE;
//return TRUE;
}
VOID
SelfDestructionDamageEffect::CmdExecute()
{
if(m_eStep == eStep_Init)
{
m_eStep = eStep_Execute;
//Start();
}
}
VOID
SelfDestructionDamageEffect::End()
{
//GameField* const pGameField = m_pOwner->GetField();
//if( (eStep_Executed != m_eStep) || !(pGameField && (pGameField == m_pField)) )
// return;
//const DWORD curHP = m_pOwner->GetHP();
//if( !curHP )
//{
// // 특수 처리 해당 Character가 바로 제거되는 상황 (Start에서 HP가 없었던 상황_이미 죽음_)
// m_pOwner->StopMoving();
// m_pField->DestroyObject( m_pOwner );
//}
Character* const owner = GetOwner();
if (owner == NULL)
{
return;
}
// 해당 몬스터 제거
const DWORD curHP = owner->GetHP();
if( curHP )
{
//m_pOwner->SetHP( 1 );
//m_pOwner->Damaged( 0, eATTACK_TYPE_MELEE, 100, FALSE );
// 그냥 죽는 거다...
owner->StopMoving();
m_pField->DestroyObject( owner );
}
}
VOID
SelfDestructionDamageEffect::Start()
{
Character* const owner = GetOwner();
if (owner == NULL)
{
return;
}
GameField* const game_field = owner->GetField();
if ((eStep_Executed == m_eStep) ||
!(game_field && (game_field == m_pField)))
{
return;
}
m_eStep = eStep_Executed;
//_NA000000_110210_ENHANCED_TARGET_SEARCH_ALGORITHM
const SkillInfoParser* skill_parser = SkillInfoParser::Instance();
const SkillScriptInfo* const base_skill_info = skill_parser->GetSkillInfo(m_SkillCode);
if (base_skill_info == NULL) {
return;
}
ns_object::SearchResult::SingleSearch search_result;
;{
ns_object::SearchOption::SingleSearch search_option(
MAX_TARGET_NUM,//int max_number_of_selected_characters,
owner, //Character* input_actor,
NULL, //Character* input_main_target_if_exist_it,
&m_vCurPos, //const WzVector* input_specific_application_center_pos_if_main_target_is_not_used_to_pos,
//
0.0f, //float attack_ranges,
m_fRadius, //float ranges_of_application,
SRF_FOWARD_360); //eSKILL_AREA_TYPE forms_of_application
bool success = game_field->FindTargetsUsingSingleSearch(search_option, &search_result);
if (success == false) {
return;
};
};
if (search_result.number_of_selected_chars == 0) {
return;
}
//
MSGSUB_SKILL_SELF_DESTRUCTION_BRD msg_brd;
;{
msg_brd.Clear();
msg_brd.m_dwAttackerKey = owner->GetObjectKey();
msg_brd.m_SkillCode = m_SkillCode;
};
StateInfoParser* const state_parser = StateInfoParser::Instance();
int number_of_hit_targets = 0;
const int number_of_targets = search_result.number_of_selected_chars;
for (int i = 0; i < number_of_targets; ++i)
{
Character* const character = search_result.targets[i];
// PK 공격이라면 관련처리를 한다.
owner->ForcedAttack(character);
// f100908.1L
DamageArgs damage_args(owner, eATTACK_TYPE_MELEE);
;{
//damage_args.option_.is_critical_;
//damage_args.option_.is_mirror_;
//damage_args.limit_hp_;
damage_args.attack_regist_kind_ = eATTACK_RESIST_SKILL;
const BASE_STATEINFO* base_stateinfo = state_parser->GetStateInfo(GetStateID());
if (base_stateinfo) {
damage_args.sd_apply_ = static_cast<eSD_APPLY>(base_stateinfo->m_bySDApply);
}
//damage_args.damage_;
//damage_args.damage_sd_;
};
// 데미지 처리
BYTE skill_effects = 0;
if (m_DamagedCharInfo.m_DamageOpt == eDamageOpt_Ratio)
{
// TODO: f110106.2L, do check a 'skill attack power'
damage_args.damage_ = ep2::CalcSkillDamage(owner, character,
eATTACK_TYPE_MELEE, true, 0, &skill_effects,
eATTACK_TYPE_MELEE, 0, static_cast<float>(m_DamagedCharInfo.m_Damage / 1000.f));
}
else //eDamageOpt_Value
{
damage_args.damage_ = m_DamagedCharInfo.m_Damage;
}
// f100908.1L
;{
//damage_args.option_.is_normal_;
damage_args.option_.is_critical_ = (skill_effects & SKILL_EFFECT_CRITICAL) != 0;
//damage_args.option_.is_mirror_;
//damage_args.target_;
//damage_args.limit_hp_;
//damage_args.attack_regist_kind_;
//damage_args.sd_apply_;
//damage_args.damage_;
//damage_args.damage_sd_;
};
owner->Damaged(&damage_args);
if (DAMAGE_INFO* damage_info = &msg_brd.m_DamageInfo[number_of_hit_targets])
{
damage_info->m_dwTargetKey = character->GetObjectKey();
damage_info->m_wDamage = damage_args.damage_;
damage_info->m_dwTargetHP = character->GetHP();
}
//
++number_of_hit_targets;
}
msg_brd.m_byNumberOfTargets = static_cast<uint8_t>(number_of_hit_targets);
if (number_of_hit_targets) {
m_pField->SendPacketAroundForSync(owner, &msg_brd);
};
BaseEffect::End();
}