| 708 | | /* =================================================== */ |
|---|
| 709 | | |
|---|
| 710 | | /* gender/race/classs menu selector */ |
|---|
| 711 | | |
|---|
| 712 | | /* |
|---|
| 713 | | * Display additional information about each race during the selection. |
|---|
| 714 | | */ |
|---|
| 715 | | static void race_aux_hook(int race, void *db, const region *reg) |
|---|
| | 768 | |
|---|
| | 769 | |
|---|
| | 770 | /* |
|---|
| | 771 | * Due to its relative complexity, point based birth has been split off into |
|---|
| | 772 | * this function. 'reset' is TRUE if we're entering from earlier in the |
|---|
| | 773 | * birth process - i.e. we want to start a character from scratch rather |
|---|
| | 774 | * than having another go at one already chosen. |
|---|
| | 775 | */ |
|---|
| | 776 | static enum birth_stage do_point_based(bool reset) |
|---|
| | 777 | { |
|---|
| | 778 | game_command cmd = { CMD_NULL }; |
|---|
| | 779 | |
|---|
| | 780 | int i, j; |
|---|
| | 781 | int stats[A_MAX]; |
|---|
| | 782 | |
|---|
| | 783 | int points_spent[A_MAX]; |
|---|
| | 784 | int points_left; |
|---|
| | 785 | |
|---|
| | 786 | /* If the first command is BIRTH_BACK, we step back a stage, so this |
|---|
| | 787 | is a reasonable default. */ |
|---|
| | 788 | enum birth_stage next_stage = BIRTH_ROLLER_CHOICE; |
|---|
| | 789 | |
|---|
| | 790 | if (reset) |
|---|
| | 791 | { |
|---|
| | 792 | /* Roll for base hitpoints, age/height/weight and social class */ |
|---|
| | 793 | get_extra(); |
|---|
| | 794 | get_ahw(); |
|---|
| | 795 | get_history(); |
|---|
| | 796 | } |
|---|
| | 797 | |
|---|
| | 798 | /* Signal that we're entering the point based birth arena. */ |
|---|
| | 799 | event_signal_birthstage(BIRTH_POINTBASED, NULL); |
|---|
| | 800 | |
|---|
| | 801 | /* Calculate and signal initial stats and points totals. */ |
|---|
| | 802 | points_left = MAX_BIRTH_POINTS; |
|---|
| | 803 | |
|---|
| | 804 | for (i = 0; i < A_MAX; i++) |
|---|
| | 805 | { |
|---|
| | 806 | /* Initial stats are all 10 and costs or zero */ |
|---|
| | 807 | stats[i] = 10; |
|---|
| | 808 | points_spent[i] = 0; |
|---|
| | 809 | |
|---|
| | 810 | /* If not resetting, we use the stored stat values from p_ptr |
|---|
| | 811 | to simulate buying the stats, just using the same method as |
|---|
| | 812 | when the BUY_STAT command is received. */ |
|---|
| | 813 | if (!reset) |
|---|
| | 814 | { |
|---|
| | 815 | for (j = 10; j < p_ptr->stat_birth[i]; j++) |
|---|
| | 816 | { |
|---|
| | 817 | int stat_cost = birth_stat_costs[j + 1]; |
|---|
| | 818 | stats[i]++; |
|---|
| | 819 | points_spent[i] += stat_cost; |
|---|
| | 820 | points_left -= stat_cost; |
|---|
| | 821 | } |
|---|
| | 822 | } |
|---|
| | 823 | } |
|---|
| | 824 | |
|---|
| | 825 | /* Use the new "birth stat" values to work out the "other" |
|---|
| | 826 | stat values (i.e. after modifiers) and tell the UI things have |
|---|
| | 827 | changed. */ |
|---|
| | 828 | recalculate_stats(stats, points_left); |
|---|
| | 829 | event_signal_birthstats(points_spent, points_left); |
|---|
| | 830 | |
|---|
| | 831 | /* Then on to the interactive part - two ways to leave */ |
|---|
| | 832 | while (cmd.command != CMD_ACCEPT_STATS && |
|---|
| | 833 | cmd.command != CMD_BIRTH_BACK) |
|---|
| | 834 | { |
|---|
| | 835 | cmd = get_birth_command(); |
|---|
| | 836 | |
|---|
| | 837 | /* If BIRTH_BACK isn't the first command, or we didn't start |
|---|
| | 838 | by resetting the stats, we redo this stage rather than actually |
|---|
| | 839 | stepping back. */ |
|---|
| | 840 | if (cmd.command != CMD_BIRTH_BACK || !reset) |
|---|
| | 841 | next_stage = BIRTH_POINTBASED; |
|---|
| | 842 | |
|---|
| | 843 | switch (cmd.command) |
|---|
| | 844 | { |
|---|
| | 845 | case CMD_BUY_STAT: |
|---|
| | 846 | { |
|---|
| | 847 | /* The choice is the index of the stat in the list to "buy" */ |
|---|
| | 848 | int choice = cmd.params.choice; |
|---|
| | 849 | if (choice >= A_MAX || choice < 0) continue; |
|---|
| | 850 | |
|---|
| | 851 | /* Can't increase stats past a "base" of 18 */ |
|---|
| | 852 | if (stats[choice] < 18) |
|---|
| | 853 | { |
|---|
| | 854 | /* Get the cost of buying the extra point (beyond what |
|---|
| | 855 | it has already cost to get this far). */ |
|---|
| | 856 | int stat_cost = birth_stat_costs[stats[choice] + 1]; |
|---|
| | 857 | |
|---|
| | 858 | if (stat_cost <= points_left) |
|---|
| | 859 | { |
|---|
| | 860 | stats[choice]++; |
|---|
| | 861 | points_spent[choice] += stat_cost; |
|---|
| | 862 | points_left -= stat_cost; |
|---|
| | 863 | |
|---|
| | 864 | /* Tell the UI the new points situation. */ |
|---|
| | 865 | event_signal_birthstats(points_spent, points_left); |
|---|
| | 866 | |
|---|
| | 867 | /* Recalculate everything that's changed because |
|---|
| | 868 | the stat has changed, and inform the UI. */ |
|---|
| | 869 | recalculate_stats(stats, points_left); |
|---|
| | 870 | } |
|---|
| | 871 | } |
|---|
| | 872 | |
|---|
| | 873 | break; |
|---|
| | 874 | } |
|---|
| | 875 | |
|---|
| | 876 | case CMD_SELL_STAT: |
|---|
| | 877 | { |
|---|
| | 878 | /* The choice is the index of the stat in the list to "sell" */ |
|---|
| | 879 | int choice = cmd.params.choice; |
|---|
| | 880 | if (choice >= A_MAX || choice < 0) continue; |
|---|
| | 881 | |
|---|
| | 882 | /* We can't "sell" stats below the base of 10. */ |
|---|
| | 883 | if (stats[choice] > 10) |
|---|
| | 884 | { |
|---|
| | 885 | int stat_cost = birth_stat_costs[stats[choice]]; |
|---|
| | 886 | |
|---|
| | 887 | stats[choice]--; |
|---|
| | 888 | points_spent[choice] -= stat_cost; |
|---|
| | 889 | points_left += stat_cost; |
|---|
| | 890 | |
|---|
| | 891 | /* Tell the UI the new points situation. */ |
|---|
| | 892 | event_signal_birthstats(points_spent, points_left); |
|---|
| | 893 | |
|---|
| | 894 | /* Recalculate everything that's changed because |
|---|
| | 895 | the stat has changed, and inform the UI. */ |
|---|
| | 896 | recalculate_stats(stats, points_left); |
|---|
| | 897 | } |
|---|
| | 898 | break; |
|---|
| | 899 | } |
|---|
| | 900 | |
|---|
| | 901 | case CMD_ACCEPT_STATS: |
|---|
| | 902 | { |
|---|
| | 903 | next_stage = BIRTH_NAME_CHOICE; |
|---|
| | 904 | break; |
|---|
| | 905 | } |
|---|
| | 906 | } |
|---|
| | 907 | } |
|---|
| | 908 | |
|---|
| | 909 | return next_stage; |
|---|
| | 910 | } |
|---|
| | 911 | |
|---|
| | 912 | |
|---|
| | 913 | enum birth_questions |
|---|
| | 914 | { |
|---|
| | 915 | BQ_METHOD = 0, |
|---|
| | 916 | BQ_SEX, |
|---|
| | 917 | BQ_RACE, |
|---|
| | 918 | BQ_CLASS, |
|---|
| | 919 | BQ_ROLLER, |
|---|
| | 920 | MAX_BIRTH_QUESTIONS |
|---|
| | 921 | }; |
|---|
| | 922 | |
|---|
| | 923 | enum birth_methods |
|---|
| | 924 | { |
|---|
| | 925 | BM_NORMAL_BIRTH = 0, |
|---|
| | 926 | BM_QUICKSTART, |
|---|
| | 927 | MAX_BIRTH_METHODS |
|---|
| | 928 | }; |
|---|
| | 929 | |
|---|
| | 930 | enum birth_rollers |
|---|
| | 931 | { |
|---|
| | 932 | BR_POINTBASED = 0, |
|---|
| | 933 | BR_AUTOROLLER, |
|---|
| | 934 | BR_NORMAL, |
|---|
| | 935 | MAX_BIRTH_ROLLERS |
|---|
| | 936 | }; |
|---|
| | 937 | |
|---|
| | 938 | /* |
|---|
| | 939 | * Create a new character. |
|---|
| | 940 | * |
|---|
| | 941 | * Note that we may be called with "junk" leftover in the various |
|---|
| | 942 | * fields, so we must be sure to clear them first. |
|---|
| | 943 | */ |
|---|
| | 944 | void player_birth(bool quickstart_allowed) |
|---|
| 718 | | char s[50]; |
|---|
| 719 | | |
|---|
| 720 | | if (race == z_info->p_max) return; |
|---|
| 721 | | |
|---|
| 722 | | /* Display relevant details. */ |
|---|
| 723 | | for (i = 0; i < A_MAX; i++) |
|---|
| 724 | | { |
|---|
| 725 | | strnfmt(s, sizeof(s), "%s%+d", stat_names_reduced[i], |
|---|
| 726 | | p_info[race].r_adj[i]); |
|---|
| 727 | | Term_putstr(RACE_AUX_COL, TABLE_ROW + i, -1, TERM_WHITE, s); |
|---|
| 728 | | } |
|---|
| 729 | | |
|---|
| 730 | | strnfmt(s, sizeof(s), "Hit die: %d ", p_info[race].r_mhp); |
|---|
| 731 | | Term_putstr(RACE_AUX_COL, TABLE_ROW + A_MAX, -1, TERM_WHITE, s); |
|---|
| 732 | | strnfmt(s, sizeof(s), "Experience: %d%% ", p_info[race].r_exp); |
|---|
| 733 | | Term_putstr(RACE_AUX_COL, TABLE_ROW + A_MAX + 1, -1, TERM_WHITE, s); |
|---|
| 734 | | strnfmt(s, sizeof(s), "Infravision: %d ft ", p_info[race].infra * 10); |
|---|
| 735 | | Term_putstr(RACE_AUX_COL, TABLE_ROW + A_MAX + 2, -1, TERM_WHITE, s); |
|---|
| 736 | | } |
|---|
| 737 | | |
|---|
| 738 | | |
|---|
| 739 | | /* |
|---|
| 740 | | * Display additional information about each class during the selection. |
|---|
| 741 | | */ |
|---|
| 742 | | static void class_aux_hook(int class_idx, void *db, const region *loc) |
|---|
| 743 | | { |
|---|
| 744 | | int i; |
|---|
| 745 | | char s[128]; |
|---|
| 746 | | |
|---|
| 747 | | if (class_idx == z_info->c_max) return; |
|---|
| 748 | | |
|---|
| 749 | | /* Display relevant details. */ |
|---|
| 750 | | for (i = 0; i < A_MAX; i++) |
|---|
| 751 | | { |
|---|
| 752 | | strnfmt(s, sizeof(s), "%s%+d", stat_names_reduced[i], |
|---|
| 753 | | c_info[class_idx].c_adj[i]); |
|---|
| 754 | | Term_putstr(CLASS_AUX_COL, TABLE_ROW + i, -1, TERM_WHITE, s); |
|---|
| 755 | | } |
|---|
| 756 | | |
|---|
| 757 | | strnfmt(s, sizeof(s), "Hit die: %d ", c_info[class_idx].c_mhp); |
|---|
| 758 | | Term_putstr(CLASS_AUX_COL, TABLE_ROW + A_MAX, -1, TERM_WHITE, s); |
|---|
| 759 | | strnfmt(s, sizeof(s), "Experience: %d%% ", c_info[class_idx].c_exp); |
|---|
| 760 | | Term_putstr(CLASS_AUX_COL, TABLE_ROW + A_MAX + 1, -1, TERM_WHITE, s); |
|---|
| 761 | | } |
|---|
| 762 | | |
|---|
| 763 | | |
|---|
| 764 | | static region gender_region = {SEX_COL, TABLE_ROW, 15, -2}; |
|---|
| 765 | | static region race_region = {RACE_COL, TABLE_ROW, 15, -2}; |
|---|
| 766 | | static region class_region = {CLASS_COL, TABLE_ROW, 19, -2}; |
|---|
| 767 | | static region roller_region = {44, TABLE_ROW, 21, -2}; |
|---|
| 768 | | |
|---|
| 769 | | |
|---|
| 770 | | /* Event handler implementation */ |
|---|
| 771 | | static bool handler_aux(char cmd, int oid, byte *val, int max, int mask, cptr topic) |
|---|
| 772 | | { |
|---|
| 773 | | if (cmd == '\xff' || cmd == '\r') { |
|---|
| 774 | | *val = oid; |
|---|
| 775 | | } |
|---|
| 776 | | else if (cmd == '*') { |
|---|
| 777 | | for(;;) |
|---|
| 778 | | { |
|---|
| 779 | | oid = rand_int(max); |
|---|
| 780 | | *val = oid; |
|---|
| 781 | | if(mask & (1L << oid)) break; |
|---|
| 782 | | } |
|---|
| 783 | | } |
|---|
| 784 | | else if (cmd == '=') |
|---|
| 785 | | { |
|---|
| 786 | | do_cmd_options(); |
|---|
| 787 | | return FALSE; |
|---|
| 788 | | } |
|---|
| 789 | | else if (cmd == KTRL('X')) |
|---|
| 790 | | { |
|---|
| 791 | | quit(NULL); |
|---|
| 792 | | } |
|---|
| 793 | | else if (cmd == '?') { |
|---|
| 794 | | char buf[80]; |
|---|
| 795 | | strnfmt(buf, sizeof(buf), "%s#%s", "birth.txt", topic); |
|---|
| 796 | | screen_save(); |
|---|
| 797 | | show_file(buf, NULL, 0, 0); |
|---|
| 798 | | screen_load(); |
|---|
| 799 | | return FALSE; |
|---|
| 800 | | } |
|---|
| 801 | | else return FALSE; |
|---|
| 802 | | |
|---|
| 803 | | sp_ptr = &sex_info[p_ptr->psex]; |
|---|
| 804 | | rp_ptr = &p_info[p_ptr->prace]; |
|---|
| 805 | | cp_ptr = &c_info[p_ptr->pclass]; |
|---|
| 806 | | mp_ptr = &cp_ptr->spells; |
|---|
| 807 | | return TRUE; |
|---|
| 808 | | } |
|---|
| 809 | | |
|---|
| 810 | | /* GENDER */ |
|---|
| 811 | | /* Display a gender */ |
|---|
| 812 | | static void display_gender(menu_type *menu, int oid, bool cursor, |
|---|
| 813 | | int row, int col, int width) |
|---|
| 814 | | { |
|---|
| 815 | | byte attr = curs_attrs[CURS_KNOWN][0 != cursor]; |
|---|
| 816 | | c_put_str(attr, sex_info[oid].title, row, col); |
|---|
| 817 | | } |
|---|
| 818 | | |
|---|
| 819 | | static bool gender_handler(char cmd, void *db, int oid) |
|---|
| 820 | | { |
|---|
| 821 | | return handler_aux(cmd, oid, &p_ptr->psex, SEX_MALE+1, |
|---|
| 822 | | 0xffffffff, sex_info[oid].title); |
|---|
| 823 | | } |
|---|
| 824 | | |
|---|
| 825 | | /* RACE */ |
|---|
| 826 | | static void display_race(menu_type *menu, int oid, bool cursor, |
|---|
| 827 | | int row, int col, int width) |
|---|
| 828 | | { |
|---|
| 829 | | byte attr = curs_attrs[CURS_KNOWN][0 != cursor]; |
|---|
| 830 | | c_put_str(attr, p_name + p_info[oid].name, row, col); |
|---|
| 831 | | } |
|---|
| 832 | | |
|---|
| 833 | | static bool race_handler(char cmd, void *db, int oid) |
|---|
| 834 | | { |
|---|
| 835 | | return handler_aux(cmd, oid, &p_ptr->prace, z_info->p_max, |
|---|
| 836 | | 0xffffffff, p_name + p_info[oid].name); |
|---|
| 837 | | } |
|---|
| 838 | | |
|---|
| 839 | | /* CLASS */ |
|---|
| 840 | | static void display_class(menu_type *menu, int oid, bool cursor, |
|---|
| 841 | | int row, int col, int width) |
|---|
| 842 | | { |
|---|
| 843 | | byte attr = curs_attrs[0 != (rp_ptr->choice & (1L << oid))][0 != cursor]; |
|---|
| 844 | | c_put_str(attr, c_name + c_info[oid].name, row, col); |
|---|
| 845 | | } |
|---|
| 846 | | |
|---|
| 847 | | static bool class_handler(char cmd, void *db, int oid) |
|---|
| 848 | | { |
|---|
| 849 | | return handler_aux(cmd, oid, &p_ptr->pclass, z_info->c_max, |
|---|
| 850 | | (rp_ptr->choice), c_name + c_info[oid].name); |
|---|
| 851 | | } |
|---|
| 852 | | |
|---|
| 853 | | /* ROLLER */ |
|---|
| 854 | | static void display_roller(menu_type *menu, int oid, bool cursor, |
|---|
| 855 | | int row, int col, int width) |
|---|
| 856 | | { |
|---|
| 857 | | byte attr = curs_attrs[CURS_KNOWN][0 != cursor]; |
|---|
| 858 | | const char *str; |
|---|
| 859 | | |
|---|
| 860 | | if (oid == 0) |
|---|
| 861 | | str = "Point-based"; |
|---|
| 862 | | else if (oid == 1) |
|---|
| 863 | | str = "Autoroller"; |
|---|
| 864 | | else |
|---|
| 865 | | str = "Standard roller"; |
|---|
| 866 | | |
|---|
| 867 | | c_prt(attr, str, row, col); |
|---|
| 868 | | } |
|---|
| 869 | | |
|---|
| 870 | | |
|---|
| 871 | | static byte roller_type = 0; |
|---|
| 872 | | #define ROLLER_POINT 0 |
|---|
| 873 | | #define ROLLER_AUTO 1 |
|---|
| 874 | | #define ROLLER_STD 2 |
|---|
| 875 | | |
|---|
| 876 | | static bool roller_handler(char cmd, void *db, int oid) |
|---|
| 877 | | { |
|---|
| 878 | | if (cmd == '\xff' || cmd == '\r') |
|---|
| 879 | | { |
|---|
| 880 | | roller_type = oid; |
|---|
| 881 | | return TRUE; |
|---|
| 882 | | } |
|---|
| 883 | | else if (cmd == '*') |
|---|
| 884 | | { |
|---|
| 885 | | roller_type = 2; |
|---|
| 886 | | return TRUE; |
|---|
| 887 | | } |
|---|
| 888 | | else if(cmd == '=') |
|---|
| 889 | | do_cmd_options(); |
|---|
| 890 | | else if(cmd == KTRL('X')) |
|---|
| 891 | | quit(NULL); |
|---|
| 892 | | else if(cmd == '?') { |
|---|
| 893 | | char buf[80]; |
|---|
| 894 | | char *str; |
|---|
| 895 | | |
|---|
| 896 | | if (oid == 0) |
|---|
| 897 | | str = "Point-based"; |
|---|
| 898 | | else if (oid == 1) |
|---|
| 899 | | str = "Autoroller"; |
|---|
| 900 | | else |
|---|
| 901 | | str = "Standard roller"; |
|---|
| 902 | | |
|---|
| 903 | | strnfmt(buf, sizeof(buf), "%s#%s", "birth.txt", str); |
|---|
| 904 | | screen_save(); |
|---|
| 905 | | show_file(buf, NULL, 0, 0); |
|---|
| 906 | | screen_load(); |
|---|
| 907 | | } |
|---|
| 908 | | |
|---|
| 909 | | return FALSE; |
|---|
| 910 | | } |
|---|
| 911 | | |
|---|
| 912 | | |
|---|
| 913 | | static const menu_iter menu_defs[] = |
|---|
| 914 | | { |
|---|
| 915 | | { MN_NULL, 0, 0, display_gender, gender_handler }, |
|---|
| 916 | | { MN_NULL, 0, 0, display_race, race_handler }, |
|---|
| 917 | | { MN_NULL, 0, 0, display_class, class_handler }, |
|---|
| 918 | | { MN_NULL, 0, 0, display_roller, roller_handler }, |
|---|
| 919 | | }; |
|---|
| 920 | | |
|---|
| 921 | | /* Menu display and selector */ |
|---|
| 922 | | |
|---|
| 923 | | #define ASEX 0 |
|---|
| 924 | | #define ARACE 1 |
|---|
| 925 | | #define ACLASS 2 |
|---|
| 926 | | #define AROLL 3 |
|---|
| 927 | | |
|---|
| 928 | | |
|---|
| 929 | | |
|---|
| 930 | | static bool choose_character(bool start_at_end) |
|---|
| 931 | | { |
|---|
| 932 | | int i = 0; |
|---|
| 933 | | |
|---|
| 934 | | const region *regions[] = { &gender_region, &race_region, &class_region, &roller_region }; |
|---|
| 935 | | byte *values[4]; /* { &p_ptr->psex, &p_ptr->prace, &p_ptr->pclass }; */ |
|---|
| 936 | | int limits[4]; /* { SEX_MALE +1, z_info->p_max, z_info->c_max }; */ |
|---|
| 937 | | |
|---|
| 938 | | menu_type menu; |
|---|
| 939 | | |
|---|
| 940 | | const char *hints[] = |
|---|
| 941 | | { |
|---|
| | 947 | game_command cmd = { CMD_NULL, 0 }; |
|---|
| | 948 | |
|---|
| | 949 | |
|---|
| | 950 | /* |
|---|
| | 951 | * The last character displayed, to allow the user to flick between two. |
|---|
| | 952 | * We rely on prev.age being zero to determine whether there is a stored |
|---|
| | 953 | * character or not, so initialise it here. |
|---|
| | 954 | */ |
|---|
| | 955 | birther prev = { 0 }; |
|---|
| | 956 | |
|---|
| | 957 | /* |
|---|
| | 958 | * If quickstart is allowed, we store the old character in this, |
|---|
| | 959 | * to allow for it to be reloaded if we step back that far in the |
|---|
| | 960 | * birth process. |
|---|
| | 961 | */ |
|---|
| | 962 | birther quickstart_prev = { 0 }; |
|---|
| | 963 | |
|---|
| | 964 | enum birth_stage next_stage = BIRTH_METHOD_CHOICE; |
|---|
| | 965 | enum birth_stage stage = BIRTH_METHOD_CHOICE; |
|---|
| | 966 | enum birth_stage last_stage = BIRTH_METHOD_CHOICE; |
|---|
| | 967 | enum birth_stage roller_choice = BIRTH_METHOD_CHOICE; |
|---|
| | 968 | |
|---|
| | 969 | int roller_mins[A_MAX]; |
|---|
| | 970 | |
|---|
| | 971 | /* Set up our "hints" for each birth question */ |
|---|
| | 972 | const char *hints[MAX_BIRTH_QUESTIONS] = { |
|---|
| | 973 | "Quickstart lets you make a new character based on your old one.", |
|---|
| | 979 | |
|---|
| | 980 | /* Set up the list of choices for each birth question. */ |
|---|
| | 981 | const char *quickstart_choices[MAX_BIRTH_METHODS] = { |
|---|
| | 982 | "Normal birth process", |
|---|
| | 983 | "Quickstart" |
|---|
| | 984 | }; |
|---|
| | 985 | |
|---|
| | 986 | const char *roller_choices[MAX_BIRTH_ROLLERS] = { |
|---|
| | 987 | "Point-based", |
|---|
| | 988 | "Autoroller", |
|---|
| | 989 | "Standard roller" |
|---|
| | 990 | }; |
|---|
| | 991 | |
|---|
| | 992 | /* These require setting up in a loop later, so just allocate memory for |
|---|
| | 993 | arrays of char * for now */ |
|---|
| | 994 | const char *sex_choices[MAX_SEXES]; |
|---|
| | 995 | |
|---|
| | 996 | const char **race_choices = mem_alloc(z_info->p_max * sizeof *race_choices); |
|---|
| | 997 | const char **class_choices = mem_alloc(z_info->c_max * sizeof *class_choices); |
|---|
| | 998 | |
|---|
| | 999 | /* For a couple of the options we have extra "help text" as well as the |
|---|
| | 1000 | hints, */ |
|---|
| | 1001 | const char **race_help = mem_alloc(z_info->p_max * sizeof *race_help); |
|---|
| | 1002 | const char **class_help = mem_alloc(z_info->c_max * sizeof *class_help); |
|---|
| | 1003 | |
|---|
| | 1004 | |
|---|
| | 1005 | /* Set up the choices for sex, race and class questions. */ |
|---|
| | 1006 | for (i = 0; i < MAX_SEXES; i++) |
|---|
| | 1007 | sex_choices[i] = sex_info[i].title; |
|---|
| | 1008 | |
|---|
| | 1009 | for (i = 0; i < z_info->p_max; i++) |
|---|
| | 1010 | race_choices[i] = p_name + p_info[i].name; |
|---|
| | 1011 | |
|---|
| | 1012 | for (i = 0; i < z_info->c_max; i++) |
|---|
| | 1013 | class_choices[i] = c_name + c_info[i].name; |
|---|
| | 1014 | |
|---|
| | 1015 | /* Set up extra help text for race and class questions (basically just |
|---|
| | 1016 | lists of various bonuses you get for each race or class). */ |
|---|
| | 1017 | for (i = 0; i < z_info->p_max; i++) |
|---|
| | 1018 | { |
|---|
| | 1019 | int j; |
|---|
| | 1020 | char *s; |
|---|
| | 1021 | size_t end; |
|---|
| | 1022 | |
|---|
| | 1023 | /* Race help text consists of: */ |
|---|
| | 1024 | int bufsize = |
|---|
| | 1025 | sizeof "STR: xx\n" * A_MAX + |
|---|
| | 1026 | sizeof "Hit die: xx\n" + |
|---|
| | 1027 | sizeof "Experience: xxx%\n" + |
|---|
| | 1028 | sizeof "Infravision: xx ft\0"; |
|---|
| | 1029 | |
|---|
| | 1030 | /* Allocate enough memory to hold that text for this race choice */ |
|---|
| | 1031 | race_help[i] = mem_alloc(bufsize * sizeof *race_help[i]); |
|---|
| | 1032 | |
|---|
| | 1033 | /* Set 's' up as a shorthand for race_choices[i] to make later lines |
|---|
| | 1034 | readable, and make sure it is an empty string. Note we cast away |
|---|
| | 1035 | the "constness" of rece_help[i] while we build the string, |
|---|
| | 1036 | safe because we know where it points (writable memory). */ |
|---|
| | 1037 | s = (char *) race_help[i]; |
|---|
| | 1038 | s[0] = '\0'; end = 0; |
|---|
| | 1039 | |
|---|
| | 1040 | /* For each stat, concatanate a "STR: xx" type sequence to the |
|---|
| | 1041 | end of the help string. */ |
|---|
| | 1042 | for (j = 0; j < A_MAX; j++) |
|---|
| | 1043 | { |
|---|
| | 1044 | strnfcat(s, bufsize, &end, "%s%+d\n", |
|---|
| | 1045 | stat_names_reduced[j], p_info[i].r_adj[j]); |
|---|
| | 1046 | } |
|---|
| | 1047 | |
|---|
| | 1048 | /* Concatenate all other bonuses to the end of the help string. */ |
|---|
| | 1049 | strnfcat(s, bufsize, &end, "Hit die: %d\n", p_info[i].r_mhp); |
|---|
| | 1050 | strnfcat(s, bufsize, &end, "Experience: %d%%\n", p_info[i].r_exp); |
|---|
| | 1051 | strnfcat(s, bufsize, &end, "Infravision: %d ft", p_info[i].infra * 10); |
|---|
| | 1052 | } |
|---|
| | 1053 | |
|---|
| | 1054 | for (i = 0; i < z_info->c_max; i++) |
|---|
| | 1055 | { |
|---|
| | 1056 | int j; |
|---|
| | 1057 | char *s; |
|---|
| | 1058 | size_t end; |
|---|
| | 1059 | |
|---|
| | 1060 | /* Class help text consists of: */ |
|---|
| | 1061 | int bufsize = |
|---|
| | 1062 | sizeof "STR: xx\n" * A_MAX + |
|---|
| | 1063 | sizeof "Hit die: xx\n" + |
|---|
| | 1064 | sizeof "Experience: xxx%\n"; |
|---|
| | 1065 | |
|---|
| | 1066 | /* Allocate enough memory to hold that text for this race choice */ |
|---|
| | 1067 | class_help[i] = mem_alloc(bufsize * sizeof *class_help[i]); |
|---|
| | 1068 | |
|---|
| | 1069 | /* Set 's' up as a shorthand for race_choices[i] to make later lines |
|---|
| | 1070 | readable, and make sure it is an empty string. Note we cast away |
|---|
| | 1071 | the "constness" of rece_help[i] while we build the string, |
|---|
| | 1072 | safe because we know where it points (writable memory). */ |
|---|
| | 1073 | s = (char *) class_help[i]; |
|---|
| | 1074 | s[0] = '\0'; end = 0; |
|---|
| | 1075 | |
|---|
| | 1076 | /* For each stat, concatanate a "STR: xx" type sequence to the |
|---|
| | 1077 | end of the help string. */ |
|---|
| | 1078 | for (j = 0; j < A_MAX; j++) |
|---|
| | 1079 | { |
|---|
| | 1080 | strnfcat(s, bufsize, &end, "%s%+d\n", |
|---|
| | 1081 | stat_names_reduced[j], c_info[i].c_adj[j]); |
|---|
| | 1082 | } |
|---|
| | 1083 | |
|---|
| | 1084 | /* Concatenate all other bonuses to the end of the help string. */ |
|---|
| | 1085 | strnfcat(s, bufsize, &end, "Hit die: %d\n", c_info[i].c_mhp); |
|---|
| | 1086 | strnfcat(s, bufsize, &end, "Experience: %d%%", c_info[i].c_exp); |
|---|
| | 1087 | } |
|---|
| | 1088 | |
|---|
| | 1089 | /* If there's a quickstart character, store it here. */ |
|---|
| | 1090 | if (quickstart_allowed) |
|---|
| | 1091 | save_roller_data(&quickstart_prev); |
|---|
| | 1092 | |
|---|
| | 1093 | /* Now we're ready to start the interactive birth process. */ |
|---|
| | 1094 | event_signal(EVENT_ENTER_BIRTH); |
|---|
| | 1095 | |
|---|
| | 1096 | /* "stage" just keeps track of where we're up to in the (somewhat tortuous) |
|---|
| | 1097 | process - the stages are laid out in approximately the right order in |
|---|
| | 1098 | the switch statement below. */ |
|---|
| | 1099 | stage = BIRTH_METHOD_CHOICE; |
|---|
| | 1100 | |
|---|
| | 1101 | /* There are two ways to leave - with a working character or by quitting */ |
|---|
| | 1102 | while (stage != BIRTH_COMPLETE) |
|---|
| | 1103 | { |
|---|
| | 1104 | switch (stage) |
|---|
| | 1105 | { |
|---|
| | 1106 | /* |
|---|
| | 1107 | * First stage is to determine the birth method - currently |
|---|
| | 1108 | * simply whether to use quickstart or do the full birth |
|---|
| | 1109 | * process. |
|---|
| | 1110 | */ |
|---|
| | 1111 | case BIRTH_METHOD_CHOICE: |
|---|
| | 1112 | { |
|---|
| | 1113 | /* Set |
|---|