[Release] HP Bar Source 99.6XT (Main 1.00.13)

^TheLast^

Active Member
Joined
Jan 13, 2010
Messages
332
Reaction score
232
Hello,
I finally found some spare time to finish this small project. As i promised i'm releasing it after it's finished. The release includes source code without compiled binaries, everyone who wanna use it can compile it, so i leave this part to you guys.

Client Side

HealthBar.h
Code:
#pragma once

#include "stdafx.h"
#include <gl\GL.h>

#pragma comment(lib,"Opengl32.lib")

#define MAX_MAIN_VIEWPORT 400

struct NEW_HEALTH_BAR
{
	WORD index;
	BYTE type;
	BYTE rate;
};


struct VAngle
{
	float X;
	float Y;
	float Z;
};

void ClearNewHealthBar();
void InsertNewHealthBar(WORD index, BYTE type, BYTE rate);
NEW_HEALTH_BAR* GetNewHealthBar(WORD index, BYTE type);
void DrawNewHealthBar();

#define pCursorX					*(DWORD *)0x7CBAF14
#define pCursorY					*(DWORD *)0x7CBAF10
#define pProtocolCall				0x004CDA7D
#define pGLSwitch					((void(*)()) 0x005F10B0)
#define pDrawBarForm				((void(*)(float PosX, float PosY, float Width, float Height)) 0x005F21D0)
#define pGetPosFromAngle			((void(*)(int a1, int a2, int a3)) 0x005F0CE0) 
#define pSetBlend					((char(*)(BYTE Mode)) 0x005F1130)
#define pDrawText					((int(*)(int posX, int posY, LPCSTR lpString, int a4, char a5, int a6))  0x00534350 )
#define DrawText					((char(*)(int a1, int a2, LPCSTR lpString))0x005343A0)
#define DrawText2					((int(*)(int a1, int a2, LPCSTR lpString, int a4, char a5, int a6))0x005342A0)
#define pSetTextColor				((void(__thiscall*)(HDC hdc, COLORREF h)) 0x00661030) // OK

#define MU_CDC_GET_THIS_POINTER		0x00643470		//99.6XT
#define MU_CDC_TABBEDTEXTOUT		0x00454500		//99.6XT

HealthBar.cpp

Code:
#include "stdafx.h"

NEW_HEALTH_BAR gNewHealthBar[MAX_MAIN_VIEWPORT];


void ClearNewHealthBar() // OK
{
	for (int n = 0; n < MAX_MAIN_VIEWPORT; n++)
	{
		gNewHealthBar[n].index = 0xFFFF;
		gNewHealthBar[n].type = 0;
		gNewHealthBar[n].rate = 0;
	}
}


void InsertNewHealthBar(WORD index, BYTE type, BYTE rate) // OK
{
	for (int n = 0; n < MAX_MAIN_VIEWPORT; n++)
	{
		if (gNewHealthBar[n].index == 0xFFFF)
		{
			gNewHealthBar[n].index = index;
			gNewHealthBar[n].type = type;
			gNewHealthBar[n].rate = rate;
			return;
		}
	}
}


NEW_HEALTH_BAR* GetNewHealthBar(WORD index, BYTE type) // OK
{
	for (int n = 0; n < MAX_MAIN_VIEWPORT; n++)
	{
		if (gNewHealthBar[n].index != 0xFFFF)
		{
			if (gNewHealthBar[n].index == index && gNewHealthBar[n].type == type)
			{
				return &gNewHealthBar[n];
			}
		}
	}

	return 0;
}


