Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


[Tutorial] How to make a Menu

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Tutorials
View previous topic :: View next topic  
Author Message
Brookliny
Master Cheater
Reputation: 0

Joined: 22 Jan 2008
Posts: 438

PostPosted: Mon Nov 23, 2009 9:30 am    Post subject: [Tutorial] How to make a Menu Reply with quote

First thing I did was create a custom cvar. I declared it globally like so:
Code:
Code:

cvar_t *menu;


Next in CG_Init (which was already added by wombat), you will need to define your cvar & its parameters in here. So wombat already added a test cvar called "testcvar" underneath we will add ours.
Code:

Code:
   menu = cgi.Cvar_Get( "menu", "0", CVAR_ARCHIVE );



In the client wrapper you will find a function that looks like this:
Code:
Code:

void CG_Draw2D( void )
{
   CG_DrawTime();
   cge.CG_Draw2D();
}

This is where all the drawing will take place, however to keep code maintained and semi organized what we did is we referenced the function where our menu will be called from within this function.

The function where we will draw our menu is "CG_DrawTime()", you can see it being referenced above.

Now I modified the original code from Wombat's, so it looks a bit different because he doesn't have a menu in his wrapper. Here is how my code looks. I will try and walk you through each part.
Code:
Code:

void CG_DrawTime()
{
   time_t rawtime;
   struct tm * timeinfo;
   time( &rawtime );
   timeinfo = localtime( &rawtime );

   char buff[100];

   /*Draw the menu*/
   if(menu->integer)
   {
      DrawMouse(); //Draw the mouse
      mouseClicks();
      /*Widgets*/

//-------------First Widget---------------------
      cgi.R_SetColor( colorWhite ); //outer outline will be white
      cgi.R_DrawBox(10, 160, 101, 16);
      cgi.R_SetColor( colorDarkRed ); //inner red box
      cgi.R_DrawBox(11, 161, 99, 14);
      cgi.R_SetColor( colorWhite ); //font color
      cgi.R_DrawString( verdana12, "First Widget", 12, 161, -1, 0 );

//-------------Second Widget---------------------
      cgi.R_SetColor( colorWhite ); //outer outline will be white
      cgi.R_DrawBox(10, 180, 101, 16);
      cgi.R_SetColor( colorDarkRed ); //inner red box
      cgi.R_DrawBox(11, 181, 99, 14);
      cgi.R_SetColor( colorWhite ); //font color
      cgi.R_DrawString( verdana12, "Second Widget", 12, 181, -1, 0 );

//-------------Third Widget---------------------
      cgi.R_SetColor( colorWhite ); //outer outline will be white
      cgi.R_DrawBox(10, 200, 101, 16);
      cgi.R_SetColor( colorDarkRed ); //inner red box
      cgi.R_DrawBox(11, 201, 99, 14);
      cgi.R_SetColor( colorWhite ); //font color
      cgi.R_DrawString( verdana12, "Third Widget", 12, 201, -1, 0 );

//-------------Fourth Widget---------------------
      cgi.R_SetColor( colorWhite ); //outer outline will be white
      cgi.R_DrawBox(10, 220, 101, 16);
      cgi.R_SetColor( colorDarkRed ); //inner red box
      cgi.R_DrawBox(11, 221, 99, 14);
      cgi.R_SetColor( colorWhite ); //font color
      cgi.R_DrawString( verdana12, "Fourth Widget", 12, 221, -1, 0 );

//-------------Time---------------------

      int h = timeinfo->tm_hour;
      int m = timeinfo->tm_min;

      static char const * const AM = "AM";
      static char const* const PM = "PM";
      char const *suffix = "AM";

      if (h >= 12 && h < 24)
      {
         if (h != 12)
         {
            h = h % 12;
         }
         suffix = "PM";
      }

      else
      {
         if (h == 0 || h == 24)
         {
            h = 12;
         }
      }

      cgi.R_SetColor( colorWhite );

      sprintf( buff, "%02i:%02i:%02i %s", h, m, timeinfo->tm_sec, suffix);
      cgi.R_DrawString( verdana12, buff, 12, 241, 12, 0 );   
   }
      cgi.R_SetColor( NULL );
}

