Title    : MenuMod for Quake 2
Filename : q2menu10.zip
Version  : 1.00
Date     : 1-24-98
Author   : David 'crt' Wright
Email    : wrightd@stanford.edu
Webpage  : http://www.planetquake.com/servers/arena

Intro
-----
As part of Rocket Arena 2 I decided to make an easy to use and very complete
menu system that could be used in any Quake 2 mod. This is the result. 

MenuMod's features include:
* Unlimited menus per client, stored in a stack
* Unlimited menu items per menu
* Two menu types, Fancy (using layout) and Regular (using centerprints)
* Minimal additions to the id code
* Ability to display 2 strings a 1 integer value per menu item
* Uses callback functions, so there is no repeating loop
* Simple and easy to remember menu keys
* Automatically scroll long menus (in fancy)

How to use
----------
MenuMod is distributed as a VC++ 5.0 example project. To add MenuMod to
your own code you need to follow these steps:

1. Add menu.c (and menu.h) to your project source files.
2. Make the following changes to the id source code:
(search for //menu to see them in the example code)

--g_local.h--
ADD
#include "menu.h"
near the top

ADD
	qboolean	showmenu;
	arena_link_t menulist; //={NULL,NULL,NULL};
	arena_link_t *curmenulink;
	arena_link_t *selected;
to the bottom of the gclient_s structure

--p_client.c--ClientThink---------------------------------
IF you are going to use normal menus
ADD
	MenuThink(ent);
to the top of ClientThink
This is not needed for Fancy Menus

--g_cmds.c--SelectNextItem--------------------------------
ADD
    //menu
	if (ent->client->showmenu)
	{
		MenuNext(ent);
		return;
	}
to the top of that function

--g_cmds.c--SelectPrevItem--------------------------------
ADD
	//menu
	if (ent->client->showmenu)
	{
		MenuPrev(ent);
		return;
	}
to the top of that function

--g_cmds.c--Cmd_InvUse_f----------------------------------
IF you want clients to be able to toggle the menu
ADD
//menu
	if (cl->showmenu)
		cl->showmenu=false;
	else
		ent->client->showmenu = ent->client->curmenulink ? true : false;
	DisplayMenu(ent);
	return;
//below is unused in menumod

Please note that this will disable the normal inventory function.

--g_cmds.c--Cmd_InvUse_f----------------------------------
ADD
	//menu
	if (ent->client->showmenu)
	{
		UseMenu(ent, 1);
		return;
	}
to the top of that function

--g_cmds.c--Cmd_InvDrop_f----------------------------------
ADD
	//menu
	if (ent->client->showmenu)
	{
		UseMenu(ent, 0);
		return;
	}
to the top of that function

The example mod also has a few additions to ClientCommand to
display the example menus.


3. Once you have made these changes, you can begin adding menus
to your mod. You will need a

	arena_link_t *menulink

in your procecdure to hold the pointer to the menu.
Then, to create a menu, simple call

	menulink = CreateMenu(ent, "Menu Title");

You can now add menu items to the menu using:

	AddMenuItem(menulink, "Item Text ", "Value Text ", value, &MyCallbackFunc);

The item will be displayed on the menu in the form
Item Text Value Text Value
So you can have two strings and a value for a menu item. Set value to -1 to display
no value, and set Value Text to NULL for no value text, Item Text must NOT be NULL.

MyCallbackFunc is the function that will be called when they select that item. See
below for more info on the callback function.

You can add as many items as you want in this manner. When you are done, add

	FinishMenu(ent, menulink);

the menu will now be displayed to the client. 

Client Commmands
----------------
[command - default binding - description]

inven - TAB - If you allow clients to toggle the menu, and you are using Fancy Menus, 
              this will toggle the menu on/off.

invprev - [ - This moves up one item on the menu. The menu will wrap down to the bottom.

invnext - ] - This moves down one item. The menu will wrap back to the top.

invuse - ENTER - This selects an item, with a "key" value of 1.

invdrop - ' - This selects an item, with a "key" value of 0.

The Callback Function
---------------------
When a client selects an item from the menu, MenuMod calls the function you
have specified for that menu item. Multiple menu items can share the same callback.
The callback function MUST be in the form:

int MyCallBackFunc(edict_t *ent, arena_link_t *menulink, arena_link_t *selected, int key)

ent is the entity that selected the menu item.

menulink is the link to the current menu.
menulink->it is the menu
menulink->prev is the previous menu
menulink->next is the next menu

selected is the link to the current item
selected->it is the item
selected->next is the next item
selected->prev is the previous item

key is the key that the pressed, invuse (ENTER) is 1, invdrop (') is 0. You can use
this to increment/decrement values based on the key.

You can do whatever you want in the menu callback function, included creating new menus,
and modifying current menu items.

When you are done, return 0 to clear the menu from the menu stack (and display the next
one if there is one) or return 1 to keep the current menu up.

Examples
--------
In the MenuMod example mod, there are three example menus.
The menus are placed on the stack when a client does /cmd dotest

The first simply places 4 items on the menu, text only. The callback function
for it displays the itemtext of the item that was selected, then returns 0 to
remove the menu.

The second exmaple shows how to set a Fraglimit/Timelimit using a menu.
The current settings are put in the menu initially. When a use selects
on of the two, MySelect2 is called and the value is incremented/decremented
based on the key they use.
MySelect3 is called for the OK item, and simple prints what they were, and
sets the correct cvar's.

The final example shows how a long menu, created with a loop, will scroll.


Other Stuff
-----------
This code is not quite as "clean" as I would like, but I desinged it to
suit my purposes. Specifically, things you need to look out for:
Strings passed for the menu title and menu item text are NOT copied, it
just uses the pointers, so if you change (or free) that memory it could affect
the menu.
The only way to switch between fancy/regular menus is a #define, so unless you
modify it, you have to use one type for your whole project. The regular menus
are not as full features (no scrolling) and have not been tested as much.

I have attemped to document the structure used to store the menu at the top
of the source. Hopefully it will help if you are trying to modify the menu code.
Remember that ->it is a *void pointer, so you will need to typecast it to do
anything useful.

The FancyMenu will replace your current layout (the statusbar).
It restores the layout to single_statusbar for single player games
and dm_statusbar for deathmatch games. If you use a custom statusbar, you 
may need to change this.

Support
-------
I am releasing this code as a contribution to the community. It will not
be an ongoing project of mine, so do not expect lots of updates or support.
I will help for critical problems, but please read over all this info, try
the example mod, and mess around with it before asking.

Licensing/Distribution
----------------------

This code is freely distributable provided that this readme is distributed
as well and is unchanged.

All code is copyright David Wright 1998.
This code may be used in any free, publicaly available mod.
Commercial code licensing is available by contacting wrightd@stanford.edu
