29internal_combat_state_t combat_state = COMBAT_MENU;
34char** ability_menu_options = NULL;
35char** potion_menu_options = NULL;
68 combat_mode_strings = (
char**) malloc(MAX_COMBAT_MODE_STRINGS *
sizeof(
char*));
69 RETURN_WHEN_NULL(combat_mode_strings, -1,
"Combat Mode",
"Allocated memory for combat mode strings in memory pool is NULL");
71 ability_menu_options = (
char**) malloc(
sizeof(
char*) * MAX_ABILITY_LIMIT);
72 if (ability_menu_options == NULL) {
73 free(combat_mode_strings);
74 combat_mode_strings = NULL;
75 log_msg(ERROR,
"Combat Mode",
"Failed to allocate memory for ability menu options.");
79 potion_menu_options = (
char**) malloc(
sizeof(
char*) * MAX_POTION_LIMIT);
80 if (potion_menu_options == NULL) {
81 free(combat_mode_strings);
82 combat_mode_strings = NULL;
83 free(ability_menu_options);
84 log_msg(ERROR,
"Combat Mode",
"Failed to allocate memory for potion menu options.");
88 for (
int i = 0; i < MAX_COMBAT_MODE_STRINGS; i++) {
89 combat_mode_strings[i] = NULL;
92 for (
int i = 0; i < MAX_ABILITY_LIMIT; i++) {
93 ability_menu_options[i] = NULL;
96 for (
int i = 0; i < MAX_POTION_LIMIT; i++) {
97 potion_menu_options[i] = NULL;
115 switch (combat_state) {
125 case EVALUATE_COMBAT:
127 if (player->current_resources.health <= 0) {
132 if (monster->current_resources.health <= 0) {
136 char message[MAX_STRING_LENGTH];
137 snprintf(message,
sizeof(message),
"You won the combat! %s is dead.", monster->name);
140 player->xp += monster->xp_reward;
147 combat_state = COMBAT_MENU;
153 return CONTINUE_COMBAT;
159 int selected_index = 0;
161 internal_combat_state_t new_state = COMBAT_MENU;
162 bool submenu_selected =
false;
164 while (!submenu_selected) {
167 combat_mode_strings[MAIN_MENU_TITLE],
168 &combat_mode_strings[MAIN_MENU_OPTION1],
180 switch (input_event.type) {
183 selected_index = (selected_index - 1 + 2) % 2;
187 selected_index = (selected_index + 1) % 2;
191 if (selected_index == 0) {
192 new_state = ABILITY_MENU;
193 }
else if (selected_index == 1) {
194 new_state = POTION_MENU;
196 submenu_selected =
true;
200 new_state = COMBAT_EXIT;
201 submenu_selected =
true;
213 int selected_index = 0;
215 internal_combat_state_t new_state = ABILITY_MENU;
216 bool ability_used_or_esc =
false;
218 while (!ability_used_or_esc) {
221 combat_mode_strings[ABILITY_MENU_TITLE],
222 ability_menu_options,
223 player->ability_count,
225 combat_mode_strings[PRESS_C_RETURN]);
234 switch (input_event.type) {
237 selected_index = (selected_index - 1 + player->ability_count) % player->ability_count;
241 selected_index = (selected_index + 1) % player->ability_count;
245 use_ability(player, monster, player->abilities[selected_index]);
248 new_state = EVALUATE_COMBAT;
249 ability_used_or_esc =
true;
253 new_state = COMBAT_MENU;
254 ability_used_or_esc =
true;
265 int selected_index = 0;
267 if (player->potion_count == 0) {
272 internal_combat_state_t new_state = POTION_MENU;
273 bool item_used_or_esc =
false;
275 while (!item_used_or_esc) {
278 combat_mode_strings[POTION_MENU_TITLE],
280 player->potion_count,
282 combat_mode_strings[PRESS_C_RETURN]);
291 switch (input_event.type) {
294 selected_index = (selected_index - 1 + player->potion_count) % player->potion_count;
298 selected_index = (selected_index + 1) % player->potion_count;
302 use_potion(player, monster, player->potion_inventory[selected_index]);
304 new_state = EVALUATE_COMBAT;
307 item_used_or_esc =
true;
311 new_state = COMBAT_MENU;
312 item_used_or_esc =
true;
324 char message[MAX_STRING_LENGTH];
325 if (attacker->type == PLAYER) {
337 if (
roll_hit(attacker->current_stats.dexterity, target->current_stats.dexterity)) {
340 draw_combat_view(combat_view_anchor, player, monster, GOBLIN_PNG, GOBLIN_HEIGHT, sprite);
342 memset(message, 0,
sizeof(message));
343 snprintf(message,
sizeof(message), combat_mode_strings[ATTACK_SUCCESS],
351 draw_combat_view(combat_view_anchor, player, monster, GOBLIN_PNG, GOBLIN_HEIGHT,
false);
353 memset(message, 0,
sizeof(message));
354 snprintf(message,
sizeof(message), combat_mode_strings[ATTACK_MISS],
360 memset(message, 0,
sizeof(message));
361 snprintf(message,
sizeof(message), combat_mode_strings[ATTACK_FAIL],
373 char message[MAX_STRING_LENGTH];
374 snprintf(message,
sizeof(message), combat_mode_strings[POTION_USE],
383 const int random_index = rand() % character->ability_count;
384 return character->abilities[random_index];
388 switch (potion->effectType) {
390 if (potion->value > (character->max_resources.health - character->current_resources.health)) {
391 character->current_resources.health = character->max_resources.health;
393 character->current_resources.health += potion->value;
397 if (potion->value > (character->max_resources.mana - character->current_resources.mana)) {
398 character->current_resources.mana = character->max_resources.mana;
400 character->current_resources.mana += potion->value;
405 if (potion->value > (character->max_resources.stamina - character->current_resources.stamina)) {
406 character->current_resources.stamina = character->max_resources.stamina;
408 character->current_resources.stamina += potion->value;
413 log_msg(ERROR,
"Character",
"Unknown potion effect type: %d", potion->effectType);
420 int* resource = NULL;
422 switch (ability->damage_type) {
424 resource = &attacker->current_resources.stamina;
427 resource = &attacker->current_resources.mana;
431 if (resource != NULL && *resource >= ability->resource_cost) {
432 *resource -= ability->resource_cost;
445 for (
int i = 0; i < MAX_ABILITY_LIMIT; i++) {
446 if (ability_menu_options[i] != NULL) {
447 free(ability_menu_options[i]);
448 ability_menu_options[i] = NULL;
452 for (
int i = 0; i < count; i++) {
453 ability_menu_options[i] = (
char*) malloc(MAX_STRING_LENGTH *
sizeof(
char));
454 if (ability_menu_options[i] == NULL) {
455 for (
int j = 0; j < i; j++) {
456 free(ability_menu_options[j]);
457 ability_menu_options[j] = NULL;
459 log_msg(ERROR,
"Combat Mode",
"Failed to allocate memory for ability menu options.");
464 for (
int i = 0; i < count; i++) {
465 snprintf(ability_menu_options[i], MAX_STRING_LENGTH,
466 combat_mode_strings[ABILITY_FORMAT],
468 abilities[i]->roll_amount,
469 abilities[i]->accuracy,
470 abilities[i]->resource_cost,
483 for (
int i = 0; i < MAX_POTION_LIMIT; i++) {
484 if (potion_menu_options[i] != NULL) {
485 free(potion_menu_options[i]);
486 potion_menu_options[i] = NULL;
490 for (
int i = 0; i < count; i++) {
491 potion_menu_options[i] = (
char*) malloc(MAX_STRING_LENGTH *
sizeof(
char));
492 if (potion_menu_options[i] == NULL) {
493 for (
int j = 0; j < i; j++) {
494 free(potion_menu_options[j]);
495 potion_menu_options[j] = NULL;
497 log_msg(ERROR,
"Combat Mode",
"Failed to allocate memory for potion menu options.");
502 for (
int i = 0; i < count; i++) {
503 snprintf(potion_menu_options[i], MAX_STRING_LENGTH,
504 combat_mode_strings[POTION_FORMAT],
512 if (combat_mode_strings != NULL) {
513 for (
int i = 0; i < MAX_COMBAT_MODE_STRINGS; i++) {
514 if (combat_mode_strings[i] != NULL) {
515 free(combat_mode_strings[i]);
516 combat_mode_strings[i] = NULL;
519 free(combat_mode_strings);
520 combat_mode_strings = NULL;
523 if (ability_menu_options != NULL) {
524 for (
int i = 0; i < MAX_ABILITY_LIMIT; i++) {
525 if (ability_menu_options[i] != NULL) {
526 free(ability_menu_options[i]);
527 ability_menu_options[i] = NULL;
530 free(ability_menu_options);
531 ability_menu_options = NULL;
534 if (potion_menu_options != NULL) {
535 for (
int i = 0; i < MAX_POTION_LIMIT; i++) {
536 if (potion_menu_options[i] != NULL) {
537 free(potion_menu_options[i]);
538 potion_menu_options[i] = NULL;
541 free(potion_menu_options);
542 potion_menu_options = NULL;
Exposes functions for working with abilities.
void remove_potion(character_t *character, potion_t *potion)
Removes a potion from a character's inventory.
Exposes functions for working working with the character.
internal_combat_state_t combat_menu(const character_t *player, const character_t *monster)
Collects the menu options for the ability menu.
ability_t * get_random_ability(const character_t *character)
Get a random ability from the character's abilities.
void collect_ability_menu_options(ability_t *abilities[], int count)
Collects all the options for abilities in the abilities menu for displaying.
void shutdown_combat_mode()
Shuts down the combat mode and frees allocated memory resources.
int init_combat_mode()
Initialize the combat mode.
void invoke_potion_effect(character_t *character, potion_t *potion)
Invoke the effect of a potion on a character.
internal_combat_state_t ability_menu(character_t *player, character_t *monster)
Collects the menu options for the ability menu.
void collect_potion_menu_options(potion_t *potions[], int count)
Collects all the options for potions in the potion menu for displaying.
internal_combat_state_t potion_menu(character_t *player, character_t *monster)
Collects the menu options for the potion menu.
void use_ability(character_t *attacker, character_t *target, const ability_t *ability)
Use an ability on a target character.
void use_potion(character_t *player, const character_t *monster, potion_t *potion)
Use a potion on a target character.
combat_result_t start_combat(character_t *player, character_t *monster)
Starts the loop for combat between the player and the monster.
bool consume_ability_resource(character_t *attacker, const ability_t *ability)
Consumes the mana or stamina resource of the attacker character.
Declares combat mode state machine, including menus and combat operations.
void update_combat_local(void)
Updates the combat mode strings with localized versions.
Exposes functions for working with the localization of the combat mode.
void draw_combat_log(vector2d_t anchor, const char *combat_log_message)
Draws the combat log.
void draw_combat_menu(const vector2d_t anchor, const char *menu_name, char **menu_options, const int menu_option_count, const int selected_index, const char *tail_msg)
Draws the combat menu.
vector2d_t draw_combat_view(const vector2d_t anchor, const character_t *player, const character_t *enemy, const char *enemy_sprite, const int sprite_height, const bool red_enemy_sprite)
Draws the combat view UI.
void draw_game_over(void)
Draws the game over screen.
Exposes functions for outputing to the screen while in the combat mode.
Defines common macros, types, and global variables for color schemes and utilities.
const char * dice_size_to_string(const dice_size_t size)
Converts a dice size enum to a string representation.
bool roll_hit(const int attacker_dex, const int defender_dex)
Rolls a D20 to determine if an attack hits.
int deal_damage(character_t *character, damage_type_t damage_type, const int damage)
Deals damage to a character based on the damage type and amount.
const char * damage_type_to_string(const damage_type_t type)
Converts a damage type enum to a string representation.
int roll_damage(const ability_t *ability)
Rolls damage based on the ability's roll amount and dice size.
Declares core game states, global database connection, and main game control functions.
Exposes functions for the IO-Handler.
void level_up(character_t *player)
Handles the level-up process for a character.
int calculate_xp_for_next_level(int level)
Calculates the XP required for the next level.
Exposes functions for working with the character.
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.
bool render_frame(void)
Render the current frame.
void clear_screen(void)
Clear the screen.
Exposes functions for outputting to the console.
const char * potion_type_to_string(potion_type_t type)
Converts a potion type to a string representation.
2-dimensional vector struct