First part you see is this:
Code:
Code:

   time_t rawtime;
   struct tm * timeinfo;
   time( &rawtime );
   timeinfo = localtime( &rawtime );

These re just some functions originally added by wombat to create an ingame clock. These will be used when we draw the time.

Next you see the character buffer. You can think of the buffer as a temporary storage area where we will store characters "letters, numbers" and then output the buffer using sprintf().

The next part is where all the magic takes place. This is where we toggle the menu. The default value we had the set to was 0, however if you want the menu to come up as soon as you are on the map you would change this code in CG_Init()
Code:

Code:
   menu = cgi.Cvar_Get( "menu", "1", CVAR_ARCHIVE );


Continuing.

So we want to toggle the menu. We can do so with the following if statement:
Code:

Code:
if(menu->integer)


This basically says if you assign a value to menu it will turn on, otherwise if it's set to 0, it will be turned off.
You can also write it like this
Code:

Code:
if(menu->integer == 1)
//turn on
else if(menu->integer == 0)
//turn off


Anywho that's the beginning of it. Next you see a call to DrawMouse().
For simplicity, that should be pretty obvious what that does. That function will draw the mouse, because obviously what good will a menu do if you can interact with it?

After that you see mouseClicks(), this function checks what was clicked. So once the mouse is clicked it will send some kind of event to the game saying it was.

Alright the next bunch of code is kind of repetitive.
The main portion of code is this bit
Code:
Code:

      cgi.R_SetColor( colorWhite ); //outer outline will be white
      cgi.R_DrawBox(10, 160, 101, 16);
      cgi.R_SetColor( colorDarkRed ); //inner red box
      cgi.R_DrawBox(11, 161, 99, 14);
      cgi.R_SetColor( colorWhite ); //font color
      cgi.R_DrawString( verdana12, "First Widget", 12, 161, -1, 0 );

The color parameters have also been added by wombat globally in our .cpp file. If you scroll up, you will see this:
Code:
Code:

// colours
vec4_t      colorBlack      = {0, 0, 0, 1};
vec4_t      colorRed      = {1, 0, 0, 1};
vec4_t      colorGreen      = {0, 1, 0, 1};
vec4_t      colorBlue      = {0, 0, 1, 1};
vec4_t      colorDkRed      = {0.5, 0, 0, 1};
vec4_t      colorDkGreen   = {0, 0.5, 0, 1};
vec4_t      colorDkBlue      = {0, 0, 0.5, 1};
vec4_t      colorLtRed      = {1, 0.5, 0.5, 1};
vec4_t      colorLtGreen   = {0.5, 1, 0.5, 1};
vec4_t      colorLtBlue      = {0.5, 0.5, 1, 1};
vec4_t      colorAlBlue      = {0, 0, 1, 0.25};
vec4_t      colorAlRed      = {1, 0, 0, 0.25};
vec4_t      colorYellow      = {1, 1, 0, 1};
vec4_t      colorMagenta   = {1, 0, 1, 1};
vec4_t      colorCyan      = {0, 1, 1, 1};
vec4_t      colorWhite      = {1, 1, 1, 1};
vec4_t      colorLtzzTEST   = {1, 1, 1, 0.25};
vec4_t      colorLtGrey      = {0.75, 0.75, 0.75, 1};
vec4_t      colorMdGrey      = {0.5, 0.5, 0.5, 1};
vec4_t      colorDkGrey      = {0.25, 0.25, 0.25, 1};
vec4_t      alphaLight      = { 0, 0, 0, 0.25 };
vec4_t      alphaMid      = { 0, 0, 0, 0.5 };
vec4_t      alphaDark      = { 0, 0, 0, 0.75 };
vec4_t      colorTransRed   = { 1, 0, 0, 0.5 };
vec4_t      colorTransBlue   = { 0, 0, 1, 0.5 };
vec4_t      colorTransWhite   = { 1, 1, 1, 0.5 };
vec4_t      colorDarkRed     = { 0.34117647058823529411764705882353, 0.035294117647058823529411764705882, 0.035294117647058823529411764705882, 1 };


