diff --git a/src/Client/WarFare/GameDef.h b/src/Client/WarFare/GameDef.h index 5c4018840..cffbb3cc9 100644 --- a/src/Client/WarFare/GameDef.h +++ b/src/Client/WarFare/GameDef.h @@ -427,7 +427,6 @@ struct __InfoPlayerOther int iKnightsGrade; // Clan grade int iKnightsRank; // Clan ranking - int iRank; // Noble rank - used to identify high-ranking titles like King [1], Senator [2]. int iTitle; // Bitmask representing various titles/roles including: // Clan Leader, Clan Assistant, Castle Lord, Feudal Lord, King, Emperor, Party leader, Solo player diff --git a/src/Client/WarFare/GameProcMain.cpp b/src/Client/WarFare/GameProcMain.cpp index 76a620e26..9779cc2a7 100644 --- a/src/Client/WarFare/GameProcMain.cpp +++ b/src/Client/WarFare/GameProcMain.cpp @@ -1088,6 +1088,9 @@ bool CGameProcMain::ProcessPacket(Packet& pkt) } } break; + case WIZ_SERVER_INDEX: + this->MsgRecv_ServerIndex(pkt); + return true; case WIZ_ITEM_UPGRADE: MsgRecv_ItemUpgrade(pkt); @@ -1867,7 +1870,7 @@ bool CGameProcMain::MsgRecv_MyInfo_All(Packet& pkt) __ASSERT(pLooks, "failed find character resource data"); s_pPlayer->InitChr(pLooks); // 관절 세팅.. - s_pPlayer->m_InfoExt.iRank = pkt.read(); + s_pPlayer->m_InfoBase.iRank = pkt.read(); s_pPlayer->m_InfoExt.iTitle = pkt.read(); s_pPlayer->m_InfoBase.iLevel = pkt.read(); s_pPlayer->m_InfoExt.iLevelPrev = s_pPlayer->m_InfoBase.iLevel; @@ -1890,16 +1893,17 @@ bool CGameProcMain::MsgRecv_MyInfo_All(Packet& pkt) /*int iAllianceID =*/pkt.read(); /*uint8_t byFlag =*/pkt.read(); - int iKnightNameLen = pkt.read(); // 소속 기사단 이름 길이. + int iKnightNameLen = pkt.read(); // 소속 기사단 이름 길이. pkt.readString(szKnightsName, iKnightNameLen); - int iKnightsGrade = pkt.read(); // 소속 기사단 등급 - int iKnightsRank = pkt.read(); // 소속 기사단 순위 + int iKnightsGrade = pkt.read(); // 소속 기사단 등급 + int iKnightsRank = pkt.read(); // 소속 기사단 순위 - /*int16_t sMarkVersion =*/pkt.read(); - /*int16_t sCapeID =*/pkt.read(); + int16_t sMarkVersion = pkt.read(); // Clan mark + int16_t sCapeID = pkt.read(); // Clan cloak // 기사단 관련 세팅.. - s_pPlayer->m_InfoExt.eKnightsDuty = eKnightsDuty; // 기사단에서의 권한.. + s_pPlayer->m_InfoExt.eKnightsDuty = eKnightsDuty; // 기사단에서의 권한.. + s_pPlayer->m_InfoBase.iMarkVersion = sMarkVersion; // Clan mark s_pPlayer->KnightsInfoSet(iKnightsID, szKnightsName, iKnightsGrade, iKnightsRank); m_pUIVar->UpdateKnightsInfo(); @@ -2177,16 +2181,8 @@ bool CGameProcMain::MsgRecv_MyInfo_All(Packet& pkt) InitPlayerPosition(__Vector3(fX, fY, fZ)); // 플레이어 위치 초기화.. 일으켜 세우고, 기본동작을 취하게 한다. s_pPlayer->RegenerateCollisionMesh(); - - // berserk temp - //s_pPlayer->PlugSet(PLUG_POS_BACK, "item/babacloak.n3cplug_cloak", nullptr); // 파트를 셋팅.. - // end berserk temp - - // berserk - //s_pPlayer->AttachCloak(); - - //.. - s_pOPMgr->Release(); // 다른 유저 관리 클래스 초기화.. + s_pPlayer->AttachCloak(sCapeID); // Cloak + s_pOPMgr->Release(); // 다른 유저 관리 클래스 초기화.. if (m_pUICmdList != nullptr) m_pUICmdList->CreateCategoryList(); @@ -2542,24 +2538,24 @@ bool CGameProcMain::MsgRecv_UserIn(Packet& pkt, bool bWithFX) /*int16_t sAllianceID =*/pkt.read(); - int iKnightNameLen = pkt.read(); // 소속 기사단 이름 길이. + int iKnightNameLen = pkt.read(); // 소속 기사단 이름 길이. std::string szKnightsName; pkt.readString(szKnightsName, iKnightNameLen); - int iKnightsGrade = pkt.read(); // 등급 - int iKnightsRank = pkt.read(); // 순위 + int iKnightsGrade = pkt.read(); // 등급 + int iKnightsRank = pkt.read(); // 순위 - /*int16_t sMarkVersion =*/pkt.read(); - /*int16_t sCapeID =*/pkt.read(); + int16_t sMarkVersion = pkt.read(); // Clan mark + int16_t sCapeID = pkt.read(); // Cloak - int iLevel = pkt.read(); // 레벨... - e_Race eRace = (e_Race) pkt.read(); - e_Class eClass = (e_Class) pkt.read(); - float fXPos = (pkt.read()) / 10.0f; - float fZPos = (pkt.read()) / 10.0f; - float fYPos = (pkt.read()) / 10.0f; + int iLevel = pkt.read(); // 레벨... + e_Race eRace = (e_Race) pkt.read(); + e_Class eClass = (e_Class) pkt.read(); + float fXPos = (pkt.read()) / 10.0f; + float fZPos = (pkt.read()) / 10.0f; + float fYPos = (pkt.read()) / 10.0f; - float fYTerrain = ACT_WORLD->GetHeightWithTerrain(fXPos, fZPos); // 지형의 높이값 얻기.. - float fYObject = ACT_WORLD->GetHeightNearstPosWithShape(__Vector3(fXPos, fYPos, fZPos)); // 오브젝트에서 가장 가까운 높이값 얻기.. + float fYTerrain = ACT_WORLD->GetHeightWithTerrain(fXPos, fZPos); // 지형의 높이값 얻기.. + float fYObject = ACT_WORLD->GetHeightNearstPosWithShape(__Vector3(fXPos, fYPos, fZPos)); // 오브젝트에서 가장 가까운 높이값 얻기.. if (fYObject > fYTerrain) fYPos = fYObject; else @@ -2581,7 +2577,7 @@ bool CGameProcMain::MsgRecv_UserIn(Packet& pkt, bool bWithFX) /*uint8_t bInvisibilityType =*/pkt.read(); /*int16_t sDirection =*/pkt.read(); /*bool bIsChicken =*/pkt.read(); - /*uint8_t bRank =*/pkt.read(); + uint8_t byRank = pkt.read(); // Noble rank - used to identify high-ranking titles like King [1], Senator [2] /*uint8_t bKnightsRank =*/pkt.read(); /*uint8_t bPersonalRank =*/pkt.read(); @@ -2629,9 +2625,12 @@ bool CGameProcMain::MsgRecv_UserIn(Packet& pkt, bool bWithFX) pUPC->m_InfoBase.eClass = eClass; pUPC->m_InfoBase.iLevel = iLevel; pUPC->m_InfoBase.iAuthority = byAuthority; + pUPC->m_InfoBase.iRank = byRank; pUPC->Init(eRace, iFace, iHair, dwItemIDs, iItemDurabilities, byItemFlags); pUPC->RotateTo(DegreesToRadians(rand() % 360), true); + pUPC->m_InfoBase.iMarkVersion = sMarkVersion; pUPC->KnightsInfoSet(iKnightsID, szKnightsName, iKnightsGrade, iKnightsRank); + pUPC->AttachCloak(sCapeID); //__KnightsInfoBase* pKIB = m_pUIKnightsOp->KnightsInfoFind(iKightsID); //if(pKIB) pUPC->KnightsNameSet(pKIB->szName, 0xffff0000); @@ -8051,3 +8050,11 @@ void CGameProcMain::MsgRecv_ZoneAbility(Packet& pkt) s_pPlayer->m_InfoExt.sZoneTariff = pkt.read(); } } + +void CGameProcMain::MsgRecv_ServerIndex(Packet& pkt) +{ + int16_t sResult = pkt.read(); + if (sResult == 0) // 1 = success, 0 = server index unavailable + return; + m_nServerIndex = pkt.read(); +} diff --git a/src/Client/WarFare/GameProcMain.h b/src/Client/WarFare/GameProcMain.h index 7d566f06c..c1aba6adf 100644 --- a/src/Client/WarFare/GameProcMain.h +++ b/src/Client/WarFare/GameProcMain.h @@ -108,6 +108,8 @@ class CGameProcMain : public CGameProcedure bool MsgRecv_CharacterSelect(Packet& pkt) override; // virtual int MsgRecv_VersionCheck(Packet& pkt) override; // virtual + void MsgRecv_ServerIndex(Packet& pkt); // Server index + int m_nServerIndex = 0; bool MsgRecv_MyInfo_All(Packet& pkt); void MsgRecv_MyInfo_HP(Packet& pkt); diff --git a/src/Client/WarFare/GameProcedure.cpp b/src/Client/WarFare/GameProcedure.cpp index b0b5d5af0..d17877038 100644 --- a/src/Client/WarFare/GameProcedure.cpp +++ b/src/Client/WarFare/GameProcedure.cpp @@ -711,6 +711,16 @@ std::string CGameProcedure::GetStrRegKeySetting() return fmt::format("Software\\KnightOnline\\{}_{}_{}", s_szAccount, s_szServer, s_iChrSelectIndex); } +std::string CGameProcedure::GetSymbolFilename(const int serverIndex, const int knightsId, const int markVersion) +{ + return fmt::format("symbol_us\\s_{}_{}_{}.dxt", serverIndex, knightsId, markVersion); +} + +int CGameProcedure::GetServerIndex() +{ + return s_pProcMain ? s_pProcMain->m_nServerIndex : 0; +} + bool CGameProcedure::ProcessPacket(Packet& pkt) { int iCmd = pkt.read(); // 커멘드 파싱.. diff --git a/src/Client/WarFare/GameProcedure.h b/src/Client/WarFare/GameProcedure.h index e6e20471a..08e45df31 100644 --- a/src/Client/WarFare/GameProcedure.h +++ b/src/Client/WarFare/GameProcedure.h @@ -149,6 +149,9 @@ class CGameProcedure : public CGameBase static void SetGameCursor(e_Cursor eCursor, bool bLocked = false); static void RestoreGameCursor(); + static std::string GetSymbolFilename(const int serverIndex, const int knightsId, const int markVersion); + static int GetServerIndex(); + protected: virtual bool ProcessPacket(Packet& pkt); void MsgRecv_ServerChange(Packet& pkt); diff --git a/src/Client/WarFare/PlayerBase.cpp b/src/Client/WarFare/PlayerBase.cpp index f004cb020..b395fe274 100644 --- a/src/Client/WarFare/PlayerBase.cpp +++ b/src/Client/WarFare/PlayerBase.cpp @@ -304,9 +304,10 @@ void CPlayerBase::KnightsInfoSet(int iID, const std::string& /*szName*/, int iGr szPlug = fmt::format("Item\\ClanAddOn_{:03}_{}.n3cplug", static_cast(m_InfoBase.eRace), iGrade); } - m_InfoBase.iKnightsID = iID; + m_InfoBase.iKnightsID = iID; + m_InfoBase.iKnightsGrade = iGrade; - CN3CPlugBase* pPlug = PlugSet(PLUG_POS_KNIGHTS_GRADE, szPlug, nullptr, nullptr); + CN3CPlugBase* pPlug = PlugSet(PLUG_POS_KNIGHTS_GRADE, szPlug, nullptr, nullptr); if (pPlug == nullptr) return; @@ -528,12 +529,24 @@ void CPlayerBase::TickAnimation() // 걷고 뛰고, 에니메이션등... 속도 적용 float fAniSpeedDelta = 1.0f; if (PSM_STOP != m_eStateMove) - fAniSpeedDelta = m_fMoveDelta; // 이동중이면 스피드 적용.. + fAniSpeedDelta = m_fMoveDelta; // 이동중이면 스피드 적용.. else if (PSA_ATTACK == m_eState) - fAniSpeedDelta = m_fAttackDelta; // 공격중이면 공격 스피드 적용.. + fAniSpeedDelta = m_fAttackDelta; // 공격중이면 공격 스피드 적용.. __ASSERT(fAniSpeedDelta >= 0.1f && fAniSpeedDelta < 10.0f, "Invalid Animation Speed Delta!!!"); - m_Chr.AniSpeedDeltaSet(fAniSpeedDelta); // 에니메이션 스피드 실제 적용.. - m_Chr.Tick(); // 에니메이션 틱.. + m_Chr.AniSpeedDeltaSet(fAniSpeedDelta); // 에니메이션 스피드 실제 적용.. + m_Chr.Tick(); // 에니메이션 틱.. + + if (m_Chr.CloakPlug() != nullptr) + { + e_CloakMove eCloakMove = CLOAK_MOVE_STOP; + if (m_eStateMove == PSM_RUN) + eCloakMove = CLOAK_MOVE_RUN; + else if (m_eStateMove == PSM_WALK) + eCloakMove = CLOAK_MOVE_WALK; + else if (m_eStateMove == PSM_WALK_BACKWARD) + eCloakMove = CLOAK_MOVE_WALK_BACKWARD; + m_Chr.CloakPlug()->GetCloak()->Tick(m_Chr.m_nLOD, m_fYawCur, eCloakMove); + } m_bAnimationChanged = false; // 큐에 넣은 에니메이션이 변하는 순간만 세팅된다.. if (m_Chr.IsAnimEnd()) // 에니메이션이 끝나면.. @@ -1702,14 +1715,22 @@ bool CPlayerBase::CheckCollisionToTargetByPlug(CPlayerBase* pTarget, int nPlug, return pTarget->CheckCollisionByBox(v1, v2, pVCol, nullptr); } -CN3CPlugBase* CPlayerBase::PlugSet(e_PlugPosition ePos, const std::string& szFN, __TABLE_ITEM_BASIC* pItemBasic, __TABLE_ITEM_EXT* pItemExt) +CN3CPlugBase* CPlayerBase::PlugSet( + e_PlugPosition ePos, const std::string& szFN, __TABLE_ITEM_BASIC* pItemBasic, __TABLE_ITEM_EXT* pItemExt, bool isForce) { if (ePos < PLUG_POS_RIGHTHAND || ePos >= PLUG_POS_COUNT) { __ASSERT(0, "Invalid Plug Position"); return nullptr; } - + if (m_InfoBase.bIsTransformed && !isForce) // Skip plug if player is transformed + { + if (pItemBasic) + m_pItemPlugBasics[ePos] = pItemBasic; + if (pItemExt) + m_pItemPlugExts[ePos] = pItemExt; + return nullptr; + } int iJoint = 0; if (PLUG_POS_RIGHTHAND == ePos) { @@ -1736,7 +1757,14 @@ CN3CPlugBase* CPlayerBase::PlugSet(e_PlugPosition ePos, const std::string& szFN, } else if (PLUG_POS_BACK == ePos) { - //m_pItemPlugBasics[PLUG_POS_BACK] = pItem; + m_pItemPlugBasics[ePos] = pItemBasic; + m_pItemPlugExts[ePos] = pItemExt; + + CN3CPlug_Cloak* pCloak = m_Chr.CloakPlugSet(szFN); + if (pCloak != nullptr) + pCloak->m_nJointIndex = ITEM_POS_SHOULDER; + + return pCloak; } else { @@ -1849,6 +1877,43 @@ CN3CPlugBase* CPlayerBase::PlugSet(e_PlugPosition ePos, const std::string& szFN, return pPlug; } +void CPlayerBase::AttachCloak(int16_t sCapeID, bool isForce) +{ + PlugSet(PLUG_POS_BACK, "", nullptr, nullptr, /*isForce=*/true); // Remove cloak + + if (sCapeID < 0) // No cloak + return; + + const std::string sMeshPath = fmt::format("Item\\Cloak_{:03}.n3cplug", static_cast(m_InfoBase.eRace)); // Cloak mesh for each race + CN3CPlug_Cloak* pCloak = static_cast(PlugSet(PLUG_POS_BACK, sMeshPath, nullptr, nullptr, isForce)); + if (pCloak == nullptr) + return; + + std::string SColourTexPath; + std::string sPatternTexPath; + std::string sClanMarkTexPath; + + if (m_InfoBase.iRank == 1) + { + SColourTexPath = "Item\\Cloak_C_99.dxt"; // King cloak + } + else + { + int nColour = sCapeID % 100; + int nPattern = sCapeID / 100; + + SColourTexPath = fmt::format("Item\\Cloak_C_{:02}.dxt", nColour); // Cloak colour + sPatternTexPath = fmt::format("Item\\Cloak_M_{:02}.dxt", nPattern); // Cloak pattern + sClanMarkTexPath = ""; // No Clan Mark + + if (m_InfoBase.iKnightsGrade <= 2) + sClanMarkTexPath = CGameProcedure::GetSymbolFilename( + CGameProcedure::GetServerIndex(), m_InfoBase.iKnightsID, m_InfoBase.iMarkVersion); // Clan Mark + } + + pCloak->Init(pCloak->Mesh(), SColourTexPath, sClanMarkTexPath, sPatternTexPath); +} + CN3CPart* CPlayerBase::PartSet(e_PartPosition ePos, const std::string& szFN, __TABLE_ITEM_BASIC* pItemBasic, __TABLE_ITEM_EXT* pItemExt) { if (ePos < PART_POS_UPPER || ePos >= PART_POS_COUNT) diff --git a/src/Client/WarFare/PlayerBase.h b/src/Client/WarFare/PlayerBase.h index 5464ca35f..4d9109ece 100644 --- a/src/Client/WarFare/PlayerBase.h +++ b/src/Client/WarFare/PlayerBase.h @@ -41,12 +41,16 @@ struct __InfoPlayerBase int iHP; int iMP; int iMPMax; - int iAuthority; // 권한 - 0 관리자, 1 - 일반유저, 255 - 블럭당한 유저... - int iKnightsID; // Clan ID + int iAuthority; // 권한 - 0 관리자, 1 - 일반유저, 255 - 블럭당한 유저... + int iKnightsID; // Clan ID int iAllianceID; int iKnightsWarEnemyID; + int iKnightsGrade; // Clan grade + int16_t iMarkVersion; // Clan mark + int iRank; // Noble rank - used to identify high-ranking titles like King [1], Senator [2]. Always 0 for NPCs. + bool bIsTransformed; - bool bRenderID; // 화면에 ID 를 찍는지.. + bool bRenderID; // 화면에 ID 를 찍는지.. __InfoPlayerBase() { @@ -70,7 +74,11 @@ struct __InfoPlayerBase iKnightsID = 0; iAllianceID = 0; iKnightsWarEnemyID = 0; + iKnightsGrade = 0; + iMarkVersion = 0; + iRank = 0; bRenderID = true; + bIsTransformed = false; } }; @@ -412,8 +420,10 @@ class CPlayerBase : public CGameBase } virtual CN3CPart* PartSet(e_PartPosition ePos, const std::string& szFN, __TABLE_ITEM_BASIC* pItemBasic, __TABLE_ITEM_EXT* pItemExt); - virtual CN3CPlugBase* PlugSet(e_PlugPosition ePos, const std::string& szFN, __TABLE_ITEM_BASIC* pItemBasic, __TABLE_ITEM_EXT* pItemExt); + virtual CN3CPlugBase* PlugSet( + e_PlugPosition ePos, const std::string& szFN, __TABLE_ITEM_BASIC* pItemBasic, __TABLE_ITEM_EXT* pItemExt, bool isForce = false); virtual void DurabilitySet(e_ItemSlot eSlot, int iDurability); + void AttachCloak(int16_t sCapeID, bool isForce = false); void TickYaw(); // 회전값 처리. void TickAnimation(); // 에니메이션 처리. diff --git a/src/Client/WarFare/PlayerMySelf.cpp b/src/Client/WarFare/PlayerMySelf.cpp index 3cf30ce04..7722e7416 100644 --- a/src/Client/WarFare/PlayerMySelf.cpp +++ b/src/Client/WarFare/PlayerMySelf.cpp @@ -566,7 +566,7 @@ void CPlayerMySelf::InventoryChrAnimationInitialize() } CN3CPlugBase* CPlayerMySelf::PlugSet( - e_PlugPosition ePos, const std::string& szFN, __TABLE_ITEM_BASIC* pItemBasic, __TABLE_ITEM_EXT* pItemExt) + e_PlugPosition ePos, const std::string& szFN, __TABLE_ITEM_BASIC* pItemBasic, __TABLE_ITEM_EXT* pItemExt, bool isForce) { int iJoint = 0; if (PLUG_POS_RIGHTHAND == ePos) @@ -595,7 +595,7 @@ CN3CPlugBase* CPlayerMySelf::PlugSet( } else if (PLUG_POS_BACK == ePos) { - //m_pItemBasicPlugRefs[PLUG_POS_BACK] = pItem; + return CPlayerBase::PlugSet(ePos, szFN, pItemBasic, pItemExt, isForce); } else { @@ -613,13 +613,9 @@ CN3CPlugBase* CPlayerMySelf::PlugSet( pPlug->ScaleSet(__Vector3(fScale, fScale, fScale)); pPlug->m_nJointIndex = iJoint; // 관절 번호 세팅.. } - // else if(PLUG_POS_BACK == ePos) - // { - // CN3CPlug_Cloak *pPlugCloak = (CN3CPlug_Cloak*)pPlug; - // } this->SetSoundPlug(pItemBasic); - return CPlayerBase::PlugSet(ePos, szFN, pItemBasic, pItemExt); + return CPlayerBase::PlugSet(ePos, szFN, pItemBasic, pItemExt, isForce); } CN3CPart* CPlayerMySelf::PartSet(e_PartPosition ePos, const std::string& szFN, __TABLE_ITEM_BASIC* pItemBasic, __TABLE_ITEM_EXT* pItemExt) diff --git a/src/Client/WarFare/PlayerMySelf.h b/src/Client/WarFare/PlayerMySelf.h index 8648a3169..036edd22d 100644 --- a/src/Client/WarFare/PlayerMySelf.h +++ b/src/Client/WarFare/PlayerMySelf.h @@ -78,8 +78,8 @@ class CPlayerMySelf : public CPlayerBase bool InitChr(__TABLE_PLAYER_LOOKS* pTblUPC) override; CN3CPart* PartSet(e_PartPosition ePos, const std::string& szFN, __TABLE_ITEM_BASIC* pItemBasic, __TABLE_ITEM_EXT* pItemExt) override; - CN3CPlugBase* PlugSet( - e_PlugPosition ePos, const std::string& szFN, __TABLE_ITEM_BASIC* pItemBasic, __TABLE_ITEM_EXT* pItemExt) override; + CN3CPlugBase* PlugSet(e_PlugPosition ePos, const std::string& szFN, __TABLE_ITEM_BASIC* pItemBasic, __TABLE_ITEM_EXT* pItemExt, + bool isForce = false) override; void Tick() override; void Render(float fSunAngle) override; diff --git a/src/Client/WarFare/PlayerOther.cpp b/src/Client/WarFare/PlayerOther.cpp index 4e776c7ee..55177ae0f 100644 --- a/src/Client/WarFare/PlayerOther.cpp +++ b/src/Client/WarFare/PlayerOther.cpp @@ -130,9 +130,11 @@ bool CPlayerOther::Init(e_Race eRace, int iFace, int iHair, uint32_t* pdwItemIDs ePart = PART_POS_FEET; eSlot = ITEM_SLOT_SHOES; } - else if (5 == i) + else if (5 == i) // Clan cape { - } // 망토 + ePlug = PLUG_POS_BACK; + eSlot = ITEM_SLOT_SHOULDER; + } else if (6 == i) { ePlug = PLUG_POS_RIGHTHAND; diff --git a/src/Client/WarFare/UIImageTooltipDlg.cpp b/src/Client/WarFare/UIImageTooltipDlg.cpp index 93aae1df1..8e99b7dd1 100644 --- a/src/Client/WarFare/UIImageTooltipDlg.cpp +++ b/src/Client/WarFare/UIImageTooltipDlg.cpp @@ -885,7 +885,7 @@ void CUIImageTooltipDlg::CalcTooltipStringNumAndWriteImpl(__IconItemSkill* spIte m_pStr[iIndex]->SetStyle(UI_STR_TYPE_HALIGN, UISTYLE_STRING_ALIGNLEFT); - if (SetTooltipTextColor(pInfoExt->iRank, spItem->pItemBasic->byNeedRank + spItem->pItemExt->siNeedRank)) + if (SetTooltipTextColor(CGameBase::s_pPlayer->m_InfoBase.iRank, spItem->pItemBasic->byNeedRank + spItem->pItemExt->siNeedRank)) m_pStr[iIndex]->SetColor(m_CWhite); else m_pStr[iIndex]->SetColor(m_CRed); diff --git a/src/Client/WarFare/UIInventory.cpp b/src/Client/WarFare/UIInventory.cpp index 71cb13724..2738dafc1 100644 --- a/src/Client/WarFare/UIInventory.cpp +++ b/src/Client/WarFare/UIInventory.cpp @@ -1905,7 +1905,7 @@ bool CUIInventory::IsValidRaceAndClass(__TABLE_ITEM_BASIC* pItem, __TABLE_ITEM_E return false; } - if (pInfoExt->iRank < pItem->byNeedRank + pItemExt->siNeedRank) + if (CGameBase::s_pPlayer->m_InfoBase.iRank < pItem->byNeedRank + pItemExt->siNeedRank) { szMsg = fmt::format_text_resource(IDS_MSG_VALID_CLASSNRACE_LOW_RANK); CGameProcedure::s_pProcMain->MsgOutput(szMsg, 0xffff3b3b); diff --git a/src/N3Base/N3Chr.cpp b/src/N3Base/N3Chr.cpp index 97567221b..d993f6805 100644 --- a/src/N3Base/N3Chr.cpp +++ b/src/N3Base/N3Chr.cpp @@ -306,6 +306,7 @@ CN3CPlugBase::~CN3CPlugBase() { s_MngTex.Delete(&m_pTexRef); s_MngTex.Delete(&m_pTexOverlapRef); + s_MngMesh.Delete(&m_pMesh); } void CN3CPlugBase::Release() @@ -316,6 +317,7 @@ void CN3CPlugBase::Release() s_MngTex.Delete(&m_pTexRef); s_MngTex.Delete(&m_pTexOverlapRef); + s_MngMesh.Delete(&m_pMesh); m_Mtl.Init(); m_vPosition.Zero(); @@ -463,7 +465,7 @@ bool CN3CPlugBase::Load(File& file) char szFN[512] = ""; file.Read(&m_ePlugType, 4); // Plug Type - //#ifdef _N3TOOL + //#ifdef _N3TOOL if (m_ePlugType > PLUGTYPE_MAX) { m_ePlugType = PLUGTYPE_NORMAL; @@ -481,8 +483,20 @@ bool CN3CPlugBase::Load(File& file) if (nL > 0) { file.Read(szFN, nL); - szFN[nL] = '\0'; - PMeshSet(szFN); + szFN[nL] = '\0'; + + char szExt[_MAX_EXT] = ""; + _splitpath_s(szFN, nullptr, 0, nullptr, 0, nullptr, 0, szExt, _MAX_EXT); + + if (_stricmp(szExt, ".n3pmesh") == 0) + { + PMeshSet(szFN); + } + else if (_stricmp(szExt, ".n3mesh") == 0) + { + s_MngMesh.Delete(&m_pMesh); + m_pMesh = s_MngMesh.Get(szFN); + } } file.Read(&nL, 4); @@ -514,13 +528,16 @@ bool CN3CPlugBase::Save(File& file) file.Write(&m_Mtl, sizeof(__Material)); // 재질 - nL = 0; - CN3PMesh* pPMesh = m_PMeshInst.GetMesh(); - if (pPMesh != nullptr) - nL = static_cast(pPMesh->FileName().size()); + nL = 0; + std::string szMeshFN; + if (CN3PMesh* pPMesh = m_PMeshInst.GetMesh()) + szMeshFN = pPMesh->FileName(); + else if (m_pMesh != nullptr) + szMeshFN = m_pMesh->FileName(); + nL = static_cast(szMeshFN.size()); file.Write(&nL, 4); if (nL > 0) - file.Write(pPMesh->FileName().c_str(), nL); + file.Write(szMeshFN.c_str(), nL); nL = 0; if (m_pTexRef != nullptr) @@ -1047,23 +1064,27 @@ CN3CPlug_Cloak::~CN3CPlug_Cloak() void CN3CPlug_Cloak::Release() { +#ifdef _N3GAME + s_MngTex.Delete(&m_pTexColour); + s_MngTex.Delete(&m_pTexClanMark); + s_MngTex.Delete(&m_pTexPattern); +#endif CN3CPlugBase::Release(); } bool CN3CPlug_Cloak::Load(File& file) { - CN3CPlugBase::Load(file); -#ifdef _N3GAME - m_Cloak.Init(this); -#endif - return 0; + if (!CN3CPlugBase::Load(file)) + return false; + + return m_pMesh != nullptr; // mesh file missing or wrong extension } #ifdef _N3TOOL bool CN3CPlug_Cloak::Save(File& file) { CN3CPlugBase::Save(file); - return 0; + return false; } #endif void CN3CPlug_Cloak::Render(const __Matrix44& mtxParent, const __Matrix44& mtxJoint) @@ -1076,7 +1097,7 @@ void CN3CPlug_Cloak::Render(const __Matrix44& mtxParent, const __Matrix44& mtxJo mtx = m_Matrix; mtx *= mtxJoint; mtx *= mtxParent; - m_Cloak.Render(mtx); + m_Cloak.Render(mtx, m_pTexColour, m_pTexPattern, m_pTexClanMark); #endif } @@ -1086,6 +1107,37 @@ void CN3CPlug_Cloak::SetLOD(int nLOD) m_Cloak.SetLOD(nLOD); #endif } + +bool CN3CPlug_Cloak::Init(CN3Mesh* pMesh, const std::string& sColourTex, + const std::string& sClanMarkTex, const std::string& sPatternTex) +{ + s_MngTex.Delete(&m_pTexColour); + s_MngTex.Delete(&m_pTexClanMark); + s_MngTex.Delete(&m_pTexPattern); + + if (!pMesh) + return false; + + //if (pMesh->VertexCount() != 49) + // return false; + //if (pMesh->IndexCount() != 216) + // return false; + + m_pTexColour = s_MngTex.Get(sColourTex, true, 0); + m_pTexClanMark = s_MngTex.Get(sClanMarkTex, true, 0); + m_pTexPattern = s_MngTex.Get(sPatternTex, true, 0); + //__ASSERT(m_pMesh && m_pTex, "IN CN3Cloak, Mesh or m_pTex is null"); + + TexSet(sColourTex); +#ifdef _N3GAME + m_Cloak.InitMeshTex(pMesh, Tex()); + m_Cloak.InitPhysics(); +#endif + SetLOD(0); + + return true; +} + // CN3cPlug_Cloak Codes End here ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// @@ -1123,6 +1175,9 @@ CN3Chr::~CN3Chr() delete *itr; m_Plugs.clear(); + delete m_pCloakPlug; + m_pCloakPlug = nullptr; + for (auto itr = m_vTraces.begin(); itr != m_vTraces.end(); ++itr) delete *itr; m_vTraces.clear(); @@ -1892,6 +1947,12 @@ void CN3Chr::Render() //////////////////////////////////////////////////// } + // Cloak render + if (m_pCloakPlug != nullptr && m_pCloakPlug->m_bVisible && m_pCloakPlug->m_nJointIndex >= 0) + { + m_pCloakPlug->Render(m_Matrix, m_MtxJoints[m_pCloakPlug->m_nJointIndex]); + } + ////////////////////////////////////////////////// // Coded (By Dino On 2002-10-11 오전 11:20:19 ) // FXPlug @@ -2201,6 +2262,24 @@ void CN3Chr::PlugAlloc(int iCount) } } +CN3CPlug_Cloak* CN3Chr::CloakPlugSet(const std::string& sMeshPath) +{ + delete m_pCloakPlug; + m_pCloakPlug = nullptr; + + if (sMeshPath.empty()) + return nullptr; + + m_pCloakPlug = new CN3CPlug_Cloak(); + if (!m_pCloakPlug->LoadFromFile(sMeshPath)) + { + delete m_pCloakPlug; + m_pCloakPlug = nullptr; + return nullptr; + } + return m_pCloakPlug; +} + /* void CN3Chr::CollisionSkinSet(const std::string& szFN) { diff --git a/src/N3Base/N3Chr.h b/src/N3Base/N3Chr.h index f2fc70a91..6ebe30aa7 100644 --- a/src/N3Base/N3Chr.h +++ b/src/N3Base/N3Chr.h @@ -12,6 +12,7 @@ #include "N3Skin.h" #include "N3Cloak.h" #include "N3PMeshInstance.h" +#include "N3Mesh.h" #include "N3Texture.h" #include "N3Joint.h" #include @@ -137,6 +138,7 @@ class CN3CPlugBase : public CN3BaseFileAccess protected: CN3PMeshInstance m_PMeshInst; // Progressive Mesh Instance + CN3Mesh* m_pMesh = nullptr; // Set when the .n3cplug references .n3mesh instead of .n3pmesh CN3Texture* m_pTexRef; // Texture Reference Pointer CN3Texture* m_pTexOverlapRef; // 위에 덧칠할 Texture Reference Pointer __Matrix44 m_MtxRot; // Rotation Matrix; @@ -227,6 +229,11 @@ class CN3CPlugBase : public CN3BaseFileAccess } void PMeshSet(const std::string& szFN); + + CN3Mesh* Mesh() + { + return m_pMesh; + } }; inline constexpr int MAX_PLUG_FX_POSITION = 5; @@ -283,6 +290,8 @@ class CN3CPlug_Cloak : public CN3CPlugBase void Release() override; void SetLOD(int nLOD); + bool Init(CN3Mesh* pMesh, const std::string& sColourTex, const std::string& sClanMarkTex, + const std::string& sPatternTex); #ifdef _N3GAME CN3Cloak* GetCloak() { @@ -293,6 +302,9 @@ class CN3CPlug_Cloak : public CN3CPlugBase #ifdef _N3GAME CN3Cloak m_Cloak; #endif + CN3Texture* m_pTexColour = nullptr; + CN3Texture* m_pTexClanMark = nullptr; + CN3Texture* m_pTexPattern = nullptr; }; // 0 - 상체, 1 - 하체 ::: 관절들을 나누어서 나누어서 에니메이션 설정.. @@ -327,12 +339,13 @@ class CN3Chr : public CN3TransformCollision // 각 조인트의 행렬.. 포인터로 두지 않은 이유는 각 캐릭터마다 따로 에니메이션이 되기 위함이다.. std::vector<__Matrix44> m_MtxJoints; - std::vector<__Matrix44> m_MtxInverses; // 조인트에 대한 역행렬 + std::vector<__Matrix44> m_MtxInverses; // 조인트에 대한 역행렬 - std::vector m_Parts; // 각 캐릭터의 부분별 Data Pointer List - std::vector m_Plugs; // 이 캐릭터에 붙이는 무기등의 Data Pointer List - std::vector<__VertexColor*> m_vTraces; // Plug Trace Polygon - class CN3FXPlug* m_pFXPlug; // 캐릭터에 FX를 붙이는 것. + std::vector m_Parts; // 각 캐릭터의 부분별 Data Pointer List + std::vector m_Plugs; // 이 캐릭터에 붙이는 무기등의 Data Pointer List + std::vector<__VertexColor*> m_vTraces; // Plug Trace Polygon + class CN3FXPlug* m_pFXPlug; // 캐릭터에 FX를 붙이는 것. + CN3CPlug_Cloak* m_pCloakPlug = nullptr; // Cloak attachment // 조인트의 일부분이 따로 에니메이션 되야 한다면.. 조인트 인덱스 시작 번호 int m_nJointPartStarts[MAX_CHR_ANI_PART]; @@ -471,6 +484,12 @@ class CN3Chr : public CN3TransformCollision return m_Plugs[iIndex]; } + CN3CPlug_Cloak* CloakPlugSet(const std::string& sMeshPath); + CN3CPlug_Cloak* CloakPlug() + { + return m_pCloakPlug; + } + void Tick(float fFrm = FRAME_SELFPLAY) override; void TickAnimationFrame(); void TickJoints(); diff --git a/src/N3Base/N3Cloak.cpp b/src/N3Base/N3Cloak.cpp index e7cf887c2..e463527d5 100644 --- a/src/N3Base/N3Cloak.cpp +++ b/src/N3Base/N3Cloak.cpp @@ -5,7 +5,6 @@ #include "StdAfxBase.h" #include "N3Cloak.h" #include "N3Texture.h" -#include "N3PMeshInstance.h" #include "N3Chr.h" CN3Cloak::CN3Cloak() @@ -14,7 +13,7 @@ CN3Cloak::CN3Cloak() m_pTex = nullptr; m_pParticle = nullptr; m_nLOD = -1; - m_pPMesh = nullptr; + m_pMesh = nullptr; m_pIndex = nullptr; m_pVertex = nullptr; m_fOffsetRecoveryTime = 0.0f; @@ -36,6 +35,7 @@ CN3Cloak::~CN3Cloak() delete[] m_pParticle; delete[] m_pIndex; delete[] m_pVertex; + delete[] m_pIndexMark; } void CN3Cloak::Release() @@ -48,23 +48,10 @@ void CN3Cloak::Release() delete[] m_pVertex; m_pVertex = nullptr; -} - -void CN3Cloak::Init(CN3CPlug_Cloak* pPlugCloak) -{ - m_pTex = pPlugCloak->Tex(); - m_pPMesh = pPlugCloak->PMesh(); - __ASSERT(m_pPMesh && m_pTex, "IN CN3Cloak, PMesh or m_pTex is null"); - - SetLOD(0); - // - m_GravityForce.x = 0.0f; - m_GravityForce.z = 0.0005f; - //m_GravityForce.y = -0.0025f; - m_GravityForce.y = -0.0005f; - - m_Force.x = m_Force.y = m_Force.z = 0.0f; + delete[] m_pIndexMark; + m_pIndexMark = nullptr; + m_nIndexCountMark = 0; } void CN3Cloak::Tick(int /*nLOD*/, float fYaw, e_CloakMove eCloakMove) @@ -86,57 +73,111 @@ void CN3Cloak::Tick(int /*nLOD*/, float fYaw, e_CloakMove eCloakMove) // fForceDelay = 0.0f; // fForceDelayLimit = 2.0f + rand()%10; // } - m_fAnchorPreserveTime -= s_fSecPerFrm; - if (m_eAnchorPattern != AMP_NONE) - { - if (m_fAnchorPreserveTime < 0.0f) - { - RestoreAnchorLine(); - } - } + // m_fAnchorPreserveTime -= s_fSecPerFrm; + // if (m_eAnchorPattern != AMP_NONE) + // { + // if (m_fAnchorPreserveTime < 0.0f) + // { + // RestoreAnchorLine(); + // } + // } + // const e_Cloak_AnchorMovePattern prevAnchor = m_eAnchorPattern; TickByPlayerMotion(eCloakMove); TickYaw(fYaw); - + // if (m_eAnchorPattern == prevAnchor && m_eAnchorPattern == AMP_NONE) + // MoveAnchorLine(AMP_NONE, 2.0f); UpdateLocalForce(); ApplyForce(); m_Force.x = m_Force.y = m_Force.z = 0.0f; } -void CN3Cloak::Render(__Matrix44& mtx) +void CN3Cloak::Render( + __Matrix44& mtx, CN3Texture* pTexColour, CN3Texture* pTexPattern, CN3Texture* pTexClanMark) { - if (m_nLOD < 0) + if (m_nLOD < 0 || m_pTex == nullptr) return; s_lpD3DDev->SetTransform(D3DTS_WORLD, mtx.toD3D()); - DWORD dwCull = 0, dwLight = 0; - s_lpD3DDev->GetRenderState(D3DRS_LIGHTING, &dwLight); + DWORD dwCull = 0; s_lpD3DDev->GetRenderState(D3DRS_CULLMODE, &dwCull); - - // - //s_lpD3DDev->SetRenderState( D3DRS_LIGHTING, FALSE); if (dwCull != D3DCULL_NONE) s_lpD3DDev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + // Mesh s_lpD3DDev->SetTexture(0, m_pTex->Get()); - s_lpD3DDev->SetTexture(1, nullptr); - s_lpD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); s_lpD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); s_lpD3DDev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); - // s_lpD3DDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE); - // s_lpD3DDev->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); - // s_lpD3DDev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + + // Colour + if (pTexColour != nullptr) + { + s_lpD3DDev->SetTexture(1, pTexColour->Get()); + s_lpD3DDev->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 0); + s_lpD3DDev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA); + s_lpD3DDev->SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE); + s_lpD3DDev->SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT); + } + else + { + s_lpD3DDev->SetTexture(1, nullptr); + s_lpD3DDev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + } + + // Pattern + if (pTexPattern != nullptr) + { + s_lpD3DDev->SetTexture(2, pTexPattern->Get()); + s_lpD3DDev->SetTextureStageState(2, D3DTSS_TEXCOORDINDEX, 0); + s_lpD3DDev->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA); + s_lpD3DDev->SetTextureStageState(2, D3DTSS_COLORARG1, D3DTA_TEXTURE); + s_lpD3DDev->SetTextureStageState(2, D3DTSS_COLORARG2, D3DTA_CURRENT); + s_lpD3DDev->SetTextureStageState(3, D3DTSS_COLOROP, D3DTOP_DISABLE); + } + else + { + s_lpD3DDev->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE); + } s_lpD3DDev->SetFVF(FVF_VNT1); s_lpD3DDev->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, m_nVertexCount, m_nIndexCount / 3, m_pIndex, D3DFMT_INDEX16, m_pVertex, sizeof(__VertexT1)); - // + if (pTexClanMark != nullptr && m_pIndexMark != nullptr && m_nIndexCountMark > 0) + { + const float fDepthBias = -0.001f; + s_lpD3DDev->SetRenderState(D3DRS_DEPTHBIAS, *reinterpret_cast(&fDepthBias)); + + s_lpD3DDev->SetTexture(0, pTexClanMark->Get()); + s_lpD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + s_lpD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + s_lpD3DDev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + s_lpD3DDev->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE); + + D3DMATRIX texMat = { 3.0f, 0.0f, 0.0f, 0.0f, 0.0f, 3.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, + -1.0f, -1.0f, 0.0f, 1.0f }; + s_lpD3DDev->SetTransform(D3DTS_TEXTURE0, &texMat); + s_lpD3DDev->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2); + + s_lpD3DDev->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, m_nVertexCount, m_nIndexCountMark, + m_pIndexMark, D3DFMT_INDEX16, m_pVertex, sizeof(__VertexT1)); + + const float fZero = 0.0f; + s_lpD3DDev->SetRenderState(D3DRS_DEPTHBIAS, *reinterpret_cast(&fZero)); + + s_lpD3DDev->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); + + // Restore stage 0 + s_lpD3DDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + s_lpD3DDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); + s_lpD3DDev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); + } + + /* Grid for debugging the cloake movement __VertexXyzColor Vtx[2] {}; - /* __VertexT1 *pTemp = m_pVertex; Vtx[0].Set(pTemp->x, pTemp->y, pTemp->z, 0xffffffff); Vtx[1].Set(1.0f, 1.0f, 1.0f, 0xffffffff); @@ -147,7 +188,7 @@ void CN3Cloak::Render(__Matrix44& mtx) Vtx[1].Set(1.0f, 1.0f, 1.0f, 0xffffffff); s_lpD3DDev->SetVertexShader(FVF_CV); s_lpD3DDev->DrawPrimitiveUP(D3DPT_LINELIST, 1, Vtx, sizeof(__VertexXyzColor)); -*/ + for (int i = 0; i < m_nGridH; i++) { @@ -179,8 +220,13 @@ void CN3Cloak::Render(__Matrix44& mtx) s_lpD3DDev->DrawPrimitiveUP(D3DPT_LINELIST, 1, Vtx, sizeof(__VertexXyzColor)); } } + */ // restore renderstate. + s_lpD3DDev->SetTexture(1, nullptr); + s_lpD3DDev->SetTexture(2, nullptr); + s_lpD3DDev->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + s_lpD3DDev->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE); if (dwCull != D3DCULL_NONE) s_lpD3DDev->SetRenderState(D3DRS_CULLMODE, dwCull); } @@ -335,17 +381,45 @@ void CN3Cloak::SetLOD(int nLevel) m_nGridW = 7; m_nGridH = 5; - int nVertexCount = m_pPMesh->GetMaxNumVertices(); - int nIndexCount = m_pPMesh->GetMaxNumIndices(); + int nVertexCount = m_pMesh->VertexCount(); + int nIndexCount = m_pMesh->IndexCount(); m_pVertex = new __VertexT1[nVertexCount]; - memcpy(&m_pVertex, m_pPMesh->GetVertices(), sizeof(__VertexT1) * nVertexCount); + memcpy(m_pVertex, m_pMesh->Vertices(), sizeof(__VertexT1) * nVertexCount); m_pIndex = new uint16_t[nIndexCount]; - memcpy(m_pIndex, m_pPMesh->GetIndices(), sizeof(uint16_t) * nIndexCount); + memcpy(m_pIndex, m_pMesh->Indices(), sizeof(uint16_t) * nIndexCount); m_nVertexCount = nVertexCount; m_nIndexCount = nIndexCount; // } - break; + // Center-quad index list for clan mark + { + constexpr int MARK_COL_MIN = 2, MARK_COL_MAX = 4; // exclusive + constexpr int MARK_ROW_MIN = 0, MARK_ROW_MAX = 2; // exclusive + int nMarkQuads = (MARK_COL_MAX - MARK_COL_MIN) * (MARK_ROW_MAX - MARK_ROW_MIN); + delete[] m_pIndexMark; + m_pIndexMark = new uint16_t[nMarkQuads * 6]; + m_nIndexCountMark = 0; + uint16_t* pDst = m_pIndexMark; + for (int row = MARK_ROW_MIN; row < MARK_ROW_MAX; row++) + { + for (int col = MARK_COL_MIN; col < MARK_COL_MAX; col++) + { + uint16_t v0 = (row + CLOAK_SKIP_LINE) * m_nGridW + col; + uint16_t v1 = (row + CLOAK_SKIP_LINE) * m_nGridW + col + 1; + uint16_t v2 = (row + CLOAK_SKIP_LINE + 1) * m_nGridW + col; + uint16_t v3 = (row + CLOAK_SKIP_LINE + 1) * m_nGridW + col + 1; + pDst[0] = v0; + pDst[1] = v1; + pDst[2] = v3; + pDst[3] = v3; + pDst[4] = v2; + pDst[5] = v0; + pDst += 6; + m_nIndexCountMark += 2; + } + } + } + break; default: break; @@ -409,24 +483,30 @@ void CN3Cloak::ApplyOffset(__Vector3& vDif) void CN3Cloak::TickYaw(float fYaw) { // 회전이 있었다. - if (fYaw != m_fPrevYaw) + /* if (fYaw != m_fPrevYaw) { - if (fYaw - m_fPrevYaw > 0.0f) + const float deltafYaw = fYaw - m_fPrevYaw; + + if (deltafYaw > 2.0f) { if (m_eAnchorPattern == AMP_NONE && m_fAnchorPreserveTime < 0.0f) MoveAnchorLine(AMP_YAWCCW, 2.0f); } - else + else if (deltafYaw < -2.0f) { if (m_eAnchorPattern == AMP_NONE && m_fAnchorPreserveTime < 0.0f) MoveAnchorLine(AMP_YAWCW, 2.0f); } - } + }*/ m_fPrevYaw = fYaw; } void CN3Cloak::TickByPlayerMotion(e_CloakMove eCurMove) { + float angleFactor = 0.0f; + float angleMag = 0.0f; + bool doWind = false; + switch (eCurMove) { case CLOAK_MOVE_STOP: @@ -434,19 +514,27 @@ void CN3Cloak::TickByPlayerMotion(e_CloakMove eCurMove) break; case CLOAK_MOVE_WALK: - m_Force.z = 0.0005f; - m_GravityForce.y = -0.0025f; - if (m_eAnchorPattern == AMP_NONE && m_fAnchorPreserveTime < 0.0f) - MoveAnchorLine(AMP_MOVEXZ, 2.0f); + // m_Force.z = 0.0005f; + m_GravityForce.y = -0.0015f; + angleFactor = 0.314159f; + angleMag = -0.0003f; + doWind = true; + // if (m_eAnchorPattern == AMP_NONE + // && m_fAnchorPreserveTime < 0.0f) + // MoveAnchorLine(AMP_MOVEXZ, 2.0f); //m_GravityForce.y = (rand()%2+1)*-0.0015f; //TRACE("Apply force {}", m_Force.z); break; case CLOAK_MOVE_RUN: - m_Force.z = 0.0009f; - m_GravityForce.y = -0.0025f; - if (m_eAnchorPattern == AMP_NONE && m_fAnchorPreserveTime < 0.0f) - MoveAnchorLine(AMP_MOVEXZ2, 2.0f); + //m_Force.z = 0.0009f; + m_GravityForce.y = -0.0005f; + angleFactor = 1.0472f; + angleMag = -0.001f; + doWind = true; + break; + // if (m_eAnchorPattern == AMP_NONE && m_fAnchorPreserveTime < 0.0f) + // MoveAnchorLine(AMP_MOVEXZ2, 2.0f); //m_GravityForce.y = (rand()%2+1)*-0.0015f; //TRACE("Apply force {}", m_Force.z); break; @@ -454,9 +542,17 @@ void CN3Cloak::TickByPlayerMotion(e_CloakMove eCurMove) default: break; } + if (doWind) + { + const int r = rand() % 10; + const float angle = (r * 0.03f + 0.7f) * angleFactor; + m_Force.x = 0.0f; + m_Force.y = sinf(angle) * angleMag; + m_Force.z = cosf(angle) * angleMag; + } } -void CN3Cloak::MoveAnchorLine(e_Cloak_AnchorMovePattern eType, float fPreserveTime) +/* void CN3Cloak::MoveAnchorLine(e_Cloak_AnchorMovePattern eType, float fPreserveTime) { if (m_eAnchorPattern != AMP_NONE) return; @@ -523,7 +619,7 @@ void CN3Cloak::MoveAnchorLine(e_Cloak_AnchorMovePattern eType, float fPreserveTi m_fAnchorPreserveTime = fPreserveTime; m_eAnchorPattern = eType; -} +}*/ void CN3Cloak::RestoreAnchorLine() { diff --git a/src/N3Base/N3Cloak.h b/src/N3Base/N3Cloak.h index ee79f334e..517cc2074 100644 --- a/src/N3Base/N3Cloak.h +++ b/src/N3Base/N3Cloak.h @@ -8,6 +8,7 @@ #pragma once #include "N3Base.h" +#include "N3Mesh.h" inline constexpr int CLOAK_MAX_WIDTH = 7; inline constexpr int CLOAK_MAX_HEIGHT = 7; @@ -70,10 +71,20 @@ class CN3Cloak : public CN3Base vx = vx1, vy = vy1, vz = vz1; } }; - - void Init(CN3CPlug_Cloak* pPlugCloak); void SetLOD(int nLevel); void ApplyOffset(__Vector3& vDif); + void InitMeshTex(CN3Mesh* pMesh, CN3Texture* pTex) + { + m_pMesh = pMesh; + m_pTex = pTex; + } + void InitPhysics() + { + m_GravityForce = { 0.0f, -0.0015f, 0.0f }; + m_Force = {}; + m_fAnchorPreserveTime = 0.0f; + m_fOffsetRecoveryTime = 0.0f; + } protected: // Anchor @@ -93,7 +104,7 @@ class CN3Cloak : public CN3Base int m_nGridW, m_nGridH; int m_nLOD; - CN3PMesh* m_pPMesh; + CN3Mesh* m_pMesh; float m_fOffsetRecoveryTime; float m_fPrevYaw; @@ -106,9 +117,13 @@ class CN3Cloak : public CN3Base void TickYaw(float fYaw); void TickByPlayerMotion(e_CloakMove eCurMove); + uint16_t* m_pIndexMark = nullptr; + int m_nIndexCountMark = 0; + public: virtual void Tick(int nLOD, float fYaw, e_CloakMove eCurMove); - virtual void Render(__Matrix44& mtx); + virtual void Render(__Matrix44& mtx, CN3Texture* pTexColour = nullptr, + CN3Texture* pTexPattern = nullptr, CN3Texture* pTexClanMark = nullptr); void Release() override; }; diff --git a/src/Server/Ebenezer/User.cpp b/src/Server/Ebenezer/User.cpp index 71659de00..f6d0e42f0 100644 --- a/src/Server/Ebenezer/User.cpp +++ b/src/Server/Ebenezer/User.cpp @@ -1893,6 +1893,16 @@ void CUser::Attack(char* pBuf) } } +void CUser::SendServerIndex() +{ + int index = 0; + char buf[8] {}; + SetByte(buf, WIZ_SERVER_INDEX, index); + SetShort(buf, 1, index); + SetShort(buf, m_pMain->m_nServerNo, index); + Send(buf, index); +} + void CUser::SendMyInfo(int type) { // TODO: @@ -14173,6 +14183,7 @@ void CUser::GameStart(char* pBuf) // Started loading if (opcode == 1) { + SendServerIndex(); SendMyInfo(0); m_pMain->UserInOutForMe(this); m_pMain->NpcInOutForMe(this); @@ -14231,6 +14242,7 @@ void CUser::GameStart(char* pBuf) // TODO: // BlinkStart(); + SetUserAbility(); // If there is a permanent chat available!!! diff --git a/src/Server/Ebenezer/User.h b/src/Server/Ebenezer/User.h index a9199e8d9..e9f345282 100644 --- a/src/Server/Ebenezer/User.h +++ b/src/Server/Ebenezer/User.h @@ -542,6 +542,7 @@ class CUser : public TcpServerSocket void Chat(char* pBuf); void LogOut(); void SelCharToAgent(char* pBuf); + void SendServerIndex(); void SendMyInfo(int type); void SelectCharacter(const char* pBuf); void Send2AI_UserUpdateInfo();