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 }