#include "stdafx.h" #include "MonsterShout.h" #include "MonsterMgr.h" #include "ScriptEngine/ScriptEngine.h" #include #include #include #include #include #include #include const char* CMonsterShout::ms_DefaultFileName = "./Script/Game/MonsterChat.gsf"; CMonsterShout& CMonsterShout::GetInstance() { static CMonsterShout monsterShout; return monsterShout; } CMonsterShout::CMonsterShout() { } CMonsterShout::~CMonsterShout() { ShoutMap::iterator pos = m_ShoutMap.begin(); ShoutMap::iterator end = m_ShoutMap.end(); for(; pos != end; ++pos) { ShoutInfo& shoutInfo = pos->second; ChatNode* lpNode = shoutInfo.m_lpNextNode; ChatNode* lpDeleteNode = lpNode; while(0 != lpNode) { lpDeleteNode = lpNode; lpNode = lpNode->m_lpNextNode; delete lpDeleteNode; } } } void SetShoutText(int nKID, int nBehavior, int nSkill_ID, int nChatType, int nPercentage, const char* szMessage) { CMonsterShout::ShoutInfo shoutInfo; CMonsterShout::ChatNode chatNode; memset(&shoutInfo, 0, sizeof(CMonsterShout::ShoutInfo)); memset(&chatNode, 0, sizeof(CMonsterShout::ChatNode)); shoutInfo.m_nKID = nKID; shoutInfo.m_nBehavior = nBehavior; shoutInfo.m_nSkill_ID = nSkill_ID; shoutInfo.m_nChatType = nChatType; chatNode.m_nPercentage = nPercentage; const CMonsterMgr::MonsterProtoType* lpMonsterProtoType = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID); if(0 != szMessage && 0 != lpMonsterProtoType) { if(shoutInfo.m_nBehavior != CMonsterShout::RESPAWN) { _snprintf(chatNode.m_szMonsterChat, MAX_PATH - 1, "%s : %s", lpMonsterProtoType->m_MonsterInfo.m_strName, szMessage); } else { _snprintf(chatNode.m_szMonsterChat, MAX_PATH - 1, "%s", szMessage); } chatNode.m_szMonsterChat[MAX_PATH - 1] = 0; chatNode.m_usChatLength = static_cast(strlen(chatNode.m_szMonsterChat)) + 1; CMonsterShout::GetInstance().AddMonsterShout(shoutInfo, chatNode); } } bool CMonsterShout::LoadScript(const char* szFileName) { SCRIPT Script = _SE_Create(szFileName); if (NULL == Script) { return false; } _SE_RegisterFunction(Script, SetShoutText, T_VOID, "MonsterChat", T_INT, T_INT, T_INT, T_INT, T_INT, T_STRING, 0); _SE_Execute(Script); _SE_Destroy(Script); return true; } void CMonsterShout::Shout(unsigned long dwMonsterCID, unsigned long nKID, unsigned short usXPos, unsigned short usZPos, Behavior eBehavior, const char* szName, unsigned short usSkill_ID) { // KID·Î °Ë»öÇÑ´Ù. // È®·ü ¹× ¿ä°ÇÀ» °Ë»çÇÑ´Ù. std::pair result = m_ShoutMap.equal_range(nKID); std::vector shoutedList; for(; result.first != result.second; ++result.first) { ShoutInfo& shoutInfo = result.first->second; bool bChatSend = false; if(shoutInfo.m_nBehavior == eBehavior) { if(SKILL_ATTACK == eBehavior || SKILL_ATTACKED == eBehavior) { // ½ºÅ³¿¡ °ø°Ý´çÇÑ °æ¿ì´Â ½ºÅ³ ŸÀÔµµ È®ÀÎÇØ¾ß ÇÑ´Ù. if(shoutInfo.m_nSkill_ID == 0xFFFF || shoutInfo.m_nSkill_ID == usSkill_ID) { bChatSend = true; } } else { bChatSend = true; } // ÀÌ¹Ì ¿ÜÄ£ ChatTypeÀÌ¸é ¿ÜÄ¡Áö ¾Ê´Â´Ù. if(shoutedList.end() != std::find(shoutedList.begin(), shoutedList.end(), shoutInfo.m_nChatType)) { bChatSend = false; } int nRand = Math::Random::ComplexRandom(100, 1); if(bChatSend && (nRand < shoutInfo.m_nTotalPercentage)) { // ¿©·¯ ¸Þ½ÃÁöÁß¿¡¼­ ¾î´À ¸Þ½ÃÁö¸¦ º¸³¾Áö¸¦ °áÁ¤ÇÑ´Ù. int nPercentage = 0; ChatNode* lpNode = shoutInfo.m_lpNextNode; while(0 != lpNode) { if(nPercentage <= nRand && nRand <= nPercentage + lpNode->m_nPercentage) { // ¿øÇÏ´Â ±¸°£ ¾È¿¡ ·£´ý°ªÀÌ ÀÖÀ¸¸é Break; break; } nPercentage += lpNode->m_nPercentage; lpNode = lpNode->m_lpNextNode; } if(0 != lpNode) { shoutedList.push_back(shoutInfo.m_nChatType); // ¸ó½ºÅÍ Ã¤ÆÃÀ» äÆÃ¼­¹ö·Î º¸³½´Ù. usState´Â XÁÂÇ¥, usError´Â ZÁÂÇ¥ÀÌ´Ù. // ³ë¸Ö äÆÃÀ϶§¸¸ ÁÂÇ¥°¡ Àǹ̰¡ ÀÖ´Ù. char szChatBuffer[PktChat::PktChatMaxSize * 2]; char szNameBuffer[PktChat::PktChatMaxSize]; szChatBuffer[0] = 0; szNameBuffer[0] = 0; if(0 != szName) { // À̸§ º¹»çÇϱâ.. _snprintf(szNameBuffer, PktChat::PktChatMaxSize - 1, "%s", szName); szNameBuffer[PktChat::PktChatMaxSize - 1]; } const char* szTarget = 0; char* szTargetPos = 0; size_t nTargetLen = 0; char* szMessageResult = 0; size_t nMessageLen = 0; switch(shoutInfo.m_nBehavior) { case NORMAL_ATTACK: case SKILL_ATTACK: case CRITICAL_ATTACK: szTarget = "$DEFNAME$"; break; case NORMAL_ATTACKED: case SKILL_ATTACKED: case CRITICAL_ATTACKED: szTarget = "$ATTNAME$"; break; case DEAD: szTarget = "$KILLERNAME$"; break; } if(0 != szTarget && (szTargetPos = strstr(lpNode->m_szMonsterChat, szTarget))) { // Ä¡È¯ÇØ¼­ ¹®ÀÚ¿­ º¹»ç. nTargetLen = strlen(szTarget); const char* szLastMessage = szTargetPos + nTargetLen; size_t nPreMessageLen = szTargetPos - lpNode->m_szMonsterChat; memcpy(szChatBuffer, lpNode->m_szMonsterChat, nPreMessageLen); nMessageLen = _snprintf(szChatBuffer + nPreMessageLen, PktChat::PktChatMaxSize * 2 - 1, "%s%s", szNameBuffer, szLastMessage); szMessageResult = szChatBuffer; nMessageLen += nPreMessageLen; } else { szMessageResult = lpNode->m_szMonsterChat; nMessageLen = lpNode->m_usChatLength; } PktChat::PktChatCmd eChatCmd = static_cast(shoutInfo.m_nChatType); CChatPacket chatPacket(szMessageResult, dwMonsterCID, eChatCmd, 0); if(chatPacket.IsValid()) { // ê ŸÀÔÀº °øÁö/ÀϹÝ/¿ÜÄ¡±â »ÓÀÌ´Ù. switch(eChatCmd) { case PktChat::SHOUT: case PktChat::NOTICE: // ¸ó½ºÅͰ¡ ¼ÓÇÑ Á¸¿¡¸¸ ÀüºÎ Àü¼ÛÇÑ´Ù. CCreatureManager::GetInstance().SendAllCharacter( chatPacket.GetCompressedPacket(), chatPacket.GetCompressedSize(), CmdCharChat); break; case PktChat::NORMAL: { // ¸ó½ºÅÍ ÁÖº¯ 8°³ ¼¿¿¡ ÀüºÎ ¸Þ½ÃÁö¸¦ º¸³½´Ù. CMonster* lpMonster = CCreatureManager::GetInstance().GetMonster(dwMonsterCID); CCell* lpCell = 0; if(0 != lpMonster && 0 != (lpCell = lpMonster->GetCellPos().m_lpCell)) { lpCell->SendAllNearCellCharacter( chatPacket.GetPacketData(), chatPacket.GetPacketSize(), CmdCharChat); } } break; } } } } } }; } void CMonsterShout::AddMonsterShout(ShoutInfo& shoutInfo, ChatNode& chatNode) { std::pair result = m_ShoutMap.equal_range(shoutInfo.m_nKID); for(; result.first != result.second; ++result.first) { ShoutInfo& foundShoutInfo = result.first->second; if(foundShoutInfo.m_nKID == shoutInfo.m_nKID && foundShoutInfo.m_nBehavior == shoutInfo.m_nBehavior && foundShoutInfo.m_nSkill_ID == shoutInfo.m_nSkill_ID && foundShoutInfo.m_nChatType == shoutInfo.m_nChatType) { foundShoutInfo.m_nTotalPercentage += chatNode.m_nPercentage; ChatNode* lpNode = foundShoutInfo.m_lpNextNode; while(0 != lpNode && 0 != lpNode->m_lpNextNode) { lpNode = lpNode->m_lpNextNode; } if(0 != lpNode && 0 == lpNode->m_lpNextNode) { lpNode->m_lpNextNode = new ChatNode(chatNode); } break; } } if(result.first == result.second) { shoutInfo.m_lpNextNode = new ChatNode(chatNode); shoutInfo.m_nTotalPercentage = chatNode.m_nPercentage; m_ShoutMap.insert(std::make_pair(shoutInfo.m_nKID, shoutInfo)); } }