Running Man

Adding items to the Controls Menu

by Gum-Lass

In this tutorial we will:

The finished product will be something like this:
Gum-Lass's Modified Controls Menu


First, all the modifications will be made in ui_controls2.c


Now first we are going to add a new sub-section to the menu. Because I'm doing the Running Man mod, I'll call it "RUN". So the new controls menu will go: Then we are going to add a bindable action to the RUN section of the menu.

Firstly, we must change the #defines :
This may seem like a waste of time, but it will help if you want to add other sub-sections.
Add this near the top of the file.

// GLs : This is the centre of the menu. I defined it so I could add more menus later. ;)
#define RM_CONTROLS_MENUMIDDLE 240
where it says "control sections", add the C_RUN #define and change the C_MAX #define


// control sections
#define C_MOVEMENT 0
#define C_LOOKING 1
#define C_WEAPONS 2
#define C_MISC 3
#define C_RUN 4 // GLs : The Running Man menu.
#define C_MAX 5


Then in the next section:
Notice how you have to add 1 to each of the #defines below ID_RUN.

#define ID_MOVEMENT 100
#define ID_LOOKING 101
#define ID_WEAPONS 102
#define ID_MISC 103
#define ID_RUN 104 // GLs : The Running Man Menu.
#define ID_DEFAULTS 105
#define ID_BACK 106
#define ID_SAVEANDEXIT 107
#define ID_EXIT 108


Then below ID_CHAT4, we will define our grapple as ID_WEAPON10.

#define ID_CHAT2 31
#define ID_CHAT3 32
#define ID_CHAT4 33
#define ID_WEAPON10 34 // GLs : Next bindable action.


Again in the next section you must add 1 to all of the #defines

// all others GLs : +1 added to all due to Grappling hook.
#define ID_FREELOOK 35
#define ID_INVERTMOUSE 36
#define ID_ALWAYSRUN 37
#define ID_AUTOSWITCH 38
#define ID_MOUSESPEED 39
#define ID_JOYENABLE 40
#define ID_JOYTHRESHOLD 41
#define ID_SMOOTHMOUSE 42


Now in the struct that follows add a line for the runningman sub-menu.

menutext_s weapons;
menutext_s misc;
menutext_s runningman; // GLs : The Running Man submenu

menuaction_s walkforward;


. . . and another like this . . .

menuaction_s chat3;
menuaction_s chat4;
menuradiobutton_s joyenable;
menuslider_s joythreshold;
menuaction_s grap_hook; // GLs : The Grappling Hook.
int section;
qboolean waitingforkey;
char playerModel[64];


Now we'll add the binding data in the bind_t array, g_bindings[]
Add a line like this at the bottom of the declaration . . .

{"messagemode2","chat - team", ID_CHAT2, ANIM_CHAT,-1,-1,-1,-1},
{"messagemode3","chat - target", ID_CHAT3, ANIM_CHAT,-1,-1,-1, -1},
{"messagemode4","chat - attacker", ID_CHAT4, ANIM_CHAT,-1,-1,-1,-1},
//GLs : Grappling Hook Added as weapon 10.
{"weapon 10", "Grappling Hook", ID_WEAPON10, ANIM_WEAPON10, '0',-1,-1,-1},
{(char*)NULL, (char*)NULL, 0, 0, -1,-1,-1,-1},


Note: the first field is the command you want to bind, the second is the name you want to show up in the menu, the third is the #define of the weapon (we added that at the start of this tut), the fourth is the #define of the animation you want to play while selected. The fifth is the default key you want it to be bound to. The sixth is the default alternate key you would like the command to be bound to. The last 2 you should leave as -1 because this is where the menu system will store the keys users will bind.

Next, we want to add our binding to a group. The static menucommon_s arrays are these groups. Because we want to add our binding to a new group (the "run" sub-menu) we must declare a new group.
Add these lines after the declaration of static menucommon_s *g_misc_controls[]