void DrawNewHealthBar() // OK
{
	((void(*)())0x00581D30)();

	int PosX, PosY, LifeProgress;
	float LifeBarWidth = 38.0f;
	char LifeDisplay[20];
	VAngle Angle;

	for (int n = 0; n < MAX_MAIN_VIEWPORT; n++)
	{
		int ViewportAddress = *(DWORD*)(0x73C8174) + 1068 * n;

		int mIndex = *(WORD*)(ViewportAddress + 492);
		int MonsterType = *(BYTE*)(ViewportAddress + 132);

		if (!ViewportAddress)
		{
			continue;
		}

		NEW_HEALTH_BAR* lpNewHealthBar = GetNewHealthBar(mIndex, MonsterType);

		if (lpNewHealthBar == 0)
		{
			continue;
		}

		int LifePercent = lpNewHealthBar->rate / 10;

		Angle.X = *(float*)(ViewportAddress + 0x10);
		Angle.Y = *(float*)(ViewportAddress + 0x14);
		Angle.Z = *(float *)(ViewportAddress + 308) + *(float *)(ViewportAddress + 24) + 100.0f;

		pGetPosFromAngle((int)&Angle, (int)&PosX, (int)&PosY);

		PosX -= (int)floor(LifeBarWidth / (double)2.0);

		if ((pCursorX >= PosX) && ((float)pCursorX <= (float)PosX + LifeBarWidth) && (pCursorY >= PosY - 2) && (pCursorY < PosY + 6))
		{
			sprintf_s(LifeDisplay, "HP : %d0%%", LifePercent);
			pDrawText(PosX, PosY - 6, LifeDisplay, 0, 0, 1);
		}

		pSetBlend(true);

		glColor4f(0.0, 0.0, 0.0, 0.5);
		pDrawBarForm((float)(PosX + 1), (float)(PosY + 1), LifeBarWidth + 4.0f, 5.0f);

		pSetBlend(true);

		glColor3f(0.2f, 0.0, 0.0);
		pDrawBarForm((float)PosX, (float)PosY, LifeBarWidth + 4.0f, 5.0f);

		glColor3f(0.19607843f, 0.039215688f, 0.0);
		pDrawBarForm((float)(PosX + 2), (float)(PosY + 2), LifeBarWidth, 1.0f);

		if (LifePercent > 10)
		{
			LifeProgress = 10;
		}
		else
		{
			LifeProgress = LifePercent;
		}

		glColor3f(0.98039216f, 0.039215688f, 0.0);

		for (int i = 0; i < LifeProgress; i++)
		{
			pDrawBarForm((float)(i * 4 + PosX + 2), (float)(PosY + 2), 3.0, 2.0);
		}

		pGLSwitch();
	}

	pGLSwitch();
	glColor3f(1.0, 1.0, 1.0);
}

Protocol.h

Code:
#ifndef _Protocol_H
#define _Protocol_H

#include "StdAfx.h"
#include "Packets.h"

#define ProtocolCore				((BOOL(*)(DWORD,BYTE*,DWORD,DWORD))0x004CDB60)

extern DWORD *GameIndex;

int cMU_ProtocolCore(int index, PBYTE lpMsg, int len, int flags);
void GCNewHealthBarRecv(PMSG_NEW_HEALTH_BAR_RECV* lpMsg);

#endif

Protocol.cpp

Code:
#include "StdAfx.h"

DWORD *GameIndex = (DWORD*)0x78305B4;

int cMU_ProtocolCore(int index, PBYTE lpMsg, int len, int flags)
{
	switch (index)
	{
	case 0xF3:
	{
		switch(((lpMsg[0]==0xC1)?lpMsg[3]:lpMsg[4]))
		{
		case 0xE2:
			GCNewHealthBarRecv((PMSG_NEW_HEALTH_BAR_RECV*)lpMsg);
			return 1;
		}

		break;
	}
	}

	return ProtocolCore(index, lpMsg, len, flags);
}

void GCNewHealthBarRecv(PMSG_NEW_HEALTH_BAR_RECV* lpMsg) // OK
{
	ClearNewHealthBar();

	for (int n = 0; n < lpMsg->count; n++)
	{
		PMSG_NEW_HEALTH_RECV* lpInfo = (PMSG_NEW_HEALTH_RECV*)(((BYTE*)lpMsg) + sizeof(PMSG_NEW_HEALTH_BAR_RECV) + (sizeof(PMSG_NEW_HEALTH_RECV)*n));

		InsertNewHealthBar(lpInfo->index, lpInfo->type, lpInfo->rate);
	}
}

dllmain.cpp

Code:
#include "stdafx.h"

BOOL APIENTRY DllMain(HMODULE hModule,
	DWORD  ul_reason_for_call,
	LPVOID lpReserved
)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

extern "C" _declspec(dllexport) void TheLast()
{
	DWORD OldProtect;
	if (VirtualProtect(LPVOID(0x401000), 2490366, PAGE_EXECUTE_READWRITE, &OldProtect))
	{
		ToolKit.SetCompleteHook(0xFF, MU_PROTOCOL_CORE, &cMU_ProtocolCore);
		ToolKit.SetCompleteHook(0xE8, 0x00580806, &DrawNewHealthBar);
	}
}

