First of all, I’d like to share with everyone the AIControl module that I’ve ported from another source.
After that, I worked on resolving various issues to make it compatible with the 5.2 Base. As of now, it’s relatively stable.
There are still some hidden aspects I haven’t fully uncovered. If you run into problems while using it, feel free to troubleshoot on your own or share with the community for support.
That’s all for now. If you’re unable to add it, or don’t understand how to integrate it, feel free to reach out and I’ll provide further assistance.
Code:
Me ( Edit / Add / Fix )
sven-n (https://github.com/sven-n/MuMainThis Completed CPP Files: Link download

Password is: tuservermu.com.ve

Now then—let’s get started.
First, declare the window ID in enum INTERFACE_LIST inside _enum.h:
INTERFACE_MUHELPER,
INTERFACE_MUHELPER_EXT,
INTERFACE_MUHELPER_SKILL_LIST,
//------------------------------------------
NewUISystem.cpp
In constructor CNewUISystem::CNewUISystem(), initialize:
m_pNewUIMuHelper = nullptr;
m_pNewUIMuHelperConfig = nullptr;
m_pNewUIMuHelperSkillList = nullptr;
//------------------------------------------
Function: bool CNewUISystem::LoadMainSceneInterface()
Initialize with SetPos:
m_pNewUIMuHelper = new CNewUIMuHelper;
if (m_pNewUIMuHelper->Create(m_pNewUIMng, setPosRight(640 - 190), 0) == false)
return false;
m_pNewUIMuHelperConfig = new CNewUIMuHelperConfig;
if (m_pNewUIMuHelperConfig->Create(m_pNewUIMng, setPosRight(640 - 380), 0) == false)
return false;
m_pNewUIMuHelperSkillList = new CNewUIMuHelperSkillList;
if (m_pNewUIMuHelperSkillList->Create(m_pNewUIMng, m_pNewUI3DRenderMng) == false)
return false;
//------------------------------------------
Don’t forget to release memory:
void CNewUISystem::UnloadMainSceneInterface()
SAFE_DELETE(m_pNewUIMuHelper);
SAFE_DELETE(m_pNewUIMuHelperConfig);
SAFE_DELETE(m_pNewUIMuHelperSkillList);
//------------------------------------------
Function: void CNewUISystem::Show(DWORD dwKey)
Add: When detecting the MuHelper Settings window, automatically stop helper
else if (dwKey == INTERFACE_MUHELPER)
{
Hide(INTERFACE_INVENTORY);
HideGroupBeforeOpenInterface();
MUHelper::g_MuHelper.Stop();
}
//------------------------------------------
Function: void CNewUISystem::Hide(DWORD dwKey)
Add this to the bottom of the function:
else if (dwKey == INTERFACE_MUHELPER)
{
m_pNewUIMng->ShowInterface(SEASON3B::INTERFACE_MUHELPER_SKILL_LIST, false);
m_pNewUIMng->ShowInterface(SEASON3B::INTERFACE_MUHELPER_EXT, false);
}
//------------------------------------------
Function: void CNewUISystem::HideAllGroupA()
Add:
INTERFACE_MUHELPER,
INTERFACE_MUHELPER_EXT,
INTERFACE_MUHELPER_SKILL_LIST,
//------------------------------------------
Function: void CNewUISystem::HideGroupBeforeOpenInterface()
Add:
INTERFACE_MUHELPER,
INTERFACE_MUHELPER_EXT,
INTERFACE_MUHELPER_SKILL_LIST,
//------------------------------------------
Create accessors using GetInstance():
CNewUIMuHelper* CNewUISystem::Get_pNewUIMuHelper() const
{
return m_pNewUIMuHelper;
}
CNewUIMuHelperConfig* CNewUISystem::Get_pNewUIMuHelperConfig() const
{
return m_pNewUIMuHelperConfig;
}
CNewUIMuHelperSkillList* CNewUISystem::Get_pNewUIMuHelperSkillList() const
{
return m_pNewUIMuHelperSkillList;
}
→ NewUISystem.h
Add:
#include "NewUIMuHelper.h"
#include "NewUIMuHelperConfig.h"
#include <NewUIMuHelperSkillList.h>
CNewUIMuHelper* m_pNewUIMuHelper;
CNewUIMuHelperConfig* m_pNewUIMuHelperConfig;
CNewUIMuHelperSkillList* m_pNewUIMuHelperSkillList;
///
CNewUIMuHelper* Get_pNewUIMuHelper() const;
CNewUIMuHelperConfig* Get_pNewUIMuHelperConfig() const;
CNewUIMuHelperSkillList* Get_pNewUIMuHelperSkillList() const;
//Khởi tạo con trỏ → Initialize pointers
#define g_pNewUIMuHelper SEASON3B::CNewUISystem::GetInstance()->Get_pNewUIMuHelper()
#define g_pNewUIMuHelperExt SEASON3B::CNewUISystem::GetInstance()->Get_pNewUIMuHelperConfig()
#define g_pNewUIMuHelperSkillList SEASON3B::CNewUISystem::GetInstance()->Get_pNewUIMuHelperSkillList()
//------------------------------------------
Tại UIWindows.h tạo con trỏ mới → In UIWindows.h, create new timer ID
#define MUHELPER_TIMER 1005
//------------------------------------------
Vào WinMain.cpp → In WinMain.cpp
Tìm đoạn: → Find line:
SetTimer(g_hWnd, HACK_TIMER, 20 * 1000, NULL);
thêm vào bên dưới: → add below:
SetTimer(g_hWnd, MUHELPER_TIMER, 250 /* ms */, MUHelper::CMuHelper::TimerProc);
//------------------------------------------
Tiếp tục vào: NewUICustomMessageBox.cpp → Continue in: NewUICustomMessageBox.cpp
Tìm hàm: → Find function:
CALLBACK_RESULT SEASON3B::CSystemMenuMsgBox::GameOverBtnDown
thêm vào phần else → add inside the else block
MUHelper::g_MuHelper.TriggerStop(); // Thêm cái này. → // Add this
LogOut = true;
SendRequestLogOut(0);
//------------------------------------------
CALLBACK_RESULT SEASON3B::CSystemMenuMsgBox::ChooseServerBtnDown
Cũng thêm vào phần else → Also add into the else block
MUHelper::g_MuHelper.TriggerStop(); // Thêm cái này. → // Add this
g_pNewUIMng->ResetActiveUIObj();
LogOut = true;
SendRequestLogOut(2);
//------------------------------------------
tiếp tục: → continue:
CALLBACK_RESULT SEASON3B::CSystemMenuMsgBox::ChooseCharacterBtnDown
Thêm vào phần else → Add into the else block
MUHelper::g_MuHelper.TriggerStop(); // Thêm cái này. → // Add this
g_pNewUIMng->ResetActiveUIObj();
LogOut = true;
SendRequestLogOut(1);
//------------------------------------------
Tiếp theo tại NewUIHeroPositionInfo.h → Next, in NewUIHeroPositionInfo.h
Tạo 1 mảng Button có 4 phần tử. → Create a Button array with 4 elements.
trong class CNewUIHeroPositionInfo → inside class CNewUIHeroPositionInfo
CNewUIButton m_Btn[4]; // Phần tử 0 tôi dùng cho việc khác. → // Element 0 is used for other purposes.
//------------------------------------------
Tiếp theo tại NewUIHeroPositionInfo.cpp → Next, in NewUIHeroPositionInfo.cpp
void CNewUIHeroPositionInfo::InitRenderButton()
Nếu không có thì tự tạo mới hàm, trong thân hàm khai báo nút nhấn
→ If it doesn’t exist, create a new function and declare buttons inside.
SetButtonInfo(&m_Btn[1], IMAGE_HERO_POSITION_INFO_BASE_WINDOW + 1, m_Pos.x + WidenX + 21, m_Pos.y + 1, 18, 13, 1, 0, 1);
SetButtonInfo(&m_Btn[2], IMAGE_HERO_POSITION_INFO_BASE_WINDOW + 2, m_Pos.x + WidenX + 37, m_Pos.y + 1, 18, 13, 1, 0, 1);
SetButtonInfo(&m_Btn[3], IMAGE_HERO_POSITION_INFO_BASE_WINDOW + 3, m_Pos.x + WidenX + 37, m_Pos.y + 1, 18, 13, 1, 0, 1);
//------------------------------------------
bool CNewUIHeroPositionInfo::Render()
Ném vào: → Insert this:
EnableAlphaTest();
glColor4f(1.f, 1.f, 1.f, 1.f);
m_Btn[1].Render(); // Thêm → // Add this
MUHelper::g_MuHelper.IsActive() ? m_Btn[3].Render() : m_Btn[2].Render(); // Thêm → // Add this
//------------------------------------------
trong: bool CNewUIHeroPositionInfo::BtnProcess()

//------------------------------------------
tiếp tục: Hotkey: → continue: Hotkey:
bool SEASON3B::CNewUIHotKey::UpdateKeyEvent()
else if (SEASON3B::IsPress(VK_HOME))
{
//Nếu không có có thể bỏ qua. Phần này chạy trực tiếp toggle luôn di.
//→ Can be skipped if unused. This part directly toggles.
if (g_pNewUISystem->IsVisible(SEASON3B::INTERFACE_MUHELPER))
{
CMsgBoxIGSCommon* pMsgBox = NULL;
CreateMessageBox(MSGBOX_LAYOUT_CLASS(CMsgBoxIGSCommonLayout), &pMsgBox);
pMsgBox->Initialize(GlobalText[3028], GlobalText[3186]);
return false;
}
else if (CharacterAttribute->Level < CharacterAttribute->MuHelperLevel)
{
unicode::t_char szText[MAX_TEXT_LENGTH] = { '\0', };
sprintf(szText, GlobalText[3188], CharacterAttribute->MuHelperLevel);
CMsgBoxIGSCommon* pMsgBox = NULL;
CreateMessageBox(MSGBOX_LAYOUT_CLASS(CMsgBoxIGSCommonLayout), &pMsgBox);
pMsgBox->Initialize(GlobalText[3028], szText);
return false;
}
else
{
MUHelper::g_MuHelper.Toggle();
}
return false;
}
//------------------------------------------
Tạo Render cho Icon Skill: → Create Render for Skill Icon:
Tương tự trong NewUIMainFrameWindow.h → Similar to NewUIMainFrameWindow.h
Đã tồn tại hàm: → The following function already exists:
void RenderSkillIcon(int iIndex, float x, float y, float width, float height)
sửa lại: → Modify it to:
void RenderSkillIcon(int iIndex, float x, float y, float width, float height, int TypeMuHelper = 0);
trong thân hàm thêm vào đầu tiên → At the beginning of the function body, add:
void SEASON3B::CNewUISkillList::RenderSkillIcon(int iIndex, float x, float y, float width, float height, int TypeMuHelper)
{
WORD bySkillType = CharacterAttribute->Skill[iIndex];
if (TypeMuHelper == 1) // MuHelper Lấy danh sách skill → MuHelper fetches the skill list
{
bySkillType = iIndex;
if ((bySkillType == 0 || !gSkillManager.FindHeroSkill((ActionSkillType)bySkillType)))
{
return;
}
}
//....Các code khác → Other code follows
}
//------------------------------------------
trong wsclient.cpp → in wsclient.cpp
void ReceiveMoveCharacter(const BYTE* ReceiveBuffer)
Tìm đến: → Find:
CHARACTER* c = &CharactersClient[FindCharacterIndex(Key)];
OBJECT* o = &c->Object;
thêm cái này → add this:
if (IsMonster(c))
{
MUHelper::g_MuHelper.AddTarget(Key, false);
}
//------------------------------------------
BOOL ReceiveTeleport(const BYTE* ReceiveBuffer, BOOL bEncrypted)
thêm bên cuối hàm: → add at the end of the function:
MUHelper::g_MuHelper.TriggerStop();
//------------------------------------------
void ReceiveCreateMonsterViewport(const BYTE* ReceiveBuffer)
thêm vào trong vòng lập → add inside the loop:
if (IsMonster(c))
{
MUHelper::g_MuHelper.AddTarget(Key, false);
}
//------------------------------------------
void ReceiveAttackDamage(const BYTE* ReceiveBuffer)
Thêm dưới hàm: → Add below the function body:
if (IsMonster(c) || IsPlayer(c))
{
MUHelper::g_MuHelper.AddTarget(Key, true);
}
//------------------------------------------
void ReceiveAction(const BYTE* ReceiveBuffer, int Size)
thêm vào trong case AT_ATTACK2: → add inside case AT_ATTACK2:
c->TargetCharacter = HeroIndex;
if (IsMonster(c) || IsPlayer(c))
{
MUHelper::g_MuHelper.AddTarget(Key, true);
}
//------------------------------------------
void ReceiveDie(const BYTE* ReceiveBuffer, int Size)
Cuối hàm → At the end of the function:
if (c == Hero)
{
MUHelper::g_MuHelper.TriggerStop();
}
//------------------------------------------
void ReceiveCreateItemViewport(const BYTE* ReceiveBuffer)
thêm vào → Add this:
CreateItem(&Items[Key], Data2->Item, Position, CreateFlag);
MUHelper::g_MuHelper.AddItem(Key, { Data2->PositionX, Data2->PositionY });
//------------------------------------------
void ReceiveDeleteItemViewport(const BYTE* ReceiveBuffer)
Thêm vào cuối vòng lập → Add at the end of the loop:
Offset += sizeof(PDELETE_CHARACTER);
MUHelper::g_MuHelper.DeleteItem(Key);
//------------------------------------------
void ReceiveCreateMoney(const BYTE* ReceiveBuffer)
Thêm vào: → Add:
CreateMoneyDrop(&Items[Data->Id], Data->Amount, Position, Data->IsFreshDrop);
MUHelper::g_MuHelper.AddItem(Data->Id, { Data->PositionX, Data->PositionY });
//------------------------------------------
Tạo 2 hàm mới: → Create 2 new functions:
void ReceiveMuHelperConfigurationData(const BYTE* ReceiveBuffer)
{
const PRECEIVE_MUHELPER_DATA* pMuHelperData = reinterpret_cast<const PRECEIVE_MUHELPER_DATA*>(ReceiveBuffer + 4);
if (pMuHelperData == nullptr)
{
assert(false);
return;
}
MUHelper::ConfigData config;
MUHelper::ConfigDataSerDe::Deserialize(*pMuHelperData, config);
g_pNewUIMuHelper->LoadSavedConfig(config);
g_ConsoleDebug->Write(MCD_RECEIVE, "0xAE [ReceiveMuHelperConfigurationData]");
}
//------------------------------------------
void ReceiveMuHelperStatusUpdate(const BYTE* ReceiveBuffer)
{
if (ReceiveBuffer == nullptr)
return;
const PRECEIVE_MUHELPER_STATUS* pMuHelperStatus = reinterpret_cast<const PRECEIVE_MUHELPER_STATUS*>(ReceiveBuffer + 4);
if (pMuHelperStatus == nullptr)
{
assert(false);
return;
}
if (pMuHelperStatus->Pause)
{
MUHelper::g_MuHelper.Stop();
}
else
{
MUHelper::g_MuHelper.Start();
if (pMuHelperStatus->Money > 0 && pMuHelperStatus->ConsumeMoney)
{
MUHelper::g_MuHelper.AddCost(pMuHelperStatus->Money);
int iTotalCost = MUHelper::g_MuHelper.GetTotalCost();
char Text[100];
sprintf(Text, GlobalText[3586], iTotalCost);
g_pChatListBox->AddText("", Text, SEASON3B::TYPE_SYSTEM_MESSAGE);
}
}
g_ConsoleDebug->Write(MCD_RECEIVE, "0x51 [ReceiveMuHelperStatusUpdate]");
}
2 hàm này gửi gói lên GS qua cổng AE và BF:51
→ These 2 functions send packets to GameServer via port AE and BF:51
Đi đến TranslateProtocol → Go to TranslateProtocol
tìm đến gói: 0xBF → find packet 0xBF
gán vào: → assign:
case 0x51: ReceiveMuHelperStatusUpdate(ReceiveBuffer); break;
cuối hàm Protocol thêm → add at the end of the Protocol function:
case 0xAE: ReceiveMuHelperConfigurationData(ReceiveBuffer); break; // gói này độc lập → this packet is independent
//------------------------------------------
Tiếp theo tại wsclient.h → Next, in wsclient.h
in end header
/ MU Helper
#pragma pack(push, 1)
typedef struct
{
BYTE DataStartMarker; // Index: 4
BYTE : 3; // Unused
BYTE JewelOrGem : 1; // Index: 5
BYTE SetItem : 1;
BYTE ExcellentItem : 1;
BYTE Zen : 1;
BYTE AddExtraItem : 1;
BYTE HuntingRange : 4; // Index: 6
BYTE ObtainRange : 4;
WORD DistanceMin; // Index: 7
WORD BasicSkill1; // Index: 9
WORD ActivationSkill1; // Index: 11
WORD DelayMinSkill1; // Index: 13
WORD ActivationSkill2; // Index: 15
WORD DelayMinSkill2; // Index: 17
WORD CastingBuffMin; // Index: 19
WORD BuffSkill0NumberID; // Index: 21
WORD BuffSkill1NumberID; // Index: 23
WORD BuffSkill2NumberID; // Index: 25
BYTE HPStatusAutoPotion : 4; // Index: 27
BYTE HPStatusAutoHeal : 4;
BYTE HPStatusOfPartyMembers : 4; // Index: 28
BYTE HPStatusDrainLife : 4;
BYTE AutoPotion : 1; // Index: 29
BYTE AutoHeal : 1;
BYTE DrainLife : 1;
BYTE LongDistanceAttack : 1;
BYTE OriginalPosition : 1;
BYTE Combo : 1;
BYTE Party : 1;
BYTE PreferenceOfPartyHeal : 1;
BYTE BuffDurationforAllPartyMembers : 1; // Index: 30
BYTE UseDarkSpirits : 1;
BYTE BuffDuration : 1;
BYTE Skill1Delay : 1;
BYTE Skill1Con : 1;
BYTE Skill1PreCon : 1;
BYTE Skill1SubCon : 2;
BYTE Skill2Delay : 1; // Index: 31
BYTE Skill2Con : 1;
BYTE Skill2PreCon : 1;
BYTE Skill2SubCon : 2;
BYTE RepairItem : 1;
BYTE PickAllNearItems : 1;
BYTE PickSelectedItems : 1;
BYTE PetAttack; // Index: 32
BYTE _UnusedPadding[36];
char ExtraItems[12][15]; // Index: 69
} PRECEIVE_MUHELPER_DATA, * LPRECEIVE_MUHELPER_DATA;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct
{
DWORD ConsumeMoney;
DWORD Money;
DWORD Pause;
} PRECEIVE_MUHELPER_STATUS, * LPRECEIVE_MUHELPER_STATUS;
#pragma pack(pop)
template <typename T>
T* safe_cast(const BYTE* buffer, size_t size)
{
if (buffer == nullptr || size < sizeof(T))
{
return nullptr;
}
return reinterpret_cast<T*>(const_cast<BYTE*>(buffer));
}
struct PMSG_HELPER_START_SEND
{
PSBMSG_HEAD header; // C1:BF:51
BYTE type;
};
Next Add
wsclientinline.h
#define SendMuHelperStatusChangeRequest(status) \
{ \
CStreamPacketEngine spe; \
spe.Init(0xC1, 0xBF); \
spe << (BYTE)0x51; \
spe << (BYTE)(status); \
spe.Send(); \
}
#define SendMuHelperSaveDataRequest(data, size) \
{ \
CStreamPacketEngine spe; \
spe.Init(0xC1, 0xAE); \
spe.AddData(data, size, FALSE); \
spe.Send(); \
}
Add this marco
rong hàm: void MoveMainScene()
→ in the function: void MoveMainScene()
thêm vào: → add the following line:
g_pNewUIMuHelper->Reset();
//------------------------------------------
Cuối cùng kiểm tra lại struct này, nếu tồn tại rồi cần update lên
→ Finally, review the following struct; if it already exists, it must be updated accordingly.