Your colors may be a bit different because I added custom ones for my interface, but the idea is the same.
Anywho, First we need to set the color of our shape we are drawing, I'm there are other ways of doing this, but since this is my first menu this is how I did it.
After you assign the color you want, you draw the box, now I have a outer white box that is alittle bit bigger than the inner box, and that gives it that white outline which looks nicer.
After you do that you assign the coordinates for the box. The box is drawn using:
Code:
Code:

cgi.R_DrawBox(10, 160, 101, 16);

Where the parameters are as follows:
Code:

Code:
cgi.R_DrawBox(x coordinate, y coordinate, width of box, height of box);


So as I mentioned for personal taste I drew a box in a box, thats what the following code does:
Code:
Code:

      cgi.R_SetColor( colorWhite ); //outer outline will be white
      cgi.R_DrawBox(10, 160, 101, 16);
      cgi.R_SetColor( colorDarkRed ); //inner red box
      cgi.R_DrawBox(11, 161, 99, 14);

Next we set a color for our font, I chose white, and then we want to draw the font inside of the box within the box (the dark red box), however we want to indent it a little so instead of starting at the first x coordinate 11, we will start at 12.
That gives you the following code here:
Code:

cgi.R_SetColor( colorWhite ); //font color
cgi.R_DrawString( verdana12, "First Widget", 12, 161, -1, 0 );

Regarding the width & height, I don't think that applies for us, because we defined the font that we're using, and the font is only set to a specific font size.

BTW, The default font is facfont 20, if you want to use any of the other ones, do the following.
if you scroll up in the cpp file you will see how facfont is declared, you will declare the others like so:
Code:

Code:
fontHeader_t *facfont20;
fontHeader_t *courier16;
fontHeader_t *courier18;
fontHeader_t *courier20;
fontHeader_t *handle16;
fontHeader_t *handle18;
fontHeader_t *marlett;
fontHeader_t *verdana12;
fontHeader_t *verdana14;

Remember how we told the menu how to behave as a cvar in CG_Init, we will do the same for the font. If you go to the function you should already see facfont declared, you will do the same for the others:
Code:
Code:

   //fonts
   facfont20 = cgi.R_LoadFont( "facfont-20" );
   courier16 = cgi.R_LoadFont( "courier-16" );
   courier18 = cgi.R_LoadFont( "courier-18" );
   courier20 = cgi.R_LoadFont( "courier-20" );
   handle16 = cgi.R_LoadFont( "handle-16" );
   handle18 = cgi.R_LoadFont( "handle-18" );
   marlett = cgi.R_LoadFont( "marlett" );
   verdana12 = cgi.R_LoadFont( "verdana-12" );
   verdana14 = cgi.R_LoadFont( "verdana-14" );

Now you should be able to use the other font, however heads up, marlett is gibberish so don't use it unless you only want your font to look weird haha.

Continuing after you draw all the widgets\boxes you want to space them out I gave my boxes 20 pixels of space on the y axis. You can see that if you scroll up where I posted the source for the function above.

After the boxes are drawn I wanted to show the time. I think it's a cool feature & wombat already did the hard work to get it working so why not. Now, I don't know about all the Europeans, but we Americans are lazy and don't understand military time, so I rewrote the function so our eyes appreciate the numbers a little better. Here is basically how it works:

Code:
Code:

      int h = timeinfo->tm_hour;
      int m = timeinfo->tm_min;

      static char const * const AM = "AM";
      static char const* const PM = "PM";
      char const *suffix = "AM";

      if (h >= 12 && h < 24)
      {
         if (h != 12)
         {
            h = h % 12;
         }
         suffix = "PM";
      }

      else
      {
         if (h == 0 || h == 24)
         {
            h = 12;
         }
      }

      cgi.R_SetColor( colorWhite );

      sprintf( buff, "%02i:%02i:%02i %s", h, m, timeinfo->tm_sec, suffix);
      cgi.R_DrawString( verdana12, buff, 12, 241, 12, 0 );   
   }
      cgi.R_SetColor( NULL );

