| 643 | | |
|---|
| 644 | | |
|---|
| 645 | | /* |
|---|
| 646 | | * Generic "get choice from menu" function |
|---|
| 647 | | */ |
|---|
| 648 | | static int get_player_choice(birth_menu *choices, int num, int def, |
|---|
| 649 | | int col, int wid, byte *select, |
|---|
| 650 | | cptr helpfile, void (*hook)(birth_menu)) |
|---|
| 651 | | { |
|---|
| 652 | | int top = 0, cur = def; |
|---|
| 653 | | int i, dir; |
|---|
| 654 | | char c; |
|---|
| 655 | | char buf[80]; |
|---|
| 656 | | bool done = FALSE; |
|---|
| 657 | | int hgt; |
|---|
| 658 | | byte attr; |
|---|
| 659 | | |
|---|
| 660 | | /* Autoselect if able */ |
|---|
| 661 | | if (num == 1) done = TRUE; |
|---|
| 662 | | |
|---|
| 663 | | /* Clear */ |
|---|
| 664 | | for (i = TABLE_ROW; i < Term->hgt; i++) |
|---|
| 665 | | { |
|---|
| 666 | | /* Clear */ |
|---|
| 667 | | Term_erase(col, i, Term->wid - wid); |
|---|
| 668 | | } |
|---|
| 669 | | |
|---|
| 670 | | /* Choose */ |
|---|
| 671 | | while (TRUE) |
|---|
| 672 | | { |
|---|
| 673 | | hgt = Term->hgt - TABLE_ROW - 1; |
|---|
| 674 | | |
|---|
| 675 | | /* Redraw the list */ |
|---|
| 676 | | for (i = 0; ((i + top < num) && (i <= hgt)); i++) |
|---|
| 677 | | { |
|---|
| 678 | | if (i + top < 26) |
|---|
| 679 | | { |
|---|
| 680 | | strnfmt(buf, sizeof(buf), "%c) %s", I2A(i + top), |
|---|
| 681 | | choices[i + top].name); |
|---|
| 682 | | } |
|---|
| 683 | | else |
|---|
| 684 | | { |
|---|
| 685 | | /* ToDo: Fix the ASCII dependency */ |
|---|
| 686 | | strnfmt(buf, sizeof(buf), "%c) %s", 'A' + (i + top - 26), |
|---|
| 687 | | choices[i + top].name); |
|---|
| 688 | | } |
|---|
| 689 | | |
|---|
| 690 | | /* Clear */ |
|---|
| 691 | | Term_erase(col, i + TABLE_ROW, wid); |
|---|
| 692 | | |
|---|
| 693 | | /* Display */ |
|---|
| 694 | | if (i == (cur - top)) |
|---|
| 695 | | { |
|---|
| 696 | | /* Highlight the current selection */ |
|---|
| 697 | | if (choices[i + top].grayed) attr = TERM_BLUE; |
|---|
| 698 | | else attr = TERM_L_BLUE; |
|---|
| 699 | | } |
|---|
| 700 | | else |
|---|
| 701 | | { |
|---|
| 702 | | if (choices[i + top].grayed) attr = TERM_SLATE; |
|---|
| 703 | | else attr = TERM_WHITE; |
|---|
| 704 | | } |
|---|
| 705 | | |
|---|
| 706 | | Term_putstr(col, i + TABLE_ROW, wid, attr, buf); |
|---|
| 707 | | } |
|---|
| 708 | | |
|---|
| 709 | | if (done) |
|---|
| 710 | | { |
|---|
| 711 | | /* Set the value */ |
|---|
| 712 | | *select = cur; |
|---|
| 713 | | |
|---|
| 714 | | /* Success */ |
|---|
| 715 | | return BIRTH_SUCCESS; |
|---|
| 716 | | } |
|---|
| 717 | | |
|---|
| 718 | | /* Display auxiliary information if any is available. */ |
|---|
| 719 | | if (hook) hook(choices[cur]); |
|---|
| 720 | | |
|---|
| 721 | | /* Move the cursor */ |
|---|
| 722 | | put_str("", TABLE_ROW + cur - top, col); |
|---|
| 723 | | |
|---|
| 724 | | c = inkey(); |
|---|
| 725 | | |
|---|
| 726 | | /* Exit the game */ |
|---|
| 727 | | if (c == KTRL('X')) quit(NULL); |
|---|
| 728 | | |
|---|
| 729 | | /* Make a choice */ |
|---|
| 730 | | if ((c == '\n') || (c == '\r')) |
|---|
| 731 | | { |
|---|
| 732 | | /* Set the value */ |
|---|
| 733 | | *select = cur; |
|---|
| 734 | | |
|---|
| 735 | | /* Success */ |
|---|
| 736 | | return BIRTH_SUCCESS; |
|---|
| 737 | | } |
|---|
| 738 | | |
|---|
| 739 | | /* Random choice */ |
|---|
| 740 | | if (c == '*') |
|---|
| 741 | | { |
|---|
| 742 | | /* Ensure legal choice */ |
|---|
| 743 | | do { cur = rand_int(num); } while (choices[cur].grayed); |
|---|
| 744 | | |
|---|
| 745 | | /* Done */ |
|---|
| 746 | | done = TRUE; |
|---|
| 747 | | } |
|---|
| 748 | | |
|---|
| 749 | | /* Alphabetic choice */ |
|---|
| 750 | | else if (isalpha((unsigned char)c)) |
|---|
| 751 | | { |
|---|
| 752 | | int choice; |
|---|
| 753 | | |
|---|
| 754 | | if (islower((unsigned char)c)) choice = A2I(c); |
|---|
| 755 | | else choice = c - 'A' + 26; |
|---|
| 756 | | |
|---|
| 757 | | /* Validate input */ |
|---|
| 758 | | if ((choice > -1) && (choice < num)) |
|---|
| 759 | | { |
|---|
| 760 | | cur = choice; |
|---|
| 761 | | |
|---|
| 762 | | /* Done */ |
|---|
| 763 | | done = TRUE; |
|---|
| 764 | | } |
|---|
| 765 | | else |
|---|
| 766 | | { |
|---|
| 767 | | bell("Illegal response to question!"); |
|---|
| 768 | | } |
|---|
| 769 | | } |
|---|
| 770 | | |
|---|
| 771 | | /* Move */ |
|---|
| 772 | | else if (isdigit((unsigned char)c) || isarrow(c)) |
|---|
| 773 | | { |
|---|
| 774 | | /* Get a direction from the key */ |
|---|
| 775 | | dir = target_dir(c); |
|---|
| 776 | | |
|---|
| 777 | | /* Going up? */ |
|---|
| 778 | | if (dir == 8) |
|---|
| 779 | | { |
|---|
| 780 | | /* Move selection */ |
|---|
| 781 | | if (cur != 0) cur--; |
|---|
| 782 | | |
|---|
| 783 | | /* Scroll up */ |
|---|
| 784 | | if ((top > 0) && ((cur - top) < 4)) top--; |
|---|
| 785 | | } |
|---|
| 786 | | |
|---|
| 787 | | /* Going down? */ |
|---|
| 788 | | else if (dir == 2) |
|---|
| 789 | | { |
|---|
| 790 | | /* Move selection */ |
|---|
| 791 | | if (cur != (num - 1)) cur++; |
|---|
| 792 | | |
|---|
| 793 | | /* Scroll down */ |
|---|
| 794 | | if ((top + hgt < (num - 1)) && ((top + hgt - cur) < 4)) top++; |
|---|
| 795 | | } |
|---|
| 796 | | |
|---|
| 797 | | /* Going back? */ |
|---|
| 798 | | else if (dir == 4) |
|---|
| 799 | | { |
|---|
| 800 | | /* Save the current value (for later) */ |
|---|
| 801 | | *select = cur; |
|---|
| 802 | | |
|---|
| 803 | | /* Return */ |
|---|
| 804 | | return BIRTH_BACK; |
|---|
| 805 | | } |
|---|
| 806 | | |
|---|
| 807 | | /* Going forward acts as pressing enter */ |
|---|
| 808 | | else if (dir == 6) |
|---|
| 809 | | { |
|---|
| 810 | | /* Set the value */ |
|---|
| 811 | | *select = cur; |
|---|
| 812 | | |
|---|
| 813 | | /* Success */ |
|---|
| 814 | | return BIRTH_SUCCESS; |
|---|
| 815 | | } |
|---|
| 816 | | } |
|---|
| 817 | | |
|---|
| 818 | | /* Hack - go back */ |
|---|
| 819 | | else if (c == ESCAPE) return BIRTH_RESTART; |
|---|
| 820 | | |
|---|
| 821 | | /* Help */ |
|---|
| 822 | | else if (c == '?') |
|---|
| 823 | | { |
|---|
| 824 | | strnfmt(buf, sizeof(buf), "%s#%s", helpfile, choices[cur].name); |
|---|
| 825 | | |
|---|
| 826 | | screen_save(); |
|---|
| 827 | | (void)show_file(buf, NULL, 0, 0); |
|---|
| 828 | | screen_load(); |
|---|
| 829 | | } |
|---|
| 830 | | |
|---|
| 831 | | /* Options */ |
|---|
| 832 | | else if (c == '=') |
|---|
| 833 | | { |
|---|
| 834 | | do_cmd_options(); |
|---|
| 835 | | } |
|---|
| 836 | | |
|---|
| 837 | | /* Invalid input */ |
|---|
| 838 | | else bell("Illegal response to question!"); |
|---|
| 839 | | |
|---|
| 840 | | /* If choice is off screen, move it to the top */ |
|---|
| 841 | | if ((cur < top) || (cur > top + hgt)) top = cur; |
|---|
| 842 | | } |
|---|
| 843 | | } |
|---|
| 844 | | |
|---|
| | 629 | /* =================================================== */ |
|---|
| | 630 | |
|---|
| | 631 | /* gender/race/classs menu selector */ |
|---|
| 949 | | /* |
|---|
| 950 | | * Player class |
|---|
| 951 | | */ |
|---|
| 952 | | static bool get_player_class(void) |
|---|
| 953 | | { |
|---|
| 954 | | int i, res; |
|---|
| 955 | | birth_menu *classes; |
|---|
| 956 | | |
|---|
| 957 | | C_MAKE(classes, z_info->c_max, birth_menu); |
|---|
| 958 | | |
|---|
| 959 | | /* Extra info */ |
|---|
| 960 | | Term_putstr(QUESTION_COL, QUESTION_ROW, -1, TERM_YELLOW, |
|---|
| 961 | | "Your 'class' determines various intrinsic abilities and bonuses."); |
|---|
| 962 | | Term_putstr(QUESTION_COL, QUESTION_ROW + 1, -1, TERM_YELLOW, |
|---|
| 963 | | "Any greyed-out entries should only be used by advanced players."); |
|---|
| 964 | | |
|---|
| 965 | | /* Tabulate classes */ |
|---|
| 966 | | for (i = 0; i < z_info->c_max; i++) |
|---|
| 967 | | { |
|---|
| 968 | | /* Analyze */ |
|---|
| 969 | | if (!(rp_ptr->choice & (1L << i))) classes[i].grayed = TRUE; |
|---|
| 970 | | else classes[i].grayed = FALSE; |
|---|
| 971 | | |
|---|
| 972 | | /* Save the string */ |
|---|
| 973 | | classes[i].name = c_name + c_info[i].name; |
|---|
| 974 | | } |
|---|
| 975 | | |
|---|
| 976 | | res = get_player_choice(classes, z_info->c_max, p_ptr->pclass, |
|---|
| 977 | | CLASS_COL, 20, &p_ptr->pclass, |
|---|
| 978 | | "birth.txt", class_aux_hook); |
|---|
| 979 | | |
|---|
| 980 | | /* Free memory */ |
|---|
| 981 | | FREE(classes); |
|---|
| 982 | | |
|---|
| 983 | | /* No selection? */ |
|---|
| 984 | | if (res < 0) return (res); |
|---|
| 985 | | |
|---|
| 986 | | /* Set class */ |
|---|
| 987 | | cp_ptr = &c_info[p_ptr->pclass]; |
|---|
| 988 | | mp_ptr = &cp_ptr->spells; |
|---|
| 989 | | |
|---|
| 990 | | return (TRUE); |
|---|
| 991 | | } |
|---|
| 992 | | |
|---|
| 993 | | |
|---|
| 994 | | /* |
|---|
| 995 | | * Player sex |
|---|
| 996 | | */ |
|---|
| 997 | | static bool get_player_sex(void) |
|---|
| 998 | | { |
|---|
| 999 | | int i, res; |
|---|
| 1000 | | birth_menu genders[MAX_SEXES]; |
|---|
| 1001 | | |
|---|
| 1002 | | /* Extra info */ |
|---|
| 1003 | | Term_putstr(QUESTION_COL, QUESTION_ROW, -1, TERM_YELLOW, |
|---|
| 1004 | | "Your 'sex' does not have any significant gameplay effects."); |
|---|
| 1005 | | |
|---|
| 1006 | | /* Tabulate genders */ |
|---|
| 1007 | | for (i = 0; i < MAX_SEXES; i++) |
|---|
| 1008 | | { |
|---|
| 1009 | | genders[i].name = sex_info[i].title; |
|---|
| 1010 | | genders[i].grayed = FALSE; |
|---|
| 1011 | | } |
|---|
| 1012 | | |
|---|
| 1013 | | res = get_player_choice(genders, MAX_SEXES, p_ptr->psex, |
|---|
| 1014 | | SEX_COL, 15, &p_ptr->psex, |
|---|
| 1015 | | "birth.txt", NULL); |
|---|
| 1016 | | |
|---|
| 1017 | | /* No selection? */ |
|---|
| 1018 | | if (res < 0) return (res); |
|---|
| 1019 | | |
|---|
| 1020 | | /* Save the sex pointer */ |
|---|
| 1021 | | sp_ptr = &sex_info[p_ptr->psex]; |
|---|
| 1022 | | |
|---|
| 1023 | | return (TRUE); |
|---|
| | 685 | static region gender_region = {SEX_COL, TABLE_ROW, 15, -2}; |
|---|
| | 686 | static region race_region = {RACE_COL, TABLE_ROW, 15, -2}; |
|---|
| | 687 | static region class_region = {CLASS_COL, TABLE_ROW, 15, -2}; |
|---|
| | 688 | |
|---|
| | 689 | static void show_help(cptr helpfile, cptr topic) { |
|---|
| | 690 | char buf[80]; |
|---|
| | 691 | strnfmt(buf, sizeof(buf), "%s#%s", helpfile, topic); |
|---|
| | 692 | screen_save(); |
|---|
| | 693 | show_file(buf, NULL, 0, 0); |
|---|
| | 694 | screen_load(); |
|---|
| | 695 | } |
|---|
| | 696 | |
|---|
| | 697 | /* GENDER */ |
|---|
| | 698 | /* Could make a general purpose display, but see no point. */ |
|---|
| | 699 | static void display_gender(menu_type *menu, int oid, bool cursor, |
|---|
| | 700 | int row, int col, int width) |
|---|
| | 701 | { |
|---|
| | 702 | byte attr = curs_attrs[CURS_KNOWN][0 != cursor]; |
|---|
| | 703 | c_prt(attr, sex_info[oid].title, row, col); |
|---|
| | 704 | } |
|---|
| | 705 | |
|---|
| | 706 | /* Not worth writing a general purpose handler */ |
|---|
| | 707 | static bool gender_handler(char cmd, void *db, int oid) |
|---|
| | 708 | { |
|---|
| | 709 | if(cmd == '\xff') { |
|---|
| | 710 | p_ptr->psex = oid; |
|---|
| | 711 | sp_ptr = &sex_info[p_ptr->psex]; |
|---|
| | 712 | } |
|---|
| | 713 | else if(cmd == '*') { |
|---|
| | 714 | p_ptr->prace = rand_int(SEX_MALE); |
|---|
| | 715 | sp_ptr = &sex_info[p_ptr->psex]; |
|---|
| | 716 | } |
|---|
| | 717 | else if(cmd == KTRL('X')) quit(NULL); |
|---|
| | 718 | else if(cmd == '?') show_help("birth.txt", sex_info[oid].title); |
|---|
| | 719 | else return FALSE; |
|---|
| | 720 | return TRUE; |
|---|
| | 721 | } |
|---|
| | 722 | |
|---|
| | 723 | /* RACE */ |
|---|
| | 724 | static void display_race(menu_type *menu, int oid, bool cursor, |
|---|
| | 725 | int row, int col, int width) |
|---|
| | 726 | { |
|---|
| | 727 | byte attr = curs_attrs[CURS_KNOWN][0 != cursor]; |
|---|
| | 728 | c_prt(attr, p_name + p_info[oid].name, row, col); |
|---|
| | 729 | } |
|---|
| | 730 | |
|---|
| | 731 | static bool race_handler(char cmd, void *db, int oid) |
|---|
| | 732 | { |
|---|
| | 733 | if(cmd == '\xff') { |
|---|
| | 734 | p_ptr->prace = oid; |
|---|
| | 735 | rp_ptr = &p_info[p_ptr->prace]; |
|---|
| | 736 | } |
|---|
| | 737 | else if(cmd == '*') { |
|---|
| | 738 | p_ptr->prace = rand_int(z_info->p_max); |
|---|
| | 739 | rp_ptr = &p_info[p_ptr->prace]; |
|---|
| | 740 | } |
|---|
| | 741 | else if(cmd == KTRL('X')) quit(NULL); |
|---|
| | 742 | else if(cmd == '?') show_help("birth.txt", p_name+p_info[oid].name); |
|---|
| | 743 | else return FALSE; |
|---|
| | 744 | return TRUE; |
|---|
| | 745 | } |
|---|
| | 746 | |
|---|
| | 747 | |
|---|
| | 748 | /* CLASS */ |
|---|
| | 749 | static void display_class(menu_type *menu, int oid, bool cursor, |
|---|
| | 750 | int row, int col, int width) |
|---|
| | 751 | { |
|---|
| | 752 | byte attr = curs_attrs[0 != (rp_ptr->choice & (1L << oid))][0 != cursor]; |
|---|
| | 753 | c_prt(attr, c_name + c_info[oid].name, row, col); |
|---|
| | 754 | } |
|---|
| | 755 | |
|---|
| | 756 | static bool class_handler(char cmd, void *db, int oid) |
|---|
| | 757 | { |
|---|
| | 758 | if(cmd == '\xff') { |
|---|
| | 759 | p_ptr->pclass = oid; |
|---|
| | 760 | cp_ptr = &c_info[p_ptr->pclass]; |
|---|
| | 761 | mp_ptr = &cp_ptr->spells; |
|---|
| | 762 | } |
|---|
| | 763 | else if(cmd == '*') { |
|---|
| | 764 | for(;;) { |
|---|
| | 765 | p_ptr->pclass = rand_int(z_info->c_max); |
|---|
| | 766 | cp_ptr = &c_info[p_ptr->pclass]; |
|---|
| | 767 | mp_ptr = &cp_ptr->spells; |
|---|
| | 768 | if((rp_ptr->choice & (1L << oid))) |
|---|
| | 769 | break; |
|---|
| | 770 | } |
|---|
| | 771 | } |
|---|
| | 772 | else if(cmd == KTRL('X')) quit(NULL); |
|---|
| | 773 | else if(cmd == '?') show_help("birth.txt", c_name+c_info[oid].name); |
|---|
| | 774 | else return FALSE; |
|---|
| | 775 | return TRUE; |
|---|
| | 776 | } |
|---|
| | 777 | |
|---|
| | 778 | |
|---|
| | 779 | static const menu_class menu_defs[] = { |
|---|
| | 780 | {0, 0, 0, display_gender, gender_handler }, |
|---|
| | 781 | {0, 0, 0, display_race, race_handler }, |
|---|
| | 782 | {0, 0, 0, display_class, class_handler }, |
|---|
| | 783 | }; |
|---|
| | 784 | |
|---|
| | 785 | /* Menu display and selector */ |
|---|
| | 786 | |
|---|
| | 787 | static void choose_character() |
|---|
| | 788 | { |
|---|
| | 789 | int i; |
|---|
| | 790 | |
|---|
| | 791 | const region *regions [] = {&gender_region, &race_region, &class_region}; |
|---|
| | 792 | byte *values [] = {&p_ptr->psex, &p_ptr->prace, &p_ptr->pclass}; |
|---|
| | 793 | int limits [] = {SEX_MALE+1, z_info->p_max, z_info->c_max}; |
|---|
| | 794 | const char *hints [] = { |
|---|
| | 795 | "Your 'sex' does not have any significant gameplay effects.", |
|---|
| | 796 | "Your 'race' determines various intrinsic factors and bonuses.", |
|---|
| | 797 | "Your 'class' determines various intrinsic abilities and bonuses" }; |
|---|
| | 798 | |
|---|
| | 799 | typedef void (*browse_f) (int oid, const region *loc); |
|---|
| | 800 | browse_f browse [] = {NULL, race_aux_hook, class_aux_hook }; |
|---|
| | 801 | menu_type menu; |
|---|
| | 802 | WIPE(&menu, menu); |
|---|
| | 803 | menu.cmd_keys = "?*"; |
|---|
| | 804 | |
|---|
| | 805 | for(i = 0; i < N_ELEMENTS(menu_defs); i++) |
|---|
| | 806 | { |
|---|
| | 807 | key_event cx; |
|---|
| | 808 | int cursor = *values[i]; |
|---|
| | 809 | clear_question(); |
|---|
| | 810 | Term_putstr(QUESTION_COL, QUESTION_ROW, -1, TERM_YELLOW, hints[i]); |
|---|
| | 811 | menu.count = limits[i]; |
|---|
| | 812 | menu.flags = MN_NO_TAGS | MN_DBL_TAP; |
|---|
| | 813 | menu_init(&menu); |
|---|
| | 814 | menu_set_class(&menu, &menu_defs[i]); |
|---|
| | 815 | menu.browse_hook = browse[i]; |
|---|
| | 816 | |
|---|
| | 817 | cx = menu_select(&menu, 0, menu.count, &cursor, *regions[i]); |
|---|
| | 818 | if(cx.key == ESCAPE) { |
|---|
| | 819 | i = 0; /* restart */ |
|---|
| | 820 | } |
|---|
| | 821 | else if(cx.type == EVT_BACK) { |
|---|
| | 822 | i--; |
|---|
| | 823 | } |
|---|
| | 824 | } |
|---|
| | 825 | |
|---|