- #ifndef __INC_GAME_MOTION_H__
- #define __INC_GAME_MOTION_H__
- #include "../../common/d3dtype.h"
- #include "../../common/CommonDefines.h"
- enum EMotionMode
- {
- MOTION_MODE_GENERAL,
- MOTION_MODE_ONEHAND_SWORD,
- MOTION_MODE_TWOHAND_SWORD,
- MOTION_MODE_DUALHAND_SWORD,
- MOTION_MODE_BOW,
- MOTION_MODE_BELL,
- MOTION_MODE_FAN,
- MOTION_MODE_HORSE,
- #ifdef ENABLE_WOLFMAN_CHARACTER
- MOTION_MODE_CLAW,
- #endif
- #ifdef OFFLINE_FARM
- MOTION_MODE_HORSE_ONEHAND_SWORD,
- MOTION_MODE_HORSE_TWOHAND_SWORD,
- MOTION_MODE_HORSE_DUALHAND_SWORD,
- MOTION_MODE_HORSE_BOW,
- MOTION_MODE_HORSE_BELL,
- MOTION_MODE_HORSE_FAN,
- MOTION_MODE_HORSE_CLAW,
- #endif
- MOTION_MODE_MAX_NUM
- };
- enum EPublicMotion
- {
- MOTION_NONE,
- MOTION_WAIT,
- MOTION_WALK,
- MOTION_RUN,
- MOTION_CHANGE_WEAPON,
- MOTION_DAMAGE,
- MOTION_DAMAGE_FLYING,
- MOTION_STAND_UP,
- MOTION_DAMAGE_BACK,
- MOTION_DAMAGE_FLYING_BACK,
- MOTION_STAND_UP_BACK,
- MOTION_DEAD,
- MOTION_DEAD_BACK,
- MOTION_NORMAL_ATTACK,
- MOTION_COMBO_ATTACK_1,
- MOTION_COMBO_ATTACK_2,
- MOTION_COMBO_ATTACK_3,
- MOTION_COMBO_ATTACK_4,
- MOTION_COMBO_ATTACK_5,
- MOTION_COMBO_ATTACK_6,
- MOTION_COMBO_ATTACK_7,
- MOTION_COMBO_ATTACK_8,
- MOTION_INTRO_WAIT,
- MOTION_INTRO_SELECTED,
- MOTION_INTRO_NOT_SELECTED,
- MOTION_SPAWN,
- MOTION_FISHING_THROW,
- MOTION_FISHING_WAIT,
- MOTION_FISHING_STOP,
- MOTION_FISHING_REACT,
- MOTION_FISHING_CATCH,
- MOTION_FISHING_FAIL,
- MOTION_STOP,
- MOTION_SPECIAL_1,
- MOTION_SPECIAL_2, // 34
- MOTION_SPECIAL_3, // 35
- MOTION_SPECIAL_4, // 36
- MOTION_SPECIAL_5, // 37
- PUBLIC_MOTION_END,
- MOTION_MAX_NUM = PUBLIC_MOTION_END,
- };
- #ifdef OFFLINE_FARM
- struct CDynamicSphereInstance // EterLib\CollisionData.h
- {
- D3DXVECTOR3 v3Position;
- D3DXVECTOR3 v3LastPosition;
- float fRadius;
- };
- typedef CDynamicSphereInstance THitTimePosition;
- #endif
- class CMob;
- class CMotion
- {
- #ifdef OFFLINE_FARM
- public:
- static constexpr float gsc_fAttackRadius = 20.0f; // ref: CActorInstance::__NormalAttackProcess
- typedef std::map<float, THitTimePosition> THitTimePositionMapEx;
- struct SCharacterMotionData
- {
- uint8_t race{ 0 };
- uint8_t weapon_type{ 0 };
- uint8_t combo_index{ 0 };
- bool riding{ false };
- };
- typedef std::map<SCharacterMotionData*, THitTimePositionMapEx> THitTimePositionMap;
- public:
- #endif
- public:
- CMotion();
- ~CMotion();
- bool LoadFromFile(const char * c_pszFileName);
- bool LoadMobSkillFromFile(const char * c_pszFileName, CMob * pMob, int iSkillIndex);
- float GetDuration() const;
- #ifdef OFFLINE_FARM
- float GetInputDuration() const;
- float GetWeaponLength() const;
- float GetExternalForce() const;
- THitTimePositionMapEx GetHitPositionData(const uint8_t c_nRace, const uint8_t c_nWeaponType, const uint8_t c_nComboIndex, bool c_bRiding) const;
- #endif
- const D3DVECTOR & GetAccumVector() const;
- bool IsEmpty();
- protected:
- bool m_isEmpty;
- float m_fDuration;
- #ifdef OFFLINE_FARM
- float m_fInputDuration;
- float m_fWeaponLength;
- float m_fExternalForce;
- std::string m_strBoneName;
- THitTimePositionMap m_mapHitPosition;
- #endif
- bool m_isAccumulation;
- D3DVECTOR m_vec3Accumulation;
- };
- typedef DWORD MOTION_KEY;
- #define MAKE_MOTION_KEY(mode, index) ( ((mode) << 24) | ((index) << 8) | (0) )
- #define MAKE_RANDOM_MOTION_KEY(mode, index, type) ( ((mode) << 24) | ((index) << 8) | (type) )
- #define GET_MOTION_MODE(key) ((BYTE) ((key >> 24) & 0xFF))
- #define GET_MOTION_INDEX(key) ((WORD) ((key >> 8) & 0xFFFF))
- #define GET_MOTION_SUB_INDEX(key) ((BYTE) ((key) & 0xFF))
- class CMotionSet
- {
- public:
- typedef std::map<DWORD, CMotion *> TContainer;
- typedef TContainer::iterator iterator;
- typedef TContainer::const_iterator const_iterator;
- public:
- CMotionSet();
- ~CMotionSet();
- void Insert(DWORD dwKey, CMotion * pkMotion);
- bool Load(const char * szFileName, int mode, int motion);
- const CMotion * GetMotion(DWORD dwKey) const;
- #ifdef OFFLINE_FARM
- CMotion::THitTimePositionMapEx GetHitPositionData(const uint8_t c_nRace, const uint8_t c_nWeaponType, const uint8_t c_nComboIndex, bool c_bRiding);
- #endif
- protected:
- // DWORD = MOTION_KEY
- TContainer m_map_pkMotion;
- };
- class CMotionManager : public singleton<CMotionManager>
- {
- public:
- #ifdef OFFLINE_FARM
- struct SCharacterSkillData
- {
- float fRadius;
- D3DVECTOR v3Position;
- float fStartingTime;
- };
- #endif
- typedef std::map<DWORD, CMotionSet *> TContainer;
- typedef TContainer::iterator iterator;
- CMotionManager();
- virtual ~CMotionManager();
- bool Build();
- const CMotionSet * GetMotionSet(DWORD dwVnum);
- const CMotion * GetMotion(DWORD dwVnum, DWORD dwKey);
- float GetMotionDuration(DWORD dwVnum, DWORD dwKey);
- #ifdef OFFLINE_FARM
- DWORD GetMotionInputDuration(DWORD dwVnum, DWORD dwKey);
- float GetMotionWeaponLength(DWORD dwVnum, DWORD dwKey);
- float GetMotionExternalForce(DWORD dwVnum, DWORD dwKey);
- CMotion::THitTimePositionMapEx GetHitPositionData(const uint8_t c_nRace, const uint8_t c_nWeaponType, const uint8_t c_nComboIndex, bool c_bRiding);
- bool GetSkillData(BYTE byRace, BYTE bySkillGrade, DWORD dwSkillVnum, std::vector <SCharacterSkillData>& vecrfData);
- void RegisterPCSkillMotion(BYTE byRace, BYTE bySkillGrade, DWORD dwSkillVnum, const std::vector <SCharacterSkillData>& vecData);
- #endif
- // POLYMORPH_BUG_FIX
- float GetNormalAttackDuration(DWORD dwVnum);
- // END_OF_POLYMORPH_BUG_FIX
- protected:
- // DWORD = JOB or MONSTER VNUM
- TContainer m_map_pkMotionSet;
- // POLYMORPH_BUG_FIX
- std::map<DWORD, float> m_map_normalAttackDuration;
- // END_OF_POLYMORPH_BUG_FIX
- #ifdef OFFLINE_FARM
- std::map <std::tuple <BYTE /* byRace */, BYTE /* bySkillGrade */, DWORD /* dwSkillVnum */>, std::vector <SCharacterSkillData> /* vecData */> m_mapSkillData;
- #endif
- };
- #endif
- #include "stdafx.h"
- #include "../../common/stl.h"
- #include "constants.h"
- #include "motion.h"
- #include "text_file_loader.h"
- #include "mob_manager.h"
- #include "char.h"
- #include "../../common/CommonDefines.h"
- // POLYMORPH_BUG_FIX
- static float MSA_GetNormalAttackDuration(const char* msaPath)
- {
- float duration = 99.0f;
- FILE * fp = fopen(msaPath, "rt");
- if (!fp)
- return duration;
- char line[1024];
- while (fgets(line, sizeof(line), fp))
- {
- char key[1024];
- char val[1024];
- sscanf(line, "%s %s", key, val);
- if (strcmp(key, "MotionDuration") == 0)
- {
- duration = atof(val);
- break;
- }
- }
- fclose(fp);
- return duration;
- }
- static float MOB_GetNormalAttackDuration(TMobTable* mobTable)
- {
- float minDuration = 99.0f;
- const char * folder = mobTable->szFolder;
- char motlistPath[1024];
- snprintf(motlistPath, sizeof(motlistPath), "data/monster/%s/motlist.txt", folder);
- FILE * fp = fopen(motlistPath, "rt");
- if (!fp)
- return minDuration;
- char line[1024];
- while (fgets(line, sizeof(line), fp))
- {
- char mode[1024];
- char type[1024];
- char msaName[1024];
- int percent;
- sscanf(line, "%s %s %s %d", mode, type, msaName, &percent);
- if (strcmp(mode, "GENERAL") == 0 && strncmp(type, "NORMAL_ATTACK", 13) == 0)
- {
- char msaPath[1024];
- snprintf(msaPath, sizeof(msaPath), "data/monster/%s/%s", folder, msaName);
- float curDuration = MSA_GetNormalAttackDuration(msaPath);
- if (curDuration < minDuration)
- minDuration = curDuration;
- }
- }
- fclose(fp);
- return minDuration;
- }
- // END_OF_POLYMORPH_BUG_FIX
- static const char* GetMotionFileName(TMobTable* mobTable, EPublicMotion motion)
- {
- char buf[1024];
- const char * folder = mobTable->szFolder;
- snprintf(buf, sizeof(buf), "data/monster/%s/motlist.txt", folder);
- FILE * fp = fopen(buf, "rt");
- char * v[4];
- if (fp != NULL)
- {
- const char* field = NULL;
- switch (motion)
- {
- case MOTION_WALK : field = "WALK"; break;
- case MOTION_RUN : field = "RUN"; break;
- case MOTION_NORMAL_ATTACK : field = "NORMAL_ATTACK"; break;
- case MOTION_SPECIAL_1 : field = "SPECIAL"; break;
- case MOTION_SPECIAL_2 : field = "SPECIAL1"; break;
- case MOTION_SPECIAL_3 : field = "SPECIAL2"; break;
- case MOTION_SPECIAL_4 : field = "SPECIAL3"; break;
- case MOTION_SPECIAL_5 : field = "SPECIAL4"; break;
- default:
- fclose(fp);
- sys_err("Motion: no process for this motion(%d) vnum(%d)", motion, mobTable->dwVnum);
- return NULL;
- }
- while (fgets(buf, 1024, fp))
- {
- v[0] = strtok(buf, " \t\r\n");
- v[1] = strtok(NULL, " \t\r\n");
- v[2] = strtok(NULL, " \t\r\n");
- v[3] = strtok(NULL, " \t\r\n");
- if (NULL != v[0] && NULL != v[1] && NULL != v[2] && NULL != v[3] && !strcasecmp(v[1], field))
- {
- fclose(fp);
- static std::string str;
- str = "data/monster/";
- str += folder;
- str += "/";
- str += v[2];
- return str.c_str();
- }
- }
- fclose(fp);
- }
- else
- {
- sys_err("Motion: %s have not motlist.txt vnum(%d) folder(%s)", folder, mobTable->dwVnum, mobTable->szFolder);
- }
- return NULL;
- }
- static void LoadMotion(CMotionSet* pMotionSet, TMobTable* mob_table, EPublicMotion motion)
- {
- const char* cpFileName = GetMotionFileName(mob_table, motion);
- if (cpFileName == NULL)
- {
- return;
- }
- CMotion* pMotion = M2_NEW CMotion;
- if (pMotion->LoadFromFile(cpFileName) == true)
- {
- if (motion == MOTION_RUN
- && 0.0f == pMotion->GetAccumVector().y
- && !IS_SET(mob_table->dwAIFlag, AIFLAG_NOMOVE)) // @warme013 (don't show this message for non-movable mobs)
- sys_err("cannot find accumulation data in file '%s'", cpFileName);
- pMotionSet->Insert(MAKE_MOTION_KEY(MOTION_MODE_GENERAL, motion), pMotion);
- }
- else
- {
- M2_DELETE(pMotion);
- sys_err("Motion: Load failed vnum(%d) motion(%d) file(%s)", mob_table->dwVnum, motion, cpFileName);
- }
- }
- static void LoadSkillMotion(CMotionSet* pMotionSet, CMob* pMob, EPublicMotion motion)
- {
- int idx = 0;
- switch (motion)
- {
- case MOTION_SPECIAL_1 : idx = 0; break;
- case MOTION_SPECIAL_2 : idx = 1; break;
- case MOTION_SPECIAL_3 : idx = 2; break;
- case MOTION_SPECIAL_4 : idx = 3; break;
- case MOTION_SPECIAL_5 : idx = 4; break;
- default :
- return;
- }
- TMobTable* mob_table = &pMob->m_table;
- if (mob_table->Skills[idx].dwVnum == 0) return;
- const char* cpFileName = GetMotionFileName(mob_table, motion);
- if (cpFileName == NULL) return;
- CMotion* pMotion = M2_NEW CMotion;
- if (pMotion->LoadMobSkillFromFile(cpFileName, pMob, idx) == true)
- {
- pMotionSet->Insert(MAKE_MOTION_KEY(MOTION_MODE_GENERAL, motion), pMotion);
- }
- else
- {
- if (mob_table->Skills[idx].dwVnum != 0)
- {
- sys_err("Motion: Skill exist but no motion data for index %d mob %u skill %u",
- idx, mob_table->dwVnum, mob_table->Skills[idx].dwVnum);
- }
- M2_DELETE(pMotion);
- }
- }
- CMotionManager::CMotionManager()
- {
- }
- CMotionManager::~CMotionManager()
- {
- iterator it = m_map_pkMotionSet.begin();
- for ( ; it != m_map_pkMotionSet.end(); ++it) {
- M2_DELETE(it->second);
- }
- }
- const CMotionSet * CMotionManager::GetMotionSet(DWORD dwVnum)
- {
- iterator it = m_map_pkMotionSet.find(dwVnum);
- if (m_map_pkMotionSet.end() == it)
- return NULL;
- return it->second;
- }
- const CMotion * CMotionManager::GetMotion(DWORD dwVnum, DWORD dwKey)
- {
- const CMotionSet * pkMotionSet = GetMotionSet(dwVnum);
- if (!pkMotionSet)
- return NULL;
- return pkMotionSet->GetMotion(dwKey);
- }
- float CMotionManager::GetMotionDuration(DWORD dwVnum, DWORD dwKey)
- {
- const CMotion * pkMotion = GetMotion(dwVnum, dwKey);
- return pkMotion ? pkMotion->GetDuration() : 0.0f;
- }
- #ifdef OFFLINE_FARM
- DWORD CMotionManager::GetMotionInputDuration(DWORD dwVnum, DWORD dwKey)
- {
- const CMotion* pkMotion = GetMotion(dwVnum, dwKey);
- if (pkMotion)
- {
- float fDuration = pkMotion->GetInputDuration();
- if (fDuration)
- {
- return static_cast<uint32_t>(std::round(fDuration * 1000));
- }
- }
- return 0;
- }
- float CMotionManager::GetMotionWeaponLength(DWORD dwVnum, DWORD dwKey)
- {
- const CMotion* pkMotion = GetMotion(dwVnum, dwKey);
- return pkMotion ? pkMotion->GetWeaponLength() : 0.0f;
- }
- float CMotionManager::GetMotionExternalForce(DWORD dwVnum, DWORD dwKey)
- {
- const CMotion* pkMotion = GetMotion(dwVnum, dwKey);
- return pkMotion ? pkMotion->GetExternalForce() : 0.0f;
- }
- CMotion::THitTimePositionMapEx CMotionManager::GetHitPositionData(const uint8_t c_nRace, const uint8_t c_nWeaponType, const uint8_t c_nComboIndex, bool c_bRiding)
- {
- auto it = m_map_pkMotionSet.begin();
- for (; it != m_map_pkMotionSet.end(); ++it)
- {
- const auto pkMotionSet = it->second;
- if (!pkMotionSet)
- continue;
- const auto mapHitPosition = pkMotionSet->GetHitPositionData(c_nRace, c_nWeaponType, c_nComboIndex, c_bRiding);
- if (!mapHitPosition.empty())
- return mapHitPosition;
- }
- return CMotion::THitTimePositionMapEx();
- }
- bool CMotionManager::GetSkillData(BYTE byRace, BYTE bySkillGrade, DWORD dwSkillVnum, std::vector <SCharacterSkillData>& vecrfData)
- {
- for (const auto& it : m_mapSkillData)
- {
- const auto& [byCurRace, byCurrSkillGrade, dwCurSkillVnum] = it.first;
- if (byCurRace == byRace && byCurrSkillGrade == bySkillGrade && dwCurSkillVnum == dwSkillVnum)
- {
- vecrfData = it.second;
- return true;
- }
- }
- return false;
- }
- void CMotionManager::RegisterPCSkillMotion(BYTE byRace, BYTE bySkillGrade, DWORD dwSkillVnum, const std::vector<SCharacterSkillData>& vecData)
- {
- m_mapSkillData[std::make_tuple(byRace, bySkillGrade, dwSkillVnum)] = vecData;
- }
- #endif
- // POLYMORPH_BUG_FIX
- float CMotionManager::GetNormalAttackDuration(DWORD dwVnum)
- {
- std::map<DWORD, float>::iterator f = m_map_normalAttackDuration.find(dwVnum);
- if (m_map_normalAttackDuration.end() == f)
- return 0.0f;
- else
- return f->second;
- }
- // END_OF_POLYMORPH_BUG_FIX
- enum EMotionEventType
- {
- MOTION_EVENT_TYPE_NONE, // 0
- MOTION_EVENT_TYPE_EFFECT, // 1
- MOTION_EVENT_TYPE_SCREEN_WAVING, // 2
- MOTION_EVENT_TYPE_SCREEN_FLASHING, // 3
- MOTION_EVENT_TYPE_SPECIAL_ATTACKING, // 4
- MOTION_EVENT_TYPE_SOUND, // 5
- MOTION_EVENT_TYPE_FLY, // 6
- MOTION_EVENT_TYPE_CHARACTER_SHOW, // 7
- MOTION_EVENT_TYPE_CHARACTER_HIDE, // 8
- MOTION_EVENT_TYPE_WARP, // 9
- MOTION_EVENT_TYPE_EFFECT_TO_TARGET, // 10
- #ifdef ENABLE_WOLFMAN_CHARACTER
- MOTION_EVENT_TYPE_RELATIVE_MOVE_ON, // 11
- MOTION_EVENT_TYPE_RELATIVE_MOVE_OFF, // 12
- #endif
- MOTION_EVENT_TYPE_MAX_NUM, // 13
- };
- bool CMotionManager::Build()
- {
- const char * c_apszFolderName[MAIN_RACE_MAX_NUM] =
- {
- "data/pc/warrior",
- "data/pc/assassin",
- "data/pc/sura",
- "data/pc/shaman",
- "data/pc2/warrior",
- "data/pc2/assassin",
- "data/pc2/sura",
- "data/pc2/shaman",
- #ifdef ENABLE_WOLFMAN_CHARACTER
- "data/pc3/wolfman",
- #endif
- };
- for (int i = 0; i < MAIN_RACE_MAX_NUM; ++i)
- {
- CMotionSet * pkMotionSet = M2_NEW CMotionSet;
- m_map_pkMotionSet.emplace(i, pkMotionSet);
- char sz[256];
- snprintf(sz, sizeof(sz), "%s/general/run.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_GENERAL, MOTION_RUN);
- snprintf(sz, sizeof(sz), "%s/general/walk.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_GENERAL, MOTION_WALK);
- snprintf(sz, sizeof(sz), "%s/twohand_sword/run.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_TWOHAND_SWORD, MOTION_RUN);
- snprintf(sz, sizeof(sz), "%s/twohand_sword/walk.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_TWOHAND_SWORD, MOTION_WALK);
- snprintf(sz, sizeof(sz), "%s/onehand_sword/run.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_ONEHAND_SWORD, MOTION_RUN);
- snprintf(sz, sizeof(sz), "%s/onehand_sword/walk.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_ONEHAND_SWORD, MOTION_WALK);
- snprintf(sz, sizeof(sz), "%s/dualhand_sword/run.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_DUALHAND_SWORD, MOTION_RUN);
- snprintf(sz, sizeof(sz), "%s/dualhand_sword/walk.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_DUALHAND_SWORD, MOTION_WALK);
- snprintf(sz, sizeof(sz), "%s/bow/run.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_BOW, MOTION_RUN);
- snprintf(sz, sizeof(sz), "%s/bow/walk.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_BOW, MOTION_WALK);
- snprintf(sz, sizeof(sz), "%s/bell/run.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_BELL, MOTION_RUN);
- snprintf(sz, sizeof(sz), "%s/bell/walk.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_BELL, MOTION_WALK);
- snprintf(sz, sizeof(sz), "%s/fan/run.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_FAN, MOTION_RUN);
- snprintf(sz, sizeof(sz), "%s/fan/walk.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_FAN, MOTION_WALK);
- snprintf(sz, sizeof(sz), "%s/horse/run.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_HORSE, MOTION_RUN);
- snprintf(sz, sizeof(sz), "%s/horse/walk.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_HORSE, MOTION_WALK);
- #ifdef ENABLE_WOLFMAN_CHARACTER
- snprintf(sz, sizeof(sz), "%s/claw/run.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_CLAW, MOTION_RUN);
- snprintf(sz, sizeof(sz), "%s/claw/walk.msa", c_apszFolderName[i]);
- pkMotionSet->Load(sz, MOTION_MODE_CLAW, MOTION_WALK);
- #endif
- #ifdef OFFLINE_FARM
- // Load combo attack motions
- for (int j = 1; j <= 7; ++j) // 7=max combo attack count
- {
- if (i == MAIN_RACE_WARRIOR_M || i == MAIN_RACE_WARRIOR_W)
- {
- snprintf(sz, sizeof(sz), "%s/twohand_sword/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_TWOHAND_SWORD, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- snprintf(sz, sizeof(sz), "%s/onehand_sword/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_ONEHAND_SWORD, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- }
- else if (i == MAIN_RACE_ASSASSIN_M || i == MAIN_RACE_ASSASSIN_W)
- {
- snprintf(sz, sizeof(sz), "%s/dualhand_sword/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_DUALHAND_SWORD, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- snprintf(sz, sizeof(sz), "%s/onehand_sword/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_ONEHAND_SWORD, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- // Bow has no combo attack
- }
- else if (i == MAIN_RACE_SURA_M || i == MAIN_RACE_SURA_W)
- {
- snprintf(sz, sizeof(sz), "%s/onehand_sword/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_ONEHAND_SWORD, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- }
- else if (i == MAIN_RACE_SHAMAN_M || i == MAIN_RACE_SHAMAN_W)
- {
- snprintf(sz, sizeof(sz), "%s/bell/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_BELL, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- snprintf(sz, sizeof(sz), "%s/fan/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_FAN, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- }
- #ifdef ENABLE_WOLFMAN_CHARACTER
- else if (i == MAIN_RACE_WOLFMAN_M)
- {
- snprintf(sz, sizeof(sz), "%s/claw/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_CLAW, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- }
- #endif
- }
- for (int j = 1; j <= 3; ++j) // 3=max horse combo attack count
- {
- if (i == MAIN_RACE_WARRIOR_M || i == MAIN_RACE_WARRIOR_W)
- {
- snprintf(sz, sizeof(sz), "%s/horse_twohand_sword/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_HORSE_TWOHAND_SWORD, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- snprintf(sz, sizeof(sz), "%s/horse_onehand_sword/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_HORSE_ONEHAND_SWORD, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- }
- else if (i == MAIN_RACE_ASSASSIN_M || i == MAIN_RACE_ASSASSIN_W)
- {
- snprintf(sz, sizeof(sz), "%s/horse_dualhand_sword/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_HORSE_DUALHAND_SWORD, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- snprintf(sz, sizeof(sz), "%s/horse_onehand_sword/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_HORSE_ONEHAND_SWORD, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- }
- else if (i == MAIN_RACE_SURA_M || i == MAIN_RACE_SURA_W)
- {
- snprintf(sz, sizeof(sz), "%s/horse_onehand_sword/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_HORSE_ONEHAND_SWORD, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- }
- else if (i == MAIN_RACE_SHAMAN_M || i == MAIN_RACE_SHAMAN_W)
- {
- snprintf(sz, sizeof(sz), "%s/horse_bell/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_HORSE_BELL, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- snprintf(sz, sizeof(sz), "%s/horse_fan/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_HORSE_FAN, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- }
- #ifdef ENABLE_WOLFMAN_CHARACTER
- else if (i == MAIN_RACE_WOLFMAN_M)
- {
- snprintf(sz, sizeof(sz), "%s/horse_claw/combo_0%d.msa", c_apszFolderName[i], j);
- pkMotionSet->Load(sz, MOTION_MODE_HORSE_CLAW, (EPublicMotion)(MOTION_COMBO_ATTACK_1 + j - 1));
- }
- #endif
- }
- #endif
- extern std::vector <DWORD> GetSkillSet(uint8_t race, uint8_t skill_group);
- extern std::string GetSkillCodeName(DWORD dwVnum);
- #ifdef OFFLINE_FARM
- // Skill motions
- if (i == MAIN_RACE_WARRIOR_M || i == MAIN_RACE_WARRIOR_W)
- {
- for (int j = 0; j < SKILL_GROUP_MAX_NUM; ++j)
- {
- const auto vecSkillSet = GetSkillSet(i, j);
- for (const auto dwSkillVnum : vecSkillSet)
- {
- const auto strSkillCodeName = GetSkillCodeName(dwSkillVnum);
- if (strSkillCodeName.empty())
- continue;
- for (int k = 1; k < SKILL_GRADE_COUNT + 1; ++k)
- {
- if (k == 1)
- snprintf(sz, sizeof(sz), "%s/skill/%s.msa", c_apszFolderName[i], strSkillCodeName.c_str());
- else
- snprintf(sz, sizeof(sz), "%s/skill/%s_%d.msa", c_apszFolderName[i], strSkillCodeName.c_str(), k);
- if (!pkMotionSet->Load(sz, MOTION_MODE_GENERAL, (EPublicMotion)(MOTION_SPECIAL_1 + k)))
- {
- sys_err("W-Motion: Load failed vnum(%d) motion(%d) file(%s)", i, MOTION_SPECIAL_1 + k, sz);
- }
- }
- }
- }
- }
- else if (i == MAIN_RACE_ASSASSIN_M || i == MAIN_RACE_ASSASSIN_W)
- {
- for (int j = 0; j < SKILL_GROUP_MAX_NUM; ++j)
- {
- const auto vecSkillSet = GetSkillSet(i, j);
- for (const auto dwSkillVnum : vecSkillSet)
- {
- const auto strSkillCodeName = GetSkillCodeName(dwSkillVnum);
- if (strSkillCodeName.empty())
- continue;
- for (int k = 1; k < SKILL_GRADE_COUNT + 1; ++k)
- {
- if (k == 1)
- snprintf(sz, sizeof(sz), "%s/skill/%s.msa", c_apszFolderName[i], strSkillCodeName.c_str());
- else
- snprintf(sz, sizeof(sz), "%s/skill/%s_%d.msa", c_apszFolderName[i], strSkillCodeName.c_str(), k);
- if (k > 1)
- {
- if (strSkillCodeName == "gigung") // only one motion for some skills
- continue;
- }
- if (!pkMotionSet->Load(sz, MOTION_MODE_GENERAL, (EPublicMotion)(MOTION_SPECIAL_1 + k)))
- {
- sys_err("A-Motion: Load failed vnum(%d) motion(%d) file(%s)", i, MOTION_SPECIAL_1 + k, sz);
- }
- }
- }
- }
- }
- else if (i == MAIN_RACE_SURA_M || i == MAIN_RACE_SURA_W)
- {
- for (int j = 0; j < SKILL_GROUP_MAX_NUM; ++j)
- {
- const auto vecSkillSet = GetSkillSet(i, j);
- for (const auto dwSkillVnum : vecSkillSet)
- {
- const auto strSkillCodeName = GetSkillCodeName(dwSkillVnum);
- if (strSkillCodeName.empty())
- continue;
- for (int k = 1; k < SKILL_GRADE_COUNT + 1; ++k)
- {
- if (k == 1)
- snprintf(sz, sizeof(sz), "%s/skill/%s.msa", c_apszFolderName[i], strSkillCodeName.c_str());
- else
- snprintf(sz, sizeof(sz), "%s/skill/%s_%d.msa", c_apszFolderName[i], strSkillCodeName.c_str(), k);
- if (!pkMotionSet->Load(sz, MOTION_MODE_GENERAL, (EPublicMotion)(MOTION_SPECIAL_1 + k)))
- {
- sys_err("S-Motion: Load failed vnum(%d) motion(%d) file(%s)", i, MOTION_SPECIAL_1 + k, sz);
- }
- }
- }
- }
- }
- else if (i == MAIN_RACE_SHAMAN_M || i == MAIN_RACE_SHAMAN_W)
- {
- for (int j = 0; j < SKILL_GROUP_MAX_NUM; ++j)
- {
- const auto vecSkillSet = GetSkillSet(i, j);
- for (const auto dwSkillVnum : vecSkillSet)
- {
- const auto strSkillCodeName = GetSkillCodeName(dwSkillVnum);
- if (strSkillCodeName.empty())
- continue;
- for (int k = 1; k < SKILL_GRADE_COUNT + 1; ++k)
- {
- if (k == 1)
- snprintf(sz, sizeof(sz), "%s/skill/%s.msa", c_apszFolderName[i], strSkillCodeName.c_str());
- else
- snprintf(sz, sizeof(sz), "%s/skill/%s_%d.msa", c_apszFolderName[i], strSkillCodeName.c_str(), k);
- if (k == 1)
- {
- if (strSkillCodeName == "hosin" || strSkillCodeName == "boho" || strSkillCodeName == "gicheon" || // for some skills, first motion does not exist
- strSkillCodeName == "jeongeop" || strSkillCodeName == "kwaesok")
- continue;
- }
- if (!pkMotionSet->Load(sz, MOTION_MODE_GENERAL, (EPublicMotion)(MOTION_SPECIAL_1 + k)))
- {
- sys_err("SH-Motion: Load failed vnum(%d) motion(%d) file(%s)", i, MOTION_SPECIAL_1 + k, sz);
- }
- }
- }
- }
- }
- #endif
- #ifdef OFFLINE_FARM
- #ifdef ENABLE_WOLFMAN_CHARACTER
- else if (i == MAIN_RACE_WOLFMAN_M)
- {
- for (int j = 0; j < SKILL_GROUP_MAX_NUM; ++j)
- {
- const auto vecSkillSet = GetSkillSet(i, j);
- for (const auto dwSkillVnum : vecSkillSet)
- {
- const auto strSkillCodeName = GetSkillCodeName(dwSkillVnum);
- if (strSkillCodeName.empty())
- continue;
- for (int k = 1; k < SKILL_GRADE_COUNT + 1; ++k)
- {
- if (k == 1)
- snprintf(sz, sizeof(sz), "%s/skill/%s.msa", c_apszFolderName[i], strSkillCodeName.c_str());
- else
- snprintf(sz, sizeof(sz), "%s/skill/%s_%d.msa", c_apszFolderName[i], strSkillCodeName.c_str(), k);
- if (!pkMotionSet->Load(sz, MOTION_MODE_GENERAL, (EPublicMotion)(MOTION_SPECIAL_1 + k)))
- {
- sys_err("WM-Motion: Load failed vnum(%d) motion(%d) file(%s)", i, MOTION_SPECIAL_1 + k, sz);
- }
- }
- }
- }
- }
- #endif
- #endif
- }
- CMobManager::iterator it = CMobManager::instance().begin();
- while (it != CMobManager::instance().end())
- {
- CMob * pkMob = (it++)->second;
- TMobTable * t = &pkMob->m_table;
- if ('\0' != t->szFolder[0])
- {
- CMotionSet * pkMotionSet = M2_NEW CMotionSet;
- m_map_pkMotionSet.emplace(t->dwVnum, pkMotionSet);
- LoadMotion(pkMotionSet, t, MOTION_WALK);
- LoadMotion(pkMotionSet, t, MOTION_RUN);
- LoadMotion(pkMotionSet, t, MOTION_NORMAL_ATTACK);
- LoadSkillMotion(pkMotionSet, pkMob, MOTION_SPECIAL_1);
- LoadSkillMotion(pkMotionSet, pkMob, MOTION_SPECIAL_2);
- LoadSkillMotion(pkMotionSet, pkMob, MOTION_SPECIAL_3);
- LoadSkillMotion(pkMotionSet, pkMob, MOTION_SPECIAL_4);
- LoadSkillMotion(pkMotionSet, pkMob, MOTION_SPECIAL_5);
- // POLYMORPH_BUG_FIX
- float normalAttackDuration = MOB_GetNormalAttackDuration(t);
- sys_log(0, "mob_normal_attack_duration:%d:%s:%.2f", t->dwVnum, t->szFolder, normalAttackDuration);
- m_map_normalAttackDuration.emplace(t->dwVnum, normalAttackDuration);
- // END_OF_POLYMORPH_BUG_FIX
- }
- }
- return true;
- }
- CMotionSet::CMotionSet()
- {
- }
- CMotionSet::~CMotionSet()
- {
- iterator it = m_map_pkMotion.begin();
- for ( ; it != m_map_pkMotion.end(); ++it) {
- M2_DELETE(it->second);
- }
- }
- const CMotion * CMotionSet::GetMotion(DWORD dwKey) const
- {
- const_iterator it = m_map_pkMotion.find(dwKey);
- if (it == m_map_pkMotion.end())
- return NULL;
- return it->second;
- }
- #ifdef OFFLINE_FARM
- CMotion::THitTimePositionMapEx CMotionSet::GetHitPositionData(const uint8_t c_nRace, const uint8_t c_nWeaponType, const uint8_t c_nComboIndex, bool c_bRiding)
- {
- auto it = m_map_pkMotion.begin();
- for (; it != m_map_pkMotion.end(); ++it)
- {
- const auto pkMotion = it->second;
- if (!pkMotion)
- continue;
- const auto& mapData = pkMotion->GetHitPositionData(c_nRace, c_nWeaponType, c_nComboIndex, c_bRiding);
- if (!mapData.empty())
- {
- return mapData;
- }
- }
- return {};
- }
- #endif
- void CMotionSet::Insert(DWORD dwKey, CMotion * pkMotion)
- {
- m_map_pkMotion.emplace(dwKey, pkMotion);
- }
- bool CMotionSet::Load(const char * szFileName, int mode, int motion)
- {
- CMotion * pkMotion = M2_NEW CMotion;
- if (!pkMotion->LoadFromFile(szFileName))
- {
- M2_DELETE(pkMotion);
- return false;
- }
- Insert(MAKE_MOTION_KEY(mode, motion), pkMotion);
- return true;
- }
- CMotion::CMotion() : m_isEmpty(true), m_fDuration(0.0f), m_isAccumulation(false)
- {
- m_vec3Accumulation.x = 0.0f;
- m_vec3Accumulation.y = 0.0f;
- m_vec3Accumulation.z = 0.0f;
- #ifdef OFFLINE_FARM
- m_fInputDuration = 0.0f;
- m_fWeaponLength = 0.0f;
- m_fExternalForce = 0.0f;
- #endif
- }
- CMotion::~CMotion()
- {
- #ifdef OFFLINE_FARM
- for (THitTimePositionMap::iterator it = m_mapHitPosition.begin(); it != m_mapHitPosition.end(); ++it)
- {
- M2_DELETE(it->first);
- }
- #endif
- }
- std::vector<std::string> SplitString(const std::string& str, char delimiter)
- {
- std::vector<std::string> tokens;
- std::string token;
- size_t start = 0;
- size_t end = 0;
- while ((end = str.find(delimiter, start)) != std::string::npos)
- {
- token = str.substr(start, end - start);
- tokens.push_back(token);
- start = end + 1;
- }
- tokens.push_back(str.substr(start));
- return tokens;
- }
- #ifdef OFFLINE_FARM
- bool ParseSkillFile(const char* c_pszFileName, int& race, int& job, int& skillVnum, int& skillGrade, std::string& codeName)
- {
- const std::string strFileName = c_pszFileName;
- std::vector<std::string> pathParts = SplitString(strFileName, '/');
- if (pathParts.size() < 4)
- {
- sys_err("Invalid skill file path: %s", c_pszFileName);
- return false;
- }
- // Get the job part (should be pc, pc2, or pc3)
- const std::string& jobPart = pathParts[1];
- // Get the race part
- const std::string& racePart = pathParts[2];
- // Get the last part (filename with extension)
- std::string fileName = pathParts[pathParts.size() - 1];
- // Split filename by '.' to get the code name
- std::vector<std::string> fileNameParts = SplitString(fileName, '.');
- if (fileNameParts.empty())
- {
- sys_err("Invalid skill file name: %s", c_pszFileName);
- return false;
- }
- codeName = fileNameParts[0];
- if (codeName.find("_") == std::string::npos)
- {
- skillGrade = 0;
- }
- else
- {
- if (codeName.find("split_slash") != std::string::npos || codeName.find("wind_death") != std::string::npos ||
- codeName.find("blue_possession") != std::string::npos || codeName.find("red_possession") != std::string::npos ||
- codeName.find("reef_attack") != std::string::npos)
- {
- std::vector<std::string> codeNameParts = SplitString(codeName, '_');
- if (codeNameParts.size() == 3)
- {
- codeName = codeNameParts[0] + "_" + codeNameParts[1];
- str_to_number(skillGrade, codeNameParts[2].c_str());
- skillGrade -= 1;
- }
- else
- {
- codeName = codeNameParts[0] + "_" + codeNameParts[1];
- skillGrade = 0;
- }
- }
- else
- {
- std::vector<std::string> codeNameParts = SplitString(codeName, '_');
- if (codeNameParts.size() != 2)
- {
- sys_err("Invalid skill code name: %s", codeName.c_str());
- return false;
- }
- codeName = codeNameParts[0];
- str_to_number(skillGrade, codeNameParts[1].c_str());
- skillGrade -= 1;
- }
- }
- // Parse race
- if (racePart == "warrior")
- race = JOB_WARRIOR;
- else if (racePart == "assassin")
- race = JOB_ASSASSIN;
- else if (racePart == "sura")
- race = JOB_SURA;
- else if (racePart == "shaman")
- race = JOB_SHAMAN;
- #ifdef ENABLE_WOLFMAN_CHARACTER
- else if (racePart == "wolfman")
- race = JOB_WOLFMAN;
- #endif
- else
- {
- sys_err("Invalid race part: %s", racePart.c_str());
- return false;
- }
- // Parse job
- if (jobPart == "pc")
- {
- job = 0;
- }
- else if (jobPart == "pc2")
- {
- job = 1;
- }
- #ifdef ENABLE_WOLFMAN_CHARACTER
- else if (jobPart == "pc3")
- {
- job = 0;
- }
- #endif
- else
- {
- sys_err("Invalid job part: %s", jobPart.c_str());
- return false;
- }
- // Get skill vnum from code name
- extern DWORD GetSkillVnumFromCodeName(const std::string & strCodeName);
- skillVnum = GetSkillVnumFromCodeName(codeName);
- if (skillVnum == 0)
- {
- sys_err("Invalid skill code name: %s", codeName.c_str());
- return false;
- }
- return true;
- }
- #endif
- bool CMotion::LoadMobSkillFromFile(const char * c_pszFileName, CMob* pMob, int iSkillIndex)
- {
- CTextFileLoader rkTextFileLoader;
- if (!rkTextFileLoader.Load(c_pszFileName))
- return false;
- //if (rkTextFileLoader.IsEmpty())
- //return false;
- rkTextFileLoader.SetTop();
- if (!rkTextFileLoader.GetTokenFloat("motionduration", &m_fDuration))
- {
- sys_err("Motion: no motion duration %s", c_pszFileName);
- return false;
- }
- //if (rkTextFileLoader.GetTokenPosition("accumulation", &m_vec3Accumulation))
- //m_isAccumulation = true;
- std::string strNodeName;
- for (DWORD i = 0; i < rkTextFileLoader.GetChildNodeCount(); ++i)
- {
- //CTextFileLoader::CGotoChild GotoChild(rkTextFileLoader, i);
- rkTextFileLoader.SetChildNode(i);
- rkTextFileLoader.GetCurrentNodeName(&strNodeName);
- if (0 == strNodeName.compare("motioneventdata"))
- {
- DWORD dwMotionEventDataCount;
- if (!rkTextFileLoader.GetTokenDoubleWord("motioneventdatacount", &dwMotionEventDataCount))
- continue;
- for (DWORD j = 0; j < dwMotionEventDataCount; ++j)
- {
- if (!rkTextFileLoader.SetChildNode("event", j))
- {
- sys_err("Motion: no event data %d %s", j, c_pszFileName);
- return false;
- }
- int iType;
- if (!rkTextFileLoader.GetTokenInteger("motioneventtype", &iType))
- {
- sys_err("Motion: no motioneventtype data %s", c_pszFileName);
- return false;
- }
- //float fRadius;
- D3DVECTOR v3Position;
- switch (iType)
- {
- case MOTION_EVENT_TYPE_FLY:
- case MOTION_EVENT_TYPE_EFFECT:
- case MOTION_EVENT_TYPE_SCREEN_WAVING:
- case MOTION_EVENT_TYPE_SOUND:
- case MOTION_EVENT_TYPE_CHARACTER_SHOW:
- case MOTION_EVENT_TYPE_CHARACTER_HIDE:
- case MOTION_EVENT_TYPE_WARP:
- case MOTION_EVENT_TYPE_EFFECT_TO_TARGET:
- #ifdef ENABLE_WOLFMAN_CHARACTER
- case MOTION_EVENT_TYPE_RELATIVE_MOVE_ON:
- case MOTION_EVENT_TYPE_RELATIVE_MOVE_OFF:
- #endif
- rkTextFileLoader.SetParentNode();
- continue;
- case MOTION_EVENT_TYPE_SPECIAL_ATTACKING:
- if (!rkTextFileLoader.SetChildNode("spheredata", 0))
- {
- sys_err("Motion: no sphere data %s", c_pszFileName);
- return false;
- }
- //if (!rTextFileLoader.GetTokenFloat("radius", &fRadius))
- //return false;
- if (!rkTextFileLoader.GetTokenPosition("position", &v3Position))
- {
- sys_err("Motion: no position data %s", c_pszFileName);
- return false;
- }
- rkTextFileLoader.SetParentNode();
- break;
- default:
- assert(!" CRaceMotionData::LoadMotionData - Strange Event Type");
- return false;
- break;
- }
- float fStartingTime;
- if (!rkTextFileLoader.GetTokenFloat("startingtime", &fStartingTime))
- {
- sys_err("Motion: no startingtime data %s", c_pszFileName);
- return false;
- }
- pMob->AddSkillSplash(iSkillIndex, 100 + DWORD(fStartingTime * 1000), -(DWORD)(v3Position.y));
- rkTextFileLoader.SetParentNode();
- }
- }
- rkTextFileLoader.SetParentNode();
- }
- pMob->m_mobSkillInfo[iSkillIndex].dwSkillVnum = pMob->m_table.Skills[iSkillIndex].dwVnum;
- pMob->m_mobSkillInfo[iSkillIndex].bSkillLevel = pMob->m_table.Skills[iSkillIndex].bLevel;
- m_isEmpty = false;
- return true;
- }
- bool CMotion::LoadFromFile(const char * c_pszFileName)
- {
- CTextFileLoader loader;
- if (!loader.Load(c_pszFileName))
- {
- sys_log(0, "Motion: LoadFromFile fail: %s", c_pszFileName);
- return false;
- }
- if (!loader.GetTokenFloat("motionduration", &m_fDuration))
- {
- sys_err("Motion: %s does not have a duration", c_pszFileName);
- return false;
- }
- if (loader.GetTokenPosition("accumulation", &m_vec3Accumulation))
- m_isAccumulation = true;
- #ifdef OFFLINE_FARM
- if (!strstr(c_pszFileName, "/monster/"))
- {
- std::string strNodeName;
- for (DWORD i = 0; i < loader.GetChildNodeCount(); ++i)
- {
- loader.SetChildNode(i);
- loader.GetCurrentNodeName(&strNodeName);
- if (0 == strNodeName.compare("comboinputdata"))
- {
- float fComboInputDataTime;
- if (loader.GetTokenFloat("inputlimittime", &fComboInputDataTime))
- {
- m_fInputDuration = fComboInputDataTime;
- }
- else
- {
- sys_err("ComboInputData: %s no input limit time", c_pszFileName);
- }
- }
- if (!strstr(c_pszFileName, "/skill/") && 0 == strNodeName.compare("attackingdata"))
- {
- if (loader.GetTokenFloat("externalforce", &m_fExternalForce))
- {
- sys_log(0, "ExternalForce: %s %f", c_pszFileName, m_fExternalForce);
- }
- else
- {
- sys_err("AttackingData: %s no external force", c_pszFileName);
- }
- // try to handle "HitDataCount" from AttackingData group
- DWORD dwHitDataCount;
- if (loader.GetTokenDoubleWord("hitdatacount", &dwHitDataCount))
- {
- for (DWORD j = 0; j < dwHitDataCount; ++j)
- {
- if (!loader.SetChildNode("hitdata", j))
- {
- sys_err("Motion: no event data %d %s", j, c_pszFileName);
- return false;
- }
- TTokenVector* tv;
- if (loader.GetTokenVector("hitposition", &tv))
- {
- TTokenVector::iterator it = tv->begin();
- THitTimePositionMapEx mapHitPosition;
- while (it != tv->end())
- {
- float time;
- THitTimePosition hp;
- time = atof(it++->c_str());
- hp.v3LastPosition.x = atof(it++->c_str());
- hp.v3LastPosition.y = atof(it++->c_str());
- hp.v3LastPosition.z = atof(it++->c_str());
- hp.v3Position.x = atof(it++->c_str());
- hp.v3Position.y = atof(it++->c_str());
- hp.v3Position.z = atof(it++->c_str());
- hp.fRadius = gsc_fAttackRadius;
- mapHitPosition[time] = hp;
- }
- // F:/Git/martysama58/s3ll_svfiles/main/srv1/share/data/pc/warrior/onehand_sword/combo_01.msa
- // get combo index from file name
- std::string strFileName = c_pszFileName;
- std::string strComboIndex = strFileName.substr(strFileName.find_last_of("_") + 1);
- strComboIndex = strComboIndex.substr(0, strComboIndex.find_last_of("."));
- int iComboIndex = atoi(strComboIndex.c_str());
- if (iComboIndex < 1 || iComboIndex > 7)
- {
- sys_err("CMotion::LoadFromFile :: invalid combo index %d", iComboIndex);
- abort();
- }
- iComboIndex--; // 1-based to 0-based
- // get weapon type from file name
- std::string strWeaponType = strFileName.substr(0, strFileName.find_last_of("/"));
- strWeaponType = strWeaponType.substr(strWeaponType.find_last_of("/") + 1, strWeaponType.size());
- int iWeaponType = 0;
- if (std::string::npos != strWeaponType.find("onehand_sword"))
- iWeaponType = WEAPON_SWORD;
- else if (std::string::npos != strWeaponType.find("dualhand_sword"))
- iWeaponType = WEAPON_DAGGER;
- else if (std::string::npos != strWeaponType.find("bow"))
- iWeaponType = WEAPON_BOW;
- else if (std::string::npos != strWeaponType.find("twohand_sword"))
- iWeaponType = WEAPON_TWO_HANDED;
- else if (std::string::npos != strWeaponType.find("bell"))
- iWeaponType = WEAPON_BELL;
- else if (std::string::npos != strWeaponType.find("fan"))
- iWeaponType = WEAPON_FAN;
- #ifdef ENABLE_WOLFMAN_CHARACTER
- else if (std::string::npos != strWeaponType.find("claw"))
- iWeaponType = WEAPON_CLAW;
- #endif
- else
- {
- sys_err("CMotion::LoadFromFile :: unknown weapon type %s", strWeaponType.c_str());
- abort();
- }
- const auto bIsRiding = strWeaponType.find("horse_") != std::string::npos;
- // get character race from file name
- std::string strRace = strFileName.substr(0, strFileName.find_last_of("/"));
- strRace = strRace.substr(0, strRace.find_last_of("/"));
- strRace = strRace.substr(strRace.find_last_of("/") + 1, strRace.size());
- int iRace = 0;
- if (0 == strRace.compare("warrior"))
- iRace = JOB_WARRIOR;
- else if (0 == strRace.compare("assassin"))
- iRace = JOB_ASSASSIN;
- else if (0 == strRace.compare("sura"))
- iRace = JOB_SURA;
- else if (0 == strRace.compare("shaman"))
- iRace = JOB_SHAMAN;
- #ifdef ENABLE_WOLFMAN_CHARACTER
- else if (0 == strRace.compare("wolfman"))
- iRace = JOB_WOLFMAN;
- #endif
- else
- {
- sys_err("CMotion::LoadFromFile :: unknown race %s", strRace.c_str());
- abort();
- }
- // skip useless data based on weapon type and race combination
- if (iRace == JOB_WARRIOR && (iWeaponType != WEAPON_TWO_HANDED && iWeaponType != WEAPON_SWORD))
- {
- loader.SetParentNode();
- continue;
- }
- else if (iRace == JOB_ASSASSIN && (iWeaponType != WEAPON_DAGGER && iWeaponType != WEAPON_BOW && iWeaponType != WEAPON_SWORD))
- {
- loader.SetParentNode();
- continue;
- }
- else if (iRace == JOB_SURA && iWeaponType != WEAPON_SWORD)
- {
- loader.SetParentNode();
- continue;
- }
- else if (iRace == JOB_SHAMAN && (iWeaponType != WEAPON_BELL && iWeaponType != WEAPON_FAN))
- {
- loader.SetParentNode();
- continue;
- }
- #ifdef ENABLE_WOLFMAN_CHARACTER
- else if (iRace == JOB_WOLFMAN && iWeaponType != WEAPON_CLAW)
- {
- loader.SetParentNode();
- continue;
- }
- #endif
- auto cmd = new SCharacterMotionData();
- cmd->race = iRace;
- cmd->weapon_type = iWeaponType;
- cmd->combo_index = iComboIndex;
- cmd->riding = bIsRiding;
- m_mapHitPosition.emplace(cmd, mapHitPosition);
- }
- // try to handle "WeaponLength" float from AttackingData group to m_fWeaponLength
- if (loader.GetTokenFloat("weaponlength", &m_fWeaponLength))
- {
- sys_log(0, "WeaponLength: %f", m_fWeaponLength);
- }
- else
- {
- sys_err("WeaponLength: not found");
- }
- // try to handle "AttackingBone" float from AttackingData group to m_strBoneName
- if (loader.GetTokenString("attackingbone", &m_strBoneName))
- {
- sys_log(0, "AttackingBone: %s", m_strBoneName.c_str());
- }
- else
- {
- sys_err("AttackingBone: not found");
- }
- loader.SetParentNode();
- }
- }
- else
- {
- TTokenVector* tv;
- if (loader.GetTokenVector("hitposition", &tv))
- {
- TTokenVector::iterator it = tv->begin();
- THitTimePositionMapEx mapHitPosition;
- while (it != tv->end())
- {
- float time;
- THitTimePosition hp;
- time = atof(it++->c_str());
- hp.v3LastPosition.x = atof(it++->c_str());
- hp.v3LastPosition.y = atof(it++->c_str());
- hp.v3LastPosition.z = atof(it++->c_str());
- hp.v3Position.x = atof(it++->c_str());
- hp.v3Position.y = atof(it++->c_str());
- hp.v3Position.z = atof(it++->c_str());
- hp.fRadius = gsc_fAttackRadius;
- mapHitPosition[time] = hp;
- }
- // F:/Git/martysama58/s3ll_svfiles/main/srv1/share/data/pc/warrior/onehand_sword/combo_01.msa
- // get combo index from file name
- std::string strFileName = c_pszFileName;
- std::string strComboIndex = strFileName.substr(strFileName.find_last_of("_") + 1);
- strComboIndex = strComboIndex.substr(0, strComboIndex.find_last_of("."));
- int iComboIndex = atoi(strComboIndex.c_str());
- if (iComboIndex < 1 || iComboIndex > 7)
- {
- sys_err("CMotion::LoadFromFile :: invalid combo index %d", iComboIndex);
- abort();
- }
- iComboIndex--; // 1-based to 0-based
- // get weapon type from file name
- std::string strWeaponType = strFileName.substr(0, strFileName.find_last_of("/"));
- strWeaponType = strWeaponType.substr(strWeaponType.find_last_of("/") + 1, strWeaponType.size());
- int iWeaponType = 0;
- if (0 == strWeaponType.compare("onehand_sword"))
- iWeaponType = WEAPON_SWORD;
- else if (0 == strWeaponType.compare("dualhand_sword"))
- iWeaponType = WEAPON_DAGGER;
- else if (0 == strWeaponType.compare("bow"))
- iWeaponType = WEAPON_BOW;
- else if (0 == strWeaponType.compare("twohand_sword"))
- iWeaponType = WEAPON_TWO_HANDED;
- else if (0 == strWeaponType.compare("bell"))
- iWeaponType = WEAPON_BELL;
- else if (0 == strWeaponType.compare("fan"))
- iWeaponType = WEAPON_FAN;
- #ifdef ENABLE_WOLFMAN_CHARACTER
- else if (0 == strWeaponType.compare("claw"))
- iWeaponType = WEAPON_CLAW;
- #endif
- else
- {
- sys_err("CMotion::LoadFromFile :: unknown weapon type %s", strWeaponType.c_str());
- abort();
- }
- const auto bIsRiding = strWeaponType.find("horse_") != std::string::npos;
- // get character race from file name
- std::string strRace = strFileName.substr(0, strFileName.find_last_of("/"));
- strRace = strRace.substr(0, strRace.find_last_of("/"));
- strRace = strRace.substr(strRace.find_last_of("/") + 1, strRace.size());
- int iRace = 0;
- if (0 == strRace.compare("warrior"))
- iRace = JOB_WARRIOR;
- else if (0 == strRace.compare("assassin"))
- iRace = JOB_ASSASSIN;
- else if (0 == strRace.compare("sura"))
- iRace = JOB_SURA;
- else if (0 == strRace.compare("shaman"))
- iRace = JOB_SHAMAN;
- #ifdef ENABLE_WOLFMAN_CHARACTER
- else if (0 == strRace.compare("wolfman"))
- iRace = JOB_WOLFMAN;
- #endif
- else
- {
- sys_err("CMotion::LoadFromFile :: unknown race %s", strRace.c_str());
- abort();
- }
- // skip useless data based on weapon type and race combination
- if (iRace == JOB_WARRIOR && (iWeaponType != WEAPON_TWO_HANDED && iWeaponType != WEAPON_SWORD))
- {
- continue;
- }
- else if (iRace == JOB_ASSASSIN && (iWeaponType != WEAPON_DAGGER && iWeaponType != WEAPON_BOW && iWeaponType != WEAPON_SWORD))
- {
- continue;
- }
- else if (iRace == JOB_SURA && iWeaponType != WEAPON_SWORD)
- {
- continue;
- }
- else if (iRace == JOB_SHAMAN && (iWeaponType != WEAPON_BELL && iWeaponType != WEAPON_FAN))
- {
- continue;
- }
- #ifdef ENABLE_WOLFMAN_CHARACTER
- else if (iRace == JOB_WOLFMAN && iWeaponType != WEAPON_CLAW)
- {
- continue;
- }
- #endif
- auto cmd = new SCharacterMotionData();
- cmd->race = iRace;
- cmd->weapon_type = iWeaponType;
- cmd->combo_index = iComboIndex;
- cmd->riding = bIsRiding;
- m_mapHitPosition.emplace(cmd, mapHitPosition);
- }
- // try to handle "WeaponLength" float from AttackingData group to m_fWeaponLength
- if (loader.GetTokenFloat("weaponlength", &m_fWeaponLength))
- {
- sys_log(0, "WeaponLength: %f", m_fWeaponLength);
- }
- else
- {
- sys_err("WeaponLength: not found");
- }
- // try to handle "AttackingBone" float from AttackingData group to m_strBoneName
- if (loader.GetTokenString("attackingbone", &m_strBoneName))
- {
- sys_log(0, "AttackingBone: %s", m_strBoneName.c_str());
- }
- else
- {
- sys_err("AttackingBone: not found");
- }
- }
- }
- if (strstr(c_pszFileName, "/skill/") && 0 == strNodeName.compare("motioneventdata"))
- {
- DWORD dwMotionEventDataCount;
- if (!loader.GetTokenDoubleWord("motioneventdatacount", &dwMotionEventDataCount))
- continue;
- std::vector <CMotionManager::SCharacterSkillData> vecSkillData;
- for (DWORD j = 0; j < dwMotionEventDataCount; ++j)
- {
- if (!loader.SetChildNode("event", j))
- {
- sys_err("Motion: no event data %d %s", j, c_pszFileName);
- return false;
- }
- int iType;
- if (!loader.GetTokenInteger("motioneventtype", &iType))
- {
- sys_err("Motion: no motioneventtype data %s", c_pszFileName);
- return false;
- }
- float fRadius;
- D3DVECTOR v3Position;
- switch (iType)
- {
- case MOTION_EVENT_TYPE_FLY:
- case MOTION_EVENT_TYPE_EFFECT:
- case MOTION_EVENT_TYPE_SCREEN_WAVING:
- case MOTION_EVENT_TYPE_SOUND:
- case MOTION_EVENT_TYPE_CHARACTER_SHOW:
- case MOTION_EVENT_TYPE_CHARACTER_HIDE:
- case MOTION_EVENT_TYPE_WARP:
- case MOTION_EVENT_TYPE_EFFECT_TO_TARGET:
- #ifdef ENABLE_WOLFMAN_CHARACTER
- case MOTION_EVENT_TYPE_RELATIVE_MOVE_ON:
- case MOTION_EVENT_TYPE_RELATIVE_MOVE_OFF:
- #endif
- loader.SetParentNode();
- continue;
- case MOTION_EVENT_TYPE_SPECIAL_ATTACKING:
- if (!loader.SetChildNode("spheredata", 0))
- {
- sys_err("Motion: no sphere data %s", c_pszFileName);
- return false;
- }
- if (!loader.GetTokenFloat("radius", &fRadius))
- {
- sys_err("Motion: no radius data %s", c_pszFileName);
- return false;
- }
- if (!loader.GetTokenPosition("position", &v3Position))
- {
- sys_err("Motion: no position data %s", c_pszFileName);
- return false;
- }
- loader.SetParentNode();
- break;
- default:
- assert(!" CRaceMotionData::LoadMotionData - Strange Event Type");
- return false;
- break;
- }
- float fStartingTime;
- if (!loader.GetTokenFloat("startingtime", &fStartingTime))
- {
- sys_err("Motion: no startingtime data %s", c_pszFileName);
- return false;
- }
- CMotionManager::SCharacterSkillData skillData;
- skillData.fRadius = fRadius;
- skillData.v3Position = v3Position;
- skillData.fStartingTime = fStartingTime;
- vecSkillData.push_back(skillData);
- loader.SetParentNode();
- }
- int race, job, skillVnum, skillGrade;
- std::string codeName;
- if (!ParseSkillFile(c_pszFileName, race, job, skillVnum, skillGrade, codeName))
- {
- sys_err("Failed to parse skill file: %s", c_pszFileName);
- return false;
- }
- CMotionManager::instance().RegisterPCSkillMotion(race, skillGrade, skillVnum, vecSkillData);
- }
- loader.SetParentNode();
- }
- }
- #endif
- sys_log(1, "%-48s %.3f %f", strchr(c_pszFileName, '/') + 1, GetDuration(), GetAccumVector().y);
- m_isEmpty = false;
- return true;
- }
- float CMotion::GetDuration() const
- {
- return m_fDuration;
- }
- #ifdef OFFLINE_FARM
- float CMotion::GetInputDuration() const
- {
- return m_fInputDuration;
- }
- float CMotion::GetWeaponLength() const
- {
- return m_fWeaponLength;
- }
- float CMotion::GetExternalForce() const
- {
- return m_fExternalForce;
- }
- CMotion::THitTimePositionMapEx CMotion::GetHitPositionData(const uint8_t c_nRace, const uint8_t c_nWeaponType, const uint8_t c_nComboIndex, bool c_bRiding) const
- {
- for (const auto& [chr, mapHitPosition] : m_mapHitPosition)
- {
- if (chr->race == c_nRace && chr->weapon_type == c_nWeaponType && chr->combo_index == c_nComboIndex && chr->riding == c_bRiding)
- {
- return mapHitPosition;
- }
- }
- return {};
- }
- #endif
- const D3DVECTOR & CMotion::GetAccumVector() const
- {
- return m_vec3Accumulation;
- }
- bool CMotion::IsEmpty()
- {
- return m_isEmpty;
- }