Basically I check to see if the time is between 1-12 or 13 & 24, if it's 12 (midday) it shows up as 00 because we did %12 we don't want that so we force it to be 12
Similarly when it's midnight the time shows 24:00 so we just set it to 12. I also went through the hassle of making it easy by it saying whether or not it's AM or PM.

You will also see that this is where the buffer comes in handy. It stores the time & label and we output what's stored in the buffer using sprintf.
Lastly, we are done drawing so we do
Code:

Code:
cgi.R_SetColor( NULL );

Ok, now here is the hard part, atleast this was for me.

You remember the drawmouse() function I had above, I tried using Windows API, and while the method worked I didn't use it because I couldn't figure out a way to draw a legit mouse\game mouse. Here is my previous code that I left commented out.
Code:

Code:
/* Not using this, but may come in handy for the future for emulating a mouse
static int x;
static int y;

LRESULT CALLBACK _WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
WNDPROC wndProc = (WNDPROC)SetWindowLong(FindWindow(0, "Medal of Honor Allied Assault"), GWL_WNDPROC, (long)_WndProc);


LRESULT CALLBACK _WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   x=(short)LOWORD(lParam);
   y=(short)HIWORD(lParam);

   return CallWindowProc(wndProc, hWnd, uMsg, wParam, lParam);
}
*/


the variables x & y are globally declared and then we needed to hook wndProc & setWindowLong.

I drew my retarded mouse as a small white box by using
Code:
Code:

      cgi.R_SetColor( colorWhite );
      cgi.R_DrawBox(100, 100, 5, 5);


Anywho, the method I used in game required some debugging. I had to do some seraching through memory and I came across the offset that determines when the mouse is enabled or disabled, and that lead me to the following code:
Code:
Code:

void DrawMouse()
{
   HWND GameWindow = FindWindow( 0, "Medal of Honor Allied Assault" );

    if( GameWindow )
    {
      DWORD ProcessID;
        GetWindowThreadProcessId( GameWindow, &ProcessID );
        HANDLE Process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, ProcessID );

        if(Process)
        {
           BYTE data[]={0x01};
              DWORD datasize = sizeof(data);
         DWORD dwOldProt;
         /*DRAW Mouse*/
         //write
         VirtualProtect((void *)0x012F6FF8, datasize, PAGE_EXECUTE_READWRITE, &dwOldProt);
         WriteProcessMemory(GetCurrentProcess(),(void *)0x012F6FF8, &data, datasize, 0);
         VirtualProtect((void *)0x012F6FF8, datasize, dwOldProt, 0);

         //read
         VirtualProtect((void *)0x012F6FF8, datasize, PAGE_EXECUTE_READWRITE, &dwOldProt);
         WriteProcessMemory(GetCurrentProcess(),(void *)0x012F6FF8, &data, datasize, 0);
         VirtualProtect((void *)0x012F6FF8, datasize, dwOldProt, 0);

         //cheat
         VirtualProtect((void *)0x012F6FF8, datasize, PAGE_EXECUTE_READWRITE, &dwOldProt);
         WriteProcessMemory(GetCurrentProcess(),(void *)0x012F6FF8, &data, datasize, 0);
         VirtualProtect((void *)0x012F6FF8, datasize, dwOldProt, 0);

         CloseHandle( Process );
      }
   }
}

When it comes to WINAPI code, there's really no better way of explaining how it works than to just look at the definition & examples that come on MSDN.

http://msdn.microsoft.com/en-us/libr...74(VS.85).aspx
http://msdn.microsoft.com/en-us/libr...98(VS.85).aspx

Anywho this will enable the mouse & draw the cursor ingame for you.

The last function required was the mouseClicks(), this tells the game what we clicked.

