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

1029 lines
35 KiB
C++

#include "stdafx.h"
#include <float.h>
#include <PublicMath.h>
#include "DragonTransStatus.h"
#include "GameServerEx.h"
#include "GameZone.h"
#include "ItemInfoParser.h"
#include "ItemManager.h"
#include "MovementChecker.h"
#include "Player.h"
#include "ResultCode.h"
#include "SCSlotContainer.h"
#include "SCSkillSlotContainer.h"
#include "ServerOptionParserEx.h"
#include "Skill.h"
#include "SkillInfoParser.h"
#include "SkillSlotManager.h"
#include "StatusManager.h"
#include "SummonedNPCs.h"
#include "SummonManager.h"
#ifdef _NA_007667_20141001_WITCHBLADE_SKILL
#include "MovingPlanner.h"
#endif //_NA_007667_20141001_WITCHBLADE_SKILL
RC::eSKILL_RESULT Player::CanUseSkilltoTarget(SkillScriptInfo* pBaseSkillInfo, DWORD TargetKey)
{
GameField* pField = GetField();
if(pField == NULL) return RC::RC_SKILL_INVALID_STATE;
Player* pCharacter = static_cast<Player*>(pField->FindObject(PLAYER_OBJECT, TargetKey));
if(pCharacter)
{
if((pBaseSkillInfo->m_byTarget == SKILL_TARGET_ENEMY_PLAYER) && (IsFriend(pCharacter) == USER_RELATION_FRIEND))
return RC::RC_SKILL_STATE_WHERE_CANNOT_ATTACK_ENEMY;
if(pCharacter->IsDead() && (pBaseSkillInfo->m_SkillClassCode != eSKILL_RESSURECTION) &&
#ifdef _NA_000000_20130812_NEW_CHARACTER_HELLROID
(pBaseSkillInfo->m_SkillClassCode != eSKILL_HELLROID_1021) && // 헬로이드 리바이브 스킬
#endif //_NA_000000_20130812_NEW_CHARACTER_HELLROID
(pBaseSkillInfo->m_SkillClassCode != eSKILL_REVIVAL) && (pBaseSkillInfo->m_SkillClassCode != eSKILL_REVERSE))
return RC::RC_SKILL_TARGET_ISDEAD;
#ifdef _NA_006623_20130409_STEEL_MODE_WHEN_ENERMY_CAN_USE_SKILL
if (pCharacter->IsStatus(eCHAR_STATE_STEEL)) {
return RC::RC_SKILL_INVALID_STATE;
}
#endif // _NA_006623_20130409_STEEL_MODE_WHEN_ENERMY_CAN_USE_SKILL
}
BASE_ABILITYINFO* pBaseAbilityInfo = NULL;
#ifdef _NA_003649_20111115_BATTLE_ZONE_HARDMODE
#if !defined(_NA_007123_20140324_SHADOW_SKILL_RENEWAL)
pBaseAbilityInfo = pBaseSkillInfo->GetAbilityInfo(eABILITY_SUMMON_DEAD_MONSTER);
if(pBaseAbilityInfo) {
// 트리거 설정된 몬스터는 소환 불가능 - arycoat 2012.01.20
NPC* target_monster = static_cast<NPC*>(pField->FindObject(MONSTER_OBJECT, TargetKey));
if(target_monster) {
const MONSTERCODE monster_code = target_monster->GetBaseInfo()->m_MonsterCode;
const sNPC_POLICY::ePOLICY policy = \
AppliedNpcDependencyChain::Instance()->GetNpcDependencyInfo( monster_code );
if (sNPC_POLICY::NPC_POLICY_NPC_ONDEAD_TRIGGER & policy ) {
return RC::RC_SKILL_CANNOT_SUMMON;
}
}
}
#endif //_NA_007123_20140324_SHADOW_SKILL_RENEWAL
pBaseAbilityInfo = pBaseSkillInfo->GetAbilityInfo(eABILITY_CUR_HP_INCREASE);
if (pBaseAbilityInfo) {
if (pBaseAbilityInfo->m_byRangeType == SKILL_ABILITY_FRIEND ||
pBaseAbilityInfo->m_byRangeType == SKILL_ABILITY_MYAREA_FRIEND )
{
NPC* target_monster = static_cast<NPC*>(pField->FindObject(MONSTER_OBJECT, TargetKey));
if (target_monster && target_monster->IsEqualObjectKind(SUMMON_OBJECT)) {
return RC::RC_SKILL_CANNOT_HEAL;
}
}
}
#endif //_NA_003649_20111115_BATTLE_ZONE_HARDMODE
return RC::RC_SKILL_SUCCESS;
}
#ifdef _NA_007667_20141001_WITCHBLADE_SKILL
RC::eSKILL_RESULT Player::CanUseSkill( const SkillInfo* skill_info, BOOL bCoolTimerReset /*= TRUE*/ )
{
SLOTCODE skill_code = skill_info->skill_code_;
DWORD target_key = skill_info->main_target_key_;
WzVector target_pos = skill_info->main_target_pos_;
SkillScriptInfo* pBaseSkillInfo = (SkillScriptInfo *)SkillInfoParser::Instance()->GetSkillInfo(skill_code);
if(!pBaseSkillInfo)
{
return RC::RC_SKILL_BASEINFO_NOTEXIST;
}
RC::eSKILL_RESULT rcResult = Character::CanUseSkill(skill_code, bCoolTimerReset);
if(rcResult != RC::RC_SKILL_SUCCESS)
return rcResult;
if (GetCharType() == eCHAR_WITCHBLADE)
{
//FP검사-----------------------------------------------------
BASE_ABILITYINFO* fp_ability_info = pBaseSkillInfo->GetAbilityInfo(eABILITY_FP_CHANGE);
if (fp_ability_info == NULL) {
fp_ability_info = pBaseSkillInfo->GetAbilityInfo(eABILITY_FP_TOGGLE);
}
if (fp_ability_info != NULL)
{
PLAYERFP need_fp = (PLAYERFP)fp_ability_info->m_iParam[1];
PLAYERFP result_fp = min(0, GetFP() + need_fp);
if (result_fp < 0) {
return RC::RC_SKILL_FP_RUN_SHORT;
}
}
//고정형 소환수-----------------------------------------------------
GameField* field = GetField();
fp_ability_info = NULL;
fp_ability_info = pBaseSkillInfo->GetAbilityInfo(eABILITY_SUMMON_IMMOVABLE);
if (fp_ability_info != NULL && field != NULL)
{
nsAI::MovingPlanner* moving_planner = field->GetMovingPlanner();
WORD attributes;
INT iTile = moving_planner->GetAllowTileToStand(target_pos, NULL, -1.0f, 100.0f, &attributes,
PTA_NO_WALK | PTA_PLAYER_FALLDOWN_TILE);
if (iTile < 0) {
return RC::RC_SKILL_FAILED;
}
}
}
SCSkillSlotContainer* pContainer = m_pSkillSlotManager->GetSkillSlotContainer();
SCSkillSlot* pCurSkillSlot = pContainer->GetSkillSlotByCode(skill_code);
// 널 체크한다.
if(FALSE == CheckNullSkillSlot(pCurSkillSlot,skill_code))
return RC::RC_SKILL_DOES_NOT_HAVE;
// 요구레벨을 체크한다.
if(FALSE == CheckRequireLv(pBaseSkillInfo))
return RC::RC_SKILL_REQUIRE_LEVEL_LIMIT;
// 스킬을 사용할 수 있는 캐릭터인지 체크한다.
if(!CheckClassDefine(skill_code, TRUE))
{
SUNLOG(eFULL_LOG, "[Player::CanUseSkill] SkillCode[%d] The Type Of Character is Invalid!", skill_code);
return RC::RC_SKILL_CHAR_CLASS_LIMIT;
}
// 스킬, 어빌리티 별로 조건 체크
rcResult = CheckSkillCondition(skill_code);
if(rcResult != RC::RC_SKILL_SUCCESS) return rcResult;
// 무기 제한
if (CheckWeaponDefine(pBaseSkillInfo) == false)
{
return RC::RC_SKILL_WEAPON_LIMIT;
}
rcResult = CanUseSkilltoTarget(pBaseSkillInfo, target_key);
if(rcResult != RC::RC_SKILL_SUCCESS) {
return rcResult;
}
// 쿨타임 처리
if(bCoolTimerReset && FALSE == CoolTimerReset(skill_code)) {
return RC::RC_SKILL_COOLTIME_ERROR;
}
return RC::RC_SKILL_SUCCESS;
}
#else
RC::eSKILL_RESULT Player::CanUseSkill(SLOTCODE SkillCode, DWORD TargetKey, BOOL bCoolTimerReset)
{
SkillScriptInfo* pBaseSkillInfo = (SkillScriptInfo *)SkillInfoParser::Instance()->GetSkillInfo(SkillCode);
if(!pBaseSkillInfo)
{
return RC::RC_SKILL_BASEINFO_NOTEXIST;
}
RC::eSKILL_RESULT rcResult = Character::CanUseSkill(SkillCode, bCoolTimerReset);
if(rcResult != RC::RC_SKILL_SUCCESS)
return rcResult;
SCSkillSlotContainer* pContainer = m_pSkillSlotManager->GetSkillSlotContainer();
SCSkillSlot* pCurSkillSlot = pContainer->GetSkillSlotByCode(SkillCode);
// 널 체크한다.
if(FALSE == CheckNullSkillSlot(pCurSkillSlot,SkillCode))
return RC::RC_SKILL_DOES_NOT_HAVE;
// 요구레벨을 체크한다.
if(FALSE == CheckRequireLv(pBaseSkillInfo))
return RC::RC_SKILL_REQUIRE_LEVEL_LIMIT;
#if !defined(_NA_0_20100901_SKILLTREE_SYSTEM)
// 요구 숙련도 체크
if(FALSE == CheckRequireSkillStat(pBaseSkillInfo))
return RC::RC_SKILL_REQUIRE_SKILLSTAT_LIMIT;
#endif
// 스킬을 사용할 수 있는 캐릭터인지 체크한다.
if(!CheckClassDefine(SkillCode, TRUE))
{
SUNLOG(eFULL_LOG, "[Player::CanUseSkill] SkillCode[%d] The Type Of Character is Invalid!", SkillCode);
return RC::RC_SKILL_CHAR_CLASS_LIMIT;
}
// 스킬, 어빌리티 별로 조건 체크
rcResult = CheckSkillCondition(SkillCode);
if(rcResult != RC::RC_SKILL_SUCCESS) return rcResult;
// 무기 제한
if (CheckWeaponDefine(pBaseSkillInfo) == false)
{
return RC::RC_SKILL_WEAPON_LIMIT;
}
rcResult = CanUseSkilltoTarget(pBaseSkillInfo, TargetKey);
if(rcResult != RC::RC_SKILL_SUCCESS) {
return rcResult;
}
// 쿨타임 처리
if(bCoolTimerReset && FALSE == CoolTimerReset(SkillCode)) {
return RC::RC_SKILL_COOLTIME_ERROR;
}
return RC::RC_SKILL_SUCCESS;
}
#endif //_NA_007667_20141001_WITCHBLADE_SKILL
RC::eSKILL_RESULT Player::CanUseSummonSkill(SLOTCODE SkillCode, DWORD TargetKey, BOOL bCoolTimerReset)
{
SkillScriptInfo* pBaseSkillInfo = (SkillScriptInfo *)SkillInfoParser::Instance()->GetSkillInfo(SkillCode);
if(!pBaseSkillInfo)
return RC::RC_SKILL_BASEINFO_NOTEXIST;
SCSkillSlotContainer* pContainer = m_pSkillSlotManager->GetSkillSlotContainer();
SCSkillSlot* pCurSkillSlot = pContainer->GetSkillSlotByCode(SkillCode);
// 널 체크한다.
if(FALSE == CheckNullSkillSlot(pCurSkillSlot,SkillCode))
return RC::RC_SKILL_DOES_NOT_HAVE;
// 요구레벨을 체크한다.
if(FALSE == CheckRequireLv(pBaseSkillInfo))
return RC::RC_SKILL_REQUIRE_LEVEL_LIMIT;
#if !defined(_NA_0_20100901_SKILLTREE_SYSTEM)
// 요구 숙련도 체크
if(FALSE == CheckRequireSkillStat(pBaseSkillInfo))
return RC::RC_SKILL_REQUIRE_SKILLSTAT_LIMIT;
#endif
RC::eSKILL_RESULT rcResult = CanUseSkilltoTarget(pBaseSkillInfo, TargetKey);
if(rcResult != RC::RC_SKILL_SUCCESS) {
return rcResult;
}
// 쿨타임 처리
if(bCoolTimerReset && FALSE == CoolTimerReset(SkillCode)) {
return RC::RC_SKILL_COOLTIME_ERROR;
}
return RC::RC_SKILL_SUCCESS;
}
RC::eSKILL_RESULT Player::CanUseSkillItem(SLOTCODE SkillCode, DWORD TargetKey, BOOL bCoolTimerReset)
{
SkillScriptInfo* pBaseSkillInfo = (SkillScriptInfo *)SkillInfoParser::Instance()->GetSkillInfo(SkillCode);
if(!pBaseSkillInfo)
return RC::RC_SKILL_BASEINFO_NOTEXIST;
RC::eSKILL_RESULT rcResult = Character::CanUseSkillItem(SkillCode);
if(rcResult != RC::RC_SKILL_SUCCESS)
return rcResult;
// 요구레벨을 체크한다.
if(FALSE == CheckRequireLv(pBaseSkillInfo))
return RC::RC_SKILL_REQUIRE_LEVEL_LIMIT;
return CanUseSkilltoTarget(pBaseSkillInfo, TargetKey);
}
BOOL Player::CheckNullSkillSlot(SCSkillSlot* pCurSkillSlot, SLOTCODE SkillCode)
{
if(!pCurSkillSlot)
{
SUNLOG(eMIDDLE_LOG, "[Player::CanUseSkill] SkillCode[%d] The Player doesn't have the skill!", SkillCode);
return FALSE;
}
return TRUE;
}
// 요구레벨을 체크한다.
BOOL Player::CheckRequireLv(SkillScriptInfo* pBaseSkillInfo)
{
if(GetLevel() < pBaseSkillInfo->m_wRequireLv)
{
SUNLOG(eFULL_LOG, "Player : [CanUseSkill] SkillCode[%d] The Level of Player doesn't reach RequireLevel!", pBaseSkillInfo->m_SkillCode);
return FALSE;
}
return TRUE;
}
BOOL Player::CheckRequireSkillStat(SkillScriptInfo* pBaseSkillInfo)
{
// 요구 숙련도1 체크
if(pBaseSkillInfo->m_wRequireSkillStat[0] && GetExperty1() < pBaseSkillInfo->m_wRequireSkillStat[0])
{
SUNLOG(eFULL_LOG, "Player : [CanUseSkill] SkillCode[%d] The SkillStat1 of Player doesn't reach RequireSkillStat1!", pBaseSkillInfo->m_SkillCode);
return FALSE;
}
// 요구 숙련도2 체크
if(pBaseSkillInfo->m_wRequireSkillStat[1] && GetExperty2() < pBaseSkillInfo->m_wRequireSkillStat[1])
{
SUNLOG(eFULL_LOG, "Player : [CanUseSkill] SkillCode[%d] The SkillStat2 of Player doesn't reach RequireSkillStat2!", pBaseSkillInfo->m_SkillCode);
return FALSE;
}
return TRUE;
}
bool Player::CheckWeaponDefine(const SkillScriptInfo* const skill_script_info) const
{
if (skill_script_info->m_iWeaponDefine[0] == -1)
{
return true;
}
const DWORD weapon_kind = GetWeaponKind();
#ifdef _NA_004530_20120315_1202_SKILL_RENEWAL
#else
// 무기가 없으면 스킬사용 불가
if (weapon_kind == eWEAPONTYPE_PUNCH)
{
SUNLOG(
eCRITICAL_LOG,
_T("|%s|%d|무기 제한 타입이 올바르지 않습니다.|SkillCode = %d, WeaponType = %d|"),
__FUNCTION__,
__LINE__,
skill_script_info->m_SkillCode,
weapon_kind
);
return false;
}
#endif
// 무기 제한조건 4개를 체크한다.
for (int i = 0; i < 4; ++i)
{
if (weapon_kind == skill_script_info->m_iWeaponDefine[i])
{
return true;
}
}
SUNLOG(
eCRITICAL_LOG,
_T("|%s|%d|무기 제한 타입이 올바르지 않습니다.|SkillCode = %d, WeaponType = %d|"),
__FUNCTION__,
__LINE__,
skill_script_info->m_SkillCode,
weapon_kind
);
return false;
}
// UNDONE | Player::CheckSkillCondition <- each loop check... by update passive skill
RC::eSKILL_RESULT Player::CheckSkillCondition(const SLOTCODE skill_code) const
{
const SkillScriptInfo* const skill_info = SkillInfoParser::Instance()->GetSkillInfo(skill_code);
if (skill_info == NULL)
{
RC::RC_SKILL_BASEINFO_NOTEXIST;
}
#if !defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_)
// HP 소진
{
const BASE_ABILITYINFO* const ability_info = skill_info->GetAbilityInfo(eABILITY_EXHAUST_HP);
if (ability_info != NULL)
{
const int value_type = ability_info->m_iParam[0];
const int ratio = ability_info->m_iParam[1];
int calc_hp = 0;
if (value_type == VALUE_TYPE_PERCENT_PER_MAX)
{
calc_hp = GetMaxHP() * ratio / 1000;
}
else if(value_type == VALUE_TYPE_PERCENT_PER_CUR)
{
calc_hp = GetHP() * ratio / 1000;
}
if (calc_hp <= 0)
{
return RC::RC_SKILL_HPMP_RUN_SHORT;
}
}
}
// HP 저하시 공격력, 방어력 증감
{
const BASE_ABILITYINFO* ability_info =
skill_info->GetAbilityInfo(eABILITY_LOWHP_ATTACKPOWER_CHANGE);
if (ability_info == NULL)
{
ability_info = skill_info->GetAbilityInfo(eABILITY_LOWHP_DEFENSE_CHANGE);
}
if (ability_info != NULL)
{
const float req_hp_ratio = ability_info->m_iOption2 / 1000.f;
float hp_ratio = 0;
if (GetMaxHP())
{
hp_ratio = (float)GetHP() / GetMaxHP();
}
if (hp_ratio > req_hp_ratio)
{
return RC::RC_SKILL_HPMP_RUN_SHORT;
}
}
}
#endif
// 투기 개수 증가
#ifdef _NA_008480_20150909_MODIFY_FIGHTING_ENERGY
#else
{
const BASE_ABILITYINFO* const ability_info =
skill_info->GetAbilityInfo(eABILITY_FIGHTING_ENERGY_NUM_INCREASE);
if (ability_info != NULL)
{
if (GetFightingEnergy() >= MAX_FIGHTING_ENERGY_NUM)
{
return RC::RC_SKILL_FIGHTING_ENERGY_FULL;
}
}
}
#endif //_NA_008480_20150909_MODIFY_FIGHTING_ENERGY
// SP 당 추가 공격력
{
const BASE_ABILITYINFO* const ability_info =
skill_info->GetAbilityInfo(eABILITY_BONUS_DAMAGE_PER_SP);
if (ability_info != NULL)
{
const DWORD reqire_mp = GetMaxMP() * ability_info->m_iOption2 / 1000;
if (GetMP() < reqire_mp)
{
return RC::RC_SKILL_HPMP_RUN_SHORT;
}
}
}
// 아드레날린
{
const BASE_ABILITYINFO* const ability_info = skill_info->GetAbilityInfo(eABILITY_ADRENALINE);
if (ability_info != NULL)
{
const SummonedNPCs* const summoned_npcs =
SummonManager::Instance()->FindSummonNPCs(GetObjectKey());
if (summoned_npcs == NULL || (summoned_npcs->GetNumberOfNPCs() <= 0))
{
return RC::RC_SKILL_SUMMONED_NOTEXIST;
}
}
}
#ifdef _NA_007123_20140324_SHADOW_SKILL_RENEWAL
#else
// 하이드
{
const BASE_ABILITYINFO* const ability_info = skill_info->GetAbilityInfo(eABILITY_HIDE);
if (ability_info != NULL)
{
const BaseStatus* const battle_state = GetStatusManager()->FindStatus(eCHAR_STATE_BATTLE);
if (battle_state != NULL)
{
return RC::RC_SKILL_CAN_NOT_STATE_HIDE;
}
#ifdef _NA_005028_20120627_MODIFY_IMPOSSIBLE_CAST_HIDE_SKILL_IN_SSQ
const GameZone* const game_zone = GetGameZonePtr();
if (game_zone != NULL)
{
const sPOLICY_ZONE& policy = game_zone->Policyment;
if (!!(policy.FIELD & policy.ENABLE_SSQ_CONTROL))
{
return RC::RC_SKILL_FAILED;
}
}
#endif // _NA_005028_20120627_MODIFY_IMPOSSIBLE_CAST_HIDE_SKILL_IN_SSQ
}
}
#endif //_NA_007123_2014_0324_SHADOW_SKILL_RENEWAL
// 오오라
;{
const BASE_ABILITYINFO* const ability_info = skill_info->GetAbilityInfo(eABILITY_AURORA);
if (ability_info != NULL)
{
const BaseStatus* const aurora_state = GetStatusManager()->FindAuroraStatus();
if (aurora_state != NULL && aurora_state->IsAbilityStatus())
{
AbilityStatus* ability_state = (AbilityStatus*)aurora_state;
SLOTCODE skill_code = ability_state->GetSkillCode();
if(false == CheckCoolTimer(skill_code)) {
return RC::RC_SKILL_COOLTIME_ERROR;
}
}
}
};
#ifdef _NA_007667_20141001_WITCHBLADE_SKILL
;{
// 스킬사용 조건 검사용 어빌리티 확인
const BASE_ABILITYINFO* condition_ability = skill_info->GetAbilityInfo(eABILITY_SKILL_CONDITION);
if (condition_ability != NULL)
{
int skill_condition = condition_ability->m_iOption2;
int value_type = condition_ability->m_iParam[0];
int condition_value = condition_ability->m_iParam[1];
RC::eSKILL_RESULT result = RC::RC_SKILL_SUCCESS;
switch (skill_condition)
{
case eSKILL_CONDITION_BELOW_HP:
{
if (value_type == VALUE_TYPE_VALUE)
{
if (GetHP() > condition_value) {
result = RC::RC_SKILL_FAILED;
}
}
else if (value_type == VALUE_TYPE_PERCENT_PER_MAX)
{
if ((GetHPRatio() * 1000.0f) > condition_value) {
result = RC::RC_SKILL_FAILED;
}
}
} break;
}
return result;
}
};
#endif //_NA_007667_20141001_WITCHBLADE_SKILL
return RC::RC_SKILL_SUCCESS;
}
// CHANGES, f100824.7L
bool Player::CanApplyPassiveSkill(SLOTCODE SkillCode)
{
SkillScriptInfo* pBaseSkillInfo = (SkillScriptInfo *)SkillInfoParser::Instance()->GetSkillInfo(SkillCode);
// 패시브 스킬인지 체크한다.
if(pBaseSkillInfo->m_bySkillType != SKILL_TYPE_PASSIVE) return FALSE;
// 스킬을 사용할 수 있는 캐릭터인지 체크한다.
if(!CheckClassDefine(SkillCode, FALSE))
{
// SUNLOG(eFULL_LOG, "Player : [CanApplyPassiveSkill] The Type Of Character is Invalid! ");
return FALSE;
}
// 무기 제한
if(pBaseSkillInfo->m_iWeaponDefine[0] != -1)
{
DWORD dwCurWeaponKind = GetWeaponKind();
#if !defined(_NA_004965_20120613_NEW_CHARACTER_MYSTIC)
// 무기가 없으면 스킬사용 불가
if(dwCurWeaponKind == eWEAPONTYPE_PUNCH)
{
// SUNLOG(eFULL_LOG, "Player : [CanApplyPassiveSkill] The Weapon Type is Invalid! ");
return FALSE;
}
#endif //_NA_004965_20120613_NEW_CHARACTER_MYSTIC
// 무기 제한조건 4개를 체크한다.
BOOL bSuccess = FALSE;
for(int i = 0; i < 4; ++i)
{
if(dwCurWeaponKind == pBaseSkillInfo->m_iWeaponDefine[i])
{
bSuccess = TRUE;
break;
}
}
if(!bSuccess)
{
// SUNLOG(eFULL_LOG, "Player : [CanApplyPassiveSkill] The Weapon Type is Invalid! ");
return FALSE;
}
}
// 요구레벨을 체크한다.
if(GetLevel() < pBaseSkillInfo->m_wRequireLv)
{
// SUNLOG(eFULL_LOG, "Player : [CanUseSkill] The Level of Player doesn't reach RequireLevel! ");
return FALSE;
}
// 요구 숙련도1 체크
if(pBaseSkillInfo->m_wRequireSkillStat[0] && GetExperty1() < pBaseSkillInfo->m_wRequireSkillStat[0])
{
// SUNLOG(eFULL_LOG, "Player : [CanUseSkill] The SkillStat1 of Player doesn't reach RequireSkillStat1! ");
return FALSE;
}
// 요구 숙련도2 체크
if(pBaseSkillInfo->m_wRequireSkillStat[1] && GetExperty2() < pBaseSkillInfo->m_wRequireSkillStat[1])
{
// SUNLOG(eFULL_LOG, "Player : [CanUseSkill] The SkillStat2 of Player doesn't reach RequireSkillStat2! ");
return FALSE;
}
// 스킬, 어빌리티 별로 조건 체크
RC::eSKILL_RESULT rcResult = CheckSkillCondition(SkillCode);
if(rcResult != RC::RC_SKILL_SUCCESS) return FALSE;
return TRUE;
}
//-------------------------------------------------------------------------------------------------
// 스킬, 스타일 습득
//-------------------------------------------------------------------------------------------------
SLOTCODE Player::GetDefaultStyle(const CODETYPE weapon_code) const
{
if (weapon_code == 0)
{
return GetPunchStyle();
}
const BASE_ITEMINFO* const weapon_info = ItemInfoParser::Instance()->GetItemInfo(weapon_code);
if (weapon_info == NULL)
{
return GetPunchStyle();
}
switch(weapon_info->m_wType)
{
case eITEMTYPE_TWOHANDSWORD:
return eSTYLE_TWOHANDSWORD_NORMAL;
case eITEMTYPE_TWOHANDAXE:
return eSTYLE_TWOHANDAXE_NORMAL;
case eITEMTYPE_ONEHANDSWORD:
return eSTYLE_ONEHANDSWORD_NORMAL;
case eITEMTYPE_SPEAR:
return eSTYLE_SPEAR_NORMAL;
case eITEMTYPE_DAGGER:
return eSTYLE_SHADOW_DAGGER_NORMAL;
case eITEMTYPE_WHIP:
return eSTYLE_SHADOW_WHIP_NORMAL;
case eITEMTYPE_STAFF:
return eSTYLE_STAFF_NORMAL;
case eITEMTYPE_ORB:
return eSTYLE_ORB_NORMAL;
case eITEMTYPE_ONEHANDCROSSBOW:
return eSTYLE_ONEHANDCROSSBOW_NORMAL;
case eITEMTYPE_ETHERWEAPON:
return eSTYLE_ETHER_NORMAL;
case eITEMTYPE_GUNTLET: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return eSTYLE_MYSTIC_GUNTLET_NORMAL;
case eITEMTYPE_POLEARM: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return eSTYLE_MYSTIC_POLEARM_NORMAL;
case eITEMTYPE_HELLROID_1: //_NA_000000_20130812_NEW_CHARACTER_HELLROID
return eSTYLE_HELLROID_WEAPON1;
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
case eITEMTYPE_ARCBLADE:
return eSTYLE_WITCHBLADE_ARCBLADE;
#endif //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
default:
return GetPunchStyle();
}
}
SLOTCODE Player::GetPunchStyle() const
{
switch(GetCharType())
{
case eCHAR_BERSERKER:
return eSTYLE_BERSERKER_PUNCH;
case eCHAR_DRAGON:
return eSTYLE_DRAGON_PUNCH;
case eCHAR_SHADOW:
return eSTYLE_SHADOW_PUNCH;
case eCHAR_VALKYRIE:
return eSTYLE_VALKYRIE_PUNCH;
case eCHAR_ELEMENTALIST:
return eSTYLE_MAGICIAN_PUNCH;
case eCHAR_MYSTIC: // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
return eSTYLE_MYSTIC_PUNCH;
case eCHAR_HELLROID: //_NA_000000_20130812_NEW_CHARACTER_HELLROID
return eSTYLE_HELLROID_PUNCH;
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
case eCHAR_WITCHBLADE:
return eSTYLE_WITCHBLADE_PUNCH;
#endif //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
default:
ASSERT(!"Player : [GetPunchStyle] Invalid CharType!");
return eSTYLE_BERSERKER_PUNCH;
}
}
BOOL Player::CheckClassDefine(SLOTCODE SkillCode, BOOL bUseActiveSkill)
{
SkillScriptInfo* pBaseSkillInfo = (SkillScriptInfo *)SkillInfoParser::Instance()->GetSkillInfo(SkillCode);
if(!(pBaseSkillInfo && (eSKILL_USER_PLAYER == pBaseSkillInfo->m_bySkillUserType)))
return FALSE;
//eCHAR_TYPE eCurType = GetCharType();
//eCHAR_TYPE eCheckType = (eCHAR_TYPE)pBaseSkillInfo->m_dwClassDefine;
BASE_PLAYERINFO& rPlayerInfo = *GetCharInfo();
const eCHAREX_TYPE charExType = (eCHAREX_TYPE)(BYTE)rPlayerInfo.m_ChangeOfClassStep;
const DWORD classDefine = pBaseSkillInfo->m_dwClassDefine;
const BOOLEAN isMatched = charExType == classDefine;
if(isMatched)
return TRUE;
#ifdef _NA_0_20120104_DRAGON_COMMON_SKILL
if (GetCharType() == eCHAR_DRAGON)
{
if (bUseActiveSkill)
{
// 변신중 액티브 스킬 사용시
StatusManager* const pStatusManager = GetStatusManager();
if(pStatusManager->Status.IsDragonTransforming())
{
DragonTransStatus* pDragonTransStatus = (DragonTransStatus*)GetStatusManager()->FindStatus(eCHAR_STATE_TRANSFORMATION);
const DWORD transformClass = (DWORD)pDragonTransStatus->GetCharType();
switch (transformClass)
{
case eTRANSFORM_TYPE_DRAGON1:
{
switch (classDefine)
{
case eTRANSFORM_TYPE_DRAGON1:
case eDRAGON_COMMON_SKILL_1stTRANS:
return TRUE;
case eCHAREX_DRAGON_1stTRANS_100LEVEL:
return (charExType == eCHAREX_DRAGON_KNIGHT_100LEVEL) ? TRUE : FALSE;
}
}
break;
case eTRANSFORM_TYPE_DRAGON2:
{
switch (classDefine)
{
case eTRANSFORM_TYPE_DRAGON2:
case eDRAGON_COMMON_SKILL_2ndTRANS:
return TRUE;
case eCHAREX_DRAGON_2ndTRANS_100LEVEL:
return (charExType == eCHAREX_DRAGON_KNIGHT_100LEVEL) ? TRUE : FALSE;
}
}
break;
}
}
else
{
switch(classDefine)
{
case eCHAR_DRAGON:
case eDRAGON_COMMON_SKILL_1stTRANS:
case eDRAGON_COMMON_SKILL_2ndTRANS:
return TRUE; // (전직/체인지업 여부를 떠나서) 이전스킬 포괄해야 한다.
}
}
}
else
{
switch(classDefine)
{
case eCHAR_DRAGON:
case eCHAREX_DRAGON_1stTRANS:
case eCHAREX_DRAGON_2ndTRANS:
case eDRAGON_COMMON_SKILL_1stTRANS:
case eDRAGON_COMMON_SKILL_2ndTRANS:
return TRUE; // (전직/체인지업 여부를 떠나서) 이전스킬 포괄해야 한다.
case eCHAREX_DRAGON_1stTRANS_100LEVEL:
case eCHAREX_DRAGON_2ndTRANS_100LEVEL:
return (charExType == eCHAREX_DRAGON_KNIGHT_100LEVEL) ? TRUE : FALSE;
}
}
return FALSE;
}
#endif
// irregular process for DRAGON & DRAGON TRANSFORMATION
switch(charExType)
{
case eCHAREX_BERSERKER_100LEVEL:
case eCHAREX_SHADOW_100LEVEL:
case eCHAREX_VALKYRIE_100LEVEL:
case eCHAREX_ELEMENTALIST_100LEVEL:
case eCHAREX_MYSTIC_100LEVEL: //_NA_004965_20120613_NEW_CHARACTER_MYSTIC
case eCHAREX_HELLROID_100LEVEL: //_NA_000000_20130812_NEW_CHARACTER_HELLROID
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
case eCHAREX_WITCHBLADE_100LEVEL:
#endif //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
return classDefine == (charExType-eCHAREX_100LEVEL_CHANGEUP_CONSTANT);
#if !defined(_NA_0_20120104_DRAGON_COMMON_SKILL)
case eCHAR_DRAGON:
case eCHAREX_DRAGON_KNIGHT_100LEVEL:
{
// 드래곤 변신인 경우 액티브스킬사용은 제한하지만, 패시브스킬 사용이나 스킬 습득은 허용한다.
if(bUseActiveSkill)
{
StatusManager* const pStatusManager = GetStatusManager();
if(pStatusManager->Status.IsDragonTransforming())
{
DragonTransStatus* pDragonTransStatus = (DragonTransStatus*)GetStatusManager()->FindStatus(eCHAR_STATE_TRANSFORMATION);
const DWORD transformClass = (DWORD)pDragonTransStatus->GetCharType();
return
(classDefine == transformClass) // 기본 비교시
|| (classDefine == transformClass+10) // 100레벨 체인지업시
//|| (classDefine == transformClass+20) // 다음 전직 비교시
;
}
}
switch(classDefine)
{
case eCHAR_DRAGON:
case eCHAREX_DRAGON_1stTRANS:
case eCHAREX_DRAGON_2ndTRANS:
return TRUE; // (전직/체인지업 여부를 떠나서) 이전스킬 포괄해야 한다.
case eCHAREX_DRAGON_1stTRANS_100LEVEL:
case eCHAREX_DRAGON_2ndTRANS_100LEVEL:
return eCHAREX_DRAGON_KNIGHT_100LEVEL == charExType;
}
}
break;
#endif //#if !defined(_NA_0_20120104_DRAGON_COMMON_SKILL)
}
return FALSE;
}
RC::eSKILL_RESULT Player::UseSkill(SkillInfo* skill_info_data, BYTE byAttackPropensity)
{//실세콘賈痰뇹잿 by:枷쟁팃숲 2021-07-05
if (skill_info_data == NULL) {
return RC::RC_SKILL_FAILED;
};
//
GameField* pField = GetField();
if (!pField || !pField->IsReady()) {
return RC::RC_SKILL_FAILED;
};
//
if (skill_info_data->skill_code_ == 0) {
return RC::RC_SKILL_FAILED;
};
//
#ifdef _NA_008069_20150210_ADD_SPA_SYSTEM
if (pField->GetGameZone()->GetZoneType() == eZONETYPE_SPA_FIELD)
{
return RC::RC_SKILL_CANNOT_USE_SPA;
}
#endif //_NA_008069_20150210_ADD_SPA_SYSTEM
//
;{ // (NOTE) to support a shadow control, __NA_S00015_20080828_NEW_HOPE_SHADOW
// 이부분 따로 함수로 빼자.
//////////////////////////////////////////////////////////////////////////
BaseStatus* pStatus = NULL;
// 현재 사용자가 투명 상태이면 투명 상태를 해제 한다.
StatusManager* pStatusManager = GetStatusManager();
pStatus = pStatusManager->FindStatus(eCHAR_STATE_HP_SUCTION);
if (pStatus)
pStatus->StopStatus();
pStatus = pStatusManager->FindStatus(eCHAR_STATE_MP_SUCTION);
if (pStatus)
pStatus->StopStatus();
#if !defined(_NA_005159_20120807_DISABLE_REMOVE_RUSH_STATE)
pStatus = pStatusManager->FindStatus(eCHAR_STATE_RUSH);
if (pStatus)
pStatus->StopStatus();
#endif //_NA_005159_20120807_DISABLE_REMOVE_RUSH_STATE
//////////////////////////////////////////////////////////////////////////
};
Character* pTargetChar = pField->FindCharacter(skill_info_data->main_target_key_);
if (!pTargetChar)
return RC::RC_SKILL_TARGET_NOTEXIST;
RC::eSKILL_RESULT rcResult = RC::RC_SKILL_SUCCESS;
const BOOLEAN bApplyGeneralForcedAtkRule = !(Policyment.FIELD & Policyment.PCC_IN_SSQ_FIELD);
if (bApplyGeneralForcedAtkRule)
{
bool befForceAttack = IsForceAttack();
SetForceAttack(skill_info_data->attack_propensity_ ==ATTACK_PROPENSITY_FORCE?true:false);
RC::eSKILL_RESULT rcResult = ChkSkillPvP(pTargetChar);
if (rcResult != RC::RC_SKILL_SUCCESS)
{
SetForceAttack(befForceAttack);
return rcResult;
}
}
// 좌표가 유효한지 체크
if (FALSE == finite(skill_info_data->cur_pos_))
{
SUNLOG(eCRITICAL_LOG, "세콘땡鱗뇹잿 :: 뎠품貫零轟槻! x[%f] y[%f] z[%f]", skill_info_data->cur_pos_.x, skill_info_data->cur_pos_.y, skill_info_data->cur_pos_.z);
return RC::RC_SKILL_POSITION_INVALID;
}
if (FALSE == finite(skill_info_data->dest_pos_))
{
SUNLOG(eCRITICAL_LOG, "세콘땡鱗뇹잿 :: 커깃貫零轟槻! x[%f] y[%f] z[%f]", skill_info_data->dest_pos_.x, skill_info_data->dest_pos_.y, skill_info_data->dest_pos_.z);
return RC::RC_SKILL_POSITION_INVALID;
}
// 클라와 서버간에 위치 보정
if (SKILL_FACTOR_NOMAL == skill_info_data->skill_factor_)
{
ModifyPosition(skill_info_data);
//ModifyPosition(TRUE, wvCurPos, wvDestPos, skill_info_data->m_wvCurPos, skill_info_data->m_wvDestPos, skill_info_data->m_SkillCode);
#ifdef _NA_007667_20141001_WITCHBLADE_SKILL
rcResult = CanUseSkill(skill_info_data, skill_info_data->main_target_key_);
#else
rcResult = CanUseSkill(skill_info_data->skill_code_, skill_info_data->main_target_key_);
#endif //_NA_007667_20141001_WITCHBLADE_SKILL
}
else
{
rcResult = CanUseSkillItem(skill_info_data->skill_code_, skill_info_data->main_target_key_);
}
if (rcResult != RC::RC_SKILL_SUCCESS)
return rcResult;
m_pSkillManager->RegisterSkill(SKILL_TYPE_ACTIVE, skill_info_data);
//__NA_S00028_SHADOW_ADD_WORK
assert(skill_info_data->root_skill_info_->IsSkill());
const SkillScriptInfo* base_skill_info = \
static_cast<const SkillScriptInfo*>(skill_info_data->root_skill_info_);
if (base_skill_info)
{
if (base_skill_info->m_byTarget == SKILL_TARGET_ENEMY ||
base_skill_info->m_byTarget == SKILL_TARGET_AREA ||
base_skill_info->m_byTarget == SKILL_TARGET_REACHABLE_ENEMY ||
base_skill_info->m_byTarget == SKILL_TARGET_ENEMY_PLAYER)
{
GetStatusManager()->UpdateExpiredTime(eCHAR_STATE_BATTLE, STATE_BATTLE_TIME);
}
}
return rcResult;
}
// m_byMOVE_SYNC_FAIL_DISTANCE값을 토대로 간단하게 위치 동기화를 한다.
// 채집, 탐색..
BOOL Player::CorrectPosition( WzVector& wvClientCurPos, WzVector& vResultCurPos )
{
if( FALSE == Character::finite(wvClientCurPos) )
return FALSE;
// 체크할 좌표 위치 보정
WzVector vServerPos;
GetPos( &vServerPos );
FLOAT fCurPosDiff = Math_Vector2DLength( vServerPos, wvClientCurPos );
SERVER_COMMON_OPTION& stServerOptionInfo = ServerOptionParserEx::Instance()->GetServerOption();
if( fCurPosDiff >= stServerOptionInfo.m_byMOVE_SYNC_FAIL_DISTANCE )
{
vResultCurPos = vServerPos;
}
else
{
vResultCurPos = wvClientCurPos;
SetPos( &wvClientCurPos );
MovementChecker* pCHECKER = GetMovementChecker();
MovementChecker::sPATH_INFO* pPathInfo = pCHECKER->GetServerPathExpUpdate();
pPathInfo->SetupLatestState( pCHECKER, .0f, 0, wvClientCurPos, wvClientCurPos );
}
return TRUE;
}
#ifdef _NA_007667_20141001_WITCHBLADE_SKILL
void Player::ProcessRisingForce()
{
if (GetCharType() != eCHAR_WITCHBLADE) {
return;
}
if (IsDead() == TRUE || IsDeleted() == true) {
return ;
}
SkillSlotManager* skillslot_manager = this->GetSkillSlotManager();
SLOTCODE skill_code = skillslot_manager->FindSkill(eSKILL_RISINGFORCE);
if (skill_code != 0)
{
//조건검사
if (CheckCoolTimer(skill_code) != true || CheckSkillCondition(skill_code) != RC::RC_SKILL_SUCCESS) {
return;
}
//스킬예약
SkillManager* skill_manager = this->GetSkillManager();
skill_manager->SetAutoCastSkill(skill_code, false);
}
}
#endif //_NA_007667_20141001_WITCHBLADE_SKILL