8415 lines
222 KiB
C++
8415 lines
222 KiB
C++
#include "stdafx.h"
|
|
#include <deque> // 2.1.16 변신 효과 중첩시 아바타 사라지는 오류 수정
|
|
#include "K3DTypes.h"
|
|
#include "SEventKeyRes.h"
|
|
#include "KSeqAvatarEx.h"
|
|
#include "KSeqAvatar.h"
|
|
#include "KSeqModel.h"
|
|
|
|
#include "KRenderObjectBone.h"
|
|
#include "KRenderObjectEtc.h"
|
|
#include "KRenderObjectMesh.h"
|
|
|
|
#include "SGameUtil.h"
|
|
|
|
#include "SAvatarProperty.h"
|
|
#include "SGameAvatarEx.h"
|
|
|
|
|
|
#include "SGame.h"
|
|
|
|
#include "SCobManager.h"
|
|
#include "SBasicStat.h"
|
|
//#include "Util.h"
|
|
//#include "GameDefine.h"
|
|
#include "SGameWork.h"
|
|
#include "SGameMessage.h"
|
|
#include "LuaVM.h"
|
|
|
|
#include "SGameViewPort.h"
|
|
|
|
#include <toolkit/XStringUtil.h>
|
|
|
|
#include "SMonsterDB.h"
|
|
#include "SCreatureDB.h"
|
|
#include "SNpcDB.h"
|
|
#include "SPetDB.h" // sonador 10.2.1 팻 시스템 구현
|
|
#include "SNpcResourceDB.h"
|
|
#include "SItemDB.h"
|
|
|
|
#include "SDefaultTextureResourceDB.h"
|
|
|
|
#include "SStringDB.h"
|
|
#include "SSkillDB.h"
|
|
#include "SMotionDB.h"
|
|
//#include "SEnhanceFXDB.h"
|
|
#include "SModelEffectResourceDB.h"
|
|
#include "STenacityDB.h"
|
|
#include "SSoundResourceDB.h"
|
|
|
|
//#include "Smove_filter.h"
|
|
|
|
//#include "SGameMessageUI.h"
|
|
|
|
#include "SDebug_Util.h"
|
|
|
|
#include "SGameSystem.h"
|
|
#include "SBotManager.h"
|
|
|
|
#include "SGameAvatarAddOnMgr.h"
|
|
#include "SGameForceSphereFX.h"
|
|
#include "SGameCircleShadowFX.h"
|
|
#include "SGameAvatarFx.h"
|
|
|
|
#include "SGameAvatarTerrainDegree.h"
|
|
|
|
#include "SGameFxSwordSlash.h"
|
|
#include "SGameFxWeaponPowerup.h"
|
|
|
|
#include "SGameOption.h"
|
|
|
|
#include <toolkit/bits_scramble.h>
|
|
|
|
#include "SSKillStageType.h"
|
|
#include "SPlayerInfoMgr.h"
|
|
//#include "SGameMessageUI.h"
|
|
#include "SUISysMsgDefine.h"
|
|
#include "SGameOption.h"
|
|
|
|
// 2010.04.22 - prodongi
|
|
#include "SSelectedAvatarInfo.h"
|
|
// 2010.05.11 - prodongi
|
|
|
|
#include "ItemBase.h"
|
|
#include "SGameWorld.h"
|
|
#include "WorldLocation.h"
|
|
#include "Arena\\ArenaSystem.h"
|
|
|
|
#include "SGameLocalPlayer.h"
|
|
|
|
extern SGameSystem* g_pCurrentGameSystem;
|
|
extern SBotManager* g_pSBotMng;
|
|
|
|
|
|
unsigned int g_pEnhanceColor[26][4]
|
|
= {
|
|
#include "EnhanceColor.txt"
|
|
};
|
|
|
|
#ifdef _DEV
|
|
void _EnhanceColorReload(void)
|
|
{
|
|
FILE* fp = fopen("EnhanceColor.txt", "rt");
|
|
if (fp == NULL) return;
|
|
|
|
|
|
memset(g_pEnhanceColor, 0, sizeof(g_pEnhanceColor));
|
|
for (int i = 0; i < 26; i++)
|
|
{
|
|
while (TRUE)
|
|
{
|
|
char buf[256];
|
|
char* ret = fgets(buf, 255, fp);
|
|
if (ret <= 0) break;
|
|
int len = strlen(buf);
|
|
for (int j = 0; j < len; j++)
|
|
{
|
|
if (buf[j] == '\"' || buf[j] == ',' || buf[j] < ' ') buf[j] = ' ';
|
|
}
|
|
char token[4][256];
|
|
sscanf(buf, "%s %s %s %s", token[0], token[1], token[2], token[3]);
|
|
if (token[0][0] == '/') continue;
|
|
|
|
int mode = _tcstoul(token[0], NULL, 16);
|
|
g_pEnhanceColor[i][0] = mode;
|
|
mode = _tcstoul(token[1], NULL, 16);
|
|
g_pEnhanceColor[i][1] = mode;
|
|
mode = _tcstoul(token[2], NULL, 16);
|
|
g_pEnhanceColor[i][2] = mode;
|
|
mode = _tcstoul(token[3], NULL, 16);
|
|
g_pEnhanceColor[i][3] = mode;
|
|
break;
|
|
};
|
|
}
|
|
|
|
fclose(fp);
|
|
}
|
|
#endif
|
|
|
|
// #include <typeinfo.h>
|
|
|
|
/// 2010.11.04 안 쓰는 것 같음 - prodongi
|
|
/*
|
|
const char * pEffPos[] =
|
|
{
|
|
"_top.nx3",
|
|
"_middle.nx3",
|
|
"_damage.nx3",
|
|
"_etc.nx3",
|
|
"_saddle.nx3",
|
|
};
|
|
*/
|
|
|
|
|
|
unsigned int g_pWeaponLength[12][8] =
|
|
{
|
|
0, 11, 12, 13, 13, 14, 15, 16, //< 한손검 101
|
|
0, 14, 15, 16, 17, 18, 20, 22, //< 한손검x->양손검 102
|
|
0, 8, 8, 9, 10, 11, 12, 13, //< 단검 103
|
|
0, 14, 16, 17, 18, 19, 21, 22, //< 창 104
|
|
0, 11, 11, 12, 13, 13, 14, 14, //< 도끼 105
|
|
0, 7, 8, 9, 10, 11, 12, 13, //< 한손메이스 106
|
|
0, 11, 11, 11, 12, 13, 14, 15, //< 양손메이스 107
|
|
0, 10, 10, 10, 10, 10, 10, 10, //< 헤비 보우 108 //10, 11, 12, 13, 14, 15, 16, 18, //< 라이트 보우 108 - 109
|
|
0, 10, 10, 10, 10, 10, 10, 10, //< 석궁 109 - 110
|
|
0, 10, 10, 11, 12, 12, 13, 13, //< 한손 지팡이 110 - 111
|
|
0, 12, 13, 14, 14, 15, 15, 16, //< 양손 지팡이 111 - 112
|
|
0, 7, 7, 8, 8, 9, 9, 9, //< 한손도끼 112 - 113
|
|
};
|
|
|
|
|
|
extern const char* pEP_Name[];
|
|
|
|
const char* pPartExt[] = { "_biped.naf","_hair.naf","_necklace.naf", "_earring.naf","_mantle.naf","_fabric.naf","_longskirt.naf","_middleskirt.naf","_shortskirt.naf","_weaponl.naf","_weaponr.naf", };
|
|
const char* pPart[] = { "biped","hair","necklace", "earring","mantle","fabric","longskirt","middleskirt","shortskirt","weaponl","weaponr", };
|
|
const char* pSex[] = { "n", "f", "m", };
|
|
const char* pRace[] = { "non", "mob", "npc", "ga", "de", "as", "af", "gi", "am", };
|
|
|
|
const char* pLeftHandEpName[2] =
|
|
{
|
|
"ep_wfx_00_l",
|
|
"ep_wfx_01_l",
|
|
};
|
|
const char* pRightHandEpName[2] =
|
|
{
|
|
"ep_wfx_00",
|
|
"ep_wfx_01",
|
|
};
|
|
const char* pTwoHandEpName[2] =
|
|
{
|
|
"ep_wfx_00_th",
|
|
"ep_wfx_01_th",
|
|
};
|
|
|
|
const char* pWeaponEpName[EFFECT_POS_WEAPON_MAX][EFFECT_POS_WEAPON_EP_MAX] =
|
|
{
|
|
{ "ep_wfx_00_l", "ep_wfx_01_l" },
|
|
{ "ep_wfx_00", "ep_wfx_01" },
|
|
{ "ep_wfx_00_th", "ep_wfx_01_th" },
|
|
};
|
|
|
|
|
|
const int WEAPON_SLASH_RECORD_SUBDIVISION = 16; // 각 frame을 sub분할하는 횟수
|
|
const int WEAPON_SLASH_RECORD_ARROW_SUBDIVISION = 1; // 각 frame을 sub분할하는 횟수
|
|
const short c_WINK_TIME = 1000; //Face Ani
|
|
|
|
const int RAMADAN_ITEM_ARMOR = 2520016;
|
|
const int RAMADAN_ITEM_HAT = 2520017;
|
|
const int RAMADAN_ITEM_GLOVE = 2520018;
|
|
const int RAMADAN_ITEM_BOOTS = 2520019;
|
|
|
|
extern K3DTexture* _getTexture(const char* texname, DWORD skin_color = 0);
|
|
|
|
//GameDefine.h 참조
|
|
|
|
#define _WEAPON_FX_
|
|
//레이저를 쏴서, 이동 리스트를 만들어서, 단계별 이동.
|
|
//namespace
|
|
//{
|
|
// struct intf_move_filter
|
|
// {
|
|
// static bool is_empty_at( SGameObject *pObj, float x, float y )
|
|
// {
|
|
// return pObj->IsBlockedAttribute( x, y );
|
|
// }
|
|
// };
|
|
//
|
|
// typedef move_filter<intf_move_filter, 16, 16> SPATHFINDER;
|
|
//};
|
|
|
|
bool SGameAvatarEx::m_sCubeRender = false;
|
|
bool SGameAvatarEx::m_sMoveSound = true;
|
|
bool SGameAvatarEx::m_sEnhanceTest = true;
|
|
|
|
volatile bool SGameAvatarEx::s_bStopThread = false;
|
|
static XCriticalSection s_AvatarLoadingLock;
|
|
static std::list< SGameAvatarEx* > s_lstThreadLoadingAvatar;
|
|
const float c_fStateCheckTime = 1000.f;
|
|
|
|
// Bone recorder
|
|
// 검광용으로 bone 위치를 보간하여 world에 대한 무기 위치 matrix를 얻어옴
|
|
class BoneRecorder {
|
|
public:
|
|
BoneRecorder() { avatar = NULL; starttime = endtime = 0; subdivision = 0; matrix_left = matrix_right = NULL; }
|
|
BoneRecorder(SGameAvatarEx* _avatar, int _subdivision) {
|
|
avatar = NULL; starttime = endtime = 0; subdivision = 0; matrix_left = matrix_right = NULL;
|
|
init(_avatar, _subdivision);
|
|
}
|
|
|
|
virtual ~BoneRecorder() { clear(); }
|
|
|
|
void init(SGameAvatarEx* _avatar, int _subdivision) {
|
|
clear();
|
|
avatar = _avatar;
|
|
if (_subdivision > 0) {
|
|
matrix_left = new K3DMatrix[_subdivision];
|
|
matrix_right = new K3DMatrix[_subdivision];
|
|
subdivision = _subdivision;
|
|
}
|
|
}
|
|
|
|
void clear() {
|
|
if (matrix_left != NULL) { delete[] matrix_left; matrix_left = NULL; }
|
|
if (matrix_right != NULL) { delete[] matrix_right; matrix_right = NULL; }
|
|
|
|
subdivision = 0;
|
|
starttime = endtime = 0;
|
|
avatar = NULL;
|
|
}
|
|
|
|
|
|
void record(DWORD _starttime, DWORD _endtime)
|
|
{
|
|
while (true)
|
|
{
|
|
if (avatar == NULL) break;
|
|
|
|
KSeqAvatarEx* seqAvatar = avatar->GetSeqForm();
|
|
if (seqAvatar == NULL) break;
|
|
|
|
KSeqAvatar* bipedSeq = seqAvatar->getAvatarPart(ANIPART_BIPED); // biped animation part
|
|
if (bipedSeq == NULL) break;
|
|
|
|
KBoneSeqObject* pBoneSeq = bipedSeq->getBoneSequencer(); // biped bone
|
|
if (pBoneSeq == NULL) break;
|
|
|
|
KBoneSeqObject* boneSeqRightWeapon = NULL; // 무기의 animation bone
|
|
KBoneSeqObject* boneSeqLeftWeapon = NULL;
|
|
|
|
|
|
KSeqAvatar* rightHandSeq = seqAvatar->getAvatarPart(ANIPART_WEAPON_RIGHT); // 오른손 무기가 붙을 위치
|
|
KSequencer* sequencer = dynamic_cast<KSequencer*>(rightHandSeq->GetCurrentAnimation());
|
|
if (sequencer != NULL)
|
|
{
|
|
boneSeqRightWeapon = dynamic_cast<KBoneSeqObject*> (sequencer->GetSeqObject(0));
|
|
}
|
|
|
|
KSeqAvatar* leftHandSeq = seqAvatar->getAvatarPart(ANIPART_WEAPON_LEFT); // 왼손 무기가 붙을 위치
|
|
sequencer = dynamic_cast<KSequencer*>(leftHandSeq->GetCurrentAnimation());
|
|
if (sequencer != NULL)
|
|
{
|
|
boneSeqLeftWeapon = dynamic_cast<KBoneSeqObject*> (sequencer->GetSeqObject(0));
|
|
}
|
|
|
|
if (boneSeqRightWeapon == NULL && boneSeqLeftWeapon == NULL) break;
|
|
|
|
K3DMatrix* pWeaponPosMat = NULL;
|
|
K3DMatrix* pBoneMat = NULL;
|
|
K3DMatrix tempMat;
|
|
|
|
DWORD actionTime;
|
|
starttime = _starttime;
|
|
endtime = _endtime;
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < subdivision; i++)
|
|
{
|
|
actionTime = (endtime - starttime) * (i + 1) / subdivision + starttime;
|
|
|
|
// Animate master bone sequencer
|
|
seqAvatar->Process(actionTime);
|
|
seqAvatar->realizeTime();
|
|
|
|
//pBoneSeq->SetTime(actionTime); // seqAvatar->Process()가 내부적으로 child시간을 계산하므로 SetTime()하면 안 됨
|
|
// pBoneSeq / boneSeq...Weapon해당
|
|
pBoneSeq->realizeTime();
|
|
|
|
if (boneSeqRightWeapon != NULL)
|
|
{
|
|
// 오른손 무기 최종 위치 계산
|
|
boneSeqRightWeapon->realizeTime();
|
|
pWeaponPosMat = &(boneSeqRightWeapon->GetBoneCacheTM()[1]);
|
|
// [0] : hand position (parallel to elbow)
|
|
// [1] : grip position (in the handle, transformed)
|
|
// [2] : blade vector (very long)
|
|
assert(pWeaponPosMat != NULL);
|
|
|
|
pBoneMat = pBoneSeq->GetBoneMatrix(DETAIL_RIGHT_HAND);
|
|
|
|
if (pBoneMat != NULL)
|
|
{
|
|
/* K3DMatrixMultiply( &(matrix_right[i])
|
|
, pWeaponPosMat // 무기 끝 위치
|
|
, pBoneMat ); // 오른손 무기 base위치
|
|
*/ K3DMatrixMultiply(tempMat, *pBoneMat, seqAvatar->GetTransform()); // <- 이것도 어떻게 보간 안 되나??
|
|
K3DMatrixMultiply((matrix_right[i]), *pWeaponPosMat, tempMat);
|
|
}
|
|
else
|
|
{
|
|
K3DMatrixIdentity((matrix_right[i]));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
K3DMatrixIdentity((matrix_right[i]));
|
|
}
|
|
|
|
if (boneSeqLeftWeapon != NULL)
|
|
{
|
|
// 왼손 무기 최종 위치 계산
|
|
boneSeqLeftWeapon->realizeTime();
|
|
pWeaponPosMat = &(boneSeqLeftWeapon->GetBoneCacheTM()[1]);
|
|
// [0] : hand position (parallel to elbow)
|
|
// [1] : grip position (in the handle, transformed)
|
|
// [2] : blade vector (very long)
|
|
assert(pWeaponPosMat != NULL);
|
|
|
|
pBoneMat = pBoneSeq->GetBoneMatrix(DETAIL_LEFT_HAND);
|
|
if (pBoneMat != NULL)
|
|
{
|
|
/* K3DMatrixMultiply( (matrix_left[i])
|
|
, *pWeaponPosMat // 무기 끝 위치
|
|
, *pBoneMat ); // 왼손 무기 base위치
|
|
*/ K3DMatrixMultiply(tempMat, *pBoneMat, seqAvatar->GetTransform());
|
|
K3DMatrixMultiply((matrix_left[i]), *pWeaponPosMat, tempMat);
|
|
}
|
|
else
|
|
{
|
|
K3DMatrixIdentity((matrix_left[i]));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
K3DMatrixIdentity((matrix_left[i]));
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//break 된 경우만 처리
|
|
{
|
|
// No capture
|
|
int i;
|
|
starttime = _starttime;
|
|
endtime = _endtime;
|
|
for (i = 0; i < subdivision; i++) {
|
|
K3DMatrixIdentity((matrix_right[i]));
|
|
K3DMatrixIdentity((matrix_left[i]));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public:
|
|
SGameAvatarEx* avatar;
|
|
DWORD starttime, endtime; // 시작시간 < 레코딩 <=끝시간. 시작시간은 계산하지 않는다.
|
|
int subdivision; // recording될 entry 숫자
|
|
K3DMatrix* matrix_left; // matrix[subdivision], 왼손용
|
|
K3DMatrix* matrix_right; // matrix[subdivision], 오른손용
|
|
};
|
|
|
|
// 2.1.16 변신 효과 중첩시 아바타 사라지는 오류 수정
|
|
class DisguiseStack
|
|
{
|
|
public:
|
|
struct Slot
|
|
{
|
|
Slot(unsigned int _stateHandle, ENC_INT _contentID, KSeqAvatarEx* _seqAvatar, float _size, float _scale, bool _isSummon)
|
|
: stateHandle(_stateHandle)
|
|
, contentID(_contentID)
|
|
, seqAvatar(_seqAvatar)
|
|
, size(_size)
|
|
, scale(_scale)
|
|
, isSummon(_isSummon)
|
|
{
|
|
}
|
|
~Slot()
|
|
{
|
|
}
|
|
Slot& operator = (const Slot& rhs)
|
|
{
|
|
//stateHandle = rhs.stateHandle; // <-- rhs 를 대입하는 것이 아니라, rhs 의 정보를 넘겨 받는 것이므로 핸들은 그대로 둔다.(ex. 중간삭제일경우)
|
|
contentID = rhs.contentID;
|
|
seqAvatar = rhs.seqAvatar;
|
|
size = rhs.size;
|
|
scale = rhs.scale;
|
|
isSummon = rhs.isSummon;
|
|
return *this;
|
|
}
|
|
bool operator == (unsigned int _stateHandle) { return stateHandle == _stateHandle; }
|
|
|
|
ENC_INT contentID;
|
|
unsigned short stateHandle;
|
|
KSeqAvatarEx* seqAvatar;
|
|
float size;
|
|
float scale;
|
|
bool isSummon;
|
|
};
|
|
|
|
struct FindByStateHandle {
|
|
FindByStateHandle(unsigned int _stateHandle) : stateHandle(_stateHandle) {}
|
|
bool operator () (const Slot& obj) const { return obj.stateHandle == stateHandle; }
|
|
unsigned int stateHandle;
|
|
};
|
|
|
|
typedef std::deque< Slot >::iterator iterator;
|
|
typedef std::deque< Slot >::const_iterator const_iterator;
|
|
|
|
~DisguiseStack()
|
|
{
|
|
while (!mSlots.empty())
|
|
{
|
|
Slot& slot = mSlots.back();
|
|
SAFE_DELETE(slot.seqAvatar);
|
|
mSlots.pop_back();
|
|
}
|
|
}
|
|
bool empty() const
|
|
{
|
|
return mSlots.empty();
|
|
}
|
|
bool onDisguise(const Slot& slot)
|
|
{
|
|
|
|
|
|
iterator found = std::find_if(mSlots.begin(), mSlots.end(), FindByStateHandle(slot.stateHandle));
|
|
|
|
if (found == mSlots.end())
|
|
{
|
|
mSlots.push_back(slot);
|
|
return true;
|
|
}
|
|
|
|
if (found == (mSlots.end() - 1))
|
|
return false;
|
|
|
|
iterator next = found + 1;
|
|
SAFE_DELETE(next->seqAvatar);
|
|
*next = *found;
|
|
mSlots.erase(found);
|
|
|
|
mSlots.push_back(slot);
|
|
return true;
|
|
}
|
|
bool onUndisguise(Slot& slot)
|
|
{
|
|
|
|
if (mSlots.empty())
|
|
return false;
|
|
|
|
iterator found;
|
|
|
|
// 핸들이 0 이면 정상적인 스택처럼 동작한다.
|
|
if (slot.stateHandle == 0)
|
|
{
|
|
found = mSlots.end() - 1;
|
|
}
|
|
else
|
|
{
|
|
found = std::find_if(mSlots.begin(), mSlots.end(), FindByStateHandle(slot.stateHandle));
|
|
if (found == mSlots.end())
|
|
return false;
|
|
|
|
// 변신 해제를 하기 위한 슬롯 정보가
|
|
// 스택의 마지막에 있는지 검사한다.
|
|
// 즉, 변신해제후 아바타의 변경이
|
|
// 필요한지를 검사한다.
|
|
if (found->stateHandle != mSlots.back().stateHandle)
|
|
{
|
|
iterator next = found + 1;
|
|
SAFE_DELETE(next->seqAvatar);
|
|
*next = *found;
|
|
mSlots.erase(found);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
slot = *found;
|
|
mSlots.pop_back();
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
std::deque< Slot > mSlots;
|
|
};
|
|
|
|
SGameAvatarEx::SGameAvatarEx(ENC_INT nContentID) :m_bArrowTrail(false)
|
|
, m_bBowClass(false)
|
|
, m_nEnergy(0)
|
|
, m_nFirst(0)
|
|
, m_nIsRefreshAni(0)
|
|
, m_pThreadAvatarEx(NULL)
|
|
, m_nThreadAniClass(0)
|
|
, m_bIsThreadPending(false)
|
|
, m_bIsThreadLoading(false)
|
|
, m_pProperty(new SAvatarProperty(nContentID)) //게임 컨텐츠
|
|
, m_pStateVM(NULL)
|
|
, m_pSeqAvatar(NULL)
|
|
, m_nProcess_state(-1) //Animation 상태
|
|
, m_nAniClass(0) //기본 Ani
|
|
, m_bLockAni(false)
|
|
, m_bLockAttackAni(false)
|
|
, m_dwTime(0) //시간
|
|
, m_dwStartTime(0) //시작 시간
|
|
, m_fVisibility(0.0f)
|
|
, m_speed(DEF_SPEED)
|
|
, m_bLocal(false)
|
|
, m_bLocalCreature(false)
|
|
, m_bLocalPet(false)
|
|
, m_vCheckPos(0.0f, 0.0f, 0.0f)
|
|
, m_pSeqRideLink(NULL)
|
|
, m_bIng(false)
|
|
, m_bReservation(false) //삭제 보류 대상 인가?
|
|
, m_bVisible(true)
|
|
, m_bPrevVisible(true)
|
|
, m_bIsMovingDetour(false)
|
|
, m_bIsChasing(false)
|
|
, m_unDetourStep(0)
|
|
, m_bRefreshDetour(false)
|
|
, m_CurrState(SObjectState::ID::STATE_NONE)
|
|
, m_CurrTarget(0)
|
|
, m_nWeaponSwing_RepeatMotion(0)
|
|
, m_pUISyncData(new UI_SYNC_DATA)
|
|
, m_bIsDead(false)
|
|
, m_bUseRot(true)
|
|
, m_fTargetRoll(1.0f)
|
|
, m_fPresentRoll(1.0f)
|
|
, m_dwPrevTime(0)
|
|
, m_vNextPos(0.0f, 0.0f, 0.0f)
|
|
, m_vView(0.0f, 1.0f, 0.0f)
|
|
, m_vTempView(m_vView)
|
|
, m_nAttackIndex(0)
|
|
, m_vTerrainPickPos(0.0f, 1.0f, 0.0f)
|
|
, m_nNewCurAniType(ANI_DEFAULT01)
|
|
, m_nCurPlayType(SEQTYPE_LOOP)
|
|
, m_pBoneRecorder(NULL)
|
|
, m_bUseRightWeaponTrail(false) // 오른손 무기 궤적 사용?
|
|
, m_bUseLeftWeaponTrail(false) // 왼손 무기 궤적 사용?
|
|
, m_pWeaponTrailRight(NULL) // 오른손 무기 궤적 object
|
|
, m_pWeaponTrailLeft(NULL) // 왼손 무기 궤적 object
|
|
, m_bThreadUseRightWeaponTrail(false)
|
|
, m_bThreadUseLeftWeaponTrail(false)
|
|
, m_bActRightWeaponTrail(false)
|
|
, m_bActLeftWeaponTrail(false)
|
|
, m_pAddOnMgr(new SGameAvatarAddOnMgr)
|
|
, m_bActivateTerrainDegree(false)
|
|
, m_pTerrainDegree(NULL)
|
|
, m_bPlayOverride(false)
|
|
, m_vTerrainNormal(0.0f, 0.0f, 0.0f)
|
|
, m_bRefreshInven(false)
|
|
, m_cPrevAttackIndex(0)
|
|
, m_pDisguiseStack(new DisguiseStack) // 2.1.16 변신 효과 중첩시 아바타 사라지는 오류 수정
|
|
//, m_pDisguiseSeqAvatar( NULL )
|
|
, m_nDisguise(NONE_DISGUISE)
|
|
//, m_fDisguiseSize( 1.0f )
|
|
//, m_fDisguiseScale( 1.0f )
|
|
, m_bActRightSwordSlashForSkill(false) //스킬 용
|
|
, m_bActLeftSwordSlashForSkill(false) //스킬 용
|
|
, m_pRightSwordSlashForSkill(NULL)
|
|
, m_pLeftSwordSlashForSkill(NULL)
|
|
, m_nSwordSlashForSkillMotion(0)
|
|
, m_nStateFlag(FLAG_STATE_NONE)
|
|
, m_fHidingVisiblity(1.0f)
|
|
, m_fHidingDetectRange(0.0f)
|
|
, m_bFootsteps(false)
|
|
, m_vTargetPos(0.0f, 0.0f, 0.0f)
|
|
, m_nTraceIdx(0)
|
|
, m_SkinDiffuse(0, 0, 0, 0)
|
|
, m_bPendLoading(false)
|
|
, m_fScaleAdjustDest(1.0f)
|
|
, m_fScaleAdjustPrev(1.0f)
|
|
, m_nScaleAdjustStartTime(0)
|
|
, m_fScaleAdjust(1.0f)
|
|
, m_nFadeOutStartTime(0)
|
|
, m_hCreatureTemp(NULL) // 2010.08.12 - prodongi
|
|
, m_bIsReloadWearListFileName(false)
|
|
, m_dwCheckTime(0)
|
|
, LastWeaponSwapTime(0) // Fraun weaponb swap exploit fix 8/19/2025
|
|
{
|
|
SetEventHandleNull();
|
|
|
|
memset(m_itemClass, 0, sizeof(m_itemClass));
|
|
|
|
for (int i(0); 3 > i; i++)
|
|
{
|
|
m_fSelcube[i] = -2;
|
|
m_fDeadcube[i] = -2;
|
|
}
|
|
for (int i(3); 6 > i; i++)
|
|
{
|
|
m_fSelcube[i] = 2;
|
|
m_fDeadcube[i] = 2;
|
|
}
|
|
|
|
for (int x = 0; x < 3; x++)
|
|
{
|
|
//1아이템 코드 //2파티클 아이디 //3이펙트 아이디
|
|
m_nLeftHandWeaponCode[x] = -1;
|
|
m_nRightHandWeaponCode[x] = -1;
|
|
m_nTwoHandWeaponCode[x] = -1;
|
|
}
|
|
|
|
for (int i = 0; i < EFFECT_POS_MAX; ++i)
|
|
{
|
|
K3DMatrixIdentity(m_matEVPMatrix[i]);
|
|
K3DMatrixIdentity(m_matEVPAttachMatrix[i]);
|
|
m_pEvpSequencer[i] = NULL;
|
|
m_bEVPAttachMatrix[i] = false;
|
|
}
|
|
|
|
for (int i = 0; i < EFFECT_POS_WEAPON_MAX; ++i)
|
|
{
|
|
for (int x = 0; x < EFFECT_POS_WEAPON_EP_MAX; x++)
|
|
{
|
|
K3DMatrixIdentity(m_matWeaponEVPMatrix[i][x]);
|
|
K3DMatrixIdentity(m_matWeaponEVPAttachMatrix[i][x]);
|
|
K3DMatrixIdentity(m_matWeaponEVPParentMatrix[i][x]);
|
|
m_pWeaponEvpSequencer[i][x] = NULL;
|
|
}
|
|
|
|
m_bWeaponEVPMatrix[i] = false;
|
|
}
|
|
|
|
m_nClassID = OBJ_PLAYER;
|
|
m_pArObject = NULL; //LocalPlayer() 만 설정
|
|
m_wCurTile = 0;
|
|
m_bInWater = false;
|
|
|
|
m_pAddOnMgr->SetGameObject(this);
|
|
|
|
m_dwSkinColor = 0;
|
|
|
|
m_dwHairColor = 0;
|
|
m_nHairColorIndex = 0;
|
|
// 2010.05.19 - prodongi
|
|
m_hideEquipInfo = 0;
|
|
m_noneDisguiseScale = 1.0f; /// 2011.04.29 - prodongi
|
|
m_disguiseEnhance = 0; /// 2011.07.28 redmine #16797 - prodongi
|
|
|
|
m_syncCamRoll = false;
|
|
m_isKMoving = false;
|
|
m_kmoveType = 0;
|
|
m_kmoveDir = 0.0f;
|
|
|
|
#ifdef _DEV
|
|
_EnhanceColorReload();
|
|
#endif
|
|
}
|
|
|
|
SGameAvatarEx::~SGameAvatarEx()
|
|
{
|
|
while (m_bIsThreadLoading)
|
|
{
|
|
Sleep(100);
|
|
}
|
|
|
|
removeFromLoadingList();
|
|
|
|
Destroy();
|
|
}
|
|
|
|
ANI_LIST_EX SGameAvatarEx::GetDefaultAnimation()
|
|
{
|
|
if (IsDead() || !IsLive())
|
|
{
|
|
return ANI_DEAD01; //죽었음
|
|
}
|
|
|
|
return ANI_DEFAULT01;
|
|
}
|
|
|
|
void SGameAvatarEx::SetMotionBlend(bool bIsBlend)
|
|
{
|
|
if (!m_pSeqAvatar || !m_bIsInit) return;
|
|
|
|
_CID(SETBONEBLEND);
|
|
KMsgGET_SETBONEBLEND msg;
|
|
msg.bUseBlend = bIsBlend;
|
|
Perform(id_SETBONEBLEND, msg);
|
|
}
|
|
|
|
unsigned int __stdcall SGameAvatarEx::avatar_loader(void* pArg)
|
|
{
|
|
while (!s_bStopThread)
|
|
{
|
|
SGameAvatarEx* pAvatar = NULL;
|
|
{
|
|
s_AvatarLoadingLock.Lock();
|
|
if (s_lstThreadLoadingAvatar.empty())
|
|
{
|
|
s_AvatarLoadingLock.UnLock();
|
|
#ifdef _DEBUG
|
|
Sleep(100);
|
|
#else
|
|
Sleep(50);
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
pAvatar = s_lstThreadLoadingAvatar.front();
|
|
s_lstThreadLoadingAvatar.pop_front();
|
|
|
|
pAvatar->StartThreadLoading();
|
|
s_AvatarLoadingLock.UnLock();
|
|
}
|
|
|
|
pAvatar->doLoading();
|
|
}
|
|
|
|
s_bStopThread = false;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void SGameAvatarEx::BeginAvatarLoadingThread()
|
|
{
|
|
unsigned dwThreadID;
|
|
HANDLE hThread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, SGameAvatarEx::avatar_loader, NULL, 0, &dwThreadID));
|
|
CloseHandle(hThread);
|
|
}
|
|
|
|
void SGameAvatarEx::EndAvatarLoadingThread()
|
|
{
|
|
_oprint("**THREAD INFO : SGameAvatarEx::EndAvatarLoadingThread\n");
|
|
|
|
s_bStopThread = true;
|
|
|
|
while (s_bStopThread) Sleep(1);
|
|
}
|
|
|
|
void SGameAvatarEx::removeFromLoadingList()
|
|
{
|
|
THREAD_SYNCRONIZE(s_AvatarLoadingLock);
|
|
|
|
if (!m_bIsThreadPending) return;
|
|
|
|
std::list< SGameAvatarEx* >::iterator it;
|
|
|
|
for (it = s_lstThreadLoadingAvatar.begin(); it != s_lstThreadLoadingAvatar.end(); ++it)
|
|
{
|
|
if (*it == this)
|
|
{
|
|
s_lstThreadLoadingAvatar.erase(it);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::addToLoadingList()
|
|
{
|
|
THREAD_SYNCRONIZE(s_AvatarLoadingLock);
|
|
|
|
#ifdef _DEBUG
|
|
std::list< SGameAvatarEx* >::iterator it;
|
|
for (it = s_lstThreadLoadingAvatar.begin(); it != s_lstThreadLoadingAvatar.end(); ++it)
|
|
{
|
|
if (*it == this)
|
|
{
|
|
assert(0);
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
m_bIsThreadPending = true;
|
|
|
|
s_lstThreadLoadingAvatar.push_back(this);
|
|
}
|
|
|
|
void SGameAvatarEx::PendLoading()
|
|
{
|
|
if (m_bIsThreadPending) return;
|
|
|
|
if (m_bPendLoading) return;
|
|
|
|
addToLoadingList();
|
|
}
|
|
|
|
bool SGameAvatarEx::doLoading()
|
|
{
|
|
struct _FlagRemover
|
|
{
|
|
_FlagRemover(volatile bool* volatile f) : pFlag(f) {}
|
|
|
|
~_FlagRemover() { *pFlag = false; }
|
|
|
|
volatile bool* volatile pFlag;
|
|
};
|
|
|
|
struct _TrueRemover
|
|
{
|
|
_TrueRemover(volatile bool* volatile f) : pFlag(f) {}
|
|
|
|
~_TrueRemover() { *pFlag = true; }
|
|
|
|
volatile bool* volatile pFlag;
|
|
};
|
|
|
|
volatile _FlagRemover _remover0(&m_bIsThreadLoading);
|
|
volatile _FlagRemover _remover1(&m_bIsThreadPending);
|
|
|
|
const char* pFileName = GetCobFileName();
|
|
if (!pFileName)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
std::string strName = pFileName;
|
|
if (strstr(strName.c_str(), ".cob") == NULL)
|
|
strName += ".cob";
|
|
|
|
m_strFileName = strName;
|
|
|
|
vec_cobset* coblist = COBManager::GetManager()->Load(strName.c_str());
|
|
if (coblist == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
KSeqAvatarEx* pSeqAvatar = NULL;
|
|
|
|
unsigned char nObjType = GetInnObjType();
|
|
|
|
if (m_nFirst == 0)
|
|
{
|
|
if (nObjType != TS_ENTER::GAME_PLAYER &&
|
|
nObjType != TS_ENTER::GAME_NPC)
|
|
{
|
|
pSeqAvatar = LoadCob(coblist);
|
|
if (pSeqAvatar == NULL)
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (nObjType == TS_ENTER::GAME_PLAYER ||
|
|
nObjType == TS_ENTER::GAME_NPC ||
|
|
nObjType == TS_ENTER::GAME_MOB ||
|
|
nObjType == TS_ENTER::GAME_SUMMON ||
|
|
nObjType == TS_ENTER::GAME_PET) // sonador 10.2.1 팻 시스템 구현
|
|
{
|
|
iterator_cobset it = coblist->begin();
|
|
if (coblist->end() != it)
|
|
{
|
|
COBSET* pCob = *it;
|
|
LoadEvent(pCob);
|
|
|
|
//큐브 Load
|
|
for (int i(0); 6 > i; i++)
|
|
{
|
|
m_fSelcube[i] = pCob->fSelCube[i];
|
|
m_fDeadcube[i] = pCob->fDeadCube[i];
|
|
}
|
|
|
|
for (int i(0); i < 3; ++i)
|
|
{
|
|
if (m_fSelcube[i] > m_fSelcube[i + 3]) ::swap(m_fSelcube[i], m_fSelcube[i + 3]);
|
|
if (m_fDeadcube[i] > m_fDeadcube[i + 3]) ::swap(m_fDeadcube[i], m_fDeadcube[i + 3]);
|
|
}
|
|
|
|
m_fOriginalSelCubeHeight = m_fSelcube[5];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//TS_ENTER::GAME_PLAYER, TS_ENTER::GAME_NPC <- 이외 타입들은 WearList가 없으므로 밑으로 들어가면 안된다
|
|
if (!m_vWearList.empty())
|
|
{
|
|
if (nObjType == TS_ENTER::GAME_PLAYER)
|
|
{
|
|
if (IsRamadanPrayRoom())
|
|
{
|
|
MakeRamadanWearItemList();
|
|
|
|
LoadingCore(pSeqAvatar, nObjType, coblist, m_vWearList_ramadan);
|
|
}
|
|
else
|
|
LoadingCore(pSeqAvatar, nObjType, coblist, m_vWearList);
|
|
}
|
|
else
|
|
{
|
|
LoadingCore(pSeqAvatar, nObjType, coblist, m_vWearList);
|
|
}
|
|
|
|
m_vWearList.clear();
|
|
}
|
|
else
|
|
{
|
|
//WearList가 없고 npc라면 cob리스트에서 읽어 들이자
|
|
if (nObjType == TS_ENTER::GAME_NPC && pSeqAvatar == NULL)
|
|
{
|
|
pSeqAvatar = LoadCob(coblist);
|
|
if (pSeqAvatar == NULL)
|
|
return false;
|
|
}
|
|
else if (nObjType == TS_ENTER::GAME_PLAYER)
|
|
{
|
|
if (IsRamadanPrayRoom())
|
|
{
|
|
MakeRamadanWearItemList();
|
|
|
|
LoadingCore(pSeqAvatar, nObjType, coblist, m_vWearList_ramadan);
|
|
}
|
|
else
|
|
LoadingCore(pSeqAvatar, nObjType, coblist, m_vWearListForRefresh);
|
|
}
|
|
}
|
|
|
|
RefreshTextureGroup(coblist);
|
|
|
|
/// 2011.07.28 redmine #16797 - prodongi
|
|
if (m_nDisguise == STAT_DISGUISE)
|
|
{
|
|
if (GetInnObjType() == TS_ENTER::GAME_SUMMON && m_disguiseEnhance)
|
|
{
|
|
_RefreshTextureGroup(1, coblist);
|
|
EnableMTE(true);
|
|
}
|
|
}
|
|
|
|
if (m_nFirst == 0)
|
|
{
|
|
Activate();
|
|
InterlockedIncrement((volatile LONG*)&m_nFirst);
|
|
}
|
|
|
|
volatile _TrueRemover _trueremover(&m_bIsInit);
|
|
|
|
return true;
|
|
}
|
|
|
|
void SGameAvatarEx::LoadingCore(class KSeqAvatarEx* pSeqAvatar, int nObjType, vec_cobset* pCobList, std::vector< WEAR_DATA >& wearList)
|
|
{
|
|
if (wearList.size() == 0 || pCobList == NULL)
|
|
return;
|
|
|
|
SAFE_DELETE(pSeqAvatar);
|
|
|
|
pSeqAvatar = new KSeqAvatarEx;
|
|
pSeqAvatar->Initialize();
|
|
pSeqAvatar->ClearAnimation();
|
|
|
|
if (nObjType == TS_ENTER::GAME_PLAYER)
|
|
{
|
|
if (m_bIsReloadWearListFileName)
|
|
{
|
|
ReloadWearListFileName(wearList);
|
|
SetReloadWearListFileName(false);
|
|
}
|
|
|
|
//TODO : COB 데이타 적용 해야 함.
|
|
iterator_cobset it = pCobList->begin();
|
|
if (pCobList->end() != it)
|
|
{
|
|
COBSET* pCob = *it;
|
|
//이펙트 Pos List
|
|
std::string strEffPosName;
|
|
int index = 0;
|
|
for (unsigned int i(0); pCob->m_EffPosList.size() > i; i++)
|
|
{
|
|
index = pCob->m_EffPosList[i].dwIndex;
|
|
strEffPosName = pCob->m_EffPosList[i].strName;
|
|
|
|
pSeqAvatar->AddEffectPos(ANIPART_BIPED, index, strEffPosName.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
//얼굴, 헤어 재로딩
|
|
if (m_pProperty)
|
|
{
|
|
// 2010.04.22 - prodongi
|
|
doLoadingHair(pSeqAvatar);
|
|
|
|
std::string strFace = GetDefaultItemDB().GetFileName(GetRace(), GetSex(), GetFace());
|
|
|
|
std::string strDeco;
|
|
getDecoTexName(strDeco);
|
|
|
|
pSeqAvatar->AddMesh(ANIPART_BIPED, MPART_FACE, strFace.c_str(), strDeco);
|
|
}
|
|
|
|
RefreshItemWearEx(pSeqAvatar, wearList);
|
|
|
|
pSeqAvatar->SetSkinDiffuse(m_SkinDiffuse);
|
|
|
|
LoadUseAnimation(pSeqAvatar);
|
|
|
|
SAFE_DELETE(m_pThreadAvatarEx); //쓰레드 끝나고 바로 들어 왔을 경우
|
|
|
|
m_pThreadAvatarEx = pSeqAvatar;
|
|
|
|
InterlockedIncrement((volatile LONG*)&m_nIsRefreshAni);
|
|
}
|
|
|
|
KSeqAvatarEx* SGameAvatarEx::LoadCob(vec_cobset* pCobList)
|
|
{
|
|
KSeqAvatarEx* pSeqAvatar = LoadCOBSet(pCobList);
|
|
|
|
if (!pSeqAvatar)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//모션 블랜딩 넣는다.
|
|
if (GetDefaultAnimation() != ANI_DEAD01)
|
|
{
|
|
if (!IsMoving())
|
|
{
|
|
if (m_nNewCurAniType == ANI_RUN) m_nNewCurAniType = ANI_DEFAULT01;
|
|
else if (m_nNewCurAniType == ANI_M_RUN_HIGH) m_nNewCurAniType = ANI_M_DEFAULT01_HIGH;
|
|
else if (m_nNewCurAniType == ANI_M_RUN_LOW) m_nNewCurAniType = ANI_M_DEFAULT01_LOW;
|
|
else if (m_nNewCurAniType == ANI_M_RUN_QILIN) m_nNewCurAniType = ANI_M_DEFAULT01_QILIN; // sonador #2.1.6
|
|
else if (m_nNewCurAniType == ANI_M_RUN_WHITE) m_nNewCurAniType = ANI_M_DEFAULT01_WHITE; // #2.1.14
|
|
else if (m_nNewCurAniType == ANI_M_RUN_UNICORN)m_nNewCurAniType = ANI_M_DEFAULT01_UNICORN; // #2.1.14
|
|
else if (m_nNewCurAniType == ANI_M_RUN_BEAKHO) m_nNewCurAniType = ANI_M_DEFAULT01_BEAKHO; /// 2011.02.08 - prodongi
|
|
}
|
|
|
|
if (IsLoopMotion(m_nNewCurAniType))
|
|
ThreadNPlayAnimation(pSeqAvatar, m_nNewCurAniType, m_nCurPlayType);
|
|
else
|
|
ThreadNPlayAnimation(pSeqAvatar, m_nNewCurAniType, SEQTYPE_NORMAL);
|
|
}
|
|
else
|
|
{
|
|
ThreadNPlayAnimation(pSeqAvatar, GetDefaultAnimation());
|
|
SetEventHandleNull();
|
|
}
|
|
|
|
pSeqAvatar->SetDeform(ANIPART_BIPED);
|
|
pSeqAvatar->SetAttach(ANIPART_BIPED);
|
|
|
|
unsigned char nObjType = GetInnObjType();
|
|
if (nObjType == TS_ENTER::GAME_PLAYER ||
|
|
nObjType == TS_ENTER::GAME_NPC ||
|
|
nObjType == TS_ENTER::GAME_MOB ||
|
|
nObjType == TS_ENTER::GAME_SUMMON ||
|
|
nObjType == TS_ENTER::GAME_PET)
|
|
{
|
|
//TODO : COB 데이타 적용 해야 함.
|
|
iterator_cobset it = pCobList->begin();
|
|
if (pCobList->end() != it)
|
|
{
|
|
COBSET* pCob = *it;
|
|
//이펙트 Pos List
|
|
std::string strEffPosName;
|
|
int index = 0;
|
|
for (unsigned int i(0); pCob->m_EffPosList.size() > i; i++)
|
|
{
|
|
index = pCob->m_EffPosList[i].dwIndex;
|
|
strEffPosName = pCob->m_EffPosList[i].strName;
|
|
|
|
pSeqAvatar->AddEffectPos(ANIPART_BIPED, index, strEffPosName.c_str());
|
|
}
|
|
|
|
//큐브 Load
|
|
for (int i(0); 6 > i; i++)
|
|
{
|
|
m_fSelcube[i] = pCob->fSelCube[i];
|
|
m_fDeadcube[i] = pCob->fDeadCube[i];
|
|
}
|
|
|
|
for (int i(0); i < 3; ++i)
|
|
{
|
|
if (m_fSelcube[i] > m_fSelcube[i + 3]) ::swap(m_fSelcube[i], m_fSelcube[i + 3]);
|
|
if (m_fDeadcube[i] > m_fDeadcube[i + 3]) ::swap(m_fDeadcube[i], m_fDeadcube[i + 3]);
|
|
}
|
|
|
|
m_fOriginalSelCubeHeight = m_fSelcube[5];
|
|
}
|
|
|
|
RefreshEffectPos(pSeqAvatar);
|
|
|
|
m_pSeqAvatar = pSeqAvatar;
|
|
|
|
//NPC Wear가 없는 것이 생기면, 아래 호출 되야 함
|
|
// if( GetInnObjType() == TS_ENTER::GAME_NPC )
|
|
// RefreshSkinColorized();
|
|
}
|
|
|
|
return pSeqAvatar;
|
|
}
|
|
|
|
void SGameAvatarEx::_RefreshTextureGroup(int texture_group_index, vec_cobset* pCobSet)
|
|
{
|
|
if (pCobSet == NULL || m_pSeqAvatar == NULL || pCobSet->empty() || texture_group_index == -1)
|
|
return;
|
|
|
|
_CID(CHANGE_MESH_TEXTURE);
|
|
KMsgCHANGE_MESH_TEXTURE msg;
|
|
|
|
iterator_cobset itCobSet = pCobSet->begin();
|
|
for (; itCobSet != pCobSet->end(); ++itCobSet)
|
|
{
|
|
for (int nMPart = 0; nMPart < MPART_MAX; ++nMPart)
|
|
{
|
|
std::vector< TEXTURE_GROUP_LIST* >::iterator itTextureGroup = (*itCobSet)->m_TextureGroupList[nMPart].begin();
|
|
for (; itTextureGroup != (*itCobSet)->m_TextureGroupList[nMPart].end(); ++itTextureGroup)
|
|
{
|
|
std::vector< TEXTURE_GROUP_LIST::Seq_list* >::iterator itSeqList = (*itTextureGroup)->vSeqList.begin();
|
|
for (; itSeqList != (*itTextureGroup)->vSeqList.end(); ++itSeqList)
|
|
{
|
|
msg.szMeshName = (*itSeqList)->strSeqName.c_str();
|
|
|
|
std::vector< std::string >::iterator itStr = (*itSeqList)->vTextureIndex[texture_group_index].begin();
|
|
while (itStr != (*itSeqList)->vTextureIndex[texture_group_index].end())
|
|
{
|
|
msg.vTextureList.push_back((*itStr).c_str());
|
|
++itStr;
|
|
}
|
|
|
|
if (msg.vTextureList.empty() == false)
|
|
{
|
|
m_pSeqAvatar->Perform((*itCobSet)->nAniPart, id_CHANGE_MESH_TEXTURE, msg);
|
|
msg.vTextureList.clear();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SGameAvatarEx::refreshWinkByOption()
|
|
{
|
|
if (m_pSeqAvatar) refreshWink(m_pSeqAvatar);
|
|
}
|
|
|
|
void SGameAvatarEx::refreshWink(KSeqAvatarEx* pSeqAvatar)
|
|
{
|
|
if (GetInnObjType() != TS_ENTER::GAME_PLAYER)
|
|
return;
|
|
|
|
if (pSeqAvatar == NULL) return;
|
|
|
|
}
|
|
|
|
|
|
void SGameAvatarEx::SetLastWeaponSwapTime(AR_TIME NewTime) // Fraun weapon swap exploit fix 8/19/2025
|
|
{
|
|
LastWeaponSwapTime = NewTime;
|
|
}
|
|
|
|
|
|
|
|
void SGameAvatarEx::MakeRamadanWearItemList()
|
|
{
|
|
m_vWearList_ramadan.clear();
|
|
|
|
// 라마단 복장 아이템 코드
|
|
int itemCode[ItemBase::MAX_ITEM_SPARE_WEAR] =
|
|
{
|
|
0, 0,
|
|
RAMADAN_ITEM_ARMOR,
|
|
RAMADAN_ITEM_HAT,
|
|
RAMADAN_ITEM_GLOVE,
|
|
RAMADAN_ITEM_BOOTS,
|
|
};
|
|
int itemWearType[ItemBase::MAX_ITEM_SPARE_WEAR] =
|
|
{
|
|
0, 0,
|
|
ItemBase::WEAR_DECO_ARMOR,
|
|
ItemBase::WEAR_DECO_HELM,
|
|
ItemBase::WEAR_DECO_GLOVE,
|
|
ItemBase::WEAR_DECO_BOOTS,
|
|
};
|
|
|
|
ClearThreadLoadWear(); //쌓여 있는 것을 지운다.
|
|
|
|
int nRace = GetRace(); // 종족
|
|
int nSex = GetSex(); // 성별
|
|
for (int x = 0; x < ItemBase::MAX_ITEM_SPARE_WEAR; x++)
|
|
{
|
|
SGameAvatarEx::WEAR_DATA weardata;
|
|
|
|
// 종족, 성별, 아이템 코드로 해당 아이템 파일 이름을 얻는다
|
|
if (itemCode[x] != 0)
|
|
{
|
|
weardata.strFileName = GetItemDB().GetFileName(nRace, nSex, itemCode[x], 0); // GetDefaultItemDB()
|
|
weardata.strFileName += ".nx3";
|
|
}
|
|
else
|
|
weardata.strFileName = "_NoItem_"; // 아이템 코드가 없으면 "_NoItem_" 으로 파일 이름 설정
|
|
|
|
weardata.nItemClass = GetItemDB().GetClassID(itemCode[x]);
|
|
weardata.nItemCode = itemCode[x];
|
|
weardata.nItemLevel = 1;
|
|
weardata.nItemEnhanceLevel = 0;
|
|
weardata.nWearType = x;
|
|
|
|
m_vWearList_ramadan.push_back(weardata); // 쓰레드로 메쉬 로딩할 리스트에 내용 추가
|
|
}
|
|
}
|
|
|
|
bool SGameAvatarEx::IsThreadLoading()
|
|
{
|
|
if (m_bIsThreadLoading || IsThreadPendLoading())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SGameAvatarEx::IsLoadComplete()
|
|
{
|
|
if (IsThreadLoading())
|
|
return false;
|
|
|
|
return m_bIsInit;
|
|
}
|
|
|
|
//#define _NO_AVATAR_THREAD_
|
|
|
|
bool SGameAvatarEx::Initialize(class K3DRenderDeviceDX* pDevice)
|
|
{
|
|
if (IsLocalPlayer())
|
|
m_vNextPos = GetCurPosWithChangeDir();
|
|
|
|
//int nSizeCnt = sizeof( ani_test )/sizeof(int);
|
|
|
|
//for( int i=0; nSizeCnt>i; i++ )
|
|
//{
|
|
// for( int n(0); ANICLS_MAX>n; n++ )
|
|
// {
|
|
// const char * pAni = GetMotionSetDB().GetAni( GetInnObjType(), ani_test[i], GetRace(), GetSex(), n );
|
|
// std::string strAniKey;
|
|
// CStringUtil::GetStrKey( pAni, '_', strAniKey );
|
|
// _oprint( "ANI_NAME : %s\n", strAniKey.c_str() );
|
|
// }
|
|
//}
|
|
|
|
return true;
|
|
}
|
|
|
|
void SGameAvatarEx::DeleteEvent(KSVEC_KEVENT_RES& svEventList)
|
|
{
|
|
_KEY_EVENT_RES* pData;
|
|
bool res;
|
|
res = svEventList.get_first_value(pData);
|
|
while (res)
|
|
{
|
|
if (pData != NULL)
|
|
{
|
|
delete pData;
|
|
}
|
|
res = svEventList.get_next_value(pData);
|
|
}
|
|
svEventList.clear();
|
|
|
|
//KSVEC_KEVENT_RES::iterator it = svEventList.begin();
|
|
//while ( it != svEventList.end() )
|
|
//{
|
|
// delete (*it);
|
|
// ++it;
|
|
//}
|
|
//svEventList.clear();
|
|
}
|
|
|
|
void SGameAvatarEx::Destroy()
|
|
{
|
|
SAFE_DELETE(m_pProperty);
|
|
|
|
//캐스팅 Effect 삭제~
|
|
if (!m_vCastEffect.empty())
|
|
{
|
|
for (unsigned int i(0); m_vCastEffect.size() > i; i++)
|
|
DelEffect(m_vCastEffect[i]);
|
|
m_vCastEffect.clear();
|
|
}
|
|
|
|
SAFE_DELETE(m_pThreadAvatarEx);
|
|
SAFE_DELETE(m_pSeqAvatar);
|
|
SAFE_DELETE(m_pStateVM);
|
|
|
|
SAFE_DELETE(m_pDisguiseStack); // 2.1.16 변신 효과 중첩시 아바타 사라지는 오류 수정
|
|
// SAFE_DELETE( m_pDisguiseSeqAvatar );
|
|
|
|
SetEventHandleNull();
|
|
|
|
DeleteEvent(m_svEventHandle00_effectList);
|
|
DeleteEvent(m_svEventHandle00_soundList);
|
|
DeleteEvent(m_svEventHandle00_motion_effect);
|
|
DeleteEvent(m_svEventHandle01_List);
|
|
DeleteEvent(m_svEventHandle02_List);
|
|
DeleteEvent(m_svEventHandle03_List);
|
|
DeleteEvent(m_svEventHandle04_List);
|
|
DeleteEvent(m_svEventHandle05_List);
|
|
DeleteEvent(m_svEventHandle06_List);
|
|
|
|
for (unsigned int i(0); m_vAttackEventList.size() > i; i++)
|
|
{
|
|
delete m_vAttackEventList[i];
|
|
}
|
|
m_vAttackEventList.erase(m_vAttackEventList.begin(), m_vAttackEventList.end());
|
|
|
|
for (unsigned int i(0); m_vSkillEventList.size() > i; i++)
|
|
{
|
|
delete m_vSkillEventList[i];
|
|
}
|
|
m_vSkillEventList.erase(m_vSkillEventList.begin(), m_vSkillEventList.end());
|
|
|
|
for (unsigned int i(0); m_vCastSkillList.size() > i; i++) //스킬 Cast 연출
|
|
{
|
|
delete m_vCastSkillList[i];
|
|
}
|
|
m_vCastSkillList.erase(m_vCastSkillList.begin(), m_vCastSkillList.end());
|
|
|
|
for (unsigned int i(0); m_vFireSkillList.size() > i; i++) //스킬 Fire 연출
|
|
{
|
|
delete m_vFireSkillList[i];
|
|
}
|
|
m_vFireSkillList.erase(m_vFireSkillList.begin(), m_vFireSkillList.end());
|
|
|
|
clearAllState();
|
|
|
|
SAFE_DELETE(m_pUISyncData);
|
|
|
|
SAFE_DELETE(m_pBoneRecorder);
|
|
|
|
SAFE_DELETE(m_pWeaponTrailRight);
|
|
SAFE_DELETE(m_pWeaponTrailLeft);
|
|
m_bUseRightWeaponTrail = false;
|
|
m_bUseLeftWeaponTrail = false;
|
|
|
|
//SAFE_DELETE(m_pWeaponPowerupRight);
|
|
//SAFE_DELETE(m_pWeaponPowerupLeft);
|
|
//m_nUpdatePowerupRight=UPDATE_NONE;
|
|
//m_nUpdatePowerupLeft=UPDATE_NONE;
|
|
|
|
//m_bUpdatePowerupSwitch=false;
|
|
|
|
SAFE_DELETE(m_pAddOnMgr);
|
|
|
|
SAFE_DELETE(m_pTerrainDegree);
|
|
|
|
//스킬 용
|
|
SAFE_DELETE(m_pRightSwordSlashForSkill);
|
|
SAFE_DELETE(m_pLeftSwordSlashForSkill);
|
|
|
|
std::vector<class SGameWork*>::iterator itWorkList = m_vWorkList.begin();
|
|
while (itWorkList != m_vWorkList.end())
|
|
{
|
|
(*itWorkList)->SetOwner(NULL);
|
|
++itWorkList;
|
|
}
|
|
}
|
|
|
|
|
|
bool SGameAvatarEx::Activate()
|
|
{
|
|
m_bIsActivated = true;
|
|
|
|
SetWeaponEnhanceFx(m_nTwoHandWeaponCode, m_bIsActivated);
|
|
SetWeaponEnhanceFx(m_nRightHandWeaponCode, m_bIsActivated);
|
|
SetWeaponEnhanceFx(m_nLeftHandWeaponCode, m_bIsActivated);
|
|
|
|
return m_bIsActivated;
|
|
}
|
|
|
|
bool SGameAvatarEx::Deactivate()
|
|
{
|
|
m_bIsActivated = false;
|
|
|
|
SetWeaponEnhanceFx(m_nTwoHandWeaponCode, m_bIsActivated);
|
|
SetWeaponEnhanceFx(m_nRightHandWeaponCode, m_bIsActivated);
|
|
SetWeaponEnhanceFx(m_nLeftHandWeaponCode, m_bIsActivated);
|
|
|
|
return true;
|
|
}
|
|
|
|
void SGameAvatarEx::ActivateFxSwordSlash()
|
|
{
|
|
if (m_pBoneRecorder == NULL)
|
|
{
|
|
m_pBoneRecorder = new BoneRecorder(this, WEAPON_SLASH_RECORD_SUBDIVISION); // 무기 궤적용 포지션 저장 obj
|
|
|
|
m_bUseRightWeaponTrail = false; // 오른손 무기 궤적 사용?
|
|
m_bUseLeftWeaponTrail = false; // 왼손 무기 궤적 사용?
|
|
}
|
|
|
|
if (m_pWeaponTrailRight == NULL)
|
|
m_pWeaponTrailRight = new SGameFxSwordSlash(true); // 오른손 무기 궤적 object
|
|
|
|
if (m_pWeaponTrailLeft == NULL)
|
|
m_pWeaponTrailLeft = new SGameFxSwordSlash(false); // 왼손 무기 궤적 object
|
|
}
|
|
|
|
//LeaveMsg가 오면 초기화 해줘야 할것들
|
|
void SGameAvatarEx::LeaveData()
|
|
{
|
|
UnArmed(m_nLeftHandWeaponCode);
|
|
UnArmed(m_nRightHandWeaponCode);
|
|
UnArmed(m_nTwoHandWeaponCode);
|
|
|
|
for (int x = 0; x < EFFECT_POS_WEAPON_MAX; ++x)
|
|
ResetWeaponEVPMatrix(x);
|
|
|
|
SetRiderCreatureInfo();
|
|
|
|
clearAllState();
|
|
|
|
if (m_pStateVM)
|
|
{
|
|
m_pStateVM->ClearInfo();
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::ReInitialize()
|
|
{
|
|
m_nProcess_state = -1;
|
|
m_nAniClass = 0;
|
|
|
|
m_bLockAni = false;
|
|
m_bLockAttackAni = false;
|
|
|
|
m_dwTime = 0;
|
|
m_dwStartTime = 0;
|
|
|
|
m_fVisibility = 0.0f;
|
|
m_speed = DEF_SPEED;
|
|
|
|
m_vCheckPos = K3DVector(0.0f, 0.0f, 0.0f);
|
|
|
|
m_bIng = false;
|
|
|
|
m_bReservation = false;
|
|
|
|
m_bVisible = true;
|
|
|
|
m_bPrevVisible = true;
|
|
|
|
m_bIsMovingDetour = false;
|
|
|
|
m_bIsChasing = false;
|
|
|
|
m_unDetourStep = 0;
|
|
|
|
m_bRefreshDetour = false;
|
|
|
|
m_CurrState = SObjectState::ID::STATE_NONE;
|
|
m_CurrTarget = 0;
|
|
|
|
m_nWeaponSwing_RepeatMotion = 0;
|
|
m_bIsDead = false;
|
|
m_nAttackIndex = 0;
|
|
m_bPlayOverride = false;
|
|
m_bRefreshInven = false;
|
|
m_cPrevAttackIndex = 0;
|
|
m_nSwordSlashForSkillMotion = 0;
|
|
m_nStateFlag = FLAG_STATE_NONE;
|
|
m_fHidingVisiblity = 1.0f;
|
|
m_fHidingDetectRange = 0.0f;
|
|
m_vTargetPos = K3DVector(0.0f, 0.0f, 0.0f);
|
|
m_nTraceIdx = 0;
|
|
m_SkinDiffuse = KColor(0, 0, 0, 0);
|
|
|
|
m_nNewCurAniType = ANI_DEFAULT01;
|
|
m_nCurPlayType = SEQTYPE_LOOP;
|
|
}
|
|
|
|
bool SGameAvatarEx::IsInit()
|
|
{
|
|
//로딩이 끝났다면 m_bIsInit == true
|
|
return m_bIsInit;
|
|
}
|
|
|
|
void SGameAvatarEx::SetShadowRenderFlag(BOOL bShadowRenderFlag)
|
|
{
|
|
if (bShadowRenderFlag)
|
|
m_xRenderFlag.On(AV_SHADOW);
|
|
else
|
|
m_xRenderFlag.Off(AV_SHADOW);
|
|
|
|
}
|
|
|
|
void SGameAvatarEx::SetVisibility(float fVisibility)
|
|
{
|
|
if (m_nStateFlag & FLAG_STATE_HIDING)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_pSeqAvatar) m_pSeqAvatar->SetVisibility(fVisibility);
|
|
|
|
m_fVisibility = fVisibility;
|
|
}
|
|
|
|
void SGameAvatarEx::SetHidingVisiblity(float fVisibility)
|
|
{
|
|
if (m_fHidingVisiblity != fVisibility)
|
|
{
|
|
if (m_pSeqAvatar) m_pSeqAvatar->SetVisibility(fVisibility);
|
|
m_fHidingVisiblity = fVisibility;
|
|
|
|
// '옵션 - 그림자 - 단순히' 로 적용하면 이 함수가 호출된다. Hiding인 경우 CircleShadow를 생성하지 않도록 막는다. bintitle. 2011.11.08
|
|
//if( (GetVisibility() <= 0.0f) || (GetHidingVisiblity() <= 0.0f) )
|
|
if (m_fHidingVisiblity <= 0.0f)
|
|
{
|
|
// Avatar를 숨기는 경우, CircleShadow도 숨겨야 한다.
|
|
if (m_pAddOnMgr->IsActivateAddOn(SGameAvatarAddOnMgr::SGAME_CIRCLE_SHADOW_FX))
|
|
{
|
|
DeActivateCircleShadow();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// '옵션 - 그림자 - 단순히' 의 경우 CircleShadow를 추가. bintitle. 2011.11.08
|
|
if (GetGameOption().GetLowShadow())
|
|
ActivateCircleShadow();
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::SetVisible(bool bVisible)
|
|
{
|
|
m_bVisible = bVisible;
|
|
|
|
if (GetInnObjType() == TS_ENTER::GAME_PLAYER)
|
|
{
|
|
bool bNewVisible = (m_xRenderFlag.IsOn(AV_BASIC) && m_bVisible);
|
|
if (m_bPrevVisible != bNewVisible)
|
|
{
|
|
SetWeaponEnhanceFx(m_nTwoHandWeaponCode, bNewVisible);
|
|
SetWeaponEnhanceFx(m_nRightHandWeaponCode, bNewVisible);
|
|
SetWeaponEnhanceFx(m_nLeftHandWeaponCode, bNewVisible);
|
|
|
|
m_bPrevVisible = bNewVisible;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::_checkPetrify()
|
|
{
|
|
if (m_nStateFlag & FLAG_STATE_PETRIFY)
|
|
{
|
|
KMsgSET_FIXTEXTURE msgFixTexture;
|
|
msgFixTexture.bUseFix = true;
|
|
msgFixTexture.pTexture = _getTexture("petrify00.dds");
|
|
SetFixTexture(&msgFixTexture);
|
|
}
|
|
else
|
|
{
|
|
KMsgSET_FIXTEXTURE msgFixTexture;
|
|
msgFixTexture.bUseFix = false;
|
|
SetFixTexture(&msgFixTexture);
|
|
}
|
|
|
|
/* bool bFind = false;
|
|
int nSize = (int)m_vStateList.size();
|
|
for( int i(0); nSize>i; i++ )
|
|
{
|
|
SMSG_STATE * pState = m_vStateList[i];
|
|
|
|
if( pState->state_code == 6012 )//석화 처리
|
|
{
|
|
if( pState->state_level )
|
|
{
|
|
bFind = true;
|
|
KMsgSET_FIXTEXTURE msgFixTexture;
|
|
msgFixTexture.bUseFix = true;
|
|
msgFixTexture.pTexture = _getTexture( "petrify00.dds" );
|
|
SetFixTexture( &msgFixTexture );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !bFind )
|
|
{
|
|
KMsgSET_FIXTEXTURE msgFixTexture;
|
|
msgFixTexture.bUseFix = false;
|
|
SetFixTexture( &msgFixTexture );
|
|
}*/
|
|
}
|
|
|
|
void SGameAvatarEx::_renderThread()
|
|
{
|
|
if (GetInnObjType() == TS_ENTER::GAME_MOB || GetInnObjType() == TS_ENTER::GAME_SUMMON || GetInnObjType() == TS_ENTER::GAME_PET)
|
|
{
|
|
if (!IsThreadLoading() && m_bIsActivated && !m_pAddOnMgr->IsActivateAddOn(SGameAvatarAddOnMgr::SGAME_AVATAR_FX))
|
|
{
|
|
ModelEffectResourceGame* pModelEffectRes = NULL;
|
|
if (GetInnObjType() == TS_ENTER::GAME_SUMMON)
|
|
{
|
|
SetMotionBlend(true);
|
|
_SUMMON_INFO_FILE* pSummon = GetCreatureDB().GetCreatureData(GetInnContentID());
|
|
if (pSummon) pModelEffectRes = GetModelEffectResourceDB().GetModelEffectResource(pSummon->model_id);
|
|
}
|
|
else if (GetInnObjType() == TS_ENTER::GAME_MOB)
|
|
{
|
|
_MONSTER_INFO_FILE* pMonster = GetMonsterDB().GetMonsterData(GetInnContentID());
|
|
if (pMonster) pModelEffectRes = GetModelEffectResourceDB().GetModelEffectResource(pMonster->monster_group);
|
|
}
|
|
else if (GetInnObjType() == TS_ENTER::GAME_PET)
|
|
{
|
|
pModelEffectRes = GetModelEffectResourceDB().GetModelEffectResource(GetPetDB().Find(GetInnContentID()).getMotionFileID());
|
|
}
|
|
|
|
if (pModelEffectRes)
|
|
{
|
|
std::string strEffectName = GetResourceDB().GetEffectResourceName(pModelEffectRes->effect_file_ID);
|
|
if (!strEffectName.empty())
|
|
{
|
|
SGameAvatarFx* pAvatarFx = (SGameAvatarFx*)m_pAddOnMgr->GetAddOn(SGameAvatarAddOnMgr::SGAME_AVATAR_FX);
|
|
if (pAvatarFx == NULL)
|
|
{
|
|
pAvatarFx = new SGameAvatarFx;
|
|
pAvatarFx->SetModelEffectRes(pModelEffectRes);
|
|
m_pAddOnMgr->AddAddOn(pAvatarFx);
|
|
}
|
|
}
|
|
}
|
|
CheckStateSkill();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if (!IsThreadLoading() && m_nIsRefreshAni && m_pThreadAvatarEx)
|
|
{
|
|
m_nAniClass = m_nThreadAniClass;
|
|
m_bUseRightWeaponTrail = m_bThreadUseRightWeaponTrail;
|
|
m_bUseLeftWeaponTrail = m_bThreadUseLeftWeaponTrail;
|
|
|
|
m_bActLeftWeaponTrail = false; //초기화
|
|
m_bActRightWeaponTrail = false;
|
|
|
|
SetVisibleWeaponTrail(false);
|
|
|
|
//쓰레드 로딩 적용
|
|
RefreshAni();
|
|
|
|
//강화 이펙트 로딩
|
|
if (m_pSeqAvatar)
|
|
{
|
|
for (int x = 0; x < EFFECT_POS_WEAPON_MAX; ++x)
|
|
{
|
|
if (m_WeaponEnhanceFx[x].weardatainfo)
|
|
LoadEnhanceEffect(m_pSeqAvatar, &m_WeaponEnhanceFx[x], x);
|
|
}
|
|
}
|
|
|
|
// sonador 7.0.16 Mantis 0002790: [모션] 아바타가 활을 착용하고 오르니토를 탔을 때 모션 문제
|
|
//if( IsMountMode() )
|
|
// HideWeapon( FALSE );
|
|
|
|
CheckStateSkill();
|
|
|
|
//초기화
|
|
InterlockedDecrement((volatile LONG*)&m_nIsRefreshAni);
|
|
|
|
|
|
// 무기 파워업 FX 업데이트 스위치 ON
|
|
//m_bUpdatePowerupSwitch=true;
|
|
|
|
//NOTE : _renderEffectLoading()전에 하면 VertexBuffer가 제대로 세팅되지 않는다!
|
|
// -> renderEtc()로 이동
|
|
}
|
|
}
|
|
|
|
if (IsStateRide())
|
|
AvatarRotationByCreature();
|
|
}
|
|
|
|
void SGameAvatarEx::_renderAvatar(unsigned long uRenderBitVector, class KViewportObject** ppViewportList, int nViewportCount)
|
|
{
|
|
if (m_pSeqAvatar)
|
|
{
|
|
// for(int i = 0; i < nViewportCount; ++i)
|
|
{
|
|
if (nViewportCount >= 1 && ppViewportList[0] && ppViewportList[0]->GetAttributes() & KViewportObject::VIEWPORT_GAME) {
|
|
m_pSeqAvatar->SetTransform(*GetTransform());
|
|
m_pSeqAvatar->Render(ppViewportList[0]);
|
|
}
|
|
|
|
if (nViewportCount >= 3 && ppViewportList[2] && ppViewportList[2]->GetAttributes() & KViewportObject::VIEWPORT_WATER) {
|
|
m_pSeqAvatar->SetTransform(*GetTransform());
|
|
m_pSeqAvatar->Render(ppViewportList[2]);
|
|
}
|
|
|
|
if (nViewportCount >= 2 && ppViewportList[1] && ppViewportList[1]->GetAttributes() & KViewportObject::VIEWPORT_SHADOW)
|
|
{
|
|
if (m_xRenderFlag.IsOn(AV_SHADOW))
|
|
{
|
|
DWORD renderFlag = MAKELONG(KRenderObject::RENDEREFX_SHADOW, SHADOW_DY_CAST);
|
|
m_pSeqAvatar->Render(ppViewportList[1], renderFlag); //등록
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::_renderEffectLoading()
|
|
{
|
|
if (!IsThreadLoading())
|
|
{
|
|
for (int x = 0; x < EFFECT_POS_MAX; ++x)
|
|
{
|
|
if (m_bEVPAttachMatrix[x])
|
|
{
|
|
if (x == EFFECT_POS_TOP || x == EFFECT_POS_MIDDLE) //위치 만 사용
|
|
{
|
|
K3DMatrixIdentity(m_matEVPAttachMatrix[x]);
|
|
m_matEVPAttachMatrix[x]._41 = m_pEvpSequencer[x]->GetAttachTransform()->_41;
|
|
m_matEVPAttachMatrix[x]._42 = m_pEvpSequencer[x]->GetAttachTransform()->_42;
|
|
m_matEVPAttachMatrix[x]._43 = m_pEvpSequencer[x]->GetAttachTransform()->_43;
|
|
}
|
|
else
|
|
m_matEVPAttachMatrix[x] = *m_pEvpSequencer[x]->GetAttachTransform();
|
|
}
|
|
}
|
|
|
|
for (int x = 0; x < EFFECT_POS_WEAPON_MAX; ++x)
|
|
{
|
|
if (m_bWeaponEVPMatrix[x] && m_WeaponEnhanceFx[x].weardatainfo)
|
|
{
|
|
for (int i = 0; i < EFFECT_POS_WEAPON_EP_MAX; ++i)
|
|
{
|
|
m_matWeaponEVPAttachMatrix[x][i] = *m_pWeaponEvpSequencer[x][i]->GetAttachTransform();
|
|
m_matWeaponEVPParentMatrix[x][i] = *m_pWeaponEvpSequencer[x][i]->GetParentTransform();
|
|
}
|
|
}
|
|
//로딩 안된것이 있는 지 검사
|
|
else if (m_WeaponEnhanceFx[x].weardatainfo)
|
|
{
|
|
LoadEnhanceEffect(m_pSeqAvatar, &m_WeaponEnhanceFx[x], x);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::SetVisibleWeaponTrail(bool bVisible)
|
|
{
|
|
if (m_bUseRightWeaponTrail && m_pWeaponTrailRight != NULL) {
|
|
m_pWeaponTrailRight->runTrail(bVisible);
|
|
}
|
|
|
|
if (m_bUseLeftWeaponTrail && m_pWeaponTrailLeft != NULL) {
|
|
m_pWeaponTrailLeft->runTrail(bVisible);
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::_renderEtc(unsigned long uRenderBitVector, class KViewportObject** ppViewportList, int nViewportCount)
|
|
{
|
|
#ifdef _WEAPON_FX_
|
|
//-- 검광 렌더링
|
|
// if ( IsLocalPlayer() )
|
|
if (GetInnObjType() == TS_ENTER::GAME_PLAYER)
|
|
{ // 현재 player자신것만 렌더링!!!!!!!!!!!
|
|
|
|
// 오른손 무기 검광
|
|
if (m_bActRightWeaponTrail && m_bUseRightWeaponTrail && m_pWeaponTrailRight != NULL && m_pWeaponTrailRight->IsRunTrail()) {
|
|
//if (IsAttacking()) {
|
|
// // 검광 on
|
|
// m_pWeaponTrailRight->runTrail(true);
|
|
//} else {
|
|
// // 검광 off (이미 있는 검광은 부드럽게 사라짐)
|
|
// m_pWeaponTrailRight->runTrail(false);
|
|
//}
|
|
|
|
K3DMatrix* ArrowMatrix = m_pBoneRecorder->matrix_right;
|
|
|
|
if (m_bBowClass)
|
|
{
|
|
ArrowMatrix->SetPosVector(m_vArrowPos);
|
|
//ArrowMatrix = &m_ArrowMatrix;
|
|
//*m_pBoneRecorder->matrix_left = m_ArrowMatrix;
|
|
if (m_bArrowTrail)
|
|
{
|
|
m_pWeaponTrailRight->addTrails(WEAPON_SLASH_RECORD_ARROW_SUBDIVISION
|
|
, m_pBoneRecorder->starttime, m_pBoneRecorder->endtime
|
|
, ArrowMatrix, m_bBowClass, m_fTargetRoll
|
|
);
|
|
m_pWeaponTrailRight->Render(ppViewportList[0]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 검광 노드 좌표 업데이트
|
|
m_pWeaponTrailRight->addTrails(WEAPON_SLASH_RECORD_SUBDIVISION // 애니메이션 프레임간 검광 분할 수. 숫자가 크면 폴리곤이 많아져서 곡선이 부드러워짐
|
|
, m_pBoneRecorder->starttime, m_pBoneRecorder->endtime // 분할 시작시간 / 끝시간
|
|
//, m_pBoneRecorder->matrix_right // recording된 좌표/방향 매트릭스
|
|
, ArrowMatrix
|
|
);
|
|
m_pWeaponTrailRight->Render(ppViewportList[0]);
|
|
}
|
|
}
|
|
|
|
// 왼손 무기 검광
|
|
if (m_bActLeftWeaponTrail && m_bUseLeftWeaponTrail && m_pWeaponTrailLeft != NULL && m_pWeaponTrailLeft->IsRunTrail()) {
|
|
|
|
//if (IsAttacking()) {
|
|
// // 검광 on
|
|
// m_pWeaponTrailLeft->runTrail(true);
|
|
//} else {
|
|
// // 검광 off (이미 있는 검광은 부드럽게 사라짐)
|
|
// m_pWeaponTrailLeft->runTrail(false);
|
|
//}
|
|
|
|
K3DMatrix* ArrowMatrix = m_pBoneRecorder->matrix_left;
|
|
if (m_bBowClass)
|
|
{
|
|
ArrowMatrix->SetPosVector(m_vArrowPos);
|
|
//ArrowMatrix = &m_ArrowMatrix;
|
|
//*m_pBoneRecorder->matrix_left = m_ArrowMatrix;
|
|
if (m_bArrowTrail)
|
|
{
|
|
m_pWeaponTrailLeft->addTrails(WEAPON_SLASH_RECORD_ARROW_SUBDIVISION
|
|
, m_pBoneRecorder->starttime, m_pBoneRecorder->endtime
|
|
, ArrowMatrix
|
|
, m_bBowClass
|
|
, m_fTargetRoll
|
|
);
|
|
|
|
m_pWeaponTrailLeft->Render(ppViewportList[0]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 검광 노드 좌표 업데이트
|
|
m_pWeaponTrailLeft->addTrails(WEAPON_SLASH_RECORD_SUBDIVISION, m_pBoneRecorder->starttime, m_pBoneRecorder->endtime, m_pBoneRecorder->matrix_left);
|
|
m_pWeaponTrailLeft->Render(ppViewportList[0]);
|
|
}
|
|
|
|
}
|
|
|
|
if (m_bActRightSwordSlashForSkill && m_pRightSwordSlashForSkill)
|
|
{
|
|
if (m_pRightSwordSlashForSkill->IsRunTrail())
|
|
{
|
|
m_pRightSwordSlashForSkill->addTrails(WEAPON_SLASH_RECORD_SUBDIVISION
|
|
, m_pBoneRecorder->starttime
|
|
, m_pBoneRecorder->endtime
|
|
, m_pBoneRecorder->matrix_right);
|
|
}
|
|
|
|
m_pRightSwordSlashForSkill->Render(ppViewportList[0]);
|
|
}
|
|
|
|
if (m_bActLeftSwordSlashForSkill && m_pLeftSwordSlashForSkill)
|
|
{
|
|
if (m_pLeftSwordSlashForSkill->IsRunTrail())
|
|
{
|
|
m_pLeftSwordSlashForSkill->addTrails(WEAPON_SLASH_RECORD_SUBDIVISION
|
|
, m_pBoneRecorder->starttime
|
|
, m_pBoneRecorder->endtime
|
|
, m_pBoneRecorder->matrix_left);
|
|
}
|
|
|
|
m_pLeftSwordSlashForSkill->Render(ppViewportList[0]);
|
|
}
|
|
}
|
|
|
|
|
|
// //-- 무기 강화 이펙트 렌더링
|
|
// if (m_pWeaponPowerupRight!=NULL || m_pWeaponPowerupLeft!=NULL) {
|
|
// // 필요하면 mesh를 다시 build
|
|
// processWeaponPowerupMeshRebuild();
|
|
//
|
|
// try {
|
|
// // Bone의 final좌표를 가져와서 또 bone이랑 blending한다 (뭔소린지 모르겠지만 이렇게 하니까 동작한다 -_-)
|
|
// KSeqAvatarEx *seqAvatar=GetSeqForm();
|
|
// if (seqAvatar==NULL) throw 0;
|
|
//
|
|
// KSeqAvatar *bipedSeq=seqAvatar->getAvatarPart(ANIPART_BIPED); // biped animation part
|
|
// if (bipedSeq==NULL) throw 0;
|
|
//
|
|
// //KBoneSeqObject* pBoneSeq=bipedSeq->getBoneSequencer(); // biped bone
|
|
// //if (pBoneSeq==NULL) throw 0;
|
|
//
|
|
// if (m_pWeaponPowerupRight!=NULL) { // && m_nUpdatePowerupRight==UPDATE_NONE) { <- update안 할때만 렌더링... 필요 없음
|
|
// KBoneSeqObject* boneSeqRightWeapon=NULL; // 무기의 animation bone
|
|
// KSeqAvatar *rightHandSeq=seqAvatar->getAvatarPart(ANIPART_WEAPON_RIGHT); // 오른손 무기가 붙을 위치
|
|
// KSequencer *sequencer=dynamic_cast<KSequencer*>(rightHandSeq->GetCurrentAnimation());
|
|
// if (sequencer!=NULL) {
|
|
// boneSeqRightWeapon=dynamic_cast<KBoneSeqObject*> (sequencer->GetSeqObject(0));
|
|
// }
|
|
//
|
|
// if (boneSeqRightWeapon!=NULL) {
|
|
// // SMorphedMesh::SetBlendMode(K3DMaterial::MBM_ALPHATEX_EDGEENHANCE_BLEND), SetWeight(NULL)용
|
|
// m_pWeaponPowerupRight->SetParentTransform(rightHandSeq->GetParentTransform(), rightHandSeq->GetAttachTransform());
|
|
//
|
|
///* // TEST for K3DMaterial::MBM_ALPHATEX_EDGEENHANCE, but not working
|
|
// K3DMatrix *pWeaponPosMat, *pBoneMat;
|
|
// K3DMatrix tempMat, resultMat;
|
|
// pWeaponPosMat=&(boneSeqRightWeapon->GetBoneCacheTM()[1]);
|
|
// pBoneMat=pBoneSeq->GetBoneMatrix(DETAIL_RIGHT_HAND);
|
|
// K3DMatrixMultiply( &tempMat, pBoneMat, &(seqAvatar->GetTransform()));
|
|
// K3DMatrixMultiply( &resultMat, pWeaponPosMat, &tempMat);
|
|
//
|
|
// m_pWeaponPowerupRight->SetParentTransform(NULL);
|
|
// m_pWeaponPowerupRight->SetTransform(resultMat);
|
|
//*/
|
|
//
|
|
// m_pWeaponPowerupRight->Render(ppViewportList[0]);
|
|
// }
|
|
// }
|
|
//
|
|
// if (m_pWeaponPowerupLeft!=NULL) { // && m_nUpdatePowerupLeft==UPDATE_NONE) {
|
|
// KBoneSeqObject* boneSeqLeftWeapon=NULL;
|
|
// KSeqAvatar *leftHandSeq=seqAvatar->getAvatarPart(ANIPART_WEAPON_LEFT); // 왼손 무기가 붙을 위치
|
|
// KSequencer *sequencer=dynamic_cast<KSequencer*>(leftHandSeq->GetCurrentAnimation());
|
|
// if (sequencer!=NULL) {
|
|
// boneSeqLeftWeapon=dynamic_cast<KBoneSeqObject*> (sequencer->GetSeqObject(0));
|
|
// }
|
|
// if (boneSeqLeftWeapon!=NULL) {
|
|
// m_pWeaponPowerupLeft->SetParentTransform(leftHandSeq->GetParentTransform(), leftHandSeq->GetAttachTransform());
|
|
// m_pWeaponPowerupLeft->Render(ppViewportList[0]);
|
|
// }
|
|
// }
|
|
//
|
|
//
|
|
// } catch (int) {
|
|
// // empty
|
|
// }
|
|
// }
|
|
#endif
|
|
|
|
m_pAddOnMgr->Render(ppViewportList, nViewportCount);
|
|
|
|
if (m_sCubeRender)
|
|
{
|
|
if (IsLive())
|
|
sel_normal_cube = K3DBoundRotCube(m_fSelcube[0], m_fSelcube[3], m_fSelcube[1], m_fSelcube[4], m_fSelcube[2], m_fSelcube[5]);
|
|
else
|
|
sel_normal_cube = K3DBoundRotCube(m_fDeadcube[0], m_fDeadcube[3], m_fDeadcube[1], m_fDeadcube[4], m_fDeadcube[2], m_fDeadcube[5]);
|
|
sel_normal_cube.SetTransform(*GetTransform());
|
|
sel_normal_cube.Render(ppViewportList[0]);
|
|
}
|
|
// if( m_pSeqAvatar ) m_pSeqAvatar->GetBoundCube()->Render( viewport );
|
|
}
|
|
|
|
|
|
bool SGameAvatarEx::Render(unsigned long uRenderBitVector, class KViewportObject** ppViewportList, int nViewportCount)
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// 거대화 처리
|
|
/// 2011.04.20 하위 클래스에서도 쓰기 위해서 함수로 뺐습니다. - prodongi
|
|
float scale;
|
|
K3DMatrix mat;
|
|
beginScaling(scale, mat);
|
|
/*
|
|
std::vector<SStateSlot*> PositiveList = GetPositiveStateList();
|
|
|
|
m_fScaleAdjustDest = 1.0f;
|
|
for (size_t i=0; i<PositiveList.size(); i++)
|
|
{
|
|
StateInfoEx* info = GetTenacityDB().GetTenacityData(PositiveList[i]->GetStateCode());
|
|
|
|
if (info->fValue[6] == 128) m_fScaleAdjustDest = info->fValue[7];
|
|
if (info->fValue[9] == 128) m_fScaleAdjustDest = info->fValue[10];
|
|
}
|
|
|
|
float fScale = 1.0f;
|
|
DWORD nowTime = GetSafeTickCount();
|
|
if (m_fScaleAdjustPrev == m_fScaleAdjustDest)
|
|
{
|
|
fScale = m_fScaleAdjustDest;
|
|
}
|
|
else
|
|
{
|
|
if (m_nScaleAdjustStartTime == 0) m_nScaleAdjustStartTime = nowTime;
|
|
|
|
float ratio = (nowTime - m_nScaleAdjustStartTime) / 1000.0f;
|
|
fScale = m_fScaleAdjustPrev * (1-ratio) + m_fScaleAdjustDest * ratio;
|
|
if (ratio > 1.0f)
|
|
{
|
|
m_nScaleAdjustStartTime = 0;
|
|
fScale = m_fScaleAdjustDest;
|
|
m_fScaleAdjustPrev = m_fScaleAdjustDest;
|
|
}
|
|
}
|
|
|
|
K3DMatrix mat = *GetTransform();
|
|
SetScalePure(fScale);
|
|
m_fSelcube[5] = m_fOriginalSelCubeHeight * fScale;
|
|
*/
|
|
// 거대화 관련 코드 종료
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Traitement en fondu
|
|
|
|
// AziaMafia LoadMap
|
|
|
|
if (m_nFadeOutStartTime != 0)
|
|
{
|
|
/// 2011.04.20 - prodongi
|
|
DWORD nowTime = GetSafeTickCount();
|
|
|
|
int nTime = nowTime - m_nFadeOutStartTime;
|
|
float fAlpha = 1.0f - (((float)nTime) / ((float)m_nFadeOutDuration));
|
|
fAlpha = max(fAlpha, 0.0f);
|
|
fAlpha = min(fAlpha, 1.0f);
|
|
SetVisibility(fAlpha);
|
|
if (nTime > m_nFadeOutDuration)
|
|
{
|
|
m_nFadeOutStartTime = 0;
|
|
SetReservation(false);
|
|
Deactivate();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 페이드아웃 관련 코드 종료
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
_renderThread();
|
|
|
|
if (!m_bVisible || !m_bIsActivated || !m_bIsInit || !m_xRenderFlag.IsOn(AV_BASIC))
|
|
{
|
|
SetTransformPure(mat);
|
|
return false;
|
|
}
|
|
|
|
|
|
if (IsPendLoading()) { SetTransformPure(mat); return false; }
|
|
|
|
_renderEffectLoading(); // sonador #2.3.1.10
|
|
|
|
_renderAvatar(uRenderBitVector, ppViewportList, nViewportCount);
|
|
_renderEtc(uRenderBitVector, ppViewportList, nViewportCount);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// 거대화 관련 코드로 인한 변경점 리셋
|
|
/// 2011.04.20 하위 클래스에서도 쓰기 위해서 함수로 뺐습니다. - prodongi
|
|
endScaling(scale, mat);
|
|
/*
|
|
SetTransformPure(mat);
|
|
|
|
m_fScaleAdjust = fScale;
|
|
*/
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
return true;
|
|
}
|
|
|
|
bool SGameAvatarEx::renderSelect(unsigned long uRenderBitVector, class KViewportObject** ppViewportList, int nViewportCount)
|
|
{
|
|
if (!m_pSeqAvatar)
|
|
return false;
|
|
|
|
float scale;
|
|
K3DMatrix mat;
|
|
beginScaling(scale, mat);
|
|
|
|
if (nViewportCount >= 1 && ppViewportList[0] && ppViewportList[0]->GetAttributes() & KViewportObject::VIEWPORT_GAME)
|
|
{
|
|
m_pSeqAvatar->SetTransform(*GetTransform());
|
|
m_pSeqAvatar->Render(ppViewportList[0], KRenderObject::RENDEREFX_SELECT);
|
|
}
|
|
|
|
endScaling(scale, mat);
|
|
|
|
return true;
|
|
}
|
|
|
|
void SGameAvatarEx::RefreshSkinColorized()
|
|
{
|
|
SetSkinColorized(m_dwSkinColor, K3DTexture::COLORIZED_DEF, m_dwHairColor);
|
|
}
|
|
|
|
void SGameAvatarEx::SetHairColorIndex(int nIndex)
|
|
{
|
|
m_nHairColorIndex = nIndex;
|
|
}
|
|
|
|
void SGameAvatarEx::SetHairColorRGB(unsigned int hairColor)
|
|
{
|
|
m_dwHairColor = hairColor;
|
|
m_dwHairColor |= 0xff000000; //서버에 알파 없음
|
|
}
|
|
|
|
void SGameAvatarEx::SetSkinColorized(const DWORD& color, const int& nMode, const DWORD& hairColor)
|
|
{
|
|
// Actual character render in game
|
|
m_dwSkinColor = color;
|
|
m_dwSkinColor |= 0xff000000; //서버에 알파 없음
|
|
|
|
SetHairColorRGB(hairColor);
|
|
|
|
if (m_pSeqAvatar)
|
|
{
|
|
{
|
|
_CID(SET_COLORIZE);
|
|
KMsgSET_COLORIZE msg;
|
|
msg.color[0] = 0;
|
|
msg.color[1] = m_dwSkinColor; //2번째 것만 사용
|
|
msg.color[2] = 0;
|
|
msg.color[3] = 0;
|
|
|
|
if (nMode == 0)
|
|
msg.nMode = K3DTexture::COLORIZED_DEF;
|
|
else if (nMode == 1)
|
|
msg.nMode = K3DTexture::COLORIZED_KEEP_ALPHA;
|
|
else if (nMode == 2)
|
|
msg.nMode = K3DTexture::COLORIZED_USEALPHA;
|
|
|
|
// 2010.05.18 아래 코드에 Deco Mesh적용 부분이 빠져 있어서 새로운 함수를 생성했습니다. - prodongi
|
|
KSeqAvatar* pAvatarPart = m_pSeqAvatar->getAvatarPart(ANIPART_BIPED);
|
|
if (pAvatarPart)
|
|
{
|
|
std::set<int> ignoreMeshList;
|
|
ignoreMeshList.insert(MPART_HAIR);
|
|
pAvatarPart->PerformWithIgnoreMesh(id_SET_COLORIZE, msg, &ignoreMeshList);
|
|
ignoreMeshList.clear();
|
|
}
|
|
}
|
|
|
|
|
|
//m_pSeqAvatar->Perform( ANIPART_BIPED, id_SET_COLORIZE, msg );
|
|
|
|
//얼굴 Mesh는 텍스쳐 알파로 인한 Blend를 적용 시키지 않는다.
|
|
_CID(SET_USE_TEXALPHA);
|
|
KMsgSET_USE_TEXALPHA use_texalpha_msg;
|
|
use_texalpha_msg.bIsUseTexAlpha = false;
|
|
|
|
// sonador 4.1.2 아바타 머리카락 알바 버그 재수정(ALPHABLENDTWOPASS)
|
|
_CID(SET_BLENDMODE);
|
|
KMsgSET_BLENDMODE set_blend_mode;
|
|
set_blend_mode.blendMode = K3DMaterial::MBM_ALPHABLENDTWOPASS;
|
|
|
|
m_pSeqAvatar->Perform(ANIPART_BIPED, MPART_FACE, id_SET_USE_TEXALPHA, use_texalpha_msg);
|
|
//m_pSeqAvatar->Perform( ANIPART_HAIR, MPART_HAIR, id_SET_BLENDMODE, set_blend_mode );
|
|
m_pSeqAvatar->Perform(ANIPART_BIPED, MPART_HAIR, id_SET_BLENDMODE, set_blend_mode);
|
|
m_pSeqAvatar->Perform(ANIPART_MANTLE, MPART_MANTLE, id_SET_BLENDMODE, set_blend_mode); // sonador 4.1.3 망토 알파 버그 수정
|
|
|
|
_oprint("[SetSkinColorized] color: %d; nMode: %d; hairColor: %d; m_nHairColorIndex: %d; m_dwHairColor: %d\n", color, nMode, hairColor, m_nHairColorIndex, m_dwHairColor);
|
|
|
|
if (m_nHairColorIndex == 0)
|
|
{
|
|
_CID(SET_COLORIZE);
|
|
KMsgSET_COLORIZE msg;
|
|
msg.color[0] = 0;
|
|
msg.color[1] = m_dwHairColor; // Only use the second one
|
|
msg.color[2] = 0;
|
|
msg.color[3] = 0;
|
|
|
|
// 아바타 머리색 변경
|
|
// 2010-2-8 : hunee
|
|
msg.nMode = K3DTexture::COLORIZED_GRAY;
|
|
//msg.nMode = K3DTexture::COLORIZED_USEALPHA;
|
|
m_pSeqAvatar->Perform(ANIPART_BIPED, MPART_HAIR, id_SET_COLORIZE, msg);
|
|
}
|
|
// 2010.05.25 - prodongi
|
|
else if (1 == m_nHairColorIndex || 2 == m_nHairColorIndex)
|
|
{
|
|
setMaintainHairColorNewToOld(GetHair(), m_nHairColorIndex, GetRace(), GetSex(), m_pSeqAvatar);
|
|
}
|
|
}
|
|
|
|
//refreshWink( m_pSeqAvatar );
|
|
}
|
|
|
|
void* SGameAvatarEx::Perform(KID id, KArg& msg)
|
|
{
|
|
if (!m_pSeqAvatar || !m_bIsInit) return (void*)0;
|
|
|
|
return m_pSeqAvatar->Perform(id, msg);
|
|
|
|
return (void*)0;
|
|
}
|
|
|
|
void* SGameAvatarEx::Perform(int nAniIndex, KID id, KArg& msg)
|
|
{
|
|
if (!m_pSeqAvatar || !m_bIsInit) return (void*)0;
|
|
|
|
return m_pSeqAvatar->Perform(nAniIndex, id, msg);
|
|
|
|
return (void*)0;
|
|
}
|
|
|
|
void* SGameAvatarEx::Perform(int nAniIndex, int nMeshIndex, KID id, KArg& msg)
|
|
{
|
|
if (!m_pSeqAvatar || !m_bIsInit) return (void*)0;
|
|
|
|
return m_pSeqAvatar->Perform(nAniIndex, nMeshIndex, id, msg);
|
|
|
|
return (void*)0;
|
|
}
|
|
|
|
//Animation 관련
|
|
|
|
void SGameAvatarEx::SetAttackAniLock(bool bLock)
|
|
{
|
|
m_bLockAttackAni = bLock;
|
|
}
|
|
|
|
void SGameAvatarEx::SetAniLock(bool bLock)
|
|
{
|
|
m_bLockAni = bLock;
|
|
//#ifndef NDEBUG
|
|
// if( m_bLocal )
|
|
// {
|
|
// if( m_bLockAni )
|
|
// _oprint( "AniLock - Lock\n" );
|
|
// else
|
|
// _oprint( "AniLock - UnLock\n" );
|
|
// }
|
|
//#endif
|
|
}
|
|
|
|
void SGameAvatarEx::FindEventList(const char* pAni, _KEY_EVENT_RES*& pCurEventHandle, KSVEC_KEVENT_RES& svEventList)
|
|
{
|
|
pCurEventHandle = NULL;
|
|
|
|
//체크할 필요는 없을듯 by metarrgear
|
|
// if( !m_bIsActivated || !m_bIsInit ) return;
|
|
|
|
_KEY_EVENT_RES* pFind = NULL;
|
|
if (svEventList.lookup(pAni, pFind))
|
|
{
|
|
pCurEventHandle = pFind;
|
|
pCurEventHandle->SetInit();
|
|
}
|
|
|
|
//_KEY_EVENT_RES temp;
|
|
//temp.SetName( pAni );
|
|
//int idx = svEventList.search_index( &temp );
|
|
//if( idx != -1 )
|
|
//{
|
|
// pCurEventHandle = svEventList[idx];
|
|
// pCurEventHandle->SetInit();
|
|
//}
|
|
}
|
|
|
|
const char* SGameAvatarEx::GetAniKey(int nObjType, int nAniIndex, bool bOnlyGetAniKey)
|
|
{
|
|
m_strAniKey = "";
|
|
|
|
if (nObjType == TS_ENTER::GAME_PLAYER || nObjType == TS_ENTER::GAME_MOB || nObjType == TS_ENTER::GAME_SUMMON || nObjType == TS_ENTER::GAME_PET)
|
|
{
|
|
const char* pAni = NULL;
|
|
|
|
if (nObjType == TS_ENTER::GAME_PLAYER)
|
|
pAni = GetMotionSetDB().GetAni(nObjType, nAniIndex, GetRace(), GetSex(), m_nAniClass);
|
|
else if (nObjType == TS_ENTER::GAME_MOB)
|
|
{
|
|
_MONSTER_INFO_FILE* pMonster = GetMonsterDB().GetMonsterData(GetInnContentID());
|
|
if (pMonster)
|
|
pAni = GetMonsterMotionSetDB().GetAni(pMonster->motion_file_id, nAniIndex);
|
|
else
|
|
{
|
|
_oprint("GetAni Key Fail - Mob : %d\n", GetInnContentID());
|
|
// assert( 0 && "GetAni Key Fail GetInnContentID() 이상한듯" );
|
|
}
|
|
}
|
|
else if (nObjType == TS_ENTER::GAME_SUMMON)
|
|
{
|
|
_SUMMON_INFO_FILE* pSummon = GetCreatureDB().GetCreatureData(GetInnContentID());
|
|
if (pSummon)
|
|
{
|
|
pAni = GetMonsterMotionSetDB().GetAni(pSummon->motion_file_id, nAniIndex);
|
|
}
|
|
else
|
|
{
|
|
_oprint("GetAni Key Fail - Summon : %d\n", GetInnContentID());
|
|
// assert( 0 && "GetAni Key Fail GetInnContentID() 이상한듯" );
|
|
}
|
|
}
|
|
else if (nObjType == TS_ENTER::GAME_PET)
|
|
{
|
|
SPetInfoEx Pet = GetPetDB().Find(GetInnContentID());
|
|
pAni = GetMonsterMotionSetDB().GetAni(Pet.getMotionFileID(), nAniIndex);
|
|
}
|
|
|
|
if (!bOnlyGetAniKey)
|
|
SetEventHandleNull();
|
|
|
|
if (pAni)
|
|
{
|
|
//이벤트 핸들 설정
|
|
if (!bOnlyGetAniKey)
|
|
{
|
|
FindEventList(pAni, m_pCurEventHandle00_effect, m_svEventHandle00_effectList);
|
|
FindEventList(pAni, m_pCurEventHandle00_sound, m_svEventHandle00_soundList);
|
|
FindEventList(pAni, m_pCurEventHandle00_motion_effect, m_svEventHandle00_motion_effect);
|
|
FindEventList(pAni, m_pCurEventHandle01, m_svEventHandle01_List);
|
|
FindEventList(pAni, m_pCurEventHandle02, m_svEventHandle02_List);
|
|
FindEventList(pAni, m_pCurEventHandle03, m_svEventHandle03_List);
|
|
FindEventList(pAni, m_pCurEventHandle04, m_svEventHandle04_List);
|
|
FindEventList(pAni, m_pCurEventHandle05, m_svEventHandle05_List);
|
|
FindEventList(pAni, m_pCurEventHandle06, m_svEventHandle06_List);
|
|
|
|
// FindMotionAddOnFx();
|
|
}
|
|
|
|
CStringUtil::GetStrKey(pAni, '_', m_strAniKey);
|
|
// _oprint( "ANI_NAME : %s\n", m_strAniKey.c_str() );
|
|
}
|
|
}
|
|
else if (nObjType == TS_ENTER::GAME_NPC)
|
|
{
|
|
//Todo
|
|
}
|
|
|
|
return m_strAniKey.c_str();
|
|
}
|
|
|
|
float SGameAvatarEx::Attack(AR_HANDLE target, K3DVector tpos, DWORD dwAttackRate, int nAniIndex)
|
|
{
|
|
m_nNewCurAniType = nAniIndex;
|
|
|
|
if (!m_pSeqAvatar || !m_bIsInit) return false;
|
|
|
|
int nBoneCount = 0;
|
|
DWORD dwMinTime, dwMaxTime;
|
|
dwMinTime = 0;
|
|
dwMaxTime = 0;
|
|
|
|
//공격 스피드 구하자.
|
|
std::string strAniKey = GetAniKey(GetInnObjType(), nAniIndex);
|
|
|
|
m_pSeqAvatar->GetFrameInfo(ANIPART_BIPED, strAniKey.c_str(), nBoneCount, dwMinTime, dwMaxTime);
|
|
|
|
float fAttack = GetAttackSpeed(dwAttackRate);
|
|
//기본 배율
|
|
float fRate = GetAniPlayRate(fAttack, dwMaxTime, false);
|
|
|
|
//_oprint( "SGameAvatarEx : total[%d], fAttack[%f], fRate[%f]\n", dwAttackRate, fAttack, fRate );
|
|
|
|
fRate = 4.8f * fRate;
|
|
|
|
//_oprint( "Attack Speed: %d, %d, %f\n", dwAttackRate, dwMaxTime, 4.8f / fRate );
|
|
|
|
_playAnimation(m_pSeqAvatar, strAniKey.c_str(), SEQTYPE_NORMAL, fRate);
|
|
|
|
return fRate;
|
|
}
|
|
|
|
float SGameAvatarEx::GetAttackSpeed(DWORD attack_speed)
|
|
{
|
|
float fAttack = attack_speed;
|
|
int nMotionSpeed = -1;
|
|
|
|
if (GetInnObjType() == TS_ENTER::GAME_MOB)
|
|
nMotionSpeed = GetMonsterDB().GetMotionSpeed(GetInnContentID());
|
|
else if (GetInnObjType() == TS_ENTER::GAME_SUMMON)
|
|
nMotionSpeed = GetCreatureDB().GetMotionSpeed(GetInnContentID());
|
|
|
|
if (nMotionSpeed == MOTION_SPEED_0) // 0:느림 = 공격5 : 대기5
|
|
{
|
|
fAttack = attack_speed - attack_speed * 0.5f;
|
|
}
|
|
else if (nMotionSpeed == MOTION_SPEED_1)// 1:보통 = 공격6 : 대기4
|
|
{
|
|
fAttack = attack_speed - attack_speed * 0.4f;
|
|
}
|
|
else if (nMotionSpeed == MOTION_SPEED_2)// 2:빠름 = 공격7 : 대기3
|
|
{
|
|
fAttack = attack_speed - attack_speed * 0.3f;
|
|
}
|
|
else if (nMotionSpeed == MOTION_SPEED_3)// 3:일반 = 공격10 : 대기0
|
|
{
|
|
fAttack = attack_speed;
|
|
}
|
|
|
|
return fAttack;
|
|
}
|
|
|
|
bool SGameAvatarEx::_damage()
|
|
{
|
|
if (!m_pSeqAvatar) return false;
|
|
|
|
// _oprint( "Damage()\n" );
|
|
|
|
//마운트 상태이거나 마운트 모드가 아니라면
|
|
if (!IsMount() && !IsMountMode())
|
|
{
|
|
if (m_pStateVM)
|
|
m_pStateVM->SetMode(SObjectStateMachine::MODE_ATTACK);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SGameAvatarEx::_playAnimation(KSeqAvatarEx* pSeqAvatarEx, const char* pAniKey, int nAniType, float fPlayRate)
|
|
{
|
|
if (pSeqAvatarEx)
|
|
{
|
|
pSeqAvatarEx->Initialize();
|
|
|
|
pSeqAvatarEx->PlayAnimation(ANIPART_BIPED, m_dwTime, pAniKey, nAniType, fPlayRate);
|
|
|
|
pSeqAvatarEx->PlayAnimation(ANIPART_HAIR, m_dwTime, pAniKey, nAniType, fPlayRate);
|
|
|
|
//pSeqAvatarEx->PlayAnimation( ANIPART_EARRING , m_dwTime, pAniKey, nAniType, fPlayRate );
|
|
|
|
pSeqAvatarEx->PlayAnimation(ANIPART_NECKLACE, m_dwTime, pAniKey, nAniType, fPlayRate);
|
|
|
|
pSeqAvatarEx->PlayAnimation(ANIPART_SHORTSKIRT, m_dwTime, pAniKey, nAniType, fPlayRate);
|
|
//m_pSeqAvatar->PlayAnimation( ANIPART_LONGSKIRT , m_dwTime, pAniKey, nAniType, fPlayRate );
|
|
|
|
pSeqAvatarEx->PlayAnimation(ANIPART_MIDSKIRT, m_dwTime, pAniKey, nAniType, fPlayRate);
|
|
|
|
pSeqAvatarEx->PlayAnimation(ANIPART_FABRIC, m_dwTime, pAniKey, nAniType, fPlayRate);
|
|
|
|
pSeqAvatarEx->PlayAnimation(ANIPART_MANTLE, m_dwTime, pAniKey, nAniType, fPlayRate);
|
|
|
|
//무기(왼,오른손)
|
|
pSeqAvatarEx->PlayAnimation(ANIPART_WEAPON_LEFT, m_dwTime, pAniKey, nAniType, fPlayRate);
|
|
|
|
pSeqAvatarEx->PlayAnimation(ANIPART_WEAPON_RIGHT, m_dwTime, pAniKey, nAniType, fPlayRate);
|
|
|
|
pSeqAvatarEx->ReSet(); //Ani 재사용시 필요.
|
|
pSeqAvatarEx->SetAttachBone();
|
|
|
|
m_bIsTryPlayAni = false;
|
|
return true;
|
|
}
|
|
|
|
m_bIsTryPlayAni = true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void SGameAvatarEx::ThreadNPlayAnimation(KSeqAvatarEx* pSeqAvatarEx, int nType, int nAniType /*= SEQTYPE_NORMAL*/, float fPlayRate/* = 4.8f */)
|
|
{
|
|
m_nNewCurAniType = nType;
|
|
m_nCurPlayType = nAniType;
|
|
m_fCurPlayRate = fPlayRate;
|
|
|
|
if (GetInnObjType() == TS_ENTER::GAME_PLAYER ||
|
|
GetInnObjType() == TS_ENTER::GAME_MOB ||
|
|
GetInnObjType() == TS_ENTER::GAME_SUMMON ||
|
|
GetInnObjType() == TS_ENTER::GAME_PET)
|
|
{
|
|
std::string strAniKey = GetAniKey(GetInnObjType(), nType);
|
|
_playAnimation(pSeqAvatarEx, strAniKey.c_str(), nAniType, fPlayRate);
|
|
}
|
|
else if (GetInnObjType() == TS_ENTER::GAME_NPC)
|
|
{
|
|
std::string strAniKey = "una_default01";
|
|
_playAnimation(pSeqAvatarEx, strAniKey.c_str(), nAniType, fPlayRate);
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::NPlayAnimation(int nType, int nAniType, float fPlayRate)
|
|
{
|
|
m_nNewCurAniType = nType;
|
|
m_nCurPlayType = nAniType;
|
|
m_fCurPlayRate = fPlayRate;
|
|
|
|
if (!m_pSeqAvatar) return;
|
|
|
|
if (GetInnObjType() == TS_ENTER::GAME_PLAYER ||
|
|
GetInnObjType() == TS_ENTER::GAME_MOB ||
|
|
GetInnObjType() == TS_ENTER::GAME_SUMMON ||
|
|
GetInnObjType() == TS_ENTER::GAME_PET)
|
|
{
|
|
std::string strAniKey = GetAniKey(GetInnObjType(), nType);
|
|
_playAnimation(m_pSeqAvatar, strAniKey.c_str(), nAniType, fPlayRate);
|
|
}
|
|
else if (GetInnObjType() == TS_ENTER::GAME_NPC)
|
|
{
|
|
std::string strAniKey = "una_default01";
|
|
_playAnimation(m_pSeqAvatar, strAniKey.c_str(), nAniType, fPlayRate);
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::NPlayOverride(int nType, float fPlayRate)
|
|
{
|
|
if (GetInnObjType() == TS_ENTER::GAME_PLAYER ||
|
|
GetInnObjType() == TS_ENTER::GAME_MOB ||
|
|
GetInnObjType() == TS_ENTER::GAME_SUMMON ||
|
|
GetInnObjType() == TS_ENTER::GAME_PET)
|
|
{
|
|
std::string strAniKey = GetAniKey(GetInnObjType(), nType);
|
|
|
|
//이펙트 관련된 것도 Override 되도록 수정 해야 한다.
|
|
if (m_pSeqAvatar && m_bIsInit)
|
|
{
|
|
m_pSeqAvatar->PlayOverride(ANIPART_BIPED, m_dwTime, strAniKey.c_str(), fPlayRate);
|
|
m_pSeqAvatar->PlayOverride(ANIPART_HAIR, m_dwTime, strAniKey.c_str(), fPlayRate);
|
|
// m_pSeqAvatar->PlayOverride( ANIPART_EARRING , m_dwTime, strAniKey.c_str(), fPlayRate );
|
|
m_pSeqAvatar->PlayOverride(ANIPART_NECKLACE, m_dwTime, strAniKey.c_str(), fPlayRate);
|
|
m_pSeqAvatar->PlayOverride(ANIPART_SHORTSKIRT, m_dwTime, strAniKey.c_str(), fPlayRate);
|
|
// m_pSeqAvatar->PlayOverride( ANIPART_LONGSKIRT , m_dwTime, strAniKey.c_str(), fPlayRate );
|
|
m_pSeqAvatar->PlayOverride(ANIPART_MIDSKIRT, m_dwTime, strAniKey.c_str(), fPlayRate);
|
|
m_pSeqAvatar->PlayOverride(ANIPART_FABRIC, m_dwTime, strAniKey.c_str(), fPlayRate);
|
|
m_pSeqAvatar->PlayOverride(ANIPART_MANTLE, m_dwTime, strAniKey.c_str(), fPlayRate);
|
|
//무기(왼,오른손)
|
|
m_pSeqAvatar->PlayOverride(ANIPART_WEAPON_LEFT, m_dwTime, strAniKey.c_str(), fPlayRate);
|
|
m_pSeqAvatar->PlayOverride(ANIPART_WEAPON_RIGHT, m_dwTime, strAniKey.c_str(), fPlayRate);
|
|
|
|
//m_pSeqAvatar->ReSet(); //Ani 재사용시 필요.
|
|
m_pSeqAvatar->SetAttachBone();
|
|
|
|
m_bPlayOverride = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//void SGameAvatarEx::PlayAnimation( int nType , int nAniType, float fPlayRate )
|
|
//{
|
|
// if( IsAniLock() )
|
|
// return;
|
|
//
|
|
// m_nCurAniType = nType;
|
|
// m_nCurPlayType = nAniType;
|
|
// m_fCurPlayRate = fPlayRate;
|
|
// // fPlayRate = .5f;
|
|
//
|
|
// //if( IsLocalPlayer() )
|
|
// // _oprint( "PlayAnimation : %d\n", nType );
|
|
//
|
|
// //if( GetAnimationType() == ANI_DEAD )
|
|
// //{
|
|
// //}
|
|
//
|
|
// //위에서 설정 할 수 있게 바꿔야 한다.
|
|
// std::string strAniKey = pAniClassEx[m_nAniClass];
|
|
// strAniKey += pAniEx[nType];
|
|
//
|
|
// //
|
|
// //_oprint( "PlayAnimation : %s\n", strAniKey.c_str() );
|
|
//
|
|
// ////동작 되는지 알 수 없다.
|
|
// //if( nType == NANI_ATTACK01 || nType == NANI_ATTACK02 )
|
|
// //{
|
|
// // if( m_pSeqAvatar ) m_pSeqAvatar->SetItemRenderFlag( ANIPART_BIPED, true );
|
|
// //}
|
|
// //else
|
|
// //{
|
|
// // if( m_pSeqAvatar ) m_pSeqAvatar->SetItemRenderFlag( ANIPART_BIPED, false );
|
|
// //}
|
|
//
|
|
// _playAnimation( strAniKey.c_str(), nAniType, fPlayRate );
|
|
//}
|
|
|
|
//Play Animation 후에 유효하다.
|
|
void SGameAvatarEx::GetCurSeqEvent(EVENT_SET& event_set)
|
|
{
|
|
event_set.pCurEvent00_effect = m_pCurEventHandle00_effect;
|
|
event_set.pCurEvent00_sound = m_pCurEventHandle00_sound;
|
|
event_set.pCurEvent00_motion_effect = m_pCurEventHandle00_motion_effect;
|
|
event_set.pCurEvent01 = m_pCurEventHandle01;
|
|
event_set.pCurEvent02 = m_pCurEventHandle02;
|
|
event_set.pCurEvent03 = m_pCurEventHandle03;
|
|
event_set.pCurEvent04 = m_pCurEventHandle04;
|
|
event_set.pCurEvent05 = m_pCurEventHandle05;
|
|
event_set.pCurEvent06 = m_pCurEventHandle06;
|
|
|
|
|
|
m_pCurEventHandle00_effect = NULL;
|
|
m_pCurEventHandle00_sound = NULL;
|
|
m_pCurEventHandle00_motion_effect = NULL;
|
|
m_pCurEventHandle01 = NULL;
|
|
m_pCurEventHandle02 = NULL;
|
|
m_pCurEventHandle03 = NULL;
|
|
m_pCurEventHandle04 = NULL;
|
|
m_pCurEventHandle05 = NULL;
|
|
m_pCurEventHandle06 = NULL;
|
|
}
|
|
|
|
//void SGameAvatarEx::PlayOverride( int nType ,float fPlayRate )
|
|
//{
|
|
//// std::string strAniKey = pAniClassEx[m_nAniClass];
|
|
//// strAniKey += pAniEx[nType];
|
|
////
|
|
//// //이펙트 관련된 것도 Override 되도록 수정 해야 한다.
|
|
//// if( m_pSeqAvatar )
|
|
//// {
|
|
//// m_pSeqAvatar->PlayOverride( ANIPART_BIPED , m_dwTime, strAniKey.c_str(), fPlayRate );
|
|
//// m_pSeqAvatar->PlayOverride( ANIPART_HAIR , m_dwTime, strAniKey.c_str(), fPlayRate );
|
|
//// m_pSeqAvatar->PlayOverride( ANIPART_EARRING , m_dwTime, strAniKey.c_str(), fPlayRate );
|
|
//// m_pSeqAvatar->PlayOverride( ANIPART_NECKLACE , m_dwTime, strAniKey.c_str(), fPlayRate );
|
|
//// m_pSeqAvatar->PlayOverride( ANIPART_SHORTSKIRT, m_dwTime, strAniKey.c_str(), fPlayRate );
|
|
////// m_pSeqAvatar->PlayOverride( ANIPART_LONGSKIRT , m_dwTime, strAniKey.c_str(), fPlayRate );
|
|
//// m_pSeqAvatar->PlayOverride( ANIPART_MIDSKIRT , m_dwTime, strAniKey.c_str(), fPlayRate );
|
|
//// m_pSeqAvatar->PlayOverride( ANIPART_FABRIC , m_dwTime, strAniKey.c_str(), fPlayRate );
|
|
//// m_pSeqAvatar->PlayOverride( ANIPART_MANTLE , m_dwTime, strAniKey.c_str(), fPlayRate );
|
|
//// //무기(왼,오른손)
|
|
//// m_pSeqAvatar->PlayOverride( ANIPART_WEAPON_LEFT , m_dwTime, strAniKey.c_str(), fPlayRate );
|
|
//// m_pSeqAvatar->PlayOverride( ANIPART_WEAPON_RIGHT, m_dwTime, strAniKey.c_str(), fPlayRate );
|
|
////
|
|
//// //m_pSeqAvatar->ReSet(); //Ani 재사용시 필요.
|
|
//// m_pSeqAvatar->SetAttachBone();
|
|
//// }
|
|
//}
|
|
|
|
//RefreshItem 한 다음에 부른다.
|
|
void SGameAvatarEx::AttachAnimation(KSeqAvatarEx* pAvatarEx)
|
|
{
|
|
if (pAvatarEx)
|
|
{
|
|
pAvatarEx->SetAttachBone();
|
|
}
|
|
}
|
|
|
|
|
|
int SGameAvatarEx::GetItemClass()
|
|
{
|
|
if (GetObjType() == TS_ENTER::GAME_MOB)
|
|
{
|
|
_MONSTER_INFO_FILE* pMob = GetMonsterDB().GetMonsterData(GetContentID());
|
|
if (pMob)
|
|
return pMob->weapon_type;
|
|
}
|
|
else if (GetObjType() == TS_ENTER::GAME_SUMMON)
|
|
{
|
|
_SUMMON_INFO_FILE* pSummon = GetCreatureDB().GetCreatureData(GetContentID());
|
|
if (pSummon)
|
|
return pSummon->weapon_type;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int SGameAvatarEx::GetMaterial() //재질
|
|
{
|
|
if (GetInnObjType() == TS_ENTER::GAME_MOB)
|
|
{
|
|
_MONSTER_INFO_FILE* pMob = GetMonsterDB().GetMonsterData(GetInnContentID());
|
|
if (pMob)
|
|
return pMob->nMaterial;
|
|
}
|
|
else if (GetInnObjType() == TS_ENTER::GAME_SUMMON)
|
|
{
|
|
_SUMMON_INFO_FILE* pSummon = GetCreatureDB().GetCreatureData(GetInnContentID());
|
|
if (pSummon)
|
|
return pSummon->nMaterial;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int SGameAvatarEx::GetMovingType()
|
|
{
|
|
//2족 소형 0
|
|
//2족 중형 1
|
|
//2족 대형 2
|
|
//2족 초대형 3
|
|
//4족 소형 4
|
|
//4족 중형 5
|
|
//4족 대형 6
|
|
//4족 초대형 7
|
|
//다족 30
|
|
//미끌 31
|
|
//외발 32
|
|
//부유 33
|
|
//비행 34
|
|
//기타 99
|
|
|
|
switch (GetInnObjType())
|
|
{
|
|
case TS_ENTER::GAME_MOB: return GetMonsterDB().GetWalkType(GetInnContentID());
|
|
case TS_ENTER::GAME_SUMMON: return GetCreatureDB().GetWalkType(GetInnContentID());
|
|
case TS_ENTER::GAME_PET: return GetPetDB().Find(GetInnContentID()).getWalkType();
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void SGameAvatarEx::RefreshAni()
|
|
{
|
|
SAFE_DELETE(m_pSeqAvatar);
|
|
m_pSeqAvatar = m_pThreadAvatarEx;
|
|
m_pThreadAvatarEx = NULL;
|
|
|
|
if (IsLocalPlayer())
|
|
m_bRefreshInven = true;
|
|
|
|
if (!m_pSeqAvatar)
|
|
{
|
|
assert(0);
|
|
return;
|
|
}
|
|
|
|
SetMotionBlend(true);
|
|
|
|
//애니 메이션 클래스 변경해야 하고, 거의 다 고쳐야 한다.
|
|
if (GetCurrAnimationID() == -1)
|
|
NPlayAnimation(ANI_DEFAULT01, m_nCurPlayType);
|
|
else
|
|
{
|
|
if (!IsMoving())
|
|
{
|
|
if (m_nNewCurAniType == ANI_RUN || m_nNewCurAniType == ANI_IDLE) m_nNewCurAniType = ANI_DEFAULT01;
|
|
else if (m_nNewCurAniType == ANI_M_RUN_HIGH) m_nNewCurAniType = ANI_M_DEFAULT01_HIGH;
|
|
else if (m_nNewCurAniType == ANI_M_RUN_LOW) m_nNewCurAniType = ANI_M_DEFAULT01_LOW;
|
|
else if (m_nNewCurAniType == ANI_M_RUN_QILIN) m_nNewCurAniType = ANI_M_DEFAULT01_QILIN; // sonador #2.1.6
|
|
else if (m_nNewCurAniType == ANI_M_RUN_WHITE) m_nNewCurAniType = ANI_M_DEFAULT01_WHITE; // #2.1.14
|
|
else if (m_nNewCurAniType == ANI_M_RUN_UNICORN) m_nNewCurAniType = ANI_M_DEFAULT01_UNICORN; // #2.1.14
|
|
else if (m_nNewCurAniType == ANI_M_RUN_BEAKHO) m_nNewCurAniType = ANI_M_DEFAULT01_BEAKHO; /// 2011.02.08 - prodongi
|
|
}
|
|
|
|
if (IsLoopMotion(m_nNewCurAniType))
|
|
NPlayAnimation(m_nNewCurAniType, m_nCurPlayType);
|
|
else
|
|
NPlayAnimation(m_nNewCurAniType, SEQTYPE_NORMAL);
|
|
|
|
if (GetCurrAnimationID() == ANI_DEAD01)
|
|
{
|
|
SetEventHandleNull();
|
|
}
|
|
}
|
|
|
|
m_pSeqAvatar->SetDeform(ANIPART_BIPED);
|
|
m_pSeqAvatar->SetAttach(ANIPART_BIPED);
|
|
|
|
if (m_bIsInit)
|
|
RefreshEffectPos(m_pSeqAvatar);
|
|
|
|
//칼라 색 변경
|
|
if (GetInnObjType() == TS_ENTER::GAME_PLAYER ||
|
|
GetInnObjType() == TS_ENTER::GAME_NPC)
|
|
{
|
|
RefreshSkinColorized();
|
|
}
|
|
|
|
// 2010.05.11 - prodongi
|
|
g_pCurrentGameSystem->updateCurTarget(GetArID());
|
|
}
|
|
|
|
void SGameAvatarEx::AddMorphMesh(class KMsgSET_MORPHMESH* pMsg)
|
|
{
|
|
m_pSeqAvatar->AddMorphMesh(ANIPART_WEAPON_RIGHT, pMsg);
|
|
m_pSeqAvatar->AddMorphMesh(ANIPART_WEAPON_LEFT, pMsg);
|
|
}
|
|
|
|
void SGameAvatarEx::SetFixTexture(class KMsgSET_FIXTEXTURE* pMsg)
|
|
{
|
|
if (!IsThreadLoading() && m_bIsActivated && m_pSeqAvatar)
|
|
{
|
|
m_pSeqAvatar->SetFixTexture(ANIPART_BIPED, pMsg);
|
|
m_pSeqAvatar->SetFixTexture(ANIPART_HAIR, pMsg);
|
|
m_pSeqAvatar->SetFixTexture(ANIPART_NECKLACE, pMsg);
|
|
m_pSeqAvatar->SetFixTexture(ANIPART_EARRING, pMsg);
|
|
m_pSeqAvatar->SetFixTexture(ANIPART_MANTLE, pMsg);
|
|
m_pSeqAvatar->SetFixTexture(ANIPART_FABRIC, pMsg);
|
|
m_pSeqAvatar->SetFixTexture(ANIPART_LONGSKIRT, pMsg);
|
|
m_pSeqAvatar->SetFixTexture(ANIPART_MIDSKIRT, pMsg);
|
|
m_pSeqAvatar->SetFixTexture(ANIPART_SHORTSKIRT, pMsg);
|
|
|
|
m_pSeqAvatar->SetFixTexture(ANIPART_WEAPON_LEFT, pMsg);
|
|
m_pSeqAvatar->SetFixTexture(ANIPART_WEAPON_RIGHT, pMsg);
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::RefreshEffectPos(KSeqAvatarEx* pSeqAvatarEx)
|
|
{
|
|
for (int x(0); x < EFFECT_POS_MAX; ++x)
|
|
{
|
|
m_bEVPAttachMatrix[x] = false;
|
|
m_pEvpSequencer[x] = NULL;
|
|
}
|
|
|
|
if (pSeqAvatarEx == NULL) return;
|
|
|
|
//이펙트 포스 설정
|
|
pSeqAvatarEx->SetAttachEffectPos(ANIPART_BIPED);
|
|
|
|
_CID(REQ_EVPOINT);
|
|
KMsgREQ_EVPOINT effect_pos_msg;
|
|
pSeqAvatarEx->Perform(ANIPART_BIPED, id_REQ_EVPOINT, effect_pos_msg);
|
|
for (int i(0); i < effect_pos_msg.GetPointCount(); ++i)
|
|
{
|
|
KEventPointSeq* pEv = effect_pos_msg.GetPoint(i);
|
|
if (!pEv) continue;
|
|
|
|
const char* pName = pEv->GetName();
|
|
for (int x(0); x < EFFECT_POS_MAX; ++x)
|
|
{
|
|
if (strlen(pName) && _stricmp(pName, pEP_Name[x]) == 0)
|
|
{
|
|
K3DMatrixIdentity(m_matEVPMatrix[x]);
|
|
|
|
//이펙트쪽 방향 문제때문에 이벤트 포인트에 위치만 가져온다
|
|
K3DMatrix matEvPoint = pEv->GetPoint();
|
|
m_matEVPMatrix[x]._41 = matEvPoint._41;
|
|
m_matEVPMatrix[x]._42 = matEvPoint._42;
|
|
m_matEVPMatrix[x]._43 = matEvPoint._43;
|
|
|
|
if (pEv->GetAttachTransform())
|
|
{
|
|
m_bEVPAttachMatrix[x] = true;
|
|
m_pEvpSequencer[x] = pEv;
|
|
|
|
K3DMatrixIdentity(m_matEVPAttachMatrix[x]);
|
|
if (x == EFFECT_POS_TOP)
|
|
{
|
|
m_matEVPAttachMatrix[x]._41 = m_pEvpSequencer[x]->GetAttachTransform()->_41;
|
|
m_matEVPAttachMatrix[x]._42 = m_pEvpSequencer[x]->GetAttachTransform()->_42;
|
|
m_matEVPAttachMatrix[x]._43 = m_pEvpSequencer[x]->GetAttachTransform()->_43;
|
|
}
|
|
else
|
|
m_matEVPAttachMatrix[x] = *m_pEvpSequencer[x]->GetAttachTransform();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//몬스터 본 이펙트 추가
|
|
if (GetInnObjType() == TS_ENTER::GAME_MOB)
|
|
{
|
|
pSeqAvatarEx->SetTransform(*GetTransform());
|
|
|
|
ModelEffectResourceGame* pModelEffectRes = NULL;
|
|
_MONSTER_INFO_FILE* pMonster = GetMonsterDB().GetMonsterData(GetInnContentID());
|
|
if (pMonster) pModelEffectRes = GetModelEffectResourceDB().GetModelEffectResource(pMonster->monster_group);
|
|
if (pModelEffectRes)
|
|
{
|
|
for (int i(0); MAX_BONE_EFFECT > i; i++)
|
|
{
|
|
if (pModelEffectRes->bUseEffect[i])
|
|
{
|
|
const char* pBoneName = pModelEffectRes->bone_name[i];
|
|
const char* pBoneEffect = GetResourceDB().GetEffectResourceName(pModelEffectRes->bone_effect[i]);
|
|
|
|
//_oprint( "AddBoneEffect : Bone[%s] BoneEffect[%s]\n", pBoneName, pBoneEffect );
|
|
|
|
pSeqAvatarEx->AddBoneEffect(ANIPART_BIPED, i, pBoneName, pBoneEffect);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//크리쳐 본 이펙트 추가
|
|
//2009-03-26 : hunee
|
|
else if (GetInnObjType() == TS_ENTER::GAME_SUMMON)
|
|
{
|
|
pSeqAvatarEx->SetTransform(*GetTransform());
|
|
|
|
ModelEffectResourceGame* pModelEffectRes = NULL;
|
|
_SUMMON_INFO_FILE* pSummon = GetCreatureDB().GetCreatureData(GetInnContentID());
|
|
if (pSummon) pModelEffectRes = GetModelEffectResourceDB().GetModelEffectResource(pSummon->model_id);
|
|
|
|
if (pModelEffectRes)
|
|
{
|
|
for (int i(0); MAX_BONE_EFFECT > i; i++)
|
|
{
|
|
if (pModelEffectRes->bUseEffect[i])
|
|
{
|
|
const char* pBoneName = pModelEffectRes->bone_name[i];
|
|
const char* pBoneEffect = GetResourceDB().GetEffectResourceName(pModelEffectRes->bone_effect[i]);
|
|
|
|
//_oprint( "AddBoneEffect : Bone[%s] BoneEffect[%s]\n", pBoneName, pBoneEffect );
|
|
|
|
pSeqAvatarEx->AddBoneEffect(ANIPART_BIPED, i, pBoneName, pBoneEffect);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const K3DVector& SGameAvatarEx::GetViewVector()
|
|
{
|
|
return m_vTempView;
|
|
}
|
|
|
|
//방향 설정
|
|
void SGameAvatarEx::SetViewVector(const K3DVector& tpos)
|
|
{
|
|
m_fTargetRoll = atan2(tpos.y - GetPosition()->y, tpos.x - GetPosition()->x);
|
|
m_dwPrevTime = m_dwTime;
|
|
m_bUseRot = true;
|
|
}
|
|
|
|
/*
|
|
//방향
|
|
void SGameAvatarEx::SetViewVector( const K3DVector &tpos )
|
|
{
|
|
// _oprint(" SetViewVector Tpos : %7.4f, %7.4f, %7.4f\n", tpos.x, tpos.y, tpos.z);
|
|
|
|
K3DVector Cur, view, Out;
|
|
Cur = GetCurPos();
|
|
|
|
view = K3DVector( tpos.x, tpos.y, 0 ) - Cur;
|
|
K3DVectorNomalize(&Out, &view);
|
|
|
|
float fVevLen = K3DVectorGetLength( K3DVector(Cur.x,Cur.y,0.f), K3DVector( tpos.x,tpos.y,0 ) );
|
|
|
|
float fLen = Magnitude( Out );
|
|
if( fLen > 0.f && fVevLen > 0.5f )
|
|
{
|
|
m_vView = Out; //뷰벡터 설정
|
|
|
|
//방향 설정
|
|
K3DMatrix mat;
|
|
K3DMatrixIdentity(mat);
|
|
|
|
mat._11 = -Out.y;
|
|
mat._21 = -Out.x;
|
|
mat._31 = 0;
|
|
mat._12 = Out.x;
|
|
mat._22 = -Out.y;
|
|
mat._32 = 0;
|
|
mat._41 = Cur.x;
|
|
mat._42 = Cur.y;
|
|
mat._43 = GetHeight( Cur.x, Cur.y,m_wCurTile );
|
|
|
|
SetTransform(mat);
|
|
}
|
|
//else {
|
|
// m_vView;
|
|
// //방향 설정
|
|
// K3DMatrix mat;
|
|
// K3DMatrixIdentity(mat);
|
|
|
|
// mat._41 = Cur.x;
|
|
// mat._42 = Cur.y;
|
|
// mat._43 = GetHeight( Cur.x, Cur.y,m_wCurTile );
|
|
|
|
// SetTransform(mat);
|
|
// {
|
|
// _oprint(" SetViewVector Out : %7.4f, %7.4f, %7.4f\n", Out.x, Out.y, Out.z);
|
|
// }
|
|
//}
|
|
}*/
|
|
|
|
void SGameAvatarEx::ClipTest(struct K3DVector* pFrustum)
|
|
{
|
|
if (!m_bIsInit) return;
|
|
|
|
if (m_pSeqAvatar)
|
|
{
|
|
if (IsStateRide())
|
|
AvatarClipTestByCreature(pFrustum);
|
|
else
|
|
m_pSeqAvatar->ClipTest(pFrustum);
|
|
|
|
|
|
if (!m_pSeqAvatar->GetIsClip())
|
|
m_xRenderFlag.On(AV_BASIC);
|
|
else
|
|
m_xRenderFlag.Off(AV_BASIC);
|
|
|
|
|
|
if (GetInnObjType() == TS_ENTER::GAME_PLAYER)
|
|
{
|
|
bool bNewVisible = (m_xRenderFlag.IsOn(AV_BASIC) && m_bVisible);
|
|
if (m_bPrevVisible != bNewVisible)
|
|
{
|
|
SetWeaponEnhanceFx(m_nTwoHandWeaponCode, bNewVisible);
|
|
SetWeaponEnhanceFx(m_nRightHandWeaponCode, bNewVisible);
|
|
SetWeaponEnhanceFx(m_nLeftHandWeaponCode, bNewVisible);
|
|
|
|
m_bPrevVisible = bNewVisible;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Picking
|
|
bool SGameAvatarEx::CheckCollision(const K3DVector& nv, const K3DVector& fv)
|
|
{
|
|
if (!IsLoadComplete()) return false;
|
|
|
|
if (!IsActivated()) return false;
|
|
|
|
if (IsLive())
|
|
{
|
|
K3DBoundRotCube cube(m_fSelcube[0], m_fSelcube[3], m_fSelcube[1], m_fSelcube[4], m_fSelcube[2], m_fSelcube[5]);
|
|
cube.SetTransform(*GetTransform());
|
|
return cube.CheckCollision(nv, fv);
|
|
}
|
|
else
|
|
{
|
|
K3DBoundRotCube cube(m_fDeadcube[0], m_fDeadcube[3], m_fDeadcube[1], m_fDeadcube[4], m_fDeadcube[2], m_fDeadcube[5]);
|
|
cube.SetTransform(*GetTransform());
|
|
return cube.CheckCollision(nv, fv);
|
|
}
|
|
|
|
assert(0);
|
|
|
|
//Load 안되면, 클릭안돼~
|
|
return false;
|
|
}
|
|
|
|
bool SGameAvatarEx::RelaxedCheckCollision(const K3DVector& nv, const K3DVector& fv, K3DVALUE r)
|
|
{
|
|
if (!IsActivated()) return false;
|
|
|
|
if (IsLive())
|
|
{
|
|
K3DBoundRotCube cube(m_fSelcube[0] - r, m_fSelcube[3] + r, m_fSelcube[1] - r, m_fSelcube[4] + r, m_fSelcube[2] - r, m_fSelcube[5] + r);
|
|
cube.SetTransform(*GetTransform());
|
|
return cube.CheckCollision(nv, fv);
|
|
}
|
|
else
|
|
{
|
|
K3DBoundRotCube cube(m_fDeadcube[0] - r, m_fDeadcube[3] + r, m_fDeadcube[1] - r, m_fDeadcube[4] + r, m_fDeadcube[2] - r, m_fDeadcube[5] + r);
|
|
cube.SetTransform(*GetTransform());
|
|
return cube.CheckCollision(nv, fv);
|
|
}
|
|
|
|
assert(0);
|
|
|
|
//Load 안되면, 클릭안돼~
|
|
return false;
|
|
}
|
|
|
|
void SGameAvatarEx::SetStat(struct SMSG_STAT_INFO* pStat)
|
|
{
|
|
if (GetArID() == pStat->handle && pStat->type == 0)
|
|
{
|
|
if (m_pProperty)
|
|
m_pProperty->ProcMsgAtStatic(pStat);
|
|
}
|
|
}
|
|
|
|
bool SGameAvatarEx::IsRender()
|
|
{
|
|
if (!m_bVisible || !m_bIsActivated || !m_bIsInit || !m_xRenderFlag.IsOn(AV_BASIC))
|
|
return true;
|
|
|
|
if (m_nStateFlag & FLAG_STATE_HIDING)
|
|
{
|
|
if (m_fHidingVisiblity < HIDING_VISIBILITY_RATE)
|
|
return false;
|
|
}
|
|
|
|
if (IsPendLoading())
|
|
return false;
|
|
|
|
return true;
|
|
|
|
// return m_xRenderFlag.IsOn( AV_BASIC );
|
|
}
|
|
|
|
void SGameAvatarEx::SetHP(int nHP, bool IsEnter)
|
|
{
|
|
if (IsEnter) //공격 받은 후~
|
|
{
|
|
if (m_pProperty)
|
|
m_pProperty->HP = nHP;
|
|
|
|
//if( GetHP() <= 0 )
|
|
if (nHP <= 0)
|
|
{
|
|
m_bIsDead = true; //시체 엔터된 경우
|
|
|
|
NPlayAnimation(ANI_DEAD01, SEQTYPE_LASTPAGE);
|
|
SetAnimationPos(SEQPOS_END);
|
|
SetEventHandleNull();
|
|
|
|
if (m_pStateVM) m_pStateVM->Dead();
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (m_pProperty)
|
|
m_pProperty->HP = nHP;
|
|
|
|
//살아난 것임.
|
|
if (IsDead() && nHP > 0)
|
|
{
|
|
m_bIsDead = false;
|
|
Default();
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::SetMaxHP(int nMaxHP)
|
|
{
|
|
if (m_pProperty) m_pProperty->MaxHP = nMaxHP;
|
|
}
|
|
|
|
void SGameAvatarEx::SetMP(int nMP)
|
|
{
|
|
if (m_pProperty) m_pProperty->MP = nMP;
|
|
}
|
|
|
|
void SGameAvatarEx::SetMaxMP(int nMaxMP)
|
|
{
|
|
if (m_pProperty) m_pProperty->MaxMP = nMaxMP;
|
|
}
|
|
void SGameAvatarEx::AddExp(__int64 nExp)
|
|
{
|
|
if (m_pProperty) m_pProperty->AddExp(nExp);
|
|
}
|
|
void SGameAvatarEx::AddJP(__int64 nJp)
|
|
{
|
|
if (m_pProperty) m_pProperty->AddJP(nJp);
|
|
}
|
|
void SGameAvatarEx::SetRace(int nRace)
|
|
{
|
|
if (m_pProperty) m_pProperty->Race = nRace;
|
|
}
|
|
int SGameAvatarEx::GetRace()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->Race;
|
|
|
|
return GCLAN_NOTHING;
|
|
}
|
|
|
|
int SGameAvatarEx::GetFace()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->FaceID;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SGameAvatarEx::GetHair()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->HairID;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SGameAvatarEx::GetLevel()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->Level;
|
|
|
|
assert(0);
|
|
return 0;
|
|
}
|
|
|
|
int SGameAvatarEx::SetLevel(int nLevel)
|
|
{
|
|
if (!m_pProperty) return false;
|
|
return m_pProperty->SetLevel(nLevel);
|
|
}
|
|
|
|
int SGameAvatarEx::GetJobLevel()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->JobLevel;
|
|
|
|
assert(0);
|
|
return 0;
|
|
}
|
|
|
|
int SGameAvatarEx::SetJobLevel(int nJobLevel)
|
|
{
|
|
if (!m_pProperty) return false;
|
|
return m_pProperty->SetJobLevel(nJobLevel);
|
|
}
|
|
|
|
/// 2011.07.11 - prodongi
|
|
void SGameAvatarEx::SetJobID(int id)
|
|
{
|
|
if (m_pProperty)
|
|
m_pProperty->SetJobID(id);
|
|
}
|
|
|
|
bool SGameAvatarEx::IsMasterClass(int id)
|
|
{
|
|
if (id % 100 >= 20) // 2011.7.13 - marine 마스터 클래스 아이디만 x20~x24
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void SGameAvatarEx::SetStatus(unsigned status)
|
|
{
|
|
if (m_pProperty)
|
|
{
|
|
m_pProperty->Status = status;
|
|
}
|
|
}
|
|
|
|
int SGameAvatarEx::GetStatus()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->Status;
|
|
return 0;
|
|
}
|
|
|
|
void SGameAvatarEx::SetObjType(unsigned char ObjType)
|
|
{
|
|
if (m_pProperty)
|
|
m_pProperty->ObjType = ObjType;
|
|
}
|
|
|
|
unsigned char SGameAvatarEx::GetObjType()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->ObjType;
|
|
|
|
assert(0);
|
|
return -1;
|
|
}
|
|
|
|
ENC_INT SGameAvatarEx::GetContentID()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->ContentID();
|
|
|
|
assert(0);
|
|
return -1;
|
|
}
|
|
int SGameAvatarEx::GetJobID()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->JobID;
|
|
|
|
assert(0);
|
|
return -1;
|
|
}
|
|
|
|
bool SGameAvatarEx::IsLocalPlayer()
|
|
{
|
|
return m_bLocal;
|
|
}
|
|
bool SGameAvatarEx::IsLocalCreature()
|
|
{
|
|
return m_bLocalCreature;
|
|
}
|
|
bool SGameAvatarEx::IsLocalPet()
|
|
{
|
|
return m_bLocalPet;
|
|
}
|
|
|
|
int SGameAvatarEx::GetPercentEXP()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->PercentEXP;
|
|
|
|
assert(0);
|
|
return -1;
|
|
}
|
|
|
|
int SGameAvatarEx::GetHP()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->HP;
|
|
|
|
assert(0);
|
|
return -1;
|
|
}
|
|
|
|
int SGameAvatarEx::GetMP()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->MP;
|
|
|
|
assert(0);
|
|
return -1;
|
|
}
|
|
|
|
int SGameAvatarEx::GetMaxHP()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->MaxHP;
|
|
|
|
assert(0);
|
|
return -1;
|
|
}
|
|
|
|
int SGameAvatarEx::GetMaxMP()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->MaxMP;
|
|
|
|
assert(0);
|
|
return -1;
|
|
}
|
|
|
|
__int64 SGameAvatarEx::GetEXP()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->EXP;
|
|
|
|
assert(0);
|
|
return -1;
|
|
}
|
|
|
|
/// 2011.04.29 int->__int64 - prodongi
|
|
__int64 SGameAvatarEx::GetJP()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->JP;
|
|
|
|
assert(0);
|
|
return -1;
|
|
}
|
|
|
|
const char* SGameAvatarEx::GetName()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->Name;
|
|
|
|
assert(0);
|
|
return "UnLoad Avatar";
|
|
}
|
|
|
|
void SGameAvatarEx::SetName(const char* szName)
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->Name = szName;
|
|
|
|
assert(0);
|
|
}
|
|
|
|
bool SGameAvatarEx::IsLive()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->IsLive();
|
|
|
|
assert(0);
|
|
return false;
|
|
}
|
|
|
|
AR_UNIT SGameAvatarEx::GetAttackRange()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->AttackRange;
|
|
|
|
assert(0);
|
|
return 1;
|
|
}
|
|
|
|
float SGameAvatarEx::GetDBAttackRange()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->DBAttackRange;
|
|
|
|
assert(0);
|
|
return 1.f;
|
|
}
|
|
|
|
void SGameAvatarEx::ProcMsgAtStatic(struct SGameMessage* pMsg)
|
|
{
|
|
//살아난 것임.
|
|
//if( pMsg->nType == MSG_REGEN_HPMP )
|
|
//{
|
|
// SMSG_REGEN_HPMP* pRegenHpMp = static_cast<SMSG_REGEN_HPMP*>(pMsg);
|
|
// if( GetHP() <= 0 && pRegenHpMp->hp > 0 )
|
|
// {
|
|
// Default();
|
|
// }
|
|
//}
|
|
|
|
if (m_pProperty) m_pProperty->ProcMsgAtStatic(pMsg);
|
|
|
|
if (pMsg->nType == MSG_STATE)
|
|
{ //상태 이상 리스트 추가/삭제
|
|
SMSG_STATE* pStateMsg = static_cast<SMSG_STATE*>(pMsg);
|
|
|
|
StateInfoEx* pStateInfo = GetTenacityDB().GetTenacityData(pStateMsg->state_code);
|
|
if (pStateInfo)
|
|
{
|
|
//104, 114 변이 유형
|
|
switch (pStateInfo->effect_type)
|
|
{
|
|
case STATE_TYPE::STATE_MUTATION_A: //몬스터 전용
|
|
{
|
|
if (pStateMsg->state_level) //변이
|
|
{
|
|
if ((int)pStateInfo->fValue[0] > 0)
|
|
{
|
|
AddDisguiseID(pStateInfo->id);
|
|
|
|
Disguise(pStateMsg->state_handle, bits_scramble< int, 3 >((int)pStateInfo->fValue[0])); // 2.1.16 변신 효과 중첩시 아바타 사라지는 오류 수정
|
|
}
|
|
}
|
|
else if (pStateMsg->state_level == 0) //해제
|
|
{
|
|
|
|
DeleteDisguiseID(pStateInfo->id);
|
|
|
|
UnDisguise(pStateMsg->state_handle);
|
|
}
|
|
}
|
|
break;
|
|
case STATE_TYPE::STATE_MUTATION_B: //소환수 전용
|
|
{
|
|
if (pStateMsg->state_level) //변이
|
|
{
|
|
if (pStateMsg->state_value > 0)
|
|
{
|
|
AddDisguiseID(pStateInfo->id);
|
|
|
|
/// 2011.07.28 redmine #16797 - prodongi
|
|
Disguise(pStateMsg->state_handle, pStateMsg->state_value, true, pStateMsg->state_level); // 2.1.16 변신 효과 중첩시 아바타 사라지는 오류 수정
|
|
/// 2011.04.29 변신전의 크기를 기준으로 해야 된다 - prodongi
|
|
/*
|
|
if( m_nDisguise == STAT_DISGUISE )
|
|
SetScale( GetScale() * ( pStateInfo->fValue[8] + pStateInfo->fValue[9] * pStateMsg->state_level ));
|
|
*/
|
|
if (m_nDisguise == STAT_DISGUISE)
|
|
{
|
|
/// 2012.08.10 변신 전의 크기를 적용하면 쿨타임이 짧은 경우에 중복 적용될 수가 있어서, 기본에서 적용 시킨다. - prodongi
|
|
//SetScale( getNoneDisguiseScale() * ( pStateInfo->fValue[8] + pStateInfo->fValue[9] * pStateMsg->state_level ));
|
|
SetScale(getNoneDisguiseScale() * (pStateInfo->fValue[8] + pStateInfo->fValue[9]));
|
|
}
|
|
}
|
|
}
|
|
else if (pStateMsg->state_level == 0) //해제
|
|
{
|
|
DeleteDisguiseID(pStateInfo->id);
|
|
|
|
UnDisguise(pStateMsg->state_handle);
|
|
}
|
|
}
|
|
break;
|
|
case STATE_TYPE::STATE_RESURRECTION:
|
|
{
|
|
if (pStateMsg->state_level)
|
|
AddStateFlag(FLAG_STATE_RESURRECTION);
|
|
else if (pStateMsg->state_level == 0)
|
|
RemoveStateFlag(FLAG_STATE_RESURRECTION);
|
|
}
|
|
break;
|
|
/* AziaMafia Fix MEZZ
|
|
case STATE_TYPE::EF_MEZZ:
|
|
{
|
|
if (pStateMsg->state_level)
|
|
AddStateFlag(FLAG_STATE_SLEEP);
|
|
else if (pStateMsg->state_level == 0)
|
|
RemoveStateFlag(FLAG_STATE_SLEEP);
|
|
}
|
|
break;
|
|
*/
|
|
case STATE_TYPE::STATE_DETECT_HIDING:
|
|
{
|
|
if (pStateMsg->state_level)
|
|
{
|
|
StateInfoEx* pStateInfo = GetTenacityDB().GetTenacityData(pStateMsg->state_code);
|
|
if (pStateInfo) SetHidingDetectRange(pStateInfo->fValue[0] * (float)DEFAULT_UNIT_SIZE);
|
|
|
|
AddStateFlag(FLAG_STATE_DETECT_HIDING);
|
|
}
|
|
else if (pStateMsg->state_level == 0)
|
|
{
|
|
SetHidingDetectRange(0.0f);
|
|
|
|
RemoveStateFlag(FLAG_STATE_DETECT_HIDING);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (pStateMsg->state_code) //석화 처리
|
|
{
|
|
case STATE_CODE::PETRIFY:
|
|
case STATE_CODE::STONECURSE_MORTAL:
|
|
{
|
|
if (pStateMsg->state_level)
|
|
{
|
|
KMsgSET_FIXTEXTURE msgFixTexture;
|
|
msgFixTexture.bUseFix = true;
|
|
msgFixTexture.pTexture = _getTexture("petrify00.dds");
|
|
SetFixTexture(&msgFixTexture);
|
|
|
|
AddStateFlag(FLAG_STATE_PETRIFY);
|
|
}
|
|
else if (pStateMsg->state_level == 0)
|
|
{
|
|
KMsgSET_FIXTEXTURE msgFixTexture;
|
|
msgFixTexture.bUseFix = false;
|
|
SetFixTexture(&msgFixTexture);
|
|
|
|
RemoveStateFlag(FLAG_STATE_PETRIFY);
|
|
}
|
|
}
|
|
break;
|
|
case STATE_CODE::HIDING:
|
|
case STATE_CODE::TRACE_OF_FUGITIVE:
|
|
{
|
|
if (pStateMsg->state_level)
|
|
{
|
|
if (IsLocalPlayer()) SetHidingVisiblity(HIDING_VISIBILITY_RATE);
|
|
|
|
else SetHidingVisiblity(0.0f);
|
|
|
|
AddStateFlag(FLAG_STATE_HIDING);
|
|
|
|
RemoveAllStateEffect();
|
|
}
|
|
else if (pStateMsg->state_level == 0)
|
|
{
|
|
SetHidingVisiblity(1.0f);
|
|
|
|
RemoveStateFlag(FLAG_STATE_HIDING);
|
|
|
|
RefreshAllStateEffect();
|
|
}
|
|
}
|
|
break;
|
|
|
|
//gmpbigsun( 20131107 ) : lockmoving by state
|
|
case SLEEP:
|
|
case NIGHTMARE:
|
|
case SCELLE:
|
|
case ANOMALY_SLEEP:
|
|
case MONSTER_SLEEP:
|
|
pStateMsg->state_level == 0 ? RemoveStateFlag(FLAG_STATE_SLEEP) : AddStateFlag(FLAG_STATE_SLEEP);
|
|
break;
|
|
case STUN:
|
|
case ILLUSION:
|
|
case FALL_FROM_SUMMON:
|
|
case CARELESSNESS:
|
|
case DEMONIC_STUN:
|
|
case ANOMALY_STUN:
|
|
case ANOMALY_ILLUSION:
|
|
case MONSTER_STUN:
|
|
pStateMsg->state_level == 0 ? RemoveStateFlag(FLAG_STATE_STUN) : AddStateFlag(FLAG_STATE_STUN);
|
|
break;
|
|
case HOLD:
|
|
case FROZEN_SNARE:
|
|
case EARTH_RESTRICTION:
|
|
case EARTH_TREMOR:
|
|
case ANOMALY_HOLD:
|
|
pStateMsg->state_level == 0 ? RemoveStateFlag(FLAG_STATE_HOLD) : AddStateFlag(FLAG_STATE_HOLD);
|
|
break;
|
|
case FEAR:
|
|
case DRAGONIC_FEAR:
|
|
case ANOMALY_FEAR:
|
|
pStateMsg->state_level == 0 ? RemoveStateFlag(FLAG_STATE_FEAR) : AddStateFlag(FLAG_STATE_FEAR);
|
|
break;
|
|
case FROZEN:
|
|
case ANOMALY_FROZEN:
|
|
case TOTAL_FROZEN:
|
|
pStateMsg->state_level == 0 ? RemoveStateFlag(FLAG_STATE_FROZEN) : AddStateFlag(FLAG_STATE_FROZEN);
|
|
break;
|
|
}
|
|
|
|
UpdateState(pStateMsg);
|
|
return;
|
|
}
|
|
}
|
|
|
|
const char* SGameAvatarEx::GetEffectPosName(std::string& strName)
|
|
{
|
|
CStringUtil::GetEventStrKey(strName.c_str(), '.', m_strTemp);
|
|
return m_strTemp.c_str();
|
|
|
|
return "";
|
|
}
|
|
|
|
const char* SGameAvatarEx::GetCobFileName()
|
|
{
|
|
if (GetInnObjType() == TS_ENTER::GAME_MOB)
|
|
return GetMonsterDB().GetCobFileName(GetInnContentID());
|
|
else if (GetInnObjType() == TS_ENTER::GAME_SUMMON)
|
|
{
|
|
return GetCreatureDB().GetCobFileName(GetInnContentID());
|
|
}
|
|
else if (GetInnObjType() == TS_ENTER::GAME_NPC)
|
|
{
|
|
// NpcResourceBase * pNPC = GetNpcResourceDB().GetNpcInfo( GetInnContentID() );
|
|
// if( pNPC )
|
|
{
|
|
std::string str = SStringDB::GetCobFileName(GetInnRace(), GetInnSex());
|
|
if (str.empty())
|
|
return GetNpcResourceDB().GetCobFileName(GetInnContentID());
|
|
else
|
|
return SStringDB::GetCobFileName(GetInnRace(), GetInnSex());
|
|
}
|
|
// else
|
|
// return GetNpcResourceDB().GetCobFileName( GetInnContentID() );
|
|
}
|
|
else if (GetInnObjType() == TS_ENTER::GAME_PLAYER)
|
|
return SStringDB::GetCobFileName(GetInnRace(), GetInnSex());
|
|
else if (GetInnObjType() == TS_ENTER::GAME_PET) // sonador 10.2.1 팻 시스템 구현
|
|
return GetPetDB().Find(GetInnContentID()).getModelFileName();
|
|
|
|
assert(0 && "Avatar 의 Type이 비정상적임");
|
|
|
|
return " ";
|
|
}
|
|
|
|
|
|
KSeqAvatarEx* SGameAvatarEx::LoadCOBSet(vec_cobset* pSet)
|
|
{
|
|
if (!pSet) return NULL;
|
|
|
|
KSeqAvatarEx* pSeqAvatar = new KSeqAvatarEx;
|
|
pSeqAvatar->Initialize();
|
|
pSeqAvatar->ClearAnimation();
|
|
|
|
iterator_cobset it = pSet->begin();
|
|
|
|
if (pSet->end() != it)
|
|
{
|
|
COBSET* pCob = *it;
|
|
LoadEvent(pCob);
|
|
}
|
|
|
|
if (GetInnObjType() == TS_ENTER::PLAYER)
|
|
LoadPlayerCOBSet(pSet, pSeqAvatar);
|
|
else if (GetInnObjType() == TS_ENTER::GAME_NPC)
|
|
LoadNpcCOBSet(pSet, pSeqAvatar);
|
|
else
|
|
LoadMonsterCOBSet(pSet, pSeqAvatar);
|
|
|
|
return pSeqAvatar;
|
|
}
|
|
|
|
void SGameAvatarEx::LoadPlayerCOBSet(vec_cobset* pSet, KSeqAvatarEx* pSeqAvatar)
|
|
{
|
|
iterator_cobset it = pSet->begin();
|
|
for (it = pSet->begin(); pSet->end() != it; it++)
|
|
{
|
|
COBSET* pCob = *it;
|
|
//TODO : 손보자
|
|
for (unsigned int j(0); pCob->m_AniList.size() > j; j++)
|
|
{
|
|
if (strstr(pCob->m_AniList[j].c_str(), "una_") &&
|
|
(strstr(pCob->m_AniList[j].c_str(), "default") ||
|
|
strstr(pCob->m_AniList[j].c_str(), "walk") ||
|
|
strstr(pCob->m_AniList[j].c_str(), "run")))
|
|
pSeqAvatar->AddAnimation(pCob->nAniPart, pCob->m_AniList[j].c_str(), true);
|
|
}
|
|
|
|
for (unsigned int j(0); pCob->m_HairList.size() > j; j++)
|
|
{
|
|
if (m_pProperty)
|
|
{
|
|
//std::string strHair = GetDefaultItemDB().GetFileName( GetRace(), GetSex(), GetHair() );
|
|
//pSeqAvatar->AddMesh( ANIPART_HAIR, MPART_HAIR, strHair.c_str() );
|
|
|
|
std::string strHair = GetDefaultItemDB().GetFileName(GetRace(), GetSex(), GetHair());
|
|
int nGroup = GetDefaultItemDB().GetDecoHairGroupID(GetHair());
|
|
std::string strDeco = GetDefaultTextureResourceDB().GetTextureName(nGroup, GetRace(), GetSex());
|
|
pSeqAvatar->AddMesh(ANIPART_BIPED, MPART_HAIR, strHair.c_str(), strDeco);
|
|
}
|
|
else
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_HAIR);
|
|
}
|
|
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_HELM);
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_MANTLE);
|
|
|
|
for (unsigned int j(0); pCob->m_FaceList.size() > j; j++)
|
|
{
|
|
if (m_pProperty)
|
|
{
|
|
std::string strFace = GetDefaultItemDB().GetFileName(GetRace(), GetSex(), GetFace());
|
|
// 2010.06.18 - prodongi
|
|
/*
|
|
// 2010.04.22 - prodongi
|
|
//std::string strDeco = GetDefaultTextureResourceDB().GetDecoTextureName();
|
|
std::string strDeco = getDecoTextureName();
|
|
*/
|
|
std::string strDeco;
|
|
getDecoTexName(strDeco);
|
|
pSeqAvatar->AddMesh(ANIPART_BIPED, MPART_FACE, strFace.c_str(), strDeco);
|
|
}
|
|
else
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_FACE);
|
|
}
|
|
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_BODY);
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_HAND);
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_FOOT);
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_L_WEAPON);
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_R_WEAPON);
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::LoadMonsterCOBSet(vec_cobset* pSet, KSeqAvatarEx* pSeqAvatar)
|
|
{
|
|
iterator_cobset it = pSet->begin();
|
|
for (it = pSet->begin(); pSet->end() != it; it++)
|
|
{
|
|
COBSET* pCob = *it;
|
|
for (unsigned int j(0); pCob->m_AniList.size() > j; j++)
|
|
{
|
|
//스쳐 지나가는 몹일수도 있으니 디폴트 모션과 뛰는 모션만 바로 로딩
|
|
if (strstr(pCob->m_AniList[j].c_str(), "default") ||
|
|
strstr(pCob->m_AniList[j].c_str(), "run"))
|
|
{
|
|
pSeqAvatar->AddAnimation(pCob->nAniPart, pCob->m_AniList[j].c_str(), true);
|
|
}
|
|
else
|
|
pSeqAvatar->AddAnimation(pCob->nAniPart, pCob->m_AniList[j].c_str(), false);
|
|
}
|
|
|
|
AddMesh(pSeqAvatar, pCob, MPART_HAIR);
|
|
AddMesh(pSeqAvatar, pCob, MPART_HELM);
|
|
AddMesh(pSeqAvatar, pCob, MPART_MANTLE);
|
|
AddMesh(pSeqAvatar, pCob, MPART_FACE);
|
|
AddMesh(pSeqAvatar, pCob, MPART_BODY);
|
|
AddMesh(pSeqAvatar, pCob, MPART_S_SKIRT);
|
|
AddMesh(pSeqAvatar, pCob, MPART_S_SKIRT);
|
|
AddMesh(pSeqAvatar, pCob, MPART_S_SKIRT);
|
|
AddMesh(pSeqAvatar, pCob, MPART_FABRIC);
|
|
AddMesh(pSeqAvatar, pCob, MPART_HAND);
|
|
AddMesh(pSeqAvatar, pCob, MPART_FOOT);
|
|
AddMesh(pSeqAvatar, pCob, MPART_L_WEAPON);
|
|
AddMesh(pSeqAvatar, pCob, MPART_R_WEAPON);
|
|
AddMesh(pSeqAvatar, pCob, MPART_S_SKIRT);
|
|
}
|
|
}
|
|
void SGameAvatarEx::LoadNpcCOBSet(vec_cobset* pSet, KSeqAvatarEx* pSeqAvatar)
|
|
{
|
|
int nRace = 0;
|
|
|
|
NpcResourceBase* pNPC = GetNpcResourceDB().GetNpcInfo(GetInnContentID());
|
|
if (pNPC)
|
|
nRace = pNPC->race_id;
|
|
|
|
iterator_cobset it = pSet->begin();
|
|
for (it = pSet->begin(); pSet->end() != it; it++)
|
|
{
|
|
COBSET* pCob = *it;
|
|
|
|
for (unsigned int j(0); pCob->m_AniList.size() > j; j++)
|
|
{
|
|
if (strstr(pCob->m_AniList[j].c_str(), "default") || strstr(pCob->m_AniList[j].c_str(), "run"))
|
|
pSeqAvatar->AddAnimation(pCob->nAniPart, pCob->m_AniList[j].c_str(), true);
|
|
else
|
|
pSeqAvatar->AddAnimation(pCob->nAniPart, pCob->m_AniList[j].c_str(), false);
|
|
}
|
|
|
|
if (nRace == 99)
|
|
{
|
|
for (unsigned int j(0); pCob->m_HairList.size() > j; j++)
|
|
{
|
|
if (m_pProperty)
|
|
{
|
|
//std::string strHair = GetDefaultItemDB().GetFileName( GetRace(), GetSex(), GetHair() );
|
|
//pSeqAvatar->AddMesh( ANIPART_BIPED, MPART_HAIR, strHair.c_str() );
|
|
|
|
std::string strHair = GetDefaultItemDB().GetFileName(GetRace(), GetSex(), GetHair());
|
|
int nGroup = GetDefaultItemDB().GetDecoHairGroupID(GetHair());
|
|
std::string strDeco = GetDefaultTextureResourceDB().GetTextureName(nGroup, GetRace(), GetSex());
|
|
pSeqAvatar->AddMesh(ANIPART_BIPED, MPART_HAIR, strHair.c_str(), strDeco);
|
|
}
|
|
else
|
|
AddMesh(pSeqAvatar, pCob, MPART_HAIR);
|
|
}
|
|
|
|
AddMesh(pSeqAvatar, pCob, MPART_HELM);
|
|
AddMesh(pSeqAvatar, pCob, MPART_MANTLE);
|
|
|
|
for (unsigned int j(0); pCob->m_FaceList.size() > j; j++)
|
|
{
|
|
if (m_pProperty)
|
|
{
|
|
std::string strFace = GetDefaultItemDB().GetFileName(GetRace(), GetSex(), GetFace());
|
|
pSeqAvatar->AddMesh(ANIPART_BIPED, MPART_FACE, strFace.c_str());
|
|
}
|
|
else
|
|
AddMesh(pSeqAvatar, pCob, MPART_FACE);
|
|
}
|
|
|
|
AddMesh(pSeqAvatar, pCob, MPART_BODY);
|
|
|
|
AddMesh(pSeqAvatar, pCob, MPART_S_SKIRT);
|
|
AddMesh(pSeqAvatar, pCob, MPART_M_SKIRT);
|
|
AddMesh(pSeqAvatar, pCob, MPART_L_SKIRT);
|
|
AddMesh(pSeqAvatar, pCob, MPART_FABRIC);
|
|
|
|
AddMesh(pSeqAvatar, pCob, MPART_HAND);
|
|
AddMesh(pSeqAvatar, pCob, MPART_FOOT);
|
|
AddMesh(pSeqAvatar, pCob, MPART_L_WEAPON);
|
|
AddMesh(pSeqAvatar, pCob, MPART_R_WEAPON);
|
|
}
|
|
else
|
|
{
|
|
for (unsigned int j(0); pCob->m_HairList.size() > j; j++)
|
|
{
|
|
if (m_pProperty)
|
|
{
|
|
//std::string strHair = GetDefaultItemDB().GetFileName( GetRace(), GetSex(), GetHair() );
|
|
//pSeqAvatar->AddMesh( ANIPART_HAIR, MPART_HAIR, strHair.c_str() );
|
|
|
|
std::string strHair = GetDefaultItemDB().GetFileName(GetRace(), GetSex(), GetHair());
|
|
int nGroup = GetDefaultItemDB().GetDecoHairGroupID(GetHair());
|
|
std::string strDeco = GetDefaultTextureResourceDB().GetTextureName(nGroup, GetRace(), GetSex());
|
|
pSeqAvatar->AddMesh(ANIPART_BIPED, MPART_HAIR, strHair.c_str(), strDeco);
|
|
break;
|
|
}
|
|
else
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_HAIR, true);
|
|
}
|
|
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_HELM, true);
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_MANTLE, true);
|
|
|
|
for (unsigned int j(0); pCob->m_FaceList.size() > j; j++)
|
|
{
|
|
if (m_pProperty)
|
|
{
|
|
std::string strFace = GetDefaultItemDB().GetFileName(GetRace(), GetSex(), GetFace());
|
|
pSeqAvatar->AddMesh(ANIPART_BIPED, MPART_FACE, strFace.c_str());
|
|
break;
|
|
}
|
|
else
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_FACE, true);
|
|
}
|
|
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_BODY, true);
|
|
|
|
AddMesh(pSeqAvatar, pCob, MPART_S_SKIRT);
|
|
AddMesh(pSeqAvatar, pCob, MPART_M_SKIRT);
|
|
AddMesh(pSeqAvatar, pCob, MPART_L_SKIRT);
|
|
AddMesh(pSeqAvatar, pCob, MPART_FABRIC);
|
|
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_HAND, true);
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_FOOT, true);
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_L_WEAPON, true);
|
|
AddCommonMesh(pSeqAvatar, pCob, MPART_R_WEAPON, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::AddMesh(KSeqAvatarEx* pSeqAvatar, COBSET* pCob, int nMeshPart)
|
|
{
|
|
std::vector< std::string >* pMeshList = pCob->GetPartNameList(nMeshPart);
|
|
|
|
if (!pMeshList) return;
|
|
|
|
std::vector< std::string >::iterator iter = pMeshList->begin();
|
|
for (; iter != pMeshList->end(); ++iter)
|
|
pSeqAvatar->AddMesh(pCob->nAniPart, nMeshPart, (*iter).c_str());
|
|
}
|
|
|
|
void SGameAvatarEx::AddCommonMesh(KSeqAvatarEx* pSeqAvatar, COBSET* pCob, int nMeshPart, bool bIsNpc)
|
|
{
|
|
std::vector< std::string >* pMeshList = pCob->GetPartNameList(nMeshPart);
|
|
|
|
if (!pMeshList) return;
|
|
|
|
std::vector< std::string >::iterator iter = pMeshList->begin();
|
|
for (; iter != pMeshList->end(); ++iter)
|
|
{
|
|
if (strstr((*iter).c_str(), "common"))
|
|
{
|
|
pSeqAvatar->AddMesh(pCob->nAniPart, nMeshPart, (*iter).c_str());
|
|
if (bIsNpc) break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::LoadUseAnimation(KSeqAvatarEx* pSeqAvatarEx)
|
|
{
|
|
if (!pSeqAvatarEx) return;
|
|
|
|
DWORD dwStartTime = GetSafeTickCount();
|
|
|
|
bool bIsNpc = false;
|
|
if (GetInnObjType() == TS_ENTER::NPC) bIsNpc = true;
|
|
|
|
// _oprint( "애니메이션 Loading Start\n" );
|
|
|
|
/// 2010.11.30 - prodongi
|
|
std::vector< int >* pAniList = GetMotionSetDB().GetAniClass(GetRace(), GetSex(), m_nThreadAniClass);
|
|
if (pAniList)
|
|
{
|
|
pSeqAvatarEx->ClearAnimation();
|
|
|
|
//타겟 창 Animation은 항상 갖고 있는다.
|
|
{
|
|
//const char * pSex[] = { "n", "f", "m", };
|
|
//const char * pRace[] = { "non", "mob", "npc", "ga", "de", "as", "af", "gi", "am", };
|
|
|
|
if (GetRace() >= GCLAN_NOTHING && GetRace() < GCLAN_MAX &&
|
|
GetSex() >= SEX_NONE && GetSex() < SEX_MAX)
|
|
{
|
|
std::string strAniName, strAniFullName;
|
|
strAniName = pRace[GetRace()];
|
|
strAniName += pSex[GetSex()];
|
|
strAniName += "_una_default01";
|
|
|
|
for (int i(0); ANIPART_MAX > i; i++)
|
|
{
|
|
strAniFullName = strAniName;
|
|
strAniFullName += pPartExt[i];
|
|
pSeqAvatarEx->AddAnimation(i, strAniFullName.c_str(), true);
|
|
}
|
|
}
|
|
}
|
|
|
|
// _oprint( "애니메이션 Loading 01 [ %d ]\n", GetSafeTickCount()-dwStartTime );
|
|
|
|
dwStartTime = GetSafeTickCount();
|
|
int nCnt = 0;
|
|
|
|
/// 2010.11.30 - prodongi
|
|
std::vector< int >::iterator it = pAniList->begin();
|
|
for (; it != pAniList->end(); it++)
|
|
{
|
|
/// 2010.11.30 - prodongi
|
|
const char* pAni = GetCharacterMotionEventDB().getFileName(*it);
|
|
if (strlen(pAni) < 2) continue;
|
|
|
|
//COB Biped Name
|
|
std::string strAniName, strAniFullName;
|
|
CStringUtil::GetEventStrKey(pAni, '_', strAniName);
|
|
|
|
//_oprint( "무기 체인지 [%d] : %s\n", nCnt++, pAni );
|
|
|
|
bool bNowLoad = false;
|
|
|
|
if (strAniName.length() > 0)
|
|
{
|
|
if (bIsNpc)
|
|
{
|
|
if (strstr(strAniName.c_str(), "default")) //|| strstr( strAniName.c_str(), "run" ) ) //나중에 이동 가능 NPC가 추가 된다면 이동/이동불가능 여부 체크후 로딩 판단
|
|
{
|
|
if (strstr(strAniName.c_str(), "ride"))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bNowLoad = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (strstr(strAniName.c_str(), "default") ||
|
|
strstr(strAniName.c_str(), "run"))
|
|
/* strstr( strAniName.c_str(), "attack" )
|
|
strstr( strAniName.c_str(), "cast" )
|
|
strstr( strAniName.c_str(), "damage" )*/
|
|
{
|
|
if (strstr(strAniName.c_str(), "ride") == 0)
|
|
{
|
|
bNowLoad = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i(0); ANIPART_MAX > i; i++)
|
|
{
|
|
strAniFullName = strAniName;
|
|
strAniFullName += pPartExt[i];
|
|
|
|
// _oprint( "무기 체인지 : %s\n", strAniFullName.c_str() );
|
|
|
|
pSeqAvatarEx->AddAnimation(i, strAniFullName.c_str(), bNowLoad);
|
|
}
|
|
}
|
|
}
|
|
|
|
// _oprint( "애니메이션 Loading 02 [ %d ]\n", GetSafeTickCount()-dwStartTime );
|
|
|
|
}
|
|
|
|
// _oprint( "애니메이션 Loading End\n" );
|
|
}
|
|
|
|
void SGameAvatarEx::SetMotionEventHandle(const char* pAni, struct _CHARACTER_MOTION* pMotionInfo, std::vector< Key_EVENT_NEW >& eventlist, KSVEC_KEVENT_RES& svHandleList)
|
|
{
|
|
_KEY_EVENT_RES* keyEvent = new _KEY_EVENT_RES;
|
|
keyEvent->SetKeyCount((int)eventlist.size(), (160 * pMotionInfo->nFrame_Length) / 4.8f);
|
|
keyEvent->SetKey(0, &eventlist[0], (int)eventlist.size());
|
|
keyEvent->SetName(pAni);
|
|
|
|
_KEY_EVENT_RES* pFind = NULL;
|
|
|
|
if (svHandleList.lookup(pAni, pFind))
|
|
{
|
|
assert(0);
|
|
}
|
|
else
|
|
{
|
|
svHandleList.add(pAni, keyEvent);
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::AddEvent(std::vector< Key_EVENT_NEW >& eventlist, int nEventID, int nTiming)
|
|
{
|
|
if (nTiming <= 0) return;
|
|
|
|
Key_EVENT_NEW key;
|
|
key.bUse = false;
|
|
key.time = (160 * nTiming) / 4.8f;
|
|
key.nHandleID = nEventID;
|
|
|
|
eventlist.push_back(key);
|
|
}
|
|
|
|
void SGameAvatarEx::LoadEvent(COBSET* pCob)
|
|
{
|
|
//NPC는 데이타 없음.
|
|
if (GetInnObjType() == TS_ENTER::GAME_NPC) return;
|
|
|
|
if (!pCob) return;
|
|
|
|
if (pCob->nAniPart == ANIPART_BIPED)
|
|
{
|
|
for (unsigned int i(0); pCob->m_AniList.size() > i; i++)
|
|
{
|
|
//뒤에 부분만 잘른다.
|
|
std::string strAni;
|
|
|
|
#if defined( _DEBUG )
|
|
std::string strAniKey, strKey;
|
|
CStringUtil::GetEventStrKey(pCob->m_AniList[i].c_str(), '_', strKey);
|
|
CStringUtil::GetStrKey(pCob->m_AniList[i].c_str(), '_', strAniKey);
|
|
#endif
|
|
|
|
CStringUtil::GetEventStrKey(pCob->m_AniList[i].c_str(), '.', strAni);
|
|
|
|
SetEventData(strAni.c_str());
|
|
}
|
|
|
|
if (GetInnObjType() == TS_ENTER::GAME_MOB)
|
|
{
|
|
int nAniSize = (int)pCob->m_AniList.size();
|
|
bool bUseDBDeadMotion = true;
|
|
|
|
for (int i(0); i < nAniSize; ++i)
|
|
{
|
|
if (strstr(pCob->m_AniList[i].c_str(), "una_") && strstr(pCob->m_AniList[i].c_str(), "dead"))
|
|
{
|
|
bUseDBDeadMotion = false; //Cob에 Dead 모션이 포함돼 있다면 패스
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bUseDBDeadMotion) //Cob에 Dead 모션이 없다면
|
|
{
|
|
_MONSTER_INFO_FILE* pMonster = GetMonsterDB().GetMonsterData(GetInnContentID());
|
|
if (pMonster) //DB에서 모션을 찾았다면
|
|
{
|
|
const char* pDeadAni01 = GetMonsterMotionSetDB().GetAni(pMonster->motion_file_id, ANI_DEAD01);
|
|
const char* pDeadAni02 = GetMonsterMotionSetDB().GetAni(pMonster->motion_file_id, ANI_DEAD02);
|
|
|
|
if (pDeadAni01) SetEventData(pDeadAni01);
|
|
if (pDeadAni02) SetEventData(pDeadAni02);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::SetEventData(const char* szAniName)
|
|
{
|
|
_CHARACTER_MOTION* pMotionEvent = GetCharacterMotionEventDB().GetAniEvent(szAniName);
|
|
if (pMotionEvent)
|
|
{
|
|
std::vector< Key_EVENT_NEW > eventlist00_effect;
|
|
std::vector< Key_EVENT_NEW > eventlist00_sound;
|
|
std::vector< Key_EVENT_NEW > eventlist00_motioin_effect;
|
|
|
|
std::vector< Key_EVENT_NEW > eventlist01;
|
|
std::vector< Key_EVENT_NEW > eventlist02;
|
|
std::vector< Key_EVENT_NEW > eventlist03;
|
|
std::vector< Key_EVENT_NEW > eventlist04;
|
|
std::vector< Key_EVENT_NEW > eventlist05;
|
|
std::vector< Key_EVENT_NEW > eventlist06;
|
|
|
|
//Main 이벤트는 예외로 이벤트 핸들을 안 쓰고, 화일을 직접 사용.
|
|
if (pMotionEvent->graphic_effect_file_ID > 0 || pMotionEvent->nGraphic_effect_speed_type == 2)
|
|
{ //시작 하자 마자 무조건 출력
|
|
Key_EVENT_NEW key;
|
|
key.bUse = false;
|
|
key.time = 0;
|
|
key.nHandleID = 0;
|
|
key.nEffPos = pMotionEvent->nGraphic_effect_position;
|
|
key.strEffect = GetResourceDB().GetEffectResourceName(pMotionEvent->graphic_effect_file_ID);
|
|
key.nSpeedType = pMotionEvent->nGraphic_effect_speed_type;
|
|
key.followflag = pMotionEvent->graphic_effect_follow;
|
|
eventlist00_effect.push_back(key);
|
|
}
|
|
|
|
//Main 이벤트는 예외로 이벤트 핸들을 안 쓰고, 화일을 직접 사용.
|
|
if (pMotionEvent->nSound_timing > 0)
|
|
{
|
|
Key_EVENT_NEW key;
|
|
key.bUse = false;
|
|
key.time = (160 * pMotionEvent->nSound_timing) / 4.8f;
|
|
key.nHandleID = 0;
|
|
key.nSoundVolume = pMotionEvent->nSound_volumn;
|
|
key.nSound_play_probability = pMotionEvent->nSound_play_probability;
|
|
key.strSound = GetResourceDB().GetSoundResourceName(pMotionEvent->sound_file_ID);
|
|
key.followflag = 0;
|
|
key.SoundOption[0] = pMotionEvent->sound_reverb_apply == 0 ? false : true;
|
|
key.SoundOption[1] = pMotionEvent->sound_filter_apply == 0 ? false : true;
|
|
key.SoundOption[2] = pMotionEvent->sound_stereo_apply == 0 ? false : true;
|
|
eventlist00_sound.push_back(key);
|
|
}
|
|
|
|
//모션 특정 프레임에 출력될 이펙트
|
|
if (pMotionEvent->fx_id != 0)
|
|
{
|
|
Key_EVENT_NEW key;
|
|
key.bUse = false;
|
|
key.time = (160 * pMotionEvent->fx_timing) / 4.8f;
|
|
key.nHandleID = 0;
|
|
key.nSoundVolume = 100;
|
|
key.nSound_play_probability = 100;
|
|
key.strSound = "";
|
|
key.nFXsetID = pMotionEvent->fx_id;
|
|
key.nEffPos = pMotionEvent->fx_position;
|
|
key.fPlayRate = (float)pMotionEvent->fx_play_speed * 4.8f;
|
|
key.followflag = 0;
|
|
eventlist00_motioin_effect.push_back(key);
|
|
}
|
|
|
|
AddEvent(eventlist01, pMotionEvent->nEvent01_id, pMotionEvent->nEvent01_timing);
|
|
AddEvent(eventlist02, pMotionEvent->nEvent02_id, pMotionEvent->nEvent02_timing);
|
|
AddEvent(eventlist03, pMotionEvent->nEvent03_id, pMotionEvent->nEvent03_timing);
|
|
AddEvent(eventlist04, pMotionEvent->nEvent04_id, pMotionEvent->nEvent04_timing);
|
|
AddEvent(eventlist05, pMotionEvent->nEvent05_id, pMotionEvent->nEvent05_timing);
|
|
AddEvent(eventlist06, pMotionEvent->nEvent06_id, pMotionEvent->nEvent06_timing);
|
|
|
|
if (!eventlist00_effect.empty()) SetMotionEventHandle(szAniName, pMotionEvent, eventlist00_effect, m_svEventHandle00_effectList);
|
|
if (!eventlist00_sound.empty()) SetMotionEventHandle(szAniName, pMotionEvent, eventlist00_sound, m_svEventHandle00_soundList);
|
|
if (!eventlist00_motioin_effect.empty()) SetMotionEventHandle(szAniName, pMotionEvent, eventlist00_motioin_effect, m_svEventHandle00_motion_effect);
|
|
if (!eventlist01.empty()) SetMotionEventHandle(szAniName, pMotionEvent, eventlist01, m_svEventHandle01_List);
|
|
if (!eventlist02.empty()) SetMotionEventHandle(szAniName, pMotionEvent, eventlist02, m_svEventHandle02_List);
|
|
if (!eventlist03.empty()) SetMotionEventHandle(szAniName, pMotionEvent, eventlist03, m_svEventHandle03_List);
|
|
if (!eventlist04.empty()) SetMotionEventHandle(szAniName, pMotionEvent, eventlist04, m_svEventHandle04_List);
|
|
if (!eventlist05.empty()) SetMotionEventHandle(szAniName, pMotionEvent, eventlist05, m_svEventHandle05_List);
|
|
if (!eventlist06.empty()) SetMotionEventHandle(szAniName, pMotionEvent, eventlist06, m_svEventHandle06_List);
|
|
|
|
eventlist00_effect.clear();
|
|
eventlist00_sound.clear();
|
|
eventlist00_motioin_effect.clear();
|
|
|
|
eventlist01.clear();
|
|
eventlist02.clear();
|
|
eventlist03.clear();
|
|
eventlist04.clear();
|
|
eventlist05.clear();
|
|
eventlist06.clear();
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::AllWorkEnd()
|
|
{
|
|
std::vector< SGameWork* >::iterator it;
|
|
//일반
|
|
if (!m_vWorkList.empty())
|
|
{
|
|
it = m_vWorkList.begin();
|
|
(*it)->SetEnd(TRUE);
|
|
}
|
|
//공격 이벤트
|
|
if (!m_vAttackEventList.empty())
|
|
{
|
|
it = m_vAttackEventList.begin();
|
|
(*it)->SetEnd(TRUE);
|
|
}
|
|
//스킬 이벤트
|
|
if (!m_vSkillEventList.empty())
|
|
{
|
|
it = m_vSkillEventList.begin();
|
|
(*it)->SetEnd(TRUE);
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::_processEvent(_KEY_EVENT_RES* pEventHandle, DWORD dwAniTime)
|
|
{
|
|
// TODO: Check this later; Performance tweak
|
|
|
|
Key_EVENT_NEW* pKey1 = NULL;
|
|
Key_EVENT_NEW* pKey2 = NULL;
|
|
|
|
pEventHandle->GetData(dwAniTime, pKey1, pKey2);
|
|
|
|
if (pKey1 && pKey1->bUse == false)
|
|
{
|
|
pKey1->bUse = true; //사용.
|
|
|
|
_MOTION_EVENT_HANDER* pEventHandler = GetMotionEventHanderDB().GetScript(pKey1->nHandleID);
|
|
if (pEventHandler == NULL) return;
|
|
|
|
std::string strScript;
|
|
|
|
if (m_bFootsteps && m_sMoveSound)
|
|
{
|
|
switch (pKey1->nHandleID)
|
|
{
|
|
// case SMotionEventHanderDB::EV_HIT : break;//힛팅
|
|
// case SMotionEventHanderDB::EV_SHOOT : break;//슈팅
|
|
case SMotionEventHanderDB::EV_WALK:
|
|
XStringUtil::Format(strScript, "%s( %u )", pEventHandler->szScript, GetArID());
|
|
break;//스텝_걷기
|
|
case SMotionEventHanderDB::EV_RUN:
|
|
XStringUtil::Format(strScript, "%s( %u )", pEventHandler->szScript, GetArID());
|
|
break;//스텝_뛰기
|
|
case SMotionEventHanderDB::EV_MWALK:
|
|
XStringUtil::Format(strScript, "%s( %u )", pEventHandler->szScript, GetArID());
|
|
break;//몬스터스텝_걷기
|
|
case SMotionEventHanderDB::EV_MRUN:
|
|
XStringUtil::Format(strScript, "%s( %u )", pEventHandler->szScript, GetArID());
|
|
break;//몬스터스텝_뛰기
|
|
}
|
|
}
|
|
|
|
if (strScript.empty())
|
|
{
|
|
switch (pKey1->nHandleID)
|
|
{
|
|
case SMotionEventHanderDB::EV_DEAD: XStringUtil::Format(strScript, "%s( %u )", pEventHandler->szScript, GetArID()); break;//캐릭터사망시 땅에부딛힘
|
|
case SMotionEventHanderDB::EV_SWING: XStringUtil::Format(strScript, "%s( %u )", pEventHandler->szScript, GetArID()); break;//무기휘두름(사운드)
|
|
case SMotionEventHanderDB::EV_WEAPON_HIT: XStringUtil::Format(strScript, "%s( %u )", pEventHandler->szScript, GetArID()); break;//무기히트(피격처리)
|
|
case SMotionEventHanderDB::EV_SCREAM: XStringUtil::Format(strScript, "%s( %u )", pEventHandler->szScript, GetArID()); break;//맞을때비명(랜덤처리)
|
|
}
|
|
}
|
|
|
|
if (strScript.length())
|
|
{
|
|
LUA()->RunString(strScript.c_str());
|
|
// _oprint( "스크립트 출력 : %s\n", pEventHandler->szScript );
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::_processDef()
|
|
{
|
|
for (unsigned int i(0); m_vAttackEventList.size() > i; i++)
|
|
m_vAttackEventList[i]->Process(m_dwTime);
|
|
|
|
for (unsigned int i(0); m_vWorkList.size() > i; i++)
|
|
m_vWorkList[i]->Process(m_dwTime);
|
|
|
|
for (unsigned int i(0); m_vSkillEventList.size() > i; i++)
|
|
m_vSkillEventList[i]->Process(m_dwTime);
|
|
|
|
//공격 이벤트 지우기~
|
|
if (!m_vAttackEventList.empty())
|
|
CheckWorkDel(m_vAttackEventList);
|
|
|
|
//스킬 이벤트 지우기~
|
|
//Work
|
|
if (!m_vSkillEventList.empty())
|
|
CheckWorkDel(m_vSkillEventList);
|
|
|
|
//Work
|
|
if (!m_vWorkList.empty())
|
|
CheckWorkDel(m_vWorkList);
|
|
|
|
if (!IsStateRide())
|
|
{
|
|
AvatarRotationProcess(m_dwTime);
|
|
|
|
K3DVector pos;
|
|
/// local에 따라서 나눈 이유는 항상 getMyPos()를 써도 되는지 확실하지 않기 때문이다.
|
|
if (IsLocalPlayer() || IsLocalCreature())
|
|
{
|
|
if (isKMoving())
|
|
pos = getMyPos();
|
|
else
|
|
pos = GetCurPosWithChangeDir();
|
|
}
|
|
else
|
|
{
|
|
pos = GetCurPosWithChangeDir();
|
|
}
|
|
|
|
if (m_vCheckPos.x != pos.x || m_vCheckPos.y != pos.y)
|
|
{
|
|
GetHeight(pos.x, pos.y, pos.z, m_wCurTile);
|
|
PlayerInsideWaterExistence(pos, m_bInWater);
|
|
m_vCheckPos = pos;
|
|
}
|
|
SetPosition(m_vCheckPos);
|
|
}
|
|
|
|
//Ani 처리
|
|
if (m_pSeqAvatar && m_bIsInit)
|
|
{
|
|
m_nProcess_state = m_pSeqAvatar->Process(m_dwTime);
|
|
|
|
//아바타 감추었을때, 위치는 갱신 한다.
|
|
if (m_pSeqAvatar && !m_xRenderFlag.IsOn(AV_BASIC))
|
|
{
|
|
m_pSeqAvatar->SetTransform(*GetTransform());
|
|
}
|
|
|
|
//마지막 꺼에서, 재 초기화
|
|
if (m_nProcess_state == KSeqAvatar::SEQINFO_LOOPWRAP)
|
|
{
|
|
SetEventHandleInit();
|
|
}
|
|
}
|
|
|
|
DWORD dwAniTime = GetAniTime();
|
|
|
|
if (m_pCurEventHandle00_effect)
|
|
{
|
|
Key_EVENT_NEW* pKey1 = NULL;
|
|
Key_EVENT_NEW* pKey2 = NULL;
|
|
|
|
m_pCurEventHandle00_effect->GetData(dwAniTime, pKey1, pKey2);
|
|
|
|
if (pKey1 && pKey1->bUse == false)
|
|
{
|
|
FindMotionAddOnFx();
|
|
|
|
if (pKey1->nSpeedType == 0)
|
|
{
|
|
pKey1->bUse = true; //사용.
|
|
//방향성 다시 잡아야 함.
|
|
AddEffect(&FX_DATA_EX(pKey1->strEffect.c_str(), pKey1->followflag, GetArID(), GetArID(), GetArID(), pKey1->nEffPos, false, 0, m_fCurPlayRate));
|
|
}
|
|
else if (pKey1->nSpeedType == 2)
|
|
{
|
|
pKey1->bUse = true; //사용.
|
|
//방향성 다시 잡아야 함.
|
|
if (!pKey1->strEffect.empty())
|
|
AddEffect(&FX_DATA_EX(pKey1->strEffect.c_str(), pKey1->followflag, GetArID(), GetArID(), GetArID(), pKey1->nEffPos, false, 0, m_fCurPlayRate));
|
|
|
|
ActivateFxSwordSlashForSkill();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_pCurEventHandle00_sound)
|
|
{
|
|
Key_EVENT_NEW* pKey1 = NULL;
|
|
Key_EVENT_NEW* pKey2 = NULL;
|
|
|
|
m_pCurEventHandle00_sound->GetData(dwAniTime, pKey1, pKey2);
|
|
|
|
if (pKey1 && pKey1->bUse == false)
|
|
{
|
|
pKey1->bUse = true; //사용.
|
|
if (pKey1->nSound_play_probability != 100)
|
|
{
|
|
int nRatio = rand() % 100;
|
|
if (nRatio < pKey1->nSound_play_probability)
|
|
StartSound(this, pKey1->strSound.c_str(), *GetPosition(), true, pKey1->nSoundVolume, false, pKey1->SoundOption);
|
|
}
|
|
else
|
|
{
|
|
StartSound(this, pKey1->strSound.c_str(), *GetPosition(), true, pKey1->nSoundVolume, false, pKey1->SoundOption);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_pCurEventHandle00_motion_effect)
|
|
{
|
|
Key_EVENT_NEW* pKey1 = NULL;
|
|
Key_EVENT_NEW* pKey2 = NULL;
|
|
|
|
m_pCurEventHandle00_motion_effect->GetData(dwAniTime, pKey1, pKey2);
|
|
|
|
if (pKey1 && pKey1->bUse == false)
|
|
{
|
|
pKey1->bUse = true; //사용.
|
|
|
|
FX_DATA fxdata;
|
|
fxdata.nFX_ID = pKey1->nFXsetID;
|
|
fxdata.nEffPos = pKey1->nEffPos;
|
|
fxdata.owner = GetArID();
|
|
fxdata.attack = GetArID();
|
|
fxdata.target = GetArID();
|
|
fxdata.fPlayRate = pKey1->fPlayRate;
|
|
fxdata.nPlayID = 0;//한번
|
|
fxdata.nMode = 0;//기본
|
|
fxdata.bDir = false;
|
|
|
|
AddEffect(&fxdata);
|
|
}
|
|
}
|
|
|
|
if (m_pCurEventHandle01) _processEvent(m_pCurEventHandle01, dwAniTime);
|
|
if (m_pCurEventHandle02) _processEvent(m_pCurEventHandle02, dwAniTime);
|
|
if (m_pCurEventHandle03) _processEvent(m_pCurEventHandle03, dwAniTime);
|
|
if (m_pCurEventHandle04) _processEvent(m_pCurEventHandle04, dwAniTime);
|
|
if (m_pCurEventHandle05) _processEvent(m_pCurEventHandle05, dwAniTime);
|
|
if (m_pCurEventHandle06) _processEvent(m_pCurEventHandle06, dwAniTime);
|
|
|
|
//Sound
|
|
// if( m_pCurSoundKeyEx )
|
|
// {
|
|
//
|
|
// Key_EVENT_EX * pKey1 = NULL;
|
|
// Key_EVENT_EX * pKey2 = NULL;
|
|
//
|
|
// m_pCurSoundKeyEx->GetData( dwAniTime, pKey1, pKey2 );
|
|
//
|
|
// if( pKey1 && pKey1->bUse == false )
|
|
// {
|
|
// pKey1->bUse = true; //사용.
|
|
//
|
|
// K3DVector pos = *K3DMatrixGetPosVector( *GetTransform() );
|
|
//
|
|
// //if( IsLocalPlayer() )
|
|
// //_oprint( "Ani Time : %d\n %s\n", dwAniTime, pKey1->strScriptFunc.c_str() );
|
|
//
|
|
// std::string strExec;
|
|
// //strTmp = pKey1->strScriptFunc.c_str();
|
|
// //str_replace( strTmp, "%d", "%u" );
|
|
//
|
|
// XStringUtil::Format( strExec, pKey1->strScriptFunc.c_str(), 0, GetArID(), GetArID() );
|
|
//
|
|
// LUA()->RunString( strExec.c_str() );
|
|
// }
|
|
// }
|
|
|
|
//Effect
|
|
// if( m_pCurEventKeyEx )
|
|
// {
|
|
//
|
|
// Key_EVENT_EX * pKey1 = NULL;
|
|
// Key_EVENT_EX * pKey2 = NULL;
|
|
//
|
|
// m_pCurEventKeyEx->GetData( dwAniTime, pKey1, pKey2 );
|
|
//
|
|
// if( pKey1 && pKey1->bUse == false )
|
|
// {
|
|
// pKey1->bUse = true; //사용.
|
|
// std::string strExec;
|
|
// //strTmp = pKey1->strScriptFunc.c_str();
|
|
// //str_replace( strTmp, "%d", "%u" );
|
|
//
|
|
// XStringUtil::Format( strExec, pKey1->strScriptFunc.c_str(), GetArID(), GetArID(), m_fCurPlayRate/4.8f );
|
|
//
|
|
// LUA()->RunString( strExec.c_str() );
|
|
// }
|
|
// }
|
|
|
|
m_pAddOnMgr->Process(m_dwTime);
|
|
}
|
|
|
|
int SGameAvatarEx::CheckWorkDel(std::vector< SGameWork* >& worklist)
|
|
{
|
|
int nDelCnt = 0;
|
|
std::vector< SGameWork* >::iterator it = worklist.begin();
|
|
while (it != worklist.end())
|
|
{
|
|
// (*it)->Process( m_dwTime );
|
|
if ((*it)->IsEnd())
|
|
{
|
|
delete (*it);
|
|
it = worklist.erase(it);
|
|
nDelCnt++;
|
|
}
|
|
else
|
|
it++;
|
|
}
|
|
|
|
return nDelCnt;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//프로세스
|
|
void SGameAvatarEx::AvatarRotationProcess(DWORD time)
|
|
{
|
|
float roll, prevroll;
|
|
roll = fmod(m_fTargetRoll, 3.1415926f * 2);
|
|
prevroll = fmod(m_fPresentRoll, 3.1415926f * 2);
|
|
|
|
const float unitval = 3.1415926f / 12 * (time - m_dwPrevTime) / 66.f;
|
|
|
|
if (fabs(roll - prevroll) > fabs(roll - prevroll - 3.1415926f * 2))
|
|
prevroll += 3.1415926f * 2;
|
|
else if (fabs(roll - prevroll) > fabs(roll - prevroll + 3.1415926f * 2))
|
|
prevroll -= 3.1415926f * 2;
|
|
|
|
float minval = min(fabs(roll - prevroll), min(fabs(roll - prevroll + 3.1415926f * 2), fabs(roll - prevroll - 3.1415926f * 2)));
|
|
|
|
if ((roll > prevroll) && (minval > unitval))
|
|
m_fPresentRoll += unitval;
|
|
else if (roll > prevroll)
|
|
m_fPresentRoll = m_fTargetRoll;
|
|
|
|
if ((roll < prevroll) && (minval > unitval))
|
|
m_fPresentRoll -= unitval;
|
|
else if (roll < prevroll)
|
|
m_fPresentRoll = m_fTargetRoll;
|
|
|
|
if (m_bActivateTerrainDegree)
|
|
{
|
|
if (m_pTerrainDegree->CheckPrevAngle() || m_bUseRot || m_syncCamRoll)
|
|
{
|
|
m_pTerrainDegree->CalcCurrentAngle(time);
|
|
|
|
K3DMatrix matWorld, matZ;
|
|
m_vView = K3DVector(0.0f, 1.0f, 0.0f);
|
|
K3DMatrixRotationZ(matZ, m_fPresentRoll + 3.1415926f / 2);
|
|
K3DVectorTransform(m_vView, m_vView, matZ);
|
|
|
|
K3DMatrixRotationYawPitchRoll(matWorld, (m_pTerrainDegree->GetCurrentAngleX() - 3.1415926f / 2),
|
|
(m_pTerrainDegree->GetCurrentAngleY() - 3.1415926f / 2),
|
|
m_fPresentRoll + 3.1415926f / 2);
|
|
|
|
matWorld._41 = GetTransform()->_41;
|
|
matWorld._42 = GetTransform()->_42;
|
|
matWorld._43 = GetTransform()->_43;
|
|
|
|
SetTransform(matWorld);
|
|
if (sMathUtil::isEqual(m_fPresentRoll, m_fTargetRoll))
|
|
{
|
|
m_bUseRot = false;
|
|
m_syncCamRoll = false;
|
|
}
|
|
}
|
|
|
|
K3DVector vPos;
|
|
if (IsLocalPlayer() || IsLocalCreature()) vPos = getMyPos();
|
|
else vPos = GetCurPosWithChangeDir();
|
|
|
|
if (m_vCheckPos.x != vPos.x || m_vCheckPos.y != vPos.y)
|
|
{
|
|
K3DVector v1, v2, v3;
|
|
GetTerrainTriangle(vPos.x, vPos.y, v1, v2, v3);
|
|
|
|
v1 = v2 - v1;
|
|
v2 = v3 - v2;
|
|
m_vTerrainNormal = CrossProduct(v2, v1);
|
|
Normalize(m_vTerrainNormal);
|
|
|
|
K3DMatrix matZ;
|
|
K3DVector vView = K3DVector(0.0f, 1.0f, 0.0f);
|
|
K3DMatrixRotationZ(matZ, m_fTargetRoll + 3.1415926f / 2);
|
|
K3DVectorTransform(vView, vView, matZ);
|
|
|
|
// K3DVector vCross = CrossProduct(m_vTerrainNormal, -vView);
|
|
// if( fabsf(vCross.z) < 0.4f )
|
|
m_pTerrainDegree->CalcTerrainDegree(m_vTerrainNormal, time);
|
|
// else
|
|
// m_pTerrainDegree->Reset( time );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_bUseRot || m_syncCamRoll)
|
|
{
|
|
K3DMatrix zRollMat;
|
|
K3DMatrixIdentity(zRollMat);
|
|
|
|
K3DMatrixRotationZ(zRollMat, m_fPresentRoll + 3.1415926f / 2);
|
|
m_vView = K3DVector(0.0f, 1.0f, 0.0f);
|
|
K3DVectorTransform(m_vView, m_vView, zRollMat);
|
|
|
|
zRollMat._41 = GetTransform()->_41;
|
|
zRollMat._42 = GetTransform()->_42;
|
|
zRollMat._43 = GetTransform()->_43;
|
|
|
|
SetTransform(zRollMat);
|
|
|
|
if (sMathUtil::isEqual(m_fPresentRoll, m_fTargetRoll))
|
|
{
|
|
m_bUseRot = false;
|
|
m_syncCamRoll = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_vTempView = -m_vView;
|
|
}
|
|
|
|
bool SGameAvatarEx::Process(DWORD time, unsigned long uProcessBitVector)
|
|
{
|
|
if (!m_vWearList_Thread.empty() && !IsThreadLoading())
|
|
{
|
|
m_vWearListForRefresh.clear();
|
|
|
|
//쓰레드 로딩 데이타
|
|
for (unsigned int i(0); m_vWearList_Thread.size() > i; ++i)
|
|
{
|
|
m_vWearList.push_back(m_vWearList_Thread[i]);
|
|
m_vWearListForRefresh.push_back(m_vWearList_Thread[i]);
|
|
}
|
|
|
|
m_vWearList_Thread.clear();
|
|
|
|
//쓰레드 로딩
|
|
PendLoading();
|
|
}
|
|
// 2010.04.22 - prodongi
|
|
else
|
|
procHairThreadData();
|
|
|
|
|
|
//Load 검사?
|
|
if (!m_bIsActivated || !m_bIsInit) return false;
|
|
|
|
//시간 처리
|
|
DWORD dwLastTime = m_dwTime;
|
|
|
|
m_dwTime = time;
|
|
|
|
|
|
// 검광 record
|
|
// if (IsLocalPlayer()) {
|
|
if (GetInnObjType() == TS_ENTER::GAME_PLAYER)
|
|
{
|
|
bool bCheck = false;
|
|
while (true)
|
|
{
|
|
if (m_pWeaponTrailRight)
|
|
bCheck = m_pWeaponTrailRight->IsRunTrail();
|
|
if (bCheck) break;
|
|
|
|
if (m_pWeaponTrailLeft)
|
|
bCheck = m_pWeaponTrailLeft->IsRunTrail();
|
|
|
|
break;
|
|
}
|
|
|
|
if (bCheck && m_pBoneRecorder)
|
|
m_pBoneRecorder->record(dwLastTime + 1, time);
|
|
|
|
if (m_bActRightSwordSlashForSkill || m_bActLeftSwordSlashForSkill)
|
|
{
|
|
if (m_nSwordSlashForSkillMotion != GetCurrAnimationID())
|
|
{
|
|
if (m_pRightSwordSlashForSkill)
|
|
m_pRightSwordSlashForSkill->runTrail(false);
|
|
|
|
if (m_pLeftSwordSlashForSkill)
|
|
m_pLeftSwordSlashForSkill->runTrail(false);
|
|
|
|
m_nSwordSlashForSkillMotion = GetCurrAnimationID();
|
|
}
|
|
|
|
bool bRight = false;
|
|
if (m_pRightSwordSlashForSkill)
|
|
bRight = m_pRightSwordSlashForSkill->IsRunTrail();
|
|
bool bLeft = false;
|
|
if (m_pLeftSwordSlashForSkill)
|
|
bLeft = m_pLeftSwordSlashForSkill->IsRunTrail();
|
|
|
|
if (bRight || bLeft)
|
|
{
|
|
if (!bCheck && m_pBoneRecorder)
|
|
m_pBoneRecorder->record(dwLastTime + 1, time);
|
|
}
|
|
else
|
|
{
|
|
DeActivateFxSwordSlashForSkill();
|
|
}
|
|
}
|
|
}
|
|
|
|
_processDef();
|
|
|
|
if (!isKMoving() && !IsMoving())
|
|
{
|
|
if (GetCurrAnimationID() == ANI_RUN ||
|
|
GetCurrAnimationID() == ANI_WALK)
|
|
{
|
|
Default();
|
|
}
|
|
else if (CurrentlyAnimationIsMRun() || CurrentlyAnimationIsMWalk()) // sonador #2.1.6
|
|
{
|
|
if (GetInnObjType() == TS_ENTER::GAME_PLAYER && IsMountMode())
|
|
{
|
|
if (!m_bLocal) Default();
|
|
}
|
|
}
|
|
|
|
//스킬 사용 중이 아니면.
|
|
if (!IsUsingSkill() && !IsPlaying())
|
|
{
|
|
if (CurrentlyAnimationIsAttack() && GetObjType() != TS_ENTER::GAME_PLAYER)
|
|
Default();
|
|
}
|
|
|
|
if (CurrentlyAnimationIsDamage() && !IsPlaying())
|
|
Default();
|
|
}
|
|
|
|
StateProcess(time);
|
|
return true;
|
|
}
|
|
|
|
|
|
void SGameAvatarEx::StateProcess(DWORD dwTime)
|
|
{
|
|
if (m_dwTime < m_dwCheckTime + 1000) return;
|
|
m_dwCheckTime = m_dwTime;
|
|
|
|
|
|
int bLocalUpdate = FALSE;
|
|
SGameLocalPlayer* localPlayer = dynamicCast<SGameLocalPlayer*>(g_pCurrentGameSystem->GetLocalPlayer());
|
|
SStateSlot* pState(NULL);
|
|
|
|
//iterator_state_slot PositiveIt = m_vecPositiveList.begin();
|
|
//iterator_state_slot NegativeIt = m_vecNegativeList.begin();
|
|
if (m_vecPositiveList.empty() && m_vecNegativeList.empty() && m_vecCashStateList.empty() && m_vecMarkStateList.empty())
|
|
return;
|
|
|
|
for (int i = 0; i < m_vecCashStateList.size(); i++)
|
|
{
|
|
m_vecCashStateList[i]->Process(dwTime);
|
|
}
|
|
|
|
/// 2011.01.14 - prodongi
|
|
for (int i = 0; i < m_vecMarkStateList.size(); i++)
|
|
{
|
|
pState = m_vecMarkStateList[i];
|
|
pState->Process(dwTime);
|
|
if (IsLocalPlayer())
|
|
{
|
|
if (dwTime > pState->GetBeginTime() + pState->GetMaxTime()) bLocalUpdate = TRUE;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < m_vecPositiveList.size(); i++)
|
|
{
|
|
pState = m_vecPositiveList[i];
|
|
if (!pState->IsToggleSkill())
|
|
{
|
|
pState->Process(dwTime);
|
|
if (IsLocalPlayer())
|
|
{
|
|
if (dwTime > pState->GetBeginTime() + pState->GetMaxTime()) bLocalUpdate = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < m_vecNegativeList.size(); i++)
|
|
{
|
|
pState = m_vecNegativeList[i];
|
|
if (!pState->IsToggleSkill())
|
|
{
|
|
pState->Process(dwTime);
|
|
if (IsLocalPlayer())
|
|
{
|
|
if (dwTime > pState->GetBeginTime() + pState->GetMaxTime()) bLocalUpdate = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*while(true)
|
|
{
|
|
if( PositiveIt == m_vecPositiveList.end() && NegativeIt == m_vecNegativeList.end() )
|
|
break;
|
|
if( PositiveIt != m_vecPositiveList.end() )
|
|
{
|
|
pState = (*PositiveIt);
|
|
if( !pState->IsToggleSkill() )
|
|
{
|
|
pState->Process(dwTime);
|
|
if (IsLocalPlayer() && (dwTime > pState->GetBeginTime()+pState->GetMaxTime() )) bLocalUpdate = TRUE;
|
|
}
|
|
++PositiveIt;
|
|
}
|
|
|
|
if( NegativeIt != m_vecNegativeList.end() )
|
|
{
|
|
pState = (*NegativeIt);
|
|
if( !pState->IsToggleSkill() )
|
|
{
|
|
pState->Process(dwTime);
|
|
if (IsLocalPlayer() && (dwTime > pState->GetBeginTime()+pState->GetMaxTime() )) bLocalUpdate = TRUE;
|
|
}
|
|
++NegativeIt;
|
|
}
|
|
}*/
|
|
|
|
if (IsLocalPlayer())
|
|
{
|
|
if ((bLocalUpdate && ((dwTime - localPlayer->m_dwUpdateTime) > 1000)))
|
|
{
|
|
int cur = GetArTime();
|
|
localPlayer->m_dwUpdateTime = dwTime;
|
|
TS_CS_UPDATE msg;
|
|
msg.handle = GetArID();
|
|
msg.ar_time = cur;
|
|
time_t nowtime;
|
|
time(&nowtime);
|
|
msg.rtc = nowtime;
|
|
SendMsg(&msg);
|
|
}
|
|
SendGameInterfaceMsg(&(SIMSG_UI_STATE_UPDATE(SIMSG_TOGGLE_UIWINDOW::UIWINDOW_STATE_H_EFFECT, m_arObject.handle)));
|
|
}
|
|
if (g_pCurrentGameSystem->IsTarget(m_arObject.handle)) SendGameInterfaceMsg(&(SIMSG_UI_STATE_UPDATE(SIMSG_TOGGLE_UIWINDOW::UIWINDOW_TARGET_STATE, m_arObject.handle)));
|
|
if (g_pCurrentGameSystem->IsPartyMember(m_arObject.handle)) SendGameInterfaceMsg(&(SIMSG_UI_STATE_UPDATE(SIMSG_TOGGLE_UIWINDOW::UIWINDOW_PARTY_STATE, m_arObject.handle)));
|
|
|
|
|
|
}
|
|
|
|
bool SGameAvatarEx::IsMoving()
|
|
{
|
|
if (m_pArObject)
|
|
{
|
|
return m_pArObject->GetMyPos().IsMoving();
|
|
}
|
|
else
|
|
{
|
|
return GetArObject().mv.IsMoving();
|
|
}
|
|
|
|
assert(0);
|
|
return false;
|
|
}
|
|
|
|
K3DVector& SGameAvatarEx::GetNextPos()
|
|
{
|
|
return m_vNextPos;
|
|
}
|
|
|
|
K3DVector SGameAvatarEx::GetCurPosWithChangeDir()
|
|
{
|
|
K3DVector Cur;
|
|
|
|
if (m_pArObject) //Local Player 임
|
|
{
|
|
Cur = K3DVector(m_pArObject->GetMyPos().x, m_pArObject->GetMyPos().y, 0.f);
|
|
if (m_pArObject->GetMyPos().HasDirectionChanged())
|
|
{
|
|
const ArPosition& cursteppos = m_pArObject->GetMyPos().GetDirection();
|
|
m_vNextPos = K3DVector(cursteppos.x, cursteppos.y, 0.f);
|
|
SetViewVector(m_vNextPos);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Cur = K3DVector(GetArObject().mv.x, GetArObject().mv.y, 0.f);
|
|
if (GetArObject().mv.HasDirectionChanged())
|
|
{
|
|
const ArPosition& cursteppos = GetArObject().mv.GetDirection();
|
|
m_vNextPos = K3DVector(cursteppos.x, cursteppos.y, 0.f);
|
|
SetViewVector(m_vNextPos);
|
|
}
|
|
}
|
|
|
|
return Cur;
|
|
}
|
|
|
|
|
|
unsigned char SGameAvatarEx::getSpeed()
|
|
{
|
|
if (m_pArObject)
|
|
{
|
|
return m_pArObject->GetMyPos().GetSpeed();
|
|
}
|
|
else
|
|
{
|
|
return GetArObject().mv.GetSpeed();
|
|
}
|
|
}
|
|
|
|
unsigned char SGameAvatarEx::getMovingSpeed()
|
|
{
|
|
if (IsMoving())
|
|
{
|
|
return getSpeed();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
K3DVector SGameAvatarEx::getMyPos()
|
|
{
|
|
/// 우선 GetCurPosWithChangeDir를 리턴하고 getMyPos()를 없애야 겠음
|
|
return GetCurPosWithChangeDir();
|
|
/*
|
|
/// m_vNextPos가 플레이어의 방향을 구할 때 쓰이기 때문에 추가함.(미니맵 등의)
|
|
|
|
if( m_pArObject ) //Local Player 임
|
|
{
|
|
if( m_pArObject->GetMyPos().HasDirectionChanged() )
|
|
{
|
|
const ArPosition& cursteppos = m_pArObject->GetMyPos().GetDirection();
|
|
m_vNextPos = K3DVector( cursteppos.x, cursteppos.y, 0.f );
|
|
}
|
|
return K3DVector( m_pArObject->GetMyPos().x, m_pArObject->GetMyPos().y, 0.f );
|
|
}
|
|
else
|
|
{
|
|
if( GetArObject().mv.HasDirectionChanged() )
|
|
{
|
|
const ArPosition& cursteppos = GetArObject().mv.GetDirection();
|
|
m_vNextPos = K3DVector( cursteppos.x, cursteppos.y, 0.f );
|
|
}
|
|
return K3DVector( GetArObject().mv.x, GetArObject().mv.y, 0.f );
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
bool SGameAvatarEx::IsPlaying()
|
|
{
|
|
if (!m_bIsActivated || !m_bIsInit) return false; //참 - -;;
|
|
if (m_pSeqAvatar)
|
|
return m_pSeqAvatar->IsPlaying();
|
|
|
|
return false;
|
|
}
|
|
|
|
void SGameAvatarEx::SetSex(int nSex)
|
|
{
|
|
if (m_pProperty) m_pProperty->Sex = nSex;
|
|
}
|
|
int SGameAvatarEx::GetSex()
|
|
{
|
|
return m_pProperty->Sex;
|
|
}
|
|
|
|
void SGameAvatarEx::SetFaceID(int nFaceID)
|
|
{
|
|
if (m_pProperty) m_pProperty->FaceID = nFaceID;
|
|
}
|
|
|
|
void SGameAvatarEx::SetHairID(int nHairID)
|
|
{
|
|
if (m_pProperty) m_pProperty->HairID = nHairID;
|
|
}
|
|
|
|
int SGameAvatarEx::GetCurrAnimationID()
|
|
{
|
|
return m_nNewCurAniType;
|
|
}
|
|
|
|
//int SGameAvatarEx::GetAnimationType()
|
|
//{
|
|
// return m_nCurAniType;
|
|
//}
|
|
|
|
DWORD SGameAvatarEx::GetAniTime()
|
|
{
|
|
if (m_pSeqAvatar && m_bIsInit)
|
|
return m_pSeqAvatar->GetAniTime();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void SGameAvatarEx::SetAnimationPos(int nPosFlag)
|
|
{
|
|
if (!m_bIsActivated || !m_bIsInit) return;
|
|
|
|
if (m_pSeqAvatar) m_pSeqAvatar->SetAnimationPos(nPosFlag);
|
|
}
|
|
|
|
void SGameAvatarEx::SetRenderFlag(int nRenderIndex)
|
|
{
|
|
if (m_xRenderFlag.IsOn(nRenderIndex))
|
|
m_xRenderFlag.Off(nRenderIndex);
|
|
else
|
|
m_xRenderFlag.On(nRenderIndex);
|
|
}
|
|
|
|
KSeqAvatarEx* SGameAvatarEx::GetSeqForm()
|
|
{
|
|
return m_pSeqAvatar;
|
|
}
|
|
|
|
void SGameAvatarEx::DestroySeqAvatar()
|
|
{
|
|
m_bIsActivated = false;
|
|
SAFE_DELETE(m_pSeqAvatar);
|
|
}
|
|
|
|
void SGameAvatarEx::SetEventHandleInit()
|
|
{
|
|
if (m_pCurEventHandle00_effect) m_pCurEventHandle00_effect->SetInit();
|
|
if (m_pCurEventHandle00_sound) m_pCurEventHandle00_sound->SetInit();
|
|
if (m_pCurEventHandle00_motion_effect) m_pCurEventHandle00_motion_effect->SetInit();
|
|
if (m_pCurEventHandle01) m_pCurEventHandle01->SetInit();
|
|
if (m_pCurEventHandle02) m_pCurEventHandle02->SetInit();
|
|
if (m_pCurEventHandle03) m_pCurEventHandle03->SetInit();
|
|
if (m_pCurEventHandle04) m_pCurEventHandle04->SetInit();
|
|
if (m_pCurEventHandle05) m_pCurEventHandle05->SetInit();
|
|
if (m_pCurEventHandle06) m_pCurEventHandle06->SetInit();
|
|
}
|
|
|
|
void SGameAvatarEx::SetEventHandleNull()
|
|
{
|
|
m_pCurEventHandle00_effect = NULL;
|
|
m_pCurEventHandle00_sound = NULL;
|
|
m_pCurEventHandle00_motion_effect = NULL;
|
|
m_pCurEventHandle01 = NULL;
|
|
m_pCurEventHandle02 = NULL;
|
|
m_pCurEventHandle03 = NULL;
|
|
m_pCurEventHandle04 = NULL;
|
|
m_pCurEventHandle05 = NULL;
|
|
m_pCurEventHandle06 = NULL;
|
|
}
|
|
|
|
void SGameAvatarEx::OnAttack(const SStateInfo& info) //일반 공격
|
|
{
|
|
SetAniLock(false);
|
|
|
|
int nAttackAni = ANI_ATTACK01;
|
|
if (GetInnObjType() == TS_ENTER::GAME_PLAYER)
|
|
{
|
|
if (!info.vAttackInfoList.empty() && (info.vAttackInfoList[0].flag & TS_ATTACK_EVENT::FLAG_CRITICAL))
|
|
{
|
|
if (info.attack_flag & TS_ATTACK_EVENT::ATTACK_FLAG_DOUBLE_ATTACK)
|
|
{
|
|
if (m_nAttackIndex == 0) nAttackAni = ANI_DOUBLE_ATTACK01;
|
|
else if (m_nAttackIndex == 1) nAttackAni = ANI_DOUBLE_ATTACK02;
|
|
else if (m_nAttackIndex == 2) nAttackAni = ANI_DOUBLE_ATTACK03;
|
|
}
|
|
else
|
|
{
|
|
if (m_nAttackIndex == 0) nAttackAni = ANI_CRITICAL_ATTACK01;
|
|
else if (m_nAttackIndex == 1) nAttackAni = ANI_CRITICAL_ATTACK02;
|
|
else if (m_nAttackIndex == 2) nAttackAni = ANI_CRITICAL_ATTACK03;
|
|
}
|
|
|
|
++m_nAttackIndex;
|
|
if (m_nAttackIndex > 2)
|
|
m_nAttackIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
m_nAttackIndex = 0;
|
|
|
|
int nAttackIndex = rand() % 3;
|
|
while (nAttackIndex == m_cPrevAttackIndex)
|
|
{
|
|
nAttackIndex = rand() % 3;
|
|
}
|
|
|
|
m_cPrevAttackIndex = nAttackIndex;
|
|
|
|
if (info.attack_flag & TS_ATTACK_EVENT::ATTACK_FLAG_DOUBLE_ATTACK)
|
|
{
|
|
if (nAttackIndex == 0) nAttackAni = ANI_DOUBLE_ATTACK01;
|
|
else if (nAttackIndex == 1) nAttackAni = ANI_DOUBLE_ATTACK02;
|
|
else if (nAttackIndex == 2) nAttackAni = ANI_DOUBLE_ATTACK03;
|
|
}
|
|
else
|
|
{
|
|
if (nAttackIndex == 0) nAttackAni = ANI_ATTACK01;
|
|
else if (nAttackIndex == 1) nAttackAni = ANI_ATTACK02;
|
|
else if (nAttackIndex == 2) nAttackAni = ANI_ATTACK03;
|
|
}
|
|
}
|
|
}
|
|
|
|
float fAttackPlayRate = Attack(info.hTarget, info.vTargetPos, info.dwSpeed, nAttackAni);
|
|
SetAttackAniLock(true);
|
|
|
|
//타겟 핸들, 현재 이벤트 키, 이벤트 전체 길이, 현재 시간, 공격 스피드
|
|
SWorkAttackEx* pAttackEx = new SWorkAttackEx(this, info.hTarget, fAttackPlayRate);
|
|
pAttackEx->SetEventHandle(m_dwTime, info.dwSpeed,
|
|
m_pCurEventHandle00_effect,
|
|
m_pCurEventHandle00_sound,
|
|
m_pCurEventHandle00_motion_effect,
|
|
m_pCurEventHandle01,
|
|
m_pCurEventHandle02,
|
|
m_pCurEventHandle03,
|
|
m_pCurEventHandle04,
|
|
m_pCurEventHandle05,
|
|
m_pCurEventHandle06);
|
|
|
|
pAttackEx->SetDamegeInfo(&info);
|
|
m_vAttackEventList.push_back(pAttackEx);
|
|
|
|
//공격 이펙트는 나올 필요가 없다.
|
|
SetEventHandleNull();
|
|
}
|
|
|
|
void SGameAvatarEx::OnAttackBow(const SStateInfo& info)//활 공격
|
|
{
|
|
|
|
}
|
|
|
|
bool SGameAvatarEx::IsUsingSkill() //스킬 사용 중 인가?
|
|
{
|
|
if (!m_vCastSkillList.empty())
|
|
return true;
|
|
|
|
if (!m_vFireSkillList.empty())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SGameAvatarEx::IsAttacking() //공격 중인가
|
|
{
|
|
if (!m_vAttackEventList.empty())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SGameAvatarEx::IsAttackingByBow()
|
|
{
|
|
std::vector< class SGameWork* >::iterator iter = m_vCastSkillList.begin();
|
|
for (; iter != m_vCastSkillList.end(); ++iter)
|
|
{
|
|
if ((*iter)->GetWorkType() != SGameWork::WORK_AIMINGBOW)
|
|
return false;
|
|
}
|
|
|
|
iter = m_vFireSkillList.begin();
|
|
for (; iter != m_vFireSkillList.end(); ++iter)
|
|
{
|
|
if ((*iter)->GetWorkType() != SGameWork::WORK_SHOOTINGBOW)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//스킬을 사용 하기 전에 설정 한다.
|
|
//애니 메이션 관리 기능 추가..
|
|
void SGameAvatarEx::StartUseSkill(int nSkillID)
|
|
{
|
|
_SKILL_FX* pSkillFX = GetSkillStageDB().GetSkillStageData(nSkillID);
|
|
|
|
//어떤 모션을 사용한다. 다른 일반 모션은 사용을 금지 한다.
|
|
//PlayAnimation을 직접 사용 금하고, Animation 관리 한다.
|
|
}
|
|
|
|
void SGameAvatarEx::EndUseSkill(int nSkillID)
|
|
{
|
|
|
|
}
|
|
|
|
void SGameAvatarEx::ActivateForceSphere()
|
|
{
|
|
m_pAddOnMgr->RemoveAddOn(SGameAvatarAddOnMgr::SGAME_FORCE_SPHERE_FX);
|
|
|
|
SGameForceSphereFX* pForceSphereFx = new SGameForceSphereFX;
|
|
// pForceSphereFx->SetSphereHeight( GetRace(), GetSex() );
|
|
|
|
switch (GetInnObjType())
|
|
{
|
|
case TS_ENTER::GAME_PLAYER:
|
|
{
|
|
if (GetSex() == SEX_MALE) pForceSphereFx->SetSphereHeight(12.0f);
|
|
else pForceSphereFx->SetSphereHeight(10.0f);
|
|
}
|
|
break;
|
|
case TS_ENTER::GAME_MOB:
|
|
{
|
|
_MONSTER_INFO_FILE* pMonster = GetMonsterDB().GetMonsterData(GetInnContentID());
|
|
if (pMonster)
|
|
{
|
|
pForceSphereFx->SetSphereHeight(pMonster->target_fx_size);
|
|
pForceSphereFx->SetSphereDistance(pMonster->target_fx_size);
|
|
}
|
|
}
|
|
break;
|
|
case TS_ENTER::GAME_SUMMON:
|
|
{
|
|
_SUMMON_INFO_FILE* pSummon = GetCreatureDB().GetCreatureData(GetInnContentID());
|
|
if (pSummon)
|
|
{
|
|
pForceSphereFx->SetSphereHeight(pSummon->target_fx_size);
|
|
pForceSphereFx->SetSphereDistance(pSummon->target_fx_size);
|
|
}
|
|
}
|
|
break;
|
|
case TS_ENTER::GAME_PET: // sonador 10.2.1 팻 시스템 구현
|
|
{
|
|
SPetInfoEx PetInfo = GetPetDB().Find(GetInnContentID());
|
|
pForceSphereFx->SetSphereHeight(PetInfo.getTargetFxSize());
|
|
pForceSphereFx->SetSphereDistance(PetInfo.getTargetFxSize());
|
|
}
|
|
break;
|
|
}
|
|
|
|
m_pAddOnMgr->AddAddOn(pForceSphereFx);
|
|
}
|
|
|
|
void SGameAvatarEx::ActivateCircleShadow()
|
|
{
|
|
m_pAddOnMgr->RemoveAddOn(SGameAvatarAddOnMgr::SGAME_CIRCLE_SHADOW_FX);
|
|
|
|
SGameCircleShadowFX* pCircleShadowFX = new SGameCircleShadowFX;
|
|
m_pAddOnMgr->AddAddOn(pCircleShadowFX);
|
|
}
|
|
void SGameAvatarEx::DeActivateCircleShadow()
|
|
{
|
|
m_pAddOnMgr->RemoveAddOn(SGameAvatarAddOnMgr::SGAME_CIRCLE_SHADOW_FX);
|
|
}
|
|
|
|
void SGameAvatarEx::OnMsgForceSphere(int nForceSphereSize)
|
|
{
|
|
SGameForceSphereFX* pForceSphereFx = (SGameForceSphereFX*)m_pAddOnMgr->GetAddOn(SGameAvatarAddOnMgr::SGAME_FORCE_SPHERE_FX);
|
|
if (!pForceSphereFx) return;
|
|
|
|
int nSize = pForceSphereFx->GetForceSphereSize();
|
|
if (nSize == 0)
|
|
{
|
|
for (int x = 0; x < nForceSphereSize; x++)
|
|
pForceSphereFx->AddForceSphere();
|
|
}
|
|
else if (nForceSphereSize > nSize)
|
|
{
|
|
nSize = nForceSphereSize - nSize;
|
|
for (int x = 0; x < nSize; x++)
|
|
pForceSphereFx->AddForceSphere();
|
|
}
|
|
else
|
|
{
|
|
nSize = nSize - nForceSphereSize;
|
|
for (int x = 0; x < nSize; x++)
|
|
pForceSphereFx->UseForceSphere();
|
|
}
|
|
m_nEnergy = nForceSphereSize;
|
|
}
|
|
|
|
//기공 추가~
|
|
void SGameAvatarEx::AddForceSphere()
|
|
{
|
|
SGameForceSphereFX* pForceSphereFx = (SGameForceSphereFX*)m_pAddOnMgr->GetAddOn(SGameAvatarAddOnMgr::SGAME_FORCE_SPHERE_FX);
|
|
if (!pForceSphereFx) return;
|
|
|
|
pForceSphereFx->AddForceSphere();
|
|
}
|
|
//기공 사용
|
|
void SGameAvatarEx::UseForceSphere()
|
|
{
|
|
SGameForceSphereFX* pForceSphereFx = (SGameForceSphereFX*)m_pAddOnMgr->GetAddOn(SGameAvatarAddOnMgr::SGAME_FORCE_SPHERE_FX);
|
|
if (!pForceSphereFx) return;
|
|
|
|
pForceSphereFx->UseForceSphere();
|
|
}
|
|
|
|
void SGameAvatarEx::EvolutionSummon(SMSG_SUMMON_EVOLUTION* pMsg)
|
|
{
|
|
if (m_pProperty == NULL) return;
|
|
|
|
m_pProperty->ContentID() = pMsg->code;
|
|
m_pProperty->Name = pMsg->name;
|
|
|
|
m_bIsInit = false;
|
|
|
|
DestroySeqAvatar();
|
|
|
|
m_pAddOnMgr->RemoveAddOn(SGameAvatarAddOnMgr::SGAME_AVATAR_FX);
|
|
|
|
Initialize(NULL);
|
|
|
|
Activate();
|
|
}
|
|
|
|
void SGameAvatarEx::SetRiderCreatureInfo(RiderCreatureInfo* pInfo)
|
|
{
|
|
if (pInfo)
|
|
{
|
|
m_RiderCreatureInfo.m_hRider = pInfo->m_hRider;
|
|
m_RiderCreatureInfo.m_nRidePos = pInfo->m_nRidePos;
|
|
m_RiderCreatureInfo.m_nRideType = pInfo->m_nRideType;
|
|
m_RiderCreatureInfo.m_bIsTransportCreature = pInfo->m_bIsTransportCreature;
|
|
}
|
|
else
|
|
{
|
|
m_RiderCreatureInfo.Reset();
|
|
}
|
|
}
|
|
|
|
class KEventPointSeq* SGameAvatarEx::GetSaddleEffectPos()
|
|
{
|
|
if (m_pSeqRideLink) return m_pSeqRideLink;
|
|
|
|
_CID(REQ_EVPOINT);
|
|
KMsgREQ_EVPOINT effect_pos_msg;
|
|
Perform(ANIPART_BIPED, id_REQ_EVPOINT, effect_pos_msg);
|
|
KEventPointSeq* pEv = NULL;
|
|
for (int i(0); effect_pos_msg.GetPointCount() > i; i++)
|
|
{
|
|
pEv = effect_pos_msg.GetPoint(i);
|
|
const char* pName = pEv->GetName();
|
|
if (strlen(pName) && _stricmp(pName, "ep_ride01_main") == 0)
|
|
return m_pSeqRideLink = pEv;
|
|
}
|
|
|
|
// assert( false && "ep_ride01_main 이펙트 포스를 찾을수 없습니다." );
|
|
m_pSeqRideLink = NULL;
|
|
|
|
return m_pSeqRideLink;
|
|
}
|
|
|
|
void SGameAvatarEx::ResetWeaponEVPMatrix(int nAnyPart)
|
|
{
|
|
m_WeaponEnhanceFx[nAnyPart].weardatainfo = false;
|
|
m_bWeaponEVPMatrix[nAnyPart] = false;
|
|
|
|
m_pWeaponEvpSequencer[nAnyPart][EFFECT_POS_WEAPON_EP_START] = NULL;
|
|
m_pWeaponEvpSequencer[nAnyPart][EFFECT_POS_WEAPON_EP_END] = NULL;
|
|
}
|
|
|
|
void SGameAvatarEx::SetWeaponInfo(KSeqAvatarEx* pAvatarEx, WEAR_DATA& WearData, const char* pEventFileName)
|
|
{
|
|
const _OPT_DATA& optData = GetGameOption().GetOptData(); // 게임 옵션 가져오기. mantis 3855이슈 관련 수정. kappamind, 2010.01.11
|
|
|
|
if (WearData.nItemCode == 0)
|
|
{
|
|
if (WearData.nWearType == ItemBase::WEAR_LEFTHAND)
|
|
{
|
|
UnArmed(m_nLeftHandWeaponCode);
|
|
ResetWeaponEVPMatrix(EFFECT_POS_LEFT_WEAPON);
|
|
}
|
|
else if (WearData.nWearType == ItemBase::WEAR_RIGHTHAND)
|
|
{
|
|
UnArmed(m_nTwoHandWeaponCode);
|
|
UnArmed(m_nRightHandWeaponCode);
|
|
|
|
ResetWeaponEVPMatrix(EFFECT_POS_RIGHT_WEAPON);
|
|
ResetWeaponEVPMatrix(EFFECT_POS_TWOHAND_WEAPON);
|
|
}
|
|
return;
|
|
}
|
|
|
|
bool bAttachEnhanceFX = true;
|
|
|
|
if (WearData.nWearType == ItemBase::WEAR_LEFTHAND)
|
|
{
|
|
UnArmed(m_nLeftHandWeaponCode);
|
|
ResetWeaponEVPMatrix(EFFECT_POS_LEFT_WEAPON);
|
|
|
|
if (((WearData.nItemClass != ItemBase::CLASS_SHIELD) && bAttachEnhanceFX)) // 치장 무기가 있고 원래의 무기를 표시안하는 경우에는 강화 효과를 아예 로드 안한다.
|
|
{
|
|
m_WeaponEnhanceFx[EFFECT_POS_LEFT_WEAPON].weardata = WearData;
|
|
m_WeaponEnhanceFx[EFFECT_POS_LEFT_WEAPON].weardatainfo = true;
|
|
|
|
if (pEventFileName)
|
|
m_WeaponEnhanceFx[EFFECT_POS_LEFT_WEAPON].strEventFileName = pEventFileName;
|
|
}
|
|
}
|
|
else if (WearData.nWearType == ItemBase::WEAR_RIGHTHAND)
|
|
{
|
|
UnArmed(m_nTwoHandWeaponCode);
|
|
UnArmed(m_nRightHandWeaponCode);
|
|
|
|
ResetWeaponEVPMatrix(EFFECT_POS_RIGHT_WEAPON);
|
|
ResetWeaponEVPMatrix(EFFECT_POS_TWOHAND_WEAPON);
|
|
|
|
if (WearData.nItemClass == ItemBase::CLASS_TWOHAND_AXE || WearData.nItemClass == ItemBase::CLASS_TWOHAND_MACE ||
|
|
WearData.nItemClass == ItemBase::CLASS_TWOHAND_SPEAR || WearData.nItemClass == ItemBase::CLASS_TWOHAND_STAFF ||
|
|
WearData.nItemClass == ItemBase::CLASS_TWOHAND_SWORD)
|
|
{
|
|
if (bAttachEnhanceFX) // 치장 무기가 있고 원래의 무기를 표시안하는 경우에는 강화 효과를 아예 로드 안한다.
|
|
{
|
|
m_WeaponEnhanceFx[EFFECT_POS_TWOHAND_WEAPON].weardata = WearData;
|
|
m_WeaponEnhanceFx[EFFECT_POS_TWOHAND_WEAPON].weardatainfo = true;
|
|
|
|
if (pEventFileName)
|
|
m_WeaponEnhanceFx[EFFECT_POS_TWOHAND_WEAPON].strEventFileName = pEventFileName;
|
|
}
|
|
}
|
|
else if (WearData.nItemClass == ItemBase::CLASS_LIGHT_BOW || WearData.nItemClass == ItemBase::CLASS_HEAVY_BOW)
|
|
{
|
|
UnArmed(m_nLeftHandWeaponCode);
|
|
ResetWeaponEVPMatrix(EFFECT_POS_LEFT_WEAPON);
|
|
|
|
m_WeaponEnhanceFx[EFFECT_POS_LEFT_WEAPON].weardata = WearData;
|
|
m_WeaponEnhanceFx[EFFECT_POS_LEFT_WEAPON].weardatainfo = true;
|
|
|
|
if (pEventFileName)
|
|
m_WeaponEnhanceFx[EFFECT_POS_LEFT_WEAPON].strEventFileName = pEventFileName;
|
|
}
|
|
else
|
|
{
|
|
if (bAttachEnhanceFX) // 치장 무기가 있고 원래의 무기를 표시안하는 경우에는 강화 효과를 아예 로드 안한다.
|
|
{
|
|
m_WeaponEnhanceFx[EFFECT_POS_RIGHT_WEAPON].weardata = WearData;
|
|
m_WeaponEnhanceFx[EFFECT_POS_RIGHT_WEAPON].weardatainfo = true;
|
|
|
|
if (pEventFileName)
|
|
m_WeaponEnhanceFx[EFFECT_POS_RIGHT_WEAPON].strEventFileName = pEventFileName;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::LoadEnhanceEffect(KSeqAvatarEx* pAvatarEx, WEAPON_ENHANCE_EFFECT* pWeaponEnFx, int nEffectPart)
|
|
{
|
|
if (nEffectPart == EFFECT_POS_LEFT_WEAPON)
|
|
{
|
|
UnArmed(m_nLeftHandWeaponCode);
|
|
Armed(pAvatarEx, m_nLeftHandWeaponCode, ANIPART_WEAPON_LEFT, EFFECT_POS_W_LEFT, pWeaponEnFx, nEffectPart);
|
|
}
|
|
else if (nEffectPart == EFFECT_POS_RIGHT_WEAPON)
|
|
{
|
|
UnArmed(m_nRightHandWeaponCode);
|
|
UnArmed(m_nTwoHandWeaponCode);
|
|
Armed(pAvatarEx, m_nRightHandWeaponCode, ANIPART_WEAPON_RIGHT, EFFECT_POS_W_RIGHT, pWeaponEnFx, nEffectPart);
|
|
}
|
|
else if (nEffectPart == EFFECT_POS_TWOHAND_WEAPON)
|
|
{
|
|
UnArmed(m_nRightHandWeaponCode);
|
|
UnArmed(m_nTwoHandWeaponCode);
|
|
Armed(pAvatarEx, m_nTwoHandWeaponCode, ANIPART_WEAPON_RIGHT, EFFECT_POS_W_TWOHAND, pWeaponEnFx, nEffectPart);
|
|
}
|
|
else
|
|
assert(false && "LoadEnhanceEffect");
|
|
}
|
|
|
|
void SetWeaponColorized(int nIndex, KSeqAvatarEx* pAvatarEx, unsigned int dwColor)
|
|
{
|
|
//DWORD dwColor = 0xFF000000;
|
|
//dwColor = ( DWORD ) b | ( DWORD ) g << 8 | ( DWORD ) r << 16;
|
|
|
|
// dwColor = ( DWORD ) rand()%255 | ( DWORD ) rand()%255 << 8 | ( DWORD ) rand()%255 << 16;
|
|
|
|
_CID(SET_COLORIZE);
|
|
_CID(SET_USE_TEXALPHA);
|
|
KMsgSET_COLORIZE msg;
|
|
msg.color[0] = dwColor;
|
|
msg.color[1] = 0;
|
|
msg.color[2] = 0;
|
|
msg.color[3] = 0;
|
|
msg.nMode = K3DTexture::COLORIZED_USEALPHA;
|
|
|
|
if (pAvatarEx)
|
|
pAvatarEx->Perform(nIndex, id_SET_COLORIZE, msg);
|
|
}
|
|
|
|
namespace
|
|
{
|
|
|
|
static char* s_szVariationPatterns[] =
|
|
{
|
|
"_r",
|
|
"_b",
|
|
NULL
|
|
};
|
|
|
|
std::string RemoveVariationPrefix(const std::string& strFileName)
|
|
{
|
|
std::string strReturn = strFileName;
|
|
std::string strPrefixExt;
|
|
|
|
for (int i = 0; s_szVariationPatterns[i] != NULL; ++i)
|
|
{
|
|
strPrefixExt = std::string(s_szVariationPatterns[i]) + ".nx3";
|
|
|
|
int nPos = strReturn.find(strPrefixExt);
|
|
if (nPos != strReturn.npos)
|
|
{
|
|
strReturn.replace(strReturn.begin() + nPos, strReturn.end(), ".nx3");
|
|
break;
|
|
}
|
|
}
|
|
return strReturn;
|
|
}
|
|
|
|
} // namespace //2011.03.30 - servantes 주석추가
|
|
|
|
|
|
void SGameAvatarEx::Armed(KSeqAvatarEx* pAvatarEx, int* nItemCode, int nAnyPart, int nEffectPos, WEAPON_ENHANCE_EFFECT* pWeaponEnFx, int nWeaponEffectPos)
|
|
{
|
|
WEAR_DATA* pWearData = &pWeaponEnFx->weardata;
|
|
|
|
bool bRefreshWpEffectPos = false;
|
|
if (pAvatarEx)
|
|
{
|
|
pAvatarEx->AddEffectPos(nAnyPart, nEffectPos, pWeaponEnFx->strEventFileName.c_str());
|
|
bRefreshWpEffectPos = RefreshWeaponEffectPos(pAvatarEx, nWeaponEffectPos);
|
|
if (!bRefreshWpEffectPos)
|
|
{
|
|
ResetWeaponEVPMatrix(nWeaponEffectPos);
|
|
pWeaponEnFx->weardatainfo = false;
|
|
}
|
|
}
|
|
|
|
int nEnhanceLevel = GetEnhanceCheatLevel();
|
|
if (nEnhanceLevel == 0)
|
|
nEnhanceLevel = pWearData->nItemEnhanceLevel;
|
|
|
|
if (((nEnhanceLevel <= 0) && (pWearData->cElementalEffect == 0)) || !GetGameOption().IsEnhanceRende())
|
|
{
|
|
if (pWearData->nItemCode != nItemCode[0])
|
|
UnArmed(nItemCode);
|
|
return;
|
|
}
|
|
|
|
if (pWearData->nItemCode != nItemCode[0])
|
|
{
|
|
UnArmed(nItemCode);
|
|
|
|
int wt_width = GetWeaponLength(pWearData->nItemCode);
|
|
int wt_length = 50 + nEnhanceLevel * 10;;
|
|
unsigned int* pcolor = g_pEnhanceColor[0];
|
|
if (nEnhanceLevel > 0 && nEnhanceLevel <= 25) pcolor = g_pEnhanceColor[nEnhanceLevel]; // 강화도에 따른 색상
|
|
|
|
<<<<<<< HEAD
|
|
bool bBowClass = (pWearData->nItemClass == ItemBase::CLASS_LIGHT_BOW) || (pWearData->nItemClass == ItemBase::CLASS_HEAVY_BOW) || (pWearData->nItemClass == ItemBase::CLASS_CROSSBOW); //Double Crossbow
|
|
=======
|
|
// AziaMafia Double Crossbow
|
|
//bool bBowClass = (pWearData->nItemClass == ItemBase::CLASS_LIGHT_BOW) || (pWearData->nItemClass == ItemBase::CLASS_HEAVY_BOW);
|
|
//bool bBowClass = (pWearData->nItemClass == ItemBase::CLASS_LIGHT_BOW) || (pWearData->nItemClass == ItemBase::CLASS_HEAVY_BOW) || (pWearData->nItemClass == ItemBase::CLASS_CROSSBOW );
|
|
|
|
// From ZONE source; dual crossbows
|
|
bool bBowClass = (pWearData->nItemClass == ItemBase::CLASS_LIGHT_BOW) || (pWearData->nItemClass == ItemBase::CLASS_HEAVY_BOW) || (pWearData->nItemClass == ItemBase::CLASS_CROSSBOW);
|
|
>>>>>>> a34328224e914a577b99c79ec6e8ffbcea554a05
|
|
m_bBowClass = bBowClass;
|
|
|
|
if (bBowClass)
|
|
{
|
|
wt_width = 1;
|
|
wt_length = 10;
|
|
}
|
|
|
|
if (nAnyPart == ANIPART_WEAPON_RIGHT || nAnyPart == ANIPART_WEAPON_LEFT)
|
|
{
|
|
//-------------------------------
|
|
//검기
|
|
if (wt_length > 1)
|
|
{
|
|
SGameFxSwordSlash* pFxSword = NULL;
|
|
if (nAnyPart == ANIPART_WEAPON_RIGHT && m_pWeaponTrailRight)
|
|
{
|
|
pFxSword = m_pWeaponTrailRight;
|
|
m_bActRightWeaponTrail = true;
|
|
}
|
|
else if (nAnyPart == ANIPART_WEAPON_LEFT && m_pWeaponTrailLeft)
|
|
{
|
|
pFxSword = m_pWeaponTrailLeft;
|
|
m_bActLeftWeaponTrail = true;
|
|
}
|
|
|
|
if (pFxSword)
|
|
{
|
|
KColor Scolor0(pcolor[0]);
|
|
KColor Scolor1(pcolor[1]);
|
|
KColor Ecolor0(pcolor[2]);
|
|
KColor Ecolor1(pcolor[3]);
|
|
pFxSword->setTrailWidth(wt_width);
|
|
pFxSword->setTrailNodeCount(wt_length);
|
|
pFxSword->setTrailNodeColor(0, 0, Scolor0.color);
|
|
pFxSword->setTrailNodeColor(0, 1, Scolor1.color);
|
|
pFxSword->setTrailNodeColor(1, 0, Ecolor0.color);
|
|
pFxSword->setTrailNodeColor(1, 1, Ecolor1.color);
|
|
if (nEnhanceLevel > 0)
|
|
{
|
|
pFxSword->setTrailTexture("wfxsforce_lv03.dds");
|
|
//pFxSword->setTrailTexture( GetResourceDB().GetTextureResourceName( pEnhanceFx->wt_texture_ID ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2010.09.28 아래에 선언된 내용을 이쪽으로 옮김 - prodongi
|
|
bool bLeftWeapon = (nAnyPart == ANIPART_WEAPON_LEFT);
|
|
bool bRightWeapon = (nAnyPart == ANIPART_WEAPON_RIGHT);
|
|
std::string strColorNx3;
|
|
std::string strAttrNx3;
|
|
|
|
// 2010.09.24 데코 아이템이 무기 대신 출력되는 경우에 데코 이펙트를 출력하게 해준다 - prodongi
|
|
//std::string strColorFile = RemoveVariationPrefix( pWearData->strFileName.c_str() );
|
|
//std::string strAttrFile = RemoveVariationPrefix( pWearData->strFileName.c_str() );
|
|
bool isDecoEffect = false;
|
|
if (pWearData->bWithDecoItem && !pWearData->bAttachDecoItem)
|
|
{
|
|
//if( GetGameOption().GetAvatarDeco() != 0 ) // 2010.10.11. 게임플레이옵션에서 "꾸미기보이기" 제거.
|
|
//{
|
|
if (bRightWeapon || (bLeftWeapon && bBowClass))
|
|
{
|
|
if (isHideEquipInfo(ItemBase::DECO_HIDE_EQUIP_WEAPON))
|
|
isDecoEffect = true;
|
|
}
|
|
else if (bLeftWeapon)
|
|
{
|
|
if (isHideEquipInfo(ItemBase::DECO_HIDE_EQUIP_SHIELD))
|
|
isDecoEffect = true;
|
|
}
|
|
// else는 뭘 해야 되나??
|
|
else
|
|
{
|
|
}
|
|
//}
|
|
}
|
|
|
|
std::string strColorFile, strAttrFile;
|
|
//if (pWearData->bWithDecoItem && !pWearData->bAttachDecoItem)
|
|
if (isDecoEffect)
|
|
{
|
|
strColorFile = RemoveVariationPrefix(pWearData->strDecoFileName.c_str());
|
|
strAttrFile = RemoveVariationPrefix(pWearData->strDecoFileName.c_str());
|
|
}
|
|
else
|
|
{
|
|
strColorFile = RemoveVariationPrefix(pWearData->strFileName.c_str());
|
|
strAttrFile = RemoveVariationPrefix(pWearData->strFileName.c_str());
|
|
}
|
|
|
|
std::string strColorTemp;
|
|
std::string strAttrTemp;
|
|
|
|
strColorNx3 = "rcwfx_";
|
|
strAttrNx3 = "rcwfx_";
|
|
|
|
// 2010.09.28 선언 위치 변경 - prodongi
|
|
/*
|
|
bool bLeftWeapon = (nAnyPart == ANIPART_WEAPON_LEFT );
|
|
bool bRightWeapon = (nAnyPart == ANIPART_WEAPON_RIGHT );
|
|
bool bBowClass = (pWearData->nItemClass == ItemBase::CLASS_LIGHT_BOW) ||
|
|
(pWearData->nItemClass == ItemBase::CLASS_HEAVY_BOW) ||
|
|
(pWearData->nItemClass == ItemBase::CLASS_CROSSBOW );
|
|
*/
|
|
|
|
//if ( pEnhanceFx )
|
|
{
|
|
if (bRightWeapon || (bLeftWeapon && bBowClass))
|
|
{
|
|
//레벨 별
|
|
if (nEnhanceLevel >= 5 && nEnhanceLevel < 10)
|
|
strColorTemp = "_lv05_color.";
|
|
else if (nEnhanceLevel >= 10 && nEnhanceLevel < 15)
|
|
strColorTemp = "_lv10_color.";
|
|
else
|
|
strColorTemp = "_lv15_color.";
|
|
|
|
}
|
|
else if (bLeftWeapon)
|
|
{
|
|
if (nEnhanceLevel >= 5 && nEnhanceLevel < 10)
|
|
strColorTemp = "_L_lv05_color.";
|
|
else if (nEnhanceLevel >= 10 && nEnhanceLevel < 15)
|
|
strColorTemp = "_L_lv10_color.";
|
|
else
|
|
strColorTemp = "_L_lv15_color.";
|
|
}
|
|
}
|
|
|
|
if (bRightWeapon || (bLeftWeapon && bBowClass))
|
|
{
|
|
switch (pWearData->cElementalEffect)
|
|
{
|
|
case 1: strAttrTemp = "_fire."; break; ///Weapon Mystic Jewel //thanks to ink
|
|
case 2: strAttrTemp = "_water."; break; ///Weapon Mystic Jewel //thanks to ink
|
|
case 3: strAttrTemp = "_wind."; break; ///Weapon Mystic Jewel //thanks to ink
|
|
case 4: strAttrTemp = "_earth."; break; ///Weapon Mystic Jewel //thanks to ink
|
|
case 5: strAttrTemp = "_light."; break;
|
|
case 6: strAttrTemp = "_dark."; break;
|
|
case 7: strAttrTemp = "_fire2."; break;
|
|
case 8: strAttrTemp = "_water2."; break;
|
|
case 9: strAttrTemp = "_wind2."; break;
|
|
case 10: strAttrTemp = "_earth2."; break;
|
|
case 11: strAttrTemp = "_light2."; break;
|
|
case 12: strAttrTemp = "_dark2."; break;
|
|
}
|
|
}
|
|
else if (bLeftWeapon)
|
|
{
|
|
switch (pWearData->cElementalEffect)
|
|
{
|
|
case 1: strAttrTemp = "_L_fire."; break;
|
|
case 2: strAttrTemp = "_L_water."; break;
|
|
case 3: strAttrTemp = "_L_wind."; break;
|
|
case 4: strAttrTemp = "_L_earth."; break;
|
|
case 5: strAttrTemp = "_L_light."; break;
|
|
case 6: strAttrTemp = "_L_dark."; break;
|
|
case 7: strAttrTemp = "_L_fire2."; break;
|
|
case 8: strAttrTemp = "_L_water2."; break;
|
|
case 9: strAttrTemp = "_L_wind2."; break;
|
|
case 10: strAttrTemp = "_L_earth2."; break;
|
|
case 11: strAttrTemp = "_L_light2."; break;
|
|
case 12: strAttrTemp = "_L_dark2."; break;
|
|
}
|
|
}
|
|
|
|
// 2011.07.26 - servantes : 가독성 있는 코드로 수정
|
|
// if( strColorFile.length() > 5 ) strColorFile.replace( strColorFile.size() - 4, 1, strColorTemp.c_str() );
|
|
// if( strAttrFile.length() > 5 ) strAttrFile.replace ( strAttrFile.size() - 4 , 1, strAttrTemp.c_str() );
|
|
if (strColorFile.length() > 5)
|
|
{
|
|
if (strColorTemp.length() > 5)
|
|
strColorFile.replace(strColorFile.size() - 4, 1, strColorTemp.c_str());
|
|
}
|
|
if (strAttrFile.length() > 5)
|
|
{
|
|
if (strAttrTemp.length() > 5)
|
|
strAttrFile.replace(strAttrFile.size() - 4, 1, strAttrTemp.c_str());
|
|
}
|
|
|
|
strColorNx3 += strColorFile;
|
|
strAttrNx3 += strAttrFile;
|
|
|
|
//무기 강화 이펙트 화일 붙이자!!!
|
|
if (nAnyPart == ANIPART_WEAPON_RIGHT)
|
|
{
|
|
AddAttachItemPart(ANIPART_WEAPON_RIGHT, ATTACH_HAND_RIGHT_WEAPON01, strColorNx3.c_str());
|
|
AddAttachItemPart(ANIPART_WEAPON_RIGHT, ATTACH_HAND_RIGHT_WEAPON02, strAttrNx3.c_str());
|
|
|
|
//if ( pEnhanceFx )
|
|
SetWeaponColorized(ANIPART_WEAPON_RIGHT, pAvatarEx, pcolor[3]);
|
|
|
|
RefreshDeform();
|
|
}
|
|
else if (nAnyPart == ANIPART_WEAPON_LEFT)
|
|
{
|
|
AddAttachItemPart(ANIPART_WEAPON_LEFT, ATTACH_HAND_LEFT_WEAPON01, strColorNx3.c_str());
|
|
AddAttachItemPart(ANIPART_WEAPON_LEFT, ATTACH_HAND_LEFT_WEAPON02, strAttrNx3.c_str());
|
|
|
|
//if ( pEnhanceFx )
|
|
SetWeaponColorized(ANIPART_WEAPON_LEFT, pAvatarEx, pcolor[3]);
|
|
|
|
RefreshDeform();
|
|
}
|
|
}
|
|
|
|
if (bRefreshWpEffectPos)
|
|
{
|
|
// nItemCode[1] = AddWeaponEnhanceEffect( nWeaponEffectPos, pEnhanceFx, pWearData->nItemClass );
|
|
}
|
|
|
|
if (nItemCode[1] == -1) return;
|
|
|
|
nItemCode[0] = pWearData->nItemCode;
|
|
}
|
|
}
|
|
|
|
|
|
void SGameAvatarEx::UnArmed(int* nItemCode)
|
|
{
|
|
if (nItemCode[1] != -1)
|
|
RemoveEnhanceEffect(nItemCode[1]);
|
|
|
|
if (nItemCode[2] != -1)
|
|
EndLoopFx(nItemCode[2]);
|
|
|
|
nItemCode[0] = -1;
|
|
nItemCode[1] = -1;
|
|
nItemCode[2] = -1;
|
|
}
|
|
|
|
int SGameAvatarEx::AddWeaponEnhanceEffect(int nWeaponEffectPos, EnhanceFX* pEnhanceFx, int nItemClass)
|
|
{
|
|
if (m_bWeaponEVPMatrix[nWeaponEffectPos])
|
|
return AddEnhanceEffect(this, nWeaponEffectPos, pEnhanceFx, nItemClass);
|
|
|
|
_oprint("무기 이벤트 포인트를 찾을수 없습니다.\n");
|
|
// assert( false && "무기 이벤트 포인트를 찾을수 없습니다." );
|
|
|
|
return -1;
|
|
}
|
|
|
|
void SGameAvatarEx::HideWeapon(BOOL bHide)
|
|
{
|
|
if (!m_pSeqAvatar || !m_bIsInit) return;
|
|
|
|
// sonador 7.0.16 Mantis 0002790: [모션] 아바타가 활을 착용하고 오르니토를 탔을 때 모션 문제
|
|
bool bShowWeapon = bHide; // sonador wrong naming
|
|
if (bShowWeapon && IsMountMode()) return;
|
|
|
|
//장착된 무기 숨기기
|
|
m_pSeqAvatar->SetMeshRenderFlag(ANIPART_WEAPON_LEFT, MPART_L_WEAPON, bHide);
|
|
m_pSeqAvatar->SetMeshRenderFlag(ANIPART_WEAPON_RIGHT, MPART_R_WEAPON, bHide);
|
|
|
|
//장착된 치자용 무기 숨기기
|
|
m_pSeqAvatar->SetDecoMeshRenderFlag(ANIPART_WEAPON_LEFT, MDECOPART_L_WEAPON, bHide);
|
|
m_pSeqAvatar->SetDecoMeshRenderFlag(ANIPART_WEAPON_RIGHT, MDECOPART_R_WEAPON, bHide);
|
|
|
|
//장착된 아이템 숨기기
|
|
m_pSeqAvatar->SetItemRenderFlag(ANIPART_BIPED, ATTACH_HAND_LEFT, bHide);
|
|
m_pSeqAvatar->SetItemRenderFlag(ANIPART_BIPED, ATTACH_HAND_RIGHT, bHide);
|
|
m_pSeqAvatar->SetItemRenderFlag(ANIPART_BIPED, ATTACH_HAND_ARM2L, bHide);
|
|
m_pSeqAvatar->SetItemRenderFlag(ANIPART_BIPED, ATTACH_HAND_ARM2R, bHide);
|
|
m_pSeqAvatar->SetItemRenderFlag(ANIPART_BIPED, ATTACH_HAND_ARM2L_DECO, bHide);
|
|
m_pSeqAvatar->SetItemRenderFlag(ANIPART_BIPED, ATTACH_HAND_ARM2R_DECO, bHide);
|
|
m_pSeqAvatar->SetItemRenderFlag(ANIPART_WEAPON_RIGHT, ATTACH_HAND_RIGHT_WEAPON01, bHide); // sonador 7.0.16 Mantis 0002790: [모션] 아바타가 활을 착용하고 오르니토를 탔을 때 모션 문제
|
|
m_pSeqAvatar->SetItemRenderFlag(ANIPART_WEAPON_RIGHT, ATTACH_HAND_RIGHT_WEAPON02, bHide); //
|
|
m_pSeqAvatar->SetItemRenderFlag(ANIPART_WEAPON_LEFT, ATTACH_HAND_LEFT_WEAPON01, bHide); //
|
|
m_pSeqAvatar->SetItemRenderFlag(ANIPART_WEAPON_LEFT, ATTACH_HAND_LEFT_WEAPON02, bHide); //
|
|
|
|
if (bHide)
|
|
{
|
|
bool bAniLock = GetAniLock();
|
|
SetAniLock(false);
|
|
|
|
AttachAnimation(m_pSeqAvatar);
|
|
|
|
m_pSeqAvatar->SetAttach(ANIPART_BIPED);
|
|
|
|
SetAniLock(bAniLock);
|
|
}
|
|
|
|
SetWeaponEnhanceFx(m_nTwoHandWeaponCode, bHide);
|
|
SetWeaponEnhanceFx(m_nRightHandWeaponCode, bHide);
|
|
SetWeaponEnhanceFx(m_nLeftHandWeaponCode, bHide);
|
|
}
|
|
|
|
void SGameAvatarEx::RefreshDeform()
|
|
{
|
|
if (!m_pSeqAvatar || !m_bIsInit) return;
|
|
|
|
bool bAniLock = GetAniLock();
|
|
SetAniLock(false);
|
|
|
|
AttachAnimation(m_pSeqAvatar);
|
|
|
|
for (int nAniPart = 0; nAniPart < ANIPART_MAX; ++nAniPart)
|
|
{
|
|
m_pSeqAvatar->SetDeform(nAniPart);
|
|
m_pSeqAvatar->SetAttach(nAniPart);
|
|
}
|
|
|
|
SetAniLock(bAniLock);
|
|
}
|
|
|
|
void SGameAvatarEx::SetWeaponEnhanceFx(int* nItemCode, bool bHide)
|
|
{
|
|
if (nItemCode[1] != -1)
|
|
{
|
|
SetRenderEnhanceFx(nItemCode[1], bHide);
|
|
}
|
|
}
|
|
|
|
bool SGameAvatarEx::IsMovingDetour()
|
|
{
|
|
size_t numDetourPoints = m_vDetourPath.size();
|
|
|
|
// if(numDetourPoints < 2) return false;
|
|
// if(numDetourPoints > m_unDetourStep + 1) return true;
|
|
|
|
if (numDetourPoints == 0)
|
|
{
|
|
EraseDetour();
|
|
return false;
|
|
}
|
|
|
|
K3DVertex curpos = *GetPosition();
|
|
|
|
if ((int)curpos.x == m_vDetourPath[numDetourPoints - 1].x && (int)curpos.y == m_vDetourPath[numDetourPoints - 1].y)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool SGameAvatarEx::IsChasing()
|
|
{
|
|
return m_bIsChasing;
|
|
}
|
|
|
|
bool SGameAvatarEx::MoveDetour(K3DVertex& vtMovePos)
|
|
{
|
|
size_t numDetourPoints = m_vDetourPath.size();
|
|
// if(numDetourPoints < m_unDetourStep + 2) return false;
|
|
if (numDetourPoints <= m_unDetourStep) return false;
|
|
|
|
bool bRefreshDetour = m_bRefreshDetour;
|
|
m_bRefreshDetour = false;
|
|
|
|
K3DVertex curpos;
|
|
|
|
curpos = *GetPosition();
|
|
|
|
if (bRefreshDetour || ((int)curpos.x == m_vDetourPath[m_unDetourStep].x && (int)curpos.y == m_vDetourPath[m_unDetourStep].y))
|
|
{
|
|
if (numDetourPoints > m_unDetourStep + 1)
|
|
{
|
|
vtMovePos.x = m_vDetourPath[m_unDetourStep + 1].x;
|
|
vtMovePos.y = m_vDetourPath[m_unDetourStep + 1].y;
|
|
vtMovePos.z = 0.0f;
|
|
|
|
++m_unDetourStep;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SGameAvatarEx::CollisionToLine(const K3DVector& vStart, const K3DVector& vEnd)
|
|
{
|
|
return m_pMsgHandler->CollisionToLine(vStart, vEnd);
|
|
}
|
|
|
|
void SGameAvatarEx::FindDetour(const K3DVertex& vEnd, bool bRestraint, bool bChase)
|
|
{
|
|
EraseDetour();
|
|
K3DVertex vStart = *GetPosition();
|
|
m_pMsgHandler->FindDetour(vStart, vEnd, m_vDetourPath, bRestraint, bChase, (GetObjType() == TS_ENTER::PLAYER));
|
|
|
|
m_bIsChasing = bChase;
|
|
m_unDetourStep = 0;
|
|
m_bRefreshDetour = true;
|
|
}
|
|
|
|
void SGameAvatarEx::EraseDetour()
|
|
{
|
|
m_vDetourPath.erase(m_vDetourPath.begin(), m_vDetourPath.end());
|
|
|
|
m_bRefreshDetour = false;
|
|
m_unDetourStep = 0;
|
|
}
|
|
|
|
size_t SGameAvatarEx::GetDetourSize()
|
|
{
|
|
if (m_vDetourPath.empty())
|
|
return 0;
|
|
|
|
return m_vDetourPath.size();
|
|
}
|
|
|
|
bool SGameAvatarEx::GetDetourPoint(size_t index, int& x, int& y)
|
|
{
|
|
size_t numDetourPoints = m_vDetourPath.size();
|
|
if (numDetourPoints <= index) return false;
|
|
|
|
x = m_vDetourPath[index].x;
|
|
y = m_vDetourPath[index].y;
|
|
|
|
return true;
|
|
}
|
|
|
|
ArPosition* SGameAvatarEx::GetAllDetourPoint()
|
|
{
|
|
int numDetourPoints = (int)m_vDetourPath.size();
|
|
if (numDetourPoints <= 1) return NULL;
|
|
|
|
ArPosition* pArPosition = new ArPosition[numDetourPoints];
|
|
for (int x = 1; x < numDetourPoints; x++)
|
|
{
|
|
pArPosition[x - 1].x = m_vDetourPath[x].x;
|
|
pArPosition[x - 1].y = m_vDetourPath[x].y;
|
|
}
|
|
|
|
m_vReqPoint.push_back(pArPosition);
|
|
|
|
return pArPosition;
|
|
}
|
|
|
|
void SGameAvatarEx::DeleteReqPoint()
|
|
{
|
|
for (size_t i(0); m_vReqPoint.size() > i; ++i)
|
|
{
|
|
SAFE_DELETE_ARRAY(m_vReqPoint[i]);
|
|
}
|
|
m_vReqPoint.clear();
|
|
}
|
|
|
|
int SGameAvatarEx::GetAllDetourPointSize()
|
|
{
|
|
int numDetourPoints = (int)m_vDetourPath.size();
|
|
if (numDetourPoints <= 1) return 0;
|
|
|
|
return numDetourPoints - 1;
|
|
}
|
|
|
|
size_t SGameAvatarEx::GetDetourStep()
|
|
{
|
|
return m_unDetourStep;
|
|
}
|
|
|
|
bool SGameAvatarEx::CheckAllState()
|
|
{
|
|
if (IsCasting() || IsAttack() || IsMount() || IsMountMode() || IsMoving() || GetStatus() & TS_ENTER::PlayerInfo::FLAG_SITDOWN)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void SGameAvatarEx::SetUISyncData(UI_SYNC_INFO::TARGET_INFO& target_info)
|
|
{
|
|
if (target_info.nTarget_hp != -1)
|
|
{
|
|
m_pUISyncData->nLast_hp = target_info.nTarget_hp;
|
|
}
|
|
else
|
|
{
|
|
if (m_pUISyncData->nLast_hp == -1)
|
|
m_pUISyncData->nLast_hp = GetHP();
|
|
}
|
|
|
|
if (target_info.nTarget_mp != -1)
|
|
{
|
|
m_pUISyncData->nLast_mp = target_info.nTarget_mp;
|
|
}
|
|
else
|
|
{
|
|
if (m_pUISyncData->nLast_mp == -1)
|
|
m_pUISyncData->nLast_mp = GetMP();
|
|
}
|
|
|
|
++m_pUISyncData->nMessageCnt;
|
|
|
|
}
|
|
void SGameAvatarEx::AddUISyncData(UI_SYNC_INFO& uisyncinfo)
|
|
{
|
|
if (uisyncinfo.nMode == SIMSG_UI_TARGET_STAT::USE_DEF ||
|
|
uisyncinfo.nMode == SIMSG_UI_TARGET_STAT::USE_HPMP ||
|
|
uisyncinfo.nMode == SIMSG_UI_TARGET_STAT::USE_STATE_DMG)
|
|
SetUISyncData(uisyncinfo.CasterInfo);
|
|
|
|
m_pUISyncData->vinfo_list.push_back(uisyncinfo);
|
|
|
|
std::vector< UI_SYNC_INFO::TARGET_INFO >::iterator iter = uisyncinfo.vTargetInfo.begin();
|
|
for (; iter != uisyncinfo.vTargetInfo.end(); )
|
|
{
|
|
SGameAvatarEx* pTarget = (SGameAvatarEx*)GetGameObject((*iter).hTarget);
|
|
if (pTarget)
|
|
{
|
|
pTarget->SetUISyncData((*iter));
|
|
++iter;
|
|
}
|
|
else
|
|
iter = uisyncinfo.vTargetInfo.erase(iter);
|
|
}
|
|
}
|
|
|
|
UI_SYNC_DATA* SGameAvatarEx::GetUISyncData()
|
|
{
|
|
return m_pUISyncData;
|
|
}
|
|
|
|
void SGameAvatarEx::Dead()
|
|
{
|
|
if (GetCurrAnimationID() != ANI_DEAD01)
|
|
{
|
|
EnterDeadAnimation();
|
|
}
|
|
|
|
if (GetObjType() == TS_ENTER::GAME_MOB)
|
|
{
|
|
ItemDrop();
|
|
}
|
|
|
|
//죽으면, 초기화
|
|
m_dwStartTime = 0;
|
|
|
|
//죽으면, 기본 상태
|
|
if (m_pStateVM)
|
|
{
|
|
m_pStateVM->SetMode(SObjectStateMachine::MODE_NORMAL);
|
|
m_pStateVM->Dead();
|
|
}
|
|
|
|
m_bIsDead = true;
|
|
}
|
|
|
|
void SGameAvatarEx::SetTerrainPickPos(K3DVector* vPick)
|
|
{
|
|
m_vTerrainPickPos = *vPick;
|
|
}
|
|
|
|
K3DVector* SGameAvatarEx::GetTerrainPickPos()
|
|
{
|
|
return &m_vTerrainPickPos;
|
|
}
|
|
|
|
const K3DMatrix* SGameAvatarEx::GetEventPointMatrix(int nEffectPos)
|
|
{
|
|
if (nEffectPos < EFFECT_POS_MAX && nEffectPos > -1)
|
|
return &m_matEVPMatrix[nEffectPos];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const K3DMatrix* SGameAvatarEx::GetEventPointAttachMatrix(int nEffectPos)
|
|
{
|
|
if (nEffectPos < EFFECT_POS_MAX && nEffectPos > -1)
|
|
return &m_matEVPAttachMatrix[nEffectPos];
|
|
|
|
return NULL;
|
|
}
|
|
int SGameAvatarEx::GetWeaponLength(int itemCode)
|
|
{
|
|
int wt_width = 10;
|
|
int cls = GetItemDB().GetClassID(itemCode) - ItemBase::CLASS_ONEHAND_SWORD;
|
|
if (cls >= 9) cls--;
|
|
int rank = GetItemDB().GetItemRank(itemCode);
|
|
if (cls >= 0 && cls <= 11 && rank >= 1 && rank <= 7)
|
|
{
|
|
wt_width = g_pWeaponLength[cls][rank];
|
|
}
|
|
return wt_width;
|
|
}
|
|
const K3DMatrix* SGameAvatarEx::GetWeaponEventPointMatrix(int nWeaponEffectPos, int nEventPointPos)
|
|
{
|
|
return &m_matWeaponEVPMatrix[nWeaponEffectPos][nEventPointPos];
|
|
}
|
|
|
|
const K3DMatrix* SGameAvatarEx::GetWeaponEventPointAttachMatrix(int nWeaponEffectPos, int nEventPointPos)
|
|
{
|
|
return &m_matWeaponEVPAttachMatrix[nWeaponEffectPos][nEventPointPos];
|
|
}
|
|
|
|
const K3DMatrix* SGameAvatarEx::GetWeaponEventPointParentMatrix(int nWeaponEffectPos, int nEventPointPos)
|
|
{
|
|
return &m_matWeaponEVPParentMatrix[nWeaponEffectPos][nEventPointPos];
|
|
}
|
|
|
|
bool SGameAvatarEx::GetWeaponEventPoint(int nWeaponEffectPos)
|
|
{
|
|
return m_bWeaponEVPMatrix[nWeaponEffectPos];
|
|
}
|
|
|
|
void SGameAvatarEx::GetCurrentAnimationInfo(int& nBoneCnt, DWORD& dwMinTime, DWORD& dwMaxTime, DWORD& dwCurAniTime)
|
|
{
|
|
if (m_pSeqAvatar && m_bIsInit)
|
|
{
|
|
std::string strAniKeyName = GetAniKey(GetInnObjType(), GetCurrAnimationID(), true);
|
|
m_pSeqAvatar->GetFrameInfo(ANIPART_BIPED, strAniKeyName.c_str(), nBoneCnt, dwMinTime, dwMaxTime);
|
|
dwCurAniTime = m_pSeqAvatar->GetAniTime();
|
|
}
|
|
}
|
|
|
|
bool SGameAvatarEx::RefreshWeaponEffectPos(KSeqAvatarEx* pSeqAvatarEx, int nWeaponEffectPos)
|
|
{
|
|
//무기 이펙트 포스 설정
|
|
pSeqAvatarEx->SetAttachEffectPos(ANIPART_WEAPON_LEFT);
|
|
pSeqAvatarEx->SetAttachEffectPos(ANIPART_WEAPON_RIGHT);
|
|
|
|
_CID(REQ_EVPOINT);
|
|
KMsgREQ_EVPOINT w_effect_pos_msg;
|
|
pSeqAvatarEx->Perform(ANIPART_WEAPON_LEFT, id_REQ_EVPOINT, w_effect_pos_msg);
|
|
pSeqAvatarEx->Perform(ANIPART_WEAPON_RIGHT, id_REQ_EVPOINT, w_effect_pos_msg);
|
|
|
|
m_bWeaponEVPMatrix[nWeaponEffectPos] = false;
|
|
m_pWeaponEvpSequencer[nWeaponEffectPos][EFFECT_POS_WEAPON_EP_START] = NULL;
|
|
m_pWeaponEvpSequencer[nWeaponEffectPos][EFFECT_POS_WEAPON_EP_END] = NULL;
|
|
|
|
if (w_effect_pos_msg.GetPointCount() <= 0) return false;
|
|
|
|
KEventPointSeq* pEv = NULL;
|
|
KEventPointSeq* pEv1 = NULL;
|
|
KEventPointSeq* pEv2 = NULL;
|
|
for (int pos_cnt = 0; w_effect_pos_msg.GetPointCount() > pos_cnt; ++pos_cnt)
|
|
{
|
|
pEv = w_effect_pos_msg.GetPoint(pos_cnt);
|
|
const char* pName = pEv->GetName();
|
|
if (strlen(pName) && _stricmp(pName, pWeaponEpName[nWeaponEffectPos][EFFECT_POS_WEAPON_EP_START]) == 0)
|
|
pEv1 = pEv;
|
|
if (strlen(pName) && _stricmp(pName, pWeaponEpName[nWeaponEffectPos][EFFECT_POS_WEAPON_EP_END]) == 0)
|
|
pEv2 = pEv;
|
|
|
|
if (pEv1 && pEv2)
|
|
{
|
|
m_matWeaponEVPMatrix[nWeaponEffectPos][EFFECT_POS_WEAPON_EP_START] = pEv1->GetPoint();
|
|
m_matWeaponEVPMatrix[nWeaponEffectPos][EFFECT_POS_WEAPON_EP_END] = pEv2->GetPoint();
|
|
|
|
if (pEv1->GetAttachTransform() && pEv2->GetAttachTransform())
|
|
{
|
|
m_bWeaponEVPMatrix[nWeaponEffectPos] = true;
|
|
|
|
m_pWeaponEvpSequencer[nWeaponEffectPos][EFFECT_POS_WEAPON_EP_START] = pEv1;
|
|
m_pWeaponEvpSequencer[nWeaponEffectPos][EFFECT_POS_WEAPON_EP_END] = pEv2;
|
|
|
|
for (int epcnt = 0; epcnt < EFFECT_POS_WEAPON_EP_MAX; ++epcnt)
|
|
{
|
|
K3DMatrixIdentity(m_matWeaponEVPAttachMatrix[nWeaponEffectPos][epcnt]);
|
|
K3DMatrixIdentity(m_matWeaponEVPParentMatrix[nWeaponEffectPos][epcnt]);
|
|
}
|
|
|
|
m_matWeaponEVPAttachMatrix[nWeaponEffectPos][EFFECT_POS_WEAPON_EP_START] = *pEv1->GetAttachTransform();
|
|
m_matWeaponEVPAttachMatrix[nWeaponEffectPos][EFFECT_POS_WEAPON_EP_END] = *pEv2->GetAttachTransform();
|
|
|
|
m_matWeaponEVPParentMatrix[nWeaponEffectPos][EFFECT_POS_WEAPON_EP_START] = *pEv1->GetParentTransform();
|
|
m_matWeaponEVPParentMatrix[nWeaponEffectPos][EFFECT_POS_WEAPON_EP_END] = *pEv2->GetParentTransform();
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return m_bWeaponEVPMatrix[nWeaponEffectPos];
|
|
}
|
|
|
|
|
|
//-------------------------------------
|
|
// Weapon powerup fx
|
|
//-------------------------------------
|
|
|
|
//void SGameAvatarEx::updateWeaponPowerupMesh(int partNo, bool forceUpdateNow) // 나중에 폴리곤 rebuild하도록 flag
|
|
//{
|
|
// if (forceUpdateNow) {
|
|
// // 현재 FX를 다시 세팅한다. (꽁수?)
|
|
// setWeaponPowerupFx(partNo, this->getWeaponPowerupFx(partNo), false);
|
|
// return;
|
|
// }
|
|
//
|
|
// switch (partNo) {
|
|
// case MPART_R_WEAPON: // 오른손 무기
|
|
// if (m_pWeaponPowerupRight!=NULL) m_nUpdatePowerupRight=UPDATE_REBUILD;
|
|
// break;
|
|
//
|
|
// case MPART_L_WEAPON:
|
|
// if (m_pWeaponPowerupLeft!=NULL) m_nUpdatePowerupLeft=UPDATE_REBUILD;
|
|
// break;
|
|
// }
|
|
//}
|
|
|
|
//void SGameAvatarEx::clearWeaponPowerupMesh(int partNo) // 나중에 폴리곤 delete하도록 flag세움
|
|
//{
|
|
// switch (partNo) {
|
|
// case MPART_R_WEAPON: // 오른손 무기
|
|
// if (m_pWeaponPowerupRight!=NULL) m_nUpdatePowerupRight=UPDATE_DELETE;
|
|
// break;
|
|
//
|
|
// case MPART_L_WEAPON:
|
|
// if (m_pWeaponPowerupLeft!=NULL) m_nUpdatePowerupLeft=UPDATE_DELETE;
|
|
// break;
|
|
// }
|
|
//}
|
|
|
|
|
|
//void SGameAvatarEx::setWeaponPowerupFx(int partNo, SGameFxWeaponPowerup *newFX, bool deleteOldFx)
|
|
//{
|
|
// if (partNo==MPART_R_WEAPON) { // 오른손 FX
|
|
// if (deleteOldFx) SAFE_DELETE(m_pWeaponPowerupRight);
|
|
// m_pWeaponPowerupRight=newFX;
|
|
// if (newFX!=NULL && m_nUpdatePowerupRight==UPDATE_NONE) {
|
|
// if (!rebuildWeaponPowerupMesh(partNo)) { // 즉시 업데이트에 실패하면
|
|
// m_nUpdatePowerupRight=UPDATE_REBUILD; // 나중에 업데이트
|
|
// }
|
|
// }
|
|
// } else if (partNo==MPART_L_WEAPON) { // 왼손 FX
|
|
// if (deleteOldFx) SAFE_DELETE(m_pWeaponPowerupLeft);
|
|
// m_pWeaponPowerupLeft=newFX;
|
|
// if (newFX!=NULL && m_nUpdatePowerupLeft==UPDATE_NONE) {
|
|
// if (!rebuildWeaponPowerupMesh(partNo)) { // 즉시 업데이트에 실패하면
|
|
// m_nUpdatePowerupLeft=UPDATE_REBUILD; // 나중에 업데이트
|
|
// }
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
//SGameFxWeaponPowerup * SGameAvatarEx::getWeaponPowerupFx(int partNo)
|
|
//{
|
|
// if (partNo==MPART_R_WEAPON) { // 오른손 FX
|
|
// return m_pWeaponPowerupRight;
|
|
// } else if (partNo==MPART_L_WEAPON) { // 왼손 FX
|
|
// return m_pWeaponPowerupLeft;
|
|
// }
|
|
// return NULL;
|
|
//}
|
|
|
|
//bool SGameAvatarEx::rebuildWeaponPowerupMesh(int partNo) // partNo : MPART_R_WEAPON or MPART_L_WEAPON
|
|
//{
|
|
// int aniPart;
|
|
// SGameFxWeaponPowerup *powerupFx;
|
|
//
|
|
// if (partNo==MPART_R_WEAPON) {
|
|
// // 오른손 FX
|
|
// aniPart=ANIPART_WEAPON_RIGHT;
|
|
// powerupFx=m_pWeaponPowerupRight;
|
|
// } else if (partNo==MPART_L_WEAPON) {
|
|
// // 왼손 FX
|
|
// aniPart=ANIPART_WEAPON_LEFT;
|
|
// powerupFx=m_pWeaponPowerupLeft;
|
|
// } else {
|
|
// assert(0);
|
|
// return false;
|
|
// }
|
|
//
|
|
// //내부에 칼 애니메이션이 있으므로, Primitive 딴 복사로는 문제가 생김.
|
|
// if (m_pSeqAvatar!=NULL && powerupFx!=NULL)
|
|
// {
|
|
// KSequencer *seq=dynamic_cast<KSequencer*>(m_pSeqAvatar->GetMesh(aniPart, partNo)); // ANIPART_WEAPON_RIGHT, MPART_R_WEAPON
|
|
// if (seq!=NULL)
|
|
// {
|
|
// KMeshSeqObject *meshseq=dynamic_cast<KMeshSeqObject*>(seq->GetSeqObject(0));
|
|
// if (meshseq!=NULL)
|
|
// {
|
|
// KMeshPrimitive *pr=meshseq->getMeshPrimitive(0);
|
|
// if (pr!=NULL)
|
|
// {
|
|
// if (pr->GetVertexBuffer()!=NULL && pr->GetIndexBuffer()!=NULL)
|
|
// {
|
|
// // Weapon mesh primitive loaded
|
|
// powerupFx->close();
|
|
// powerupFx->init(pr); // do initialize
|
|
//
|
|
// return true;
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// return false;
|
|
//}
|
|
|
|
|
|
//void SGameAvatarEx::deleteWeaponPowerupMesh(int partNo) // 폴리곤 삭제
|
|
//{
|
|
// assert(partNo==MPART_R_WEAPON || partNo==MPART_L_WEAPON);
|
|
// if (partNo==MPART_R_WEAPON) {
|
|
// m_pWeaponPowerupRight->close();
|
|
// } else if (partNo==MPART_L_WEAPON) {
|
|
// m_pWeaponPowerupLeft->close();
|
|
// }
|
|
//}
|
|
|
|
|
|
//void SGameAvatarEx::processWeaponPowerupMeshRebuild()
|
|
//{
|
|
////!!TEST : Localplayer일 경우에만 처리
|
|
////if ( IsLocalPlayer() )
|
|
//
|
|
// if (m_bUpdatePowerupSwitch) { // 무기 강화 이펙트 초기화 (weapon mesh가 update되었음)
|
|
// bool br, bl; // 좌우 모두 제대로 처리 되었나?
|
|
// br=bl=false;
|
|
//
|
|
// if (m_pWeaponPowerupRight!=NULL && m_nUpdatePowerupRight!=UPDATE_NONE) { // 오른손용
|
|
// if (m_nUpdatePowerupRight==UPDATE_DELETE) {
|
|
// // polygon delete
|
|
// deleteWeaponPowerupMesh(MPART_R_WEAPON);
|
|
// m_nUpdatePowerupRight=UPDATE_NONE;
|
|
// br=true;
|
|
// } else if (rebuildWeaponPowerupMesh(MPART_R_WEAPON)) {
|
|
// m_nUpdatePowerupRight=UPDATE_NONE;
|
|
// br=true;
|
|
// } else if (m_pSeqAvatar->GetMesh(ANIPART_WEAPON_RIGHT, MPART_R_WEAPON)==NULL) {
|
|
// // 오른손 무기 mesh가 존재하지 않으면
|
|
// // update플래그 소멸
|
|
// deleteWeaponPowerupMesh(MPART_R_WEAPON);
|
|
// m_nUpdatePowerupRight=UPDATE_NONE;
|
|
// br=true;
|
|
// }
|
|
// // else br=false;
|
|
// } else br=true;
|
|
//
|
|
// if (m_pWeaponPowerupLeft!=NULL && m_nUpdatePowerupLeft!=UPDATE_NONE) { // 왼손용
|
|
// if (m_nUpdatePowerupLeft==UPDATE_DELETE) {
|
|
// // polygon delete
|
|
// deleteWeaponPowerupMesh(MPART_L_WEAPON);
|
|
// m_nUpdatePowerupLeft=UPDATE_NONE;
|
|
// bl=true;
|
|
// } else if (rebuildWeaponPowerupMesh(MPART_L_WEAPON)) {
|
|
// m_nUpdatePowerupLeft=UPDATE_NONE;
|
|
// bl=true;
|
|
// } else if (m_pSeqAvatar->GetMesh(ANIPART_WEAPON_LEFT, MPART_L_WEAPON)==NULL) {
|
|
// // 오른손 무기 mesh가 존재하지 않으면
|
|
// // update플래그 소멸
|
|
// deleteWeaponPowerupMesh(MPART_L_WEAPON);
|
|
// m_nUpdatePowerupLeft=UPDATE_NONE;
|
|
// bl=true;
|
|
// }
|
|
// // else bl=false;
|
|
// } else bl=true;
|
|
//
|
|
// if (br && bl) {
|
|
// m_bUpdatePowerupSwitch=false;
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
|
|
//-------------------------------------
|
|
// Terrain degree
|
|
//-------------------------------------
|
|
|
|
void SGameAvatarEx::ActivateTerrainDegree()
|
|
{
|
|
m_bActivateTerrainDegree = true;
|
|
|
|
if (m_pTerrainDegree) return;
|
|
|
|
m_pTerrainDegree = new SGameAvatarTerrainDegree;
|
|
}
|
|
|
|
void SGameAvatarEx::DeActivateTerrainDegree()
|
|
{
|
|
m_bActivateTerrainDegree = false;
|
|
|
|
SAFE_DELETE(m_pTerrainDegree);
|
|
}
|
|
|
|
float SGameAvatarEx::GetCurAngleX()
|
|
{
|
|
return m_bActivateTerrainDegree ? m_pTerrainDegree->GetCurrentAngleX() : 0.0f;
|
|
}
|
|
|
|
float SGameAvatarEx::GetCurAngleY()
|
|
{
|
|
return m_bActivateTerrainDegree ? m_pTerrainDegree->GetCurrentAngleY() : 0.0f;
|
|
}
|
|
|
|
void SGameAvatarEx::StandingDegree()
|
|
{
|
|
if (!m_bActivateTerrainDegree) return;
|
|
|
|
K3DVector vPos = GetCurPosWithChangeDir();
|
|
K3DVector v1, v2, v3;
|
|
GetTerrainTriangle(vPos.x, vPos.y, v1, v2, v3);
|
|
|
|
v1 = v2 - v1;
|
|
v2 = v3 - v2;
|
|
|
|
m_vTerrainNormal = CrossProduct(v2, v1);
|
|
Normalize(m_vTerrainNormal);
|
|
|
|
K3DMatrix matZ;
|
|
K3DVector vView = K3DVector(0.0f, 1.0f, 0.0f);
|
|
K3DMatrixRotationZ(matZ, m_fTargetRoll + 3.1415926f / 2);
|
|
K3DVectorTransform(vView, vView, matZ);
|
|
|
|
// K3DVector vCross = CrossProduct(m_vTerrainNormal, -vView);
|
|
// if( fabsf(vCross.z) < 0.4f )
|
|
m_pTerrainDegree->CalcTerrainDegree(m_vTerrainNormal, m_dwTime);
|
|
// else
|
|
// m_pTerrainDegree->Reset( m_dwTime );
|
|
}
|
|
|
|
void SGameAvatarEx::StandingDegreeForMount()
|
|
{
|
|
if (!m_bActivateTerrainDegree) return;
|
|
|
|
m_pTerrainDegree->Reset(m_dwTime);
|
|
}
|
|
|
|
void SGameAvatarEx::FindNewEvent()
|
|
{
|
|
int nObjType = GetInnObjType();
|
|
if (nObjType == TS_ENTER::GAME_PLAYER || nObjType == TS_ENTER::GAME_MOB || nObjType == TS_ENTER::GAME_SUMMON || nObjType == TS_ENTER::GAME_PET) // sonador 10.2.1 팻 시스템 구현
|
|
{
|
|
const char* pAni = NULL;
|
|
|
|
if (nObjType == TS_ENTER::GAME_PLAYER)
|
|
pAni = GetMotionSetDB().GetAni(nObjType, m_nNewCurAniType, GetRace(), GetSex(), m_nAniClass);
|
|
else if (nObjType == TS_ENTER::GAME_MOB)
|
|
{
|
|
_MONSTER_INFO_FILE* pMonster = GetMonsterDB().GetMonsterData(GetInnContentID());
|
|
if (pMonster)
|
|
pAni = GetMonsterMotionSetDB().GetAni(pMonster->motion_file_id, m_nNewCurAniType);
|
|
}
|
|
else if (nObjType == TS_ENTER::GAME_SUMMON)
|
|
{
|
|
_SUMMON_INFO_FILE* pSummon = GetCreatureDB().GetCreatureData(GetInnContentID());
|
|
if (pSummon)
|
|
{
|
|
pAni = GetMonsterMotionSetDB().GetAni(pSummon->motion_file_id, m_nNewCurAniType);
|
|
}
|
|
}
|
|
else if (nObjType == TS_ENTER::GAME_PET) // sonador 10.2.1 팻 시스템 구현
|
|
{
|
|
SPetInfoEx PetInfo = GetPetDB().Find(GetInnContentID());
|
|
pAni = GetMonsterMotionSetDB().GetAni(PetInfo.getMotionFileID(), m_nNewCurAniType);
|
|
}
|
|
|
|
SetEventHandleNull();
|
|
|
|
//이벤트 핸들 설정
|
|
FindEventList(pAni, m_pCurEventHandle00_effect, m_svEventHandle00_effectList);
|
|
FindEventList(pAni, m_pCurEventHandle00_sound, m_svEventHandle00_soundList);
|
|
FindEventList(pAni, m_pCurEventHandle00_motion_effect, m_svEventHandle00_motion_effect);
|
|
FindEventList(pAni, m_pCurEventHandle01, m_svEventHandle01_List);
|
|
FindEventList(pAni, m_pCurEventHandle02, m_svEventHandle02_List);
|
|
FindEventList(pAni, m_pCurEventHandle03, m_svEventHandle03_List);
|
|
FindEventList(pAni, m_pCurEventHandle04, m_svEventHandle04_List);
|
|
FindEventList(pAni, m_pCurEventHandle05, m_svEventHandle05_List);
|
|
FindEventList(pAni, m_pCurEventHandle06, m_svEventHandle06_List);
|
|
|
|
FindMotionAddOnFx();
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::FindMotionAddOnFx()
|
|
{
|
|
if (!m_pCurEventHandle00_effect) return;
|
|
|
|
Key_EVENT_NEW* pKey1 = NULL;
|
|
Key_EVENT_NEW* pKey2 = NULL;
|
|
|
|
m_pCurEventHandle00_effect->GetData(GetAniTime(), pKey1, pKey2);
|
|
|
|
if (!pKey1 || pKey1->bUse == false) return;
|
|
|
|
if (pKey1->nSpeedType == 1)
|
|
{
|
|
pKey1->bUse = true;
|
|
|
|
SGameAvatarMotionFx* pAvatarMotionFx = (SGameAvatarMotionFx*)m_pAddOnMgr->GetAddOn(SGameAvatarAddOnMgr::SGAME_AVATAR_MOTION_FX);
|
|
if (pAvatarMotionFx)
|
|
{
|
|
pAvatarMotionFx->SetMotioinFxInfo(m_dwTime, pKey1->strEffect.c_str(), pKey1->nEffPos, m_nNewCurAniType);
|
|
pAvatarMotionFx->ChangeNewMotionFx();
|
|
pAvatarMotionFx->SetRenderFlag(true);
|
|
}
|
|
else
|
|
{
|
|
pAvatarMotionFx = new SGameAvatarMotionFx;
|
|
pAvatarMotionFx->SetMotioinFxInfo(m_dwTime, pKey1->strEffect.c_str(), pKey1->nEffPos, m_nNewCurAniType);
|
|
m_pAddOnMgr->AddAddOn(pAvatarMotionFx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SGameAvatarMotionFx* pAvatarMotionFx = (SGameAvatarMotionFx*)m_pAddOnMgr->GetAddOn(SGameAvatarAddOnMgr::SGAME_AVATAR_MOTION_FX);
|
|
if (pAvatarMotionFx) pAvatarMotionFx->SetRenderFlag(false);
|
|
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::FindMotionAddOnFx(Key_EVENT_NEW* pKey1)
|
|
{
|
|
if (!pKey1) return;
|
|
|
|
if (pKey1->nSpeedType == 1)
|
|
{
|
|
SGameAvatarMotionFx* pAvatarMotionFx = (SGameAvatarMotionFx*)m_pAddOnMgr->GetAddOn(SGameAvatarAddOnMgr::SGAME_AVATAR_MOTION_FX);
|
|
if (pAvatarMotionFx)
|
|
{
|
|
pAvatarMotionFx->SetMotioinFxInfo(m_dwTime, pKey1->strEffect.c_str(), pKey1->nEffPos, m_nNewCurAniType);
|
|
pAvatarMotionFx->ChangeNewMotionFx();
|
|
pAvatarMotionFx->SetRenderFlag(true);
|
|
}
|
|
else
|
|
{
|
|
pAvatarMotionFx = new SGameAvatarMotionFx;
|
|
pAvatarMotionFx->SetMotioinFxInfo(m_dwTime, pKey1->strEffect.c_str(), pKey1->nEffPos, m_nNewCurAniType);
|
|
m_pAddOnMgr->AddAddOn(pAvatarMotionFx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SGameAvatarMotionFx* pAvatarMotionFx = (SGameAvatarMotionFx*)m_pAddOnMgr->GetAddOn(SGameAvatarAddOnMgr::SGAME_AVATAR_MOTION_FX);
|
|
if (pAvatarMotionFx) pAvatarMotionFx->SetRenderFlag(false);
|
|
|
|
}
|
|
}
|
|
|
|
bool SGameAvatarEx::CurrentlyAnimationIsMount()
|
|
{
|
|
switch (GetCurrAnimationID())
|
|
{
|
|
case ANI_M_MOUNT_HIGH:
|
|
case ANI_M_MOUNT_LOW:
|
|
case ANI_M_MOUNT01_WHITE:
|
|
case ANI_M_MOUNT01_UNICORN:
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SGameAvatarEx::CurrentlyAnimationIsUnMount()
|
|
{
|
|
switch (GetCurrAnimationID())
|
|
{
|
|
case ANI_M_UNMOUNT_HIGH:
|
|
case ANI_M_UNMOUNT_LOW:
|
|
case ANI_M_FALL:
|
|
case ANI_M_UNMOUNT01_WHITE:
|
|
case ANI_M_UNMOUNT01_UNICORN:
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// sonador #2.1.6
|
|
bool SGameAvatarEx::CurrentlyAnimationIsMDef()
|
|
{
|
|
switch (GetCurrAnimationID())
|
|
{
|
|
case ANI_M_DEFAULT01_HIGH:
|
|
case ANI_M_DEFAULT01_LOW:
|
|
case ANI_M_DEFAULT01_QILIN:
|
|
case ANI_M_DEFAULT01_WHITE: // #2.1.14
|
|
case ANI_M_DEFAULT01_UNICORN: // #2.1.14
|
|
case ANI_M_DEFAULT01_BEAKHO: /// 2011.02.08 - prodongi
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SGameAvatarEx::CurrentlyAnimationIsMWalk()
|
|
{
|
|
switch (GetCurrAnimationID())
|
|
{
|
|
case ANI_M_WALK:
|
|
case ANI_M_WALK_QILIN:
|
|
case ANI_M_WALK_WHITE: // #2.1.14
|
|
case ANI_M_WALK_UNICORN: // #2.1.14
|
|
case ANI_M_WALK_BEAKHO: /// 2011.02.08 - prodongi
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SGameAvatarEx::CurrentlyAnimationIsMRun()
|
|
{
|
|
switch (GetCurrAnimationID())
|
|
{
|
|
case ANI_M_RUN_HIGH: return true;
|
|
case ANI_M_RUN_LOW: return true;
|
|
case ANI_M_RUN_QILIN: return true; // sonador #2.1.6
|
|
case ANI_M_RUN_WHITE: return true; // #2.1.14
|
|
case ANI_M_RUN_UNICORN: return true; // #2.1.14
|
|
case ANI_M_RUN_BEAKHO: return true; /// 2011.02.08 - prodongi
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SGameAvatarEx::CurrentlyAnimationIsAttack()
|
|
{
|
|
switch (GetCurrAnimationID())
|
|
{
|
|
case ANI_ATTACK01: return true;
|
|
case ANI_ATTACK02: return true;
|
|
case ANI_ATTACK03: return true;
|
|
case ANI_CRITICAL_ATTACK01: return true;
|
|
case ANI_CRITICAL_ATTACK02: return true;
|
|
case ANI_CRITICAL_ATTACK03: return true;
|
|
case ANI_DOUBLE_ATTACK01: return true;
|
|
case ANI_DOUBLE_ATTACK02: return true;
|
|
case ANI_DOUBLE_ATTACK03: return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SGameAvatarEx::CurrentlyAnimationIsDamage()
|
|
{
|
|
switch (GetCurrAnimationID())
|
|
{
|
|
case ANI_DAMAGE01: return true;
|
|
case ANI_DAMAGE02: return true;
|
|
case ANI_M_DAMAGE01: return true;
|
|
case ANI_M_DAMAGE02: return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void SGameAvatarEx::InputFreezing()
|
|
{
|
|
if (m_pStateVM)
|
|
m_pStateVM->InputFreezing();
|
|
}
|
|
|
|
void SGameAvatarEx::InputThawing()
|
|
{
|
|
if (m_pStateVM)
|
|
m_pStateVM->InputThawing();
|
|
}
|
|
|
|
void SGameAvatarEx::ClearPendingNextState()
|
|
{
|
|
if (m_pStateVM)
|
|
m_pStateVM->ClearPendingNextState();
|
|
}
|
|
|
|
bool SGameAvatarEx::IsLoopMotion(int nAniType)
|
|
{
|
|
switch (nAniType)
|
|
{
|
|
case ANI_DEFAULT01: return true;
|
|
case ANI_DEFAULT02: return true;
|
|
case ANI_IDLE: return true;
|
|
case ANI_WALK: return true;
|
|
case ANI_RUN: return true;
|
|
case ANI_M_IDLE: return true;
|
|
case ANI_M_WALK: return true;
|
|
case ANI_M_DEFAULT01_HIGH: return true;
|
|
case ANI_M_RUN_HIGH: return true;
|
|
case ANI_M_DEFAULT01_LOW: return true;
|
|
case ANI_M_RUN_LOW: return true;
|
|
case ANI_M_DEFAULT01_QILIN: return true; // sonador #2.1.6
|
|
case ANI_M_WALK_QILIN: return true;
|
|
case ANI_M_RUN_QILIN: return true;
|
|
case ANI_M_DEFAULT01_WHITE: return true; // #2.1.14
|
|
case ANI_M_WALK_WHITE: return true; //
|
|
case ANI_M_RUN_WHITE: return true; //
|
|
case ANI_M_DEFAULT01_UNICORN: return true; // #2.1.14
|
|
case ANI_M_WALK_UNICORN: return true; //
|
|
case ANI_M_RUN_UNICORN: return true; //
|
|
/// 2011.02.08 - prodongi
|
|
case ANI_M_DEFAULT01_BEAKHO:
|
|
case ANI_M_WALK_BEAKHO:
|
|
case ANI_M_RUN_BEAKHO: return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//AvatarEx 내부 사용 용
|
|
void SGameAvatarEx::SetInnSex(int nSex)
|
|
{
|
|
if (m_pProperty) m_pProperty->InnSex = nSex;
|
|
}
|
|
|
|
void SGameAvatarEx::SetInnRace(int nRace)
|
|
{
|
|
if (m_pProperty) m_pProperty->InnRace = nRace;
|
|
}
|
|
|
|
void SGameAvatarEx::SetInnFaceID(int nFaceID)
|
|
{
|
|
if (m_pProperty) m_pProperty->InnFaceID = nFaceID;
|
|
}
|
|
|
|
void SGameAvatarEx::SetInnHairID(int nHairID)
|
|
{
|
|
if (m_pProperty) m_pProperty->InnHairID = nHairID;
|
|
}
|
|
|
|
void SGameAvatarEx::SetInnObjType(unsigned char ObjType)
|
|
{
|
|
if (m_pProperty) m_pProperty->InnObjType = ObjType;
|
|
}
|
|
|
|
int SGameAvatarEx::GetInnSex()
|
|
{
|
|
if (m_pProperty) return m_pProperty->InnSex;
|
|
return 0;
|
|
}
|
|
|
|
int SGameAvatarEx::GetInnRace()
|
|
{
|
|
if (m_pProperty) return m_pProperty->InnRace;
|
|
return 0;
|
|
}
|
|
|
|
int SGameAvatarEx::GetInnFace()
|
|
{
|
|
if (m_pProperty) return m_pProperty->InnFaceID;
|
|
return 0;
|
|
}
|
|
|
|
int SGameAvatarEx::GetInnHair()
|
|
{
|
|
if (m_pProperty) return m_pProperty->InnHairID;
|
|
return 0;
|
|
}
|
|
|
|
unsigned char SGameAvatarEx::GetInnObjType()
|
|
{
|
|
if (m_pProperty)
|
|
return m_pProperty->InnObjType;
|
|
return -1;
|
|
}
|
|
|
|
ENC_INT SGameAvatarEx::GetInnContentID()
|
|
{
|
|
if (m_pProperty) return m_pProperty->InnContentID();
|
|
return -1;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//변장
|
|
|
|
void SGameAvatarEx::UpdateDisguiseState()
|
|
{
|
|
iterator_state_slot PositiveIt = m_vecPositiveList.begin();
|
|
iterator_state_slot NegativeIt = m_vecNegativeList.begin();
|
|
|
|
SStateSlot* pState(NULL);
|
|
StateInfoEx* pStateInfo(NULL);
|
|
|
|
while (true)
|
|
{
|
|
//이로운 지속효과와 해로운 지속효과를 모두 순환하였으니 break;
|
|
if (PositiveIt == m_vecPositiveList.end() && NegativeIt == m_vecNegativeList.end())
|
|
break;
|
|
|
|
if (PositiveIt != m_vecPositiveList.end())
|
|
{
|
|
if (m_vecPositiveList.end() == PositiveIt + 1)
|
|
SetDisguise(*PositiveIt, true);
|
|
else
|
|
SetDisguise(*PositiveIt);
|
|
|
|
++PositiveIt;
|
|
}
|
|
|
|
if (NegativeIt != m_vecNegativeList.end())
|
|
{
|
|
if (m_vecNegativeList.end() == NegativeIt + 1)
|
|
SetDisguise(*NegativeIt, true);
|
|
else
|
|
SetDisguise(*NegativeIt);
|
|
|
|
++NegativeIt;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::SetDisguise(SStateSlot* pState, bool bLastDisguese /*= false*/)
|
|
{
|
|
|
|
if (!pState) return;
|
|
StateInfoEx* pStateInfo = GetTenacityDB().GetTenacityData(pState->GetStateCode());
|
|
|
|
bool bComplete = false; // 변신이 끝난후 쓰레드가 돌았는지 체크 (변신 완료후 쓰레드를 거쳐야 다음 변신적용가능)
|
|
|
|
if (pStateInfo)
|
|
{
|
|
switch (pStateInfo->effect_type)
|
|
{
|
|
case STATE_TYPE::STATE_MUTATION_A: //몬스터 전용
|
|
{
|
|
if (pState->GetStateLevel()) //변이
|
|
{
|
|
if ((int)pStateInfo->fValue[0] > 0)
|
|
{
|
|
AddDisguiseID(pStateInfo->id);
|
|
|
|
while (bComplete == false)
|
|
{
|
|
bComplete = Disguise(pState->GetStateHandle(), bits_scramble< int, 3 >((int)pStateInfo->fValue[0])); // 2.1.16 변신 효과 중첩시 아바타 사라지는 오류 수정
|
|
|
|
}
|
|
|
|
if (bLastDisguese)
|
|
m_nDisguise = STAT_DISGUISE;
|
|
|
|
}
|
|
|
|
}
|
|
else if (pState->GetStateLevel() == 0) //해제
|
|
{
|
|
DeleteDisguiseID(pStateInfo->id);
|
|
UnDisguise(pState->GetStateHandle());
|
|
}
|
|
}
|
|
break;
|
|
case STATE_TYPE::STATE_MUTATION_B: //소환수 전용
|
|
{
|
|
if (pState->GetStateLevel()) //변이
|
|
{
|
|
if (pState->GetStateValue() > 0)
|
|
{
|
|
AddDisguiseID(pStateInfo->id);
|
|
|
|
Disguise(pState->GetStateHandle(), pState->GetStateValue(), true, pState->GetStateLevel());
|
|
|
|
/*
|
|
while (bComplete == false)
|
|
{
|
|
bComplete = Disguise(pState->GetStateHandle(), pState->GetStateValue(), true , pState->GetStateLevel() ); // 2.1.16 변신 효과 중첩시 아바타 사라지는 오류 수정
|
|
}
|
|
|
|
if (bLastDisguese)
|
|
m_nDisguise = STAT_DISGUISE;
|
|
|
|
*/
|
|
|
|
if (m_nDisguise == STAT_DISGUISE)
|
|
{
|
|
//SetScale( getNoneDisguiseScale() * ( pStateInfo->fValue[8] + pStateInfo->fValue[9] * pState->GetStateLevel() ));
|
|
SetScale(getNoneDisguiseScale() * (pStateInfo->fValue[8] + pStateInfo->fValue[9]));
|
|
}
|
|
}
|
|
}
|
|
else if (pState->GetStateLevel() == 0) //해제
|
|
{
|
|
DeleteDisguiseID(pStateInfo->id);
|
|
UnDisguise(pState->GetStateHandle());
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
m_nDisguise = STAT_DISGUISE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::CheckDisguise()
|
|
{
|
|
if (m_nDisguise == PROG_DISGUISE)
|
|
{
|
|
|
|
UpdateDisguiseState();
|
|
}
|
|
else if (m_nDisguise == REMO_DISGUISE)
|
|
{
|
|
|
|
// 2.1.16 변신 효과 중첩시 아바타 사라지는 오류 수정
|
|
unsigned int handle = m_UndisguiseStateHandleQueue.front();
|
|
m_UndisguiseStateHandleQueue.pop_front();
|
|
UnDisguise(handle);
|
|
}
|
|
}
|
|
|
|
// 2.1.16 변신 효과 중첩시 아바타 사라지는 오류 수정
|
|
/// 2011.07.28 redmine #16797 - prodongi
|
|
bool SGameAvatarEx::Disguise(unsigned int stateHandle, ENC_INT nContentID, bool bIsSummon, int disguiseEnhance)
|
|
{
|
|
/// 2011.07.28 redmine #16797 ¼¹ö¿¡¼ SMSG_STATE¸¦ ¹Þ´Â °Í°ú µ¥ÀÌŸ ·Îµù ¼ø¼°¡ ¾È ¸Â¾Æ¼ ÀÌ·¸°Ô ÇÔ - prodongi
|
|
if (disguiseEnhance > 1)
|
|
m_disguiseEnhance = 1;
|
|
else
|
|
m_disguiseEnhance = 0;
|
|
|
|
/// 2011.06.20 servantes : 9078 : Å©¸®Ã³ º¯½Å ÈÄ ¾ß¼ö º¯½Å ½ºÅ³ »ç¿ë ½Ã ¹®Á¦
|
|
ENC_INT _tempContentID = 0;
|
|
|
|
if (IsThreadLoading() || !m_bIsActivated || !m_pSeqAvatar)
|
|
{
|
|
m_nDisguise = PROG_DISGUISE; //º¯Àå Áß »óÅ·Î
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (m_nDisguise == STAT_DISGUISE) //ÀÌ¹Ì º¯Àå ÁßÀ̶ó¸é
|
|
{
|
|
// 2011.06.20 - servantes
|
|
_tempContentID = GetInnContentID();
|
|
|
|
if (GetInnContentID() == nContentID)
|
|
return true;
|
|
else
|
|
_tempContentID = nContentID;
|
|
|
|
//KSeqAvatarEx* pSeqAvatar = m_pSeqAvatar;
|
|
//m_pSeqAvatar = m_pDisguiseSeqAvatar;
|
|
//SetScale( m_fDisguiseScale );
|
|
|
|
//SAFE_DELETE( pSeqAvatar );
|
|
}
|
|
// 2011.06.20 - servantes
|
|
else // 2011.06.20 - servantes
|
|
{
|
|
_tempContentID = nContentID;
|
|
}
|
|
}
|
|
|
|
// 2011.06.20 - servantes
|
|
if (!m_pDisguiseStack->onDisguise(DisguiseStack::Slot(stateHandle, _tempContentID, m_pSeqAvatar, GetSize(), GetScale(), bIsSummon)))
|
|
return true;
|
|
|
|
Deactivate();
|
|
|
|
//m_pDisguiseSeqAvatar = m_pSeqAvatar;
|
|
//m_fDisguiseSize = GetSize();
|
|
//m_fDisguiseScale = GetScale();
|
|
|
|
/// 2011.04.29 - prodongi
|
|
float oldScale = GetScale();
|
|
|
|
m_pSeqAvatar = NULL;
|
|
|
|
m_nFirst = 0;
|
|
|
|
|
|
// 2011.06.20 - servantes
|
|
m_pProperty->SetInnContentID(_tempContentID);
|
|
|
|
if (!bIsSummon)
|
|
{
|
|
SetInnObjType(TS_ENTER::GAME_MOB);
|
|
}
|
|
else
|
|
{
|
|
SetInnObjType(TS_ENTER::GAME_SUMMON);
|
|
}
|
|
|
|
SetInnSex(0);
|
|
SetInnRace(0);
|
|
SetInnFaceID(0);
|
|
SetInnHairID(0);
|
|
|
|
InfoRemoveForDisguise();
|
|
|
|
switch (GetInnObjType())
|
|
{
|
|
case TS_ENTER::GAME_PLAYER:
|
|
{
|
|
SetScale(1.0f);
|
|
}
|
|
break;
|
|
case TS_ENTER::GAME_NPC:
|
|
{
|
|
SetScale(1.0f);
|
|
}
|
|
break;
|
|
case TS_ENTER::GAME_MOB:
|
|
{
|
|
// 2011.06.20 - servantes
|
|
_MONSTER_INFO_FILE* pMonsterInfo = GetMonsterDB().GetMonsterData(_tempContentID);
|
|
|
|
if (pMonsterInfo)
|
|
{
|
|
/* if( m_strBackupName.empty() )
|
|
{
|
|
m_strBackupName = GetName();
|
|
SetName( GetStringDB().GetString( pMonsterInfo->name_id ) );
|
|
}*/
|
|
|
|
SetScale(pMonsterInfo->scale);
|
|
|
|
if (GetObjType() == TS_ENTER::GAME_PLAYER)
|
|
SetRunNWalkAniSpeed(pMonsterInfo);
|
|
}
|
|
else
|
|
SetScale(1.0f);
|
|
}
|
|
break;
|
|
case TS_ENTER::GAME_SUMMON:
|
|
{
|
|
// 2011.06.20 - servantes
|
|
_SUMMON_INFO_FILE* pSummon = GetCreatureDB().GetCreatureData(_tempContentID);
|
|
|
|
if (pSummon)
|
|
{
|
|
/* if( m_strBackupName.empty() )
|
|
{
|
|
m_strBackupName = GetName();
|
|
SetName( GetStringDB().GetString( pSummon->name_id ) );
|
|
}*/
|
|
|
|
SetScale(pSummon->scale);
|
|
|
|
if (GetObjType() == TS_ENTER::GAME_PLAYER)
|
|
SetRunNWalkAniSpeed(pSummon);
|
|
}
|
|
else
|
|
SetScale(1.0f);
|
|
}
|
|
break;
|
|
}
|
|
|
|
RefreshEffectPos(NULL);
|
|
|
|
addToLoadingList();
|
|
|
|
/// 2011.04.29 º¯½Å ÀüÀÇ Å©±â¸¦ ÀúÀåÇØ ³õ´Â´Ù - prodongi
|
|
if (m_nDisguise == NONE_DISGUISE)
|
|
{
|
|
m_noneDisguiseScale = oldScale;
|
|
}
|
|
|
|
|
|
m_nDisguise = STAT_DISGUISE; //º¯Àå »óÅÂ
|
|
|
|
doLoading();
|
|
|
|
return true;
|
|
}
|
|
|
|
// 2.1.16 변신 효과 중첩시 아바타 사라지는 오류 수정
|
|
void SGameAvatarEx::UnDisguise(unsigned int stateHandle)
|
|
{
|
|
|
|
/// 2011.07.28 redmine #16797 - prodongi
|
|
m_disguiseEnhance = 0;
|
|
|
|
if (IsThreadLoading() || !m_bIsActivated || !m_pSeqAvatar)
|
|
{
|
|
m_nDisguise = REMO_DISGUISE; //변장 해제 중 상태로
|
|
m_UndisguiseStateHandleQueue.push_back(stateHandle);
|
|
return;
|
|
}
|
|
|
|
/* if( m_strBackupName.empty() == false )
|
|
{
|
|
SetName( m_strBackupName.c_str() );
|
|
m_strBackupName.clear();
|
|
}*/
|
|
|
|
if (m_pDisguiseStack->empty())
|
|
{
|
|
m_nDisguise = NONE_DISGUISE;
|
|
return;
|
|
}
|
|
|
|
DisguiseStack::Slot disguiseSlot(stateHandle, 0, 0, 0, 0, 0);
|
|
|
|
if (!m_pDisguiseStack->onUndisguise(disguiseSlot))
|
|
return;
|
|
|
|
SAFE_DELETE(m_pSeqAvatar);
|
|
m_pSeqAvatar = disguiseSlot.seqAvatar;
|
|
|
|
if (!m_DisguiseList.empty())
|
|
{
|
|
m_pProperty->SetInnContentID(disguiseSlot.contentID);
|
|
|
|
if (!disguiseSlot.isSummon)
|
|
{
|
|
SetInnObjType(TS_ENTER::GAME_MOB);
|
|
}
|
|
else
|
|
{
|
|
SetInnObjType(TS_ENTER::GAME_SUMMON);
|
|
}
|
|
|
|
SetInnSex(0);
|
|
SetInnRace(0);
|
|
SetInnFaceID(0);
|
|
SetInnHairID(0);
|
|
|
|
InfoRemoveForDisguise();
|
|
|
|
SetScale(disguiseSlot.scale);
|
|
|
|
|
|
switch (GetInnObjType())
|
|
{
|
|
case TS_ENTER::GAME_MOB:
|
|
{
|
|
_MONSTER_INFO_FILE* pMonsterInfo = GetMonsterDB().GetMonsterData(disguiseSlot.contentID);
|
|
if (pMonsterInfo && GetObjType() == TS_ENTER::GAME_PLAYER)
|
|
SetRunNWalkAniSpeed(pMonsterInfo);
|
|
}
|
|
break;
|
|
case TS_ENTER::GAME_SUMMON:
|
|
{
|
|
_SUMMON_INFO_FILE* pSummon = GetCreatureDB().GetCreatureData(disguiseSlot.contentID);
|
|
if (pSummon && GetObjType() == TS_ENTER::GAME_PLAYER)
|
|
SetRunNWalkAniSpeed(pSummon);
|
|
}
|
|
break;
|
|
}
|
|
|
|
//이벤트 다시 로드
|
|
const char* pFileName = GetCobFileName();
|
|
if (pFileName)
|
|
{
|
|
std::string strName = pFileName;
|
|
if (strstr(strName.c_str(), ".cob") == NULL)
|
|
strName += ".cob";
|
|
|
|
m_strFileName = strName;
|
|
|
|
vec_cobset* coblist = COBManager::GetManager()->Load(strName.c_str());
|
|
if (coblist)
|
|
{
|
|
RefreshTextureGroup(coblist);
|
|
|
|
iterator_cobset it = coblist->begin();
|
|
if (coblist->end() != it)
|
|
{
|
|
COBSET* pCob = *it;
|
|
LoadEvent(pCob);
|
|
|
|
//큐브 Load
|
|
for (int i(0); 6 > i; i++)
|
|
{
|
|
m_fSelcube[i] = pCob->fSelCube[i];
|
|
m_fDeadcube[i] = pCob->fDeadCube[i];
|
|
}
|
|
|
|
for (int i(0); i < 3; ++i)
|
|
{
|
|
if (m_fSelcube[i] > m_fSelcube[i + 3]) ::swap(m_fSelcube[i], m_fSelcube[i + 3]);
|
|
if (m_fDeadcube[i] > m_fDeadcube[i + 3]) ::swap(m_fDeadcube[i], m_fDeadcube[i + 3]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RefreshEffectPos(m_pSeqAvatar);
|
|
|
|
|
|
|
|
|
|
//변장 해제 될때 이펙트
|
|
AddEffect(GetArID(), GetArID(), GetArID(), 4079, EFFECT_POS_BOTTOM);
|
|
return;
|
|
}
|
|
|
|
Activate();
|
|
|
|
SetScale(disguiseSlot.scale);
|
|
|
|
//기존 정보로 셋팅
|
|
m_pProperty->SetInnContentID(GetContentID());
|
|
|
|
SetInnObjType(GetObjType());
|
|
SetInnSex(GetSex());
|
|
SetInnRace(GetRace());
|
|
SetInnFaceID(GetFace());
|
|
SetInnHairID(GetHair());
|
|
|
|
InfoRemoveForDisguise();
|
|
|
|
//이벤트 다시 로드
|
|
const char* pFileName = GetCobFileName();
|
|
if (pFileName)
|
|
{
|
|
std::string strName = pFileName;
|
|
if (strstr(strName.c_str(), ".cob") == NULL)
|
|
strName += ".cob";
|
|
|
|
m_strFileName = strName;
|
|
|
|
vec_cobset* coblist = COBManager::GetManager()->Load(strName.c_str());
|
|
if (coblist)
|
|
{
|
|
iterator_cobset it = coblist->begin();
|
|
if (coblist->end() != it)
|
|
{
|
|
COBSET* pCob = *it;
|
|
LoadEvent(pCob);
|
|
//큐브 Load
|
|
for (int i(0); 6 > i; i++)
|
|
{
|
|
m_fSelcube[i] = pCob->fSelCube[i];
|
|
m_fDeadcube[i] = pCob->fDeadCube[i];
|
|
}
|
|
|
|
for (int i(0); i < 3; ++i)
|
|
{
|
|
if (m_fSelcube[i] > m_fSelcube[i + 3]) ::swap(m_fSelcube[i], m_fSelcube[i + 3]);
|
|
if (m_fDeadcube[i] > m_fDeadcube[i + 3]) ::swap(m_fDeadcube[i], m_fDeadcube[i + 3]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//이펙트 포스 다시 얻어오기
|
|
RefreshEffectPos(m_pSeqAvatar);
|
|
NPlayAnimation(m_nNewCurAniType, m_nCurPlayType);
|
|
|
|
SetVisibility(m_fVisibility);
|
|
|
|
//변장 해제 될때 이펙트
|
|
AddEffect(GetArID(), GetArID(), GetArID(), 4079, EFFECT_POS_BOTTOM);
|
|
|
|
m_nDisguise = NONE_DISGUISE; //원 상태
|
|
}
|
|
|
|
bool SGameAvatarEx::IsLastDisguise()
|
|
{
|
|
if (m_DisguiseList.empty())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void SGameAvatarEx::AddDisguiseID(int nDisguiseId)
|
|
{
|
|
|
|
std::list<int>::iterator it;
|
|
|
|
for (it = m_DisguiseList.begin(); it != m_DisguiseList.end(); ++it)
|
|
{
|
|
if (*it == nDisguiseId)
|
|
return; // 이미 추가 되어있는 id
|
|
}
|
|
|
|
m_DisguiseList.push_back(nDisguiseId);
|
|
|
|
}
|
|
|
|
void SGameAvatarEx::DeleteDisguiseID(int nDisguiseId)
|
|
{
|
|
|
|
std::list<int>::iterator it;
|
|
|
|
for (it = m_DisguiseList.begin(); it != m_DisguiseList.end(); ++it)
|
|
{
|
|
if (*it == nDisguiseId)
|
|
{
|
|
it = m_DisguiseList.erase(it);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//변장을 위한 정보 삭제
|
|
void SGameAvatarEx::InfoRemoveForDisguise()
|
|
{
|
|
SetEventHandleInit();
|
|
SetEventHandleNull();
|
|
|
|
DeleteEvent(m_svEventHandle00_effectList);
|
|
DeleteEvent(m_svEventHandle00_soundList);
|
|
DeleteEvent(m_svEventHandle00_motion_effect);
|
|
DeleteEvent(m_svEventHandle01_List);
|
|
DeleteEvent(m_svEventHandle02_List);
|
|
DeleteEvent(m_svEventHandle03_List);
|
|
DeleteEvent(m_svEventHandle04_List);
|
|
DeleteEvent(m_svEventHandle05_List);
|
|
DeleteEvent(m_svEventHandle06_List);
|
|
|
|
if (m_pAddOnMgr)
|
|
{
|
|
m_pAddOnMgr->RemoveAddOn(SGameAvatarAddOnMgr::SGAME_AVATAR_FX);
|
|
m_pAddOnMgr->RemoveAddOn(SGameAvatarAddOnMgr::SGAME_AVATAR_MOTION_FX);
|
|
}
|
|
|
|
SGameCircleShadowFX* pCirclrShadowFx = (SGameCircleShadowFX*)m_pAddOnMgr->GetAddOn(SGameAvatarAddOnMgr::SGAME_CIRCLE_SHADOW_FX);
|
|
if (pCirclrShadowFx) pCirclrShadowFx->Refresh();
|
|
|
|
m_bUseRot = true;
|
|
}
|
|
|
|
bool SGameAvatarEx::SetFrame(int nFrame)
|
|
{
|
|
KSeqAvatarEx* pSeqAvatar = GetSeqForm();
|
|
if (!pSeqAvatar) return false;
|
|
|
|
KSeqAvatar* pBipedSeq = pSeqAvatar->getAvatarPart(ANIPART_BIPED);
|
|
if (!pBipedSeq) return false;
|
|
|
|
KBoneSeqObject* pBoneSeq = pBipedSeq->getBoneSequencer();
|
|
if (!pBipedSeq) return false;
|
|
|
|
KBoneSeqObject* pBoneSeqRightWeapon = NULL;
|
|
KBoneSeqObject* pBoneSeqLeftWeapon = NULL;
|
|
|
|
KSeqAvatar* pRightHandSeq = pSeqAvatar->getAvatarPart(ANIPART_WEAPON_RIGHT);
|
|
KSequencer* pSequencer = dynamic_cast<KSequencer*>(pRightHandSeq->GetCurrentAnimation());
|
|
if (pSequencer != NULL)
|
|
{
|
|
pBoneSeqRightWeapon = dynamic_cast<KBoneSeqObject*> (pSequencer->GetSeqObject(0));
|
|
}
|
|
|
|
KSeqAvatar* pLeftHandSeq = pSeqAvatar->getAvatarPart(ANIPART_WEAPON_LEFT);
|
|
pSequencer = dynamic_cast<KSequencer*>(pLeftHandSeq->GetCurrentAnimation());
|
|
if (pSequencer != NULL)
|
|
{
|
|
pBoneSeqLeftWeapon = dynamic_cast<KBoneSeqObject*> (pSequencer->GetSeqObject(0));
|
|
}
|
|
|
|
if (!pBoneSeqRightWeapon || !pBoneSeqLeftWeapon) return false;
|
|
|
|
DWORD dwTime = nFrame * 160;
|
|
|
|
pSeqAvatar->SetAniTime(dwTime);
|
|
pSeqAvatar->realizeTime();
|
|
|
|
pBoneSeq->realizeTime();
|
|
|
|
pRightHandSeq->realizeTime();
|
|
pLeftHandSeq->realizeTime();
|
|
|
|
pBoneSeqRightWeapon->realizeTime();
|
|
pBoneSeqLeftWeapon->realizeTime();
|
|
|
|
_renderEffectLoading();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SGameAvatarEx::SetFxSwordSlashDBData(SGameFxSwordSlash* pFxSwordSlash, int nItemCode, int nEnhanceLevel)
|
|
{
|
|
if (pFxSwordSlash == NULL) return false;
|
|
|
|
|
|
int wt_width = GetWeaponLength(nItemCode);
|
|
int wt_length = 50 + nEnhanceLevel * 10; // 강화도에 따라 trail이 길어진다
|
|
unsigned int* pcolor = g_pEnhanceColor[0];
|
|
if (nEnhanceLevel > 0 && nEnhanceLevel <= 25) pcolor = g_pEnhanceColor[nEnhanceLevel]; // 강화도에 따른 색상
|
|
|
|
if (wt_length > 1)
|
|
{
|
|
KColor Scolor0(pcolor[0]);
|
|
KColor Scolor1(pcolor[1]);
|
|
KColor Ecolor0(pcolor[2]);
|
|
KColor Ecolor1(pcolor[3]);
|
|
|
|
pFxSwordSlash->setTrailWidth(wt_width);
|
|
pFxSwordSlash->setTrailNodeCount(wt_length);
|
|
pFxSwordSlash->setTrailNodeColor(0, 0, Scolor0.color);
|
|
pFxSwordSlash->setTrailNodeColor(0, 1, Scolor1.color);
|
|
pFxSwordSlash->setTrailNodeColor(1, 0, Ecolor0.color);
|
|
pFxSwordSlash->setTrailNodeColor(1, 1, Ecolor1.color);
|
|
|
|
pFxSwordSlash->setTrailTexture("wfxsforce_lv03.dds");
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void SGameAvatarEx::ActivateFxSwordSlashForSkill()
|
|
{/*
|
|
if(GetInnObjType() != TS_ENTER::GAME_PLAYER) return;
|
|
|
|
m_nSwordSlashForSkillMotion = GetCurrAnimationID();
|
|
|
|
ItemBase::ItemCode nRightHandCode = GetItemCode(ItemBase::WEAR_WEAPON);
|
|
if(m_bActRightWeaponTrail == false && m_bActRightSwordSlashForSkill == false)
|
|
{
|
|
SGameFxSwordSlash* pFxSwordSlash = new SGameFxSwordSlash(true);
|
|
if(SetFxSwordSlashDBData(pFxSwordSlash, nRightHandCode, 15))
|
|
{
|
|
m_pRightSwordSlashForSkill = pFxSwordSlash;
|
|
m_pRightSwordSlashForSkill->runTrail(true);
|
|
m_bActRightSwordSlashForSkill = true;
|
|
}
|
|
else
|
|
{
|
|
SAFE_DELETE(pFxSwordSlash);
|
|
}
|
|
}
|
|
|
|
ItemBase::ItemCode nLeftHandCode = GetItemCode(ItemBase::WEAR_SHIELD);
|
|
if(m_bActLeftWeaponTrail == false && m_bActLeftSwordSlashForSkill == false)
|
|
{
|
|
SGameFxSwordSlash* pFxSwordSlash = new SGameFxSwordSlash(false);
|
|
if(SetFxSwordSlashDBData(pFxSwordSlash, nLeftHandCode, 15))
|
|
{
|
|
m_pLeftSwordSlashForSkill = pFxSwordSlash;
|
|
m_pLeftSwordSlashForSkill->runTrail(true);
|
|
m_bActLeftSwordSlashForSkill = true;
|
|
}
|
|
else
|
|
{
|
|
SAFE_DELETE(pFxSwordSlash);
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
void SGameAvatarEx::DeActivateFxSwordSlashForSkill()
|
|
{
|
|
m_bActRightSwordSlashForSkill = false;
|
|
m_bActLeftSwordSlashForSkill = false;
|
|
|
|
SAFE_DELETE(m_pRightSwordSlashForSkill);
|
|
SAFE_DELETE(m_pLeftSwordSlashForSkill);
|
|
|
|
m_nSwordSlashForSkillMotion = 0;
|
|
}
|
|
|
|
void SGameAvatarEx::CheckStateSkill()
|
|
{
|
|
_checkPetrify();
|
|
CheckDisguise();
|
|
|
|
if (m_nStateFlag & FLAG_STATE_HIDING)
|
|
{
|
|
if (m_pSeqAvatar)
|
|
m_pSeqAvatar->SetVisibility(m_fHidingVisiblity);
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::UpdateState(SMSG_STATE* pMsg)
|
|
{
|
|
if (pMsg->state_level)
|
|
{
|
|
AddState(pMsg);
|
|
}
|
|
else if (pMsg->state_level == 0)
|
|
{
|
|
DeleteState(pMsg);
|
|
}
|
|
else
|
|
{
|
|
assert(0 && "상태 이상 데이타 이상!!!");
|
|
}
|
|
}
|
|
|
|
struct FuncSortEndTime
|
|
{
|
|
bool operator() (const SStateSlot* pr1, const SStateSlot* pr2) const
|
|
{
|
|
return pr1->GetEndTime() < pr2->GetEndTime();
|
|
}
|
|
};
|
|
|
|
void SGameAvatarEx::AddState(SMSG_STATE* pMsg)
|
|
{
|
|
int nPos(NULL);
|
|
SStateSlot* pOldState(GetOldStateInfo(pMsg, nPos));
|
|
SStateSlot* pOldCashState(GetOldCashStateInfo(pMsg, nPos));
|
|
|
|
if (pOldState) //이미 있는 것이니 레벨과 데이터만 갱신
|
|
{
|
|
StateInfoEx* s_data(GetTenacityDB().GetTenacityData(pMsg->state_code));
|
|
if (!s_data)
|
|
return;
|
|
|
|
pOldState->SetStateLevel(pMsg->state_level);
|
|
pOldState->SetStateTime(pMsg->start_time, pMsg->end_time);
|
|
pOldState->SetToggleType(pMsg->isToggle);
|
|
pOldState->SetStateValue(pMsg->state_value);
|
|
|
|
SIMSG_UI_STATE_LIST_UPDATE MSG(pMsg->handle, SIMSG_UI_STATE_LIST_UPDATE::STATE_CHANGE, s_data->is_harmful, nPos, pOldState);
|
|
SendGameInterfaceMsg(&MSG);
|
|
|
|
if (!pMsg->isToggle && IsLocalPlayer())
|
|
{
|
|
/// 2012.02.01 중첩 불가이고, 새로 걸리는 버프 일 때만 - prodongi
|
|
if (1 > s_data->reiteration_count)
|
|
{
|
|
if (pMsg->isNewState)
|
|
OutputAddStateSystemMsg(pMsg);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
//gmpbigsun(20131120): Sort
|
|
if (pOldState->IsHarmful())
|
|
std::sort(m_vecNegativeList.begin(), m_vecNegativeList.end(), FuncSortEndTime());
|
|
else
|
|
std::sort(m_vecPositiveList.begin(), m_vecPositiveList.end(), FuncSortEndTime());
|
|
|
|
SIMSG_UI_STATE_LIST_UPDATE MSG2(pMsg->handle, SIMSG_UI_STATE_LIST_UPDATE::STATE_REFRESH, false, 0, NULL);
|
|
SendGameInterfaceMsg(&MSG2);
|
|
//-----------------------------------------------------------------------
|
|
|
|
}
|
|
else if (pOldCashState)
|
|
{
|
|
StateInfoEx* s_data(GetTenacityDB().GetTenacityData(pMsg->state_code));
|
|
if (!s_data)
|
|
return;
|
|
|
|
pOldCashState->SetStateLevel(pMsg->state_level);
|
|
pOldCashState->SetStateTime(pMsg->start_time, pMsg->end_time);
|
|
pOldCashState->SetToggleType(pMsg->isToggle);
|
|
pOldCashState->SetStateValue(pMsg->state_value);
|
|
|
|
if (isMarkState(pMsg->state_code))
|
|
{
|
|
SIMSG_UI_STATE_LIST_UPDATE MSG(pMsg->handle, SIMSG_UI_STATE_LIST_UPDATE::STATE_UPDATE_MARK, s_data->is_harmful, nPos, pOldCashState);
|
|
SendGameInterfaceMsg(&MSG);
|
|
|
|
std::sort(m_vecMarkStateList.begin(), m_vecMarkStateList.end(), FuncSortEndTime());
|
|
SIMSG_UI_STATE_LIST_UPDATE MSG2(pMsg->handle, SIMSG_UI_STATE_LIST_UPDATE::STATE_REFRESH, false, 0, NULL);
|
|
SendGameInterfaceMsg(&MSG2);
|
|
|
|
}
|
|
else if (IsCashState(pMsg->state_code))
|
|
{
|
|
SIMSG_UI_STATE_LIST_UPDATE MSG(pMsg->handle, SIMSG_UI_STATE_LIST_UPDATE::STATE_CHANGE_CASH, s_data->is_harmful, nPos, pOldCashState);
|
|
SendGameInterfaceMsg(&MSG);
|
|
|
|
std::sort(m_vecCashStateList.begin(), m_vecCashStateList.end(), FuncSortEndTime());
|
|
SIMSG_UI_STATE_LIST_UPDATE MSG2(pMsg->handle, SIMSG_UI_STATE_LIST_UPDATE::STATE_REFRESH, false, 0, NULL);
|
|
SendGameInterfaceMsg(&MSG2);
|
|
}
|
|
else
|
|
__noop;
|
|
|
|
/// 2012.02.01 중첩 불가이고, 새로 걸리는 버프 일 때만 - prodongi
|
|
if (1 > s_data->reiteration_count)
|
|
{
|
|
if (pMsg->isNewState)
|
|
OutputAddStateSystemMsg(pMsg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int nIndex(0);
|
|
SStateSlot* pSlot = AddStateInfo(pMsg, nIndex);
|
|
if (!pSlot) return;
|
|
|
|
/// 2011.01.14 - prodongi
|
|
if (isMarkState(pMsg->state_code))
|
|
{
|
|
SIMSG_UI_STATE_LIST_UPDATE MSG(pMsg->handle, SIMSG_UI_STATE_LIST_UPDATE::STATE_UPDATE_MARK, false, 0, NULL);
|
|
SendGameInterfaceMsg(&MSG);
|
|
}
|
|
else if (IsCashState(pMsg->state_code))
|
|
{
|
|
SIMSG_UI_STATE_LIST_UPDATE MSG(pMsg->handle, SIMSG_UI_STATE_LIST_UPDATE::STATE_ADD_CASH, pSlot->IsHarmful(), nIndex, pSlot);
|
|
SendGameInterfaceMsg(&MSG);
|
|
}
|
|
else
|
|
{
|
|
SIMSG_UI_STATE_LIST_UPDATE MSG(pMsg->handle, SIMSG_UI_STATE_LIST_UPDATE::STATE_ADD, pSlot->IsHarmful(), nIndex, pSlot);
|
|
SendGameInterfaceMsg(&MSG);
|
|
}
|
|
|
|
if (IsLocalPlayer())
|
|
OutputAddStateSystemMsg(pMsg);
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::DeleteState(SMSG_STATE* pMsg)
|
|
{
|
|
StateInfoEx* s_data = GetTenacityDB().GetTenacityData(pMsg->state_code);
|
|
if (!s_data) return;
|
|
|
|
int nPos(0);
|
|
SStateSlot* pState = GetOldStateInfo(pMsg, nPos);
|
|
if (!pState) pState = GetOldCashStateInfo(pMsg, nPos);
|
|
if (!pState) return;
|
|
int nStateLv(pState->GetStateLevel());
|
|
|
|
int nIndex = DeleteStateInfo(pMsg->handle, pMsg->state_handle, pMsg->state_code);
|
|
if (nIndex != -1)
|
|
{
|
|
/// 2011.01.14 - prodongi
|
|
if (isMarkState(pMsg->state_code))
|
|
{
|
|
SIMSG_UI_STATE_LIST_UPDATE MSG(pMsg->handle, SIMSG_UI_STATE_LIST_UPDATE::STATE_UPDATE_MARK, false, 0, NULL);
|
|
SendGameInterfaceMsg(&MSG);
|
|
}
|
|
else if (IsCashState(pMsg->state_code))
|
|
{
|
|
SIMSG_UI_STATE_LIST_UPDATE MSG(pMsg->handle, SIMSG_UI_STATE_LIST_UPDATE::STATE_DELETE_CASH, s_data->is_harmful, nIndex, NULL);
|
|
SendGameInterfaceMsg(&MSG);
|
|
}
|
|
else
|
|
{
|
|
SIMSG_UI_STATE_LIST_UPDATE MSG(pMsg->handle, SIMSG_UI_STATE_LIST_UPDATE::STATE_DELETE, s_data->is_harmful, nIndex, NULL);
|
|
SendGameInterfaceMsg(&MSG);
|
|
}
|
|
|
|
if (IsLocalPlayer())
|
|
OutputDeleteStateSystemMsg(pMsg, nStateLv);
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::OutputAddStateSystemMsg(SMSG_STATE* pMsg)
|
|
{
|
|
// _performance_print( "%d - %d - %d - %d - %d [ %d %d ]\n", pMsg->handle, pMsg->state_handle, pMsg->state_code, pMsg->state_level, pMsg->data_owner, pMsg->end_time, pMsg->start_time );
|
|
|
|
std::string strTextMsg;
|
|
StateInfoEx* pStateInfo = GetTenacityDB().GetTenacityData(pMsg->state_code);
|
|
|
|
std::string strStateNAme(GetStringDB().GetString(GetTenacityDB().GetNameID(pMsg->state_code)));
|
|
if (pStateInfo && !pStateInfo->is_harmful) //이로운 스킬
|
|
{
|
|
strTextMsg = SR(SYS_MSG_USE_BUFF, "#@skill_name@#", strStateNAme.c_str(), "#@skill_level@#", pMsg->state_level);
|
|
// AziaMafia Fix String 96
|
|
strTextMsg = SR(SYS_MSG_USE_BUFF, "#@s@#", strStateNAme.c_str());
|
|
}
|
|
else
|
|
{
|
|
strTextMsg = SR(SYS_MSG_GET_DEBUFF, "#@skill_name@#", strStateNAme.c_str(), "#@skill_level@#", pMsg->state_level);
|
|
// AziaMafia Fix String 96
|
|
strTextMsg = SR(SYS_MSG_GET_DEBUFF, "#@s@#", strStateNAme.c_str());
|
|
}
|
|
|
|
|
|
if (!strTextMsg.empty()) m_pMsgHandler->AddChatMessage(strTextMsg.c_str());
|
|
}
|
|
|
|
void SGameAvatarEx::OutputDeleteStateSystemMsg(SMSG_STATE* pMsg, int nLv)
|
|
{
|
|
std::string strTextMsg = SStringDB::ParseString(GetStringDB().GetString(SYS_MSG_DISABLE_BUFF),
|
|
"#@skill_name@#", GetStringDB().GetString(GetTenacityDB().GetNameID(pMsg->state_code)),
|
|
"#@skill_level@#", SStringDB::ToString(nLv).c_str());
|
|
|
|
// AziaMafia Fix String 96
|
|
strTextMsg = SStringDB::ParseString(GetStringDB().GetString(SYS_MSG_DISABLE_BUFF),
|
|
"#@s@#", GetStringDB().GetString(GetTenacityDB().GetNameID(pMsg->state_code)));
|
|
|
|
if (!strTextMsg.empty()) m_pMsgHandler->AddChatMessage(strTextMsg.c_str());
|
|
}
|
|
|
|
SStateSlot* SGameAvatarEx::GetOldStateInfo(SMSG_STATE* pMsg, int& nOutPos)
|
|
{
|
|
iterator_state_slot PositiveIt = m_vecPositiveList.begin();
|
|
iterator_state_slot NegativeIt = m_vecNegativeList.begin();
|
|
|
|
int nPos(0);
|
|
while (true)
|
|
{
|
|
//이로운 지속효과와 해로운 지속효과를 모두 순환하였으니 break;
|
|
if (PositiveIt == m_vecPositiveList.end() && NegativeIt == m_vecNegativeList.end())
|
|
break;
|
|
|
|
//이로운 지속효과
|
|
if (PositiveIt != m_vecPositiveList.end())
|
|
{
|
|
if (IsEqualState(*PositiveIt, pMsg))
|
|
{
|
|
nOutPos = nPos;
|
|
return *PositiveIt;
|
|
}
|
|
|
|
++PositiveIt;
|
|
}
|
|
|
|
//해로운 지속효과
|
|
if (NegativeIt != m_vecNegativeList.end())
|
|
{
|
|
if (IsEqualState(*NegativeIt, pMsg))
|
|
{
|
|
nOutPos = nPos;
|
|
return *NegativeIt;
|
|
}
|
|
|
|
++NegativeIt;
|
|
}
|
|
++nPos;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
SStateSlot* SGameAvatarEx::GetOldCashStateInfo(SMSG_STATE* pMsg, int& nOutPos)
|
|
{
|
|
/// 2012.08.08 m_vecMarkStateList도 캐쉬 아이템에 해당 되기 때문에 같이 검사함 - prodongi
|
|
SStateSlot* stat = GetStateInfo(m_vecCashStateList, pMsg, nOutPos);
|
|
if (stat)
|
|
return stat;
|
|
|
|
stat = GetStateInfo(m_vecMarkStateList, pMsg, nOutPos);
|
|
if (stat)
|
|
return stat;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
SStateSlot* SGameAvatarEx::GetStateInfo(vec_state_slot const& stateList, SMSG_STATE* pMsg, int& nOutPos)
|
|
{
|
|
vec_state_slot::const_iterator it = stateList.begin();
|
|
|
|
int nPos(0);
|
|
while (it != stateList.end())
|
|
{
|
|
if (IsEqualState(*it, pMsg))
|
|
{
|
|
nOutPos = nPos;
|
|
return *it;
|
|
}
|
|
++it;
|
|
++nPos;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
StateInfoEx* SGameAvatarEx::GetStateDBInfo(STATE_TYPE nType)
|
|
{
|
|
/// 2011.01.14 - prodongi
|
|
StateInfoEx* pStateInfo = NULL;
|
|
|
|
pStateInfo = GetStateDBInfo(m_vecPositiveList, nType);
|
|
if (pStateInfo) return pStateInfo;
|
|
|
|
pStateInfo = GetStateDBInfo(m_vecNegativeList, nType);
|
|
if (pStateInfo) return pStateInfo;
|
|
|
|
pStateInfo = GetStateDBInfo(m_vecCashStateList, nType);
|
|
if (pStateInfo) return pStateInfo;
|
|
|
|
pStateInfo = GetStateDBInfo(m_vecMarkStateList, nType);
|
|
if (pStateInfo) return pStateInfo;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/// 2011.01.14 - prodongi
|
|
StateInfoEx* SGameAvatarEx::GetStateDBInfo(vec_state_slot const& stateList, STATE_TYPE nType)
|
|
{
|
|
vec_state_slot::const_iterator iter = stateList.begin();
|
|
for (; iter != stateList.end(); ++iter)
|
|
{
|
|
StateInfoEx* pStateInfo = GetTenacityDB().GetTenacityData((*iter)->GetStateCode());
|
|
if (pStateInfo == NULL) continue;
|
|
|
|
if (pStateInfo->effect_type == nType) return pStateInfo;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
bool SGameAvatarEx::IsEqualState(SStateSlot* pInfo, SMSG_STATE* pMsg)
|
|
{
|
|
if (!pInfo || !pMsg) return false;
|
|
|
|
return IsEqualState(pInfo, pMsg->handle, pMsg->state_handle, pMsg->state_code);
|
|
}
|
|
|
|
bool SGameAvatarEx::IsEqualState(SStateSlot* pInfo, AR_HANDLE hTarget, AR_HANDLE hState, unsigned int state_code)
|
|
{
|
|
if (!pInfo) return false;
|
|
|
|
if (pInfo->GetTargetHandle() == hTarget &&
|
|
pInfo->GetStateHandle() == hState &&
|
|
pInfo->GetStateCode() == state_code)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
SStateSlot* SGameAvatarEx::AddStateInfo(SMSG_STATE* pMsg, int& nIndex)
|
|
{
|
|
SStateSlot* pState = new SStateSlot;
|
|
pState->SetTargetHandle(pMsg->handle);
|
|
pState->SetStateHandle(pMsg->state_handle);
|
|
pState->SetStateCode(pMsg->state_code);
|
|
pState->SetStateLevel(pMsg->state_level);
|
|
pState->SetStateValue(pMsg->state_value);
|
|
pState->SetToggleType(pMsg->isToggle);
|
|
pState->SetStateTime(pMsg->start_time, pMsg->end_time);
|
|
|
|
StateInfoEx* s_data = GetTenacityDB().GetTenacityData(pMsg->state_code);
|
|
if (s_data)
|
|
{
|
|
vec_state_slot* pvStateList = NULL;
|
|
|
|
/// 2011.01.14 - prodongi
|
|
if (isMarkState(pMsg->state_code))
|
|
{
|
|
pvStateList = &m_vecMarkStateList;
|
|
}
|
|
else if (IsCashState(pMsg->state_code))
|
|
{
|
|
pvStateList = &m_vecCashStateList;
|
|
}
|
|
else
|
|
{
|
|
pState->SetStateHarmful(s_data->is_harmful);
|
|
if (s_data->is_harmful)
|
|
pvStateList = &m_vecNegativeList;
|
|
else
|
|
pvStateList = &m_vecPositiveList;
|
|
}
|
|
|
|
pvStateList->push_back(pState);
|
|
|
|
//gmpbigsun(20131119) : 종료시간기준 sort
|
|
std::sort(pvStateList->begin(), pvStateList->end(), FuncSortEndTime());
|
|
}
|
|
else
|
|
{
|
|
SAFE_DELETE(pState);
|
|
}
|
|
return pState;
|
|
}
|
|
|
|
int SGameAvatarEx::DeleteStateInfo(AR_HANDLE hTarget, AR_HANDLE hState, unsigned int state_code)
|
|
{
|
|
/// 2011.01.14 - prodongi
|
|
if (isMarkState(state_code))
|
|
{
|
|
int nIndexpos(0);
|
|
iterator_state_slot it = m_vecMarkStateList.begin();
|
|
while (it != m_vecMarkStateList.end())
|
|
{
|
|
SStateSlot* pSlot = *it;
|
|
if (pSlot->GetStateCode() == state_code)
|
|
{
|
|
SAFE_DELETE(pSlot);
|
|
m_vecMarkStateList.erase(it);
|
|
return nIndexpos;
|
|
}
|
|
++it;
|
|
++nIndexpos;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
if (IsCashState(state_code))
|
|
{
|
|
int nIndexpos(0);
|
|
iterator_state_slot it = m_vecCashStateList.begin();
|
|
while (it != m_vecCashStateList.end())
|
|
{
|
|
SStateSlot* pSlot = *it;
|
|
if (pSlot->GetStateCode() == state_code)
|
|
{
|
|
SAFE_DELETE(pSlot);
|
|
m_vecCashStateList.erase(it);
|
|
return nIndexpos;
|
|
}
|
|
++it;
|
|
++nIndexpos;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
iterator_state_slot NegativeIt = m_vecNegativeList.begin();
|
|
iterator_state_slot PositiveIt = m_vecPositiveList.begin();
|
|
|
|
int nPos(0);
|
|
while (true)
|
|
{
|
|
//이로운 지속효과와 해로운 지속효과를 모두 순환하였으니 break;
|
|
if (PositiveIt == m_vecPositiveList.end() && NegativeIt == m_vecNegativeList.end())
|
|
break;
|
|
|
|
//이로운 지속효과
|
|
if (PositiveIt != m_vecPositiveList.end())
|
|
{
|
|
if (IsEqualState(*PositiveIt, hTarget, hState, state_code))
|
|
{
|
|
SAFE_DELETE((*PositiveIt));
|
|
PositiveIt = m_vecPositiveList.erase(PositiveIt);
|
|
return nPos;
|
|
}
|
|
else ++PositiveIt;
|
|
}
|
|
|
|
//해로운 지속효과
|
|
if (NegativeIt != m_vecNegativeList.end())
|
|
{
|
|
if (IsEqualState(*NegativeIt, hTarget, hState, state_code))
|
|
{
|
|
SAFE_DELETE((*NegativeIt));
|
|
NegativeIt = m_vecNegativeList.erase(NegativeIt);
|
|
return nPos;
|
|
}
|
|
else ++NegativeIt;
|
|
}
|
|
++nPos;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
bool SGameAvatarEx::IsCashState(unsigned int state_code)
|
|
{
|
|
for (int i(0); i < c_nMaxCashState; ++i)
|
|
{
|
|
if (c_nCashStateId[i] == state_code)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// 2011.01.14 - prodongi
|
|
bool SGameAvatarEx::isMarkState(unsigned int state_code) const
|
|
{
|
|
if (9004 == state_code || /// 시크루트 프리패스
|
|
9005 == state_code || /// 라펠즈 pc방
|
|
9006 == state_code) /// 라펠즈 더블 plus pc방
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void SGameAvatarEx::GetAllStateList(vec_state_slot& rStateList, bool bAddCashState)
|
|
{
|
|
rStateList.clear();
|
|
|
|
int nSize = 0;
|
|
if (bAddCashState)
|
|
{
|
|
nSize = (int)m_vecCashStateList.size();
|
|
for (int i(0); i < nSize; ++i)
|
|
rStateList.push_back(m_vecCashStateList[i]);
|
|
|
|
/// 2011.01.14 - prodongi
|
|
nSize = (int)m_vecMarkStateList.size();
|
|
for (int i(0); i < nSize; ++i)
|
|
rStateList.push_back(m_vecMarkStateList[i]);
|
|
}
|
|
|
|
nSize = (int)m_vecPositiveList.size();
|
|
for (int i(0); i < nSize; ++i)
|
|
rStateList.push_back(m_vecPositiveList[i]);
|
|
|
|
nSize = (int)m_vecNegativeList.size();
|
|
for (int i(0); i < nSize; ++i)
|
|
rStateList.push_back(m_vecNegativeList[i]);
|
|
}
|
|
|
|
bool SGameAvatarEx::HaveState(bool bAddCashState)
|
|
{
|
|
if (HavePositiveState() || HaveNegativeState())
|
|
return true;
|
|
if (bAddCashState && HaveCashState())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void SGameAvatarEx::clearAllState()
|
|
{
|
|
for (unsigned int i(0); m_vecPositiveList.size() > i; i++) //현재 상태 이상 리스트
|
|
{
|
|
SAFE_DELETE(m_vecPositiveList[i]);
|
|
}
|
|
for (unsigned int i(0); m_vecNegativeList.size() > i; i++) //현재 상태 이상 리스트
|
|
{
|
|
SAFE_DELETE(m_vecNegativeList[i]);
|
|
}
|
|
for (unsigned int i(0); m_vecCashStateList.size() > i; i++) //현재 상태 이상 리스트
|
|
{
|
|
SAFE_DELETE(m_vecCashStateList[i]);
|
|
}
|
|
/// 2011.01.14 - prodongi
|
|
for (unsigned int i(0); m_vecMarkStateList.size() > i; i++) //현재 상태 이상 리스트
|
|
{
|
|
SAFE_DELETE(m_vecMarkStateList[i]);
|
|
}
|
|
|
|
m_vecPositiveList.clear();
|
|
m_vecNegativeList.clear();
|
|
m_vecCashStateList.clear();
|
|
/// 2011.01.14 - prodongi
|
|
m_vecMarkStateList.clear();
|
|
}
|
|
|
|
bool SGameAvatarEx::CurrentlyAnimationIsLoopWrap()
|
|
{
|
|
return m_nProcess_state == KSeqAvatar::SEQINFO_LOOPWRAP ? true : false;
|
|
}
|
|
|
|
void SGameAvatarEx::UnMountFallUnSummon()
|
|
{
|
|
if (m_pStateVM == NULL) return;
|
|
|
|
if (m_pStateVM->GetMode() == SObjectStateMachine::MODE_MOUNT)
|
|
{
|
|
m_pStateVM->SetMode(SObjectStateMachine::MODE_NORMAL);
|
|
m_pStateVM->StopCurrentState();
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::SetSkinDiffuse(KColor& diffuse)
|
|
{
|
|
m_SkinDiffuse.r = diffuse.r;
|
|
m_SkinDiffuse.g = diffuse.g;
|
|
m_SkinDiffuse.b = diffuse.b;
|
|
m_SkinDiffuse.a = diffuse.a / 255;
|
|
|
|
if (m_pSeqAvatar) m_pSeqAvatar->SetSkinDiffuse(m_SkinDiffuse);
|
|
}
|
|
|
|
void SGameAvatarEx::RefreshItemWear()
|
|
{
|
|
ClearThreadLoadWear();
|
|
|
|
for (unsigned int i(0); m_vWearListForRefresh.size() > i; ++i)
|
|
{
|
|
//m_vWearList_Thread.push_back( m_vWearListForRefresh[i] );
|
|
AddThreadItemWear(m_vWearListForRefresh[i]);
|
|
}
|
|
m_vWearListForRefresh.clear();
|
|
}
|
|
|
|
void SGameAvatarEx::RefreshAllStateEffect()
|
|
{
|
|
vec_state_slot vecStateList;
|
|
GetAllStateList(vecStateList, false);
|
|
|
|
SGameOption& gameoption = GetGameOption();
|
|
|
|
SMSG_STATE state;
|
|
SStateSlot* pStateSlot = NULL;
|
|
|
|
iterator_state_slot iter = vecStateList.begin();
|
|
for (; iter != vecStateList.end(); ++iter)
|
|
{
|
|
pStateSlot = (*iter);
|
|
if (pStateSlot == NULL) continue;
|
|
|
|
state.handle = pStateSlot->GetTargetHandle();
|
|
state.state_handle = pStateSlot->GetStateHandle();
|
|
state.state_code = pStateSlot->GetStateCode();
|
|
state.state_level = pStateSlot->GetStateLevel();
|
|
state.end_time = pStateSlot->GetEndTime();
|
|
|
|
if (state.end_time == (AR_TIME)(-1))
|
|
{ //토글형 스킬 임
|
|
state.isToggle = true;
|
|
}
|
|
|
|
DelStateEffect(&state);
|
|
|
|
bool bAdd = false;
|
|
if (IsLocalPlayer() || IsLocalCreature() || gameoption.IsStatePlayerEftRend())
|
|
bAdd = true;
|
|
else if (gameoption.IsStatePartyEftRend())
|
|
{
|
|
if (GetObjType() == TS_ENTER::GAME_SUMMON)
|
|
{
|
|
if (IsPartyRaidMemeber(GetMaster()))
|
|
bAdd = true;
|
|
}
|
|
else
|
|
{
|
|
if (IsPartyRaidMemeber(GetArID()))
|
|
bAdd = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (gameoption.IsStateEnemyEftRend())
|
|
bAdd = true;
|
|
}
|
|
|
|
if (GetStatus() & TS_ENTER::CreatureInfo::FLAG_INVISIBLE ||
|
|
GetStateFlag() & SGameAvatarEx::FLAG_STATE_HIDING)
|
|
{
|
|
bAdd = false; //Invisible모드이거나 은신모드일경우 이펙트를 보여주지 않는다
|
|
}
|
|
|
|
if (bAdd) AddStateEffect(&state);
|
|
}
|
|
}
|
|
|
|
void SGameAvatarEx::RemoveAllStateEffect()
|
|
{
|
|
vec_state_slot vecStateList;
|
|
GetAllStateList(vecStateList, false);
|
|
|
|
SMSG_STATE state;
|
|
SStateSlot* pStateSlot = NULL;
|
|
|
|
iterator_state_slot iter = vecStateList.begin();
|
|
for (; iter != vecStateList.end(); ++iter)
|
|
{
|
|
pStateSlot = (*iter);
|
|
if (pStateSlot == NULL) continue;
|
|
|
|
state.handle = pStateSlot->GetTargetHandle();
|
|
state.state_handle = pStateSlot->GetStateHandle();
|
|
state.state_code = pStateSlot->GetStateCode();
|
|
state.state_level = pStateSlot->GetStateLevel();
|
|
state.end_time = pStateSlot->GetEndTime();
|
|
|
|
DelStateEffect(&state);
|
|
}
|
|
}
|
|
|
|
// 죽을때 모션이 두개이기 때문에 모션 선택하는 부분을 따로 함수로 뺐다.
|
|
void SGameAvatarEx::EnterDeadAnimation()
|
|
{
|
|
NPlayAnimation(ANI_DEAD01, SEQTYPE_NORMAL);
|
|
}
|
|
|
|
// 가상함수로 만들어서 AvatarEx의 하위클래스들에 맞게 바꿔야 함..
|
|
int SGameAvatarEx::GetAnimationLength(int ani_id)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
bool SGameAvatarEx::ExistAnimation(int ani_id)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
#ifndef _EQUATION
|
|
bool SGameAvatarEx::IsInDeathMatch()
|
|
{
|
|
int x = GetPosition()->x;
|
|
int y = GetPosition()->y;
|
|
|
|
if (
|
|
(x >= 193536 && x <= 201600
|
|
&& y >= 104832 && y <= 112896)
|
|
|| (x >= 201600 && x <= 209664
|
|
&& y >= 104832 && y <= 112896)
|
|
|
|
|| (x >= 193536 && x <= 201600
|
|
&& y >= 96768 && y <= 104832)
|
|
|| (x >= 201600 && x <= 209664
|
|
&& y >= 96768 && y <= 104832)
|
|
|
|
|| (x >= 193536 && x <= 201600
|
|
&& y >= 88704 && y <= 96768)
|
|
|| (x >= 201600 && x <= 209664
|
|
&& y >= 88704 && y <= 96768)
|
|
|
|
|| (x >= 193536 && x <= 201600
|
|
&& y >= 80640 && y <= 88704)
|
|
|| (x >= 201600 && x <= 209664
|
|
&& y >= 80640 && y <= 88704)
|
|
) // 데스매치
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#else
|
|
|
|
bool SGameAvatarEx::IsInDeathMatch()
|
|
{
|
|
return GetCurrentLocation() == PLAYER_IN_DEATHMATCH;
|
|
}
|
|
#endif
|
|
|
|
bool SGameAvatarEx::IsInBearroad()
|
|
{
|
|
int x = GetPosition()->x;
|
|
int y = GetPosition()->y;
|
|
|
|
if (x >= 84435 && x <= 94471
|
|
&& y >= 4320 && y <= 12343)// 베어로드 안쪽임.
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool SGameAvatarEx::IsInBearroadLobby()
|
|
{
|
|
int x = GetPosition()->x;
|
|
int y = GetPosition()->y;
|
|
|
|
if (x >= 81831 && x <= 85288
|
|
&& y >= 636 && y <= 4295)// 베어로드 대기실
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void SGameAvatarEx::setHairThreadData(SMSG_HAIR_INFO* msg)
|
|
{
|
|
m_hairThreadData.m_isRecv = true;
|
|
m_hairThreadData.m_hairId = msg->nHairID;
|
|
m_hairThreadData.m_hairColorIndex = msg->nHairColorIndex;
|
|
m_hairThreadData.m_hairColorRgb = msg->nHairColorRGB;
|
|
}
|
|
|
|
void SGameAvatarEx::procHairThreadData()
|
|
{
|
|
if (IsThreadLoading()) return;
|
|
if (m_bPendLoading) return;
|
|
if (!m_hairThreadData.m_isRecv) return;
|
|
if (!m_pSeqAvatar) return;
|
|
|
|
m_hairThreadData.m_isRecv = false;
|
|
SetHairID(m_hairThreadData.m_hairId);
|
|
SetHairColorIndex(m_hairThreadData.m_hairColorIndex);
|
|
SetHairColorRGB(m_hairThreadData.m_hairColorRgb);
|
|
|
|
// 2010.06.10 머리 장식/투구가 있는지 체크, 헤어가 보일 경우는 제외 - prodongi
|
|
KSeqAvatar* avatarPart = m_pSeqAvatar->getAvatarPart(ANIPART_BIPED);
|
|
if (avatarPart->isDecoMeshCheck() && avatarPart->isRenderDecoMesh(MDECOPART_HELM) && 1 == avatarPart->IsExistDecoMesh(MDECOPART_HELM) && !avatarPart->isRenderMesh(MPART_HAIR))
|
|
return;
|
|
// 2010.07.26 헬멧을 장착하고 있어도 헤어가 보일 경우는 제외- prodongi
|
|
if (avatarPart->isMeshCheck() && avatarPart->isRenderMesh(MPART_HELM) && 1 == avatarPart->IsExistMesh(MPART_HELM) && !avatarPart->isRenderMesh(MPART_HAIR))
|
|
return;
|
|
|
|
doLoadingHair(m_pSeqAvatar);
|
|
RefreshSkinColorized();
|
|
m_pSeqAvatar->SetDeform(ANIPART_BIPED);
|
|
m_pSeqAvatar->SetAttach(ANIPART_BIPED);
|
|
|
|
if (IsLocalPlayer())
|
|
m_bRefreshInven = true;
|
|
|
|
g_pCurrentGameSystem->updateCurTarget(GetArID());
|
|
}
|
|
|
|
void SGameAvatarEx::doLoadingHair(KSeqAvatarEx* avatar)
|
|
{
|
|
std::string modelName = GetDefaultItemDB().GetFileName(GetRace(), GetSex(), GetHair());
|
|
int nGroup = GetDefaultItemDB().GetDecoHairGroupID(GetHair());
|
|
std::string texName = GetDefaultTextureResourceDB().GetTextureName(nGroup, m_nHairColorIndex, GetRace(), GetSex());
|
|
avatar->AddMesh(ANIPART_BIPED, MPART_HAIR, modelName.c_str(), texName);
|
|
}
|
|
|
|
// 2010.06.18 - prodongi
|
|
void SGameAvatarEx::getDecoTexName(std::string& texName)
|
|
{
|
|
int nGroup = GetDefaultItemDB().GetDecoFaceGroupID(GetFace());
|
|
texName = GetDefaultTextureResourceDB().GetTextureName(nGroup, getDecoIndex(), GetRace(), GetSex());
|
|
}
|
|
|
|
// MTE
|
|
void SGameAvatarEx::EnableMTE(bool bEnable, const char* szFileName)
|
|
{
|
|
if (TS_ENTER::GAME_MOB != GetInnObjType() && TS_ENTER::GAME_SUMMON != GetInnObjType())
|
|
return;
|
|
|
|
_CID(SET_MTETEX);
|
|
|
|
std::string strMteTexName;
|
|
KMsgSET_MTETEX kMsg;
|
|
kMsg.pTexture = NULL;
|
|
|
|
if (NULL != szFileName)
|
|
strMteTexName = szFileName;
|
|
else
|
|
{
|
|
std::string strCobName = GetCobFileName();
|
|
if (strCobName.find(".cob") == std::string::npos)
|
|
strCobName += ".cob";
|
|
|
|
vec_cobset* coblist = COBManager::GetManager()->Load(strCobName.c_str());
|
|
if (coblist)
|
|
{
|
|
if (coblist->empty())
|
|
return;
|
|
|
|
COBSET* pCob = (*coblist)[0];
|
|
|
|
strMteTexName = pCob->m_strCameraCollisionFile;
|
|
}
|
|
}
|
|
|
|
|
|
//텍스쳐 정보가 유효한경우만 적용
|
|
if (true == strMteTexName.empty() || strMteTexName.find('.') == std::string::npos)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (bEnable)
|
|
{
|
|
NX3LoadPack loadpack;
|
|
loadpack.Init();
|
|
kMsg.pTexture = KTextureManager::GetManager()->GetTexture(strMteTexName.c_str(), &loadpack);
|
|
}
|
|
else
|
|
kMsg.pTexture = NULL;
|
|
}
|
|
|
|
if (m_pSeqAvatar)
|
|
m_pSeqAvatar->Perform(id_SET_MTETEX, kMsg);
|
|
}
|
|
|
|
/// 2011.04.20 거대화 처리 시작 - prodongi
|
|
void SGameAvatarEx::beginScaling(float& scale, K3DMatrix& oldTM)
|
|
{
|
|
std::vector<SStateSlot*> PositiveList = GetPositiveStateList();
|
|
|
|
/// 2012.08.10 가장 큰 스케일 값이 적용되도록 한다 - prodongi
|
|
m_fScaleAdjustDest = -1.0f;
|
|
for (size_t i = 0; i < PositiveList.size(); i++)
|
|
{
|
|
bool bflag = false;
|
|
StateInfoEx* info = GetTenacityDB().GetTenacityData(PositiveList[i]->GetStateCode());
|
|
|
|
if (GetStatus() & TS_ENTER::PlayerInfo::FLAG_SELL_BOOTH || GetStatus() & TS_ENTER::PlayerInfo::FLAG_BUY_BOOTH)
|
|
bflag = true;
|
|
|
|
if (info->fValue[6] == 128 && !bflag)
|
|
{
|
|
float fScaleLev = (float)info->fValue[7] + ((float)info->fValue[8] * (float)PositiveList[i]->GetStateLevel());
|
|
m_fScaleAdjustDest = ::max(m_fScaleAdjustDest, fScaleLev);
|
|
|
|
if (m_fScaleAdjustDest <= 0.0f)
|
|
m_fScaleAdjustDest = 1.0f;
|
|
//m_fScaleAdjustDest = ::max(m_fScaleAdjustDest, (float)info->fValue[7]);
|
|
}
|
|
if (info->fValue[9] == 128)
|
|
m_fScaleAdjustDest = ::max(m_fScaleAdjustDest, (float)info->fValue[10]);
|
|
}
|
|
if (-1.0f >= m_fScaleAdjustDest)
|
|
m_fScaleAdjustDest = 1.0f;
|
|
|
|
scale = 1.0f;
|
|
DWORD nowTime = GetSafeTickCount();
|
|
if (m_fScaleAdjustPrev == m_fScaleAdjustDest)
|
|
{
|
|
scale = m_fScaleAdjustDest;
|
|
}
|
|
else
|
|
{
|
|
if (m_nScaleAdjustStartTime == 0) m_nScaleAdjustStartTime = nowTime;
|
|
|
|
float ratio = (nowTime - m_nScaleAdjustStartTime) / 1000.0f;
|
|
scale = m_fScaleAdjustPrev * (1 - ratio) + m_fScaleAdjustDest * ratio;
|
|
if (ratio > 1.0f)
|
|
{
|
|
m_nScaleAdjustStartTime = 0;
|
|
scale = m_fScaleAdjustDest;
|
|
m_fScaleAdjustPrev = m_fScaleAdjustDest;
|
|
}
|
|
}
|
|
|
|
oldTM = *GetTransform();
|
|
SetScalePure(scale);
|
|
m_fSelcube[5] = m_fOriginalSelCubeHeight * scale;
|
|
}
|
|
|
|
/// 2011.04.20 거대화 처리 종료 - prodongi
|
|
void SGameAvatarEx::endScaling(float scale, K3DMatrix const& oldTM)
|
|
{
|
|
SetTransformPure(oldTM);
|
|
|
|
m_fScaleAdjust = scale;
|
|
}
|
|
|
|
/// 2011.04.21 - prodongi
|
|
void SGameAvatarEx::setCameraRoll(float angle)
|
|
{
|
|
if (sMathUtil::isEqual(m_fPresentRoll, angle))
|
|
return;
|
|
|
|
m_fPresentRoll = angle;
|
|
m_fTargetRoll = angle;
|
|
m_dwPrevTime = m_dwTime;
|
|
m_syncCamRoll = true;
|
|
m_kmoveDir = angle;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------------------
|
|
// 의상 파일 이름을 재 로딩한다.
|
|
//-----------------------------------------------------------------------------------------------------------------
|
|
void SGameAvatarEx::ReloadWearListFileName(std::vector<WEAR_DATA>& wearList)
|
|
{
|
|
int nSex(GetSex());
|
|
int nRace(GetRace());
|
|
|
|
for (UINT nCount = 0; nCount < wearList.size(); nCount++)
|
|
{
|
|
WEAR_DATA* pWearData(&wearList[nCount]);
|
|
if (NULL == pWearData)
|
|
continue;
|
|
|
|
int nitemCode(pWearData->nItemCode);
|
|
|
|
if (nitemCode < 10000) // 기본 Mesh
|
|
{
|
|
if (nitemCode != 0)
|
|
pWearData->strFileName = GetDefaultItemDB().GetFileName(nRace, nSex, nitemCode);
|
|
else
|
|
pWearData->strFileName = "_NoItem_";
|
|
}
|
|
else
|
|
{
|
|
if (pWearData->nAppearanceItemCode)
|
|
pWearData->strFileName = GetItemDB().GetFileName(nRace, nSex, pWearData->nAppearanceItemCode, pWearData->nItemLevel);
|
|
else
|
|
pWearData->strFileName = GetItemDB().GetFileName(nRace, nSex, pWearData->nItemCode, pWearData->nItemLevel);
|
|
|
|
pWearData->strFileName += ".nx3";
|
|
}
|
|
|
|
if (pWearData->bWithDecoItem)
|
|
{
|
|
if (pWearData->nAppearanceItemCode)
|
|
pWearData->strDecoFileName = GetItemDB().GetFileName(nRace, nSex, pWearData->nAppearanceItemCode, pWearData->nItemLevel);
|
|
else
|
|
pWearData->strDecoFileName = GetItemDB().GetFileName(nRace, nSex, pWearData->nDecoItemCode, pWearData->nItemLevel);
|
|
pWearData->strDecoFileName += ".nx3";
|
|
}
|
|
}
|
|
}
|