This part of the code also required some modifications. I was running into issues with the cursor coordinates being off sync with the actual game coordinates, so I had to do more debugging to figure out where the x,y coordinates were stored in memory. I then let the mouse position = to those values stored in those offsets.

That lead me to this code here:
Code:

Code:
   POINT myPos;
   myPos.x = *(int*)0x10FFDEC;
   myPos.y = *(int*)0x10FFDF0;


POINT is a Windows data type that defines the mouse positions.

At this point in time I did some checks to make sure we are clicking the buttons and nothing else. Now we declared the size & offsets of our buttons so we know how big they are, but now we need to tell the game where they are.

I have the following piece of code that checks for 3 things.
1. We are in MOHAA & our menu is enabled
2. Whether or not we are in full screen mode or windowed mode
3. Are we clicking the left mouse button

Code:
Code:

   if(FindWindow( 0, "Medal of Honor Allied Assault" ) && menu->integer)
   {
      if(cgs->glConfig.isFullscreen == true)
      {
         if(GetAsyncKeyState(VK_LBUTTON)&1)
         {
            if((myPos.x >= 11)&&(myPos.x <= 110)&&(myPos.y >= 161)&&(myPos.y <= 175))
               cgi.Printf("I clicked the first widget \n");
         }
      }
      else if(cgs->glConfig.isFullscreen == false)
      {
         if(GetAsyncKeyState(VK_LBUTTON)&1)
         {
            if((myPos.x >= 11)&&(myPos.x <= 110)&&(myPos.y >= 161)&&(myPos.y <= 175))
               cgi.Printf("I clicked the first widget \n");
         }

      }
   }

If all of the statements I mentioned above are true the next thing we do is define the coordinates.

We know that these are the coordinated of the box we are interested in:
Code:
Code:

cgi.R_DrawBox(11, 161, 99, 14);


So, what we do is this.
1. Check if the mouse position is greater than or equal to 11, since our coordinate starts at 11.
2. Assuming #1 is correct is the mouse pointer less than or equal to width of the button + the 11 pixels we are offset by? (11 + 99= 110)
3. Assuming the above are correct we now check the y axis. So is the mouse cursor greater than or equal to 161?
4. Assuming the above 3 statements are correct, is our cursor less than or equal to thebutton height + the y axis offset (161 + 14 = 175)

If all of the above requirements are true, then the game knows our cursor is within the first button\widget, so to tell ourselves that this works & to test it we will print out "I clicked the first widget" using:
Code:

Code:
cgi.Printf("I clicked the first widget \n");

Obviously for whatever reason you use the menu for you will replace the printf function with whatever you want the first button even to do whether it's to enable\disable a feature,event, toggle something whatever the case.

I hope everyone finds this useful, and can seriously learn from it. I agree with everyone else here you can't learn from simply copy pasting, however from personal experience I learn best from examples so I figure you can use my work as an example.

I want to thank the following individuals for helping me out with this code. If I forgot anyone, let me know.

Wombat
Okidoki
bobbysing
roverturbo
quicktime
klownterfit
paulius
learn_more
heiko

Edit:
Here is an image of how the menu looks, despite the fact that in the image the PM & AM didn't print out, in the code above it was fixed.
http://x-null.net/menu.JPG

_________________
Back to top
View user's profile Send private message
ebynakis
Master Cheater
Reputation: 0

Joined: 06 Jun 2008
Posts: 288
Location: Somewere dark...i'm scared:(...yeah it's Romania

PostPosted: Wed Nov 25, 2009 2:23 am    Post subject: Reply with quote

Thanx man .. i need this tutorial
_________________
+Rep Is Fun!
Back to top
View user's profile Send private message
ErcHimA
Newbie cheater
Reputation: 0

Joined: 07 Oct 2013
Posts: 18
Location: In Your Heart :P

PostPosted: Sun Jan 19, 2014 5:20 pm    Post subject: Reply with quote

thank you very much, but, ohw to change the background trainer?
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Tutorials All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites