/* * Copyright (C) 2002-2007 The Warp Rogue Team * Part of the Warp Rogue Project * * This software is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License. * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY. * * See the license.txt file for more details. */ /* * Module Name: CharacterAdvancement * Description: - */ #define Uses_Ui #define Uses_Stats #define Uses_Perks #define Uses_Psychic #define Uses_Character #define Uses_Util #define Uses_Career #include "mheader.h" #include "charadv.h" static MENU * increase_stat_menu_create(const CHARACTER *); static MENU * buy_perk_menu_create(const CHARACTER *); static MENU * perk_from_tome_menu_create(const CHARACTER *); static MENU * learn_psy_power_menu_create(const CHARACTER *); static void follow_career_path(CHARACTER *); static MENU * follow_career_path_menu_create(const CHARACTER *); static MENU * new_career_path_menu_create(void); /* * gives the passed amount of EPs to the passed character */ void give_ep(CHARACTER *character, EXPERIENCE_POINTS ep) { if (ep <= 0 || character->ep_total == EP_LIMIT) return; if (ep > EP_LIMIT) ep = EP_LIMIT; if (character->ep_total + ep > EP_LIMIT) { ep = EP_LIMIT - character->ep_total; } character->ep += ep; character->ep_total += ep; } /* * the character advancement screen */ void character_advancement_screen(CHARACTER *character) { LIST *items; MENU *menu; /* create advancement menu */ items = list_new(); list_add(items, "Increase stat"); list_add(items, "Buy perk"); list_add(items, "Learn psychic power"); list_add(items, "Change career (follow path)"); list_add(items, "Change career (new path)"); menu = menu_create(items); while (true) { command_bar_set(4, CM_UP, CM_DOWN, CM_OK, CM_EXIT); render_character_advancement_screen(character); update_screen(); character_advancement_screen_menu(menu); if (menu->entered_command == CM_EXIT) { break; } if (character->career == CAREER_NIL) { continue; } switch (menu->highlighted) { case 0: increase_stat(character, false); break; case 1: new_perk(character, false); break; case 2: if (character->perk[PK_PSYCHIC] && n_psy_powers(character) == 0) { learn_psy_power(character, true); } else { learn_psy_power(character, false); } break; case 3: follow_career_path(character); break; case 4: new_career_path(character, false); break; } } menu_free(menu); } /* * the new career path screen */ void new_career_path(CHARACTER *character, bool initial_career) { MENU *menu; if (!initial_career && (!career_completed(character) || character->ep < EP_COST_CHANGE_CAREER_NEW_PATH)) { command_bar_set(1, CM_EXIT); render_new_career_path_screen(character, initial_career); update_screen(); command_bar_get_command(); return; } menu = new_career_path_menu_create(); while (true) { CAREER_INDEX career_index; const char *career_name; CAREER *career; if (initial_career) { command_bar_set(4, CM_UP, CM_DOWN, CM_INFO, CM_OK ); } else { command_bar_set(5, CM_UP, CM_DOWN, CM_INFO, CM_OK, CM_EXIT ); } render_new_career_path_screen(character, initial_career); update_screen(); new_career_path_screen_menu(menu, initial_career); if (menu->entered_command == CM_EXIT) { break; } career_name = (const char *)list_data_at(menu->items, menu->highlighted ); career_index = name_to_career_index(career_name); career = get_career_pointer(career_index); if (menu->entered_command == CM_INFO) { career_screen(career); continue; } else if (menu->entered_command == CM_OK) { career_set(character, career_index); if (!initial_career) { character->ep -= EP_COST_CHANGE_CAREER_NEW_PATH; message(SID_CHANGE_CAREER_NEW_PATH, "Career changed!" ); } break; } } if (menu != NULL) { menu_free(menu); } } /* * the increase stat screen */ void increase_stat(CHARACTER *character, bool free_advance) { MENU *menu; COMMAND entered_command; menu = increase_stat_menu_create(character); do { STAT stat; const char *stat_name; if (menu == NULL || (!free_advance && character->ep < EP_COST_INCREASE_STAT) ) { command_bar_set(1, CM_EXIT); render_increase_stat_screen(character, menu, free_advance ); update_screen(); command_bar_get_command(); break; } if (free_advance) { command_bar_set(3, CM_UP, CM_DOWN, CM_OK); } else { command_bar_set(4, CM_UP, CM_DOWN, CM_OK, CM_EXIT); } render_increase_stat_screen(character, menu, free_advance ); increase_stat_screen_menu(menu, free_advance); stat_name = list_data_at(menu->items, menu->highlighted); stat = name_to_stat(stat_name, false); entered_command = menu->entered_command; if (entered_command == CM_OK) { stat_advance(character, stat); message(SID_INCREASE_STAT, "%s stat increased! ", stat_long_name(stat) ); if (free_advance) { break; } character->ep -= EP_COST_INCREASE_STAT; menu_free(menu); menu = increase_stat_menu_create(character); entered_command = CM_NIL; } } while (entered_command != CM_EXIT); if (menu != NULL) { menu_free(menu); } } /* * the new perk screen */ bool new_perk(CHARACTER *character, bool perk_from_tome) { MENU *menu; bool perk_gained; perk_gained = false; while (true) { const char *chosen_perk; PERK perk; if (perk_from_tome) { menu = perk_from_tome_menu_create(character); } else { menu = buy_perk_menu_create(character); } if (menu == NULL || (character->ep < EP_COST_BUY_PERK && !perk_from_tome) || character_n_perks(character) >= MAX_CHARACTER_PERKS ) { command_bar_set(1, CM_EXIT); render_new_perk_screen(character, menu, perk_from_tome ); update_screen(); command_bar_get_command(); break; } command_bar_set(5, CM_UP, CM_DOWN, CM_INFO, CM_OK, CM_EXIT); render_new_perk_screen(character, menu, perk_from_tome); update_screen(); new_perk_screen_menu(menu, perk_from_tome); if (menu->entered_command == CM_EXIT) { break; } chosen_perk = (const char *)list_data_at(menu->items, menu->highlighted ); perk = name_to_perk(chosen_perk); if (menu->entered_command == CM_OK) { if (!perk_from_tome) { character->ep -= EP_COST_BUY_PERK; } give_perk(character, perk); perk_gained = true; message(SID_NEW_PERK, "%s perk gained! ", perk_name(perk) ); if (perk == PK_PSYCHIC) { learn_psy_power(character, true); } if (perk_from_tome) { break; } } else if (menu->entered_command == CM_INFO) { perk_screen(perk); } menu_free(menu); } if (menu != NULL) { menu_free(menu); } return perk_gained; } /* * the learn psychic power screen */ bool learn_psy_power(CHARACTER *character, bool free_power) { MENU *menu; bool power_learned; power_learned = false; while (true) { PSY_POWER power; const char *power_name; menu = learn_psy_power_menu_create(character); if (menu == NULL || !character->perk[PK_PSYCHIC] || (!free_power && character->ep < EP_COST_LEARN_PSY_POWER) || n_psy_powers(character) >= MAX_CHARACTER_PSY_POWERS) { command_bar_set(1, CM_EXIT); render_learn_psy_power_screen(character, menu, free_power ); update_screen(); command_bar_get_command(); break; } command_bar_set(5, CM_UP, CM_DOWN, CM_INFO, CM_OK, CM_EXIT); render_learn_psy_power_screen(character, menu, free_power); update_screen(); learn_psy_power_screen_menu(menu, free_power); if (menu->entered_command == CM_EXIT) { break; } power_name = (const char *)list_data_at(menu->items, menu->highlighted ); power = name_to_psy_power(power_name); if (menu->entered_command == CM_OK) { if (!free_power) { character->ep -= EP_COST_LEARN_PSY_POWER; } character->psy_power[power] = true; message(SID_LEARN_PSY_POWER, "%s learned! ", psy_power_name(power) ); power_learned = true; if (free_power) { break; } } else if (menu->entered_command == CM_INFO) { psy_power_screen(power); } menu_free(menu); } if (menu != NULL) { menu_free(menu); } return power_learned; } /* * creates a increase stat menu */ static MENU * increase_stat_menu_create(const CHARACTER *character) { MENU *menu; LIST *items; STAT i; CAREER *career; career = get_career_pointer(character->career); items = list_new(); for (i = 0; i < MAX_STATS; i++) { if (character->stat[i].advance >= career->max_stat_advance[i]) { continue; } list_add(items, (void *)stat_long_name(i)); } if (items->n_nodes == 0) { list_free(items); return NULL; } menu = menu_create(items); return menu; } /* * creates the buy perk menu */ static MENU * buy_perk_menu_create(const CHARACTER *character) { LIST *items; MENU *menu; CAREER *career; PERK i; career = get_career_pointer(character->career); items = list_new(); for (i = 0; i < MAX_PERKS; i++) { if (!character->perk[i] && career->perk[i]) { list_add(items, (void *)perk_name(i)); } } if (items->n_nodes == 0) { list_free(items); return NULL; } menu = menu_create(items); return menu; } /* * creates the perk from tome menu */ static MENU * perk_from_tome_menu_create(const CHARACTER *character) { LIST *items; MENU *menu; PERK i; items = list_new(); for (i = 0; i < MAX_PERKS; i++) { if (!character->perk[i] && perk_in_tome(i)) { list_add(items, (void *)perk_name(i)); } } if (items->n_nodes == 0) { list_free(items); return NULL; } menu = menu_create(items); return menu; } /* * creates the learn psychic power menu */ static MENU * learn_psy_power_menu_create(const CHARACTER *character) { LIST *items; MENU *menu; PSY_POWER i; items = list_new(); for (i = 0; i < MAX_PSY_POWERS; i++) { if (!character->psy_power[i] && psy_power_implemented(i)) { list_add(items, (void *)psy_power_name(i)); } } if (items->n_nodes == 0) { list_free(items); return NULL; } menu = menu_create(items); return menu; } /* * the follow career path screen */ static void follow_career_path(CHARACTER *character) { MENU *menu; while (true) { CAREER_INDEX career_index; const char *career_name; CAREER *career; menu = follow_career_path_menu_create(character); if (!career_completed(character) || menu == NULL || character->ep < EP_COST_CHANGE_CAREER_FOLLOW_PATH) { command_bar_set(1, CM_EXIT); render_follow_career_path_screen(character, menu); update_screen(); command_bar_get_command(); break; } command_bar_set(5, CM_UP, CM_DOWN, CM_INFO, CM_OK, CM_EXIT); render_follow_career_path_screen(character, menu); update_screen(); follow_career_path_screen_menu(menu); if (menu->entered_command == CM_EXIT) { break; } career_name = (const char *)list_data_at( menu->items, menu->highlighted ); career_index = name_to_career_index(career_name); career = get_career_pointer(career_index); if (menu->entered_command == CM_INFO) { career_screen(career); } else if (menu->entered_command == CM_OK) { character->ep -= EP_COST_CHANGE_CAREER_FOLLOW_PATH; career_set(character, career_index); message(SID_CHANGE_CAREER_FOLLOW_PATH, "Career changed!" ); break; } menu_free(menu); } if (menu != NULL) { menu_free(menu); } } /* * creates the follow career path menu */ static MENU * follow_career_path_menu_create(const CHARACTER *character) { LIST *items; MENU *menu; CAREER *career; CAREER_INDEX i; career = get_career_pointer(character->career); items = list_new(); for (i = 0; i < MAX_CAREER_EXITS; i++) { if (is_empty_string(career->exit[i])) { break; } list_add(items, career->exit[i]); } if (items->n_nodes == 0) { list_free(items); return NULL; } menu = menu_create(items); return menu; } /* * creates the new career path menu */ static MENU * new_career_path_menu_create(void) { LIST *items; MENU *menu; CAREER_INDEX i; N_CAREERS n_careers; n_careers = get_n_careers(); items = list_new(); for (i = 0; i < n_careers; i++) { CAREER *career; career = get_career_pointer(i); if (career->type != CAREER_TYPE_BASIC) { continue; } list_add(items, (void *)career->name); } menu = menu_create(items); return menu; }