|
|
|
|||
|
Tutorials for Experienced
|
| You are the regular coder but want to reach higher levels of engine coding, special hacking techniques, then it's in here. We surely can meet your level and exceed it, if not ? Then post a tutorial yourself ! Get known !!!! |
|
||||||
![]() |
|
|
LinkBack | Thread Tools | Display Modes |
(#1 (permalink))
|
|
Supervisor
![]() Posts: 242
Join Date: Sep 2006
Location: in ur program, making massive overheads
Last Online: Today 04:26 PM Reputation:
![]() User is Offline
|
Adding basic DIB effects to a trainer -
07-07-2009, 08:07 PM
Depression is quite the cue for writing. Oh well - don't feel bad, lines of code do an amazing job of dulling affect, and even more, we get to cover DIB effects! I remembered when I started getting into writing trainers, the only resources available covering DIB's were [sheep]'s and micral's tutorials; don't get me wrong, both of these tutorials are great, but for people just starting coding trainers (or coding in general), the explanations offered in both are very terse.
*Do not misinterpret me, if you are new to coding, I would suggest you stray away from launching into DIB's.* *This tutorial builds upon the code we established in the last tutorial: Separating the injector and the hack - DoxCoding Forums . The only thing we are going to be modifying is the GUI.* Before we begin working on any DIB effects, we need to edit our trainer slightly - first we need to alter the window style, so the whole thing flows better together; we also need to adjust the size so we can fit all of our effects. So edit our CreateWindow call to look like: Code:
hwnd = CreateWindow(wc.lpszClassName, "TrainerEngine", WS_POPUP, (GetSystemMetrics(SM_CXSCREEN)-400)/2, (GetSystemMetrics(SM_CYSCREEN)-300)/2, 400, 300, NULL, NULL, hInstance, NULL); With our window enlarged, we now need to modify the location of our buttons so that they reside on the bottom: Code:
CreateWindow("button", "Start Game", WS_VISIBLE | WS_CHILD, 25, 278, 100, 20, hWnd, (HMENU)1, NULL, NULL);
CreateWindow("button", "About", WS_VISIBLE | WS_CHILD, 150, 278, 100, 20, hWnd, (HMENU)3, NULL, NULL);
CreateWindow("button", "Exit", WS_VISIBLE | WS_CHILD, 275, 278, 100, 20, hWnd, (HMENU)2, NULL, NULL);
Code:
case WM_LBUTTONDOWN: break; Code:
SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, lParam); Code:
case WM_KEYDOWN: if(wParam == VK_ESCAPE) PostQuitMessage(0); break; *Most of the y calculations in this tutorial are based off using the background included in the .ZIP at the end of this file. Adjust if you change the dimensions. Also, it is possible to over the DIB plane over the whole window, and load in .RAW images. Both ways work.* Before we can set up our DIB'ing interface, we need to first set up a BITMAPINFO structure to pass to it - under WinMain, we need to declare it and fill it with values: Code:
BITMAPINFO plane = {0};
plane.bmiHeader.biSize = 40; //size of the structure, can also use sizeof() macro
plane.bmiHeader.biWidth = 400; //width of our plane
plane.bmiHeader.biHeight = -205; //height
plane.bmiHeader.biPlanes = 1; //one layer
plane.bmiHeader.biBitCount = 32; //32 bit colour
*Before we can continue, we need to declare two global variables - under your includes, and before your WndProc, add: Code:
HDC dc = 0; unsigned char* buffer; First, before we can create our DIB section, we need to grab a valid device context handle; to do this, we are going to get the current device context, and then pass it CreateCompatibleDC to give us an active handle we can draw on. Right after our call to CreateWindow place: Code:
dc = CreateCompatibleDC(GetDC(hwnd)); Code:
SelectObject(dc, CreateDIBSection(dc, &plane, 0, (void**)&buffer, 0, 0)); Buffer will become our drawing plane; it is easiest to think of it as a series of on's (1) and off's (0). For example, a square on a 4x4 plane would look like: Quote 1111
1001 1001 1111 Quote FF000000
*Make sure to note that we pass pointers to our plane structure, and our buffer.* *Some may be confused as to why we declared buffer as a null terminating string (char*) - that's for letters right? Incorrect, the only thing the character type identifies a variable as is that it can hold -127 to 127. To extend its range, we are going to modify it with the "unsigned" keyword that extends its range from 0 to 255(FF). Since that's all we need for an individual colour, we are good to go.* With our DIB plane set up, we next need to set the background mode to transparent, and set the text colour to white so we can draw text on it: Code:
SetBkMode(dc, TRANSPARENT); SetTextColor(dc, 0xffffff); *0x designates hex in C++.* With our buffer now set up, we need to go back to the WndProc to ensure that it is painted on the screen. First, since we are going to be calling BeginPaint, we need a PAINTSTRUCT to pass to it - under the gamePath and path definitions: Code:
PAINTSTRUCT ps = {0};
Code:
case WM_PAINT: break; Code:
BitBlt(BeginPaint(hWnd, &ps), 0, 69, 400, 205, dc, 0, 0, SRCCOPY); EndPaint(hWnd, &ps); We can now write a function to draw an individual pixel - at the top of your program, before the WndProc, but after the globals: Code:
void placePixel(int x, int y, unsigned char r, unsigned char g, unsigned char b)
{
register int loc = 0;
loc = (y * 400) + x;
buffer[loc*4] = b;
buffer[loc*4+1] = g;
buffer[loc*4+2] = r;
}
Let's start dissecting this function, because for those of you not working with DIB's, this may appear a bit confusing. Taking in an x and y coordinate, plus the three primary colours, we then determine the pixel's actual location. Actual? That's right, we can't draw to a specific x and y, we instead need to determine where the x and y coordinates we are provided land us. Take, for example, if we pass the value (20, 2). First we start off by factoring in the y aspect; we know that each line has 400 pixels, so if we want to move two lines down, we already need to get to the 800'th pixel range: Quote 2*400 = 800 + x
Quote 800 + 20 = 820
With our actual location, we can begin to shift our values into the corresponding array element - we reference the location * 4 (to compensate for the fact each pixel is a dword), and then move the blue hex value into the first byte, green into the second byte (+1), and red in the the third (+2). *Why are we moving the values in BGR order? Because we need to compensate for Intel's little endianness architecture that reads dwords "backwards."* With our plane all set up, let's start throwing in some basic effects. We are going to start off with the classic starfield effect - stealing micral's idea, we are going to create a small structure for each of our stars. At the top of the program, before our placePixel function: Code:
struct star
{
short int x;
short int y;
};
*Yes, an integer and a DWORD are essentially the same thing.* With that declare, right underneath we can declare our arrays of stars - we are going to make it two layers, one moving and one static: Code:
star starfield[50] = {0, 0};
star background[300] = {0, 0};
Code:
int i = 0; Our arrays declared, we now need to initialise them; under our WM_CREATE case: Code:
for(i = 0; i < 300; i++)
{
if(i < 50)
{
starfield[i].x = rand()%400;
starfield[i].y = rand()%200+1;
}
background[i].x = rand()%400;
background[i].y = rand()%200+1;
}
*The +1 for the y is to ensure that none of the stars land on our separator.* Since we need to move our stars and constantly refresh the screen, the best way to do this is through the use of a timer - under the WM_CREATE case still: Code:
SetTimer(hWnd, 4, 10, 0); *Before we continue, we need to make sure to clean up the timer when we exit; under the WM_DESTROY case: Code:
KillTimer(hWnd, 4); Our timer set up, we need to declare the case to handle it: Code:
case WM_TIMER: break; Code:
memset(buffer, 0, 328000); A clear buffer, we can start drawing our stars - let's start first with our static objects, the background stars and the separator bar: Code:
for(i = 0; i < 400; i++)
{
if(i < 300)
placePixel(background[i].x, background[i].y, 100, 100, 100);
placePixel(i, 0, 250, 250, 250);
}
Code:
for(i = 0; i < 50; i++)
{
}
Code:
if(starfield[i].x-- < 2)
{
starfield[i].y = rand()%200+1;
starfield[i].x = 395;
}
Code:
placePixel(starfield[i].x, starfield[i].y, rand()%255, rand()%255, rand()%255); placePixel(starfield[i].x-1, starfield[i].y, rand()%255, rand()%255, rand()%255); placePixel(starfield[i].x-2, starfield[i].y, rand()%255, rand()%255, rand()%255); placePixel(starfield[i].x-3, starfield[i].y, rand()%255, rand()%255, rand()%255); Finally, we need to finish up our WM_TIMER case by refreshing the entire window: Code:
RedrawWindow(hWnd, 0, 0, RDW_INVALIDATE); Code:
RECT rect = {100, 50, 70, 70};
Code:
DrawText(dc, "= Windows XP MineSweeper + 1 =\n Code..................attilathedud\n Graphics............shashank\n Tune......................", 130, &rect, DT_NOCLIP); Build it again, and you will notice lovely text! The final code: Code:
#include <windows.h>
#include "inject.h"
#include "resource.h"
#define WIN32_LEAN_AND_MEAN
HDC dc = 0;
int i = 0;
unsigned char* buffer;
struct star
{
short int x;
short int y;
};
star starfield[50] = {0, 0};
star background[300] = {0, 0};
void placePixel(int x, int y, unsigned char r, unsigned char g, unsigned char b)
{
register int loc = 0;
loc = (y * 400) + x;
buffer[loc*4] = b;
buffer[loc*4+1] = g;
buffer[loc*4+2] = r;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
OPENFILENAME ofn;
char gamePath[256] = {0}, path[256] = {0};
PAINTSTRUCT ps = {0};
RECT rect = {100, 50, 70, 70};
switch(msg)
{
case WM_CREATE:
CreateWindow("button", "Start Game", WS_VISIBLE | WS_CHILD, 25, 278, 100, 20, hWnd, (HMENU)1, NULL, NULL);
CreateWindow("button", "About", WS_VISIBLE | WS_CHILD, 150, 278, 100, 20, hWnd, (HMENU)3, NULL, NULL);
CreateWindow("button", "Exit", WS_VISIBLE | WS_CHILD, 275, 278, 100, 20, hWnd, (HMENU)2, NULL, NULL);
SetTimer(hWnd, 4, 10, 0);
for(i = 0; i < 300; i++)
{
if(i < 50)
{
starfield[i].x = rand()%400;
starfield[i].y = rand()%200+1;
}
background[i].x = rand()%400;
background[i].y = rand()%200+1;
}
break;
case WM_PAINT:
BitBlt(BeginPaint(hWnd, &ps), 0, 69, 400, 205, dc, 0, 0, SRCCOPY);
EndPaint(hWnd, &ps);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case 1:
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFile = gamePath;
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(gamePath);
ofn.lpstrFilter = ".Exe\0*.EXE\0";
ofn.lpstrTitle = "Please Locate Game";
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if(GetOpenFileName(&ofn))
{
GetModuleFileName(NULL, path, sizeof(path));
for(i = strlen(path); path[i] != '\\'; i--)
path[i] = 0;
strcat(path, "dibInjectorDll.dll");
PROCESS_INFORMATION pI = startProcess(gamePath);
inject(path, pI);
ResumeThread(pI.hThread);
CloseHandle(pI.hThread);
PostQuitMessage(0);
}
break;
case 2:
PostQuitMessage(0);
break;
case 3:
MessageBox(hWnd, "Trainer for Windows XP MineSweeper.\n Hit F7 in-game to set timer to 0. \n Coded by attilathedud.\n Graphics by shashank & attilathedud.\n DoxCoding.com.", "TrainerEngine", MB_OK);
}
break;
case WM_TIMER:
memset(buffer, 0, 328000);
for(i = 0; i < 400; i++)
{
if(i < 300)
placePixel(background[i].x, background[i].y, 100, 100, 100);
placePixel(i, 0, 250, 250, 250);
}
for(i = 0; i < 50; i++)
{
if(starfield[i].x-- < 2)
{
starfield[i].y = rand()%200+1;
starfield[i].x = 395;
}
placePixel(starfield[i].x, starfield[i].y, rand()%255, rand()%255, rand()%255);
placePixel(starfield[i].x-1, starfield[i].y, rand()%255, rand()%255, rand()%255);
placePixel(starfield[i].x-2, starfield[i].y, rand()%255, rand()%255, rand()%255);
placePixel(starfield[i].x-3, starfield[i].y, rand()%255, rand()%255, rand()%255);
}
DrawText(dc, "= Windows XP MineSweeper + 1 =\n Code..................attilathedud\n Graphics............shashank\n Tune......................", 130, &rect, DT_NOCLIP);
RedrawWindow(hWnd, 0, 0, RDW_INVALIDATE);
break;
case WM_LBUTTONDOWN:
SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, lParam);
break;
case WM_KEYDOWN:
if(wParam == VK_ESCAPE)
PostQuitMessage(0);
break;
case WM_DESTROY:
KillTimer(hWnd, 4);
PostQuitMessage(0);
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
HWND hwnd;
WNDCLASS wc = {0};
MSG msg = {0};
BITMAPINFO plane = {0};
plane.bmiHeader.biSize = 40;
plane.bmiHeader.biWidth = 400;
plane.bmiHeader.biHeight = -205;
plane.bmiHeader.biPlanes = 1;
plane.bmiHeader.biBitCount = 32;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(ID_ICON));
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = "TrainerEngine";
wc.hbrBackground = CreatePatternBrush(LoadBitmap(hInstance, (char*)ID_BACK));
RegisterClass(&wc);
hwnd = CreateWindow(wc.lpszClassName, "TrainerEngine", WS_POPUP, (GetSystemMetrics(SM_CXSCREEN)-400)/2, (GetSystemMetrics(SM_CYSCREEN)-300)/2, 400, 300, NULL, NULL, hInstance, NULL);
dc = CreateCompatibleDC(GetDC(hwnd));
SelectObject(dc, CreateDIBSection(dc, &plane, 0, (void**)&buffer, 0, 0));
SetBkMode(dc, TRANSPARENT);
SetTextColor(dc, 0xffffff);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
UnregisterClass("TrainerEngine", hInstance);
while(1)
{
GetMessage(&msg, NULL, 0, 0);
if(msg.message == WM_QUIT)
break;
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
<3 attilathedud Shoutouts: STN - For his DVT trainer-template which gave me a lot of ideas, and for helping me with debugging. He be sexy. And he's still the star-field god. atam0s - For helping debugging and throwing out suggestions for how to append a timer to the project. Wouldn't have been possible without you mate, thanks. King_Orgy - For testing, being a sexy dude. pandas - He's always going to have a shoutout for helping me when I was new. Thanks oldie. Written for doxcoding.com, make sure credits stay intact if posted elsewhere. |
|
![]() |
| Bookmarks |
| Thread Tools | |
| Display Modes | |
|
|
|
| New To Site? | Need Help? |