/hud_info_string.c

https://gitlab.com/fzwoch/fodquake · C · 539 lines · 440 code · 79 blank · 20 comment · 124 complexity · 699ed947fbc8e3c664c38aefa66a270f MD5 · raw file

  1. /*
  2. Copyright (C) 2010 Jürgen Legler
  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 <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include "quakedef.h"
  19. #include "linked_list.h"
  20. #include "hud_new.h"
  21. #include "hud_functions.h"
  22. #include "strl.h"
  23. #define HIS_PLAIN_TEXT (1<<0)
  24. #define HIS_FUNCTION (1<<1)
  25. #define HIS_IDENTIFIER '$'
  26. #define HIS_IDENTIFIER_OPENING_BRACKET '{'
  27. #define HIS_IDENTIFIER_CLOSING_BRACKET '}'
  28. struct hud_info_string_type
  29. {
  30. char *name;
  31. char *(*value_function)(void *info);
  32. int type; // 0 = team, 1 = player
  33. };
  34. static char *team_rl_count_vf(void *info)
  35. {
  36. static char buf[512];
  37. struct team *team;
  38. team = (struct team *)info;
  39. snprintf(buf, sizeof(buf), "%i", team->rl_count);
  40. return buf;
  41. }
  42. #if 1
  43. #warning Please check my suggestion for a replacement below this function :P
  44. static char *team_armor_count_vf(void *info)
  45. {
  46. static char buf[512];
  47. int space = 0;
  48. struct team *team;
  49. team = (struct team *)info;
  50. buf[0] = '\0';
  51. if (team->ra_count > 0)
  52. {
  53. strlcat(buf, va("&cf00%i", team->ra_count), sizeof(buf));
  54. space = 1;
  55. }
  56. if (team->ya_count > 0)
  57. {
  58. if (space)
  59. strlcat(buf, " ", sizeof(buf));
  60. strlcat(buf, va("&cff0%i", team->ya_count), sizeof(buf));
  61. space = 1;
  62. }
  63. if (team->ga_count > 0)
  64. {
  65. if (space)
  66. strlcat(buf, " ", sizeof(buf));
  67. strlcat(buf, va("&c0f0%i", team->ga_count), sizeof(buf));
  68. space = 1;
  69. }
  70. if (space)
  71. strlcat(buf, "&cfff", sizeof(buf));
  72. return buf;
  73. }
  74. #else
  75. static char *team_armor_count_vf(void *info)
  76. {
  77. static char buf[512];
  78. int space = 0;
  79. struct team *team;
  80. team = (struct team *)info;
  81. buf[0] = '\0';
  82. if (team->ra_count > 0)
  83. strlcat(buf, va("&cf00%i ", team->ra_count), sizeof(buf));
  84. if (team->ya_count > 0)
  85. strlcat(buf, va("&cff0%i ", team->ya_count), sizeof(buf));
  86. if (team->ga_count > 0)
  87. strlcat(buf, va("&c0f0%i ", team->ga_count), sizeof(buf));
  88. if (buf[0])
  89. {
  90. buf[strlen(buf)-1] = 0;
  91. strlcat(buf, "&cfff", sizeof(buf));
  92. }
  93. return buf;
  94. }
  95. #endif
  96. static char *team_powerups_vf(void *info)
  97. {
  98. static char buf[4];
  99. int i;
  100. struct team *team;
  101. team = (struct team *)info;
  102. i = 0;
  103. if (team->items & IT_QUAD)
  104. {
  105. buf[i] = 'q';
  106. buf[i++] |= 128;
  107. }
  108. if (team->items & IT_INVULNERABILITY)
  109. {
  110. buf[i] = 'p';
  111. buf[i++] |= 128;
  112. }
  113. if (team->items & IT_INVISIBILITY)
  114. {
  115. buf[i] = 'r';
  116. buf[i++] |= 128;
  117. }
  118. buf[i] = '\0';
  119. return buf;
  120. }
  121. static char *player_health_vf(void *info)
  122. {
  123. static char buf[512];
  124. player_info_t *player;
  125. player = (player_info_t *)info;
  126. snprintf(buf, sizeof(buf), "%i", player->stats[STAT_HEALTH]);
  127. return buf;
  128. }
  129. static char *player_armor_vf(void *info)
  130. {
  131. static char buf[5];
  132. player_info_t *player;
  133. player = (player_info_t *)info;
  134. snprintf(buf, sizeof(buf), "%i", player->stats[STAT_ARMOR]);
  135. return buf;
  136. }
  137. static char *player_armor_type_vf(void *info)
  138. {
  139. player_info_t *player;
  140. player = (player_info_t *)info;
  141. if (player->stats[STAT_ITEMS] & IT_ARMOR1)
  142. return "g";
  143. if (player->stats[STAT_ITEMS] & IT_ARMOR2)
  144. return "y";
  145. if (player->stats[STAT_ITEMS] & IT_ARMOR2)
  146. return "r";
  147. return "";
  148. }
  149. static char *player_weapons_vf(void *info)
  150. {
  151. static char buf[7];
  152. player_info_t *player;
  153. int i;
  154. player = (player_info_t *)info;
  155. i = 0;
  156. if (player->stats[STAT_ITEMS] & IT_SUPER_SHOTGUN)
  157. {
  158. buf[i++] = '3';
  159. if (player->stats[STAT_ACTIVEWEAPON] & IT_SUPER_SHOTGUN)
  160. buf[i-1] |= 128;
  161. }
  162. if (player->stats[STAT_ITEMS] & IT_NAILGUN)
  163. {
  164. buf[i++] = '4';
  165. if (player->stats[STAT_ACTIVEWEAPON] & IT_NAILGUN)
  166. buf[i-1] |= 128;
  167. }
  168. if (player->stats[STAT_ITEMS] & IT_SUPER_NAILGUN)
  169. {
  170. buf[i++] = '5';
  171. if (player->stats[STAT_ACTIVEWEAPON] & IT_SUPER_NAILGUN)
  172. buf[i-1] |= 128;
  173. }
  174. if (player->stats[STAT_ITEMS] & IT_GRENADE_LAUNCHER)
  175. {
  176. buf[i++] = '6';
  177. if (player->stats[STAT_ACTIVEWEAPON] & IT_GRENADE_LAUNCHER)
  178. buf[i-1] |= 128;
  179. }
  180. if (player->stats[STAT_ITEMS] & IT_ROCKET_LAUNCHER)
  181. {
  182. buf[i++] = '7';
  183. if (player->stats[STAT_ACTIVEWEAPON] & IT_ROCKET_LAUNCHER)
  184. buf[i-1] |= 128;
  185. }
  186. if (player->stats[STAT_ITEMS] & IT_LIGHTNING)
  187. {
  188. buf[i++] = '8';
  189. if (player->stats[STAT_ACTIVEWEAPON] & IT_LIGHTNING)
  190. buf[i-1] |= 128;
  191. }
  192. buf[i] = '\0';
  193. return buf;
  194. }
  195. static char *player_powerups_vf(void *info)
  196. {
  197. static char buf[4];
  198. player_info_t *player;
  199. int i;
  200. player = (player_info_t *)info;
  201. i = 0;
  202. if (player->stats[STAT_ITEMS] & IT_QUAD)
  203. {
  204. buf[i] = 'q';
  205. buf[i++] |= 128;
  206. }
  207. if (player->stats[STAT_ITEMS] & IT_INVULNERABILITY)
  208. {
  209. buf[i] = 'p';
  210. buf[i++] |= 128;
  211. }
  212. if (player->stats[STAT_ITEMS] & IT_INVISIBILITY)
  213. {
  214. buf[i] = 'r';
  215. buf[i++] |= 128;
  216. }
  217. buf[i] = '\0';
  218. return buf;
  219. }
  220. static struct hud_info_string_type types[] = {
  221. { "team_rl_count", team_rl_count_vf, 0},
  222. { "team_armor_count", team_armor_count_vf, 0},
  223. { "team_powerups", team_powerups_vf, 0},
  224. { "player_health", player_health_vf, 1},
  225. { "player_armor", player_armor_vf, 1},
  226. { "player_armor_type", player_armor_type_vf, 1},
  227. { "player_powerups", player_powerups_vf, 1},
  228. { "player_weapons", player_weapons_vf, 1}
  229. };
  230. static void Clear_Info_String(struct hud_info_string *info_string)
  231. {
  232. struct hud_info_string_entry *entry, *current;
  233. if (!info_string)
  234. return;
  235. entry = info_string->entry;
  236. while(entry)
  237. {
  238. current = entry;
  239. entry = entry->next;
  240. if (current->type == HIS_PLAIN_TEXT)
  241. if (current->string)
  242. free(current->string);
  243. free(current);
  244. }
  245. free(info_string);
  246. }
  247. static struct hud_info_string_type *get_type(char *name, int type)
  248. {
  249. int i;
  250. for (i=0;i<(sizeof(types)/sizeof(*types));i++)
  251. if (types[i].type == type)
  252. if (strcmp(types[i].name, name) == 0)
  253. return &types[i];
  254. return NULL;
  255. }
  256. static int set_variable(char *string, struct hud_info_string_entry *entry, int type)
  257. {
  258. char *ptr;
  259. int i, max;
  260. char buf[256];
  261. struct hud_info_string_type *string_type;
  262. ptr = string;
  263. ptr += 2;
  264. i=0;
  265. max = strlen(string);
  266. #warning You read 2 bytes past the end of the input here, don't you? ptr = string; ptr += 2; max = strlen(string) and then you use max to indicate the end of ptr, which is +2.
  267. while (*ptr != HIS_IDENTIFIER_CLOSING_BRACKET && i < sizeof(buf) && i < max)
  268. {
  269. buf[i] = *ptr;
  270. ptr++;
  271. i++;
  272. }
  273. if (*ptr != HIS_IDENTIFIER_CLOSING_BRACKET)
  274. {
  275. Com_Printf("malformed info string, could not find closing \"%c\"\n.", HIS_IDENTIFIER_CLOSING_BRACKET);
  276. return 1;
  277. }
  278. #warning Off-by-one bug here. The loop above will exit when i >= sizeof(buf).
  279. buf[i] = '\0';
  280. string_type = get_type(buf, type);
  281. if (!string_type)
  282. {
  283. #warning printf? Ugly, ugly. Yes, there are more than one. Please fix them all :)
  284. printf("type \"%s\" not found.\n", buf);
  285. return 1;
  286. }
  287. entry->value_function = string_type->value_function;
  288. entry->type = HIS_FUNCTION;
  289. return 0;
  290. }
  291. static int set_string(char *string, struct hud_info_string_entry *entry)
  292. {
  293. char *ptr;
  294. int i, max;
  295. char buf[256];
  296. ptr = string;
  297. i=0;
  298. max = Colored_String_Length(string);
  299. #warning This logic looks broken... Using the parsed string length on the raw string input? Same as from above basically.
  300. while (*ptr != HIS_IDENTIFIER && i < sizeof(buf) && i < max)
  301. {
  302. buf[i] = *ptr;
  303. ptr++;
  304. i++;
  305. }
  306. #warning Off-by-one bug here. The loop above will exit when i >= sizeof(buf).
  307. buf[i] = '\0';
  308. entry->string = strdup(buf);
  309. if (entry->string == NULL)
  310. return 1;
  311. entry->type = HIS_PLAIN_TEXT;
  312. return 0;
  313. }
  314. static int Parse_Info_String(char *string, struct hud_info_string *info_string, int type)
  315. {
  316. struct hud_info_string_entry *entry;
  317. int length, once;
  318. char *ptr;
  319. if (!string || !info_string)
  320. return 1;
  321. length = Colored_String_Length(string);
  322. #warning This logic looks broken... Using the parsed string length on the raw string input? Same as from above basically.
  323. entry = calloc(1, sizeof(*entry));
  324. if (entry == NULL)
  325. return 1;
  326. info_string->entry = entry;
  327. ptr = string;
  328. once = 1;
  329. while (ptr < (string + length) && *ptr != '\0')
  330. {
  331. if (!once)
  332. {
  333. entry->next = calloc(1, sizeof(*entry));
  334. if (entry->next == NULL)
  335. return 1;
  336. entry = entry->next;
  337. }
  338. once = 0;
  339. // check if its text
  340. if (*ptr != HIS_IDENTIFIER)
  341. {
  342. if(set_string(ptr, entry))
  343. return 1;
  344. ptr = strchr(ptr, HIS_IDENTIFIER);
  345. if (ptr == 0)
  346. break;
  347. continue;
  348. }
  349. if (*ptr == HIS_IDENTIFIER && *(ptr +1) == HIS_IDENTIFIER)
  350. ptr++;
  351. // check if next part is a variable
  352. if (*(ptr+1) == HIS_IDENTIFIER_OPENING_BRACKET)
  353. {
  354. if (*ptr == HIS_IDENTIFIER)
  355. {
  356. if(set_variable(ptr, entry, type))
  357. return 1;
  358. ptr = strchr(ptr, HIS_IDENTIFIER_CLOSING_BRACKET);
  359. if (ptr == 0)
  360. break;
  361. ptr++;
  362. }
  363. continue;
  364. }
  365. }
  366. return 0;
  367. }
  368. int HUD_Info_String_Changed(struct hud_item *self, int type)
  369. {
  370. struct hud_info_string *is;
  371. char *string;
  372. is = NULL;
  373. string = NULL;
  374. if (type != 0 && type != 1)
  375. return 1;
  376. if (type == 0)
  377. Clear_Info_String(self->team_info_string);
  378. else if (type == 1)
  379. Clear_Info_String(self->team_player_info_string);
  380. if (type == 0)
  381. is = self->team_info_string = calloc(1, sizeof(struct hud_info_string));
  382. else if (type == 1)
  383. is = self->team_player_info_string = calloc(1, sizeof(struct hud_info_string));
  384. if (is == NULL)
  385. {
  386. Com_Printf("error allocating hud_info_string\n");
  387. return 1;
  388. }
  389. if (type == 0)
  390. string = self->team_info_string_plain;
  391. else if (type == 1)
  392. string = self->team_player_info_string_plain;
  393. if (!string)
  394. return 1;
  395. if (Parse_Info_String(string, is, type))
  396. {
  397. Com_Printf("error parsing the string\n");
  398. Clear_Info_String(is);
  399. return 1;
  400. }
  401. return 0;
  402. }
  403. void HUD_Setup_Player_Info_String(struct hud_item *self, struct team *team, int number)
  404. {
  405. struct hud_info_string_entry *entry;
  406. char buf[512];
  407. if (team->players_frag_sorted_info_string[number])
  408. free (team->players_frag_sorted_info_string[number]);
  409. team->players_frag_sorted_info_string[number] = NULL;;
  410. if (!self->team_player_info_string)
  411. return;
  412. buf[0] = '\0';
  413. entry = self->team_player_info_string->entry;
  414. while (entry)
  415. {
  416. if (entry->type == HIS_PLAIN_TEXT)
  417. {
  418. strlcat(buf, entry->string, sizeof(buf));
  419. }
  420. else if (entry->type == HIS_FUNCTION)
  421. {
  422. strlcat(buf, entry->value_function((void *)team->players_frag_sorted[number]), sizeof(buf));
  423. }
  424. entry = entry->next;
  425. }
  426. team->players_frag_sorted_info_string[number] = strdup(buf);
  427. if (team->players_frag_sorted_info_string[number] == NULL)
  428. Com_Printf("warning: strdup in \"HUD_Setup_Player_Info_String\" failed.\n");
  429. }
  430. void HUD_Setup_Team_Info_String(struct hud_item *self, struct team *team)
  431. {
  432. struct hud_info_string_entry *entry;
  433. char buf[512];
  434. if (team->info_string)
  435. free (team->info_string);
  436. team->info_string = NULL;
  437. if (!self->team_info_string)
  438. return;
  439. buf[0] = '\0';
  440. entry = self->team_info_string->entry;
  441. while (entry)
  442. {
  443. if (entry->type == HIS_PLAIN_TEXT)
  444. {
  445. strlcat(buf, entry->string, sizeof(buf));
  446. }
  447. else if (entry->type == HIS_FUNCTION)
  448. {
  449. strlcat(buf, entry->value_function((void *)team), sizeof(buf));
  450. }
  451. entry = entry->next;
  452. }
  453. team->info_string = strdup(buf);
  454. if (team->info_string == NULL)
  455. Com_Printf("warning: strdup in \"HUD_Setup_Team_Info_String\" failed.\n");
  456. }