#include "stdafx.h" #include "Ability.h" #include "StateInfoParser.h" #include "SkillInfoParser.h" #include "Battle.h" #include "GameZone.h" #include "Skill.h" #include "CharacterFormula.h" #include "StatusManager.h" #include "./MovingPlanner.h" void Ability::Init(Skill* skill, const BASE_ABILITYINFO* ability_info) { skill_ = skill; Character* const owner = skill->GetOwner(); const SLOTCODE skill_code = skill->GetSkillCode(); SkillInfo* const skill_info = skill->GetSkillInfo(); const SkillScriptInfo* script_info = skill->GetSkillBaseInfo(); const BYTE skill_stat_type = script_info->m_bySkillStatType; InitDetailed(owner, skill_code, skill_info, skill_stat_type, ability_info); } void Ability::InitDetailed( Character* attacker, SLOTCODE skill_code, SkillInfo* skill_info, BYTE skill_stat_type, const BASE_ABILITYINFO* ability_info) { __UNUSED((skill_info, skill_stat_type)); skill_code_ = skill_code; base_ability_info_ = ability_info; attacker_= attacker; event_code_ = 0; } bool Ability::Execute(Character* target, BYTE* msg, WORD& msg_size) { if (GetAttacker() == NULL) { return false; } if (target != NULL && target->IsDeleted()) { return false; } if (msg != NULL) { SKILL_RESULT_CODE* const result_msg = (SKILL_RESULT_CODE*)msg; result_msg->m_wAbilityIndex = GetIndex(); msg_size = result_msg->GetSize(); result_msg->m_wStatusCode = 0; result_msg->m_iStatusTime = 0; #ifdef _NA_007667_20141001_WITCHBLADE_SKILL result_msg->overlap_status_count = 0; #endif //_NA_007667_20141001_WITCHBLADE_SKILL } return true; } bool Ability::IsValidStateID() const { const eCHAR_STATE_TYPE state_type = GetStateID(); if (state_type != eCHAR_STATE_INVALID) { return false; } return true; } bool Ability::CanExecute( Character* attacker, Character* target, DWORD main_target_key, WzVector /*main_target_pos*/) { if (base_ability_info_ == NULL) { return false; } const eABILITY_RANGE_TYPE range_type = eABILITY_RANGE_TYPE(base_ability_info_->m_byRangeType); const DWORD range_type_bitset = (1 << range_type); const StatusManager* const attacker_status_manager = attacker->GetStatusManager(); const StatusField& attacker_status_field = attacker_status_manager->Status; if (attacker_status_field.IsPassConstraint(attacker, base_ability_info_) == false) { return false; } const DWORD apply_check_canbe_attacked = (1 << SKILL_ABILITY_ENEMY) | (1 << SKILL_ABILITY_TARGETAREA_ENEMY) | (1 << SKILL_ABILITY_MYAREA_ENEMY); if ((range_type_bitset & apply_check_canbe_attacked) && !target->CanBeAttacked()) { return false; } const DWORD apply_safety_zone_rule_field = (1 << SKILL_ABILITY_ENEMY) | (1 << SKILL_ABILITY_TARGETAREA_ENEMY) | (1 << SKILL_ABILITY_MYAREA_ENEMY) | (1 << SKILL_ABILITY_PLAYER_ENEMY); if (apply_safety_zone_rule_field & range_type_bitset) { WORD skip_check_tile_attr_for_target = 0; if (target->IsEqualObjectKind(MAPNPC_OBJECT)) { skip_check_tile_attr_for_target = PTA_NO_WALK; } if (nsAI::PlanEventObject::AcceptableTarget( target, PTA_SAFETY_ZONE, skip_check_tile_attr_for_target) == false) { return false; } if ((attacker != target) && (nsAI::PlanEventObject::AcceptableTarget(attacker, PTA_SAFETY_ZONE, 0) == false)) { return false; } } const StatusManager* const target_status_manager = target->GetStatusManager(); bool is_riding_or_spreading = false; { const StatusField& target_status_field = target_status_manager->Status; if (target_status_field.IsRidingRider() || target_status_field.IsSpreadWings()) { is_riding_or_spreading = true; } } if (base_ability_info_->m_wAbilityID == eABILITY_KNOCKBACK || base_ability_info_->m_wAbilityID == eABILITY_KNOCKBACK2) { if (is_riding_or_spreading) { return false; } } #ifdef _NA_007128_20140326_MONDSCHIEN_DOMINATION //°¢ÀλóÅ¿¡¼­´Â ¾Æ·¡ ¾îºô¸®Æ¼°¡ Àû¿ëµÇÁö¾Ê´Â´Ù(°¢ÀÎ ½ÇÆÐ ¹æÁö) if ( target_status_manager->FindStatus(eCHAR_STATE_STAMP)) { switch(base_ability_info_->m_wAbilityID) { case eABILITY_STUN_STATUS: case eABILITY_KNOCKBACK: case eABILITY_KNOCKBACK2: case eABILITY_PULLING: return false; default: break; } } #endif //_NA_007128_20140326_MONDSCHIEN_DOMINATION // Ç®¸µÀÇ ¸é¿ªÁ¶°Ç °Ë»ç´Â º°µµ·Î ÁøÇàÇÑ´Ù. // Ç®¸µÀº State°¡ ¾Æ´Ï±â ¶§¹® if (base_ability_info_->m_wAbilityID == eABILITY_PULLING) { //Ç®¸µ¿¡ ¸é¿ªµÇ´Â »óŵé if (target_status_manager->FindStatus(eCHAR_STATE_PROTECTION) != NULL) { return false; } } const eCHAR_STATE_TYPE state_type = GetStateID(); const BASE_STATEINFO* const state_info = StateInfoParser::Instance()->GetStateInfo(state_type); bool check_success_rate = false; //Àû¿ëÇÏ·Á´Â State°¡ ÀÖÀ» °æ¿ì if (state_info != NULL) { if (!state_info->m_bRidingApply) { if (is_riding_or_spreading) { return false; } } if (state_info->m_byType == eSTATE_TYPE_ABNORMAL || state_info->m_byType == eSTATE_TYPE_WEAKENING) { // µð¹öÇÁ°è¿­ State ¸é¿ª °ü·Ã #ifdef _NA_008486_20150914_TOTAL_BALANCE if (target_status_manager->FindStatus(eCHAR_STATE_PROTECTION) || target_status_manager->FindStatus(eCHAR_STATE_STAMP) || target_status_manager->isImmunityDamageState(attacker)) { return false; } #else if (target_status_manager->FindStatus(eCHAR_STATE_PROTECTION) || target_status_manager->FindStatus(eCHAR_STATE_STAMP) || target_status_manager->isImmunityDamageState()) { return false; } #endif //_NA_008486_20150914_TOTAL_BALANCE check_success_rate = true; } else if (state_info->m_byType == eSTATE_TYPE_SPECIALITY) { if (target_status_manager->FindStatus(eCHAR_STATE_IMMUNITY_DAMAGE)) { #ifdef _JP_006544_DRAGON_NIGHT_DRAGONTANS_BUG #else return false; #endif // _JP_006544_DRAGON_NIGHT_DRAGONTANS_BUG } check_success_rate = true; } if (IsStatusHit( attacker, target, base_ability_info_->m_wSuccessRate, state_type, GetSKill()) == false) { return false; } } if (check_success_rate == false) { if (!DrawLots((BYTE)(base_ability_info_->m_wSuccessRate / 10.0f))) { return false; } } if (CheckAbilityRange( attacker, target, main_target_key, base_ability_info_->m_byRangeType) == false) { return false; } return true; } bool Ability::CheckAbilityRange( Character* const attacker, Character* const target, const DWORD main_target_key, const BYTE ability_range_type) const { if (ability_range_type == SKILL_ABILITY_CORPSE_RESURRECTION || ability_range_type == SKILL_ABILITY_CORPSE_FRIEND || ability_range_type == SKILL_ABILITY_MYAREA_CORPSE_ENEMY || ability_range_type == SKILL_ABILITY_CORPSE_ENEMY) { if (!target->IsDead()) { return false; } } else if (target->IsDead()) { return false; } if (ability_range_type == SKILL_ABILITY_FIELD) { return false; } switch (ability_range_type) { case SKILL_ABILITY_FRIEND: case SKILL_ABILITY_TARGETAREA_FRIEND: case SKILL_ABILITY_MYAREA_FRIEND: case SKILL_ABILITY_CORPSE_FRIEND: { if (attacker->IsFriend(target) != USER_RELATION_FRIEND) { return false; } } break; case SKILL_ABILITY_ENEMY: case SKILL_ABILITY_TARGETAREA_ENEMY: case SKILL_ABILITY_MYAREA_ENEMY: case SKILL_ABILITY_MYAREA_CORPSE_ENEMY: case SKILL_ABILITY_CORPSE_ENEMY: { if (attacker->IsFriend(target) != USER_RELATION_ENEMY) { return false; } } break; case SKILL_ABILITY_CORPSE_RESURRECTION: { if (!attacker->CanResurrection(target)) { return false; } } break; case SKILL_ABILITY_ME: case SKILL_ABILITY_FIELD: case SKILL_ABILITY_SUMMON: case SKILL_ABILITY_SUMMONED_MONSTER: break; case SKILL_ABILITY_PLAYER_ENEMY: if (target->IsEqualObjectKind(PLAYER_OBJECT) == 0) { return false; } break; default: break; } if (ability_range_type == SKILL_ABILITY_FRIEND || ability_range_type == SKILL_ABILITY_ENEMY) { if (main_target_key != target->GetObjectKey()) { return false; } } else if (ability_range_type == SKILL_ABILITY_ME) { if (attacker->GetObjectKey() != target->GetObjectKey()) { return false; } } return true; }