// GLs : The Running Man Menu.
static menucommon_s *g_rm_controls[] = {
(menucommon_s *)&s_controls.grap_hook,
NULL,
};

Then just below it add this line to the next group.

static menucommon_s **g_controls[] = {
g_movement_controls,
g_looking_controls,
g_weapons_controls,
g_misc_controls,
g_rm_controls, // GLs : Adding it to the main menu.
};


Add these lines in the Controls_Update( void ) function.

// makes sure flags are right on the group selection controls
s_controls.looking.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
s_controls.movement.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
s_controls.weapons.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
s_controls.misc.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
// GLs : Don't forget Running Man
s_controls.runningman.generic.flags &= ~(QMF_GRAYED|QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);


s_controls.looking.generic.flags |= QMF_PULSEIFFOCUS;
s_controls.movement.generic.flags |= QMF_PULSEIFFOCUS;
s_controls.weapons.generic.flags |= QMF_PULSEIFFOCUS;
s_controls.misc.generic.flags |= QMF_PULSEIFFOCUS;
// GLs : Don't forget Running Man here either.
s_controls.runningman.generic.flags |= QMF_PULSEIFFOCUS;


That sets the right flags so that your new item will pulse if the mouse moves over it.

Now, go down to about line 645 and add a section like this below case C_MISC like so:

case C_MISC:
s_controls.misc.generic.flags &= ~QMF_PULSEIFFOCUS;
s_controls.misc.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
break;

case C_RUN:
s_controls.runningman.generic.flags &= ~QMF_PULSEIFFOCUS;
s_controls.runningman.generic.flags |= (QMF_HIGHLIGHT|QMF_HIGHLIGHT_IF_FOCUS);
break;

}


Now we must change something in the void Controls_MenuEvent( void* ptr, int event ) function.
This is about line 1090.
As usual, add the lines in Red

case ID_MISC:
if (event == QM_ACTIVATED)
{
s_controls.section = C_MISC;
Controls_Update();
}
break;

// GLs : The Running Man Menu
case ID_RUN:
if (event == QM_ACTIVATED)
{
s_controls.section = C_RUN;
Controls_Update();
}
break;


case ID_DEFAULTS:
if (event == QM_ACTIVATED)
{
UI_ConfirmMenu( "SET TO DEFAULTS?", Controls_ResetDefaults_Draw, Controls_ResetDefaults_Action );
}
break;


Now you should be able to switch to your menu when you click on it.

Now comes the bit where we actually add all these things to the menu.
In the function void Controls_MenuInit( void ) from about line 1245 change all the lines like so.

s_controls.looking.generic.type = MTYPE_PTEXT;
s_controls.looking.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
s_controls.looking.generic.id = ID_LOOKING;
s_controls.looking.generic.callback = Controls_MenuEvent;
s_controls.looking.generic.x = 152;
s_controls.looking.generic.y = RM_CONTROLS_MENUMIDDLE - 2 * PROP_HEIGHT;
s_controls.looking.string = "LOOK";
s_controls.looking.style = UI_RIGHT;
s_controls.looking.color = color_red;

s_controls.movement.generic.type = MTYPE_PTEXT;
s_controls.movement.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
s_controls.movement.generic.id = ID_MOVEMENT;
s_controls.movement.generic.callback = Controls_MenuEvent;
s_controls.movement.generic.x = 152;
s_controls.movement.generic.y = RM_CONTROLS_MENUMIDDLE - PROP_HEIGHT;
s_controls.movement.string = "MOVE";
s_controls.movement.style = UI_RIGHT;
s_controls.movement.color = color_red;

s_controls.weapons.generic.type = MTYPE_PTEXT;
s_controls.weapons.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
s_controls.weapons.generic.id = ID_WEAPONS;
s_controls.weapons.generic.callback = Controls_MenuEvent;
s_controls.weapons.generic.x = 152;
s_controls.weapons.generic.y = RM_CONTROLS_MENUMIDDLE;
s_controls.weapons.string = "SHOOT";
s_controls.weapons.style = UI_RIGHT;
s_controls.weapons.color = color_red;