GameServer Side

Health packet info worker

Code:
void Start(){
_beginthread(TimerWorker, 0, NULL);
}

void TimerWorker(void * ignored) {

	while (true)
	{
		for (int n = 0; n < OBJECT_MAX; n++)
		{
			LPOBJ lpObj = gObj(n);

			if (lpObj->Type == OBJECT_USER && lpObj->Connected == 3)
			{
				GCNewHealthBarSend(lpObj);
			}
		}

		Sleep(500);
	}
}

void __cdecl GCNewHealthBarSend(LPOBJ lpObj) // OK
{
	BYTE send[4096];

	PMSG_NEW_HEALTH_BAR_SEND pMsg;

	pMsg.header.set(0xF3, 0xE2, 0);

	int size = sizeof(pMsg);

	pMsg.count = 0;

	PMSG_NEW_HEALTH_BAR info;

	for (int n = 0; n < MAX_VIEWPORT; n++)
	{
		if (lpObj->VpPlayer[n].state != VIEWPORT_SEND && lpObj->VpPlayer[n].state != VIEWPORT_WAIT)
		{
			continue;
		}

		if (lpObj->VpPlayer[n].type != OBJECT_MONSTER)
		{
			continue;
		}

		if (OBJECT_RANGE(lpObj->VpPlayer[n].index) == 0)
		{
			continue;
		}

		LPOBJ lpTarget = gObj(lpObj->VpPlayer[n].index);

		if (lpTarget->Live == 0)
		{
			continue;
		}

		info.index = lpTarget->m_Index;

		info.type = (BYTE)lpTarget->Type;

		info.rate = (BYTE)((lpTarget->Life * 100) / (lpTarget->MaxLife + lpTarget->AddLife));

		memcpy(&send[size], &info, sizeof(info));
		size += sizeof(info);

		pMsg.count++;
	}

	pMsg.header.size[0] = SET_NUMBERHB(size);

	pMsg.header.size[1] = SET_NUMBERLB(size);

	memcpy(send, &pMsg, sizeof(pMsg));

	DataSend(lpObj->m_Index, send, size);
}

Packet.h

Code:
struct PSWMSG_HEAD
{
	void set(BYTE head, BYTE subh, WORD size) // OK
	{
		this->type = 0xC2;
		this->size[0] = HIBYTE(size);
		this->size[1] = LOBYTE(size);
		this->head = head;
		this->subh = subh;
	}

	void setE(BYTE head, BYTE subh, WORD size) // OK
	{
		this->type = 0xC4;
		this->size[0] = HIBYTE(size);
		this->size[1] = LOBYTE(size);
		this->head = head;
		this->subh = subh;
	}

	BYTE type;
	BYTE size[2];
	BYTE head;
	BYTE subh;
};

struct PMSG_NEW_HEALTH_BAR_RECV
{
	PSWMSG_HEAD header; // C2:F3:E2
	BYTE count;
};

struct PMSG_NEW_HEALTH_RECV
{
	WORD index;
	BYTE type;
	BYTE rate;
};


Main.exe Link : Download (MEGA)

Compatible with this GameServer: [Release] DarksTeam MuServer 0.99.60/62T (1.0M) Beta 9

pz7QKTp.jpg


 
Last edited:
just use this main that will work or need to do something else?
 
You must create a project and compile the sources. The offsets are for that main.exe. Plus the implementation require server side customs too. Everything needed is available, but this isn't thread for beginners. @DarkMaster can optimize my code and add it as feature to his 99.6XT release, of course that depends on him if he ever planned to add such customs. This source is useful for drawing bars and forms on the game UI. With some additional functions a lot of visual customizations can be done. Some ideas for future development could be: Fix HP/Mana/SD/Exp bars to support over 65535 values; Draw VIP bar/interface; Draw Resets/Grand Resets in the stats panel; Draw Quest info, hints and requirements. All those are just small part of everything which can be done and which i might do in future.

P.S. The server side example void TimerWorker() is not the best idea and might consume a lot CPU so instead of that can be mapped the original GameServer timer callback.
 
@^TheLast^ Thanks for the release.

One thing can you share me the dll for gs, I'm working on a mac and cannot make work visual studio on a VM. A will be very grateful.

Thanks.