Esse é o sistema de chat que uso nos meus gameservers, espero que ajudem vocês!

Funções que eu uso que podem ser substituidas:
TNotice::SendNotice -> GCServerMsgStringSend
Log.LogNormal -> LogAddFunc

ChatCore.cpp
Código:
#include "StdAfx.h"
#include "ChatCore.h"

Command g_Chat;

Command::Command(void)
{
}

Command::~Command(void)
{
}

void Command::ManagementCore(int aIndex, LPBYTE lpMsg)
{
	if(!_memicmp(lpMsg,"creditos",8))
	{
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(20));
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(21));
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(22));
	}
	else if(!_memicmp(lpMsg,"post",4))
	{
		this->PostCommand(aIndex,(char*)(lpMsg+4));
	}
	else if(!_memicmp(lpMsg,"sair",4))
	{
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(23));
		CloseClient(aIndex);
	}
	else if(!_memicmp(lpMsg,"limparpk",8))
	{
		this->PkClearCommand(aIndex);
	}
	else if(!_memicmp(lpMsg,"for",3))
	{
		this->AddCommand(aIndex,(char*)(lpMsg+3),STR_TYPE);
	}
	else if(!_memicmp(lpMsg,"agi",3))
	{
		this->AddCommand(aIndex,(char*)(lpMsg+3),AGI_TYPE);
	}
	else if(!_memicmp(lpMsg,"vit",3))
	{
		this->AddCommand(aIndex,(char*)(lpMsg+3),VIT_TYPE);
	}
	else if(!_memicmp(lpMsg,"ene",3))
	{
		this->AddCommand(aIndex,(char*)(lpMsg+3),ENE_TYPE);
	}
	else if(!_memicmp(lpMsg,"cmd",3))
	{
		this->AddCommand(aIndex,(char*)(lpMsg+3),CMD_TYPE);
	}
}

void Command::AddCommand(int aIndex,char * lpMsg,int type)
{
	OBJECTSTRUCT *lpObj = (OBJECTSTRUCT*)OBJECT_POINTER(aIndex);

	int Points = GetNumber(lpMsg,0);

	if(Settings.m_Commands[1].Active != 1)
	{
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(24));
		return;
	}
	else if(strlen(lpMsg) < 1)
	{
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(25));
		return;
	}
	else if(lpObj->Level < Settings.m_Commands[1].Level)
    {
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(26),(Settings.m_Commands[1].Level - lpObj->Level));
	    return;
	}
	else if(lpObj->Money < Settings.m_Commands[1].Price)
    {
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(27),Settings.m_Commands[1].Price);
	    return;
	}
	else if(lpObj->LevelUpPoint < Points || Points <= 0)
    {
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(28));
	    return;
	}
	else if(Points > Settings.m_Commands[1].MaxPoints)
    {
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(29),Settings.m_Commands[1].MaxPoints);
	    return;
	}

	WORD* AddType;

	switch(type)
	{
		case 0:
			AddType = (WORD*)&lpObj->Strength;
			break;
		case 1:
			AddType = (WORD*)&lpObj->Dexterity;
			break;
		case 2:
			AddType = (WORD*)&lpObj->Vitality;
			break;
		case 3:
			AddType = (WORD*)&lpObj->Energy;
			break;
		case 4:
			AddType = (WORD*)&lpObj->Leadership;
			break;
	}

	if(*AddType + Points > 32700)
	{
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(30));
	    return;
	}

	lpObj->Money -= Settings.m_Commands[1].Price;
	GCMoneySend(aIndex,lpObj->Money);

	*AddType += Points;
	lpObj->LevelUpPoint -= Points;

	GCLevelUpMsgSend(lpObj->m_Index,0);
	TNotice::SendNotice(aIndex,1,Msg.GetMsg(31),Points);

	Log.LogNormal("[CommandLogger] %s adicionou %d pontos! Preço: %d",4,lpObj->Name,Points,Settings.m_Commands[1].Price);
}

