/* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define mvwclrtobot(win, y, x) (wmove((win), (y), (x)) == ERR ? ERR : wclrtobot((win))) #define NUM_FIELDS 7 void draw_output(WINDOW* win, int race, int sex, int spec, int sign, int attrs[ATTRIBUTE_COUNT], int skills[SKILL_COUNT]); enum FIELDS { RACE, SEX, SPEC, ATTR, SKILL_MAJ, SKILL_MIN, SIGN }; typedef struct mw_menu { MENU *m; WINDOW *w; PANEL *p; int *selections; int num_selections; int max_selections; } mw_menu; int main() { int ch, x, y; WINDOW *win_input, *win_output; PANEL *panel_input, *panel_output; initscr(); cbreak(); noecho(); keypad(stdscr, 1); curs_set(0); refresh(); win_input = newwin(8, COLS, 0, 0); box(win_input, 0, 0); panel_input = new_panel(win_input); win_output = newwin(LINES-8, COLS, 8, 0); panel_output = new_panel(win_output); int out_skills[SKILL_COUNT] = {0}; int out_attrs[ATTRIBUTE_COUNT] = {0}; int input_col_width = (COLS - 2) / 5; int input_col_height = 6; WINDOW *field_windows[NUM_FIELDS]; field_windows[0] = newwin(input_col_height/2, input_col_width, 1, 1 ); field_windows[1] = newwin(input_col_height/2, input_col_width, input_col_height/2+1, 1 ); field_windows[2] = newwin(input_col_height/2, input_col_width, 1, input_col_width+1); field_windows[3] = newwin(input_col_height/2, input_col_width, input_col_height/2+1, input_col_width+1); field_windows[4] = newwin(input_col_height, input_col_width, 1, input_col_width*2+1); field_windows[5] = newwin(input_col_height, input_col_width, 1, input_col_width*3+1); field_windows[6] = newwin(input_col_height, input_col_width, 1, input_col_width*4+1); PANEL *field_panels[NUM_FIELDS]; for (int i = 0; i < NUM_FIELDS; ++i) { field_panels[i] = new_panel(field_windows[i]); } const char *field_headers[] = { "Race", "Sex", "Specializ.", "Favored Attr.", "Major Skills", "Minor Skills", "Birthsign" }; const char **field_strings[] = { MW_RACE_STR, MW_SEX_STR, MW_SPECIALIZATION_STR, MW_ATTRIBUTE_STR, MW_SKILL_STR, MW_SKILL_STR, MW_BIRTHSIGN_STR }; const int field_items[] = { RACE_COUNT, SEX_COUNT, SPECIALIZATION_COUNT, ATTRIBUTE_COUNT, SKILL_COUNT, SKILL_COUNT, BIRTHSIGN_COUNT }; const int field_max_selections[] = { 1, 0, 1, 2, 5, 5, 1 }; int selected_col = 0; int selected_row = 0; int selected_field = 0; WINDOW* selected_field_window; for(int i = 0; i < 7; ++i) { WINDOW* w = field_windows[i]; wattron(w, A_BOLD); mvwaddstr(w, 0, 0, field_headers[i]); wattroff(w, A_BOLD); } mvwchgat(field_windows[selected_field], 0, 0, -1, A_BOLD | A_REVERSE, 0, NULL); mw_menu field_menus[NUM_FIELDS] = {0}; for (int i = 0; i < NUM_FIELDS; ++i) { int x, y; field_menus[i].num_selections = 0; field_menus[i].max_selections = field_max_selections[i]; field_menus[i].selections = malloc(field_menus[i].max_selections * sizeof(*field_menus[0].selections)); for (int j = 0; j < field_menus[i].max_selections; ++j) { field_menus[i].selections[j] = -1; } if (i == SEX) continue; ITEM ** tmp_items = calloc(field_items[i] + 1, sizeof(ITEM*)); for (int j = 0; j < field_items[i]; ++j) { tmp_items[j] = new_item(field_strings[i][j], field_strings[i][j]); } tmp_items[field_items[i]] = NULL; field_menus[i].m = new_menu(tmp_items); if(i == SKILL_MIN || i == SKILL_MAJ) { set_menu_format(field_menus[i].m, 9, 3); } if(field_menus[i].max_selections > 1) { menu_opts_off(field_menus[i].m, O_ONEVALUE); } else { field_menus[i].num_selections = 1; field_menus[i].selections[0] = 0; } menu_opts_off(field_menus[i].m, O_SHOWDESC); menu_opts_off(field_menus[i].m, O_ROWMAJOR); set_menu_mark(field_menus[i].m, "*"); scale_menu(field_menus[i].m, &y, &x); y+=2; x+=2; field_menus[i].w = newwin(y, x, (LINES-y)/2, (COLS-x)/2); set_menu_sub(field_menus[i].m, derwin(field_menus[i].w, y-2, x-2, 1, 1)); post_menu(field_menus[i].m); field_menus[i].p = new_panel(field_menus[i].w); hide_panel(field_menus[i].p); box(field_menus[i].w, 0, 0); } field_menus[RACE].selections[0] = DARK_ELF; field_menus[SPEC].selections[0] = COMBAT; field_menus[SIGN].selections[0] = APPRENTICE; field_menus[SEX].selections[0] = MALE; mvwaddstr(field_windows[RACE], 1, 0, field_strings[RACE][field_menus[RACE].selections[0]]); mvwaddstr(field_windows[SEX], 1, 0, field_strings[SEX][field_menus[SEX].selections[0]]); mvwaddstr(field_windows[SPEC], 1, 0, field_strings[SPEC][field_menus[SPEC].selections[0]]); mvwaddstr(field_windows[SIGN], 1, 0, field_strings[SIGN][field_menus[SEX].selections[0]]); draw_output(win_output, field_menus[RACE].selections[0], field_menus[SEX].selections[0], field_menus[SPEC].selections[0], field_menus[SIGN].selections[0], out_attrs, out_skills); update_panels(); doupdate(); int in_field_menu = -1; int selection_changed = 0; selected_field_window = field_windows[selected_field]; mw_menu *cur_menu; ITEM **cur_menu_items; int *other_menu_selected; while ((ch = getch()) != KEY_F(1)) { if (in_field_menu == -1) { switch(ch) { case KEY_LEFT: selected_col = (selected_col + 4) % 5; selection_changed = 1; break; case KEY_RIGHT: selected_col = (selected_col + 1) % 5; selection_changed = 1; break; case KEY_UP: case KEY_DOWN: selected_row = !selected_row; selection_changed = 1; break; case ' ': if (selected_field == SEX) { field_menus[SEX].selections[0] = !field_menus[SEX].selections[0]; mvwclrtobot(selected_field_window, 1, 0); waddstr(selected_field_window, field_strings[SEX][field_menus[SEX].selections[0]]); break; } cur_menu = &field_menus[selected_field]; other_menu_selected = NULL; if (selected_field == SKILL_MAJ) { other_menu_selected = field_menus[SKILL_MIN].selections; } else if (selected_field == SKILL_MIN) { other_menu_selected = field_menus[SKILL_MAJ].selections; } cur_menu_items = menu_items(cur_menu->m); if (other_menu_selected != NULL) { for (int i = 0; i < field_items[selected_field]; ++i) { item_opts_on(cur_menu_items[i], O_SELECTABLE); } for (int i = 0; i < cur_menu->max_selections && other_menu_selected[i] != -1; ++i) { item_opts_off(cur_menu_items[other_menu_selected[i]], O_SELECTABLE); } } show_panel(cur_menu->p); in_field_menu = selected_field; break; } if (selection_changed) { mvwchgat(selected_field_window, 0, 0, -1, A_BOLD, 0, NULL); if (selected_col < 2) { selected_field = selected_col * 2 + selected_row; } else { selected_field = selected_col + 2; } selected_field_window = field_windows[selected_field]; mvwchgat(selected_field_window, 0, 0, -1, A_BOLD | A_REVERSE, 0, NULL); selection_changed = 0; } } else { switch(ch) { case KEY_UP: menu_driver(cur_menu->m, REQ_UP_ITEM); break; case KEY_DOWN: menu_driver(cur_menu->m, REQ_DOWN_ITEM); break; case KEY_LEFT: menu_driver(cur_menu->m, REQ_LEFT_ITEM); break; case KEY_RIGHT: menu_driver(cur_menu->m, REQ_RIGHT_ITEM); break; case ' ': if(cur_menu->max_selections > 1) { ITEM* cur_item = current_item(cur_menu->m); if (item_opts(cur_item) & O_SELECTABLE) { menu_driver(cur_menu->m, REQ_TOGGLE_ITEM); if (item_value(cur_item)) { if(cur_menu->num_selections == cur_menu->max_selections) { menu_driver(cur_menu->m, REQ_TOGGLE_ITEM); } else { cur_menu->num_selections += 1; } } else { cur_menu->num_selections -= 1; } } break; } case '\n': if (cur_menu->max_selections > 1) { for (int i = 0, j = 0; i < field_items[selected_field]; ++i){ if(item_value(cur_menu_items[i])) { cur_menu->selections[j++] = i; } } for (int j = cur_menu->num_selections; j < cur_menu->max_selections; ++j) { cur_menu->selections[j] = -1; } } else { cur_menu->selections[0] = item_index(current_item(cur_menu->m)); } mvwclrtobot(selected_field_window, 1, 0); for (int i = 0; i < cur_menu->num_selections; ++i) { mvwaddstr(selected_field_window, i+1, 0, field_strings[selected_field][cur_menu->selections[i]]); } for (int i = 0; i < SKILL_COUNT; ++i) { out_skills[i] = 0; } for (int i = 0; i < field_menus[SKILL_MIN].num_selections; ++i) { out_skills[field_menus[SKILL_MIN].selections[i]] = 1; } for (int i = 0; i < field_menus[SKILL_MAJ].num_selections; ++i) { out_skills[field_menus[SKILL_MAJ].selections[i]] = 2; } for (int i = 0; i < ATTRIBUTE_COUNT; ++i) { out_attrs[i] = 0; } for (int i = 0; i < field_menus[ATTR].num_selections; ++i) { out_attrs[field_menus[ATTR].selections[i]] = 1; } draw_output(win_output, field_menus[RACE].selections[0], field_menus[SEX].selections[0], field_menus[SPEC].selections[0], field_menus[SIGN].selections[0], out_attrs, out_skills); hide_panel(cur_menu->p); in_field_menu = -1; break; } } update_panels(); doupdate(); } endwin(); return 0; } void draw_output(WINDOW* win, int race, int sex, int spec, int sign, int attrs[ATTRIBUTE_COUNT], int skills[SKILL_COUNT]) { int y, x; getmaxyx(win, y, x); int col_width = x / 5; int max_row = 15; int final_skills[SKILL_COUNT]; for(int i = 0; i < SKILL_COUNT; ++i) { int n = 5; if (skills[i] == 1) n += 10; if (skills[i] == 2) n += 25; if (i / 9 == spec) n += 5; n += MW_RACE_SKILLS[race][i]; final_skills[i] = n; } int final_attrs[ATTRIBUTE_COUNT]; for(int i = 0; i < ATTRIBUTE_COUNT; ++i) { int n = 40; n += MW_RACE_ATTRS[race][sex][i]; if (attrs[i]) n += 10; final_attrs[i] = n; } werase(win); wattron(win, A_BOLD); mvwaddstr(win, 0, 0, "Attributes"); mvwaddstr(win, 0, col_width, "Major Skills"); mvwaddstr(win, 7, col_width, "Minor Skills"); mvwaddstr(win, 0, col_width * 2, "Misc Skills"); wattroff(win, A_BOLD); if (sign == STEED) { final_attrs[SPEED] += 25; } else if (sign == LOVER) { final_attrs[AGILITY] += 25; } int final_health = (final_attrs[STRENGTH]+final_attrs[ENDURANCE])/2; int final_magicka = final_attrs[INTELLIGENCE] * (1 + MW_RACE_MAGICKA_BONUS[race] + MW_BIRTHSIGN_MAGICKA_BONUS[sign]); int final_fatigue = final_attrs[STRENGTH] + final_attrs[WILLPOWER] + final_attrs[AGILITY] + final_attrs[ENDURANCE]; if (sign == LADY) { final_attrs[PERSONALITY] += 25; final_attrs[ENDURANCE] += 25; } int final_abilities_count = 0, final_powers_count = 0, final_spells_count = 0; int final_abilities[ABILITY_COUNT] = {0}; for (int i = 0; i < ABILITY_COUNT; ++i) { final_abilities[i] = MW_RACE_ABILITIES[race][i] || MW_BIRTHSIGN_ABILITIES[sign][i]; if (final_abilities[i]) final_abilities_count++; } int final_powers[POWER_COUNT] = {0}; for (int i = 0; i < POWER_COUNT; ++i) { final_powers[i] = MW_RACE_POWERS[race][i] || MW_BIRTHSIGN_POWERS[sign][i]; if (final_powers[i]) final_powers_count++; } int final_spells[SPELL_COUNT] = {0}; for (int i = 0; i < SPELL_COUNT; ++i) { final_spells[i] = MW_RACE_SPELLS[race][i] || MW_BIRTHSIGN_SPELLS[sign][i]; } for (int i = 0; i < STARTING_SPELL_COUNT; ++i) { if(skills[MW_STARTING_SPELL[i][1]] == 0) continue; int sum = final_skills[MW_STARTING_SPELL[i][1]]*2 + final_attrs[WILLPOWER]/5 + final_attrs[LUCK]/10; if(sum >= MW_STARTING_SPELL[i][2]) final_spells[MW_STARTING_SPELL[i][0]] = 1; } for (int i = 0; i < SPELL_COUNT; ++i) { if (final_spells[i]) final_spells_count++; } mvwprintw(win, 1, 0, "%-11s%4d", "Health", final_health); mvwprintw(win, 2, 0, "%-11s%4d", "Magicka", final_magicka); mvwprintw(win, 3, 0, "%-11s%4d", "Fatigue", final_fatigue); for (int i = 0; i < ATTRIBUTE_COUNT; ++i) { mvwprintw(win, i + 5, 0, "%-12s%3d", MW_ATTRIBUTE_STR[i], final_attrs[i]); } int dyn_row = 15; if (final_powers_count != 0) { for (int i = POWER_COUNT-1; i >= 0; --i) { if (final_powers[i]) { mvwaddstr(win, dyn_row, col_width*3, MW_POWER_STR[i]); dyn_row -= 1; } } wattron(win, A_BOLD); mvwaddstr(win, dyn_row, col_width*3, "Powers"); wattroff(win, A_BOLD); dyn_row -= 2; } if (final_abilities_count != 0) { for (int i = ABILITY_COUNT-1; i >= 0; --i) { if (final_abilities[i]) { mvwaddstr(win, dyn_row, col_width*3, MW_ABILITY_STR[i]); dyn_row -= 1; } } wattron(win, A_BOLD); mvwaddstr(win, dyn_row, col_width*3, "Abilities"); wattroff(win, A_BOLD); dyn_row -= 2; } int spell_row = max_row; if (final_spells_count != 0) { for (int i = SPELL_COUNT-1; i >= 0; --i) { if (final_spells[i]) { mvwaddstr(win, spell_row, col_width*4, MW_SPELL_STR[i]); spell_row -= 1; } } wattron(win, A_BOLD); mvwaddstr(win, spell_row, col_width*4, "Spells"); wattroff(win, A_BOLD); spell_row -= 2; } int skill_min_i = 0; int skill_maj_i = 0; int skill_msc_i = 0; int skill_msc_overflow = 0; for (int i = 0; i < SKILL_COUNT; ++i) { int row; int col; if (skills[i] == 2) { row = ++skill_maj_i; col = col_width; } else if (skills[i] == 1) { row = ++skill_min_i + 7; col = col_width; } else if (!skill_msc_overflow) { int row_mod = max_row; row = (skill_msc_i % row_mod) + 1; col = col_width * (skill_msc_i / row_mod + 2); if (col >= col_width * 3 && row >= dyn_row) { skill_msc_overflow = 1; continue; } skill_msc_i += 1; } mvwprintw(win, row, col, "%-12s%3d", MW_SKILL_STR[i], final_skills[i]); } }