Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
320 lines
10 KiB
C++
320 lines
10 KiB
C++
#include "stdafx.h"
|
||
#include "MonsterShout.h"
|
||
#include "MonsterMgr.h"
|
||
#include "ScriptEngine/ScriptEngine.h"
|
||
|
||
#include <Network/Packet/ChatPacket.h>
|
||
#include <Network/Packet/PacketCommand.h>
|
||
#include <Network/Dispatch/Chat/ChatDispatch.h>
|
||
|
||
#include <Map/FieldMap/Cell.h>
|
||
#include <Utility/Math/Math.h>
|
||
|
||
#include <Creature/CreatureManager.h>
|
||
#include <Creature/Monster/Monster.h>
|
||
|
||
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<unsigned short>(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<49><44> <20>˻<EFBFBD><CBBB>Ѵ<EFBFBD>.
|
||
// Ȯ<><C8AE> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>˻<EFBFBD><CBBB>Ѵ<EFBFBD>.
|
||
|
||
std::pair<ShoutMap::iterator, ShoutMap::iterator> result = m_ShoutMap.equal_range(nKID);
|
||
std::vector<int> 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)
|
||
{
|
||
// <20><>ų<EFBFBD><C5B3> <20><><EFBFBD>ݴ<EFBFBD><DDB4><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ų Ÿ<>Ե<EFBFBD> Ȯ<><C8AE><EFBFBD>ؾ<EFBFBD> <20>Ѵ<EFBFBD>.
|
||
if(shoutInfo.m_nSkill_ID == 0xFFFF || shoutInfo.m_nSkill_ID == usSkill_ID)
|
||
{
|
||
bChatSend = true;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
bChatSend = true;
|
||
}
|
||
|
||
// <20>̹<EFBFBD> <20><>ģ ChatType<70≯<EFBFBD> <20><>ġ<EFBFBD><C4A1> <20>ʴ´<CAB4>.
|
||
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))
|
||
{
|
||
// <20><><EFBFBD><EFBFBD> <20><EFBFBD><DEBD><EFBFBD><EFBFBD>߿<EFBFBD><DFBF><EFBFBD> <20><><EFBFBD><EFBFBD> <20><EFBFBD><DEBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
|
||
int nPercentage = 0;
|
||
|
||
ChatNode* lpNode = shoutInfo.m_lpNextNode;
|
||
while(0 != lpNode)
|
||
{
|
||
if(nPercentage <= nRand && nRand <= nPercentage + lpNode->m_nPercentage)
|
||
{
|
||
// <20><><EFBFBD>ϴ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>ȿ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Break;
|
||
break;
|
||
}
|
||
|
||
nPercentage += lpNode->m_nPercentage;
|
||
lpNode = lpNode->m_lpNextNode;
|
||
}
|
||
|
||
if(0 != lpNode)
|
||
{
|
||
shoutedList.push_back(shoutInfo.m_nChatType);
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ä<><C3A4><EFBFBD><EFBFBD> ä<>ü<EFBFBD><C3BC><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>. usState<74><65> X<><58>ǥ, usError<6F><72> Z<><5A>ǥ<EFBFBD>̴<EFBFBD>.
|
||
// <20><><EFBFBD><EFBFBD> ä<><C3A4><EFBFBD>϶<EFBFBD><CFB6><EFBFBD> <20><>ǥ<EFBFBD><C7A5> <20>ǹ̰<C7B9> <20>ִ<EFBFBD>.
|
||
|
||
char szChatBuffer[PktChat::PktChatMaxSize * 2];
|
||
char szNameBuffer[PktChat::PktChatMaxSize];
|
||
|
||
szChatBuffer[0] = 0;
|
||
szNameBuffer[0] = 0;
|
||
|
||
if(0 != szName)
|
||
{
|
||
// <20≯<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϱ<EFBFBD>..
|
||
_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)))
|
||
{
|
||
// ġȯ<C4A1>ؼ<EFBFBD> <20><><EFBFBD>ڿ<EFBFBD> <20><><EFBFBD><EFBFBD>.
|
||
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<PktChat::PktChatCmd>(shoutInfo.m_nChatType);
|
||
|
||
CChatPacket chatPacket(szMessageResult, dwMonsterCID, eChatCmd, 0);
|
||
|
||
if(chatPacket.IsValid())
|
||
{
|
||
// ê Ÿ<><C5B8><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>/<2F>Ϲ<EFBFBD>/<2F><>ġ<EFBFBD><C4A1> <20><><EFBFBD>̴<EFBFBD>.
|
||
|
||
switch(eChatCmd)
|
||
{
|
||
case PktChat::SHOUT:
|
||
case PktChat::NOTICE:
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD>Ͱ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
|
||
CCreatureManager::GetInstance().SendAllCharacter(
|
||
chatPacket.GetCompressedPacket(),
|
||
chatPacket.GetCompressedSize(), CmdCharChat);
|
||
break;
|
||
|
||
case PktChat::NORMAL:
|
||
|
||
{
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ֺ<EFBFBD> 8<><38> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><EFBFBD><DEBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||
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<ShoutMap::iterator, ShoutMap::iterator> 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));
|
||
}
|
||
}
|
||
|