p_menu.c 5.2 KB

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