1
0
Fork 0
forked from fte/fteqw
fteqw/engine/client/m_items.c
Spoike 9ae7e2621d SOFTWARE RENDERING IS BROKEN: DO NOT USE ASM VERSION.
Lots of changes.
CSQC should be functional, but is still tied to debug builds. It WILL have some bugs still, hopefully I'll be able to clean them up better if people test it a bit.
Precompiled headers are working properly now. Compile times are now much quicker in msvc. This takes most of the files this commit.
Restructured how client commands work. They're buffered outside the network message, some multithreaded code is in. It needs a bit of testing before it's active.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@885 fc73d0e0-1445-4013-8a0c-d673dee63da5
2005-02-28 07:16:19 +00:00

1440 lines
34 KiB
C

//read menu.h
#include "quakedef.h"
int omousex;
int omousey;
qboolean mousemoved;
qboolean bindingactive;
void Draw_TextBox (int x, int y, int width, int lines)
{
mpic_t *p;
int cx, cy;
int n;
// draw left side
cx = x;
cy = y;
p = Draw_SafeCachePic ("gfx/box_tl.lmp");
if (!p) //assume none exist
return;
if (p)
Draw_TransPic (cx, cy, p);
p = Draw_SafeCachePic ("gfx/box_ml.lmp");
for (n = 0; n < lines; n++)
{
cy += 8;
if (p)
Draw_TransPic (cx, cy, p);
}
p = Draw_SafeCachePic ("gfx/box_bl.lmp");
if (p)
Draw_TransPic (cx, cy+8, p);
// draw middle
cx += 8;
while (width > 0)
{
cy = y;
p = Draw_SafeCachePic ("gfx/box_tm.lmp");
if (p)
Draw_TransPic (cx, cy, p);
p = Draw_SafeCachePic ("gfx/box_mm.lmp");
for (n = 0; n < lines; n++)
{
cy += 8;
if (n == 1)
p = Draw_SafeCachePic ("gfx/box_mm2.lmp");
if (p)
Draw_TransPic (cx, cy, p);
}
p = Draw_SafeCachePic ("gfx/box_bm.lmp");
if (p)
Draw_TransPic (cx, cy+8, p);
width -= 2;
cx += 16;
}
// draw right side
cy = y;
p = Draw_SafeCachePic ("gfx/box_tr.lmp");
if (p)
Draw_TransPic (cx, cy, p);
p = Draw_SafeCachePic ("gfx/box_mr.lmp");
for (n = 0; n < lines; n++)
{
cy += 8;
if (p)
Draw_TransPic (cx, cy, p);
}
p = Draw_SafeCachePic ("gfx/box_br.lmp");
if (p)
Draw_TransPic (cx, cy+8, p);
}
void Draw_BigFontString(int x, int y, const char *text)
{
int sx, sy;
mpic_t *p;
p = Draw_SafeCachePic ("gfx/menu/bigfont.lmp");
while(*text)
{
if (*text >= 'a' && *text <= 'z')
{
sx = ((*text-'a')%8)*20;
sy = ((*text-'a')/8)*20;
}
else if (*text >= 'A' && *text <= 'Z')
{
sx = ((*text-'A')%8)*20;
sy = ((*text-'A')/8)*20;
}
else// if (*text <= ' ')
{
sx=-1;
sy=-1;
}
if(sx>=0)
Draw_SubPic(x, y, p, sx, sy, 20, 20);
x+=20;
text++;
}
}
char *menudotstyle;
int maxdots;
int mindot;
int dotofs;
void MenuDrawItems(int xpos, int ypos, menuoption_t *option, menu_t *menu)
{
int i;
mpic_t *p;
while (option)
{
if (mousemoved && !bindingactive)
{
if (omousex > xpos+option->common.posx && omousex < xpos+option->common.posx+option->common.width)
if (omousey > ypos+option->common.posy && omousey < ypos+option->common.posy+option->common.height)
{
if (menu->selecteditem != option)
{
S_LocalSound ("misc/menu1.wav");
menu->selecteditem = option;
}
if (menu->cursoritem)
menu->cursoritem->common.posy = menu->selecteditem->common.posy;
}
}
if (!option->common.ishidden)
switch(option->common.type)
{
case mt_text:
if (!option->text.text)
Draw_Character (xpos+option->common.posx, ypos+option->common.posy, 12+((int)(realtime*4)&1));
else if (option->text.isred)
Draw_Alt_String(xpos+option->common.posx, ypos+option->common.posy, option->text.text);
else
Draw_String(xpos+option->common.posx, ypos+option->common.posy, option->text.text);
break;
case mt_button:
if (!menu->cursoritem && menu->selecteditem == option)
Draw_Alt_String(xpos+option->common.posx, ypos+option->common.posy, option->button.text);
else
Draw_String(xpos+option->common.posx, ypos+option->common.posy, option->button.text);
break;
case mt_buttonbigfont:
Draw_BigFontString(xpos+option->common.posx, ypos+option->common.posy, option->button.text);
break;
case mt_menudot:
i = (int)(realtime * 10)%maxdots;
p = Draw_SafeCachePic(va(menudotstyle, i+mindot ));
Draw_TransPic(xpos+option->common.posx, ypos+option->common.posy+dotofs, p);
break;
case mt_picture:
p = NULL;
if (menu->selecteditem && menu->selecteditem->common.posx == option->common.posx && menu->selecteditem->common.posy == option->common.posy)
p = Draw_SafeCachePic(va("%s_sel", option->picture.picturename));
if (!p)
p = Draw_SafeCachePic(option->picture.picturename);
Draw_TransPic (xpos+option->common.posx, ypos+option->common.posy, p);
break;
case mt_childwindow:
MenuDrawItems(xpos+option->common.posx, ypos+option->common.posy, ((menu_t *)option->custom.data)->options, (menu_t *)option->custom.data);
break;
case mt_box:
Draw_TextBox(xpos+option->common.posx, ypos+option->common.posy, option->box.width, option->box.height);
break;
case mt_slider:
if (option->slider.var)
{
#define SLIDER_RANGE 10
float range;
int i;
int x = xpos+option->common.posx;
int y = ypos+option->common.posy;
range = (option->slider.current - option->slider.min)/(option->slider.max-option->slider.min);
if (option->slider.text)
{
if (!menu->cursoritem && menu->selecteditem == option)
Draw_Alt_String(x, y, option->slider.text);
else
Draw_String(x, y, option->slider.text);
x += strlen(option->slider.text)*8+28;
}
if (range < 0)
range = 0;
if (range > 1)
range = 1;
Draw_Character (x-8, y, 128);
for (i=0 ; i<SLIDER_RANGE ; i++)
Draw_Character (x + i*8, y, 129);
Draw_Character (x+i*8, y, 130);
Draw_Character (x + (SLIDER_RANGE-1)*8 * range, y, 131);
}
break;
case mt_checkbox:
{
int x = xpos+option->common.posx;
int y = ypos+option->common.posy;
qboolean on;
if (option->check.func)
on = option->check.func(option, CHK_CHECKED);
else if (!option->check.var)
on = option->check.value;
else if (option->check.bits) //bits is a bitmask for use with cvars (users can be clumsy, so bittage of 0 uses non-zero as true, but sets only bit 1)
{
if (option->check.var->latched_string)
on = atoi(option->check.var->latched_string)&option->check.bits;
else
on = (int)(option->check.var->value)&option->check.bits;
}
else
{
if (option->check.var->latched_string)
on = !!atof(option->check.var->latched_string);
else
on = !!option->check.var->value;
}
if (option->check.text)
{
if (!menu->cursoritem && menu->selecteditem == option)
Draw_Alt_String(x, y, option->check.text);
else
Draw_String(x, y, option->check.text);
x += strlen(option->check.text)*8+28;
}
#if 0
if (on)
Draw_Character (x, y, 131);
else
Draw_Character (x, y, 129);
#endif
if (on)
Draw_String (x, y, "on");
else
Draw_String (x, y, "off");
}
break;
case mt_edit:
{
int x = xpos+option->common.posx;
int y = ypos+option->common.posy;
if (!menu->cursoritem && menu->selecteditem == option)
Draw_Alt_String(x, y, option->edit.caption);
else
Draw_String(x, y, option->edit.caption);
x+=strlen(option->edit.caption)*8+8;
Draw_TextBox(x-8, y-8, 16, 1);
Draw_String(x, y, option->edit.text);
if (menu->selecteditem == option && (int)(realtime*4) & 1)
{
x += strlen(option->edit.text)*8;
Draw_Character(x, y, 11);
}
}
break;
case mt_bind:
{
int x = xpos+option->common.posx;
int y = ypos+option->common.posy;
int l;
int keys[2];
char *keyname;
if (!menu->cursoritem && menu->selecteditem == option)
Draw_Alt_String(x, y, option->bind.caption);
else
Draw_String(x, y, option->bind.caption);
x += strlen(option->bind.caption)*8+28;
{
l = strlen (option->bind.command);
M_FindKeysForCommand (option->bind.command, keys);
if (bindingactive && menu->selecteditem == option)
{
Draw_String (x, y, "Press key");
}
else if (keys[0] == -1)
{
Draw_String (x, y, "???");
}
else
{
keyname = Key_KeynumToString (keys[0]);
Draw_String (x, y, keyname);
x += strlen(keyname) * 8;
if (keys[1] != -1)
{
Draw_String (x + 8, y, "or");
Draw_String (x + 32, y, Key_KeynumToString (keys[1]));
}
}
}
}
break;
case mt_combo:
{
int x = xpos+option->common.posx;
int y = ypos+option->common.posy;
Draw_String(x, y, option->combo.caption);
x += strlen(option->combo.caption)*8+24;
Draw_String(x, y, option->combo.options[option->combo.selectedoption]);
}
break;
case mt_custom:
option->custom.draw(xpos+option->common.posx, ypos+option->common.posy, &option->custom, menu);
break;
default:
Sys_Error("Bad item type\n");
break;
}
option = option->common.next;
}
}
void MenuDraw(menu_t *menu)
{
if (menu->event)
menu->event(menu);
menu->xpos = ((vid.width - 320)>>1);
MenuDrawItems(menu->xpos, menu->ypos, menu->options, menu);
}
menutext_t *MC_AddWhiteText(menu_t *menu, int x, int y, const char *text, qboolean rightalign)
{
menutext_t *n = Z_Malloc(sizeof(menutext_t));
n->common.type = mt_text;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->text = text;
if (rightalign && text)
n->common.posx -= strlen(text)*8;
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menutext_t *MC_AddBufferedText(menu_t *menu, int x, int y, const char *text, qboolean rightalign, qboolean red)
{
menutext_t *n = Z_Malloc(sizeof(menutext_t) + strlen(text)+1);
n->common.type = mt_text;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->text = (char *)(n+1);
strcpy((char *)(n+1), text);
n->isred = red;
if (rightalign && text)
n->common.posx -= strlen(text)*8;
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menutext_t *MC_AddRedText(menu_t *menu, int x, int y, const char *text, qboolean rightalign)
{
menutext_t *n;
n = MC_AddWhiteText(menu, x, y, text, false);
n->isred = true;
return n;
}
menubind_t *MC_AddBind(menu_t *menu, int x, int y, const char *caption, char *command)
{
menubind_t *n = Z_Malloc(sizeof(menutext_t) + strlen(caption)+1 + strlen(command)+1);
n->common.type = mt_bind;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->caption = (char *)(n+1);
strcpy(n->caption, caption);
n->command = n->caption+strlen(n->caption)+1;
strcpy(n->command, command);
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menupicture_t *MC_AddPicture(menu_t *menu, int x, int y, char *picname)
{
menupicture_t *n;
if (!qrenderer)
return NULL;
Draw_SafeCachePic(picname);
n = Z_Malloc(sizeof(menupicture_t) + strlen(picname)+1);
n->common.type = mt_picture;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->picturename = (char *)(n+1);
strcpy(n->picturename, picname);
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menupicture_t *MC_AddCenterPicture(menu_t *menu, int y, char *picname)
{
int x;
mpic_t *p;
if (!qrenderer)
return NULL;
p = Draw_SafeCachePic(picname);
if (!p)
x = 320/2;
else
x = (320-p->width)/2;
return MC_AddPicture(menu, x, y, picname);
}
menupicture_t *MC_AddCursor(menu_t *menu, int x, int y)
{
int q1, h2, q2;
menupicture_t *n = Z_Malloc(sizeof(menupicture_t));
n->common.type = mt_menudot;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
q1 = COM_FDepthFile("gfx/menudot1.lmp", true);
h2 = COM_FDepthFile("gfx/menu/menudot1.lmp", true);
q2 = COM_FDepthFile("pics/m_cursor1.pcx", true);
if (q2 < h2 && q2 < q1)
{ //AND QUAKE 2 WINS!!!
menudotstyle = "m_cursor%i";
mindot = 0;
maxdots = 15;
dotofs=0;
}
else if (h2 < q1)
{ //AND THE WINNER IS HEXEN 2!!!
menudotstyle = "gfx/menu/menudot%i.lmp";
mindot = 1;
maxdots = 8;
dotofs=-5;
}
else
{ //QUAKE 1 WINS BY DEFAULT!
menudotstyle = "gfx/menudot%i.lmp";
mindot = 1;
maxdots = 6;
dotofs=0;
}
return n;
}
menuedit_t *MC_AddEdit(menu_t *menu, int x, int y, char *text, char *def)
{
menuedit_t *n = Z_Malloc(sizeof(menuedit_t));
n->common.type = mt_edit;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->modified = true;
n->caption = text;
Q_strncpyz(n->text, def, sizeof(n->text));
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menuedit_t *MC_AddEditCvar(menu_t *menu, int x, int y, char *text, char *name)
{
menuedit_t *n = Z_Malloc(sizeof(menuedit_t)+strlen(text)+1);
cvar_t *cvar;
cvar = Cvar_Get(name, "", CVAR_USERCREATED|CVAR_ARCHIVE, NULL); //well, this is a menu/
n->common.type = mt_edit;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->common.width = (strlen(text)+17)*8;
n->common.height = 8;
n->modified = true;
n->caption = (char *)(n+1);
strcpy((char *)(n+1), text);
n->cvar = cvar;
Q_strncpyz(n->text, cvar->string, sizeof(n->text));
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menubox_t *MC_AddBox(menu_t *menu, int x, int y, int width, int height)
{
menubox_t *n = Z_Malloc(sizeof(menupicture_t));
n->common.type = mt_box;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->width = width;
n->height = height;
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menucustom_t *MC_AddCustom(menu_t *menu, int x, int y, const char *data)
{
menucustom_t *n = Z_Malloc(sizeof(menucustom_t));
n->common.type = mt_custom;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->data = NULL;
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menucheck_t *MC_AddCheckBox(menu_t *menu, int x, int y, const char *text, cvar_t *var, int bits)
{
menucheck_t *n = Z_Malloc(sizeof(menucheck_t)+strlen(text)+1);
n->common.type = mt_checkbox;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->common.height = 8;
n->common.width = (strlen(text)+7)*8;
n->text = (char *)(n+1);
strcpy((char *)(n+1), text);
n->var = var;
n->bits = bits;
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menuslider_t *MC_AddSlider(menu_t *menu, int x, int y, const char *text, cvar_t *var, float min, float max)
{
menuslider_t *n = Z_Malloc(sizeof(menuslider_t)+strlen(text)+1);
n->common.type = mt_slider;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->common.height = 8;
n->common.width = (strlen(text)+SLIDER_RANGE+5)*8;
n->var = var;
n->text = (char *)(n+1);
strcpy((char *)(n+1), text);
if (var)
n->current = var->value;
n->min = min;
n->max = max;
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menucombo_t *MC_AddCombo(menu_t *menu, int x, int y, const char *caption, const char **ops, int initialvalue)
{
menucombo_t *n = Z_Malloc(sizeof(menucombo_t));
n->common.type = mt_combo;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->common.height = 8;
n->common.width = strlen(caption)*8;
n->caption = caption;
n->options = ops;
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
n->numoptions = 0;
while(ops[n->numoptions])
{
n->common.width = strlen(caption)*8+strlen(ops[n->numoptions])*8;
n->numoptions++;
}
if (initialvalue >= n->numoptions)
{
Con_Printf("WARNING: Fixed initialvalue for %s\n", caption);
initialvalue = n->numoptions-1;
}
n->selectedoption = initialvalue;
return n;
}
menucombo_t *MC_AddCvarCombo(menu_t *menu, int x, int y, const char *caption, cvar_t *cvar, const char **ops, const char **values)
{
menucombo_t *n = Z_Malloc(sizeof(menucombo_t));
n->common.type = mt_combo;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->common.height = 8;
n->common.width = strlen(caption)*8;
n->caption = caption;
n->options = ops;
n->values = values;
n->cvar = cvar;
n->selectedoption = 0;
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
n->numoptions = 0;
while(ops[n->numoptions])
{
if (!strcmp(values[n->numoptions], cvar->string))
n->selectedoption = n->numoptions;
n->common.width = strlen(caption)*8+strlen(ops[n->numoptions])*8;
n->numoptions++;
}
return n;
}
menubutton_t *MC_AddConsoleCommand(menu_t *menu, int x, int y, const char *text, const char *command)
{
menubutton_t *n = Z_Malloc(sizeof(menubutton_t)+strlen(text)+1+strlen(command)+1);
n->common.type = mt_button;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->common.height = 8;
n->common.width = strlen(text)*8;
n->text = (char *)(n+1);
strcpy((char *)(n+1), text);
n->command = n->text + strlen(n->text)+1;
strcpy((char *)n->command, command);
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menubutton_t *MC_AddConsoleCommandBigFont(menu_t *menu, int x, int y, const char *text, const char *command)
{
menubutton_t *n = Z_Malloc(sizeof(menubutton_t)+strlen(text)+1+strlen(command)+1);
n->common.type = mt_buttonbigfont;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->common.height = 8;
n->common.width = strlen(text)*8;
n->text = (char *)(n+1);
strcpy((char *)(n+1), text);
n->command = n->text + strlen(n->text)+1;
strcpy((char *)n->command, command);
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menubutton_t *MC_AddCommand(menu_t *menu, int x, int y, char *text, qboolean (*command) (union menuoption_s *,struct menu_s *,int))
{
menubutton_t *n = Z_Malloc(sizeof(menubutton_t));
n->common.type = mt_button;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->text = text;
n->command = NULL;
n->key = command;
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
menubutton_t *VARGS MC_AddConsoleCommandf(menu_t *menu, int x, int y, const char *text, char *command, ...)
{
va_list argptr;
static char string[1024];
menubutton_t *n;
va_start (argptr, command);
_vsnprintf (string,sizeof(string)-1, command,argptr);
va_end (argptr);
n = Z_Malloc(sizeof(menubutton_t) + strlen(string)+1);
n->common.type = mt_button;
n->common.iszone = true;
n->common.posx = x;
n->common.posy = y;
n->text = text;
n->command = (char *)(n+1);
strcpy((char *)(n+1), string);
n->common.next = menu->options;
menu->options = (menuoption_t *)n;
return n;
}
void MC_Slider_Key(menuslider_t *option, int key)
{
float range = (option->current - option->min)/(option->max-option->min);
if (key == K_LEFTARROW)
{
range -= 0.1;
if (range < 0)
range = 0;
option->current = range = (range * (option->max-option->min)) + option->min;
if (option->var)
Cvar_SetValue(option->var, range);
}
else if (key == K_RIGHTARROW)
{
range += 0.1;
if (range > 1)
range = 1;
option->current = range = (range * (option->max-option->min)) + option->min;
if (option->var)
Cvar_SetValue(option->var, range);
}
else if (key == K_ENTER || key == K_MOUSE1)
{
range += 0.1;
if (range >= 1.05)
range = 0;
if (range > 1)
range = 1;
option->current = range = (range * (option->max-option->min)) + option->min;
if (option->var)
Cvar_SetValue(option->var, range);
}
else
return;
S_LocalSound ("misc/menu2.wav");
}
void MC_CheckBox_Key(menucheck_t *option, int key)
{
if (key != K_ENTER && key != K_LEFTARROW && key != K_RIGHTARROW && key != K_MOUSE1)
return;
if (option->func)
option->func((union menuoption_s *)option, CHK_TOGGLE);
else if (!option->var)
option->value = !option->value;
else
{
if (option->bits)
{
int old;
if (option->var->latched_string)
old = atoi(option->var->latched_string);
else
old = option->var->value;
if (old & option->bits)
Cvar_SetValue(option->var, old&~option->bits);
else
Cvar_SetValue(option->var, old|option->bits);
}
else
{
if (option->var->latched_string)
Cvar_SetValue(option->var, !atof(option->var->latched_string));
else
Cvar_SetValue(option->var, !option->var->value);
}
S_LocalSound ("misc/menu2.wav");
}
}
void MC_EditBox_Key(menuedit_t *edit, int key)
{
int len = strlen(edit->text);
if (key == K_DEL || key == K_BACKSPACE)
{
if (!len)
return;
edit->text[len-1] = '\0';
}
else if (key < 32 || key > 127)
return;
else
{
edit->text[len] = key;
edit->text[len+1] = '\0';
}
edit->modified = true;
if (edit->cvar)
{
Cvar_Set(edit->cvar, edit->text);
S_LocalSound ("misc/menu2.wav");
}
}
void MC_Combo_Key(menucombo_t *combo, int key)
{
if (key == K_ENTER || key == K_RIGHTARROW || key == K_MOUSE1)
{
combo->selectedoption++;
if (combo->selectedoption >= combo->numoptions)
combo->selectedoption = 0;
changed:
if (combo->cvar)
Cvar_Set(combo->cvar, (char *)combo->values[combo->selectedoption]);
}
else if (key == K_LEFTARROW)
{
combo->selectedoption--;
if (combo->selectedoption < 0)
combo->selectedoption = combo->numoptions-1;
goto changed;
}
}
menu_t *currentmenu;
menu_t *firstmenu;
void M_AddMenuFront (menu_t *menu)
{
menu_t *pmenu;
m_state = m_complex;
if (!firstmenu)
{
M_AddMenu(menu);
return;
}
pmenu = firstmenu;
while(pmenu->parent)
pmenu = pmenu->parent;
pmenu->parent = menu;
menu->child = pmenu;
menu->parent = NULL;
menu->exclusive = true;
menu->xpos = ((vid.width - 320)>>1);
currentmenu = menu;
}
void M_AddMenu (menu_t *menu)
{
m_state = m_complex;
menu->parent = firstmenu;
if (firstmenu)
firstmenu->child = menu;
menu->child = NULL;
firstmenu = menu;
menu->exclusive = true;
currentmenu = menu;
}
menu_t *M_CreateMenu (int extrasize)
{
menu_t *menu;
menu = Z_Malloc(sizeof(menu_t)+extrasize);
menu->iszone=true;
menu->data = menu+1;
M_AddMenu(menu);
return menu;
}
void M_HideMenu (menu_t *menu)
{
if (menu == firstmenu)
firstmenu = menu->parent;
else
{
menu_t *prev;
prev = menu->child;
if (prev)
prev->parent = menu->parent;
if (menu->parent)
menu->parent->child = menu;
}
}
void M_RemoveMenu (menu_t *menu)
{
menuoption_t *op, *oop;
if (menu->remove)
menu->remove(menu);
if (menu == firstmenu)
firstmenu = menu->parent;
else
{
menu_t *prev;
prev = menu->child;
if (prev)
prev->parent = menu->parent;
if (menu->parent)
menu->parent->child = menu;
}
op = menu->options;
while(op)
{
oop = op;
op = op->common.next;
if (oop->common.iszone)
Z_Free(oop);
}
menu->options=NULL;
if (menu->iszone)
{
menu->iszone=false;
Z_Free(menu);
}
if (menu == currentmenu)
currentmenu = firstmenu;
}
void M_RemoveAllMenus (void)
{
if (!firstmenu)
return;
while(firstmenu)
M_RemoveMenu(firstmenu);
}
void M_Complex_Draw(void)
{
extern int mousecursor_x, mousecursor_y;
menu_t *menu, *cmenu;
qboolean foundexclusive = false;
if (omousex != mousecursor_x || omousey != mousecursor_y)
mousemoved = true;
else
mousemoved = false;
omousex = mousecursor_x;
omousey = mousecursor_y;
if (!firstmenu)
{
key_dest = key_game;
m_state = m_none;
return;
}
for (menu = firstmenu; menu; )
{
cmenu = menu;
menu = menu->parent; //this way we can remove the currently drawn menu easily (if needed)
if (cmenu->exclusive)
{
if (foundexclusive)
continue;
foundexclusive=true;
}
MenuDraw(cmenu);
}
Draw_Character(mousecursor_x-4, mousecursor_y-4, '+');
}
menuoption_t *M_NextItem(menu_t *m, menuoption_t *old)
{
menuoption_t *op = m->options;
while(op->common.next)
{
if (op->common.next == old)
return op;
op = op->common.next;
}
return op;
}
menuoption_t *M_NextSelectableItem(menu_t *m, menuoption_t *old)
{
menuoption_t *op;
if (!old)
old = M_NextItem(m, old);
op = old;
while (1)
{
if (!op)
op = currentmenu->options;
op = M_NextItem(m, op);
if (!op)
op = currentmenu->options;
if (op == old)
{
if (op->common.type == mt_slider || op->common.type == mt_checkbox || op->common.type == mt_button || op->common.type == mt_buttonbigfont || op->common.type == mt_edit || op->common.type == mt_combo || op->common.type == mt_bind)
return op;
return NULL; //whoops.
}
if (op->common.type == mt_slider || op->common.type == mt_checkbox || op->common.type == mt_button || op->common.type == mt_buttonbigfont || op->common.type == mt_edit || op->common.type == mt_combo || op->common.type == mt_bind)
if (!op->common.ishidden)
return op;
}
}
menuoption_t *M_PrevSelectableItem(menu_t *m, menuoption_t *old)
{
menuoption_t *op;
if (!old)
old = currentmenu->options;
op = old;
while (1)
{
if (!op)
op = currentmenu->options;
op = op->common.next;
if (!op)
op = currentmenu->options;
if (op == old)
return old; //whoops.
if (op->common.type == mt_slider || op->common.type == mt_checkbox || op->common.type == mt_button || op->common.type == mt_buttonbigfont || op->common.type == mt_edit || op->common.type == mt_combo || op->common.type == mt_bind)
if (!op->common.ishidden)
return op;
}
}
void M_Complex_Key(int key)
{
if (!currentmenu)
return; //erm...
if (currentmenu->key)
if (currentmenu->key(key, currentmenu))
return;
if (currentmenu->selecteditem && currentmenu->selecteditem->common.type == mt_custom && (key == K_DOWNARROW || key == K_UPARROW || key == K_TAB))
if (currentmenu->selecteditem->custom.key(&currentmenu->selecteditem->custom, currentmenu, key))
return;
if (currentmenu->selecteditem && currentmenu->selecteditem->common.type == mt_bind)
{
if (bindingactive)
{
S_LocalSound ("misc/menu1.wav");
if (key != K_ESCAPE && key != '`')
{
Cbuf_InsertText (va("bind %s \"%s\"\n", Key_KeynumToString (key), currentmenu->selecteditem->bind.command), RESTRICT_LOCAL);
}
bindingactive = false;
return;
}
}
switch(key)
{
case K_ESCAPE:
//remove
M_RemoveMenu(currentmenu);
S_LocalSound ("misc/menu3.wav");
break;
case K_TAB:
case K_DOWNARROW:
currentmenu->selecteditem = M_NextSelectableItem(currentmenu, currentmenu->selecteditem);
if (currentmenu->selecteditem)
{
S_LocalSound ("misc/menu1.wav");
if (currentmenu->cursoritem)
currentmenu->cursoritem->common.posy = currentmenu->selecteditem->common.posy;
}
break;
case K_UPARROW:
currentmenu->selecteditem = M_PrevSelectableItem(currentmenu, currentmenu->selecteditem);
if (currentmenu->selecteditem)
{
S_LocalSound ("misc/menu1.wav");
if (currentmenu->cursoritem)
currentmenu->cursoritem->common.posy = currentmenu->selecteditem->common.posy;
}
break;
default:
if (!currentmenu->selecteditem)
{
if (!currentmenu->options)
return;
currentmenu->selecteditem = currentmenu->options;
}
switch(currentmenu->selecteditem->common.type)
{
case mt_slider:
MC_Slider_Key(&currentmenu->selecteditem->slider, key);
break;
case mt_checkbox:
MC_CheckBox_Key(&currentmenu->selecteditem->check, key);
break;
case mt_button:
case mt_buttonbigfont:
if (!currentmenu->selecteditem->button.command)
currentmenu->selecteditem->button.key(currentmenu->selecteditem, currentmenu, key);
else if (key == K_ENTER || key == K_MOUSE1)
{
Cbuf_AddText(currentmenu->selecteditem->button.command, RESTRICT_LOCAL);
S_LocalSound ("misc/menu2.wav");
}
break;
case mt_custom:
currentmenu->selecteditem->custom.key(&currentmenu->selecteditem->custom, currentmenu, key);
break;
case mt_edit:
MC_EditBox_Key(&currentmenu->selecteditem->edit, key);
break;
case mt_combo:
MC_Combo_Key(&currentmenu->selecteditem->combo, key);
break;
case mt_bind:
if (key == K_ENTER)
bindingactive = true;
else if (key == K_BACKSPACE || key == K_DEL)
M_UnbindCommand (currentmenu->selecteditem->bind.command);
default:
break;
}
break;
}
}
typedef struct {
int itemselected;
menu_t *dropout;
menutext_t *op[64];
char *text[64];
menu_t *parent;
} guiinfo_t;
qboolean MC_GuiKey(int key, menu_t *menu)
{
guiinfo_t *info = (guiinfo_t *)menu->data;
switch(key)
{
case K_ESCAPE:
if (info->dropout)
MC_GuiKey(key, info->dropout);
else
{
guiinfo_t *gui;
M_RemoveMenu(menu);
if (menu->parent)
{
gui = (guiinfo_t *)menu->parent->data;
gui->dropout = NULL;
}
}
break;
case K_ENTER:
case K_RIGHTARROW:
if (info->dropout)
MC_GuiKey(key, info->dropout);
else
{
int y, i;
guiinfo_t *gui;
info->dropout = M_CreateMenu(sizeof(guiinfo_t));
currentmenu = info->dropout;
info->dropout->key = MC_GuiKey;
info->dropout->exclusive = false;
info->dropout->parent = menu;
info->dropout->xpos = 0;
info->dropout->ypos = menu->ypos+info->itemselected*8;
for (i = 0; info->text[i]; i++)
if (info->dropout->xpos < strlen(info->text[i]))
info->dropout->xpos = strlen(info->text[i]);
info->dropout->xpos*=8;
info->dropout->xpos+=menu->xpos;
gui = (guiinfo_t *)info->dropout->data;
gui->text[0] = "Hello";
gui->text[1] = "Hello again";
gui->text[2] = "Hello yet again";
for (y = 0, i = 0; gui->text[i]; i++, y+=1*8)
{
info->op[i] = MC_AddRedText(info->dropout, 0, y, gui->text[i], false);
}
}
break;
case K_LEFTARROW:
if (info->dropout)
MC_GuiKey(key, info->dropout);
else
{
guiinfo_t *gui;
M_RemoveMenu(menu);
if (menu->parent)
{
gui = (guiinfo_t *)menu->parent->data;
gui->dropout = NULL;
}
}
break;
case K_UPARROW:
info->op[info->itemselected]->isred = true;
if (info->itemselected)
info->itemselected--;
info->op[info->itemselected]->isred = false;
break;
case K_DOWNARROW:
if (!info->op[info->itemselected])
break;
info->op[info->itemselected]->isred = true;
if (info->text[info->itemselected+1])
info->itemselected++;
info->op[info->itemselected]->isred = false;
break;
}
return true;
}
qboolean MC_Main_Key (int key, menu_t *menu) //here purly to restart demos.
{
if (key == K_ESCAPE)
{
extern int m_save_demonum;
key_dest = key_game;
m_state = m_none;
cls.demonum = m_save_demonum;
if (cls.demonum != -1 && !cls.demoplayback && cls.state == ca_disconnected && COM_CheckParm("-demos"))
CL_NextDemo ();
return true;
}
return false;
}
void M_Menu_Main_f (void)
{
extern cvar_t m_helpismedia;
menubutton_t *b;
menu_t *mainm;
mpic_t *p;
int q1, q2, h2;
SCR_EndLoadingPlaque(); //just in case...
if (!Draw_SafeCachePic)
{
Con_ToggleConsole_f();
return;
}
/*
if (0)
{
int x, i;
guiinfo_t *gui;
m_state = m_complex;
key_dest = key_menu;
m_entersound = true;
mainm = M_CreateMenu(sizeof(guiinfo_t));
mainm->key = MC_GuiKey;
mainm->xpos=0;
gui = (guiinfo_t *)mainm->data;
gui->text[0] = "Single";
gui->text[1] = "Multiplayer";
gui->text[2] = "Quit";
for (x = 0, i = 0; gui->text[i]; i++)
{
gui->op[i] = MC_AddRedText(mainm, x, 0, gui->text[i], false);
x+=(strlen(gui->text[i])+1)*8;
}
return;
}
*/
q1 = COM_FDepthFile("gfx/mainmenu.lmp", true);
q2 = COM_FDepthFile("pics/m_main.pcx", true);
h2 = COM_FDepthFile("gfx/menu/title0.lmp", true);
if (q2 < q1 && q2 < h2) //quake2 main menu.
{
if (Draw_SafeCachePic("pics/m_main_game"))
{
m_state = m_complex;
key_dest = key_menu;
m_entersound = true;
mainm = M_CreateMenu(0);
mainm->key = MC_Main_Key;
MC_AddPicture(mainm, 0, 4, "pics/m_main_plaque");
p = Draw_SafeCachePic("pics/m_main_logo");
if (!p)
return;
MC_AddPicture(mainm, 0, 173, "pics/m_main_logo");
MC_AddPicture(mainm, 68, 13, "pics/m_main_game");
MC_AddPicture(mainm, 68, 53, "pics/m_main_multiplayer");
MC_AddPicture(mainm, 68, 93, "pics/m_main_options");
MC_AddPicture(mainm, 68, 133, "pics/m_main_video");
MC_AddPicture(mainm, 68, 173, "pics/m_main_quit");
mainm->selecteditem = (menuoption_t *)
MC_AddConsoleCommand (mainm, 68, 13, "", "menu_single\n");
MC_AddConsoleCommand (mainm, 68, 53, "", "menu_multi\n");
MC_AddConsoleCommand (mainm, 68, 93, "", "menu_options\n");
MC_AddConsoleCommand (mainm, 68, 133, "", "menu_video\n");
MC_AddConsoleCommand (mainm, 68, 173, "", "menu_quit\n");
mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, 42, 13);
}
return;
}
else if (h2 < q1)
{
m_state = m_complex;
key_dest = key_menu;
m_entersound = true;
mainm = M_CreateMenu(0);
mainm->key = MC_Main_Key;
MC_AddPicture(mainm, 16, 0, "gfx/menu/hplaque.lmp");
p = Draw_SafeCachePic("gfx/menu/title0.lmp");
if (!p)
return;
MC_AddPicture(mainm, (320-p->width)/2, 0, "gfx/menu/title0.lmp");
b=MC_AddConsoleCommandBigFont (mainm, 80, 64, "Single Player", "menu_single\n");
b->common.width = 12*20;
b->common.height = 20;
b=MC_AddConsoleCommandBigFont (mainm, 80, 64+20, "MultiPlayer", "menu_multi\n");
b->common.width = 12*20;
b->common.height = 20;
b=MC_AddConsoleCommandBigFont (mainm, 80, 64+40, "Options", "menu_options\n");
b->common.width = 12*20;
b->common.height = 20;
if (m_helpismedia.value)
b=MC_AddConsoleCommandBigFont (mainm, 80, 64+60, "Media", "menu_media\n");
else
b=MC_AddConsoleCommandBigFont (mainm, 80, 64+60, "Help", "help\n");
b->common.width = 12*20;
b->common.height = 20;
b=MC_AddConsoleCommandBigFont (mainm, 80, 64+80, "Quit", "menu_quit\n");
b->common.width = 12*20;
b->common.height = 20;
mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, 48, 64);
}
else
{
m_state = m_complex;
key_dest = key_menu;
m_entersound = true;
mainm = M_CreateMenu(0);
p = Draw_SafeCachePic("gfx/ttl_main.lmp");
if (!p)
{
MC_AddRedText(mainm, 16, 0, "MAIN MENU", false);
mainm->selecteditem = (menuoption_t *)
MC_AddConsoleCommand (mainm, 64, 32, "Join server", "menu_servers\n");
MC_AddConsoleCommand (mainm, 64, 40, "Options", "menu_options\n");
MC_AddConsoleCommand (mainm, 64, 48, "Quit", "menu_quit\n");
return;
}
mainm->key = MC_Main_Key;
MC_AddPicture(mainm, 16, 4, "gfx/qplaque.lmp");
MC_AddPicture(mainm, (320-p->width)/2, 4, "gfx/ttl_main.lmp");
MC_AddPicture(mainm, 72, 32, "gfx/mainmenu.lmp");
b=MC_AddConsoleCommand (mainm, 16, 32, "", "menu_single\n");
mainm->selecteditem = (menuoption_t *)b;
b->common.width = p->width;
b->common.height = 20;
b=MC_AddConsoleCommand (mainm, 16, 52, "", "menu_multi\n");
b->common.width = p->width;
b->common.height = 20;
b=MC_AddConsoleCommand (mainm, 16, 72, "", "menu_options\n");
b->common.width = p->width;
b->common.height = 20;
if (m_helpismedia.value)
b=MC_AddConsoleCommand(mainm, 16, 92, "", "menu_media\n");
else
b=MC_AddConsoleCommand(mainm, 16, 92, "", "help\n");
b->common.width = p->width;
b->common.height = 20;
b=MC_AddConsoleCommand (mainm, 16, 112, "", "menu_quit\n");
b->common.width = p->width;
b->common.height = 20;
mainm->cursoritem = (menuoption_t *)MC_AddCursor(mainm, 54, 32);
}
}