s_controls.misc.generic.type = MTYPE_PTEXT;
s_controls.misc.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
s_controls.misc.generic.id = ID_MISC;
s_controls.misc.generic.callback = Controls_MenuEvent;
s_controls.misc.generic.x = 152;
s_controls.misc.generic.y = RM_CONTROLS_MENUMIDDLE + PROP_HEIGHT;
s_controls.misc.string = "MISC";
s_controls.misc.style = UI_RIGHT;
s_controls.misc.color = color_red;

// GLs : Initializing the Running Man Menu.
s_controls.runningman.generic.type = MTYPE_PTEXT;
s_controls.runningman.generic.flags = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
s_controls.runningman.generic.id = ID_RUN;
s_controls.runningman.generic.callback = Controls_MenuEvent;
s_controls.runningman.generic.x = 152;
s_controls.runningman.generic.y = RM_CONTROLS_MENUMIDDLE + 2 * PROP_HEIGHT; // so it's below misc
s_controls.runningman.string = "RUN"; // GLs : Maybe try "RUNNING MAN" later?
s_controls.runningman.style = UI_RIGHT;
s_controls.runningman.color = color_blue;


Then further down at about line 1430, do like this.

s_controls.bfg.generic.type = MTYPE_ACTION;
s_controls.bfg.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
s_controls.bfg.generic.callback = Controls_ActionEvent;
s_controls.bfg.generic.ownerdraw = Controls_DrawKeyBinding;
s_controls.bfg.generic.id = ID_WEAPON9;

// GLs : Running Man's Grappling Hook
s_controls.grap_hook.generic.type = MTYPE_ACTION;
s_controls.grap_hook.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
s_controls.grap_hook.generic.callback = Controls_ActionEvent;
s_controls.grap_hook.generic.ownerdraw = Controls_DrawKeyBinding;
s_controls.grap_hook.generic.id = ID_WEAPON10;

s_controls.attack.generic.type = MTYPE_ACTION;
s_controls.attack.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN;
s_controls.attack.generic.callback = Controls_ActionEvent;
s_controls.attack.generic.ownerdraw = Controls_DrawKeyBinding;
s_controls.attack.generic.id = ID_ATTACK;


We're almost done, I know it's been long, but we're getting close.
At about line 1610 add the following

Menu_AddItem( &s_controls.menu, &s_controls.looking );
Menu_AddItem( &s_controls.menu, &s_controls.movement );
Menu_AddItem( &s_controls.menu, &s_controls.weapons );
Menu_AddItem( &s_controls.menu, &s_controls.misc );
// GLs : The Running Man sub-menu
Menu_AddItem( &s_controls.menu, &s_controls.runningman );


Then this at about line 1660

Menu_AddItem( &s_controls.menu, &s_controls.chat2 );
Menu_AddItem( &s_controls.menu, &s_controls.chat3 );
Menu_AddItem( &s_controls.menu, &s_controls.chat4 );

// GLs : Now Stuff on the Running Man Menu
Menu_AddItem( &s_controls.menu, &s_controls.grap_hook );

Menu_AddItem( &s_controls.menu, &s_controls.back );


And then we're finished. Phew. That took a while.
Anyway, I hope this was helpful for everyone. I know it had me buggered for quite some time. I was beginning to think there was an engine limited number of items one could have on a menu. Luckily, Barry (SoWat!) helped me out and so did DrooG. It turned out all I had wrong was that I just added the grapple define after the last defined thing. BIG MISTAKE. You actually have to add it after the bindable actions and add 1 to all the other defines. That is :

DO NOT JUST ADD #define ID_WEAPON10 42

We'll anyway, I hope this has been helpful.

If you have any questions (or if I've buggered up this tutorial.), e-mail me (Gum-Lass) at benjamin.horn@studentmail.newcastle.edu.au and let me know what you think. Also, please check out my mod, "The Running Man", at http://www.geocites.com/gumlass.