Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

p_menu.c (5316B)


      1 /*
      2 Copyright (C) 1997-2001 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 #include "g_local.h"
     21 
     22 // Note that the pmenu entries are duplicated
     23 // this is so that a static set of pmenu entries can be used
     24 // for multiple clients and changed without interference
     25 // note that arg will be freed when the menu is closed, it must be allocated memory
     26 pmenuhnd_t *PMenu_Open(edict_t *ent, pmenu_t *entries, int cur, int num, void *arg)
     27 {
     28 	pmenuhnd_t *hnd;
     29 	pmenu_t *p;
     30 	int i;
     31 
     32 	if (!ent->client)
     33 		return NULL;
     34 
     35 	if (ent->client->menu) {
     36 		gi.dprintf("warning, ent already has a menu\n");
     37 		PMenu_Close(ent);
     38 	}
     39 
     40 	hnd = malloc(sizeof(*hnd));
     41 
     42 	hnd->arg = arg;
     43 	hnd->entries = malloc(sizeof(pmenu_t) * num);
     44 	memcpy(hnd->entries, entries, sizeof(pmenu_t) * num);
     45 	// duplicate the strings since they may be from static memory
     46 	for (i = 0; i < num; i++)
     47 		if (entries[i].text)
     48 			hnd->entries[i].text = strdup(entries[i].text);
     49 
     50 	hnd->num = num;
     51 
     52 	if (cur < 0 || !entries[cur].SelectFunc) {
     53 		for (i = 0, p = entries; i < num; i++, p++)
     54 			if (p->SelectFunc)
     55 				break;
     56 	} else
     57 		i = cur;
     58 
     59 	if (i >= num)
     60 		hnd->cur = -1;
     61 	else
     62 		hnd->cur = i;
     63 
     64 	ent->client->showscores = true;
     65 	ent->client->inmenu = true;
     66 	ent->client->menu = hnd;
     67 
     68 	PMenu_Do_Update(ent);
     69 	gi.unicast (ent, true);
     70 
     71 	return hnd;
     72 }
     73 
     74 void PMenu_Close(edict_t *ent)
     75 {
     76 	int i;
     77 	pmenuhnd_t *hnd;
     78 
     79 	if (!ent->client->menu)
     80 		return;
     81 
     82 	hnd = ent->client->menu;
     83 	for (i = 0; i < hnd->num; i++)
     84 		if (hnd->entries[i].text)
     85 			free(hnd->entries[i].text);
     86 	free(hnd->entries);
     87 	if (hnd->arg)
     88 		free(hnd->arg);
     89 	free(hnd);
     90 	ent->client->menu = NULL;
     91 	ent->client->showscores = false;
     92 }
     93 
     94 // only use on pmenu's that have been called with PMenu_Open
     95 void PMenu_UpdateEntry(pmenu_t *entry, const char *text, int align, SelectFunc_t SelectFunc)
     96 {
     97 	if (entry->text)
     98 		free(entry->text);
     99 	entry->text = strdup(text);
    100 	entry->align = align;
    101 	entry->SelectFunc = SelectFunc;
    102 }
    103 
    104 void PMenu_Do_Update(edict_t *ent)
    105 {
    106 	char string[1400];
    107 	int i;
    108 	pmenu_t *p;
    109 	int x;
    110 	pmenuhnd_t *hnd;
    111 	char *t;
    112 	qboolean alt = false;
    113 
    114 	if (!ent->client->menu) {
    115 		gi.dprintf("warning:  ent has no menu\n");
    116 		return;
    117 	}
    118 
    119 	hnd = ent->client->menu;
    120 
    121 	strcpy(string, "xv 32 yv 8 picn inventory ");
    122 
    123 	for (i = 0, p = hnd->entries; i < hnd->num; i++, p++) {
    124 		if (!p->text || !*(p->text))
    125 			continue; // blank line
    126 		t = p->text;
    127 		if (*t == '*') {
    128 			alt = true;
    129 			t++;
    130 		}
    131 		sprintf(string + strlen(string), "yv %d ", 32 + i * 8);
    132 		if (p->align == PMENU_ALIGN_CENTER)
    133 			x = 196/2 - strlen(t)*4 + 64;
    134 		else if (p->align == PMENU_ALIGN_RIGHT)
    135 			x = 64 + (196 - strlen(t)*8);
    136 		else
    137 			x = 64;
    138 
    139 		sprintf(string + strlen(string), "xv %d ",
    140 			x - ((hnd->cur == i) ? 8 : 0));
    141 
    142 		if (hnd->cur == i)
    143 			sprintf(string + strlen(string), "string2 \"\x0d%s\" ", t);
    144 		else if (alt)
    145 			sprintf(string + strlen(string), "string2 \"%s\" ", t);
    146 		else
    147 			sprintf(string + strlen(string), "string \"%s\" ", t);
    148 		alt = false;
    149 	}
    150 
    151 	gi.WriteByte (svc_layout);
    152 	gi.WriteString (string);
    153 }
    154 
    155 void PMenu_Update(edict_t *ent)
    156 {
    157 	if (!ent->client->menu) {
    158 		gi.dprintf("warning:  ent has no menu\n");
    159 		return;
    160 	}
    161 
    162 	if (level.time - ent->client->menutime >= 1.0) {
    163 		// been a second or more since last update, update now
    164 		PMenu_Do_Update(ent);
    165 		gi.unicast (ent, true);
    166 		ent->client->menutime = level.time;
    167 		ent->client->menudirty = false;
    168 	}
    169 	ent->client->menutime = level.time + 0.2;
    170 	ent->client->menudirty = true;
    171 }
    172 
    173 void PMenu_Next(edict_t *ent)
    174 {
    175 	pmenuhnd_t *hnd;
    176 	int i;
    177 	pmenu_t *p;
    178 
    179 	if (!ent->client->menu) {
    180 		gi.dprintf("warning:  ent has no menu\n");
    181 		return;
    182 	}
    183 
    184 	hnd = ent->client->menu;
    185 
    186 	if (hnd->cur < 0)
    187 		return; // no selectable entries
    188 
    189 	i = hnd->cur;
    190 	p = hnd->entries + hnd->cur;
    191 	do {
    192 		i++, p++;
    193 		if (i == hnd->num)
    194 			i = 0, p = hnd->entries;
    195 		if (p->SelectFunc)
    196 			break;
    197 	} while (i != hnd->cur);
    198 
    199 	hnd->cur = i;
    200 
    201 	PMenu_Update(ent);
    202 }
    203 
    204 void PMenu_Prev(edict_t *ent)
    205 {
    206 	pmenuhnd_t *hnd;
    207 	int i;
    208 	pmenu_t *p;
    209 
    210 	if (!ent->client->menu) {
    211 		gi.dprintf("warning:  ent has no menu\n");
    212 		return;
    213 	}
    214 
    215 	hnd = ent->client->menu;
    216 
    217 	if (hnd->cur < 0)
    218 		return; // no selectable entries
    219 
    220 	i = hnd->cur;
    221 	p = hnd->entries + hnd->cur;
    222 	do {
    223 		if (i == 0) {
    224 			i = hnd->num - 1;
    225 			p = hnd->entries + i;
    226 		} else
    227 			i--, p--;
    228 		if (p->SelectFunc)
    229 			break;
    230 	} while (i != hnd->cur);
    231 
    232 	hnd->cur = i;
    233 
    234 	PMenu_Update(ent);
    235 }
    236 
    237 void PMenu_Select(edict_t *ent)
    238 {
    239 	pmenuhnd_t *hnd;
    240 	pmenu_t *p;
    241 
    242 	if (!ent->client->menu) {
    243 		gi.dprintf("warning:  ent has no menu\n");
    244 		return;
    245 	}
    246 
    247 	hnd = ent->client->menu;
    248 
    249 	if (hnd->cur < 0)
    250 		return; // no selectable entries
    251 
    252 	p = hnd->entries + hnd->cur;
    253 
    254 	if (p->SelectFunc)
    255 		p->SelectFunc(ent, hnd);
    256 }