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

7655 lines
193 KiB
C++

//------------------------------------------------------------------------------
// Character.cpp
// (C) 2005 Webzen Sunstudio
//------------------------------------------------------------------------------
#include "SunClientPrecompiledHeader.h"
#include <PlayerAttributes.h>
#include "Character.h"
#include "ObjectManager.h"
#include "InterfaceManager.h"
#include "Player.h"
#include "Monster.h"
#include "NPC.h"
#include <SCItemSlot.h>
#include "Map.h"
#include "globalfunc.h"
#include "CollectionParser.h"
#include "State/StateCollect.h"
#include "Hero.h"
#include "CooltimeManager.h"
#include "Gamefunc.h"
#include "ChatDialog.h"
#include "SkillInfoParser.h"
#include "ProjectileManagerEx.h"
#include "HeroActionInput.h"
#include "SoundEffect.h"
#include "ResourceManager.h"
#include "HeadMeshInfoParser.h"
#include "StateInfoParser.h"
#include "SkillEffectInfoParser.h"
#include "Camera.h"
#include "GameConst_Color.h"
#include "Map.h"
#include "SceneBase.h"
#include "Clone.h"
#include "CloneManager.h"
#include "Application.h"
#include "uiGuildMan/uiGuildMan.h"
#include "State/SkillStateFactory.h"
#include "EquipmentContainer.h"
#include "ItemInfoParser.h"
#include "LoadScene.h"
#include "ItemAttrCalculator.h"
#include "ItemManager.h"
#include "AppearanceResourceCode.h"
#include "HeroEquipmentContainer.h"
#include "uiPartyMan/uiPartyMan.h"
#include "SkillEffectFunc.h"
#ifdef _NA_008350_20150617_SPA_NEW_STYLE_MODE_ANIMATION
#include "SpaZoneInfoParser.h"
#endif //_NA_008350_20150617_SPA_NEW_STYLE_MODE_ANIMATION
#ifdef _NA_008679_20160202_REWORK_BATTLEGROUND
#include "BattleGroundInfoParser.h"
#endif //_NA_008679_20160202_REWORK_BATTLEGROUND
extern DWORD g_CurTime;
extern float g_fUpperForce;
extern float g_fGravity;
//------------------------------------------------------------------------------
/**
*/
Character::Character():
m_dwTargetObjectKey ( 0),
m_fMoveSpeed ( 0.1f),
m_fAttackRange ( 4.0f),
m_fReachNPCRange ( 5.f),
m_dwHP ( 1),
m_iAttackStandTime ( 0),
m_dwMoveTarget ( 0),
m_dwLatestAttack ( 0),
m_dwLatestQueueAttack ( 0),
m_fSpinForce ( 0.0f),
m_dwTerrainAttribute ( 0),
m_fMeshHeight ( 1.0f),
m_dwNextActionAttackSerial ( 0),
m_iEmoteIcon ( 0),
m_iEmoteIconDelay ( 0),
m_iDeathTimer ( 0),
m_dwAttackEffectTime ( 0),
m_CurrentEmotionAnimationID ( 0),
m_iTextFadeCurDelay ( 0),
m_bFade ( FALSE),
m_bNoCull ( FALSE),
m_bCameraAlpha ( FALSE),
m_bVibrateMove ( FALSE),
m_fVibrateCurrent ( 0.0f),
m_bDeathTimer ( FALSE),
m_pEmoteDraw ( NULL),
m_fAlpha ( 255.0f),
m_bShield ( FALSE),
m_dwHideTime (0),
m_bHide (FALSE),
m_dwCurColorTime (0),
m_nSeekNodeCount (20000),
#ifdef _YJ_FISHING_SYSTEM_000933
m_wiCurFishingAniID ( 0),
#endif //_YJ_FISHING_SYSTEM_000933
m_reserveHP ( 0),
m_dwSD ( 0),
m_hWaterEllipse ( INVALID_HANDLE_VALUE )
{
m_IsPolymorphApperance = FALSE;
m_OldTerrainColor=WzColor_RGBA(255,255,255,255);
m_listTargeter.clear();
m_vNotProcessedList.clear();
m_wvOldVisiblePos.x = 0.0f;
m_wvOldVisiblePos.y = 0.0f;
m_wvOldVisiblePos.z = 0.0f;
m_fHeight = 0.0f;
m_byFloor = 0;
m_FreeMove = FALSE;
m_ForceTurn = FORCE_TURN_NONE;
m_bShowName = FALSE;
m_fVisibleAngleZ = 0.0f;
m_fVisibleAngleModifier = 0.0f;
m_TransformData.Init();
m_ReflectDamageList.clear();
NormalAttack.ani_type = 0;
NormalAttack.combo_max_count = 3;
}
void Character::SetShow(BOOL bFlag)
{
Object::SetShow(bFlag);
ShowFullsetEffect(bFlag);
RefreshFullsetEffect(this);
}
void Character::SetAngle(float fAngleX, float fAngleY, float fAngleZ)
{
Object::SetAngle( fAngleX, fAngleY, fAngleZ );
m_fVisibleAngleZ = fAngleZ;
}
void Character::Rotate(float fAngle, BOOL bSetVisibleAngle /* = FALSE */ )
{
Object::Rotate( fAngle, bSetVisibleAngle );
if( bSetVisibleAngle == TRUE )
{
m_fVisibleAngleZ = GetAngle();
}
}
void Character::SetAngle( float fAngle, BOOL bSetVisibleAngle )
{
Object::SetAngle( fAngle, bSetVisibleAngle );
if( bSetVisibleAngle == TRUE )
{
m_fVisibleAngleZ = fAngle;
}
}
//------------------------------------------------------------------------------
/**
원거리 공격
*/
DWORD Character::CreateProjectile(Character *pTarget,int iArrowBone)
{
cProjectileUnit* pProjectile = new cProjectileUnit();
pProjectile->SetLifeTime( 300 );
pProjectile->SetArrowStartPosition( GetArrowBonePos(0) );
if( Character* pTarget = (Character*)GetTargetObject() )
{
pProjectile->SetArrowTargetObjectKey(pTarget->GetObjectKey(), TRUE );
}
else
{
pProjectile->SetArrowTargetPosition( GetArrowBonePos(0) + GetDirection() * 4.0f );
}
pProjectile->SetUnitCode( eProjectile_SRC_ARROW );
pProjectile->CreateTrail( g_ProjectileManagerEx.GetTrailTexture(), 0.04f, 0.8f, 100, 150, 255 );
pProjectile->SetHitData( GetObjectKey(), GetCurrentAttackSerial(), 0, FALSE, 0, FALSE );
g_ProjectileManagerEx.InsertProjectile( pProjectile );
return pProjectile->GetKey();
}
//-------------------------------------------------------------------------------------------
/**
*/
void Character::SetStateTotalInfo( STATE_TOTAL_INFO & rStateTotalInfo )
{
DeleteAllSkillEffect();
for ( int i = 0; i < rStateTotalInfo.m_Count; ++i )
{
STATE_INFO * pStateInfo = &rStateTotalInfo.m_Slot[i];
if (NULL == pStateInfo)
{
ASSERT(0);
continue;
}
SkillScriptInfo * pSkillInfo =
SkillInfoParser::Instance()->GetSkillInfo(pStateInfo->m_SkillCode);
if (!pSkillInfo)
{
ASSERT(0);
continue;
}
BASE_ABILITYINFO * pAbilityInfo =
pSkillInfo->GetAbilityInfoByIndex(pStateInfo->m_byAbilityIndex);
if ( !pAbilityInfo )
{
ASSERT(0);
continue;
}
int remain_time;
#ifdef __NA_0_20080618_STATE_INFO_SIZE_DECREASE
if( pStateInfo->m_wLeavedTime == (WORD)-1 )
remain_time = -1;
else
remain_time = pStateInfo->m_wLeavedTime * SEC_PER_TICK;
#else
remain_time = pStateInfo->m_iLeavedTime * SEC_PER_TICK;
#endif
if( SKILL_EFFECT* pEffect = SKILL_EFFECT::CreateSkillStatusEffect( pAbilityInfo->m_wStateID, pStateInfo->m_SkillCode, remain_time, pAbilityInfo ) )
{
pEffect->CreateEffect( this, 0 );
AddSkillEffect(pEffect);
}
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetCondition(BYTE byCondition)
{
m_byCondition = byCondition;
}
//------------------------------------------------------------------------------
/**
*/
Character::~Character()
{
m_listTargeter.clear();
m_vNotProcessedList.clear();
if( m_hWaterEllipse != INVALID_HANDLE_VALUE )
{
g_pEffectManager->RemoveEffectPtr( m_hWaterEllipse );
m_hWaterEllipse = INVALID_HANDLE_VALUE;
}
// 캐릭터가 사라질때 가지고 있는 액션은 모두 처리 한다.
ProcessAllRemainActionResult();
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::Create( DWORD dwObjectKey, DWORD dwID )
{
if (!Object::Create(dwObjectKey, dwID))
{
return FALSE;
}
////if(m_transFormResourceCode)
//// SetAppearanceKind(APPEARANCEINFO::PLAYERTRANSFORM);
//m_TransformData.m_TransFormType = eTRANSFORM_TYPE_NONE;
//m_TransformData.m_OldTransFormType = m_TransFormType;
m_TransformData.Init();
SetVector(&m_wvOldVisiblePos,0.0f,0.0f,0.0f);
SetAngle(0.0f,TRUE);
m_fVisibleAngleModifier = 0.0f;
m_dwLockedTargetID = 0;
m_bLocked = FALSE;
m_bLockedPosition = FALSE;
SetVector(&m_vNormal,0.0f,0.0f,0.0f);
SetVector(&m_wvInterpolateOffset,0.0f,0.0f,0.0f);
SetVector(&m_vJumpFrom,0.0f,0.0f,0.0f);
m_bJump = FALSE;
m_dwLatestAttack = 0;
m_dwAttackSerial = 1;
m_dwNextAttackSerial = 1;
m_bAttackMove = FALSE;
m_bNextMove = FALSE;
ZeroMemory(&m_vAttackStartPos,sizeof(m_vAttackStartPos));
ZeroMemory(&m_vAttackEndPos,sizeof(m_vAttackEndPos));
m_bMoveState = CMS_RUN;
m_dwHitPause = 0;
m_fVibrateForce = 0.0f;
m_dwHP = 1;
m_iFightingEnergy = 0;
m_iEmoteIcon = 0;
// 사운드
m_iVoiceHandle = -1;
m_iVoiceKind = 0;
EmptyAttackResultList();
m_ActionQueue.empty();
//InitializeState();
PLAYER_ACTION idleaction;
idleaction.ActionID = ACTION_IDLE;
idleaction.IDLE.vCurPos = GetPosition();
SetCurrentAction(&idleaction);
m_SkillEffectArray.clear();
m_vNearPos=c_ZeroVector;
m_dwSpecialMoveCurTime=0;
m_bSpecialMoveMove=FALSE;
m_bSitting=FALSE;
#ifdef _NA_008546_20151029_SITTING_PACKET_DELAY_POSITION_SYNC_BUG
sitting_packet_delay_ = FALSE;
#endif //_NA_008546_20151029_SITTING_PACKET_DELAY_POSITION_SYNC_BUG
m_dwAttackEffectTime=0;
m_fAlpha= 255.0f;
EnableCustomLight( TRUE );
m_bObserverMode = FALSE; // 옵저버 모드
m_dwHideTime = 0;
m_bHide = FALSE;
m_ReflectDamageList.clear();
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
DestroyViceSwordWeaponEffect();
#endif // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
void Character::InitMeshHeight()
{
if( WzBoundingVolume* pBV = GetBoundingVolume() )
{
if (pBV->m_eBvType == BVT_AABB)
{
// 공중에 떠있는 몹들때문에 maxz로 대신 사용
float fHeight = (pBV->m_aabb.m_wvMax.z - pBV->m_aabb.m_wvMin.z);
SetMeshHeight(fHeight);
}
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::Destroy()
{
ReleaseFullsetEffect();
FreeEmoteIcon();
ReleaseMoveTarget();
if (g_pMap && g_pMap->IsLoaded())
{
RemoveObjectToOctree();
}
DeleteAllSkillEffect();
m_listDamageEffectHndl.clear();
Object::Destroy();
ReleaseShieldEffect();
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
DestroyViceSwordWeaponEffect();
cPlayerFPFullEffect::DestroyFPFullEffect();
#endif // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
}
//------------------------------------------------------------------------------
/**
타겟의 위치가 설수 없는 타일일 경우 근처 포지션을 구해 준다.
Todo:vTemp가 갈수 없는 곳일 경우 방향 값을 회전 시키며 구하는 로직이 필요
*/
WzVector Character::GetNearTargetPos(WzVector vSrc)
{
if(g_pSunTerrain&&g_pPathExplorer&&
m_vNearPos==c_ZeroVector)
{
// 이동 가능한 근접 위치 탐색
WzVector target_vector =GetPosition(); //타겟 위치
WzVector direct_vector = vSrc - target_vector; //타겟의 방향
VectorNormalize(&direct_vector, &direct_vector);
WzVector check_vector; //체크 지점
//원형으로 체크 할 때 순서 조절
WzVector modified_dir; // 수정된 방향
static float angle_turn[8] = {0.0f, D3DX_PI*1/4, -D3DX_PI*1/4, D3DX_PI*1/2,
-D3DX_PI*1/2, D3DX_PI*3/4, -D3DX_PI*3/4, D3DX_PI};
for (int index = 0; index < 8; ++index)
{
for (float add_distance = 1.0f; add_distance <= 3.0f; add_distance += 0.5f)
{
// 원형으로 방향 체크
float theta = angle_turn[index];
modified_dir.x = cosf(theta)*direct_vector.x + sinf(theta)*direct_vector.y;
modified_dir.y = -1*sinf(theta)*direct_vector.x + cosf(theta)*direct_vector.y;
modified_dir.z = direct_vector.z;
check_vector = target_vector + (modified_dir * add_distance);
g_pSunTerrain->PathExp_Reset(g_pPathExplorer,&check_vector,-1);
g_pPathExplorer->Stop();
float length = VectorLength(&check_vector);
WzVector long_offset_vector = modified_dir*length*-1;
g_pSunTerrain->PathExp_Thrust(g_pPathExplorer,&long_offset_vector, PTA_NO_WALK);
g_pSunTerrain->PathExp_Progress(g_pPathExplorer,1000000,NULL);
WzVector new_pos_vector = g_pPathExplorer->GetPos();
// 이동 가능한 지역인지 체크
int tile_number = g_pSunTerrain->x_pPathFinder->GetTileToStand(new_pos_vector, NULL, -1.0f, 10.0f );
if (tile_number < 0)
{
continue;
}
if (g_pMap->GetWorldBase()->x_pPathFinder->GetAttribute(tile_number) & PTA_NO_WALK)
{
continue;
}
WzVector length_vector = new_pos_vector - m_vNearPos;
length = VectorLength(&length_vector);
//짧게 덜컥 거리는거 방지
if(length < 0.3f)
{
continue;
}
m_vNearPos = new_pos_vector;
return m_vNearPos;
}
}
}
return m_vNearPos;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::Process(DWORD dwTick)
{
Object::Process(dwTick);
DWORD processTick;
#ifdef _YJ_MOD_UNIT_PROCESS
if( IsEnableDisplay() )
#endif //_YJ_MOD_UNIT_PROCESS
{
SUNPROCESSPROFILE_BEGIN(_T("ProcessCharacterEtc"));
ProcessSkillEffect(dwTick);
ProcessEmoteDelay(dwTick);
ProcessRushClone();
if (m_iAttackStandTime)
{
m_iAttackStandTime -= dwTick;
if (m_iAttackStandTime < 0)
{
m_iAttackStandTime = 0;
}
}
if(m_dwHideTime>dwTick)
{
m_dwHideTime-=dwTick;
m_bHide=TRUE;
}
else
{
if(m_bHide==TRUE)
{
SetFadeIn(1000);
}
m_bHide=FALSE;
m_dwHideTime=0;
}
SUNPROCESSPROFILE_END(_T("ProcessCharacterEtc"));
} //if(GetVisible())
if(IsMove()) //움직이는 놈들은 갱신 해준다.
m_vNearPos=c_ZeroVector;
m_dwAttackEffectTime-= dwTick;
m_dwAttackEffectTime=max(m_dwAttackEffectTime,0);
if (m_bFade)
{
m_iFadeCurDelay += dwTick;
if (m_iFadeCurDelay >= m_iFadeTotDelay)
{
m_bFade = FALSE;
}
}
float fProcessMultiplier = GetProcessMultiplier();
// 캐스팅 오차를 줄이자
if (fProcessMultiplier <= 1.0f)
{
processTick = dwTick;
}
else
{
processTick = (DWORD)((float)dwTick * GetProcessMultiplier());
}
#ifdef _YJ_MOD_UNIT_PROCESS
if( IsEnableDisplay() )
{
SUNPROCESSPROFILE_BEGIN(_T("ProcessCharacterState"));
StateProcess( g_CurTime, processTick );
SUNPROCESSPROFILE_END(_T("ProcessCharacterState"));
}
else
{
SUNPROCESSPROFILE_BEGIN(_T("CharacterOnlyMove"));
if(ACTION_MOVE == GetCurrentAction()->ActionID || ACTION_ATTACK == GetCurrentAction()->ActionID)
StateProcess( g_CurTime, processTick );
else
ProcessInterpolation(dwTick);
SUNPROCESSPROFILE_END(_T("CharacterOnlyMove"));
}
#else
StateProcess( g_CurTime, processTick );
#endif //_YJ_MOD_UNIT_PROCESS
ProcessInterpolationAttachment( dwTick );
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
void Character::ProcessTextFade( DWORD dwTick )
{
return;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::MakePathPacket( MSG_CG_SYNC_MOVE_SYN *pPacket)
{
if( pPacket == NULL )
{
return FALSE;
}
if (!m_pPathExplorer->IsMoving())
{
return FALSE;
}
WzVector vCurPos = m_pPathExplorer->GetPos();
WzVector vTarget = m_pPathExplorer->GetTargetPos();
pPacket->m_byCategory = CG_SYNC;
pPacket->m_byProtocol = CG_SYNC_MOVE_SYN;
// 이동 데이터 얻기
#if WZENGINEVER >= 470
int iPath[_MAX_PATHROUTE_SIZE];
pPacket->m_byNumRoute = m_pPathExplorer->GetTileRoute( iPath, _MAX_PATHROUTE_SIZE );
for (int a = 0; a < pPacket->m_byNumRoute; a++)
{
pPacket->m_iRoute[a] = iPath[a];
}
#else
// 임시로 예외처리를 해 두었으나, 향후 제거되어야 할 코드
int iPath[MAX_PATH_ROUTE > _MAX_PATHROUTE_SIZE ? MAX_PATH_ROUTE : _MAX_PATHROUTE_SIZE];
pPacket->m_byNumRoute = m_pPathExplorer->GetTileRoute( iPath );
for (int a = 0; a < pPacket->m_byNumRoute && a < _MAX_PATHROUTE_SIZE; a++)
{
pPacket->m_iRoute[a] = iPath[a];
}
#endif
pPacket->wvCurPos = vCurPos;
pPacket->wvDestPos = vTarget;
m_vLastSend = vTarget;
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::MakeTargetPathPacket( MSG_CG_SYNC_TARGET_MOVE_SYN *pPacket )
{
if( pPacket == NULL )
{
return FALSE;
}
if (!m_pPathExplorer->IsMoving())
{
return FALSE;
}
WzVector vCurPos = m_pPathExplorer->GetPos();
WzVector vTarget = m_pPathExplorer->GetTargetPos();
pPacket->m_byCategory = CG_SYNC;
pPacket->m_byProtocol = CG_SYNC_TARGET_MOVE_SYN;
// 이동 데이터 얻기
#if WZENGINEVER >= 470
int iPath[_MAX_PATHROUTE_SIZE];
pPacket->m_byNumRoute = m_pPathExplorer->GetTileRoute( iPath, _MAX_PATHROUTE_SIZE );
for (int a = 0; a < (int)(pPacket->m_byNumRoute); a++)
{
pPacket->m_iRoute[a] = iPath[a];
}
#else
// 임시로 예외처리를 해 두었으나, 향후 제거되어야 할 코드
int iPath[MAX_PATH_ROUTE > _MAX_PATHROUTE_SIZE ? MAX_PATH_ROUTE : _MAX_PATHROUTE_SIZE];
pPacket->m_byNumRoute = m_pPathExplorer->GetTileRoute( iPath );
for (int a = 0; a < (int)(pPacket->m_byNumRoute) && a < _MAX_PATHROUTE_SIZE; a++)
{
pPacket->m_iRoute[a] = iPath[a];
}
#endif
pPacket->wvCurPos = vCurPos;
pPacket->wvDestPos = vTarget;
m_vLastSend = vTarget;
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
void Character::StopMove( void )
{
if( m_pPathExplorer->IsMoving() )
{
m_pPathExplorer->Stop();
}
}
//------------------------------------------------------------------------------
BOOL Character::IsMyHero()
{
if( g_pHero != NULL )
{
if( g_pHero->GetObjectKey() == GetObjectKey() )
return TRUE;
}
return FALSE;
}
//------------------------------------------------------------------------------
BOOL Character::IsPartyMember()
{
return GlobalFunc::IsParty( GetObjectKey() );
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::IsMoving( void )
{
return m_pPathExplorer->IsMoving();
}
//------------------------------------------------------------------------------
/**
*/
inline BOOL Outside_Plane_AABB( WzPlane *pwp, BvAABB *pbaabb)
{
const WzVector* pwvSrcMin = &pbaabb->m_wvMin;
const WzVector* pwvSrcMax = &pbaabb->m_wvMax;
static WzVector wvMin;
wvMin.x = ( pwp->m_wvNormal.x < 0.0f) ? pwvSrcMax->x : pwvSrcMin->x;
wvMin.y = ( pwp->m_wvNormal.y < 0.0f) ? pwvSrcMax->y : pwvSrcMin->y;
wvMin.z = ( pwp->m_wvNormal.z < 0.0f) ? pwvSrcMax->z : pwvSrcMin->z;
// 면과의 관계 검사
if( Distance_Plane_Vertex( pwp, wvMin) > 0.0f)
{
return TRUE;
}
return FALSE;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::Render( void )
{
// GetTerrainMesh가 너무느려서 Debug에선 사용하지 않는다.
WzBoundingVolume *pVolume = GetBoundingVolume();
if (pVolume && !m_bNoCull)
{
WzBoundingVolume bvVolume = *pVolume;
St_Camera *pCameraInfo = g_pSunRenderer->GetCameraInfo();
if (pCameraInfo)
{
WzPlane nearplane = pCameraInfo->m_wfFrustum.m_wpPlanes[FP_NEAR];
nearplane.m_wvNormal = -nearplane.m_wvNormal;
WzVector vPos =
(pCameraInfo->m_wvDir * pCameraInfo->m_fNear) + pCameraInfo->m_wvFrom;
if (Contain_Bv_Vertex(&bvVolume,vPos))
{
return FALSE;
}
}
}
// 이부분은 정확한 의미를 파악해서 작성하자
// 내가 보기엔 선택 / 피킹시에는 알파를 적용 안할려고 그런것같은데..
BOOL bBright = FALSE;
BOOL bRet = FALSE;
if (g_HeroInput.GetPickedObjectKey() == GetObjectKey())
{
bBright = TRUE;
}
if (g_HeroInput.GetCurrentTarget() == GetObjectKey())
{
bBright = TRUE;
}
SUNPROFILE_BEGIN( _T("CharApplyTerrainColor") );
ApplyTerrainColor(TRUE);
SUNPROFILE_END( _T("CharApplyTerrainColor") );
//현재 히어로만 처리 된다.
if (m_bCameraAlpha)
{
WzColor color = GetColor();
int iAlpha=(int)m_fAlpha;
SetColor(Red_WzColor(color),Green_WzColor(color),Blue_WzColor(color),iAlpha);
}
if(m_bHide)
{
WzColor color = GetColor();
SetColor(Red_WzColor(color),Green_WzColor(color),Blue_WzColor(color),0);
}
WzColor oldcolor = g_pSunRenderer->GetAmbientColor();
if (g_pMap)
{
if (g_pMap->IsApplyAnotherLight())
{
g_pSunRenderer->SetColor(g_pMap->GetCharacterAmbientColor(),WRIC_AMBIENT);
}
}
bool IsHero = false;
if(g_pHero)
{
if(GetObjectKey() == g_pHero->GetObjectKey())
{
IsHero = true;
}
}
if(IsHero && m_fAlpha <= 0.0f) // 알파값이 0.0보다 작고 Hero이면 그리지 않는다.
{
_asm nop;
}
else
{
StartExtraEffect();
bRet = Object::Render();
EndExtraEffect();
}
if (m_pEmoteDraw)
{
WzVector vPos = GetVisiblePos();
vPos.z += GetMeshHeight() + 0.2f;
m_pEmoteDraw->SetPosition(vPos,FALSE);
g_pSunRenderer->AnimateUnit(m_pEmoteDraw);
g_pSunRenderer->RenderUnit(m_pEmoteDraw);
}
g_pSunRenderer->SetColor(oldcolor,WRIC_AMBIENT);
return bRet;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::RenderOutline( const WzColor& color , float fThickness )
{
// GetTerrainMesh가 너무느려서 Debug에선 사용하지 않는다.
if ( m_bFade || m_bHide || m_bObserverMode )
{
return FALSE;
}
if ( WzBoundingVolume* pVolume = GetBoundingVolume() )
{
WzBoundingVolume bvVolume = *pVolume;
if( St_Camera* pCameraInfo = g_pSunRenderer->GetCameraInfo() )
{
WzVector vPos = (pCameraInfo->m_wvDir * pCameraInfo->m_fNear) + pCameraInfo->m_wvFrom;
GlobalFunc::ShrinkBoundingVolume(&bvVolume,0.6f);
if ( Contain_Bv_Vertex( &bvVolume, vPos) )
{
return TRUE;
}
}
}
return Object::RenderOutline(color,fThickness);
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetFadeIn(int iDelay)
{
if (iDelay >= 0)
{
m_iFadeCurDelay = 0;
m_iFadeTotDelay = iDelay;
m_bFade = TRUE;
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetAttackRange( float fRange )
{
assert(fRange >= 0.0f);
m_fAttackRange = fRange;
}
//------------------------------------------------------------------------------
/**
*/
float Character::ProcessAnimation(DWORD dwTick,WzEvent *pEvent,BOOL bIgnoreEvent)
{
CWzUnitDraw *pDraw = GetBasePart();
if (pDraw)
{
// 캐릭터는 VisibleAngleZ를 사용
pDraw->SetRotation( GetAngleX() ,0.0f, m_fVisibleAngleZ, FALSE);
}
float fProgressRate;
if (m_pEmoteDraw)
{
g_pSunRenderer->ProgressUnitFrame(m_pEmoteDraw,(float)dwTick);
}
if( m_dwHitPause == 0 )
{
fProgressRate = Object::ProcessAnimation(dwTick,pEvent,bIgnoreEvent);
}
else
{
if (m_dwHitPause <= dwTick)
{
m_dwHitPause = 0;
}
else
{
m_dwHitPause -= dwTick;
}
fProgressRate = Object::ProcessAnimation(1,pEvent,bIgnoreEvent);
}
return fProgressRate;
}
//------------------------------------------------------------------------------
/**
*/
void Character::LockOn(DWORD dwObjectKey)
{
// 나중에 변수를 하나로!
if (dwObjectKey)
{
m_dwLockedTargetID = dwObjectKey;
m_bLocked = TRUE;
}
else
{
m_dwLockedTargetID = 0;
m_bLocked = FALSE;
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::LockOnPosition(BOOL bFlag,WzVector vVector)
{
m_bLockedPosition = bFlag;
if (m_bLockedPosition)
{
m_vLockedPosition = vVector;
}
}
//------------------------------------------------------------------------------
/**
*/
DWORD Character::GetLockedTarget()
{
return m_dwLockedTargetID;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::UseSkill( int SkillID )
{
DWORD dwObjectType = 0;
BIT_ADD(dwObjectType,GetSCObject().GetObjectType());
StateBase* pSkill = g_SkillStateFactory.CreateState( SkillID, dwObjectType );
if ( pSkill == NULL )
{
return FALSE;
}
SetNextSkillState(pSkill);
SetNextState(STATE::SKILL,g_CurTime);
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
void Character::UpdateOctree()
{
UpdateOctree( FALSE );
}
//------------------------------------------------------------------------------
/**
*/
void Character::UpdateOctree( BOOL bForce )
{
if( m_wvOldVisiblePos != GetVisiblePos() ||
GetOctIndex() == INVALID_WZOCTINDEX ||
bForce )
{
m_wvOldVisiblePos = GetVisiblePos();
if (g_pMap->IsLoaded())
{
AddObjectToOctree();
}
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetVisibleAngleModifer(float fAngle)
{
ClampAngle(&fAngle);
m_fVisibleAngleModifier = fAngle;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::ProcessInterpolation(DWORD dwTick,float fInterpolateRatio)
{
WzVector vTempPos;
#ifdef _PERF_DEBUG
vTempPos = m_pPathExplorer->GetPos();
#else
assert(m_pPathExplorer->GetVisiblePos().x == m_pPathExplorer->GetPos().x);
assert(m_pPathExplorer->GetVisiblePos().y == m_pPathExplorer->GetPos().y);
vTempPos = m_pPathExplorer->GetVisiblePos() + m_wvInterpolateOffset;
const float INTERPOLATE_EPSILON = 1.0e-04f;
const float INTERPOLATE_RATIO = 0.92f;
if (fabs(m_wvInterpolateOffset.x) < INTERPOLATE_EPSILON)
{
m_wvInterpolateOffset.x = 0.0f;
}
else
{
m_wvInterpolateOffset.x *= fInterpolateRatio;
}
if (fabs(m_wvInterpolateOffset.y) < INTERPOLATE_EPSILON)
{
m_wvInterpolateOffset.y = 0.0f;
}
else
{
m_wvInterpolateOffset.y *= fInterpolateRatio;
}
if (fabs(m_wvInterpolateOffset.z) < INTERPOLATE_EPSILON)
{
m_wvInterpolateOffset.z = 0.0f;
}
else
{
m_wvInterpolateOffset.z *= fInterpolateRatio;
}
#endif // _PERF_DEBUG
if( IsFreeMove() == FALSE )
{
// 지형 높이에 상관 없이 정해진 높이 값으로 움직인다.
SetVisiblePos( vTempPos );
// m_wvVisiblePos = vTempPos;
}
const float fVibrateSpeed = 0.0150f;
const float fEpsilon = 0.00005f;
const float fRate = -0.90f;
WzVector vRealVisiblePos = GetVisiblePos();
// 떨기
if (m_bVibrateMove)
{
if (m_fVibrateForce != 0.0f)
{
if ( m_fVibrateCurrent < m_fVibrateForce)
{
m_fVibrateCurrent += (fVibrateSpeed * dwTick);
if (m_fVibrateCurrent >= m_fVibrateForce)
{
m_fVibrateCurrent = m_fVibrateForce;
m_fVibrateForce *= fRate;
}
}
else
{
m_fVibrateCurrent -= (fVibrateSpeed * dwTick);
if (m_fVibrateCurrent <= m_fVibrateForce)
{
m_fVibrateCurrent = m_fVibrateForce;
m_fVibrateForce *= fRate;
}
}
if (fabs(m_fVibrateForce) <= fEpsilon)
{
m_fVibrateForce = 0.0f;
m_bVibrateMove = FALSE;
m_fVibrateCurrent = 0.0f;
}
vRealVisiblePos += m_vVibrateDirection * m_fVibrateCurrent;
}
else
{
m_bVibrateMove = FALSE;
}
}
// 띄우기
vRealVisiblePos.z += m_fHeight;
GetBasePart()->SetPosition(vRealVisiblePos);
// renderpart의 형태에 따라 octindex 변경
UpdateOctree();
const float fTurnSpeed = WZ_PI / 4.0f; // 15도
float fDestViewAngle = GetAngle() + m_fVisibleAngleModifier;
if (fDestViewAngle >= WZ_PI * 2.0f)
{
fDestViewAngle -= WZ_PI * 2.0f;
}
else if (fDestViewAngle < 0.0f)
{
fDestViewAngle += WZ_PI * 2.0f;
}
ClampAngle(&fDestViewAngle);
if (fDestViewAngle != m_fVisibleAngleZ)
{
// 각도를 더하는게 빠른지 빼는게 빠른지 판단한다.
float fLeftDiff; // 이쪽이 더하기
float fRightDiff; // 빼기
if ( fDestViewAngle > m_fVisibleAngleZ)
{
fLeftDiff = fDestViewAngle - m_fVisibleAngleZ;
}
else
{
fLeftDiff = fDestViewAngle - m_fVisibleAngleZ + WZ_PI * 2.0f;
}
// 반대쪽 회전각도와의 합은 360도
fRightDiff = WZ_PI * 2.0f - fLeftDiff;
// 강제 방향조정.
switch(m_ForceTurn)
{
case FORCE_TURN_RIGHT:
fLeftDiff = 99999.9f;
break;
case FORCE_TURN_LEFT:
fRightDiff = 99999.9f;
break;
}
if ( fLeftDiff <= fRightDiff )
{
if (fLeftDiff > fTurnSpeed)
{
m_fVisibleAngleZ += fTurnSpeed;
ClampAngle(&m_fVisibleAngleZ);
}
else
{
m_fVisibleAngleZ = fDestViewAngle;
m_ForceTurn = FORCE_TURN_NONE;
}
}
else
{
if (fRightDiff > fTurnSpeed)
{
m_fVisibleAngleZ -= fTurnSpeed;
ClampAngle(&m_fVisibleAngleZ);
}
else
{
m_fVisibleAngleZ = fDestViewAngle;
m_ForceTurn = FORCE_TURN_NONE;
}
}
}
if (m_fSpinForce > 0.0f)
{
m_fSpinForce *= 0.8f;
if (m_fSpinForce <= 0.05f)
{
m_fSpinForce = 0.0f;
}
m_fVisibleAngleZ += m_fSpinForce;
ClampAngle(&m_fVisibleAngleZ);
}
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetInterpolatePosition()
{
if (GENERALPARAM->IsInterpolatePosition())
{
if (m_pPathExplorer->GetTerrainMesh() != -1)
{
WzVector vCurrentPos = m_pPathExplorer->GetVisiblePos();
m_wvInterpolateOffset = GetVisiblePos() - vCurrentPos;
//보간 거리가 3미터가 넘어갈때 리셋한다
if( VectorLength( &m_wvInterpolateOffset ) > 3.0f )
{
SetVector(&m_wvInterpolateOffset,0.f,0.f,0.f);
}
}
}
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::IsJumping()
{
return m_bJump;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetJumpFlag(BOOL bFlag)
{
m_bJump = bFlag;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetJumpInfo(WzVector *pvJumpFrom,WzVector *pvJumpTo)
{
m_vJumpFrom = *pvJumpFrom;
m_vJumpTo = *pvJumpTo;
WzVector vDistance;
vDistance = m_vJumpTo - m_vJumpFrom;
m_fJumpDistance = VectorLength(&vDistance);
}
//------------------------------------------------------------------------------
/**
*/
void Character::GetJumpInfo(WzVector *pvJumpFrom,WzVector *pvJumpTo,float *pDistance)
{
*pvJumpFrom = m_vJumpFrom;
*pvJumpTo = m_vJumpTo;
*pDistance = m_fJumpDistance;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetHP( DWORD dwHP )
{
m_dwHP = dwHP;
}
void Character::SetHPInfo(HPINFO *pInfo)
{
// 내용이 없는게 정상
return;
}
//------------------------------------------------------------------------------
/**
*/
DWORD Character::GetHP( void )
{
return m_dwHP;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetMP( DWORD dwMP )
{
m_dwMP = dwMP;
}
//------------------------------------------------------------------------------
/**
*/
DWORD Character::GetMP( void )
{
return m_dwMP;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetReserveHP( DWORD val )
{
m_reserveHP = val;
}
//------------------------------------------------------------------------------
/**
*/
DWORD Character::GetReserveHP( void )
{
return m_reserveHP;
}
//------------------------------------------------------------------------------
/**
*/
DWORD Character::GetLatestAttack()
{
return m_dwLatestAttack;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetLatestAttack(DWORD dwTimeSerial)
{
if (dwTimeSerial > m_dwLatestAttack)
{
m_dwLatestAttack = dwTimeSerial;
}
}
DWORD Character::GetLatestQueueAttack()
{
return m_dwLatestQueueAttack;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetLatestQueueAttack(DWORD dwTimeSerial)
{
if (dwTimeSerial > m_dwLatestQueueAttack)
{
m_dwLatestQueueAttack = dwTimeSerial;
}
}
//------------------------------------------------------------------------------
/**
*/
DWORD Character::GetCurrentAttackSerial()
{
return m_dwAttackSerial;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetCurrentAttackSerial(DWORD dwAttackSerial)
{
m_dwAttackSerial = dwAttackSerial;
}
//------------------------------------------------------------------------------
/**
*/
DWORD Character::GetNextAttackSerial()
{
return m_dwNextAttackSerial;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetNextAttackSerial(DWORD dwSerial)
{
m_dwNextAttackSerial = dwSerial;
}
//------------------------------------------------------------------------------
/**
*/
void Character::AddNextAttackSerial()
{
m_dwNextAttackSerial++;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetTargetID(DWORD dwObjectKey)
{
m_dwTargetObjectKey = dwObjectKey;
}
//------------------------------------------------------------------------------
/**
*/
Object* Character::GetTargetObject()
{
return g_ObjectManager.GetObject(m_dwTargetObjectKey);
}
//------------------------------------------------------------------------------
/**
공격 결과를 실행 하기 위해
*/
int Character::AddAttackResult(ATTACK_RESULT *pattresult)
{
m_AttackResultList.push_back(*pattresult);
return m_AttackResultList.size();
}
//------------------------------------------------------------------------------
/**
*/
int Character::GetAttackResultListSize()
{
return m_AttackResultList.size();
}
//------------------------------------------------------------------------------
/**
*/
void Character::EmptyAttackResultList()
{
m_AttackResultList.clear();
}
void Character::_ProcessRemainAttackResult( DWORD attack_serail, BOOL is_right, BOOL is_additional_effect )
{
ATTACK_RESULT_LIST::iterator itr(m_AttackResultList.begin());
while(itr != m_AttackResultList.end())
{
ATTACK_RESULT* attack_result = &(*itr);
ATTACK_RESULT_LIST::iterator tempitr = itr;
++itr;
Character* target_character = NULL;
if (attack_result != NULL)
{
target_character = g_ObjectManager.GetCharacter(attack_result->GetTargetData().GetTargetObjectKey() );
}
// 자기 어택씨리얼보다 작은거는 무조건 처리한다
if (attack_result->GetAttackSerial() < attack_serail)
{
if (target_character != NULL)
{
target_character->ProcessReflectDamage();
}
_ProcessAttackResult( attack_result, is_right, is_additional_effect);
m_AttackResultList.erase(tempitr);
}
}
}
BOOL Character::ProcessAttackResult_Group(DWORD dwAttackSerial, BOOL bRight, BOOL bAddtionalEffect )
{
_ProcessRemainAttackResult( dwAttackSerial, bRight, bAddtionalEffect );
BOOL bResult = FALSE;
BOOL first_group_start = TRUE;
DWORD current_group_id = GROUP_ID_NONE;//그룹 없음 이다.0번은
ATTACK_RESULT_LIST::iterator itr(m_AttackResultList.begin());
while(itr != m_AttackResultList.end())
{
ATTACK_RESULT* attack_result = &(*itr);
ATTACK_RESULT_LIST::iterator tempitr = itr;
++itr;
// 찾았으면!
if (tempitr->GetAttackSerial() == dwAttackSerial)
{
// AttackSerial이 같고 히트수가 여러개 일경우에 동일한 AttackSeral에 그룹아이디가 1,2,3,4.. 순으로 등록되어있다
// 첫번째 히트에 그룹1, 두번째 히트에 그룹2를 처리하기 위한 코드
if( attack_result->GetGroupID() != GROUP_ID_NONE )
{
if( first_group_start )
{
current_group_id = attack_result->GetGroupID(); // 이번에 처리할 그룹아이디를 구하는과정
first_group_start = FALSE;
}
// 그룹 삭제에서 그룹 아이디가 없다면 삭제 안된다.
if( attack_result->GetGroupID() == current_group_id )
{
if( Character* target_character = g_ObjectManager.GetCharacter(attack_result->GetTargetData().GetTargetObjectKey()) )
{
target_character->ProcessReflectDamage();
}
bResult = TRUE;
_ProcessAttackResult( attack_result, bRight, bAddtionalEffect );
m_AttackResultList.erase(tempitr);
}
}
}
}
//! 반사계열 모두 처리 처리
ProcessReflectDamage();
return bResult;
}
BOOL Character::ProcessAttackResult_Target(DWORD dwAttackSerial, DWORD target_object_key, BOOL bRight, BOOL bAddtionalEffect )
{
_ProcessRemainAttackResult( dwAttackSerial, bRight, bAddtionalEffect );
if( target_object_key == 0xFFFFFFFF )
return FALSE;
BOOL first_group_start = TRUE;
DWORD current_group_id = GROUP_ID_NONE;//그룹 없음 이다.0번은
ATTACK_RESULT_LIST::iterator itr(m_AttackResultList.begin());
while(itr != m_AttackResultList.end())
{
ATTACK_RESULT* attack_result = &(*itr);
ATTACK_RESULT_LIST::iterator tempitr = itr;
++itr;
// 찾았으면!
if (attack_result->GetAttackSerial() == dwAttackSerial)
{
if(attack_result->GetTargetData().GetTargetObjectKey() == target_object_key )
{
if( Character* target_character = g_ObjectManager.GetCharacter(attack_result->GetTargetData().GetTargetObjectKey()) )
{
target_character->ProcessReflectDamage();
}
m_AttackResultList.erase(tempitr);
break;
}
}
}
//! 반사계열 모두 처리 처리
ProcessReflectDamage();
return FALSE;
}
BOOL Character::ProcessAttackResult(DWORD dwAttackSerial, BOOL bAll, BOOL bRight, BOOL bAddtionalEffect )
{
_ProcessRemainAttackResult( dwAttackSerial, bRight, bAddtionalEffect );
ATTACK_RESULT_LIST::iterator itr(m_AttackResultList.begin());
while(itr != m_AttackResultList.end())
{
ATTACK_RESULT* attack_result = &(*itr);
ATTACK_RESULT_LIST::iterator tempitr = itr;
++itr;
// 찾았으면!
if (attack_result->GetAttackSerial() == dwAttackSerial)
{
if( Character* target_character = g_ObjectManager.GetCharacter(attack_result->GetTargetData().GetTargetObjectKey()) )
{
target_character->ProcessReflectDamage();
}
_ProcessAttackResult( attack_result, bRight, bAddtionalEffect);
m_AttackResultList.erase(tempitr);
if ( bAll == FALSE ) //모두 지울게 아니라면 리턴
{
ProcessReflectDamage();
return TRUE;
}
}
}
//! 반사계열 모두 처리 처리
ProcessReflectDamage();
return FALSE;
}
//------------------------------------------------------------------------------
void Character::ProcessReflectDamage()
{
ATTACK_RESULT_LIST::iterator begin = m_ReflectDamageList.begin();
ATTACK_RESULT_LIST::iterator end = m_ReflectDamageList.end();
for (; begin != end; ++begin)
{
_ProcessAttackResult(&(*begin));
}
m_ReflectDamageList.clear();
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::_ProcessAttackResult(ATTACK_RESULT *pResult,BOOL bRight,BOOL bAddtionalEffect)
{
if ( !g_pHero )
{
return TRUE;
}
if ( Character* target_character = (Character *)g_ObjectManager.GetObject(pResult->GetTargetData().GetTargetObjectKey()) )
{
BOOL bShowDamageMesh = FALSE;
switch (GAMEOPTION->GetDamageOutput())
{
case eODO_NONE:
break;
case eODO_SHOWMINE:
{
if ((g_pHero->GetObjectKey() == GetObjectKey()) ||
(g_pHero->GetObjectKey() == target_character->GetObjectKey()))
{
bShowDamageMesh = TRUE;
}
else if (target_character->IsKindOfObject(MONSTER_OBJECT) == TRUE)
{
Monster* monster = static_cast<Monster*>(target_character);
if (monster != NULL)
{
if ((monster->GetMonsterInfo()->m_byGrade == eNPC_FRIEND_MAPOBJECT_NPC) ||
(monster->GetMonsterInfo()->m_byGrade == eNPC_FRIEND_MONSTER))
{
bShowDamageMesh = TRUE;
}
}
}
else if ((target_character->IsKindOfObject(NPC_OBJECT) == TRUE) &&
(target_character->IsKindOfObject(MONSTER_OBJECT) == FALSE))
{
NPC* npc = static_cast<NPC*>(target_character);
if (npc != NULL)
{
if (npc->GetExtraInfo()->m_eNPCTYPE == eNPC_TYPE_PROTECTS)
{
bShowDamageMesh = TRUE;
}
}
}
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
// 나만의 옵션에서 소환수의 의한 표시를 보여 줄 수 있도록 한다.
if ( g_pHero && g_pHero->FindSummon(this->GetObjectKey()) == TRUE)
{
bShowDamageMesh = TRUE;
}
#endif // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
}
break;
case eODO_SHOWALL:
{
bShowDamageMesh = TRUE;
}
break;
}
#ifdef _NA_007113_20140324_SHADOW_SKILL_BALLANCE_RENEWAL
if (target_character && target_character->GetHideSkill() == HIDE_SKILL_INFO::ALL_HIDE)
{
// 하이드 상태면 데미지 수치 안띄움
bShowDamageMesh = FALSE;
}
#endif //_NA_007113_20140324_SHADOW_SKILL_BALLANCE_RENEWAL
// 실질적 체력 처리
if ( pResult->GetTimeSerial() >= target_character->GetLatestAttack() )
{
// 미스가 난건 등록 안한다!
if ( pResult->GetTargetData().IsMiss() == FALSE || pResult->GetTargetData().IsForceSetLastestAttack() == TRUE )
{
target_character->SetLatestAttack( pResult->GetTimeSerial());
}
// 힐은 HP 설정을 여기서 하지않음
if ( pResult->GetTargetData().IsHeal() == FALSE )
{
// 피까고
if ( pResult->GetTargetData().IsNoDamage() == false )
{
if ((pResult->GetTargetData().IsHeal() == FALSE) &&
(pResult->GetTargetData().IsLive() > 0) &&
//(pChr->IsKindOfObject(MONSTER_OBJECT) == TRUE) &&
(target_character->GetHP() == 0))
{
//GlobalFunc::OutputMsg_Error(eOUTPUT_MSG_CHAT, "hp 에러! 죽었다 살아남");
//WRITELOG(eLOG_LEVEL_ERR, c_wOUTPUT_LOG_SYSCHAT, "hp 에러! 죽었다 살아남");
}
else
{
if( pResult->GetTargetData().GetTargetHP() == 0 )
{
target_character->SetDeathSkillCode( pResult->GetSkillCode() );
}
target_character->SetHP(pResult->GetTargetData().GetTargetHP() );
#ifdef _NA_006638_20120415_ADD_SHIELD_INFO_IN_TARGET_INFO
target_character->SetSD(pResult->GetTargetData().GetTargetSD());
#endif //_NA_006638_20120415_ADD_SHIELD_INFO_IN_TARGET_INFO
}
}
}
}
// 비주얼적인 처리
if (pResult->GetTargetData().IsNoDamage() )
{
bShowDamageMesh = FALSE;
}
if (bShowDamageMesh && pResult->GetTargetData().IsHeal() == FALSE )
{
//공격자는 플레이어.주인공.플레이어몬스터일경우
if(IsKindOfObject(PLAYER_OBJECT) || IsKindOfObject(SSQMONSTER_OBJECT))
{
//피격자는 쉴드버프가 있을때 필드이펙트를 터뜨린다(무조건)
//자해공격:공격자와 데미지받는사람이 같을경우는 제외
if(target_character->GetObjectKey()!=GetObjectKey() && target_character->IsShield())
{
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("A671"),
target_character->GetBonePos(target_character->GetBoneIndex(eSKILLEFFECT_POS_BODY)),pResult->GetTargetData().GetTargetObjectKey());
}
}
}
// 미스난 공격은 Miss만 띄우고 끝!
if (pResult->GetTargetData().IsMiss())
{
if (!pResult->GetTargetData().IsNoDamage())
{
target_character->OnMiss(bShowDamageMesh);
}
//원하는 타수에 빼기 위해 기본은 true이다.
if(bAddtionalEffect)
{
DWORD TargetAdditionalEffect = pResult->GetTargetData().GetAdditionalEffect();
// 큐행동에 관련된것을 따로 씨리얼을 세팅한다.
if (( TargetAdditionalEffect & ATTACK_ADDITIONAL_EFFECT_KNOCKBACK)
|| (TargetAdditionalEffect & ATTACK_ADDITIONAL_EFFECT_AIR)
|| (TargetAdditionalEffect & ATTACK_ADDITIONAL_EFFECT_DOWN)
|| (TargetAdditionalEffect & ATTACK_ADDITIONAL_EFFECT_KNOCKBACK2)
|| (TargetAdditionalEffect & ATTACK_ADDITIONAL_EFFECT_KNOCKBACK3)
)
{
target_character->SetLatestQueueAttack(pResult->GetTimeSerial());
}
}
return TRUE;
}
// 적대적결과 일때는 맞는 애니메이션을!
if (!pResult->GetTargetData().IsHeal())
{
if (!pResult->GetTargetData().IsNoDamage() )
{
DAMAGE_PRAM DamageParam(pResult,bRight,GetObjectKey());
target_character->OnDamage(DamageParam);
OnAttack(pResult->GetSkillCode());
}
//원하는 타수에 빼기 위해 기본은 true이다.
if(bAddtionalEffect)
{
DWORD TargetAdditionalEffect = pResult->GetTargetData().GetAdditionalEffect();
// 큐행동에 관련된것을 따로 씨리얼을 세팅한다.
if (( TargetAdditionalEffect & ATTACK_ADDITIONAL_EFFECT_KNOCKBACK)
|| (TargetAdditionalEffect & ATTACK_ADDITIONAL_EFFECT_AIR)
|| (TargetAdditionalEffect & ATTACK_ADDITIONAL_EFFECT_DOWN)
|| (TargetAdditionalEffect & ATTACK_ADDITIONAL_EFFECT_KNOCKBACK2)
|| (TargetAdditionalEffect & ATTACK_ADDITIONAL_EFFECT_KNOCKBACK3)
)
{
target_character->SetLatestQueueAttack(pResult->GetTimeSerial());
}
}
}
BOOL bCritical = pResult->GetTargetData().CheckAdditionalEffect(ATTACK_ADDITIONAL_EFFECT_CRITICAL) ? TRUE : FALSE;
BOOL bDoubleDamage = pResult->GetTargetData().CheckAdditionalEffect(ATTACK_ADDITIONAL_EFFECT_DOUBLE) ? TRUE : FALSE;
WzColor damagecolor;
eDAMAGEPOPUP_KIND eKind;
float fMultiplier = 1.0f;
if (target_character->IsKindOfObject(MONSTER_OBJECT))
{
if (!pResult->GetTargetData().IsHeal() )
{
if (GetObjectKey() == g_pHero->GetObjectKey())
{
damagecolor = c_Hero2MonsterHPDamageColor;
}
else
{
damagecolor = c_MonsterHPDamageColor;
}
eKind = eDAMAGEPOPUP_ENEMYHPDAMAGE;
}
else
{
damagecolor = c_MonsterHPHealColor;
eKind = eDAMAGEPOPUP_HEAL;
}
}
else
{
if (!pResult->GetTargetData().IsHeal() )
{
if (target_character->GetObjectKey() == g_pHero->GetObjectKey())
{
damagecolor = c_HeroHPDamageColor;
fMultiplier = 0.9f;
}
else
{
damagecolor = c_PlayerHPDamageColor;
}
eKind = eDAMAGEPOPUP_PLAYERHPDAMAGE;
}
else
{
damagecolor = c_PlayerHPHealColor;
eKind = eDAMAGEPOPUP_HEAL;
}
}
if (!pResult->GetTargetData().IsNoDamage())
{
if (bShowDamageMesh)
{
//콤보카운트가 있을때
if (pResult->GetTargetData().GetComboCount() != 0)
{
fMultiplier += (pResult->GetTargetData().GetComboCount() * 0.3f);
}
target_character->CreatePopupMesh( pResult->GetSkillCode(), pResult->GetTargetData().GetDamage(), eKind, damagecolor,bCritical, bDoubleDamage, fMultiplier, FALSE);
}
}
else
{
__asm nop;
}
if(target_character->IsKindOfObject(PLAYER_OBJECT))
{
Player* pTargetPlayer = (Player*)target_character;
if ((pTargetPlayer->GetObjectKey() == g_pHero->GetObjectKey()) &&
(0 != pTargetPlayer->GetCollectObjKey()) &&
(pResult->GetTargetData().IsHeal() == FALSE))
{
const CollectionInfo* pCI = CollectionParser::Instance()->FindCollectionInfo(pTargetPlayer->GetCollectID());
if (NULL != pCI &&
((CollectionInfo::OBJ_COLLECT == pCI->m_Condition[CollectionInfo::STAMP])
#ifdef _NA_005026_20120527_CHAOS_ZONE_BATTLE_GROUND
|| (CollectionInfo::OBJ_BATTLE_GROUND_STRONGPOINT == pCI->m_Condition[CollectionInfo::STAMP])
#endif //_NA_005026_20120527_CHAOS_ZONE_BATTLE_GROUND
))
{
TCHAR* debug_message = NULL;
#ifdef _DEV_VER
debug_message = _T("MSG_CG_COLLECT_CANCEL_SYN[Damage]");
#endif
StateCollect::SendCollectCancelSyn(debug_message);
}
}
}
}
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
BYTE Character::GetMoveState()
{
return m_bMoveState;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetMoveState(BYTE state)
{
m_bMoveState = state;
}
//------------------------------------------------------------------------------
/**
주의!
STATE::MOVE와 이 함수는 직접적인 관련이 없습니다!!
이 함수는 PathExp에 명령을 내리는 역할일 뿐입니다.
적이 맞아서 뒤로 밀리는 처리에도 이 함수를 호출할수있습니다.
*/
BOOL Character::Move(WzVector vCurPos,WzVector vDestPos,BYTE byState,BOOL bThrust,int iCurTileNum,int iDestTileNum)
{
m_pPathExplorer->Stop();
if (m_pPathExplorer->GetTile() == -1)
{
return FALSE;
}
SetMoveState(byState);
if (vCurPos.x == vDestPos.x && vCurPos.y == vDestPos.y) return FALSE;
if (!bThrust)
{
int iTileFocussing = -1;
// 대상 Tile 얻기
if (iDestTileNum != -1)
{
iTileFocussing = iDestTileNum;
}
else
{
float ft = 0.0f;
iTileFocussing = g_pSunTerrain->x_pPathFinder->GetTileToStand( vDestPos, &ft, -1.0f, 10.0f );
vDestPos.z -= ft;
}
if( iTileFocussing < 0 )
{
return FALSE;
}
// 갈수 없는 타일로 가는 명령은 무시
if (g_pMap->GetWorldBase()->x_pPathFinder->GetAttribute(iTileFocussing) & ( PTA_ONLY_JUMP |PTA_NO_WALK))
{
return FALSE;
}
// 디폴트 이동 제약 타일
WORD wAttr = PTA_ONLY_JUMP | PTA_NO_WALK | PTA_PLAYER_FALLDOWN_TILE;
// Monster인 경우 점프타일 위를 걸을 수 있게한다.
if (IsKindOfObject(MONSTER_OBJECT))
{
wAttr &= (~PTA_ONLY_JUMP);
}
//const int SEEK_NODE = 500;
// 길찾기
// 일단 모두 점프할수있다.
// 속성따라 다름
SUNPROCESSPROFILE_BEGIN(_T("PathFinding"));
ENUM_FINDPATH_RESULT rt=g_pSunTerrain->PathExp_FindPath( m_pPathExplorer, vDestPos, iTileFocussing, wAttr, GetSeekNodeCount());
if(rt==EFR_FAILURE||rt==EFR_SAME_POSITION)
{
SUNPROCESSPROFILE_END(_T("PathFinding"));
return FALSE;
}
SUNPROCESSPROFILE_END(_T("PathFinding"));
}
else
{
WzVector vDist;
vDist = vDestPos - vCurPos;
// 디폴트 이동 제약 타일
WORD wAttr = PTA_ONLY_JUMP |PTA_NO_WALK;
// Monster인 경우 점프타일 위를 걸을 수 있게한다.
if( IsKindOfObject(MONSTER_OBJECT) )
{
wAttr &= (~PTA_ONLY_JUMP);
}
g_pSunTerrain->PathExp_Thrust( m_pPathExplorer,&vDist,wAttr);
}
m_vTargetPosition = vDestPos;
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
int Character::EmptyActionQueue()
{
while( !m_ActionQueue.empty() )
{
m_ActionQueue.pop();
}
return 1;
}
//------------------------------------------------------------------------------
/**
*/
int Character::GetActionQueueCount()
{
return m_ActionQueue.size();
}
//------------------------------------------------------------------------------
/**
*/
int Character::PutAction(PLAYER_ACTION *pAction)
{
m_ActionQueue.push(*pAction);
// 큐에 너무많은 명령이 쌓이지는 않는지 체크
if (m_ActionQueue.size() > 150)
{
WRITELOG(eLOG_LEVEL_DBG, c_wOUTPUT_LOG_CENTER, _T("m_ActionQueue.size() > 150"));
}
return m_ActionQueue.size();
}
//------------------------------------------------------------------------------
/**
*/
int Character::DoAction(PLAYER_ACTION *pAction)
{
SetCurrentAction(pAction);
PLAYER_ACTION idleaction;
idleaction.ActionID = ACTION_IDLE;
idleaction.IDLE.vCurPos = GetPosition();
switch(pAction->ActionID)
{
case ACTION_ATTACK:
{
Character *pTarget = (Character *)g_ObjectManager.GetObject(pAction->ATTACK.dwTargetID);
StopMove();
if (pTarget)
{
if (pAction->ATTACK.bAttackMove)
{
SetPosition(pAction->ATTACK.vCurPos);
SetAttackMovePath(pAction->ATTACK.vCurPos,pAction->ATTACK.vDestPos);
SetAttackMove(TRUE);
}
else
{
SetAttackMove(FALSE);
SetPosition(pAction->ATTACK.vCurPos);
}
SetInterpolatePosition();
SetTargetID(pTarget->GetObjectKey());
SetAttackSequence((eATTACK_SEQUENCE)pAction->ATTACK.byAttackType);
#ifdef _NA003109_STYLE_PRESENTATION_IMPROVEMENT
NormalAttack.ani_type = pAction->ATTACK.style_presentation;
#endif //_NA003109_STYLE_PRESENTATION_IMPROVEMENT
SetNextActionAttackSerial(pAction->ATTACK.dwAttackSerial);
SetNextState(STATE::ATTACK,g_CurTime);
return 1;
}
// 때릴놈이 없네~
else
{
// 때린 결과만 처리하고
ProcessAttackResult(pAction->ATTACK.dwAttackSerial,TRUE);
// 놀아용~
SetCurrentAction(&idleaction);
SetNextState(STATE::IDLE,g_CurTime);
return 0;
}
}
break;
case ACTION_TRANSFORM:
{
StopMove();
GetTransformData().SetTransFormResourceCode(pAction->TRANSFORM.rcCode);
GetTransformData().SetTransFormType(pAction->TRANSFORM.transFormType);
GetTransformData().SetTransFormProcessType(pAction->TRANSFORM.transFormProcess);
GetTransformData().SetAppearanceKind(pAction->TRANSFORM.appearKind);
SetNextState(STATE::TRANSFORM,g_CurTime);
return 1;
}
break;
case ACTION_FALLDOWN:
{
StopMove();
SetNextState(STATE::FALL_DOWN,g_CurTime);
return 1;
}
break;
case ACTION_AIR_FALLDOWN:
{
StopMove();
SetNextState( STATE::AIR_FALL_DOWN, g_CurTime );
return 1;
}
break;
// 이동~
case ACTION_MOVE:
{
StopMove();
SetNextMove(pAction->MOVE.vCurPos.wvPos,pAction->MOVE.vDestPos.wvPos,pAction->MOVE.byState,pAction->MOVE.bThrust,pAction->MOVE.vCurPos.wTile,pAction->MOVE.vDestPos.wTile);
SetPosition(pAction->MOVE.vCurPos.wvPos,pAction->MOVE.vCurPos.wTile);
SetInterpolatePosition();
SetNextState(STATE::MOVE,g_CurTime);
return 1;
}
break;
case ACTION_KEYBOARDMOVE:
{
StopMove();
SetPosition(pAction->KEYBOARDMOVE.vKeyboardCurPos);
SetInterpolatePosition();
SetAngle(pAction->KEYBOARDMOVE.fKeyboardAngle);
SetMoveFlag(pAction->KEYBOARDMOVE.byKeyboardState);
SetNextState(STATE::KEYBOARDMOVE,g_CurTime);
return 1;
}
break;
case ACTION_SPECIAL_MOVE:
{
StopMove();
SetPosition(pAction->SPECIALMOVE.vCurPos);
SetInterpolatePosition();
SetAngle(pAction->SPECIALMOVE.fAngle,TRUE);// 특수 이동은 바로 꺽는다.
SetSpecialMoveFlag(pAction->SPECIALMOVE.bType);
SetNextState(STATE::SPECIALMOVE,g_CurTime);
return 1;
}
break;
case ACTION_SKILL:
{
Character *pTarget = (Character *)g_ObjectManager.GetObject(pAction->SKILL.dwTargetID);
StopMove();
if (pTarget)
{
SetCurrentAction(pAction);
SetNextActionAttackSerial(pAction->ATTACK.dwAttackSerial);
SetTargetID(pAction->SKILL.dwTargetID);
SetDirection( pTarget->GetVisiblePos() );
UseSkill(pAction->SKILL.dwSkillID);
return 1;
}
// 때릴놈이 없네~
else
{
// 때린 결과만 처리하고
ProcessAttackResult(pAction->SKILL.dwAttackSerial,TRUE);
// 놀아용~
SetNextState(STATE::IDLE,g_CurTime);
SetCurrentAction(&idleaction);
return 0;
}
}
break;
case ACTION_KNOCKBACK:
{
// 액션큐를 사용하지 않음
StopMove();
SetNextState(STATE::DAMAGE,g_CurTime);
return 1;
}
break;
case ACTION_TOAIR:
{
// 액션큐를 사용하지 않음
StopMove();
//TOAIR_INFO info;
//info.bGroundHit = FALSE;
//info.fDownForceLimit = pAction->TOAIR.fDownForceLimit;
//info.fGravity = pAction->TOAIR.fGravity;
//info.fHeightLimit = pAction->TOAIR.fHeightLimit;
//info.fUpperForce = pAction->TOAIR.fUpperForce;
//info.iBoundCount = 0;
//info.bForceDown= pAction->TOAIR.bForceDown;
//ToAirInfo(&info);
SetNextState(STATE::AIR,g_CurTime);
return 1;
}
break;
case ACTION_DOWN:
{
// 액션큐를 사용하지 않음
StopMove();
SetNextState(STATE::DOWN,g_CurTime);
return 1;
}
break;
case ACTION_GETUP:
{
// 액션큐를 사용하지 않음
StopMove();
SetNextState(STATE::GETUP,g_CurTime);
return 1;
}
break;
case ACTION_SIT:
{
StopMove();
SetNextState(STATE::SIT,g_CurTime);
return 1;
}
break;
case ACTION_EVENTJUMP:
{
StopMove();
SetNextState(STATE::EVENTJUMP,g_CurTime);
return 1;
}
break;
case ACTION_STOP:
{
StopMove();
SetPosition(pAction->STOP.vCurPos);
SetNextState(STATE::IDLE,g_CurTime);
return 1;
}
break;
case ACTION_NPCMEET:
{
if(STATE::NPC_SPECIAL_ACT_LOOP_STATE != GetCurState())
SetNextState(STATE::NPC_RESPONSE_STATE, g_CurTime);
return 1;
}
break;
case ACTION_VENDORMEET:
{
return 1;
}
break;
case ACTION_ATTACKJUMP:
{
StopMove();
SetNextActionAttackSerial(pAction->ATTACKJUMP.dwAttackSerial);
SetDirection( pAction->ATTACKJUMP.vDestPos.wvPos );
SetNextState(STATE::ATTACKJUMP,g_CurTime);
return 1;
}
break;
case ACTION_RUNAWAY:
{
StopMove();
SetNextMove(pAction->MOVE.vCurPos.wvPos,pAction->MOVE.vDestPos.wvPos,pAction->MOVE.byState,pAction->MOVE.bThrust,pAction->MOVE.vCurPos.wTile,pAction->MOVE.vDestPos.wTile);
SetPosition(pAction->MOVE.vCurPos.wvPos,pAction->MOVE.vCurPos.wTile);
SetInterpolatePosition();
SetNextState(STATE::RUNAWAY,g_CurTime);
return 1;
}
break;
case ACTION_TELEPORT:
{
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("k470"),GetVisiblePos(),GetObjectKey());
StopMove();
WzVector vPos=pAction->TELEPORT.vDest;
SetDestWarp(vPos);
SetPosition(vPos);
SetDirection(vPos, TRUE);
}
break;
case ACTION_TRIGGER_ANIMATION_CONTROL:
{
if (pAction->TRIGGERANIMATIONCONTROL.start_animation_id != 0)
{
StopMove();
SetNextState(STATE::TRIGGER_ANIMATION_CONTROL, g_CurTime);
return 1;
}
}
break;
#ifdef _NA_008016_20150203_SUN_RANKING_SYSTEM_BRONZE
case ACTION_BRONZE_STAND:
{
StopMove();
SetNextState(STATE::BRONZE_STAND, g_CurTime);
return 1;
}
break;
#endif // _NA_008016_20150203_SUN_RANKING_SYSTEM_BRONZE
default:
{
WRITELOG(eLOG_LEVEL_ERR, c_wOUTPUT_LOG_FILE | c_wOUTPUT_LOG_CENTER, _T("[%d] Character::DoNextAction() 처리되지 않은 큐 명령"), pAction->ActionID);
assert(!"Character::DoNextAction() 처리되지 않은 큐 명령");
break;
}
}
SetCurrentAction(&idleaction);
SetNextState(STATE::IDLE,g_CurTime);
return 0;
}
//------------------------------------------------------------------------------
/**
*/
int Character::DoNextAction()
{
PLAYER_ACTION action;
while( !m_ActionQueue.empty() )
{
action = m_ActionQueue.front();
m_ActionQueue.pop();
// 액션을 실행하는데 성공했으면 리턴
// 실패시에는 그 다음액션을 시도.
if (DoAction(&action))
{
return 1;
}
}
SetNextState(STATE::IDLE,g_CurTime);
return 0;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::CheckQueueActionCondition()
{
assert(m_ActionQueue.size() != 0);
// 일반 캐릭터는 다음 Action이 Damage 액션이 아닌이상 무조건 성공합니다.
// Damage Action은 캐릭터의 데미지가 처리된후에만 발동합니다
switch(m_ActionQueue.front().ActionID)
{
case ACTION_TOAIR:
case ACTION_KNOCKBACK:
case ACTION_DOWN:
case ACTION_KNOCKBACK2:
return FALSE;
}
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::IsMove()
{
return BOOL( m_pPathExplorer && m_pPathExplorer->IsMoving() );
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::IsTransFormation()
{
return FindSkillEffect( eCHAR_STATE_TRANSFORMATION ) != NULL;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::IsStun()
{
return FindSkillEffect( eCHAR_STATE_STUN ) != NULL
|| FindSkillEffect( eCHAR_STATE_STUN2 ) != NULL;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::IsSleep()
{
return FindSkillEffect( eCHAR_STATE_SLEEP ) != NULL;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::IsFrozen()
{
return FindSkillEffect( eCHAR_STATE_FROZEN ) != NULL;
}
BOOL Character::IsPolymorph()
{
return FindSkillEffect( eCHAR_STATE_POLYMORPH ) != NULL;
}
//#ifdef _DEBUG
// static DWORD s_TestObjectKey = 0;
//
// if( GetObjectKey() == s_TestObjectKey )
// return TRUE;
//#endif
//
// return FALSE;
//}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::IsBlind2()
{
#ifdef _DEBUG
if( FindSkillEffect( (eCHAR_STATE_TYPE)972 ) != NULL )
return TRUE;
#endif
return FindSkillEffect( (eCHAR_STATE_TYPE)eCHAR_STATE_WHITE_BLIND ) != NULL; // 화이트블라인드
}
BOOL Character::IsDarkofLightZoneState()
{
return FindSkillEffect( (eCHAR_STATE_TYPE)eCHAR_STATE_DARK_OF_LIGHT_ZONE ) != NULL; //
}
BOOL Character::IsGravityZoneState()
{
return FindSkillEffect( (eCHAR_STATE_TYPE)eCHAR_STATE_GRAVITY_ZONE ) != NULL; //
}
BOOL Character::IsDetectingHide()
{
return FindSkillEffect( (eCHAR_STATE_TYPE)eCHAR_STATE_DETECTING_HIDE ) != NULL; //
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::IsBlind()
{
return FindSkillEffect( eCHAR_STATE_BLIND ) != NULL;
}
//------------------------------------------------------------------------------
bool Character::IsSteel()
{
return FindSkillEffect( eCHAR_STATE_STEEL ) != NULL;
/*
|| FindSkillEffect( eCHAR_STATE_STEEL2 ) != NULL
|| FindSkillEffect( eCHAR_STATE_STEEL3 ) != NULL
|| FindSkillEffect( eCHAR_STATE_STEEL4 ) != NULL
|| FindSkillEffect( eCHAR_STATE_STEEL5 ) != NULL;*/
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::IsFainting()
{
return FindSkillEffect( eCHAR_STATE_SLEEP ) != NULL
|| FindSkillEffect( eCHAR_STATE_STUN ) != NULL
|| FindSkillEffect( eCHAR_STATE_STUN2 ) != NULL;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::IsBlock()
{
if(this->GetCurrentAnimation()==this->GetCurrentBlockAnimation())
{
float fFrame = GetTotalFrame() - 1.0f;
float fRate = (fFrame) ? ((GetCurrentFrame() * 100.0f) / fFrame) : 100;
if(fRate<100)
return TRUE;
}
return FALSE;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::CannotAir()
{
switch (GetCurState())
{
case STATE::SKILL:
case STATE::KEYBOARDJUMP:
case STATE::ATTACKJUMP:
case STATE::TRANSFORM:
case STATE::FALL_DOWN:
case STATE::COLLECT:
{
return TRUE;
break;
}
}
return FALSE;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::CannotMove()
{
for( size_t i=0;i!=m_SkillEffectArray.size();++i)
{
SKILL_EFFECT* pEffect = m_SkillEffectArray[i];
switch (pEffect->dwStatusID )
{
case eCHAR_STATE_DOWN: // 다운
case eCHAR_STATE_FEAR: // 공포
case eCHAR_STATE_SLEEP: // 수면
case eCHAR_STATE_STUN: // 스턴
case eCHAR_STATE_STUN2: // 스턴2
case eCHAR_STATE_FROZEN: // 프로즌
case eCHAR_STATE_DELAY: // 딜레이?
case eCHAR_STATE_STONE: // 석화
case eCHAR_STATE_SUMMON: // 소환중
case eCHAR_STATE_MP_FEAR2: // 피어2
case eCHAR_STATE_THRUST: // 밀리기
#ifdef _NA_007619_20140916_PROCESS_CHANGE_AIRBLOW_DOWN
case eCHAR_STATE_UPPERDOWN:
#endif // _NA_007619_20140916_PROCESS_CHANGE_AIRBLOW_DOWN
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
case eCHAR_STATE_CHARMED:
#endif // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
//case eCHAR_STATE_POLYMORPH:
case eCHAR_STATE_HOLDING: // 홀딩 (이동불가)
{
return TRUE;
}
break;
}
}
return FALSE;
}
//------------------------------------------------------------------------------
BOOL Character::CannotAction()
{
for( size_t i=0;i!=m_SkillEffectArray.size();++i)
{
SKILL_EFFECT* pEffect = m_SkillEffectArray[i];
switch (pEffect->dwStatusID )
{
case eCHAR_STATE_DOWN: // 다운
case eCHAR_STATE_FEAR: // 공포
case eCHAR_STATE_SLEEP: // 수면
case eCHAR_STATE_STUN: // 스턴
case eCHAR_STATE_STUN2: // 스턴2
case eCHAR_STATE_FROZEN: // 프로즌
case eCHAR_STATE_DELAY: // 딜레이
case eCHAR_STATE_STONE: // 석화
case eCHAR_STATE_SUMMON: // 소환중
case eCHAR_STATE_MP_FEAR2: // 피어2
case eCHAR_STATE_THRUST: // 밀리기
case eCHAR_STATE_FATAL_POINT: // 페이탈포인트 (홀딩+스턴)
#ifdef _NA_007619_20140916_PROCESS_CHANGE_AIRBLOW_DOWN
case eCHAR_STATE_UPPERDOWN:
#endif // _NA_007619_20140916_PROCESS_CHANGE_AIRBLOW_DOWN
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
case eCHAR_STATE_CHARMED:
#endif // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
//case eCHAR_STATE_POLYMORPH: // 폴리모프 (이동가능)
{
return TRUE;
}
break;
}
}
return FALSE;
}
BOOL Character::IsImpossible()
{
return FindSkillEffect( eCHAR_STATE_ATTACK_IMPOSSIBLE ) != NULL;
}
//------------------------------------------------------------------------------
/** 클론 이펙트(클론복사잔상)
*/
void Character::CloneEffect(DWORD LiveTime, DWORD DisappearTime,BYTE byStyle)
{
DWORD dwCloneKey;
dwCloneKey = g_CloneManager.CreateClone(this);
Clone *pClone = g_CloneManager.GetClone(dwCloneKey);
if(!pClone) return;
switch(byStyle)
{
case 0://하이드
{
pClone->SetColor(WzColor_RGBA(255,255,255,120));
}
break;
case 1: //러쉬
{
pClone->SetAlphaBlend(AB_ALPHA);
pClone->SetColor(WzColor_RGBA(125,125,125,125));
}
break;
}
pClone->SetAnimation(this->GetCurrentAnimation());
pClone->SetPosition(this->GetPosition());
pClone->SetLifeTime( LiveTime );
pClone->SetDisappear( DisappearTime );
pClone->SetCurrentFrame(this->GetCurrentFrame());
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::CanBeAttackTarget()
{
switch(GetCurState())
{
case STATE::DEATH:
//case STATE::JUMP:
//case STATE::AIR:
case STATE::EVENTJUMP:
return FALSE;
}
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetNextMove(WzVector vCurPos,WzVector vDestPos,BYTE byState,BOOL bThrust,int iCurIndex,int iDestIndex)
{
m_vNextMoveCurPos = vCurPos;
m_vNextMoveDestPos = vDestPos;
m_bNextMoveState = byState;
m_bNextMoveThrust = bThrust;
m_iNextMoveCurTile = iCurIndex;
m_iNextMoveDestTile = iDestIndex;
m_bNextMove = TRUE;
}
//------------------------------------------------------------------------------
/**
*/
void Character::StartNextMove()
{
if (m_bNextMove)
{
if (!m_bNextMoveThrust)
{
Move(m_vNextMoveCurPos,m_vNextMoveDestPos,m_bNextMoveState,m_bNextMoveThrust,m_iNextMoveCurTile,m_iNextMoveDestTile);
}
else
{
Move(m_vNextMoveCurPos,m_vNextMoveDestPos,m_bNextMoveState,m_bNextMoveThrust,m_iNextMoveCurTile,-1);
}
m_bNextMove = FALSE;
}
else
{
if (GetSCObject().GetObjectType() == MONSTER_OBJECT)
{
__asm nop;
}
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetAttackMove(BOOL bMove)
{
m_bAttackMove = bMove;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetAttackMovePath(HONGPOS vCurPos,HONGPOS vDestPos)
{
m_vAttackStartPos = vCurPos;
m_vAttackEndPos = vDestPos;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetHitPause(DWORD dwPause)
{
m_dwHitPause = dwPause;
}
//------------------------------------------------------------------------------
/**
*/
DWORD Character::GetHitPause()
{
return m_dwHitPause;
}
//------------------------------------------------------------------------------
/**
*/
void Character::Vibrate(WzVector vDirection,float fForce)
{
#ifdef VIBRATE_CHARACTER
m_vVibrateDirection = vDirection;
m_fVibrateForce = fForce;
m_fVibrateCurrent = 0.0f;
m_bVibrateMove = TRUE;
#endif
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetMoveSpeed( float fMoveSpeed )
{
m_fMoveSpeed = fMoveSpeed;
}
//------------------------------------------------------------------------------
/**
*/
float Character::GetMoveSpeed( void )
{
return m_fMoveSpeed;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetCurrentAction(PLAYER_ACTION *pAction)
{
m_CurAction = *pAction;
}
//------------------------------------------------------------------------------
/**
*/
PLAYER_ACTION* Character::GetCurrentAction()
{
return &m_CurAction;
}
PLAYER_ACTION* Character::GetNextAction()
{
if( GetActionQueueCount() )
{
return &m_ActionQueue.front();
}
else
{
return NULL;
}
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::CommonStateProcess()
{
if (GetActionQueueCount())
{
PLAYER_ACTION NextAction = m_ActionQueue.front();
switch (NextAction.ActionID)
{
case ACTION_KNOCKBACK2:
case ACTION_KNOCKBACK:
case ACTION_TOAIR:
case ACTION_DOWN:
if ( GetLatestQueueAttack() >= NextAction.dwTimeSerial)
{
DoNextAction();
return TRUE;
}
break;
case ACTION_ETHERIA_EXTRACT:
case ACTION_SUMMON_RIDER:
case ACTION_FALLDOWN:
case ACTION_KEYBOARDJUMP:
case ACTION_TRANSFORM:
case ACTION_WINGS_SPREAD:
case ACTION_WINGS_FURL:
case ACTION_RIDER_SPREAD:
case ACTION_RIDER_FURL:
{
if( m_dwHP == 0 && NextAction.ActionID == ACTION_TRANSFORM )
break;
DoNextAction();
return TRUE;
}
break;
}
}
// 피없으면 바로 죽으셈
if (m_dwHP <=0 )
{
int iDestTileFocussing = g_pSunTerrain->x_pPathFinder->GetTileToStand(GetPosition(), NULL, -1.0f, 100.0f);
if (iDestTileFocussing >= 0)
{
WORD Attribute = g_pMap->GetWorldBase()->x_pPathFinder->GetAttribute(iDestTileFocussing);
if (Attribute & (PTA_PLAYER_FALLDOWN_TILE))
{
SetNextState(STATE::FALL_DOWN, g_CurTime);
return TRUE;
}
}
SetNextState(STATE::DEATH, g_CurTime);
return TRUE;
}
return FALSE;
}
//------------------------------------------------------------------------------
/**
*/
float Character::GetProcessMultiplier()
{
const float fMaxMultiplier = 5.0f;
// 큐가 하나만 쌓여있어도 꽤나 처리가 느리다는뜻이다!!
const int iTolerance = 1;
float fMultiplier = 1.0f;
int count = GetActionQueueCount();
if (count >= iTolerance)
{
while(count > 0)
{
fMultiplier *= 1.1f;
if (fMultiplier > fMaxMultiplier)
{
break;
}
count--;
}
}
if (fMultiplier > fMaxMultiplier)
{
fMultiplier = fMaxMultiplier;
}
return fMultiplier;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetHitCount(int count)
{
m_iHitCount = count;
}
//------------------------------------------------------------------------------
/**
*/
int Character::GetHitCount()
{
return m_iHitCount;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::ProcessNextAction()
{
if (GetActionQueueCount())
{
if (CheckQueueActionCondition())
{
DoNextAction();
return TRUE;
}
else
{
SetNextState(STATE::IDLE,g_CurTime);
return TRUE;
}
}
return FALSE;
}
//------------------------------------------------------------------------------
/**
*/
void Character::ProcessAllRemainActionResult()
{
PLAYER_ACTION action;
while( !m_ActionQueue.empty() )
{
action = m_ActionQueue.front();
m_ActionQueue.pop();
switch(action.ActionID)
{
case ACTION_ATTACK:
{
ProcessAttackResult(action.ATTACK.dwAttackSerial,TRUE);
}
break;
case ACTION_SKILL:
{
ProcessAttackResult(action.SKILL.dwAttackSerial,TRUE);
}
break;
case ACTION_ATTACKJUMP:
{
ProcessAttackResult(action.ATTACKJUMP.dwAttackSerial,TRUE);
}
break;
}
}
ATTACK_RESULT_LIST::iterator itr;
itr = m_AttackResultList.begin();
while(itr != m_AttackResultList.end())
{
ATTACK_RESULT ret = *itr;
_ProcessAttackResult(&ret);
itr++;
}
m_AttackResultList.clear();
//! 반사계열 처리
ProcessReflectDamage();
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetAttackSequence( eATTACK_SEQUENCE sequence )
{
m_eAttackSequence = sequence;
}
//------------------------------------------------------------------------------
/**
*/
eATTACK_SEQUENCE Character::GetAttackSequence( void )
{
return m_eAttackSequence;
}
//------------------------------------------------------------------------------
/**
*/
void Character::HitSpin(float fForce,BOOL bRight)
{
m_fSpinForce = fForce;
}
//------------------------------------------------------------------------------
/**
*/
void Character::PlayDamageSound(eWEAPONSOUNDKIND eSoundKind)
{
;
}
//------------------------------------------------------------------------------
/**
*/
void Character::CreateDamageEffect(BOOL bCritical,BOOL bRight,DWORD dwAttackObjId)
{
WzVector wvEffectPos = GetArrowTargetPos();
wvEffectPos.z += GetHeight();
float fHeight = GetArrowTargetHeight();
HANDLE hSparkEffect = INVALID_HANDLE_VALUE;
HANDLE hBloodEffect = INVALID_HANDLE_VALUE;
WzID wiDamageEffectID = INVALID_WZID;
WzID wiCDamageEffectID = INVALID_WZID;
BOOL bEventEffect = FALSE;
Object* pChr = g_ObjectManager.GetObject(dwAttackObjId);
if(pChr && pChr->IsKindOfObject(PLAYER_OBJECT))
{
Player *pPlayer = static_cast<Player*>(pChr);
//맞은데미지가 이벤트웨폰(사탕)이였다면 이펙트를 터뜨린다.
if(pPlayer && this!=pPlayer && pPlayer->IsEventWeapon())
{
bEventEffect = TRUE;
}
}
#ifdef _PERF_DEBUG
return;
#endif
if (bEventEffect)
{
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("J760"),wvEffectPos,dwAttackObjId,GetObjectKey());
}
else
{
//////////////////////////////////////////////////////////////////////////
// 한 캐릭터에 너무 많은 데미지이펙트가 붙는걸 방지하기 위한 코드
std::list<HANDLE>::iterator iter = m_listDamageEffectHndl.begin();
std::list<HANDLE>::iterator iterEnd = m_listDamageEffectHndl.end();
int iDamageEftCnt = 0;
while(iterEnd != iter)
{
HANDLE hHndl = (*iter);
if (NULL != g_pEffectManager->GetEffectPtrHandle(hHndl))
{
++iDamageEftCnt;
++iter;
}
else
{
iter = m_listDamageEffectHndl.erase(iter);
}
}
if(SCENE_TYPE_DOMINATION == GameFramework::GetCurScene()
#ifdef _NA_008334_20150608_SONNENSCHEIN
|| SCENE_TYPE_SONNENSCHEIN == GameFramework::GetCurScene()
#endif //_NA_008334_20150608_SONNENSCHEIN
)
{
if(MAX_DAMAGE_EFFECT_CNT_IN_DOMINATION < iDamageEftCnt)
return;
}
else
{
if (MAX_DAMAGE_EFFECT_CNT < iDamageEftCnt)
return;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
//스크립트에 타격 이펙트가 있는지 체크(있으면 있는걸로 없으면 기본으로)
if (TRUE == this->IsKindOfObject(MONSTER_OBJECT))
{
Monster* pMon = (Monster*)this;
wiDamageEffectID = pMon->GetMonsterInfo()->m_wiDamageEffectID;
wiCDamageEffectID = pMon->GetMonsterInfo()->m_wiCDamageEffectID;
}
// 타격효과
if (bCritical)
{
if (INVALID_WZID == wiCDamageEffectID)
{
Object* pObj = g_ObjectManager.GetObject(dwAttackObjId);
if (pObj)
{
if (TRUE == pObj->IsKindOfObject(PLAYER_OBJECT))
{
Player* pPlayer = (Player*)pObj;
switch (pPlayer->GetClass())
{
case eCHAR_SHADOW:
// 스파크
hSparkEffect = GlobalFunc::CreateEffectBeUpToOption(StrToWzID("A650"),wvEffectPos,dwAttackObjId,GetObjectKey());
break;
default:
// 스파크
hSparkEffect = GlobalFunc::CreateEffectBeUpToOption(StrToWzID("A008"),wvEffectPos,dwAttackObjId,GetObjectKey());
break;
}
}
else
{
// 스파크
hSparkEffect = GlobalFunc::CreateEffectBeUpToOption(StrToWzID("A008"),wvEffectPos,dwAttackObjId,GetObjectKey());
}
// 피
hBloodEffect = GlobalFunc::CreateEffectBeUpToOption(StrToWzID("A005"),wvEffectPos,dwAttackObjId,GetObjectKey());
}
}
else
{
hSparkEffect = GlobalFunc::CreateEffectBeUpToOption(wiCDamageEffectID,wvEffectPos,dwAttackObjId,GetObjectKey());
}
}
else
{
if (INVALID_WZID == wiDamageEffectID)
{
// 피
hBloodEffect = GlobalFunc::CreateEffectBeUpToOption(StrToWzID("A004"),wvEffectPos,dwAttackObjId,GetObjectKey());
// 스파크
hSparkEffect = GlobalFunc::CreateEffectBeUpToOption(StrToWzID("A007"),wvEffectPos,dwAttackObjId,GetObjectKey());
}
else
{
hSparkEffect = GlobalFunc::CreateEffectBeUpToOption(wiDamageEffectID,wvEffectPos,dwAttackObjId,GetObjectKey());
}
}
}
if (INVALID_HANDLE_VALUE != hSparkEffect)
{
m_listDamageEffectHndl.push_back(hSparkEffect);
}
WzVector vBaseScale;
vBaseScale.x = 1.0f;
vBaseScale.y = 1.0f;
vBaseScale.z = 1.0f;
//! 2011.5.3 / i4u4me / 캐릭팀(조흥래팀장)에서 타격시 딜레이 주지 않게 요청
//! 관련 작업 undef 함, 효과는 유지
//#ifdef _YJ_MOD_BLOW_MOTION_001188
CEffectBody* pBodyB = g_pEffectManager->GetEffectPtrHandle(hBloodEffect);
CEffectBody* pBodyS = g_pEffectManager->GetEffectPtrHandle(hSparkEffect);
float fDestAngle = WZ_PI / 4.0f;
WzVector vRot;
WzVector vScaleBlood, vScaleSpark;
vRot.x = 0.0f;
vRot.y = 0.0f;
vRot.z = 0.f;
if (bRight)
{
vRot.z -= fDestAngle;
}
else
{
vRot.z += fDestAngle;
}
if (4.0f < fHeight)
{
SetVector(&vScaleBlood, 4.0f, 4.0f, 4.0f);
SetVector(&vScaleSpark, 2.f, 2.f, 2.f);
}
else if (3.5f < fHeight)
{
SetVector(&vScaleBlood, 3.5f, 3.5f, 3.5f);
SetVector(&vScaleSpark, 1.8f, 1.8f, 1.8f);
}
else if (3.0f < fHeight)
{
SetVector(&vScaleBlood, 3.0f, 3.0f, 3.0f);
SetVector(&vScaleSpark, 1.4f, 1.4f, 1.4f);
}
else if (2.5f < fHeight)
{
SetVector(&vScaleBlood, 2.5f, 2.5f, 2.5f);
SetVector(&vScaleSpark, 1.2f, 1.2f, 1.2f);
}
else
{
SetVector(&vScaleBlood, 2.f, 2.f, 2.f);
SetVector(&vScaleSpark, 1.f, 1.f, 1.f);
}
if (pBodyB)
{
pBodyB->SetResultMatrix(wvEffectPos,vRot,vScaleBlood);
}
if (pBodyS)
{
if (INVALID_WZID == wiDamageEffectID)
{
pBodyS->SetResultMatrix(wvEffectPos,vRot,vScaleSpark);
}
else
{
vRot.x = 0.0f;
vRot.y = 0.0f;
vRot.z = GetAngle();
pBodyS->SetResultMatrix(wvEffectPos,vRot,vBaseScale);
}
}
//#endif //_YJ_MOD_BLOW_MOTION_001188
//////////////////////////////////////////////////////////////////////////
}
//------------------------------------------------------------------------------
/**
죽었음
*/
BOOL Character::IsDead()
{
return (m_dwHP == 0) ? TRUE : FALSE;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetAttackStandTime(int iTime)
{
m_iAttackStandTime = iTime;
}
//------------------------------------------------------------------------------
/**
*/
float Character::GetAttackSpeedModifier()
{
return 1.0f;
}
//------------------------------------------------------------------------------
/**
*/
float Character::GetMoveSpeedModifier()
{
return 1.0f;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::OnUseItem(DWORD dwItemCode)
{
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::OnUnUseItem(DWORD dwItemCode)
{
return TRUE;
}
////------------------------------------------------------------------------------
//HANDLE Character::AddStateEffect(WzID state_effect_id, DWORD target_objectkey, SKILL_EFFECT* skill_effect)
//{
// if ((state_effect_id) > 0 && (skill_effect != NULL))
// {
// return GlobalFunc::CreateEffectBeUpToOption(state_effect_id,
// GetSkillEffectPos(skill_effect),
// GetSkillEffectRotate(skill_effect),
// GetSkillEffectScale(skill_effect),
// target_objectkey,
// GetObjectKey());
// }
// return INVALID_HANDLE_VALUE;
//}
#include <algorithm>
bool _Sort_Effect( SKILL_EFFECT* pLeft, SKILL_EFFECT* pRight )
{
#ifdef _NA_006819_20130719_STATE_ICON_RENDER
static int sort_order[] = { 5, //eSTATE_KIND_DEBUFF = 0,
3, //eSTATE_KIND_ITEM = 1,
1, //eSTATE_KIND_CASH = 2,
4, //eSTATE_KIND_ETC = 3,
0, //eSTATE_KIND_SHIELD = 4,
2, //eSTATE_KIND_SKILL = 5,
999}; //eSTATE_KIND_MAX = 6, // 낮은값이 앞에오도록 정렬됨
// 캐릭터스킬,쉴드,캐쉬,아이템,기타,디버프 순서
#else // _NA_006819_20130719_STATE_ICON_RENDER
//eSTATE_KIND_DEBUFF = 0,
//eSTATE_KIND_SKILL = 1,
//eSTATE_KIND_CASH = 2,
//eSTATE_KIND_ETC = 3, //기타
//eSTATE_KIND_SHIELD =4,//쉴드 최우선
//eSTATE_KIND_MAX = 5,
static int sort_order[] = {4,2,1,3,0,999};
// 쉴드,캐쉬,스킬,기타,디버프 순서
#endif // _NA_006819_20130719_STATE_ICON_RENDER
if( sort_order[pLeft->GetIconKind()] < sort_order[pRight->GetIconKind()] )
return true;
if( sort_order[pLeft->GetIconKind()] == sort_order[pRight->GetIconKind()] )
return pLeft->iRemainTime < pRight->iRemainTime;
return false;
};
void Character::OnAddState( eCHAR_STATE_TYPE StateType )
{
//쉴드체크
if( StateType == eCHAR_STATE_ETC_EXIST_SHELD_POINT)
{
m_bShield = TRUE;
}
else if( StateType == eCHAR_STATE_DETECTING_HIDE )
{
if( GetObjectKey() == g_pHero->GetObjectKey() )
{
g_ObjectManager.RefreshPlayerHideState();
}
}
else if( StateType == eCHAR_STATE_DARK_OF_LIGHT_ZONE )
{
if( IsKindOfObject(PLAYER_OBJECT) )
{
Player* pPlayer = (Player*)this;
pPlayer->RefreshHideState(FALSE);
}
}
else if( StateType == eCHAR_STATE_POLYMORPH )
{
SetPolymorph(TRUE);
}
else if( StateType == eCHAR_STATE_BLIND || StateType == eCHAR_STATE_WHITE_BLIND )
{
if( GetTargetObject() != NULL )
{
SetTargetID(0);
}
if( IsMyHero() == TRUE )
{
g_HeroInput.SetCurrentTarget(0);
}
}
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
else if( StateType == eCHAR_STATE_VICE_SWORD )
{
CreateViceSwordWeaponEffect();
if (g_pHero == this)
{
SCItemSlot& rEquipItemSlot =
static_cast<SCItemSlot&>(ItemManager::Instance()->GetContainer(SI_EQUIPMENT)->GetSlot(EquipmentContainer::EQUIP_WEAPON1));
rEquipItemSlot.GetLaxLock()->EnterLock();
}
}
#endif // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
if( m_bShield)
{
ReleaseShieldEffect();
}
//#ifdef _DEBUG
// if( BASE_STATEINFO* pStateInfo = StateInfoParser::Instance()->GetStateInfo( StateType ) )
// {
// char temp[1024];
// wsprintf( temp, "AddState : %s [%d]%s\n", GetName(), (int)StateType, pStateInfo->m_szStateName );
// OutputDebugStr( temp );
// }
//#endif
}
void Character::OnRemoveState( eCHAR_STATE_TYPE StateType, BOOL IsDestroy )
{
//#ifdef _DEBUG
// if( BASE_STATEINFO* pStateInfo = StateInfoParser::Instance()->GetStateInfo( StateType ) )
// {
// char temp[1024];
// wsprintf( temp, "RemoveState : %s [%d]%s\n", GetName(), (int)StateType, pStateInfo->m_szStateName );
// OutputDebugStr( temp );
// }
//#endif
//쉴드체크
if( StateType == eCHAR_STATE_ETC_EXIST_SHELD_POINT)
{
m_bShield = FALSE;
}
else if( StateType == eCHAR_STATE_DETECTING_HIDE )
{
if( IsMyHero() == TRUE )
{
g_ObjectManager.RefreshPlayerHideState();
}
}
else if( StateType == eCHAR_STATE_DARK_OF_LIGHT_ZONE )
{
if( IsKindOfObject(PLAYER_OBJECT) )
{
Player* pPlayer = (Player*)this;
pPlayer->RefreshHideState(FALSE);
}
}
else if( StateType == eCHAR_STATE_POLYMORPH )
{
SetPolymorph( FALSE );
}
//TODO: 스테터스해제시 예외처리해야될구문
//상태해제
switch(StateType)
{
case eCHAR_STATE_SEALING:
case eCHAR_STATE_CONFUSE:
{
if( IsMyHero() == TRUE )
{
g_pHero->SetLockSkill(FALSE);
}
}
break;
case eCHAR_STATE_TRANSPARENT:
{
SetHideSkill(FALSE);
}
break;
case eCHAR_STATE_ETC_EXIST_SHELD_POINT:
{
if( IsDestroy == FALSE )
{
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("A670"),GetBodyPos(),GetObjectKey());
}
}
break;
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
case eCHAR_STATE_VICE_SWORD:
{
DestroyViceSwordWeaponEffect();
if (g_pHero == this)
{
if (ItemManager::Instance()->GetContainer(SI_EQUIPMENT))
{
SCItemSlot& rEquipItemSlot =
static_cast<SCItemSlot&>(ItemManager::Instance()->GetContainer(SI_EQUIPMENT)->GetSlot(EquipmentContainer::EQUIP_WEAPON1));
rEquipItemSlot.GetLaxLock()->LeaveLock();
}
}
}
break;
#endif // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
}
CreateShieldEffect();
}
//------------------------------------------------------------------------------
/**
*/
int Character::AddSkillEffect(SKILL_EFFECT *pEffect)
{
static int s_iEffectID = 1;
if( pEffect == NULL )
return 1;
pEffect->iEffectID = s_iEffectID;
m_SkillEffectArray.push_back(pEffect);
std::sort(m_SkillEffectArray.begin(), m_SkillEffectArray.end(), _Sort_Effect );
s_iEffectID++;
// 절대로 0은 만들지 않는다.
if (s_iEffectID == 0)
{
s_iEffectID++;
}
OnAddState( (eCHAR_STATE_TYPE)pEffect->dwStatusID );
return pEffect->iEffectID;
}
SKILL_EFFECT* Character::FindSkillEffect( eCHAR_STATE_TYPE StateType )
{
for( size_t i=0;i!=m_SkillEffectArray.size();++i)
{
SKILL_EFFECT* pEffect = m_SkillEffectArray[i];
if( pEffect->dwStatusID == StateType )
{
return pEffect;
}
}
return NULL;
}
//------------------------------------------------------------------------------
/**
*/
SKILL_EFFECT* Character::GetSkillEffect(int iEffectID)
{
for( size_t i=0;i!=m_SkillEffectArray.size();++i)
{
SKILL_EFFECT* pEffect = m_SkillEffectArray[i];
if (pEffect->iEffectID == iEffectID)
{
return pEffect;
}
}
return NULL;
}
//------------------------------------------------------------------------------
/**
*/
void Character::DeleteAllSkillEffect()
{
for( size_t i=0;i!=m_SkillEffectArray.size();++i)
{
SKILL_EFFECT* pEffect = m_SkillEffectArray[i];
eCHAR_STATE_TYPE StateType = (eCHAR_STATE_TYPE)pEffect->dwStatusID;
// 아이템 사용에 의한 버프가 제거되는 경우에, 해당 아이템의 이펙트가 있다면 함께 제거
if( SkillScriptInfo * pSkillInfo = SkillInfoParser::Instance()->GetSkillInfo((SLOTCODE)pEffect->dwSkillID) )
{
RemoveItemEffectByItemCode(pSkillInfo->m_dwItemCode);
}
delete pEffect;
OnRemoveState(StateType, TRUE);
}
m_SkillEffectArray.clear();
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::DeleteSkillEffect(int iEffectID)
{
for( size_t i=0;i!=m_SkillEffectArray.size();++i)
{
SKILL_EFFECT * pEffect = m_SkillEffectArray[i];
if (pEffect->iEffectID == iEffectID)
{
eCHAR_STATE_TYPE StateType = (eCHAR_STATE_TYPE)pEffect->dwStatusID;
// 아이템 사용에 의한 버프가 제거되는 경우에, 해당 아이템의 이펙트가 있다면 함께 제거
if( SkillScriptInfo* pSkillInfo = SkillInfoParser::Instance()->GetSkillInfo((SLOTCODE)pEffect->dwSkillID) )
{
RemoveItemEffectByItemCode( pSkillInfo->m_dwItemCode );
}
#ifdef _DEBUG
BASE_STATEINFO *pInfo = StateInfoParser::Instance()->GetStateInfo(pEffect->dwStatusID);
TCHAR szBuff[1024] = {0,};
if(pInfo)
Snprintf(szBuff, 1023, "\nDeleteSkillEffect(%s): %d\n\r", pInfo->m_szStateName, pEffect->dwStatusID);
else
Snprintf(szBuff, 1023, "\npInfo==NULL!!!! DeleteSkillEffect: %d\n\r", pEffect->dwStatusID);
GlobalFunc::OutputMsg_Notice( eOUTPUT_MSG_CHAT, szBuff );
#endif
delete pEffect;
m_SkillEffectArray.erase( m_SkillEffectArray.begin() + i );
OnRemoveState( StateType );
return TRUE;
}
}
return FALSE;
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::ProcessSkillEffect(DWORD dwTick)
{
for( size_t i=0;i!=m_SkillEffectArray.size();++i)
{
SKILL_EFFECT* pEffect = m_SkillEffectArray[i];
pEffect->Process( this, dwTick );
}
#ifdef _NA_007294_20140613_DRAGONKNIGHT_RENEWAL
#else
// 이펙트가 본보다 늦게 따라오는 현상이 있어 AnimateUnit() 뒤로 옴김
UpdateSkillEffectPos();
#endif //_NA_007294_20140613_DRAGONKNIGHT_RENEWAL
UpdateShieldEffect();
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
void Character::UpdateSkillEffectPos()
{
for( size_t i=0;i!=m_SkillEffectArray.size();++i)
{
SKILL_EFFECT *pEffect = m_SkillEffectArray[i];
pEffect->UpdateEffect( this );
}
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::RemoveSkillEffectWithStatus(eCHAR_STATE_TYPE StateType)
{
int iSkillEffectID = -1;
BOOL bForceDestroy = TRUE;
for( size_t i=0;i!=m_SkillEffectArray.size();++i)
{
SKILL_EFFECT* pEffect = m_SkillEffectArray[i];
if (pEffect->dwStatusID == StateType)
{
iSkillEffectID = pEffect->iEffectID;
break;
}
}
// Status 에 해당하는effect를 찾았으면 삭제.
if (iSkillEffectID >= 0)
{
return DeleteSkillEffect(iSkillEffectID);
}
return FALSE;
}
//------------------------------------------------------------------------------
/**
*/
void Character::DoPeriodicDamage(DAMAGETYPE wDamage,DWORD dwTargetKey,DWORD dwTargetHP,DWORD timeSerial,DWORD dwSkillCode)
{
Character* target_character = g_ObjectManager.GetCharacter(dwTargetKey);
if (target_character != NULL)
{
target_character->ProcessReflectDamage();
}
ATTACK_RESULT attret;
ZeroMemory(&attret,sizeof(attret));
attret.SetSkillCode(dwSkillCode);
attret.SetTimeSerial(timeSerial);
attret.GetTargetData().SetTargetObjectKey( dwTargetKey );
attret.GetTargetData().SetTargetHP( dwTargetHP );
#ifdef _NA_006638_20120415_ADD_SHIELD_INFO_IN_TARGET_INFO
if (target_character && target_character->IsKindOfObject(PLAYER_OBJECT))
{
attret.GetTargetData().SetTargetSD(target_character->GetSD());
}
#endif //_NA_006638_20120415_ADD_SHIELD_INFO_IN_TARGET_INFO
attret.GetTargetData().SetDamage( wDamage );
attret.GetTargetData().AddAdditionalEffect( ATTACK_ADDITIONAL_EFFECT_DONOTPLAYANIMATION );
_ProcessAttackResult(&attret);
}
//------------------------------------------------------------------------------
void Character::AddReflectDamage(DAMAGETYPE damage, DWORD target_object_key, DWORD target_hp, DWORD time_serial, DWORD skill_code)
{
ATTACK_RESULT attret;
ZeroMemory(&attret, sizeof(attret));
attret.SetSkillCode(skill_code);
attret.SetTimeSerial(time_serial);
attret.GetTargetData().SetTargetObjectKey( target_object_key );
attret.GetTargetData().SetTargetHP( target_hp );
#ifdef _NA_006638_20120415_ADD_SHIELD_INFO_IN_TARGET_INFO
Character* target_character = g_ObjectManager.GetCharacter(target_object_key);
if (target_character && target_character->IsKindOfObject(PLAYER_OBJECT))
{
attret.GetTargetData().SetTargetSD(target_character->GetSD());
}
#endif //_NA_006638_20120415_ADD_SHIELD_INFO_IN_TARGET_INFO
attret.GetTargetData().SetDamage( damage );
attret.GetTargetData().AddAdditionalEffect( ATTACK_ADDITIONAL_EFFECT_DONOTPLAYANIMATION );
m_ReflectDamageList.push_back(attret);
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetFightingEnergy(int count)
{
m_iFightingEnergy = count;
}
//------------------------------------------------------------------------------
/**
*/
int Character::GetFightingEnergy()
{
return m_iFightingEnergy;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetIdleAnimation()
{
WzID animID;
WzID currentanimID;
currentanimID = GetCurrentAnimation();
// 어택스탠드 때문에 지속적으로 애니메이션세팅을 다시해준다.
animID = GetCurrentIdleAnimation();
if( animID != currentanimID )
{
SetAnimation( animID, TRUE );
// 0이 아니었으면 Blend
if (currentanimID != 0)
{
GetBasePart()->SetInterpolationFrame(6);
}
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetMoveAnimation()
{
WzID animID;
// 어택스탠드 때문에 지속적으로 애니메이션세팅을 다시해준다.
animID = GetCurrentMoveAnimation();
if (animID != GetCurrentAnimation())
{
SetAnimation( animID, TRUE );
}
}
//-------------------------------------------------------------------------------------------
/**
*/
void Character::SetRunAwayAnimation()
{
WzID animID;
// 어택스탠드 때문에 지속적으로 애니메이션세팅을 다시해준다.
animID = GetCurrentRunAwayAnimation();
if (animID != GetCurrentAnimation())
{
SetAnimation( animID, TRUE );
};
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::GetAttackTargetList(DWORD dwAttackSerial,int *pNum,DWORD *pTarget, int target_buffer_size)
{
ATTACK_RESULT_LIST::iterator itr,tempitr;
itr = m_AttackResultList.begin();
BOOL bFind = FALSE;
int iCount = 0;
while(itr != m_AttackResultList.end())
{
if (itr->GetAttackSerial() == dwAttackSerial)
{
pTarget[iCount] = itr->GetTargetData().GetTargetObjectKey();
iCount++;
if (iCount >= target_buffer_size - 1)
{
break;
}
}
itr++;
}
*pNum = iCount;
return (iCount ? TRUE : FALSE);
}
//------------------------------------------------------------------------------
/**
*/
void Character::OnStartMove()
{
;
}
//------------------------------------------------------------------------------
/**
*/
void Character::OnStartRun()
{
;
}
//------------------------------------------------------------------------------
/**
*/
void Character::OnAttack(DWORD dwSkillCode)
{
}
//------------------------------------------------------------------------------
/**
*/
void Character::OnDamage(const DAMAGE_PRAM &rDamage)
{
BASE_SKILLINFO *pInfo = SkillInfoParser::Instance()->GetSkillInfo((SLOTCODE)rDamage.pResult->GetSkillCode());
if(pInfo)
{
SkillEffectFunc::CreateSkillEventEffect( pInfo->m_SkillClassCode, this, cSkillEventEffectInfoData::EVENT_TYPE_DAMAGE );
}
WzVector wvEffectPos = GetArrowTargetPos();
wvEffectPos.z += GetHeight();
#ifndef _PERF_DEBUG
if(pInfo)
{
switch (pInfo->m_SkillClassCode)//스킬에 따른 이펙트 처리
{
case eSKILL_FIRE_ARROW://불계열
case eSKILL_FIRE_BALL:
case eSKILL_FIRE_SPEAR:
case eSKILL_ETHER_BLASE:
case eSKILL_HEAL_MAGIC_ARRAY:
case eSKILL_STAR_FALL:
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("F020"),wvEffectPos,rDamage.dwObjKey,GetObjectKey());
break;
case eSKILL_BEAST_MASTER_DEADLY_STRIKE:
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("F020"),wvEffectPos,rDamage.dwObjKey,GetObjectKey());
// 스파크
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("A004"),wvEffectPos,rDamage.dwObjKey,GetObjectKey());
// 피
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("A007"),wvEffectPos,rDamage.dwObjKey,GetObjectKey());
// 백쇼크
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("A009"),wvEffectPos,rDamage.dwObjKey,GetObjectKey());
break;
case eSKILL_ICE_DAGGER://얼음 계열
case eSKILL_ICE_DAGGER2:
case eSKILL_ICE_BLAST:
case eSKILL_ICE_BOLT:
case eSKILL_PRESSING_WALL:
case eSKILL_FROZON_SHIELD:
case eSKILL_FROZEN_ARROW:
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("F030"),wvEffectPos,rDamage.dwObjKey,GetObjectKey());
break;
case eSKILL_INQUIRY:
case eSKILL_WIND_BOLT: //라이팅 계열
case eSKILL_HEAVY_SHOT:
case eSKILL_LIGHTING:
case eSKILL_SHOCKWAVE:
case eSKILL_LIGHTING_WAVE:
case eSKILL_ELECTRIC_FIELD:
case eSKILL_WIND_SHIELD:
case eSKILL_ARCHBISHOP_OF_DARKNESS_DOOM:
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("F040"),wvEffectPos,rDamage.dwObjKey,GetObjectKey());
break;
case eSKILL_POISON_THORN: //독 계열
case eSKILL_SONY_VINE:
case eSKILL_POISON_RAIN:
case eSKILL_POWER_WAVE: //?
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("F011"),wvEffectPos,rDamage.dwObjKey,GetObjectKey());
break;
}
}
#endif
WzVector vScale = c_UnitVector;
if ( rDamage.pResult->GetTargetData().CheckAdditionalEffect( ATTACK_ADDITIONAL_EFFECT_CRITICAL) == FALSE )
{
SetVector(&vScale, 0.5f, 0.5f, 0.5f);
}
if ( rDamage.pResult->GetTargetData().CheckAdditionalEffect( ATTACK_ADDITIONAL_EFFECT_ETHERDEVICE_METAL ) == TRUE )
{
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("E265"), wvEffectPos, vScale);
}
if ( rDamage.pResult->GetTargetData().CheckAdditionalEffect( ATTACK_ADDITIONAL_EFFECT_ETHERDEVICE_ETHER ) == TRUE )
{
GlobalFunc::CreateEffectBeUpToOption(StrToWzID("E270"), wvEffectPos, vScale);
}
}
//-------------------------------------------------------------------------------------------
/**
*/
WzID Character::GetCurrentRunAwayAnimation()
{
return 0;
}
//------------------------------------------------------------------------------
/**
*/
WzID Character::GetCurrentReviveAnimation()
{
return 0;
}
//------------------------------------------------------------------------------
/**
*/
WzID Character::GetCurrentTransFormAnimation()
{
WzID animationID = 0;
char szAniCode[5];
ZeroMemory(szAniCode,sizeof(szAniCode));
{
szAniCode[0] = 'T';
szAniCode[1] = '0';
szAniCode[2] = '0';
szAniCode[3] = '1';
}
animationID = StrToWzID(szAniCode);
return animationID;
}
//------------------------------------------------------------------------------
/**
*/
WzID Character::GetCurrentBlockAnimation()
{
return 0;
}
//------------------------------------------------------------------------------
/**
*/
WzID Character::GetCurrentCamAnimation()
{
return 0;
}
//------------------------------------------------------------------------------
/**
*/
WzID Character::GetCurrentAttackJumpAnimation()
{
return 0;
}
//------------------------------------------------------------------------------
/**
*/
WzID Character::GetCurrentKnockBack2Animation()
{
return 0;
}
//------------------------------------------------------------------------------
/**
*/
void Character::OnMiss(BOOL bCreateDamageMesh)
{
SetAttackStandTime(ATTACK_STAND_TIME);
WzColor popupcolor;
if (IsKindOfObject(MONSTER_OBJECT))
{
popupcolor = c_MonsterHPDamageColor;
}
else
{
popupcolor = c_PlayerHPDamageColor;
}
if (bCreateDamageMesh)
{
CreatePopupMesh(0, 0, eDAMAGEPOPUP_BLOCK, popupcolor, FALSE, FALSE);
}
PlayBlockAnimation();
}
//------------------------------------------------------------------------------
/**
*/
void Character::OnUseSkill()
{
return;
}
//------------------------------------------------------------------------------
/**
*/
void Character::OnShotFire(int iShotCount)
{
return;
}
//------------------------------------------------------------------------------
/**
*/
void Character::OnShotEnd()
{
return;
}
//------------------------------------------------------------------------------
/**
*/
void Character::RenderTextOnHead(TCHAR *szString,WzColor color,int yoffset,BOOL bForceRender, bool bIsCharacterScene)
{
if ((GameFramework::GetCurrentScene()->GetType() == SCENE_TYPE_SSQ)
#ifdef _NA_004756_120504_SHOW_SSQ_PLAYER_NAME
&& ((g_pHero->IsGM() == FALSE) || (GENERALPARAM->IsShowSSQPlayerName() == FALSE))
#endif //_NA_004756_120504_SHOW_SSQ_PLAYER_NAME
)
{
return;
}
// 강제로 랜더링 하는 경우가 아니라면, 대화를 표시하고 있는경우 패스
if ( GetChatDisplayTime() && !bForceRender)
{
return;
}
if (m_bObserverMode)
{
return;
}
if (g_InterfaceManager.GetShowFlag() || bForceRender)
{
float fDepth;
WzVector wzVisualPos = GetVisiblePos();
WzColor oldcolor = g_pSunRenderer->GetDiffuseColor();
g_pSunRenderer->Set2DMode(TRUE);
g_pSunRenderer->x_pManagerTextOut->StartToUseFont(StrToWzID("m217"));
//WzVector wzPos = GetPosition();
wzVisualPos.z += GetMeshHeight();
wzVisualPos.z += HEIGHT_GAP;
//if (is_spread_wings())
//{
// //! 날개 상태이면 위로 좀더 올려 준다.
// wzVisualPos.z += 1.4f;
//}
POINT pt2;
g_pSunRenderer->GetScreenPos( &pt2, &wzVisualPos ,&fDepth);
RECT rc;
SIZE textsize;
g_pSunRenderer->x_pManagerTextOut->GetTextExtentPoint(szString, lstrlen(szString), &textsize);
rc.left = pt2.x - (textsize.cx / 2);
if (IsKindOfObject(MONSTER_OBJECT))
rc.top = pt2.y + (yoffset * textsize.cy) - 22;
else
rc.top = pt2.y + (yoffset * textsize.cy)-1;
if (bIsCharacterScene && (rc.top < 0))
rc.top = (yoffset * textsize.cy);
rc.right = rc.left + textsize.cx;
rc.bottom = rc.top + 50;
WzColor BackColor = WzColor_RGBA(0,0,0,100);
if( m_bShowName)
RenderBlockedText(szString,&rc,color,BackColor);
else
{
if(TRUE == this->IsKindOfObject(PLAYER_OBJECT))
{
Player* pPlayer = (Player*)this;
if( pPlayer->IsShowVedorTitle() && pPlayer->GetBeHaveState() == PLAYER_BEHAVE_VENDOR_ESTABLISHER_STATE )
{
RenderBlockedTextWithDepthTest(szString,&rc,color,BackColor,fDepth,false);
}
else
{
RenderBlockedTextWithDepthTest(szString,&rc,color,BackColor,fDepth,true);
}
}
else
{
RenderBlockedTextWithDepthTest(szString,&rc,color,BackColor,fDepth,false);
}
}
g_pSunRenderer->x_pManagerTextOut->EndUseFont();
g_pSunRenderer->Set2DMode( FALSE );
g_pSunRenderer->SetColor(oldcolor);
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::CreateEffectAtHead(WzID effectID,float fHeight)
{
WzVector wvEffectPos = GetVisiblePos();
wvEffectPos.z += fHeight;
wvEffectPos.z += m_fHeight;
GlobalFunc::CreateEffectBeUpToOption(effectID,wvEffectPos,GetObjectKey());
}
//------------------------------------------------------------------------------
/**
*/
void Character::RenderInfo()
{
Object::RenderInfo();
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::IsRangedNormalAttack()
{
return FALSE;
}
//------------------------------------------------------------------------------
/**
*/
WzVector Character::GetArrowBonePos(int index)
{
return GetVisiblePos();
}
//------------------------------------------------------------------------------
/**
*/
WzVector Character::GetHandBonePos(int index)
{
WzVector ret = GetVisiblePos();
int boneindex = -1;
if (!IsAnimated())
{
AnimateUnit();
}
if (GetBasePart())
{
if (GetBasePart()->GetWzUnit())
{
WzBoneInfo *pInfo;
if(index)//오른손
{
pInfo= GetBasePart()->GetWzUnit()->GetBoneInfo(StrToWzID("RHND"));
}
else
{
pInfo= GetBasePart()->GetWzUnit()->GetBoneInfo(StrToWzID("LHND"));
}
if (pInfo)
{
boneindex = pInfo->m_iNode;
}
}
}
if (boneindex != -1)
{
CWzUnitDraw *pSkeleton = GetBasePart();
if (pSkeleton)
{
WzMatrix *pBoneMatrix = pSkeleton->GetTransformBuffer();
if (pBoneMatrix)
{
WzVector vPos;vPos.x = vPos.y = vPos.z = 0.0f;
GameFunc::GetBonePos( GetBasePart(), boneindex, &vPos);
ret.x = vPos.x;
ret.y = vPos.y;
ret.z = vPos.z;
}
}
}
return ret;
}
WzVector Character::GetWeaponBonePos(int index)
{
WzVector ret = GetVisiblePos();
int boneindex = -1;
if (!IsAnimated())
{
AnimateUnit();
}
if (GetBasePart())
{
if (GetBasePart()->GetWzUnit())
{
WzBoneInfo *pInfo = GetBasePart()->GetWzUnit()->GetBoneInfo(StrToWzID("ARRW"));//일반적인 무기본은 고정하고 쓰자.
if (pInfo)
{
boneindex = pInfo->m_iNode;
}
}
}
if (boneindex != -1)
{
CWzUnitDraw *pSkeleton = GetBasePart();
if (pSkeleton)
{
WzMatrix *pBoneMatrix = pSkeleton->GetTransformBuffer();
if (pBoneMatrix)
{
WzVector vPos;vPos.x = vPos.y = vPos.z = 0.0f;
GameFunc::GetBonePos( GetBasePart(), boneindex, &vPos);
ret.x = vPos.x;
ret.y = vPos.y;
ret.z = vPos.z;
}
}
}
return ret;
}
//------------------------------------------------------------------------------
bool Character::GetBodyBonePos(OUT WzVector* pos)
{
int boneindex = -1;
if (GetBasePart() && GetBasePart()->GetWzUnit())
{
WzID wiBodyID = StrToWzID("BODY");
WzBoneInfo *pInfo = GetBasePart()->GetWzUnit()->GetBoneInfo(wiBodyID);
if ((pInfo != NULL) && (pInfo->m_wiBone == wiBodyID))
{
boneindex = pInfo->m_iNode;
}
}
if ((boneindex != -1) && (GetBasePart() != NULL) && (GetBasePart()->GetTransformBuffer() != NULL))
{
if (pos != NULL)
{
WzVector vPos;vPos.x = vPos.y = vPos.z = 0.0f;
if(GameFunc::GetBonePos( GetBasePart(), boneindex, &vPos) == FALSE )
{
return false;
}
(*pos).x = vPos.x;
(*pos).y = vPos.y;
(*pos).z = vPos.z;
}
return true;
}
return false;
}
//------------------------------------------------------------------------------
WzVector Character::GetBodyPos()
{
WzVector ret;
if (GetBodyBonePos(&ret) == false)
{
// 본이 없을때는 현재 위치에서 메쉬 높이의 1/2 만큼 올린다.
ret = GetVisiblePos();
ret.z += (GetMeshHeight() * 0.5f);
}
return ret;
}
//------------------------------------------------------------------------------
/**
*/
DWORD Character::GetTerrainAttribute()
{
return m_dwTerrainAttribute;
}
//------------------------------------------------------------------------------
/**
*/
void Character::OnFootStep(BOOL b2D /*=FASLE*/)
{
Object::OnFootStep();
}
//------------------------------------------------------------------------------
float Character::GetWaterEffectSizeFromBoundingVolume()
{
WzBoundingVolume* bv = GetBoundingVolume();
if (bv != NULL)
{
if (bv->m_eBvType == BVT_AABB)
{
WzVector diff = bv->m_aabb.m_wvMax - bv->m_aabb.m_wvMin;
diff.z = 0;
return VectorLength(&diff);
}
else if (bv->m_eBvType == BVT_SPHERE)
{
return bv->m_BvSphere.m_fRadius * 2.0f;
}
}
return 1.0f;
}
//------------------------------------------------------------------------------
/**
*/
float Character::GetAngleForMoveDirection()
{
return Math_GetAngleFromVector( &GetDirection() );
}
void Character::OnWaterWave()
{
if( m_dwTerrainAttribute == eTERRAIN_ATTRIBUTE_WATER )
{
WzVector vPos = GetWaterTerrainPos();
HANDLE hWaterWave = GlobalFunc::CreateEffectBeUpToOption( StrToWzID("I690"), vPos, GetObjectKey() );
CEffectBody * pBody = g_pEffectManager->GetEffectPtrHandle( hWaterWave );
if( pBody )
{
WzVector vRot;
vRot.x = 0.0f;
vRot.z = GetAngleForMoveDirection();
vRot.y = 0.0f;
WzVector vScale;
float effect_scale = GetWaterEffectSizeFromBoundingVolume();
SetVector(&vScale, effect_scale, effect_scale, effect_scale);
pBody->SetResultMatrix( vPos, vRot, vScale );
}
}
}
WzVector Character::GetWaterTerrainPos()
{
WzVector vPos = GetVisiblePos();
WzVector vTemp;
SetVector( &vTemp, 0.0f, 0.0f, 0.0f );
GameFunc::PickTerrainMesh( vPos, vTemp, TMGO_SPECULAR, GetMeshHeight() );
return vTemp;
}
void Character::OnWaterEllipse()
{
if( m_dwTerrainAttribute == eTERRAIN_ATTRIBUTE_WATER )
{
WzVector vPos = GetWaterTerrainPos();
CEffectBody * pBody = g_pEffectManager->GetEffectPtrHandle( m_hWaterEllipse );
if( pBody == NULL )
{
m_hWaterEllipse = GlobalFunc::CreateEffectBeUpToOption( StrToWzID("I691"), vPos, GetObjectKey() );
pBody = g_pEffectManager->GetEffectPtrHandle( m_hWaterEllipse );
}
if(pBody)
{
WzVector vRot, vScale;
float effect_scale = GetWaterEffectSizeFromBoundingVolume();
SetVector( &vRot, 0.0f, 0.0f, 0.0f );
SetVector(&vScale, effect_scale, effect_scale, effect_scale);
pBody->SetResultMatrix( vPos, vRot, vScale );
if( GetCurState() == STATE::KEYBOARDJUMP )
{
pBody->SetShow( FALSE );
}
else
{
pBody->SetShow( TRUE );
}
}
}
else
{
CEffectBody * pBody = g_pEffectManager->GetEffectPtrHandle( m_hWaterEllipse );
if( pBody )
{
WzVector vPos = GetWaterTerrainPos();
WzVector vRot, vScale;
SetVector( &vRot, 0.0f, 0.0f, 0.0f );
SetVector( &vScale, 1.0f, 1.0f, 1.0f );
pBody->SetResultMatrix( vPos, vRot, vScale );
pBody->SetShow( FALSE );
}
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::CreatePopupMesh(
CODETYPE SkillCode,
INT64 iNumber,
eDAMAGEPOPUP_KIND eKind,
WzColor color,
BOOL bCritical,
BOOL bDoubleDamage,
float fMultiplier,
int iSecondary,
WzColor secondarycol,
float fHeight,
BOOL bHero /*= FALSE*/
)
{
DAMAGE_POPUP popup;
popup.dTime = 0;
popup.vPos = GetVisiblePos();
float fMeshHeight;
fMeshHeight = GetMeshHeight();
WzVector wzScale = {1.f, 1.f, 1.f};
// 데미지가 너무 높은곳에서 나와서 안보이는일이 없도록함
if (fMeshHeight >= 3.5f)
{
fMeshHeight = 3.5f;
}
else
{
GetScale(&wzScale);
}
//* wzScale.z
popup.vPos.z += fMeshHeight ;
popup.vPos.z += fHeight;
popup.SkillCode = SkillCode;
popup.bHero = bHero;
popup.iNumber = iNumber;
popup.iNumber2 = iSecondary;
popup.Color = color;
popup.Color2 = secondarycol;
popup.eKind = eKind;
popup.bCritical = bCritical;
popup.fMultiplier = fMultiplier;
popup.bDoubleDamage = bDoubleDamage;
g_InterfaceManager.AddDamageList(popup);
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetMeshHeight(float fMeshHeight)
{
m_fMeshHeight = fMeshHeight;
}
//------------------------------------------------------------------------------
/**
*/
float Character::GetMeshHeight()
{
return m_fMeshHeight;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetStandAnimationDelay()
{
const int STAND_ANIMATION_MINIMUM_DELAY = 8000;
const int STAND_ANIMATION_DELAY_VARIATION = 7000;
m_dwStandAnimDelay =
STAND_ANIMATION_MINIMUM_DELAY + rand() % STAND_ANIMATION_DELAY_VARIATION;
}
int Character::GetSkillEffectCount(DWORD status_code)
{
int count = 0;
for( size_t i=0;i!=m_SkillEffectArray.size();++i)
{
SKILL_EFFECT* effect = m_SkillEffectArray[i];
if( effect->dwStatusID == status_code )
{
++count;
}
}
return count;
}
//------------------------------------------------------------------------------
/**
*/
float Character::GetArrowTargetHeight()
{
return (GetMeshHeight() * 3.0f / 5.0f);
}
//------------------------------------------------------------------------------
/**
*/
WzVector Character::GetArrowTargetPos()
{
return GetBodyPos();
}
//------------------------------------------------------------------------------
/**
*/
void Character::OnShotStart()
{
return;
}
//------------------------------------------------------------------------------
/**
*/
int Character::GetBoneIndex(BYTE byType)
{
int boneindex = -1;
if (!IsAnimated())
{
AnimateUnit();
}
WzID id=0;
switch (byType)
{
case eSKILLEFFECT_POS_HEAD:
{
id = StrToWzID("HEAD");
}
break;
case eSKILLEFFECT_POS_RHAND:
{
id=StrToWzID("RHND");
}
break;
case eSKILLEFFECT_POS_LHAND:
{
id=StrToWzID("LHND");
}
break;
case eSKILLEFFECT_POS_WEAPON:
{
id=StrToWzID("ARRW");
}
break;
case eSKILLEFFECT_POS_BODY:
{
id=StrToWzID("BODY");
}
break;
case eSKILLEFFECT_POS_BOTTOM:
{
id=StrToWzID("BTTM");
}
break;
case eSKILLEFFECT_POS_BUST:
{
id=StrToWzID("BUST");
}
break;
case eSKILLEFFECT_ONLY_POS:
{
return -1;
}
break;
}
if (GetBasePart())
{
if (GetBasePart()->GetWzUnit())
{
WzBoneInfo *pInfo = GetBasePart()->GetWzUnit()->GetBoneInfo(id);//일반적인 무기본은 고정하고 쓰자.
if (pInfo)
{
boneindex = pInfo->m_iNode;
}
}
}
return boneindex;
}
//------------------------------------------------------------------------------
int Character::GetBoneIndexByWzID(WzID bone_id)
{
if (!IsAnimated())
{
AnimateUnit();
}
if (GetBasePart() && GetBasePart()->GetWzUnit())
{
WzBoneInfo *pInfo = GetBasePart()->GetWzUnit()->GetBoneInfo(bone_id);
if (pInfo)
{
return pInfo->m_iNode;
}
}
return -1;
}
//------------------------------------------------------------------------------
WzVector Character::GetSkillEffectRotate(SKILL_EFFECT* skill_effect)
{
if (skill_effect->bApplyParentRotate)
{
WzVector rotate;
rotate.y = 0.0f;
rotate.z = GetAngle();
rotate.x = GetAngleX();
return rotate;
}
return c_ZeroVector;
}
//------------------------------------------------------------------------------
WzVector Character::GetSkillEffectScale(SKILL_EFFECT* skill_effect)
{
if (skill_effect->bApplyParentScale)
{
return GetScale();
}
return c_UnitVector;
}
//------------------------------------------------------------------------------
WzVector Character::GetSkillEffectPos(SKILL_EFFECT* skill_effect)
{
return (GetSkillEffectPos(skill_effect->effect_position_type, skill_effect->effect_position_bone_index ) + skill_effect->effect_position_offset);
}
//------------------------------------------------------------------------------
/**
*/
WzVector Character::GetSkillEffectPos( eSKILLEFFECT_POS position_type, int bone_index )
{
if( position_type == eSKILLEFFECT_POS_BONE_INDEX )
return GetBonePos( bone_index );
switch (position_type)
{
default:
case eSKILLEFFECT_POS_HEAD:
{
WzVector vPos = GetVisiblePos();
float fMeshHeight = GetMeshHeight();
vPos.z += fMeshHeight;
return vPos;
}
break;
case eSKILLEFFECT_TARGET_POS:
{
Character *pTarget = (Character *)GetTargetObject();
if(pTarget)
return pTarget->GetVisiblePos();
else
return GetVisiblePos();
}
break;
case eSKILLEFFECT_POS_BODY:
{
return GetBodyPos();
}
break;
//case eSKILLEFFECT_ONLY_POS:
case eSKILLEFFECT_POS_FOOT:
{
return GetVisiblePos();
}
break;
case eSKILLEFFECT_POS_RHAND:
{
return GetHandBonePos(1);
}
break;
case eSKILLEFFECT_POS_LHAND:
{
return GetHandBonePos(0);
}
break;
case eSKILLEFFECT_POS_WEAPON:
{
return GetWeaponBonePos(0);
}
break;
case eSKILLEFFECT_ONLY_POS:
{
WzVector picked_position;
GameFunc::PickTerrainMesh(GetVisiblePos(), picked_position, TMGO_NO_COLLISION, 0.5f);
return picked_position;
}
break;
case eSKILLEFFECT_POS_NONE:
{
return GetVisiblePos();
}
break;
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::AddTargetingCount(DWORD dwTargeter)
{
list<DWORD>::iterator iter;
iter = m_listTargeter.begin();
for (;iter != m_listTargeter.end(); iter++)
{
if (dwTargeter == *iter)
{
return;
}
}
m_listTargeter.push_back(dwTargeter);
}
//------------------------------------------------------------------------------
/**
*/
void Character::RemoveTargetingCount(DWORD dwTargeter)
{
list<DWORD>::iterator iter;
iter = m_listTargeter.begin();
for (;iter != m_listTargeter.end(); iter++)
{
if (dwTargeter == *iter)
{
m_listTargeter.erase(iter);
break;
}
}
}
//------------------------------------------------------------------------------
/**
*/
int Character::GetTargetingCount()
{
return m_listTargeter.size();
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetMoveTarget(DWORD dwMoveTarget)
{
m_dwMoveTarget = dwMoveTarget;
}
//------------------------------------------------------------------------------
/**
*/
DWORD Character::GetMoveTarget()
{
return m_dwMoveTarget;
}
//------------------------------------------------------------------------------
/**
*/
void Character::OnDead()
{
ReleaseMoveTarget();
#ifdef _NA_007113_SHADOW_PATCH_UNTARGET_MONSTER_DIE
ReleaseHeroTarget();
#endif //_NA_007113_SHADOW_PATCH_UNTARGET_MONSTER_DIE
}
void Character::ReleaseHeroTarget()
{
DWORD TargetObjectKey = g_HeroInput.GetCurrentTarget();
if( GetObjectKey() == TargetObjectKey )
{
g_HeroInput.SetCurrentTarget(0);
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::ReleaseMoveTarget()
{
if (m_dwMoveTarget)
{
Character *pChr = (Character *)g_ObjectManager.GetObject(m_dwMoveTarget);
if (pChr)
{
pChr->RemoveTargetingCount(GetObjectKey());
}
m_dwMoveTarget = 0;
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetStartMoveTime( DWORD dwTime )
{
m_dwStartMoveTime = dwTime;
}
//------------------------------------------------------------------------------
/**
*/
DWORD Character::GetStartMoveTime( void )
{
return m_dwStartMoveTime;
}
//------------------------------------------------------------------------------
/**
*/
void Character::OnParalyzed()
{
StopMove();
}
//------------------------------------------------------------------------------
/**
*/
BOOL Character::IsInNotprocessedList(DWORD dwAttackSerial)
{
return FALSE;
}
//------------------------------------------------------------------------------
/**
*/
void Character::RemoveNotprocessedList(DWORD dwAttackSerial)
{
}
//------------------------------------------------------------------------------
/**
*/
void Character::AddNotprocessedList(DWORD dwAttackSerial)
{
m_vNotProcessedList.push_back(dwAttackSerial);
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetNextActionAttackSerial(DWORD dwAttackSerial)
{
m_dwNextActionAttackSerial = dwAttackSerial;
}
//------------------------------------------------------------------------------
/**
*/
DWORD Character::GetNextActionAttackSerial()
{
return m_dwNextActionAttackSerial;
}
//------------------------------------------------------------------------------
/**
*/
WzVector Character::GetHeadBonePos()
{
return GetBonePos(7);
}
//------------------------------------------------------------------------------
/**
*/
void Character::ApplyTerrainColor(BOOL bApply)
{
#ifdef _PERF_DEBUG
return;
#endif
int iAlpha = 255;
if (m_bFade)
{
float fAlpha= (float)m_iFadeCurDelay / (float)m_iFadeTotDelay;
fAlpha = 255.0f * fAlpha;
iAlpha=(int)fAlpha;
}
iAlpha=min(iAlpha,255);
if (m_pPathExplorer && bApply)
{
if (m_pPathExplorer->GetTerrainMesh() != -1)
{
if (g_pMap)
{
if (g_pMap->IsLoaded())
{
int iR,iG,iB;
float fT = 10.0f;
m_vNormal = c_ZeroVector;
#if( WZENGINEVER >= 290 )
// 캐릭터가 딛고 있는 메쉬를 찾는다.
// 캐릭터의 (위치+키높이)에서 아래방향으로 지형메쉬를 찾음.
WzVector visible_position = GetVisiblePos();
float character_height = GetMeshHeight();
if (character_height < 1.0f)
{
character_height = 1.0f;
}
int mesh = g_pMap->GetWorldBase()->PathExp_GetMeshToStand(visible_position, &fT, 5.0f,0,&m_vNormal, character_height);
#else
int mesh = g_pMap->GetWorldBase()->PathExp_GetMeshToStand(m_pPathExplorer->GetPos(), &fT, 5.0f,0,&m_vNormal);
#endif
int meshtexture = -1;
if (mesh != -1)
{
meshtexture = g_pMap->GetWorldBase()->GetTextureIndexOfTerrainMesh(mesh);
}
if (meshtexture != -1) {
m_dwTerrainAttribute = g_pMap->GetWorldBase()->GetTerrainMeshUserOption(meshtexture);
}
if ( mesh < 0 || fT > 5.0f)
{
// 밑에 없거나 거리가 5m 이상인 경우 무시
}
else
{
float fWeight = GRAPHICPARAM->GetTerrainColorRate();
WzColor color = g_pMap->GetWorldBase()->GetTerrainLight(m_pPathExplorer->GetPos(),mesh);
float degree = acos(m_vNormal.z);
degree=n_rad2deg(degree);
if(degree<20.0f)
{
iR = int( Red_WzColor(color) * fWeight + (float)255 * (1.0f - fWeight) );
iG = int( Green_WzColor(color) * fWeight + (float)255 * (1.0f - fWeight) );
iB = int( Blue_WzColor(color) * fWeight + (float)255 * (1.0f - fWeight) );
SetColor(iR,iG,iB,iAlpha);
}
}
}
}
}
}
//서있는 곳이 없거나 길찾기가 없을 서있는 면이 90도 보다 클경우 칼라가 없을수도 있다.
WzColor LastColor = GetColor();
SetColor(Red_WzColor(LastColor),Green_WzColor(LastColor),Blue_WzColor(LastColor),iAlpha);
}
//-------------------------------------------------------------------------------------------
/**
*/
int Character::GetEmoticonIcon() const
{
return m_iEmoteIcon;
}
//------------------------------------------------------------------------------
/**
*/
void Character::ShowEmoticonIcon(int iEmote,int iDelay)
{
m_iEmoteIconDelay = iDelay;
if (0 == iEmote && m_pEmoteDraw)
{
m_iEmoteIcon = iEmote;
ResourceManager::Instance()->FreeResourceUnitDraw(m_pEmoteDraw);
m_pEmoteDraw = NULL;
}
else
if (m_iEmoteIcon != iEmote)
{
m_iEmoteIcon = iEmote;
if (m_iEmoteIcon)
{
BASE_HeadMeshInfo *pInfo = HeadMeshInfoParser::Instance()->GetHeadMeshInfo(m_iEmoteIcon);
if (pInfo)
{
if (m_pEmoteDraw)
{
ResourceManager::Instance()->FreeResourceUnitDraw(m_pEmoteDraw);
m_pEmoteDraw = NULL;
}
m_pEmoteDraw = ResourceManager::Instance()->AllocResourceUnitDraw(pInfo->m_dwIcon + ENGINE_RESOURCE_ID_OFFSET);
if (m_pEmoteDraw->GetWzUnit() != NULL)
{
int iAniCnt = m_pEmoteDraw->GetWzUnit()->GetCountAnimationInfo();
if (iAniCnt > 0)
{
WzAnimationInfo * pwzAniInfo = m_pEmoteDraw->GetWzUnit()->GetAnimationInfoByIndex(0);
if (pwzAniInfo)
{
pwzAniInfo->m_wiAction;
m_pEmoteDraw->SetCurrentAnimation( pwzAniInfo->m_wiAction, TRUE );
}
}
}
}
}
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::ProcessEmoteDelay(DWORD dwTick)
{
if (m_iEmoteIconDelay > 0 )
{
m_iEmoteIconDelay -= dwTick;
if (m_iEmoteIconDelay <= 0)
{
FreeEmoteIcon();
}
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::FreeEmoteIcon()
{
m_iEmoteIcon = 0;
m_iEmoteIconDelay = 0;
if (m_pEmoteDraw)
{
ResourceManager::Instance()->FreeResourceUnitDraw(m_pEmoteDraw);
m_pEmoteDraw = NULL;
}
}
//------------------------------------------------------------------------------
/**
*/
void Character::StopVoice()
{
if (m_iVoiceHandle != -1)
{
g_SoundEffect.StopVoice(m_iVoiceHandle);
m_iVoiceHandle = -1;
}
}
//----------------------------------------------------------------------------
/**
*/
BOOL Character::CanUseSkillLimitMP(SLOTCODE skillID, BOOL bShowFailMessage /*= FALSE*/)
{
TCHAR szFailMessage[INTERFACE_STRING_LENGTH];
BASE_SKILLINFO *pInfo = SkillInfoParser::Instance()->GetSkillInfo(skillID);
assert(pInfo);
if (!pInfo)
{
return FALSE;
}
if (GetMP() < pInfo->m_wMPSpend)
{
if (bShowFailMessage)
{
g_InterfaceManager.GetInterfaceString(eST_SKILL_FAIL_NOT_ENOUGH_MP,szFailMessage,INTERFACE_STRING_LENGTH);
GlobalFunc::OutputMsg_Notice(eOUTPUT_MSG_CHAT,szFailMessage);
g_HeroInput.PlayNotEnoughManaSound();
}
return FALSE;
}
return TRUE;
}
//----------------------------------------------------------------------------
/**
*/
BOOL Character::CanUseSkillLimitHP(SLOTCODE skillID, BOOL bShowFailMessage /*= FALSE*/)
{
TCHAR szFailMessage[INTERFACE_STRING_LENGTH];
BASE_SKILLINFO *pInfo = SkillInfoParser::Instance()->GetSkillInfo(skillID);
assert(pInfo);
if (!pInfo)
{
return FALSE;
}
// 여기다가 어빌리티 345에 대한 처리를 해주어야 할 것 같다.
SkillScriptInfo* skill_info_ptr = SkillInfoParser::Instance()->GetSkillInfo(static_cast<SLOTCODE>(skillID));
BASE_ABILITYINFO* ability_info = NULL;
if ( skill_info_ptr )
ability_info = skill_info_ptr->GetAbilityInfoByIndex(0);
if ( ability_info && ability_info->m_wAbilityID == eABILITY_VARIATION_PUREVALUE_HP
&& this == g_pHero)
{
int need_hp = ability_info->m_iParam[1]; // 소모 HP
switch ( ability_info->m_iParam[0] )
{
case VALUE_TYPE_VALUE:
{
// 소모 HP그대로 적용
}
break;
case VALUE_TYPE_PERCENT_PER_CUR:
{
need_hp = static_cast<int>(this->GetHP() * (need_hp / 1000.0f));
}
break;
case VALUE_TYPE_PERCENT_PER_MAX:
{
need_hp = static_cast<int>(this->GetMaxHP() * (need_hp / 1000.0f));
}
break;
case VALUE_TYPE_RATIO_VALUE:
{
// VALUE_TYPE_RATIO_VALUE 주로 데미지 같은데서 사용.
assert(!"345(eABILITY_VARIATION_PUREVALUE_HP) 부적절한 타입");
}
break;
default:
{
// no operator
}
break;
}
need_hp = this->GetHP() + need_hp;
if (need_hp <= 0)
{
TCHAR skill_name[INTERFACE_STRING_LENGTH] = {0, };
g_InterfaceManager.GetInterfaceString(skill_info_ptr->m_dwSkillNcode, skill_name, INTERFACE_STRING_LENGTH);
//7019 %s 스킬을 사용하기엔 체력이 너무 적습니다.
if ( bShowFailMessage )
{
g_InterfaceManager.GetInterfaceStringFormat(szFailMessage,
INTERFACE_STRING_LENGTH,
7019,
skill_name);
GlobalFunc::OutputMsg_Notice(eOUTPUT_MSG_CHAT, szFailMessage);
}
return FALSE;
}
}
// HP제한 체크
if (GetHP() < pInfo->m_wHPSpend)
{
if (bShowFailMessage)
{
g_InterfaceManager.GetInterfaceString(eST_SKILL_FAIL_NOT_ENOUGH_HP,szFailMessage,INTERFACE_STRING_LENGTH);
GlobalFunc::OutputMsg_Notice(eOUTPUT_MSG_CHAT,szFailMessage);
}
return FALSE;
}
return TRUE;
}
//----------------------------------------------------------------------------
/**
*/
BOOL
Character::CanUseSkillLimitCoolTime(SLOTCODE skillID, BOOL bShowFailMessage /*= FALSE*/)
{
TCHAR szFailMessage[INTERFACE_STRING_LENGTH];
BASE_SKILLINFO *pInfo = SkillInfoParser::Instance()->GetSkillInfo(skillID);
assert(pInfo);
if (!pInfo)
{
return FALSE;
}
if ( !g_pHero )
{
return FALSE;
}
util::Timer *pTimer = xGetCooltimeManager()->GetSkillCooltime(skillID);
if (!pTimer) return FALSE;
// 쿨타임이 아직 안지났으면 못쓴다~
if (!pTimer->IsExpired(FALSE))
{
if (bShowFailMessage)
{
g_InterfaceManager.GetInterfaceString(eST_SKILL_FAIL_COOLTIME_NOT_EXPIRED,szFailMessage,INTERFACE_STRING_LENGTH);
GlobalFunc::OutputMsg_Notice(eOUTPUT_MSG_CHAT,szFailMessage);
}
return FALSE;
}
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
float Character::GetRangeWithHero()
{
float fRet = 99999999.9f;
if (g_pHero)
{
WzVector vDiff = GetPosition() - g_pHero->GetPosition();
fRet = VectorLength2(&vDiff);
}
return fRet;
}
//------------------------------------------------------------------------------
/**
*/
int Character::GetShotCount()
{
return 1;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetNoCull(BOOL bFlag)
{
m_bNoCull = bFlag;
}
//------------------------------------------------------------------------------
/**
*/
void Character::SetCurrentMoveSpeed()
{
}
void Character::SetObserverMode( BYTE byObserverMode, BOOL IsHero )
{
m_bObserverMode = byObserverMode;
if( IsHero )
{
if( m_bObserverMode )
{
SetShow( FALSE );
}
else
{
SetShow( TRUE );
}
}
else
{
if( m_bObserverMode )
{
SetShow( FALSE );
}
else
{
SetShow( TRUE );
}
}
}
BOOL Character::IsObserverMode( void )
{
return m_bObserverMode;
}
//------------------------------------------------------------------------------
/**
*/
DWORD Character::GetCurrentTileAtt( BOOL bForce )
{
if( bForce )
{
DWORD dwAtt = Object::GetCurrentTileAtt();
return dwAtt;
}
return m_dwCurTileAtt;
}
//------------------------------------------------------------------------------
/**
*/
DWORD ConvertServerToClientEffect(DWORD dwEffect)
{
DWORD dwTempEffect=0;
if(BIT_CHECK(dwEffect,SKILL_EFFECT_KNOCKBACK))
{
BIT_ADD(dwTempEffect,ATTACK_ADDITIONAL_EFFECT_KNOCKBACK);
}
if(BIT_CHECK(dwEffect,SKILL_EFFECT_KNOCKDOWN))
{
BIT_ADD(dwTempEffect,ATTACK_ADDITIONAL_EFFECT_DOWN);
}
if(BIT_CHECK(dwEffect,SKILL_EFFECT_STUN))
{
BIT_ADD(dwTempEffect,ATTACK_ADDITIONAL_EFFECT_STUN);
}
if(BIT_CHECK(dwEffect,SKILL_EFFECT_CRITICAL))
{
BIT_ADD(dwTempEffect,ATTACK_ADDITIONAL_EFFECT_CRITICAL);
}
return dwTempEffect;
}
//------------------------------------------------------------------------------
/**
*/
RESOURCECODE Character::sTransformData::GetTransFormResourceCode()
{
if( GameFramework::GetCurrentScene()->GetType() == SCENE_TYPE_SSQ )
return 11575;
else
return m_TransFormResourceCode;
}
// [3/10/2011 iforall]
// Player, PlayerMonster 클래스에서 Appearance/Equip 관련 공통코드 가져옴
// 애니매이션/전투/액션 등에 관한 공통코드도 가져온 이후 분리작업 필요
void Character::AnimateUnit()
{
Object::AnimateUnit();
if( GlobalFunc::IsSSQScene() == FALSE )
ProcessFullsetEffect(this);
#ifdef _NA_007294_20140613_DRAGONKNIGHT_RENEWAL
// 이펙트가 본보다 늦게 따라오는 현상이 있어 AnimateUnit() 뒤로 옴김
UpdateSkillEffectPos();
#endif //_NA_007294_20140613_DRAGONKNIGHT_RENEWAL
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
if (GetClass() == eCHAR_WITCHBLADE)
{
ProcessFPFullEffect(this);
UpdateViceSwordWeaponEffect();
}
#endif // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
}
float GetHeightInfo(eCHAR_TYPE class_type,int height_variation)
{
float unit_scale = 1.0f;
if (GlobalFunc::IsSSQScene())
{
return unit_scale;
}
HeroHeightInfoParser* parser_instance = HeroHeightInfoParser::Instance();
BASE_HeroHeightInfo* player_height_info = parser_instance->GetHeroHeightInfo(class_type);
assert(height_variation >= 0 && height_variation < MAX_HEIGHT_VARIATION);
if (player_height_info)
{
unit_scale = player_height_info->m_fHeight[height_variation];
}
return unit_scale;
}
BOOL Character::IsBodyOnlyRenderMode()
{
#ifdef _NA_008679_20160202_REWORK_BATTLEGROUND
if ((GlobalFunc::IsBattleGroundScene() == TRUE) &&
(((GetObjectKey() > ONLYCLIENT_OBJECT_KEY) && (GetObjectKey() < MAX_OBJECT_KEY)) == false) && // 추가 생성된 객체 제외 (순수 사람만)
(IsKindOfObject(PLAYER_OBJECT) == TRUE))
{
SLOTCODE special_item_code = GetSpecialSceneItemCode();
BYTE scene_costume_code = HIBYTE(special_item_code);
BattleGroundCostumeInfo* costume_info =
BattleGroundInfoParser::Instance()->GetBattleGroundCostumeInfo(scene_costume_code, static_cast<eCHAR_TYPE>(GetClass()));
if ((costume_info != NULL) &&
(costume_info->costume_code1 != 0 || costume_info->costume_code2 != 0))
{
// 코스튬 코드가 있는 경우
return TRUE;
}
return FALSE;
}
#endif //_NA_008679_20160202_REWORK_BATTLEGROUND
#ifdef _NA_008069_20150210_ADD_SPA_SYSTEM
if ((GlobalFunc::IsSpaScene() == TRUE) &&
(((GetObjectKey() > ONLYCLIENT_OBJECT_KEY) && (GetObjectKey() < MAX_OBJECT_KEY)) == false) && // 추가 생성된 객체 제외 (순수 사람만)
(IsKindOfObject(PLAYER_OBJECT) == TRUE))
{
return TRUE;
}
#endif //_NA_008069_20150210_ADD_SPA_SYSTEM
#ifdef _NA_004035_20120227_COSTUME_ITEM
if( GetCostumeItemCode() != 0 && GameFramework::GetCurScene() != SCENE_TYPE_SSQ
#ifdef _NA_006683_20130502_EQUIPMENTS_VISIBLE_COSTUME
&& isHideCostume() == false
#endif
)
{
return TRUE;
}
#endif //_NA_004035_20120227_COSTUME_ITEM
return FALSE;
}
void Character::RefreshAppearRender(BOOL refresh_bone /*= FALSE*/)
{
EquipmentContainer* equipment_container = GetEquipmentContainer();
if (equipment_container == NULL)
{
return;
}
if (IsUseDelayLoading() == true)
{
return;
}
APPEARANCEINFO parts_info;
ZeroMemory(&parts_info, sizeof(parts_info));
if (IsTransForm())
{
//용변신상태에서는 RefreshAppearRender 호출되는걸 막아줘야된다
parts_info.ObjectType = APPEARANCEINFO::PLAYERTRANSFORM;
parts_info.resourceCode = GetTransformData().GetTransFormResourceCode();
RefreshRender(&parts_info, refresh_bone);
//SetIdleAnimation();
}
#ifdef _NA_008069_20150210_ADD_SPA_SYSTEM
else if ((GlobalFunc::IsSpaScene() == TRUE) &&
(((GetObjectKey() > ONLYCLIENT_OBJECT_KEY) && (GetObjectKey() < MAX_OBJECT_KEY)) == false) && // 추가 생성된 객체 제외 (순수 사람만)
(IsKindOfObject(PLAYER_OBJECT) == TRUE))
{
//온천외형
RefreshSpaRender(refresh_bone);
}
#endif //_NA_008069_20150210_ADD_SPA_SYSTEM
#ifdef _NA_008679_20160202_REWORK_BATTLEGROUND
else if ((GlobalFunc::IsBattleGroundScene() == TRUE) &&
(((GetObjectKey() > ONLYCLIENT_OBJECT_KEY) && (GetObjectKey() < MAX_OBJECT_KEY)) == false) && // 추가 생성된 객체 제외 (순수 사람만)
(IsKindOfObject(PLAYER_OBJECT) == TRUE))
{
//전장외형
RefreshBattleGroundRender(refresh_bone);
}
#endif //_NA_008679_20160202_REWORK_BATTLEGROUND
#ifdef _NA_004035_20120227_COSTUME_ITEM
else if( GetCostumeItemCode() != 0 && GameFramework::GetCurScene() != SCENE_TYPE_SSQ
#ifdef _NA_006683_20130502_EQUIPMENTS_VISIBLE_COSTUME
&& isHideCostume() == false
#endif
)
{
DWORD class_code = GetClass();
parts_info.ObjectType = APPEARANCEINFO::PLAYER;
parts_info.Job = class_code;
if( const BASE_ITEMINFO* item_info = ItemInfoParser::Instance()->GetItemInfo( (CODETYPE)GetCostumeItemCode() ) )
{
// 머리
parts_info.Equipment[BP_HAIR].dwItemID= GetPartVariation(PLAYER_VARIATION_HAIR);
parts_info.Equipment[BP_HAIR].iEnchant = GetGender() == GenderType::kFemale ? item_info->m_bHeadType1 : item_info->m_bHeadType;
parts_info.Equipment[BP_FACE].dwItemID = GetPartVariation(PLAYER_VARIATION_FACE);
// 방어구
parts_info.Equipment[BP_ARMOR].dwItemID = GetCostumeItemCode();
}
#ifdef _NA_008633_20160104_ADD_DECORATECOSTUME
if ( GetDecorateCostumeItemCode() != 0 )
{
parts_info.Equipment[BP_DECORATE_COSTUME].dwItemID = GetDecorateCostumeItemCode();
}
#endif // _NA_008633_20160104_ADD_DECORATECOSTUME
// 무기
int equip_pos = equipment_container->GetEquipPosByParts(BP_WEAPON);
SCItemSlot& item_slot = static_cast<SCItemSlot&>(equipment_container->GetSlot(equip_pos));
if ( (TRUE == this->IsMyHero()) || (this->GetObjectKey() == EQUIPMENT_CHARACTER_KEY) )
{
ns_formula::EquipSlotsManageInfo* equip_slot_manage_info = g_pHero->GetEquipmentContainer()->GetEquipmentManageInfo();
ns_formula::EquipSlotsManageInfo::Node* it = equip_slot_manage_info->slots;
if (equip_slot_manage_info->slots[equip_pos].activated == true) // 아이템이 비활성화인 경우 적용안함
{
SetEquipAppearInfo( &parts_info.Equipment[BP_WEAPON], item_slot );
}
}
else
{
SetEquipAppearInfo( &parts_info.Equipment[BP_WEAPON], item_slot );
}
// 악세서리(날개)
#ifdef _NA_000000_20120420_EQUIPMENTS_VISIBLE_WING
for( int i=BP_SPECIAL_ACCESSORY1;i<=BP_SPECIAL_ACCESSORY3;++i)
{
int equip_pos = equipment_container->GetEquipPosByParts(i);
SCItemSlot& item_slot = static_cast<SCItemSlot&>(equipment_container->GetSlot(equip_pos));
if ( is_spread_wings() == true && item_slot.IsWingItem() == true )
{
SetEquipAppearInfo(&parts_info.Equipment[i], item_slot);
}
}
#endif//_NA_000000_20120420_EQUIPMENTS_VISIBLE_WING
//파츠 갱신
RefreshRender(&parts_info, refresh_bone);
ReleaseFullsetEffect();
class_code = GetImageClass();
SetScale(GetHeightInfo(static_cast<eCHAR_TYPE>(class_code), GetHeightVariation()));
}
#endif//_NA_004035_20120227_COSTUME_ITEM
else
{
DWORD class_code = GetClass();
parts_info.ObjectType = APPEARANCEINFO::PLAYER;
parts_info.Job = class_code;
for (int parts_position = (BP_BONE + 1); parts_position < BP_COUNT; ++parts_position)
{
int equip_pos = equipment_container->GetEquipPosByParts(parts_position);
//외형에 영향을 주는 파츠가 아니다.
if (equip_pos == EquipmentContainer::EQUIP_MAX)
{
continue;
}
// 슬롯이 비었을경우(헬멧은 예외처리된다)
if (equipment_container->IsEmpty(equip_pos))
{
CheckEmptyHelmet(equip_pos,
parts_info,
GetPartVariation(PLAYER_VARIATION_HAIR),
GetPartVariation(PLAYER_VARIATION_FACE));
continue;
}
SCItemSlot& item_slot = static_cast<SCItemSlot&>(equipment_container->GetSlot(equip_pos));
bool is_visible = false;
if ( (TRUE == this->IsMyHero()) || (this->GetObjectKey() == EQUIPMENT_CHARACTER_KEY) )
{
ns_formula::EquipSlotsManageInfo* equip_slot_manage_info = g_pHero->GetEquipmentContainer()->GetEquipmentManageInfo();
ns_formula::EquipSlotsManageInfo::Node* it = equip_slot_manage_info->slots;
if (equip_slot_manage_info->slots[equip_pos].activated == false) // 아이템이 비활성화인 경우 적용안함
{
CheckEmptyHelmet(equip_pos,
parts_info,
GetPartVariation(PLAYER_VARIATION_HAIR),
GetPartVariation(PLAYER_VARIATION_FACE));
continue;
}
}
//헬멧일 경우는 예외처리
if (equip_pos == EquipmentContainer::EQUIP_HELMET)
{
SetEquipAppearHelmet(parts_info,
item_slot,
GetPartVariation(PLAYER_VARIATION_HAIR),
GetPartVariation(PLAYER_VARIATION_FACE),
IsHideHelmet()
, GetGender()
);
}
#ifdef _NA_000000_20120420_EQUIPMENTS_VISIBLE_WING
else if (equip_pos >= EquipmentContainer::EQUIP_SACCESSORY1 && equip_pos <= EquipmentContainer::EQUIP_SACCESSORY3)
{
if (!is_spread_wings() && item_slot.IsWingItem() && IsHideWing())
{
SetEquipAppearInfo(NULL, item_slot);
}
else
{
SetEquipAppearInfo(&parts_info.Equipment[parts_position], item_slot);
}
}
#endif//_NA_000000_20120420_EQUIPMENTS_VISIBLE_WING
else
{
SetEquipAppearInfo(&parts_info.Equipment[parts_position], item_slot);
}
}
#ifdef _NA_008633_20160104_ADD_DECORATECOSTUME
if ( GetDecorateCostumeItemCode() != 0 && isHideCostume() == FALSE )
{
parts_info.Equipment[BP_DECORATE_COSTUME].dwItemID = GetDecorateCostumeItemCode();
}
#endif // _NA_008633_20160104_ADD_DECORATECOSTUME
//파츠 갱신
RefreshRender(&parts_info, refresh_bone);
class_code = GetImageClass();
SetScale(GetHeightInfo(static_cast<eCHAR_TYPE>(class_code), GetHeightVariation()));
// 엘리트 아이템 연출관련
if (GENERALPARAM->IsNet())
{
if( GlobalFunc::IsSSQScene() == FALSE )
{
RefreshFullsetItemInfo( this );
}
}
}
}
void Character::SetPolymorph( BOOL Active )
{
if( m_IsPolymorphApperance == Active )
return;
m_IsPolymorphApperance = Active;
}
void Character::CreateCharacterVariation(APPEARANCEINFO* appearance_info, BOOL only_bone)
{
cCharacterData::Initialize();
ClassCodeEx class_code;
class_code.class_code = appearance_info->Job;
appearance_info->Job = class_code.class_type;
SetClass(static_cast<eCHAR_TYPE>(class_code.class_type));
SetGender(static_cast<GenderType::Value>(class_code.gender));
InitRender(BP_COUNT, BP_BONE, appearance_info, AppearanceManager::kAppearanceAttachIndex_Count, only_bone);
}
void Character::DestroyCharacterVariation()
{
cCharacterData::Release();
}
SCSlotContainer* Character::GetSlotContainer( SLOTIDX slotIdx )
{
switch( slotIdx )
{
case SI_EQUIPMENT:
{
return GetEquipmentContainer();
}
break;
}
return NULL;
}
//
//bool Character::IsSetitemEquipmentSlot(int equipment_slot_index)
//{
// switch (equipment_slot_index)
// {
// case eEQUIPCONTAINER_ARMOR:
// case eEQUIPCONTAINER_HELMET:
// case eEQUIPCONTAINER_PANTS:
// case eEQUIPCONTAINER_BOOTS:
// case eEQUIPCONTAINER_GLOVE:
// {
// return true;
// }
// break;
// case eEQUIPCONTAINER_BELT:
// case eEQUIPCONTAINER_PROTECTOR:
// case eEQUIPCONTAINER_SHIRTS:
// {
// if (IsKindOfObject(PLAYER_OBJECT) != FALSE)
// {
// return true;
// }
//
// if (IsKindOfObject(NPC_OBJECT) != FALSE)
// {
// return false;
// }
// }
// break;
// }
//
// return false;
//}
//
////-------------------------------------------------------------------------------------------
///** 세트 아이템을 모두 장착 하였느냐? ( 풀셋을 만족하였나? )
//GS_DESC:현재 동일종류의 아이템이여도 아머파츠와 다른파츠가 디바인이 다르다면 풀셋이 아니라
//고체크하고있는데 맞는지는 모르겠음
//*/
//eKIND_OF_EQUIPED_SETITEM Character::GetEquipedKindOfSetItem(OUT WORD& setitem_optioninfo_setgroupcode) //m_sFullSetEffectInfo를 셋팅해준다
//{
// SCSlotContainer * pContainer = GetEquipmentContainer();
// if (pContainer == NULL)
// {
// return eKIND_OF_EQUIPED_SETITEM_NONE;
// }
// eITEMSUBTYPE eSubType;
// WORD SetCode;
// BOOL bDivine = FALSE;
//
// SCItemSlot & rItemSlot = (SCItemSlot &)pContainer->GetSlot(eEQUIPCONTAINER_ARMOR);
//
// const BASE_ITEMINFO* pItemInfo = rItemSlot.GetImageItemInfo();
//
// //슬롯유효검사
// if (rItemSlot.IsContainValidItem() && NULL != pItemInfo )
// {
// eSubType = (eITEMSUBTYPE)pItemInfo->m_wSubType;
// SetCode = pItemInfo->set_group_code;
// }
// else
// {
// eSubType = eITEMSUBTYPE_GENERAL;
// SetCode = 0;
// }
//
// ClearFullsetEffectInfo();
//
// eKIND_OF_EQUIPED_SETITEM eKindofEquipedSet = eKIND_OF_EQUIPED_SETITEM_NONE;
//
// for ( int i = 0; i < pContainer->GetMaxSlotNum(); ++i )
// {
// // 이놈들만 체크한다.
// // 플레이어와 Monster/NPC 는 조건이 틀리다.
// if (IsSetitemEquipmentSlot(i) == false)
// {
// continue;
// }
//
// if ( pContainer->IsEmpty(i) )
// {
// return eKIND_OF_EQUIPED_SETITEM_NONE;
// }
//
// SCItemSlot & rItemSlot = (SCItemSlot &)pContainer->GetSlot(i);
//
// if (GetEquipmentContainer()->GetEquipmentManageInfo()->slots[i].activated == false)
// {
// // 아이템이 비활성화인 경우 허용안함
// return eKIND_OF_EQUIPED_SETITEM_NONE;
// }
//
// const BASE_ITEMINFO* pItemInfo = rItemSlot.GetImageItemInfo();
// if ( !pItemInfo )
// {
// return eKIND_OF_EQUIPED_SETITEM_NONE;
// }
//
// // 이전의 값과 다른 셋인지 체크한다.
// // eEQUIPCONTAINER_ARMOR와 나머지 장비들을 비교한다.
// if ((eSubType != pItemInfo->m_wSubType) ||
// (SetCode != pItemInfo->set_group_code))
// {
// return eKIND_OF_EQUIPED_SETITEM_NONE;
// }
// }
//
// //풀셋으로 장착하고 있다면..
// if( 0 != pItemInfo->GetApplySetItemOptionType())
// {
// SETITEM_OPTION_INFO* pSetItemOpt = SetItemOptionInfoParser::Instance()->Find(pItemInfo->set_group_code);
// if(pSetItemOpt)
// {
// for(int i = 0; i < MAX_SETITEM_EFFECT_NUM; ++i)
// {
// if (INVALID_WZID != pSetItemOpt->m_dwEffectCode[i])
// {
// sFullSetEffectInfo effect_info;
// effect_info.m_dwEffectID = pSetItemOpt->m_dwEffectCode[i][GetGender()];
// effect_info.m_btBoneIdx = pSetItemOpt->m_btBoneIdx[i][GetGender()];
// // 럭키아이템처럼 처리한다(bysubType)
// if (pSetItemOpt->m_byItemType == 5)
// {
// eSubType = eITEMSUBTYPE_FATE;
// }
// SetFullsetEffectInfo(i, effect_info);
// }
// }
// setitem_optioninfo_setgroupcode = pSetItemOpt->m_wSetGroupCode;
// }
// }
//
// switch ( eSubType )
// {
// case eITEMSUBTYPE_GENERAL:
// {
// eKindofEquipedSet = eKIND_OF_EQUIPED_SETITEM_GENERAL;
// }
// break;
//
// case eITEMSUBTYPE_ELITE_SSQ:
// case eITEMSUBTYPE_ELITE:
// {
// eKindofEquipedSet = eKIND_OF_EQUIPED_SETITEM_ELITE;
// }
// break;
//
//
// case eITEMSUBTYPE_UNIQUE:
// {
// eKindofEquipedSet = eKIND_OF_EQUIPED_SETITEM_UNIQUE;
// }
// break;
//
// case eITEMSUBTYPE_FATE:
// {
// eKindofEquipedSet = eKIND_OF_EQUIPED_SETITEM_LUCKY;
// }
// break;
//
// default:
// eKindofEquipedSet = eKIND_OF_EQUIPED_SETITEM_NONE;
// break;
// }
//
// return eKindofEquipedSet;
//}
////------------------------------------------------------------------------------
///**
//*/
//BOOL Character::GetAttachEffectForSetItemPos( Character* pCharacter, OUT WzVector& Attach_Position)
//{
// int iBoneIndex = -1;
//
// // 가슴 본을 구해온다.
// switch( pCharacter->GetClass() )
// {
// case eCHAR_BERSERKER: iBoneIndex = 5;
// break;
// case eCHAR_DRAGON: iBoneIndex = 5;
// break;
// case eCHAR_VALKYRIE: iBoneIndex = 6;
// break;
// case eCHAR_ELEMENTALIST: iBoneIndex = 6;
// break;
// case eCHAR_SHADOW: iBoneIndex = 6;
// break;
// case eCHAR_MYSTIC: iBoneIndex = 5;
// break;
// default:
// break;
// }
//
// Attach_Position = pCharacter->GetVisiblePos();
// Attach_Position.z += pCharacter->GetHeight() / 2.0f;
//
// return GameFunc::GetBonePos( GetBasePart(), iBoneIndex, &Attach_Position);
//}
//
////------------------------------------------------------------------------------
///**
//*/
//int Character::GetAttachEffectForEliteItemBone()
//{
// int iBoneIndex = -1;
//
// // 가슴 본을 구해온다.
// switch (GetClass())
// {
// case eCHAR_BERSERKER:
// iBoneIndex = 5;
// break;
// case eCHAR_DRAGON:
// iBoneIndex = 5;
// break;
// case eCHAR_VALKYRIE:
// iBoneIndex = 6;
// break;
// case eCHAR_ELEMENTALIST:
// iBoneIndex = 6;
// break;
// case eCHAR_SHADOW:
// iBoneIndex = 6;
// break;
// case eCHAR_MYSTIC: //_NA_004965_20120613_NEW_CHARACTER_MYSTIC
// iBoneIndex = 5;
// break;
//
// default:
// break;
// }
//
// return iBoneIndex;
//}
void Character::HideHelmet(BOOL is_hide, BOOL is_refresh/* = TRUE*/)
{
if (IsHideHelmet() != is_hide)
{
// 용변신 중에 헬멧보이기 옵션이 변경되었다고 하여 RefreshAppearRender() 을 호출할 필요가 없음
// 변신중이 파츠를 안그리기 때문에 Refresh할 필요는 없으며 m_bHideHelmet 에 세팅해주는 것으로 변신해제시 옵션이 적용됨
cCharacterData::SetHideHelmet(is_hide);
if ((is_refresh == TRUE) && (IsTransForm() == FALSE))
{
RefreshAppearRender();
}
}
}
#ifdef _NA_000000_20120420_EQUIPMENTS_VISIBLE_WING
void Character::HideWing(BOOL is_hide, BOOL is_refresh/* = TRUE*/)
{
if (IsHideWing() != is_hide)
{
cCharacterData::SetHideWing( is_hide );
if ((is_refresh == TRUE) && (IsTransForm() == FALSE))
{
RefreshAppearRender();
}
}
}
#endif//_NA_000000_20120420_EQUIPMENTS_VISIBLE_WING
#ifdef _NA_006683_20130502_EQUIPMENTS_VISIBLE_COSTUME
void Character::HideCostume( BOOL is_Hide,BOOL is_refresh /*= TRUE*/ )
{
if (isHideCostume() != is_Hide)
{
cCharacterData::SetHideCostume( is_Hide );
if ((is_refresh == TRUE) && (IsTransForm() == FALSE))
{
RefreshAppearRender();
}
}
}
#endif
void Character::CreateShieldEffect()
{
if( IsCharacterDataCreated() == false )
{
return;
}
//쉴드가 없어지면 쉴드깨진이펙트 출력해준다
HANDLE effect_handle = GetDestroyShieldEffect();
if( m_bShield == FALSE )
{
if( effect_handle == INVALID_HANDLE_VALUE )
{
effect_handle = GlobalFunc::CreateEffectBeUpToOption(StrToWzID("A701"), GetBodyPos(), GetObjectKey() );
SetDestroyShieldEffect(effect_handle);
}
}
}
void Character::UpdateShieldEffect()
{
if( m_bShield == FALSE )
return;
if( IsCharacterDataCreated() == false )
{
return;
}
#ifdef _NA_007113_20140324_SHADOW_SKILL_BALLANCE_RENEWAL
if (GetHideSkill() == HIDE_SKILL_INFO::ALL_HIDE)
{
// 하이드 상태면 안띄움
return;
}
#endif //_NA_007113_20140324_SHADOW_SKILL_BALLANCE_RENEWAL
//쉴드가있을때나 핸들이 없을땐리턴
HANDLE effect_handle = GetDestroyShieldEffect();
if( effect_handle == INVALID_HANDLE_VALUE )
return;
if( CEffectBody* effect_body = g_pEffectManager->GetEffectPtrHandle(effect_handle) )
{
effect_body->SetResultMatrix(GetBodyPos(),c_ZeroVector,c_UnitVector);
}
}
void Character::ReleaseShieldEffect()
{
if( IsCharacterDataCreated() == false )
{
return;
}
HANDLE effect_handle = GetDestroyShieldEffect();
if (effect_handle != INVALID_HANDLE_VALUE )
{
g_pEffectManager->RemoveEffectPtr(effect_handle);
SetDestroyShieldEffect(INVALID_HANDLE_VALUE);
}
}
void Character::CheckEmptyHelmet(int equip_pos, APPEARANCEINFO& parts_info, int hair_variation, int face_variation)
{
if (equip_pos == EquipmentContainer::EQUIP_HELMET &&
GlobalFunc::IsSSQScene() == FALSE)
{
parts_info.Equipment[BP_HAIR].dwItemID = hair_variation;
parts_info.Equipment[BP_FACE].dwItemID = face_variation;
}
}
void Character::SetEquipAppearHelmet(APPEARANCEINFO& parts_info, SCItemSlot& item_slot, int hair_variation, int face_variation, BOOL hide_helmet, GenderType::Value gender )
{
int hair_type = 0;
bool draw_face = true;
bool draw_hair = true;
//헬멧 보이기 상태에서만 셋팅
if (hide_helmet == FALSE)
{
SetEquipAppearInfo(&parts_info.Equipment[BP_HELM], item_slot);
BASE_ITEMINFO* item_info_ptr = ItemInfoParser::Instance()->GetItemInfo(item_slot.GetImageCode());
if (item_info_ptr)
{
int customize_type = 0;
if (gender == GenderType::kMale)
{
hair_type = item_info_ptr->m_bHeadType;
customize_type = item_info_ptr->m_wCustomize;
}
else
{
hair_type = item_info_ptr->m_bHeadType1;
customize_type = item_info_ptr->m_wCustomize1;
}
if (customize_type == 1)
{
//1일경우 얼굴.머리카락 랜더안함
draw_face = false;
draw_hair = false;
}
else if (customize_type == 2)
{
// 해당 값이 2이면 머리카락 랜더안함
draw_hair = false;
}
}
}
//타락한 사원에서는 무조건 그림
if (g_LoadScene.GetNextSceneAfterLoaded() == SCENE_TYPE_SSQ)
{
draw_hair = false;
draw_face = false;
}
if (draw_hair == true)
{
parts_info.Equipment[BP_HAIR].dwItemID = hair_variation;
parts_info.Equipment[BP_HAIR].iEnchant = hair_type;
}
if (draw_face == true)
{
parts_info.Equipment[BP_FACE].dwItemID = face_variation;
}
}
void Character::SetEquipAppearInfo(EQUIPAPPEARINFO* parts_info, SCItemSlot& item_slot)
{
if (parts_info != NULL)
{
parts_info->dwItemID = item_slot.GetImageCode();
parts_info->bDivine = item_slot.IsDivine();
parts_info->iEnchant = item_slot.GetEnchant();
}
}
DWORD Character::GetWeaponKind()
{
EquipmentContainer* equipment_container = GetEquipmentContainer();
if (equipment_container == NULL)
{
return eWEAPONTYPE_PUNCH;
}
// 무기에따라서 기본자세가 바뀝니다.
SCSlot& rSlot = equipment_container->GetSlot(EquipmentContainer::EQUIP_WEAPON1);
if (rSlot.GetCode() == 0)
{
return eWEAPONTYPE_PUNCH;
}
else
{
BASE_ITEMINFO *pItemInfo = ItemInfoParser::Instance()->GetItemInfo(rSlot.GetCode());
if(!pItemInfo)
{
WRITELOG(eLOG_LEVEL_ERR, c_wOUTPUT_LOG_CENTER, "Invalid Weapon ID [%d]", rSlot.GetCode());
assert(pItemInfo && "장착된 무기 ID가 잘못되었습니다.");
return eWEAPONTYPE_PUNCH;
}
return pItemInfo->m_wType;
}
}
char Character::GetWeaponAnimationCode()
{
const char kInvalid_Code = '0';
if(IsTransForm())
{
return kInvalid_Code;
}
#ifdef _NA_008069_20150210_ADD_SPA_SYSTEM
if (GlobalFunc::IsSpaScene() == TRUE)
{
return kInvalid_Code;
}
#endif //_NA_008069_20150210_ADD_SPA_SYSTEM
DWORD weapon_kind = GetWeaponKind();
switch(weapon_kind)
{
case eWEAPONTYPE_TWOHANDAXE:
case eWEAPONTYPE_STAFF:
{
return '1';
}
break;
case eWEAPONTYPE_TWOHANDSWORD:
case eWEAPONTYPE_ONEHANDSWORD:
case eWEAPONTYPE_ONEHANDCROSSBOW:
case eWEAPONTYPE_ORB:
case eWEAPONTYPE_DAGGER:
case eWEAPONTYPE_GUNTLET: //_NA_004965_20120613_NEW_CHARACTER_MYSTIC
case eWEAPONTYPE_HELLROID_1: //_NA_000000_20130812_NEW_CHARACTER_HELLROID
case eWEAPONTYPE_ARCBLADE: //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
{
return '2';
}
break;
case eWEAPONTYPE_SPEAR:
case eWEAPONTYPE_ETHERWEAPON:
case eWEAPONTYPE_WHIP:
case eWEAPONTYPE_POLEARM: //_NA_004965_20120613_NEW_CHARACTER_MYSTIC
{
return '3';
}
break;
case eWEAPONTYPE_PUNCH:
{
return '0';
}
break;
#ifdef _YJ_FISHING_SYSTEM_000933
case eWEAPONTYPE_FISHING_POLE:
{
return kInvalid_Code;
}
break;
#endif //_YJ_FISHING_SYSTEM_000933
default:
{
assert(!"무기 계열 Text 정보가 잘못되었습니다.");
return '2';
}
break;
}
}
int Character::GetWeaponBone(int index)
{
if( IsCharacterDataCreated() == false )
{
return 0;
}
CWzUnit* unit_ptr = GetBasePart()->GetWzUnit();
if (unit_ptr == NULL)
{
return 0;
}
// 클래스 및 무기에 따른 본이름
WzBoneInfo* bone_Info = NULL;
switch (GetWeaponKind())
{
// 'WEA1' only
case eWEAPONTYPE_TWOHANDSWORD:
case eWEAPONTYPE_GUNTLET: // 건틀릿은 오른손만 착용 //_NA_004965_20120613_NEW_CHARACTER_MYSTIC
case eWEAPONTYPE_HELLROID_1: //_NA_000000_20130812_NEW_CHARACTER_HELLROID
{
bone_Info = unit_ptr->GetBoneInfo(StrToWzID("WEA1"));
}
break;
// 'WEA1' & 'WEA2'
case eWEAPONTYPE_ONEHANDSWORD:
case eWEAPONTYPE_DAGGER:
case eWEAPONTYPE_ONEHANDCROSSBOW:
case eWEAPONTYPE_STAFF:
case eWEAPONTYPE_ORB:
case eWEAPONTYPE_ARCBLADE: //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
{
if (index == 0)
{
bone_Info = unit_ptr->GetBoneInfo(StrToWzID("WEA1"));
}
else
{
bone_Info = unit_ptr->GetBoneInfo(StrToWzID("WEA2"));
}
}
break;
// 'WEA3' only
case eWEAPONTYPE_TWOHANDAXE:
case eWEAPONTYPE_SPEAR:
case eWEAPONTYPE_WHIP:
case eWEAPONTYPE_ETHERWEAPON:
case eWEAPONTYPE_POLEARM: //_NA_004965_20120613_NEW_CHARACTER_MYSTIC
{
bone_Info = unit_ptr->GetBoneInfo(StrToWzID("WEA3"));
}
break;
}
if (bone_Info != NULL)
{
return bone_Info->m_iNode;
}
return 0;
}
// [3/10/2011 iforall]
//////////////////////////////////////////////////////////////////////////
int Character::GetSpecialAccessoryBone(WzID id)
{
WzBoneInfo* pInfo = NULL;
if (StrToWzID("Null") == id)
{
return -1;
}
if (GetBasePart()->GetWzUnit() != NULL)
{
pInfo = GetBasePart()->GetWzUnit()->GetBoneInfo(id);
if (pInfo != NULL)
{
return pInfo->m_iNode;
}
}
return -1;
}
#ifdef _DH_NPC_GROUP_NAME
void Character::RenderTextOnHeadGroup(TCHAR *szString, WzColor color, int yoffset)
{
TCHAR szGuildString[INTERFACE_STRING_LENGTH] = { 0,};
Snprintf (szGuildString,INTERFACE_STRING_LENGTH-1, _T("< %s >"), szString);
if (GetChatDisplayTime())//채팅 중 랜더 안함
{
return;
}
if (g_InterfaceManager.GetShowFlag())
{
WzVector wzVisualPos = GetVisiblePos();
WzColor oldcolor = g_pSunRenderer->GetDiffuseColor();
g_pSunRenderer->Set2DMode( TRUE );
g_pSunRenderer->x_pManagerTextOut->StartToUseFont( StrToWzID("m217") );
WzVector wzPos = GetPosition();
wzVisualPos.z += GetMeshHeight();
wzVisualPos.z += HEIGHT_GAP;
POINT pt2;
float fDepth;
g_pSunRenderer->GetScreenPos( &pt2, &wzVisualPos , &fDepth );
SIZE textsizeGuild, textSizeName;
g_pSunRenderer->x_pManagerTextOut->GetTextExtentPoint(szGuildString,lstrlen(szGuildString),&textsizeGuild);
RECT rc;
rc.left = pt2.x - (textsizeGuild.cx / 2);
rc.top = pt2.y + yoffset - 2 ;
rc.right = rc.left + textsizeGuild.cx;
rc.bottom = rc.top + 50;
WzColor BackColor = WzColor_RGBA(0,0,0,100);
const TCHAR* player_name = GetName();
g_pSunRenderer->x_pManagerTextOut->GetTextExtentPoint((TCHAR*)player_name, lstrlen(player_name), &textSizeName);// 글로벌 엔진버전이 낮아서 error발생 (TCHAR*)필요 추후 제거 요망
SIZE BigTextSize = textsizeGuild.cx > textSizeName.cx ? textsizeGuild : textSizeName;
//if (this->IsExistGuild())
{
RenderBlockedTextWithDepthTest(szGuildString,&rc,color,BackColor,fDepth);//배경 Rect그리기
RenderBlockedTextWithDepthTest(szGuildString,&rc,color,BackColor,fDepth, true);
}
g_pSunRenderer->x_pManagerTextOut->EndUseFont();
g_pSunRenderer->Set2DMode(FALSE);
g_pSunRenderer->SetColor(oldcolor);
}
}
#endif//_DH_NPC_GROUP_NAME
//------------------------------------------------------------------------------
WzID Character::GetNormalAttackAniCode(BASE_STYLEINFO* info, eATTACK_SEQUENCE attack_sequence, int ani_type)
{
if ((GetClass() == eCHAR_BERSERKER) ||
(GetClass() == eCHAR_DRAGON) ||
(GetClass() == eCHAR_MYSTIC)) // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
{
if (ani_type == 0)
{
//! 2타 애니메이션
if (info->m_SkillCode == eSTYLE_TWOHANDSWORD_NORMAL)
{
switch(attack_sequence)
{
case eATTACK_SEQUENCE_FIRST: return StrToWzID("A201");
case eATTACK_SEQUENCE_SECOND: return StrToWzID("A203");
}
}
else if (info->m_SkillCode == eSTYLE_TWOHANDAXE_NORMAL)
{
switch(attack_sequence)
{
case eATTACK_SEQUENCE_FIRST: return StrToWzID("A101");
case eATTACK_SEQUENCE_SECOND: return StrToWzID("A102");
}
}
else if (info->m_SkillCode == eSTYLE_ONEHANDSWORD_NORMAL)
{
switch(attack_sequence)
{
case eATTACK_SEQUENCE_FIRST: return StrToWzID("A201");
case eATTACK_SEQUENCE_SECOND: return StrToWzID("A203");
}
}
else if (info->m_SkillCode == eSTYLE_SPEAR_NORMAL)
{
switch(attack_sequence)
{
case eATTACK_SEQUENCE_FIRST: return StrToWzID("A301");
case eATTACK_SEQUENCE_SECOND: return StrToWzID("A303");
}
}
else if (info->m_SkillCode == eSTYLE_MYSTIC_GUNTLET_NORMAL) //_NA_004965_20120613_NEW_CHARACTER_MYSTIC
{
switch(attack_sequence)
{
case eATTACK_SEQUENCE_FIRST: return StrToWzID("A201");
case eATTACK_SEQUENCE_SECOND: return StrToWzID("A203");
}
}
else if (info->m_SkillCode == eSTYLE_MYSTIC_POLEARM_NORMAL) //_NA_004965_20120613_NEW_CHARACTER_MYSTIC
{
switch(attack_sequence)
{
case eATTACK_SEQUENCE_FIRST: return StrToWzID("A301");
case eATTACK_SEQUENCE_SECOND: return StrToWzID("A303");
}
}
}
else if (ani_type == 2)
{
//! 3타애니
if (info->m_SkillCode == eSTYLE_TWOHANDSWORD_NORMAL)
{
switch(attack_sequence)
{
case eATTACK_SEQUENCE_FIRST: return StrToWzID("S213");
case eATTACK_SEQUENCE_SECOND: return StrToWzID("S215");
case eATTACK_SEQUENCE_THIRD: return StrToWzID("S217");
}
}
else if (info->m_SkillCode == eSTYLE_TWOHANDAXE_NORMAL)
{
switch(attack_sequence)
{
case eATTACK_SEQUENCE_FIRST: return StrToWzID("S113");
case eATTACK_SEQUENCE_SECOND: return StrToWzID("S115");
case eATTACK_SEQUENCE_THIRD: return StrToWzID("S117");
}
}
else if (info->m_SkillCode == eSTYLE_ONEHANDSWORD_NORMAL)
{
switch(attack_sequence)
{
case eATTACK_SEQUENCE_FIRST: return StrToWzID("S213");
case eATTACK_SEQUENCE_SECOND: return StrToWzID("S215");
case eATTACK_SEQUENCE_THIRD: return StrToWzID("S217");
}
}
else if (info->m_SkillCode == eSTYLE_SPEAR_NORMAL)
{
switch(attack_sequence)
{
case eATTACK_SEQUENCE_FIRST: return StrToWzID("S301");
case eATTACK_SEQUENCE_SECOND: return StrToWzID("S303");
case eATTACK_SEQUENCE_THIRD: return StrToWzID("S305");
}
}
else if (info->m_SkillCode == eSTYLE_MYSTIC_GUNTLET_NORMAL) //_NA_004965_20120613_NEW_CHARACTER_MYSTIC
{
switch(attack_sequence)
{
case eATTACK_SEQUENCE_FIRST: return StrToWzID("S213");
case eATTACK_SEQUENCE_SECOND: return StrToWzID("S215");
case eATTACK_SEQUENCE_THIRD: return StrToWzID("S217");
}
}
else if (info->m_SkillCode == eSTYLE_MYSTIC_POLEARM_NORMAL) //_NA_004965_20120613_NEW_CHARACTER_MYSTIC
{
switch(attack_sequence)
{
case eATTACK_SEQUENCE_FIRST: return StrToWzID("S313");
case eATTACK_SEQUENCE_SECOND: return StrToWzID("S315");
case eATTACK_SEQUENCE_THIRD: return StrToWzID("S317");
}
}
}
}
switch(attack_sequence)
{
case eATTACK_SEQUENCE_FIRST: return info->m_wzidCodeFirst.id;
case eATTACK_SEQUENCE_SECOND: return info->m_wzidCodeSecond.id;
case eATTACK_SEQUENCE_THIRD: return info->m_wzidCodeThird.id;
}
return StrToWzID("A001");
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 뒤로 밀리는 애니메이션과 함께 넉백
void Character::SetKnockBack( const WzVector& CurrentPosition, const WzVector& TargetPosition )
{
#ifdef _NA_007115_20140313_MONDSCHIEN_RENEWAL
if (CheckDominationCollectState() == TRUE)
return;
#endif // _NA_007115_20140313_MONDSCHIEN_RENEWAL
// 모든 데미지를 처리한다
ProcessAttackResult( GetCurrentAttackSerial(), TRUE );
EmptyActionQueue();
// 액션 큐 무시, 현재 상태를 스킵하고 바로 변경
SetNextState( STATE::KNOCKBACK, g_CurTime );
CommitChangeState( g_CurTime );
// 목표위치로 이동
StopMove();
Move( CurrentPosition, TargetPosition , CMS_WALK, TRUE, -1, -1 );
}
void Character::SetKnockBack2( const WzVector& CurrentPosition, const WzVector& TargetPosition )
{
#ifdef _NA_007115_20140313_MONDSCHIEN_RENEWAL
if (CheckDominationCollectState() == TRUE)
return;
#endif // _NA_007115_20140313_MONDSCHIEN_RENEWAL
// 모든 데미지를 처리한다
ProcessAttackResult( GetCurrentAttackSerial(), TRUE );
EmptyActionQueue();
// 액션 큐 무시, 현재 상태를 스킵하고 바로 변경
SetNextState( STATE::KNOCKBACK2, g_CurTime );
CommitChangeState( g_CurTime );
// 목표위치로 이동
StopMove();
Move( CurrentPosition, TargetPosition , CMS_WALK, TRUE, -1, -1 );
}
// 점프하면서 대상 위치로 튕귀며 이동된다 (이그니션의 풀링)
void Character::SetKnockBack3( const WzVector& CurrentPosition, const WzVector& TargetPosition )
{
#ifdef _NA_007115_20140313_MONDSCHIEN_RENEWAL
if (CheckDominationCollectState() == TRUE)
return;
#endif // _NA_007115_20140313_MONDSCHIEN_RENEWAL
#ifdef _NA_008472_20150903_IMPROVED_BALANCE
if (IsAbnormalityProtection() == TRUE)
{
return;
}
#endif // _NA_008472_20150903_IMPROVED_BALANCE
// 모든 데미지를 처리한다
ProcessAttackResult( GetCurrentAttackSerial(), TRUE );
EmptyActionQueue();
// 뛰우기 위한 값을 설정
m_AirData.m_fDownForceLimit = -50.0f;
m_AirData.m_fUpperForce = 25.0f;
m_AirData.m_fGravity = 140.0f;
m_AirData.m_fHighLimit = 5.0f;
m_fHeight = 0.0f;
// 액션 큐 무시하고 바로 변경
SetNextState( STATE::KNOCKBACK3, g_CurTime );
CommitChangeState( g_CurTime );
// 목표위치로 이동
StopMove();
Move( CurrentPosition, TargetPosition , CMS_WALK, TRUE, -1, -1 );
}
void Character::SetDown( DWORD Duration )
{
#ifdef _NA_007115_20140313_MONDSCHIEN_RENEWAL
if (CheckDominationCollectState() == TRUE)
return;
#endif // _NA_007115_20140313_MONDSCHIEN_RENEWAL
// 모든 데미지를 처리한다
ProcessAttackResult( GetCurrentAttackSerial(), TRUE );
EmptyActionQueue();
// 액션 큐 무시, 현재 상태를 스킵하고 바로 변경
SetNextState( STATE::DOWN, g_CurTime );
CommitChangeState( g_CurTime );
#ifdef _NA_008472_20150903_IMPROVED_BALANCE
// 일어나는 동작이 없어졌다.
#else
// 일어나는 애니메이션의 시간을 미리 계산한 한다
DWORD GetUpAnimationTime = 1000;
WzID DownAnimationID;
switch( GetWeaponAnimationCode() )
{
case '0': DownAnimationID = StrToWzID("F003"); break;
case '1': DownAnimationID = StrToWzID("F103"); break;
case '2': DownAnimationID = StrToWzID("F203"); break;
case '3': DownAnimationID = StrToWzID("F303"); break;
}
if( WzAnimationInfo* pAnimationInfo = GetAnimationInfo(DownAnimationID) )
{
GetUpAnimationTime = pAnimationInfo->m_nMaxFrame * DEF_NUM_FRAMES_PER_MS;
}
#endif // _NA_008472_20150903_IMPROVED_BALANCE
#ifdef _NA_008472_20150903_IMPROVED_BALANCE
// 일어나는 시간이 없어졌다.
m_DownTime = g_CurTime + Duration;
#else
// 일어나는 시간만큼을 미리 뺴둔다. (넘어지는 시간, + 일어나는 시간을 합한것보다 다운 시간이 적다면 문제가 생기므로 최소 2초의 시간을 부여한다)
m_DownTime = g_CurTime + max(2000, Duration - GetUpAnimationTime );
#endif // _NA_008472_20150903_IMPROVED_BALANCE
// 목표위치로 이동
StopMove();
//Move( ResultData.GetCurrentPosition().wvPos, ResultData.GetDestPosition().wvPos, CMS_WALK, TRUE, -1, -1 );
}
// 다운과 넉백이 동시에 발생
void Character::SetKnockBackDown( const WzVector& CurrentPosition, const WzVector& TargetPosition, DWORD DownDuration )
{
#ifdef _NA_007115_20140313_MONDSCHIEN_RENEWAL
if (CheckDominationCollectState() == TRUE)
return;
#endif // _NA_007115_20140313_MONDSCHIEN_RENEWAL
// 일단 다운으로 적용
// 모든 데미지를 처리한다
ProcessAttackResult( GetCurrentAttackSerial(), TRUE );
EmptyActionQueue();
// 액션 큐 무시, 현재 상태를 스킵하고 바로 변경
SetNextState( STATE::DOWN, g_CurTime );
CommitChangeState( g_CurTime );
// 일어나는 애니메이션의 시간을 미리 계산한 한다
DWORD GetUpAnimationTime = 1000;
WzID DownAnimationID;
switch( GetWeaponAnimationCode() )
{
case '0': DownAnimationID = StrToWzID("F003"); break;
case '1': DownAnimationID = StrToWzID("F103"); break;
case '2': DownAnimationID = StrToWzID("F203"); break;
case '3': DownAnimationID = StrToWzID("F303"); break;
}
if( WzAnimationInfo* pAnimationInfo = GetAnimationInfo(DownAnimationID) )
{
GetUpAnimationTime = pAnimationInfo->m_nMaxFrame * DEF_NUM_FRAMES_PER_MS;
}
// 일어나는 시간만큼을 미리 뺴둔다. (넘어지는 시간, + 일어나는 시간을 합한것보다 다운 시간이 적다면 문제가 생기므로 최소 2초의 시간을 부여한다)
m_DownTime = g_CurTime + max(2000, DownDuration - GetUpAnimationTime );
// 목표위치로 이동
StopMove();
Move( CurrentPosition, TargetPosition , CMS_WALK, TRUE, -1, -1 );
}
void Character::SetStun( const WzVector& CurrentPosition )
{
#ifdef _NA_007115_20140313_MONDSCHIEN_RENEWAL
if (CheckDominationCollectState() == TRUE)
return;
#endif // _NA_007115_20140313_MONDSCHIEN_RENEWAL
// 모든 데미지를 처리한다
ProcessAttackResult( GetCurrentAttackSerial(), TRUE );
EmptyActionQueue();
// 액션 큐 무시, 현재 상태를 스킵하고 바로 변경
SetNextState( STATE::IDLE, g_CurTime );
CommitChangeState( g_CurTime );
StopMove();
SetPosition( CurrentPosition );
}
void Character::SetIdleState()
{
// 모든 데미지를 처리한다
ProcessAttackResult( GetCurrentAttackSerial(), TRUE );
EmptyActionQueue();
// 액션 큐 무시, 현재 상태를 스킵하고 바로 변경
SetNextState( STATE::IDLE, g_CurTime );
CommitChangeState( g_CurTime );
}
void Character::SetAir( DWORD Duration )
{
#ifdef _NA_007115_20140313_MONDSCHIEN_RENEWAL
if (CheckDominationCollectState() == TRUE)
return;
#endif // _NA_007115_20140313_MONDSCHIEN_RENEWAL
#ifdef _NA_008472_20150903_IMPROVED_BALANCE
if (IsAbnormalityProtection() == TRUE)
{
return;
}
#endif // _NA_008472_20150903_IMPROVED_BALANCE
// 모든 데미지를 처리한다
ProcessAttackResult( GetCurrentAttackSerial(), TRUE );
EmptyActionQueue();
// 액션 큐 무시, 현재 상태를 스킵하고 바로 변경
SetNextState( STATE::AIR, g_CurTime );
CommitChangeState( g_CurTime );
// 일어나는 애니메이션의 시간을 미리 계산한 한다
static DWORD GetUpAnimationTime = 1000;
WzID DownAnimationID;
switch( GetWeaponAnimationCode() )
{
case '0': DownAnimationID = StrToWzID("F003"); break;
case '1': DownAnimationID = StrToWzID("F103"); break;
case '2': DownAnimationID = StrToWzID("F203"); break;
case '3': DownAnimationID = StrToWzID("F303"); break;
}
static DWORD double_attack_duration = 2000;
static DWORD double_attack_duration2 = 5000;
#ifdef _NA_007619_20140916_PROCESS_CHANGE_AIRBLOW_DOWN
static DWORD double_attack_duration3 = 2500;
#endif // _NA_007619_20140916_PROCESS_CHANGE_AIRBLOW_DOWN
if( Duration == double_attack_duration )
{
m_AirData.m_MoveType = sAirData::MOVE_TYPE_NORMAL;
m_AirData.m_fDownForceLimit = -40.0f;
m_AirData.m_fGravity = 200.0f;
m_AirData.m_fHighLimit = 3.4f;
m_AirData.m_fUpperForce = 100.0f;
m_AirData.m_NoDown = TRUE;
}
else if( Duration == double_attack_duration2 )
{
static int s_mode = 1;
m_AirData.m_MoveType = sAirData::MOVE_TYPE_AIRBLOW;
static float fDownLimit = -20.0f;
static float fGravity = 37.0f;
static float fHeightLimit = 4.5f;
static float fUpperForce = 22.0f;
static DWORD DownTime = 1000;
static float fMaxHeight = 1.3f;
m_AirData.m_fDownForceLimit = fDownLimit;
m_AirData.m_fGravity = fGravity;
m_AirData.m_fHighLimit = fHeightLimit;
m_AirData.m_fUpperForce = fUpperForce;
m_AirData.m_NoDown = FALSE;
m_AirData.m_DownTime = DownTime;
m_AirData.m_MaxHeight = fMaxHeight;
m_AirData.m_StartTime = GetCurrentTime();
m_AirData.m_NoDown = FALSE;
}
#ifdef _NA_007619_20140916_PROCESS_CHANGE_AIRBLOW_DOWN
else if( Duration == double_attack_duration3 )
{
// 현재 사용하지는 않지만 혹시 몰라 추가.
m_AirData.m_MoveType = sAirData::MOVE_TYPE_AIRBLOW;
static float fDownLimit1 = -20.0f;
static float fGravity1 = 50.0f;
static float fHeightLimit1 = 4.5f;
static float fUpperForce1 = 22.0f;
static DWORD DownTime1 = 500;
static float fMaxHeight1 = 1.3f;
m_AirData.m_fDownForceLimit = fDownLimit1;
m_AirData.m_fGravity = fGravity1;
m_AirData.m_fHighLimit = fHeightLimit1;
m_AirData.m_fUpperForce = fUpperForce1;
m_AirData.m_NoDown = FALSE;
m_AirData.m_DownTime = DownTime1;
m_AirData.m_MaxHeight = fMaxHeight1;
m_AirData.m_StartTime = GetCurrentTime();
m_AirData.m_NoDown = FALSE;
}
#endif // _NA_007619_20140916_PROCESS_CHANGE_AIRBLOW_DOWN
// 일어나는 시간만큼을 미리 뺴둔다. (넘어지는 시간, + 일어나는 시간을 합한것보다 다운 시간이 적다면 문제가 생기므로 최소 2초의 시간을 부여한다)
// 체공시간은 일단 패스
m_AirData.m_AirTime = g_CurTime + max(2000, Duration - GetUpAnimationTime );
StopMove();
}
#ifdef _NA_007619_20140916_PROCESS_CHANGE_AIRBLOW_DOWN
void Character::SetAirBlowAir( DWORD Duration )
{
if (CheckDominationCollectState() == TRUE)
return;
// 모든 데미지를 처리한다
ProcessAttackResult( GetCurrentAttackSerial(), TRUE );
EmptyActionQueue();
// 액션 큐 무시, 현재 상태를 스킵하고 바로 변경
SetNextState( STATE::AIR, g_CurTime );
//CommitChangeState( g_CurTime ); // 바로 액션을 하지 않는다.
// 일어나는 애니메이션의 시간을 미리 계산한 한다
static DWORD GetUpAnimationTime = 1000;
WzID DownAnimationID;
switch( GetWeaponAnimationCode() )
{
case '0': DownAnimationID = StrToWzID("F003"); break;
case '1': DownAnimationID = StrToWzID("F103"); break;
case '2': DownAnimationID = StrToWzID("F203"); break;
case '3': DownAnimationID = StrToWzID("F303"); break;
}
m_AirData.m_MoveType = sAirData::MOVE_TYPE_AIRBLOW;
const float fDownLimitAir = -20.0f;
const float fGravityAir = 50.0f;
const float fHeightLimitAir = 4.5f;
const float fUpperForceAir = 22.0f;
const DWORD DownTimeAir = 500;
const float fMaxHeightAir = 1.3f;
m_AirData.m_fDownForceLimit = fDownLimitAir;
m_AirData.m_fGravity = fGravityAir;
m_AirData.m_fHighLimit = fHeightLimitAir;
m_AirData.m_fUpperForce = fUpperForceAir;
m_AirData.m_NoDown = FALSE;
m_AirData.m_DownTime = DownTimeAir;
m_AirData.m_MaxHeight = fMaxHeightAir;
m_AirData.m_StartTime = GetCurrentTime();
m_AirData.m_NoDown = FALSE;
// 일어나는 시간만큼을 미리 뺴둔다. (넘어지는 시간, + 일어나는 시간을 합한것보다 다운 시간이 적다면 문제가 생기므로 최소 2초의 시간을 부여한다)
// 체공시간은 일단 패스
m_AirData.m_AirTime = g_CurTime + max(2000, Duration - GetUpAnimationTime );
StopMove();
}
#endif // _NA_007619_20140916_PROCESS_CHANGE_AIRBLOW_DOWN
void Character::AddAirForce( float fAddUpperForce, float fHeightLimit )
{
//m_AirData.m_fUpperForce += fAddUpperForce;
//m_AirData.m_fHighLimit += fHeightLimit;
//if( m_AirData.m_MoveType != 0 )
// return;
static int s_mode = 2;
static float fUpperForce = 10.0f;
static float fStaticUpperForce = 10.0f;
static float fStaticUpperForce2 = 5.0f;
//static float fHeightLimit = 0.5f;
if( s_mode == 0 )
{
m_AirData.m_fUpperForce += fUpperForce;
if( m_AirData.m_fUpperForce >= fStaticUpperForce )
m_AirData.m_fUpperForce = fStaticUpperForce;
}
else if( s_mode == 1 )
{
m_AirData.m_fUpperForce = fStaticUpperForce2;
}
else if( s_mode == 2 )
{
static float sf = 0.5f;
m_AirData.m_fUpperForce += sf;
static float sh = 0.1f;
m_fHeight += sh;
}
// m_AirData.m_fHighLimit += fHeightLimit;
}
void Character::UpdateAir( DWORD TickTime )
{
if( m_AirData.m_MoveType == sAirData::MOVE_TYPE_NORMAL )
{
static float s_speed_multiplier = 0.001f;
static float s_height_multiplier = 0.001f;
m_AirData.m_fUpperForce -= (m_AirData.m_fGravity * TickTime * s_speed_multiplier);
if( m_AirData.m_fUpperForce < m_AirData.m_fDownForceLimit )
{
m_AirData.m_fUpperForce = m_AirData.m_fDownForceLimit;
}
m_fHeight += (m_AirData.m_fUpperForce * TickTime * s_height_multiplier);
if( m_fHeight >= m_AirData.m_fHighLimit )
{
m_fHeight = m_AirData.m_fHighLimit;
}
if( m_fHeight < 0.0f )
m_fHeight = 0.0f;
}
else if( m_AirData.m_MoveType == sAirData::MOVE_TYPE_AIRBLOW )
{
static float s_speed_multiplier = 0.0007f;
static float s_height_multiplier = 0.0008f;
static float s_height_multiplier2 = 0.00025f;
static float s_height_multiplier3 = 0.001f;
DWORD CurrentTime = GetCurrentTime();
if( m_AirData.m_StartTime + m_AirData.m_DownTime > CurrentTime )
{
// 이 구간은 떨어지지는 않는다
m_AirData.m_fUpperForce -= (m_AirData.m_fGravity * TickTime * s_speed_multiplier);
if( m_AirData.m_fUpperForce < 0.0f )
m_AirData.m_fUpperForce = 0.0f;
if( m_AirData.m_fUpperForce < m_AirData.m_fDownForceLimit )
{
m_AirData.m_fUpperForce = m_AirData.m_fDownForceLimit;
}
if( m_fHeight >= m_AirData.m_MaxHeight )
{
m_fHeight += (m_AirData.m_fUpperForce * TickTime * s_height_multiplier2);
}
else
{
m_fHeight += (m_AirData.m_fUpperForce * TickTime * s_height_multiplier);
}
if( m_fHeight >= m_AirData.m_fHighLimit )
{
m_fHeight = m_AirData.m_fHighLimit;
}
}
else
{
m_AirData.m_fUpperForce -= (m_AirData.m_fGravity * TickTime * s_height_multiplier3);
if( m_AirData.m_fUpperForce < m_AirData.m_fDownForceLimit )
{
m_AirData.m_fUpperForce = m_AirData.m_fDownForceLimit;
}
m_fHeight += (m_AirData.m_fUpperForce * TickTime * s_height_multiplier3);
if( m_fHeight >= m_AirData.m_fHighLimit )
{
m_fHeight = m_AirData.m_fHighLimit;
}
if( m_fHeight < 0.0f )
m_fHeight = 0.0f;
}
}
}
void Character::SetFallDown( float fGravity, float fUpperForce )
{
m_FallDownData.m_fGravity = fGravity;
m_FallDownData.m_fUpperForce = fUpperForce;
m_fHeight = 0.0f;
}
void Character::UpdateFallDown( DWORD TickTime )
{
m_FallDownData.m_fUpperForce += m_FallDownData.m_fGravity * TickTime * SPEED_MULTIPLIER;
float fDelta = m_FallDownData.m_fUpperForce * (float)TickTime * SPEED_MULTIPLIER;
m_fHeight += fDelta;
if( m_fHeight < -100.0f )
{
m_fHeight = -100.0f;
}
}
#ifdef _NA_007115_20140313_MONDSCHIEN_RENEWAL
BOOL Character::CheckDominationCollectState()
{
if(GlobalFunc::IsDominationScene() == TRUE
&& this->GetCurState() == STATE::COLLECT)
return TRUE;
return FALSE;
}
#endif // _NA_007115_20140313_MONDSCHIEN_RENEWAL
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
void Character::CreateViceSwordWeaponEffect()
{
if (is_vice_sword_effect_() == TRUE)
return;
DestroyViceSwordWeaponEffect();
// 왼손, 오른손
for (unsigned int i = 0; i < 2; ++i)
{
CWzUnitDraw* weapon_unit_draw_ptr = GetAttachment(i).GetUnitDraw();
if (!weapon_unit_draw_ptr)
{
DestroyViceSwordWeaponEffect();
continue;
}
CWzUnit* wz_unit_ptr = weapon_unit_draw_ptr->GetWzUnit();
if( !wz_unit_ptr )
return;
WzBoneInfo* bone_info_ptr = NULL;
if (i == 0) // 왼손
{
bone_info_ptr = wz_unit_ptr->GetBoneInfo(StrToWzID("WEA1"));
}
if (i == 1) // 오른손
{
bone_info_ptr = wz_unit_ptr->GetBoneInfo(StrToWzID("WEA2"));
}
if (!bone_info_ptr)
continue;
if (i == 0) // 왼손
{
vice_sword_effect_handle_[0] = GlobalFunc::CreateEffectBeUpToOption(StrToWzID("KE46"),
weapon_unit_draw_ptr->GetBonePos(bone_info_ptr->m_iNode));
}
if (i == 1) // 오른손
{
vice_sword_effect_handle_[1] = GlobalFunc::CreateEffectBeUpToOption(StrToWzID("KE45"),
weapon_unit_draw_ptr->GetBonePos(bone_info_ptr->m_iNode));
}
}
UpdateViceSwordWeaponEffect();
}
void Character::DestroyViceSwordWeaponEffect()
{
for(int i=0 ;i < 2; ++i)
{
if( vice_sword_effect_handle_[i] != INVALID_HANDLE_VALUE )
{
g_pEffectManager->RemoveEffectPtr(vice_sword_effect_handle_[i]);
vice_sword_effect_handle_[i] = INVALID_HANDLE_VALUE;
}
}
}
void Character::UpdateViceSwordWeaponEffect()
{
if (is_vice_sword_effect_() == FALSE)
{
return;
}
// 왼손, 오른손
for (unsigned int i = 0; i < 2; ++i)
{
if (GetAttachmentCount() <= i)
{
return;
}
CWzUnitDraw* weapon_unit_draw_ptr = GetAttachment(i).GetUnitDraw();
if (!weapon_unit_draw_ptr)
continue;
CWzUnit* wz_unit_ptr = weapon_unit_draw_ptr->GetWzUnit();
if( !wz_unit_ptr )
{
DestroyViceSwordWeaponEffect();
return;
}
WzBoneInfo* bone_info_ptr = NULL;
if (i == 0) // 왼손
{
bone_info_ptr = wz_unit_ptr->GetBoneInfo(StrToWzID("WEA1"));
}
if (i == 1) // 오른손
{
bone_info_ptr = wz_unit_ptr->GetBoneInfo(StrToWzID("WEA2"));
}
if (!bone_info_ptr)
continue;
WzMatrix* pwzmTransform = weapon_unit_draw_ptr->GetTransformBuffer();
if (!pwzmTransform)
{
return;
}
WzMatrix wmOffsetRot, wmRot, wmPosMat, wmScale;
MatrixIdentity(&wmOffsetRot);
//Rotation
WzVector vRot;
SetVector(&vRot, n_deg2rad(0.0f), n_deg2rad(0.0f), n_deg2rad(0.0f));
MatrixRotationZYX(&wmOffsetRot, &vRot);
MatrixMultiply(&wmRot, &wmOffsetRot, &pwzmTransform[bone_info_ptr->m_iNode]);
//Position
WzVector vOffsetPos;
WzVector offset_pos;
if (i == 0)
{
SetVector(&offset_pos, 0.0f, 0.0f, 0.0f);
}
if (i == 1)
{
SetVector(&offset_pos, -0.3f, 0.0f, 0.0f);
}
VectorTransformCoord(&vOffsetPos, &offset_pos, &wmRot);
MatrixTranslation(&wmPosMat, vOffsetPos.x, vOffsetPos.y, vOffsetPos.z);
//두번적용못하게
wmRot._41=0;
wmRot._42=0;
wmRot._43=0;
MatrixScaling(&wmScale, 1.0f ,1.0f, 1.0f);
if (vice_sword_effect_handle_[i] == INVALID_HANDLE_VALUE)
{
continue;
}
CEffectBody* pBody = g_pEffectManager->GetEffectPtrHandle(vice_sword_effect_handle_[i]);
if (!pBody)
{
continue;
}
pBody->SetResultMatrix(&wmPosMat, &wmRot, &wmScale);
}
}
BOOL Character::is_vice_sword_effect_()
{
if (vice_sword_effect_handle_[0] != INVALID_HANDLE_VALUE &&
vice_sword_effect_handle_[1] != INVALID_HANDLE_VALUE)
{
return TRUE;
}
return FALSE;
}
#endif // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
#ifdef _NA_008069_20150210_ADD_SPA_SYSTEM
void Character::RefreshSpaRender(BOOL refresh_bone /*= FALSE*/)
{
APPEARANCEINFO parts_info;
ZeroMemory(&parts_info, sizeof(parts_info));
DWORD class_code = GetClass();
parts_info.ObjectType = APPEARANCEINFO::PLAYER;
parts_info.Job = class_code;
SLOTCODE spa_item_code = GetSpecialSceneItemCode();
if (spa_item_code == 0)
{
#ifdef _NA_008350_20150617_SPA_NEW_STYLE_MODE_ANIMATION
SpaZoneInfo* spa_info = SpaZoneInfoParser::Instance()->GetSpaZoneInfo(g_pMap->GetMapID());
if (spa_info)
{
spa_item_code = static_cast<SLOTCODE>(spa_info->base_costume_code);
}
#else
spa_item_code = 7254; // 7254 기본 입장권
#endif //_NA_008350_20150617_SPA_NEW_STYLE_MODE_ANIMATION
}
const BASE_ITEMINFO* item_info = ItemInfoParser::Instance()->GetItemInfo(spa_item_code);
if (item_info && item_info->m_wType == eITEMTYPE_SPA_TICKET)
{
DWORD spa_costume_item = 0;
switch (GetImageClass())
{
case eCHAR_BERSERKER: spa_costume_item = item_info->m_wEqClass1; break;
case eCHAR_DRAGON: spa_costume_item = item_info->m_wEqClass2; break;
case eCHAR_SHADOW: spa_costume_item = item_info->m_wEqClass3; break;
case eCHAR_VALKYRIE: spa_costume_item = item_info->m_wEqClass4; break;
case eCHAR_ELEMENTALIST:spa_costume_item = item_info->m_wEqClass5; break;
case eCHAR_MYSTIC: spa_costume_item = item_info->m_wEqClass6; break; // _NA_004965_20120613_NEW_CHARACTER_MYSTIC
case eCHAR_HELLROID: spa_costume_item = item_info->m_wEqClass7; break; // _NA_000000_20130812_NEW_CHARACTER_HELLROID
case eCHAR_WITCHBLADE: spa_costume_item = item_info->m_wEqClass8; break; // _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
}
const BASE_ITEMINFO* costume_item_info = ItemInfoParser::Instance()->GetItemInfo(spa_costume_item);
if (costume_item_info)
{
// 머리
#ifdef _NA_000000_20150616_SPA_COSTUME_SHOW_HAIR
if (GetGender() == GenderType::kMale)
{
if (costume_item_info->m_wCustomize == 1 ||
costume_item_info->m_wCustomize == 2)
{
parts_info.Equipment[BP_HAIR].dwItemID = 0;
parts_info.Equipment[BP_HAIR].iEnchant = 0;
}
else
{
parts_info.Equipment[BP_HAIR].dwItemID = GetPartVariation(PLAYER_VARIATION_HAIR);
parts_info.Equipment[BP_HAIR].iEnchant = costume_item_info->m_bHeadType;
}
}
else
{
if (costume_item_info->m_wCustomize1 == 1 ||
costume_item_info->m_wCustomize1 == 2)
{
parts_info.Equipment[BP_HAIR].dwItemID = 0;
parts_info.Equipment[BP_HAIR].iEnchant = 0;
}
else
{
parts_info.Equipment[BP_HAIR].dwItemID = GetPartVariation(PLAYER_VARIATION_HAIR);
parts_info.Equipment[BP_HAIR].iEnchant = costume_item_info->m_bHeadType1;
}
}
#else
parts_info.Equipment[BP_HAIR].dwItemID = 0;
parts_info.Equipment[BP_HAIR].iEnchant = 0;
#endif //_NA_000000_20150616_SPA_COSTUME_SHOW_HAIR
parts_info.Equipment[BP_FACE].dwItemID = GetPartVariation(PLAYER_VARIATION_FACE);
// 방어구
parts_info.Equipment[BP_ARMOR].dwItemID = costume_item_info->m_Code;
}
}
//파츠 갱신
RefreshRender(&parts_info, refresh_bone);
ReleaseFullsetEffect();
class_code = GetImageClass();
SetScale(GetHeightInfo(static_cast<eCHAR_TYPE>(class_code), GetHeightVariation()));
}
#endif //_NA_008069_20150210_ADD_SPA_SYSTEM
#ifdef _NA_008472_20150903_IMPROVED_BALANCE
BOOL Character::IsAbnormalityProtection()
{
// 디펜스모션 일 때 이상상태 보호.
if (this->FindSkillEffect(eCHAR_STATE_PROTECTION))
{
return TRUE;
}
// 에너지석션 일 때 이상상태 보호.
if (this->FindSkillEffect(eCHAR_STATE_HP_SUCTION))
{
return TRUE;
}
return FALSE;
}
#endif // _NA_008472_20150903_IMPROVED_BALANCE
#ifdef _NA_008679_20160202_REWORK_BATTLEGROUND
void Character::RefreshBattleGroundRender(BOOL refresh_bone /*= FALSE*/)
{
APPEARANCEINFO parts_info;
ZeroMemory(&parts_info, sizeof(parts_info));
DWORD class_code = GetClass();
parts_info.ObjectType = APPEARANCEINFO::PLAYER;
parts_info.Job = class_code;
SLOTCODE special_item_code = GetSpecialSceneItemCode();
BYTE scene_costume_code = HIBYTE(special_item_code);
BYTE scene_weapon_code = LOBYTE(special_item_code);
BattleGroundCostumeInfo* costume_info =
BattleGroundInfoParser::Instance()->GetBattleGroundCostumeInfo(scene_costume_code, GetClass());
if (costume_info == NULL)
{
#ifdef _DEV_VER
GlobalFunc::OutputMsg_Notice(eOUTPUT_MSG_CHAT, "BattleGroundCostumeInfo is NULL: costume code(%d)",scene_costume_code);
#endif //_DEV_VE
}
else
{
if (costume_info->costume_code1 != 0 || costume_info->costume_code2 != 0)
{
// 코스튬 코드가 있는 경우
const BASE_ITEMINFO* item_info = ItemInfoParser::Instance()->GetItemInfo(
GetGender() == GenderType::kMale ? costume_info->costume_code1 : costume_info->costume_code2);
if (item_info)
{
// 머리
parts_info.Equipment[BP_HAIR].dwItemID = GetPartVariation(PLAYER_VARIATION_HAIR);
parts_info.Equipment[BP_HAIR].iEnchant = GetGender() == GenderType::kFemale ? item_info->m_bHeadType1 : item_info->m_bHeadType;
parts_info.Equipment[BP_FACE].dwItemID = GetPartVariation(PLAYER_VARIATION_FACE);
// 방어구
parts_info.Equipment[BP_ARMOR].dwItemID = item_info->m_Code;
}
}
else
{
// 코스튬 코드가 없는 경우
SCItemSlot ItemSlot;
ItemSlot.SetEnchant(costume_info->enchant);
if (costume_info->armor_item_code)
{
ItemSlot.SetCode(costume_info->armor_item_code);
SetEquipAppearInfo(&parts_info.Equipment[BP_ARMOR], ItemSlot);
}
if (costume_info->helm_item_code)
{
ItemSlot.SetCode(costume_info->helm_item_code);
//SetEquipAppearInfo(&parts_info.Equipment[BP_HELM], ItemSlot);
SetEquipAppearHelmet(parts_info,
ItemSlot,
GetPartVariation(PLAYER_VARIATION_HAIR),
GetPartVariation(PLAYER_VARIATION_FACE),
FALSE,
GetGender()
);
}
if (costume_info->pants_item_code)
{
ItemSlot.SetCode(costume_info->pants_item_code);
SetEquipAppearInfo(&parts_info.Equipment[BP_PANTS], ItemSlot);
}
if (costume_info->boots_item_code)
{
ItemSlot.SetCode(costume_info->boots_item_code);
SetEquipAppearInfo(&parts_info.Equipment[BP_BOOTS], ItemSlot);
}
if (costume_info->gloves_item_code)
{
ItemSlot.SetCode(costume_info->gloves_item_code);
SetEquipAppearInfo(&parts_info.Equipment[BP_GLOVE], ItemSlot);
}
}
}
// 무기
BattleGroundWeaponInfo* weapon_info =
BattleGroundInfoParser::Instance()->GetBattleGroundWeaponInfo(scene_weapon_code, GetClass());
if (weapon_info == NULL)
{
#ifdef _DEV_VER
GlobalFunc::OutputMsg_Notice(eOUTPUT_MSG_CHAT, "GetBattleGroundWeaponInfo is NULL: weapon code(%d)",scene_weapon_code);
#endif //_DEV_VE
}
else
{
WORD item_code = 0;
if (GetWeaponKind() == weapon_info->weapon_type_A)
{
item_code = weapon_info->weapon_item_code_A;
}
else if (GetWeaponKind() == weapon_info->weapon_type_B)
{
item_code = weapon_info->weapon_item_code_B;
}
if (item_code)
{
SCItemSlot ItemSlot;
ItemSlot.SetCode(item_code);
ItemSlot.SetEnchant(weapon_info->enchant);
SetEquipAppearInfo(&parts_info.Equipment[BP_WEAPON], ItemSlot);
}
}
//파츠 갱신
RefreshRender(&parts_info, refresh_bone);
ReleaseFullsetEffect();
class_code = GetImageClass();
SetScale(GetHeightInfo(static_cast<eCHAR_TYPE>(class_code), GetHeightVariation()));
}
#endif //_NA_008679_20160202_REWORK_BATTLEGROUND