#include "stdafx.h" #include // 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 #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 #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 /// 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 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(rightHandSeq->GetCurrentAnimation()); if (sequencer != NULL) { boneSeqRightWeapon = dynamic_cast (sequencer->GetSeqObject(0)); } KSeqAvatar* leftHandSeq = seqAvatar->getAvatarPart(ANIPART_WEAPON_LEFT); // 왼손 무기가 붙을 위치 sequencer = dynamic_cast(leftHandSeq->GetCurrentAnimation()); if (sequencer != NULL) { boneSeqLeftWeapon = dynamic_cast (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(_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::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(rightHandSeq->GetCurrentAnimation()); // if (sequencer!=NULL) { // boneSeqRightWeapon=dynamic_cast (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(leftHandSeq->GetCurrentAnimation()); // if (sequencer!=NULL) { // boneSeqLeftWeapon=dynamic_cast (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 PositiveList = GetPositiveStateList(); m_fScaleAdjustDest = 1.0f; for (size_t i=0; iGetStateCode()); 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 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(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(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(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(m_pSeqAvatar->GetMesh(aniPart, partNo)); // ANIPART_WEAPON_RIGHT, MPART_R_WEAPON // if (seq!=NULL) // { // KMeshSeqObject *meshseq=dynamic_cast(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::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::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(pRightHandSeq->GetCurrentAnimation()); if (pSequencer != NULL) { pBoneSeqRightWeapon = dynamic_cast (pSequencer->GetSeqObject(0)); } KSeqAvatar* pLeftHandSeq = pSeqAvatar->getAvatarPart(ANIPART_WEAPON_LEFT); pSequencer = dynamic_cast(pLeftHandSeq->GetCurrentAnimation()); if (pSequencer != NULL) { pBoneSeqLeftWeapon = dynamic_cast (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 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& 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"; } } }