void Command::PostCommand(int aIndex,char * lpMsg)
{
	OBJECTSTRUCT *lpObj = (OBJECTSTRUCT*)OBJECT_POINTER(aIndex);

	int Delay = (GetTickCount()-lpObj->SaveTimeForStatics)/1000;

	if(Settings.m_Commands[0].Active != 1)
	{
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(24));
		return;
	}
	else if(strlen(lpMsg) < 1)
	{
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(32));
		return;
	}
	else if(lpObj->Level < Settings.m_Commands[0].Level)
    {
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(26),(Settings.m_Commands[0].Level - lpObj->Level));
	    return;
	}
	else if(lpObj->Money < Settings.m_Commands[0].Price)
    {
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(27),Settings.m_Commands[0].Price);
	    return;
	}
	else if(Delay < Settings.m_Commands[0].Delay)
	{
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(33),(Settings.m_Commands[0].Delay-Delay));
		return;
	}
	else if(!strcmpi(" ",lpMsg))
	{
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(32));
		return;
	}
	else
	{
		lpObj->SaveTimeForStatics = GetTickCount();

		lpObj->Money -= Settings.m_Commands[0].Price;
		GCMoneySend(aIndex,lpObj->Money);

		TNotice::SendWhisperToAll(lpObj->Name,Msg.GetMsg(34),lpMsg);
	}

	Log.LogNormal("[CommandLogger] %s usou o Chat Global, Preço: %d",4,lpObj->Name,Settings.m_Commands[0].Price);
}

void Command::PkClearCommand(int aIndex)
{
	OBJECTSTRUCT *lpObj = (OBJECTSTRUCT*)OBJECT_POINTER(aIndex);

	if(Settings.m_Commands[2].Active != 1)
	{
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(24));
		return;
	}
	else if(lpObj->Level < Settings.m_Commands[2].Level)
    {
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(26),(Settings.m_Commands[2].Level - lpObj->Level));
	    return;
	}
	else if(lpObj->Money < Settings.m_Commands[2].Price)
    {
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(27),Settings.m_Commands[2].Price);
	    return;
	}
	else if(lpObj->m_PK_Level < 4)
	{
		TNotice::SendNotice(aIndex,1,Msg.GetMsg(35));
	    return;
	}
	else
	{
		lpObj->m_PK_Level = 2;
		GCPkLevelSend(aIndex,lpObj->m_PK_Level);

		lpObj->Money -= Settings.m_Commands[2].Price;
		GCMoneySend(aIndex,lpObj->Money);

		if(Settings.m_Commands[2].Relog == 1)
		{
			gObjCloseSet(aIndex,1);
			GCLevelUpMsgSend(aIndex,0);
	        TNotice::SendNotice(aIndex,1,Msg.GetMsg(36));
		}
		else
		{
			GCLevelUpMsgSend(aIndex,0);
	        TNotice::SendNotice(aIndex,1,Msg.GetMsg(37));
		}
	}

	Log.LogNormal("[CommandLogger] %s usou o 'PkClear'! Preço:%d",4,lpObj->Name,Settings.m_Commands[2].Price);
}
ChatCore.h
Código:
#ifndef CHAT_CORE_H
#define CHAT_CORE_H

class Command
{
private:
public:
	Command(void);
	~Command(void);

	void Init();

	void ManagementCore(int aIndex,LPBYTE lpMsg);
	void GMManagementCore(int aIndex,LPBYTE lpMsg);

	void AddCommand(int aIndex,char * lpMsg, int type);
	void PostCommand(int aIndex,char * lpMsg);
	void PkClearCommand(int aIndex);
};

extern Command g_Chat;

#define STR_TYPE 0
#define AGI_TYPE 1
#define VIT_TYPE 2
#define ENE_TYPE 3
#define CMD_TYPE 4

#endif
no ProtocolCore
OBS: lpMsg, a maioria usa como aRecv
Código:
switch(protoNum)
	{
	    case 0x00: // ManagementCore
			if((char)lpMsg[13] == '/')
			{
				g_Chat.ManagementCore(aIndex,(LPBYTE)(lpMsg+14));
			} break;
....
Bom é isso, espero que vocês gostem do meu trabalho!
Bom uso! Caso usar, matenha os créditos
Se gostar agradeça hehehe

by Matheus Borba
eGamesTeam!