DungeonCrawl
Loading...
Searching...
No Matches
inventory_mode.c
Go to the documentation of this file.
1
5#include "inventory_mode.h"
6
8#include "../common.h"
9#include "../game.h"
12#include "../item/gear.h"
14#include "../src/combat/combat_mode.h"
16
17// === Internal Functions ===
24bool can_equip_gear(character_t* player, gear_t* gear);
30void collect_inventory_gear_options(gear_t* gear_inventory[], int count);
41void collect_inv_potion_options(potion_t* potion_inventory[], int count);
42
43// === Intern Global Variables ===
44vector2d_t inventory_view_anchor = {1, 1};
45internal_inventory_state_t inventory_state = INVENTORY_MENU;
46
47int inventory_gear_count = 0;
48int inventory_potion_count = 0;
49
50char** inventory_gear_options = NULL;
51char** inventory_equipment_options = NULL;
52char** inventory_potion_options = NULL;
53
55 inventory_mode_strings = (char**) malloc(sizeof(char*) * MAX_INVENTORY_STRINGS);
56 RETURN_WHEN_NULL(inventory_mode_strings, -1, "Inventory Mode", "Failed to allocate memory for inventory mode strings");
57
58 inventory_equipment_options = (char**) malloc(sizeof(char*) * MAX_SLOT);
59 if (inventory_equipment_options == NULL) {
60 free(inventory_mode_strings);
61 log_msg(ERROR, "Inventory Mode", "Failed to allocate memory for inventory equipment options");
62 return -1;
63 }
64
65 // preset the strings to NULL
66 for (int i = 0; i < MAX_INVENTORY_STRINGS; i++) {
67 inventory_mode_strings[i] = NULL;
68 }
69 // preset the equipped gear options to NULL
70 for (int i = 0; i < MAX_SLOT; i++) {
71 inventory_equipment_options[i] = NULL;
72 }
73
74 //update local once, so the strings are initialized
76 //add update local function to the observer list
78 return 0;
79}
80
81inventory_result_t start_inventory(character_t* player, character_t* monster) {
82 if (monster != NULL) {
83 collect_inventory_gear_options(monster->gear_inventory, monster->gear_count);
84 collect_inventory_equipment_options(monster->equipment);
85 collect_inv_potion_options(monster->potion_inventory, monster->potion_count);
86 } else {
87 collect_inventory_gear_options(player->gear_inventory, player->gear_count);
88 collect_inventory_equipment_options(player->equipment);
89 collect_inv_potion_options(player->potion_inventory, player->potion_count);
90 }
91
92 switch (inventory_state) {
93 case INVENTORY_MENU:
94 inventory_state = inventory_menu(player, monster);
95 break;
96 case INVENTORY_GEAR_MENU:
97 inventory_state = inventory_gear_menu(player, monster);
98 break;
99 case INVENTORY_EQUIPMENT_MENU:
100 inventory_state = inventory_equipment_menu(player, monster);
101 break;
102 case INVENTORY_POTION_MENU:
103 inventory_state = inventory_potion_menu(player, monster);
104 break;
105 case INVENTORY_EXIT:
106 inventory_state = INVENTORY_MENU;
107 return EXIT_TO_MAP;
108 }
109 return CONTINUE_INVENTORY;
110}
111
113 const character_t* target = (monster != NULL) ? monster : player;
114 const vector2d_t anchor = draw_inventory_view(inventory_view_anchor, target);
115 int selected_index = 0;
116
117 internal_inventory_state_t new_state = INVENTORY_MENU;
118 bool submenu_selected = false;
119
120 while (!submenu_selected) {
121 if (monster != NULL) {
122 draw_inventory_menu(anchor,
123 inventory_mode_strings[LOOT_MAIN_MENU_TITLE],
124 NULL,
125 &inventory_mode_strings[LOOT_OPTION_SHOW_GEAR],
126 3,
127 selected_index,
128 NULL,
129 inventory_mode_strings[FINISH_LOOTING_MSG]);
130 } else {
131 draw_inventory_menu(anchor,
132 inventory_mode_strings[MAIN_MENU_TITLE],
133 NULL,
134 &inventory_mode_strings[SHOW_GEAR],
135 3,
136 selected_index,
137 NULL,
138 inventory_mode_strings[PRESS_C_RETURN]);
139 }
140
141 // check for input
142 input_event_t input_event;
143 if (!get_input_blocking(&input_event)) {
144 continue;
145 }
146
147 // Handle input using logical input types
148 switch (input_event.type) {
149 case INPUT_UP:
150 selected_index = (selected_index - 1 + 3) % 3;
151 break;
152 case INPUT_DOWN:
153 selected_index = (selected_index + 1) % 3;
154 break;
155 case INPUT_CONFIRM:
156 if (selected_index == 0) {
157 new_state = INVENTORY_GEAR_MENU;
158 } else if (selected_index == 1) {
159 new_state = INVENTORY_EQUIPMENT_MENU;
160 } else if (selected_index == 2) {
161 new_state = INVENTORY_POTION_MENU;
162 }
163 submenu_selected = true;
164 break;
165 case INPUT_CANCEL:
166 case INPUT_INVENTORY:
167 new_state = INVENTORY_EXIT;
168 submenu_selected = true;
169 break;
170 default:
171 break;
172 }
173 }
174 return new_state;
175}
176
178 const character_t* target = (monster != NULL) ? monster : player;
179 vector2d_t anchor = draw_inventory_view(inventory_view_anchor, target);
180 int selected_index = 0;
181
182 if (target->gear_count == 0) {
183 draw_inventory_log(anchor, inventory_mode_strings[INVENTORY_EMPTY_MSG]);
184 return INVENTORY_MENU;
185 }
186
187 internal_inventory_state_t new_state = INVENTORY_GEAR_MENU;
188 bool item_selected_or_esc = false;
189
190 while (!item_selected_or_esc) {
191 if (monster != NULL) {
192 draw_inventory_menu(anchor,
193 inventory_mode_strings[INVENTORY_MENU_TITLE],
194 inventory_mode_strings[LOOT_GEAR_MENU_HEADER],
195 inventory_gear_options,// TODO
196 monster->gear_count,
197 selected_index,
198 NULL,
199 inventory_mode_strings[PRESS_C_RETURN]);
200 } else {
201 draw_inventory_menu(anchor,
202 inventory_mode_strings[INVENTORY_MENU_TITLE],
203 inventory_mode_strings[INVENTORY_MENU_HEADER],
204 inventory_gear_options,// TODO
205 player->gear_count,
206 selected_index,
207 inventory_mode_strings[INVENTORY_DROP_GEAR_MSG],
208 inventory_mode_strings[PRESS_C_RETURN]);
209 }
210
211 // check for input
212 input_event_t input_event;
213 if (!get_input_blocking(&input_event)) {
214 continue;
215 }
216
217 // For character keys like 'd'/'D', we need to check the raw input value
218 uint32_t key_id = input_event.raw_input.id;
219
220 // Handle input using logical input types
221 switch (input_event.type) {
222 case INPUT_UP:
223 selected_index = (selected_index - 1 + target->gear_count) % target->gear_count;
224 break;
225 case INPUT_DOWN:
226 selected_index = (selected_index + 1) % target->gear_count;
227 break;
228 case INPUT_CONFIRM:
229 if (monster != NULL) {
230 if (player->gear_count < MAX_GEAR_LIMIT) {
231 add_gear(player, monster->gear_inventory[selected_index]);
232 remove_gear(monster, monster->gear_inventory[selected_index]);
233 collect_inventory_gear_options(monster->gear_inventory, monster->gear_count);
234 } else {
235 anchor = draw_inventory_view(inventory_view_anchor, target);
236 draw_inventory_log(anchor, inventory_mode_strings[INVENTORY_FULL_MSG]);
237 }
238 } else {
239 if (player->equipment[player->gear_inventory[selected_index]->slot] == NULL) {
240 if (can_equip_gear(player, player->gear_inventory[selected_index])) {
241 equip_gear(player, player->gear_inventory[selected_index]);
242 collect_inventory_gear_options(player->gear_inventory, player->gear_count);
243 } else {
244 anchor = draw_inventory_view(inventory_view_anchor, target);
245 draw_inventory_log(anchor, inventory_mode_strings[EQUIPMENT_HANDS_SLOT_FULL]);
246 }
247 } else {
248 anchor = draw_inventory_view(inventory_view_anchor, target);
249 draw_inventory_log(anchor, inventory_mode_strings[EQUIPMENT_SLOT_FULL]);
250 }
251 }
252 return INVENTORY_GEAR_MENU;
253 case INPUT_CANCEL:
254 new_state = INVENTORY_MENU;
255 item_selected_or_esc = true;
256 break;
257 default:
258 // Handle special character keys
259 if ((key_id == 'd' || key_id == 'D') && monster == NULL) {
260 remove_gear(player, player->gear_inventory[selected_index]);
261 collect_inventory_gear_options(player->gear_inventory, player->gear_count);
262 return INVENTORY_GEAR_MENU;
263 }
264 break;
265 }
266 }
267 return new_state;
268}
269
277bool can_equip_gear(character_t* player, gear_t* gear) {
278 if (gear->slot == SLOT_BOTH_HANDS) {
279 if (player->equipment[SLOT_LEFT_HAND] != NULL || player->equipment[SLOT_RIGHT_HAND] != NULL) {
280 return false;
281 }
282 } else if (gear->slot == SLOT_LEFT_HAND || gear->slot == SLOT_RIGHT_HAND) {
283 if (player->equipment[SLOT_BOTH_HANDS] != NULL) {
284 return false;
285 }
286 }
287 return true;
288}
289
291 const character_t* target = (monster != NULL) ? monster : player;
292 vector2d_t anchor = draw_inventory_view(inventory_view_anchor, target);
293 int selected_index = 0;
294
295 internal_inventory_state_t new_state = INVENTORY_EQUIPMENT_MENU;
296 bool item_selected_or_esc = false;
297
298 while (!item_selected_or_esc) {
299 if (monster != NULL) {
300 draw_inventory_menu(anchor,
301 inventory_mode_strings[EQUIPMENT_MENU_TITLE],
302 inventory_mode_strings[LOOT_EQUIPMENT_MENU_HEADER],
303 inventory_equipment_options,// TODO
304 MAX_SLOT,
305 selected_index,
306 NULL,
307 inventory_mode_strings[PRESS_C_RETURN]);
308 } else {
309 draw_inventory_menu(anchor,
310 inventory_mode_strings[EQUIPMENT_MENU_TITLE],
311 inventory_mode_strings[EQUIPMENT_MENU_HEADER],
312 inventory_equipment_options,// TODO
313 MAX_SLOT,
314 selected_index,
315 NULL,
316 inventory_mode_strings[PRESS_C_RETURN]);
317 }
318
319 // check for input
320 input_event_t input_event;
321 if (!get_input_blocking(&input_event)) {
322 continue;
323 }
324
325 // Handle input using logical input types
326 switch (input_event.type) {
327 case INPUT_UP:
328 selected_index = (selected_index - 1 + MAX_SLOT) % MAX_SLOT;
329 break;
330 case INPUT_DOWN:
331 selected_index = (selected_index + 1) % MAX_SLOT;
332 break;
333 case INPUT_CONFIRM:
334 if (monster != NULL) {
335 if (monster->equipment[selected_index] != NULL) {
336 if (player->gear_count < MAX_GEAR_LIMIT) {
337 add_gear(player, monster->equipment[selected_index]);
338 remove_equipped_gear(monster, (gear_slot_t) selected_index);
339 collect_inventory_equipment_options(monster->equipment);
340 } else {
341 anchor = draw_inventory_view(inventory_view_anchor, target);
342 draw_inventory_log(anchor, inventory_mode_strings[INVENTORY_FULL_MSG]);
343 }
344 return INVENTORY_EQUIPMENT_MENU;
345 }
346 } else {
347 if (player->equipment[selected_index] != NULL) {
348 if (player->gear_count < MAX_GEAR_LIMIT) {
349 unequip_gear(player, (gear_slot_t) selected_index);
350 collect_inventory_equipment_options(player->equipment);
351 } else {
352 anchor = draw_inventory_view(inventory_view_anchor, target);
353 draw_inventory_log(anchor, inventory_mode_strings[INVENTORY_FULL_MSG]);
354 }
355 return INVENTORY_EQUIPMENT_MENU;
356 }
357 }
358 break;
359 case INPUT_CANCEL:
360 new_state = INVENTORY_MENU;
361 item_selected_or_esc = true;
362 break;
363 default:
364 break;
365 }
366 }
367 return new_state;
368}
369
371 const character_t* target = (monster != NULL) ? monster : player;
372 vector2d_t anchor = draw_inventory_view(inventory_view_anchor, target);
373 int selected_index = 0;
374
375 if (target->potion_count == 0) {
376 draw_inventory_log(anchor, inventory_mode_strings[POTION_EMPTY_MSG]);
377 return INVENTORY_MENU;
378 }
379
380 internal_inventory_state_t new_state = INVENTORY_MENU;
381 bool item_selected_or_esc = false;
382
383 while (!item_selected_or_esc) {
384 if (monster != NULL) {
385 draw_inventory_menu(anchor,
386 inventory_mode_strings[POTION_MENU_TITLE],
387 inventory_mode_strings[LOOT_POTION_MENU_HEADER],
388 inventory_potion_options,// TODO
389 monster->potion_count,
390 selected_index,
391 NULL,
392 inventory_mode_strings[PRESS_C_RETURN]);
393 } else {
394 draw_inventory_menu(anchor,
395 inventory_mode_strings[POTION_MENU_TITLE],
396 inventory_mode_strings[POTION_MENU_HEADER],
397 inventory_potion_options,// TODO
398 player->potion_count,
399 selected_index,
400 inventory_mode_strings[POTION_DROP_POTION_MSG],
401 inventory_mode_strings[PRESS_C_RETURN]);
402 }
403
404 // check for input
405 input_event_t input_event;
406 if (!get_input_blocking(&input_event)) {
407 continue;
408 }
409
410 // For character keys like 'd'/'D', we need to check the raw input value
411 uint32_t key_id = input_event.raw_input.id;
412
413 // Handle input using logical input types
414 switch (input_event.type) {
415 case INPUT_UP:
416 selected_index = (selected_index - 1 + target->potion_count) % target->potion_count;
417 break;
418 case INPUT_DOWN:
419 selected_index = (selected_index + 1) % target->potion_count;
420 break;
421 case INPUT_CONFIRM:
422 if (monster != NULL) {
423 if (player->potion_count < MAX_POTION_LIMIT) {
424 add_potion(player, monster->potion_inventory[selected_index]);
425 remove_potion(monster, monster->potion_inventory[selected_index]);
426 collect_inv_potion_options(monster->potion_inventory, monster->potion_count);
427 } else {
428 anchor = draw_inventory_view(inventory_view_anchor, target);
429 draw_inventory_log(anchor, inventory_mode_strings[POTION_FULL_MSG]);
430 }
431 } else {
432 char message[MAX_STRING_LENGTH];
433 snprintf(message, sizeof(message), inventory_mode_strings[POTION_USE],//TODO: This method of using formats is not safe!
434 player->name,
435 player->potion_inventory[selected_index]->name,
436 player->potion_inventory[selected_index]->value,
437 potion_type_to_string(player->potion_inventory[selected_index]->effectType));
438
439 invoke_potion_effect(player, player->potion_inventory[selected_index]);
440 anchor = draw_inventory_view(inventory_view_anchor, target);
441 draw_inventory_log(anchor, message);
442 collect_inv_potion_options(player->potion_inventory, player->potion_count);
443 }
444 return INVENTORY_POTION_MENU;
445 case INPUT_CANCEL:
446 new_state = INVENTORY_MENU;
447 item_selected_or_esc = true;
448 break;
449 default:
450 // Handle special character keys
451 if ((key_id == 'd' || key_id == 'D') && monster == NULL) {
452 remove_potion(player, player->potion_inventory[selected_index]);
453 collect_inv_potion_options(player->potion_inventory, player->potion_count);
454 return INVENTORY_POTION_MENU;
455 }
456 break;
457 }
458 }
459 return new_state;
460}
461
468void collect_inventory_gear_options(gear_t* gear_inventory[], const int count) {
469 if (inventory_gear_options != NULL) {
470 for (int i = 0; i < inventory_gear_count; i++) {
471 if (inventory_gear_options[i] != NULL) {
472 free(inventory_gear_options[i]);
473 inventory_gear_options[i] = NULL;
474 }
475 }
476 free(inventory_gear_options);
477 inventory_gear_options = NULL;
478 }
479
480 inventory_gear_count = count;
481 inventory_gear_options = (char**) malloc(count * sizeof(char*));
482 RETURN_WHEN_NULL(inventory_gear_options, , "Inventory Mode", "Failed to allocate memory for inventory gear options");
483
484 for (int i = 0; i < count; i++) {
485 inventory_gear_options[i] = (char*) malloc(MAX_STRING_LENGTH * sizeof(char));
486 if (inventory_gear_options[i] == NULL) {
487 for (int j = 0; j < i; j++) {
488 free(inventory_gear_options[j]);
489 inventory_gear_options[j] = NULL;
490 }
491 free(inventory_gear_options);
492 inventory_gear_options = NULL;
493 log_msg(ERROR, "Inventory Mode", "Failed to allocate memory for inventory gear options");
494 return;
495 }
496 }
497
498 for (int i = 0; i < count; i++) {
499 snprintf(inventory_gear_options[i], MAX_STRING_LENGTH,
500 inventory_mode_strings[INVENTORY_GEAR_FORMAT],//TODO: This method of using formats is not safe!
501 gear_inventory[i]->local_key,
502 gear_slot_to_string(gear_inventory[i]->slot),
503 gear_inventory[i]->defenses.armor,
504 gear_inventory[i]->defenses.magic_resist);
505 }
506}
507
514 if (inventory_equipment_options != NULL) {
515 for (int i = 0; i < MAX_SLOT; i++) {
516 if (inventory_equipment_options[i] != NULL) {
517 free(inventory_equipment_options[i]);
518 inventory_equipment_options[i] = NULL;
519 }
520 }
521 for (int i = 0; i < MAX_SLOT; i++) {
522 inventory_equipment_options[i] = (char*) malloc(MAX_STRING_LENGTH * sizeof(char));
523 if (inventory_equipment_options[i] == NULL) {
524 for (int j = 0; j < i; j++) {
525 free(inventory_equipment_options[j]);
526 inventory_equipment_options[j] = NULL;
527 }
528 log_msg(ERROR, "Inventory Mode", "Failed to allocate memory for inventory equipment options");
529 return;
530 }
531 }
532 }
533
534 for (int i = 0; i < MAX_SLOT; i++) {
535 if (equipment[i] != NULL) {
536 snprintf(inventory_equipment_options[i], MAX_STRING_LENGTH,
537 inventory_mode_strings[INVENTORY_GEAR_FORMAT],//TODO: This method of using formats is not safe!
538 equipment[i]->local_key,
539 gear_slot_to_string((gear_slot_t) i),
540 equipment[i]->defenses.armor,
541 equipment[i]->defenses.magic_resist);
542 } else {
543 snprintf(inventory_equipment_options[i], MAX_STRING_LENGTH,
544 inventory_mode_strings[INVENTORY_GEAR_FORMAT_EMPTY],//TODO: This method of using formats is not safe!
545 gear_slot_to_string((gear_slot_t) i));
546 }
547 }
548}
549
556void collect_inv_potion_options(potion_t* potion_inventory[], int count) {
557 if (inventory_potion_options != NULL) {
558 for (int i = 0; i < inventory_potion_count; i++) {
559 if (inventory_potion_options[i] != NULL) {
560 free(inventory_potion_options[i]);
561 inventory_potion_options[i] = NULL;
562 }
563 }
564 free(inventory_potion_options);
565 inventory_potion_options = NULL;
566 }
567
568 inventory_potion_count = count;
569 inventory_potion_options = (char**) malloc(count * sizeof(char*));
570 RETURN_WHEN_NULL(inventory_potion_options, , "Inventory Mode", "Failed to allocate memory for inventory potion options");
571
572 for (int i = 0; i < count; i++) {
573 inventory_potion_options[i] = (char*) malloc(MAX_STRING_LENGTH * sizeof(char));
574 if (inventory_potion_options[i] == NULL) {
575 for (int j = 0; j < i; j++) {
576 free(inventory_potion_options[j]);
577 inventory_potion_options[j] = NULL;
578 }
579 free(inventory_potion_options);
580 inventory_potion_options = NULL;
581 log_msg(ERROR, "Inventory Mode", "Failed to allocate memory for inventory potion options");
582 return;
583 }
584 }
585
586 for (int i = 0; i < count; i++) {
587 snprintf(inventory_potion_options[i], MAX_STRING_LENGTH,
588 inventory_mode_strings[POTION_FORMAT],
589 potion_inventory[i]->name,
590 potion_type_to_string(potion_inventory[i]->effectType),
591 potion_inventory[i]->value);
592 }
593}
594
596 // free the local strings
597 if (inventory_mode_strings != NULL) {
598 for (int i = 0; i < MAX_INVENTORY_STRINGS; i++) {
599 if (inventory_mode_strings[i] != NULL) {
600 free(inventory_mode_strings[i]);
601 }
602 }
603 free(inventory_mode_strings);
604 }
605 // free the inventory gear options
606 if (inventory_gear_options != NULL) {
607 for (int i = 0; i < inventory_gear_count; i++) {
608 if (inventory_gear_options[i] != NULL) {
609 free(inventory_gear_options[i]);
610 }
611 }
612 free(inventory_gear_options);
613 }
614 // free the inventory equipped gear options
615 if (inventory_equipment_options != NULL) {
616 for (int i = 0; i < MAX_SLOT; i++) {
617 if (inventory_equipment_options[i] != NULL) {
618 free(inventory_equipment_options[i]);
619 }
620 }
621 free(inventory_equipment_options);
622 }
623 // free the inventory potion options
624 if (inventory_potion_options != NULL) {
625 for (int i = 0; i < inventory_potion_count; i++) {
626 if (inventory_potion_options[i] != NULL) {
627 free(inventory_potion_options[i]);
628 }
629 }
630 free(inventory_potion_options);
631 }
632}
void add_gear(character_t *character, gear_t *gear)
Adds gear to a character's inventory.
Definition character.c:156
void equip_gear(character_t *character, gear_t *gear)
Equips a gear item to a character.
Definition character.c:272
void add_potion(character_t *character, potion_t *potion)
Adds a potion to a character's inventory.
Definition character.c:242
void remove_gear(character_t *character, gear_t *gear)
Removes a gear item from a character's inventory.
Definition character.c:169
void remove_potion(character_t *character, potion_t *potion)
Removes a potion from a character's inventory.
Definition character.c:254
void remove_equipped_gear(character_t *character, gear_slot_t slot)
Removes the gear equipped in a specific slot of a character.
Definition character.c:187
void unequip_gear(character_t *character, const gear_slot_t slot)
Unequips a gear item from a character and adds it to the character's inventory.
Definition character.c:292
Exposes functions for working working with the character.
void invoke_potion_effect(character_t *character, potion_t *potion)
Invoke the effect of a potion on a character.
Defines common macros, types, and global variables for color schemes and utilities.
Declares core game states, global database connection, and main game control functions.
const char * gear_slot_to_string(gear_slot_t slot)
Converts a gear slot enumeration value to its string representation.
Definition gear.c:86
Exposes functions for working with gear.
bool get_input_blocking(input_event_t *event)
Get the next input event (blocking)
Exposes functions for working with input.
internal_inventory_state_t inventory_menu(character_t *player, character_t *monster)
Displays the main inventory menu.
inventory_result_t start_inventory(character_t *player, character_t *monster)
Starts the inventory mode.
void collect_inventory_equipment_options(gear_t *equipment[])
Checks which options are available in the equipment menu for display.
bool can_equip_gear(character_t *player, gear_t *gear)
Checks if the equipment can be equipped in case it occupies a hands slot.
void collect_inventory_gear_options(gear_t *gear_inventory[], int count)
Checks which options are available in the inventory menu for display.
void shutdown_inventory_mode(void)
Shuts down the inventory mode and frees allocated resources.
void collect_inv_potion_options(potion_t *potion_inventory[], int count)
Checks which options are available in the potion menu for display.
internal_inventory_state_t inventory_equipment_menu(character_t *player, character_t *monster)
Displays the equipment inventory menu.
internal_inventory_state_t inventory_potion_menu(character_t *player, character_t *monster)
Displays the potion inventory menu.
internal_inventory_state_t inventory_gear_menu(character_t *player, character_t *monster)
Displays the gear inventory menu.
int init_inventory_mode()
Initialize the inventory mode.
Exposes functions for working with the inventory mode.
internal_inventory_state_t
Internal states for the inventory mode.
void update_inventory_local(void)
Updates the inventory mode strings with the actual local strings.
Exposes functions for localizing the inventory mode.
void draw_inventory_menu(const vector2d_t anchor, const char *menu_name, const char *header_msg, char **menu_options, const int menu_option_count, const int selected_index, const char *key_msg, const char *tail_msg)
Draws the inventory menu.
vector2d_t draw_inventory_view(const vector2d_t anchor, const character_t *player)
Draws the inventory view UI.
void draw_inventory_log(vector2d_t anchor, const char *inventory_log_message)
Draws the inventory log.
Exposes functions for outputing to the screen while in the inventory mode.
void observe_local(void(*update_func)(void))
Registers an observer function to be notified of updates from the local handler.
Exposes public functions for the localization handler.
void log_msg(const log_level_t level, const char *module, const char *format,...)
Logs a formatted message with a specified log level and module.
Definition logger.c:246
const char * potion_type_to_string(potion_type_t type)
Converts a potion type to a string representation.
Definition potion.c:40
Definition gear.h:32
Structure for advanced input events with context data.
Definition input_types.h:43
2-dimensional vector struct
Definition common.h:164