/* File: birth.c */ /* Purpose: create a player character */ /* * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke * * This software may be copied and distributed for educational, research, and * not for profit purposes provided that this copyright and statement are * included in all such copies. */ #include "angband.h" /* * Base stats array */ int base_stats[6]; /* * Costs of various stats -- MJC */ int stat_points[18] = { 0, /* 0 */ 0, /* 1 */ 0, /* 2 */ 0, /* 3 */ 0, /* 4 */ 0, /* 5 */ 0, /* 6 */ 0, /* 7 */ -4, /* 8 */ -3, /* 9 */ -2, /* 10 */ -1, /* 11 */ 0, /* 12 */ 2, /* 13 */ 4, /* 14 */ 6, /* 15 */ 9, /* 16 */ 12, /* 17 */ }; /* * A structure to hold "rolled" information */ typedef struct { s16b age; s16b wt; s16b ht; s16b sc; s32b au; s16b stat[6]; char history[4][60]; } birther; /* * Player background information */ typedef struct { cptr info; /* Textual History */ byte roll; /* Frequency of this entry */ byte chart; /* Chart index */ byte next; /* Next chart index */ byte bonus; /* Social Class Bonus + 50 */ } hist_type; /* * Background information (see below) * * Chart progression by race: * Human/Dunadan --> 1 --> 2 --> 3 --> 50 --> 51 --> 52 --> 53 * Half-Elf --> 4 --> 1 --> 2 --> 3 --> 50 --> 51 --> 52 --> 53 * Elf/High-Elf --> 7 --> 8 --> 9 --> 54 --> 55 --> 56 * Hobbit --> 10 --> 11 --> 3 --> 50 --> 51 --> 52 --> 53 * Gnome --> 13 --> 14 --> 3 --> 50 --> 51 --> 52 --> 53 * Dwarf --> 16 --> 17 --> 18 --> 57 --> 58 --> 59 --> 60 --> 61 * Half-Orc --> 19 --> 20 --> 2 --> 3 --> 50 --> 51 --> 52 --> 53 * Half-Troll --> 22 --> 23 --> 62 --> 63 --> 64 --> 65 --> 66 * High-Elf --> 25 --> 26 --> 27 --> 54 --> 55 --> 56 * * XXX XXX XXX This table *must* be correct or drastic errors may occur! */ static hist_type bg[] = { {"You are the illegitimate and unacknowledged child ", 10, 1, 2, 25}, {"You are the illegitimate but acknowledged child ", 20, 1, 2, 35}, {"You are one of several children ", 95, 1, 2, 45}, {"You are the first child ", 100, 1, 2, 50}, {"of a Serf. ", 40, 2, 3, 65}, {"of a Yeoman. ", 65, 2, 3, 80}, {"of a Townsman. ", 80, 2, 3, 90}, {"of a Guildsman. ", 90, 2, 3,105}, {"of a Landed Knight. ", 96, 2, 3,120}, {"of a Titled Noble. ", 99, 2, 3,130}, {"of a Royal Blood Line. ", 100, 2, 3,140}, {"You are the black sheep of the family. ", 20, 3,50, 20}, {"You are a credit to the family. ", 80, 3,50, 55}, {"You are a well liked child. ", 100, 3,50, 60}, {"Your mother was a Silvan Elf. ", 40, 4, 1, 50}, {"Your father was a Silvan Elf. ", 75, 4, 1, 55}, {"Your mother was a Sinda Elf. ", 90, 4, 1, 55}, {"Your father was a Sinda Elf. ", 100, 4, 1, 60}, {"You are one of several children ", 60, 7, 8, 50}, {"You are the only child ", 100, 7, 8, 55}, {"of a Silvan Elf ", 75, 8, 9, 50}, {"of a Sinda Elf ", 100, 8, 9, 55}, {"Ranger. ", 40, 9,54, 80}, {"Archer. ", 70, 9,54, 90}, {"Warrior. ", 87, 9,54,110}, {"Mage. ", 95, 9,54,125}, {"Prince. ", 99, 9,54,140}, {"King. ", 100, 9,54,145}, {"You are one of several children of a Hobbit ", 85,10,11, 45}, {"You are the only child of a Hobbit ", 100,10,11, 55}, {"Bum. ", 20,11, 3, 55}, {"Tavern Owner. ", 30,11, 3, 80}, {"Miller. ", 40,11, 3, 90}, {"Home Owner. ", 50,11, 3,100}, {"Burglar. ", 80,11, 3,110}, {"Warrior. ", 95,11, 3,115}, {"Mage. ", 99,11, 3,125}, {"Clan Elder. ", 100,11, 3,140}, {"You are one of several children of a Gnome ", 85,13,14, 45}, {"You are the only child of a Gnome ", 100,13,14, 55}, {"Beggar. ", 20,14, 3, 55}, {"Braggart. ", 50,14, 3, 70}, {"Prankster. ", 75,14, 3, 85}, {"Warrior. ", 95,14, 3,100}, {"Mage. ", 100,14, 3,125}, {"You are one of two children of a Dwarven ", 25,16,17, 40}, {"You are the only child of a Dwarven ", 100,16,17, 50}, {"Thief. ", 10,17,18, 60}, {"Prison Guard. ", 25,17,18, 75}, {"Miner. ", 75,17,18, 90}, {"Warrior. ", 90,17,18,110}, {"Priest. ", 99,17,18,130}, {"King. ", 100,17,18,150}, {"You are the black sheep of the family. ", 15,18,57, 10}, {"You are a credit to the family. ", 85,18,57, 50}, {"You are a well liked child. ", 100,18,57, 55}, {"Your mother was an Orc, but it is unacknowledged. ", 25,19,20, 25}, {"Your father was an Orc, but it is unacknowledged. ", 100,19,20, 25}, {"You are the adopted child ", 100,20, 2, 50}, {"Your mother was a Cave-Troll ", 30,22,23, 20}, {"Your father was a Cave-Troll ", 60,22,23, 25}, {"Your mother was a Hill-Troll ", 75,22,23, 30}, {"Your father was a Hill-Troll ", 90,22,23, 35}, {"Your mother was a Water-Troll ", 95,22,23, 40}, {"Your father was a Water-Troll ", 100,22,23, 45}, {"Cook. ", 5,23,62, 60}, {"Warrior. ", 95,23,62, 55}, {"Shaman. ", 99,23,62, 65}, {"Clan Chief. ", 100,23,62, 80}, {"You are one of several children ", 60,25,26, 50}, {"You are the only child ", 100,25,26, 55}, {"of a Teleri ", 75,26,27, 50}, {"of a Noldo ", 95,26,27, 55}, {"of a Vanya ", 100,26,27, 60}, {"Ranger. ", 40,27,54, 80}, {"Archer. ", 70,27,54, 90}, {"Warrior. ", 87,27,54,110}, {"Mage. ", 95,27,54,125}, {"Prince. ", 99,27,54,140}, {"King. ", 100,27,54,145}, {"You have dark brown eyes, ", 20,50,51, 50}, {"You have brown eyes, ", 60,50,51, 50}, {"You have hazel eyes, ", 70,50,51, 50}, {"You have green eyes, ", 80,50,51, 50}, {"You have blue eyes, ", 90,50,51, 50}, {"You have blue-gray eyes, ", 100,50,51, 50}, {"straight ", 70,51,52, 50}, {"wavy ", 90,51,52, 50}, {"curly ", 100,51,52, 50}, {"black hair, ", 30,52,53, 50}, {"brown hair, ", 70,52,53, 50}, {"auburn hair, ", 80,52,53, 50}, {"red hair, ", 90,52,53, 50}, {"blond hair, ", 100,52,53, 50}, {"and a very dark complexion.", 10,53, 0, 50}, {"and a dark complexion.", 30,53, 0, 50}, {"and an average complexion.", 80,53, 0, 50}, {"and a fair complexion.", 90,53, 0, 50}, {"and a very fair complexion.", 100,53, 0, 50}, {"You have light grey eyes, ", 85,54,55, 50}, {"You have light blue eyes, ", 95,54,55, 50}, {"You have light green eyes, ", 100,54,55, 50}, {"straight ", 75,55,56, 50}, {"wavy ", 100,55,56, 50}, {"black hair, and a fair complexion.", 75,56, 0, 50}, {"brown hair, and a fair complexion.", 85,56, 0, 50}, {"blond hair, and a fair complexion.", 95,56, 0, 50}, {"silver hair, and a fair complexion.", 100,56, 0, 50}, {"You have dark brown eyes, ", 99,57,58, 50}, {"You have glowing red eyes, ", 100,57,58, 60}, {"straight ", 90,58,59, 50}, {"wavy ", 100,58,59, 50}, {"black hair, ", 75,59,60, 50}, {"brown hair, ", 100,59,60, 50}, {"a one foot beard, ", 25,60,61, 50}, {"a two foot beard, ", 60,60,61, 51}, {"a three foot beard, ", 90,60,61, 53}, {"a four foot beard, ", 100,60,61, 55}, {"and a dark complexion.", 100,61, 0, 50}, {"You have slime green eyes, ", 60,62,63, 50}, {"You have puke yellow eyes, ", 85,62,63, 50}, {"You have blue-bloodshot eyes, ", 99,62,63, 50}, {"You have glowing red eyes, ", 100,62,63, 55}, {"dirty ", 33,63,64, 50}, {"mangy ", 66,63,64, 50}, {"oily ", 100,63,64, 50}, {"sea-weed green hair, ", 33,64,65, 50}, {"bright red hair, ", 66,64,65, 50}, {"dark purple hair, ", 100,64,65, 50}, {"and green ", 25,65,66, 50}, {"and blue ", 50,65,66, 50}, {"and white ", 75,65,66, 50}, {"and black ", 100,65,66, 50}, {"ulcerous skin.", 33,66, 0, 50}, {"scabby skin.", 66,66, 0, 50}, {"leprous skin.", 100,66, 0, 50} }; /* Current stats */ static s16b stat_use[6]; /* * Display the character creation title header. */ static void show_create_header() { put_str("Character Creation", 0, 30); } /* * Choose the character's sex -JWT- */ static void choose_sex(void) { char c; put_str("m) Male", 21, 2); put_str("f) Female", 21, 17); while (1) { put_str("Choose a sex (? for Help, Q to Quit): ", 20, 2); c = inkey(); if (c == 'Q') quit(NULL); if ((c == 'm') || (c == 'M')) { p_ptr->male = TRUE; c_put_str(TERM_L_BLUE, "Male", 3, 15); break; } else if ((c == 'f') || (c == 'F')) { p_ptr->male = FALSE; c_put_str(TERM_L_BLUE, "Female", 3, 15); break; } else if (c == '?') { do_cmd_help("birth.txt"); } else { bell(); } } clear_from(20); } /* * Allows player to select a race -JWT- */ static void choose_race(void) { int j, k, l, m; char c; char out_val[160]; k = 0; l = 2; m = 21; for (j = 0; j < MAX_RACES; j++) { p_ptr->prace = j; rp_ptr = &race_info[p_ptr->prace]; (void)sprintf(out_val, "%c) %s", I2A(j), rp_ptr->title); put_str(out_val, m, l); l += 15; if (l > 70) { l = 2; m++; } } while (1) { put_str("Choose a race (? for Help, Q to Quit): ", 20, 2); c = inkey(); if (c == 'Q') quit(NULL); j = (islower(c) ? A2I(c) : -1); if ((j < MAX_RACES) && (j >= 0)) { p_ptr->prace = j; rp_ptr = &race_info[p_ptr->prace]; c_put_str(TERM_L_BLUE, rp_ptr->title, 4, 15); break; } else if (c == '?') { do_cmd_help("race.txt"); } else { bell(); } } clear_from(20); } /* * Gets a character class -JWT- */ static void choose_class() { int j, k, l, m; int cl[MAX_CLASS]; char c; char out_val[160]; /* Prepare to list */ k = 0; l = 2; m = 21; /* No legal choices yet */ for (j = 0; j < MAX_CLASS; j++) cl[j] = 0; /* Display the legal choices */ for (j = 0; j < MAX_CLASS; j++) { /* Verify legality */ if (rp_ptr->choice & (1L << j)) { p_ptr->pclass = j; cp_ptr = &class_info[p_ptr->pclass]; sprintf(out_val, "%c) %s", I2A(k), cp_ptr->title); put_str(out_val, m, l); cl[k++] = j; l += 15; if (l > 70) { l = 2; m++; } } } /* Get a class */ while (1) { put_str("Choose a class (? for Help, Q to Quit): ", 20, 2); c = inkey(); if (c == 'Q') quit(NULL); j = (islower(c) ? A2I(c) : -1); if ((j < k) && (j >= 0)) { p_ptr->pclass = cl[j]; cp_ptr = &class_info[p_ptr->pclass]; c_put_str(TERM_L_BLUE, cp_ptr->title, 5, 15); break; } else if (c == '?') { do_cmd_help("class.txt"); } else { bell(); } } /* Important -- Choose the magic info */ mp_ptr = &magic_info[p_ptr->pclass]; clear_from(20); } /* * Returns adjusted stat -JK- * Algorithm by -JWT- * * auto_roll is boolean and states maximum changes should be used rather * than random ones to allow specification of higher values to wait for * * The "p_ptr->maximize" code is important -BEN- */ static int adjust_stat(int value, s16b amount) { int i; /* Negative amounts */ if (amount < 0) { /* Apply penalty */ for (i = 0; i < (0 - amount); i++) { if (value >= 18+10) { value -= 10; } else if (value > 18) { value = 18; } else if (value > 3) { value--; } } } /* Positive amounts */ else if (amount > 0) { /* Apply reward */ for (i = 0; i < amount; i++) { if (value < 18) { value++; } else if (p_ptr->maximize) { value += 10; } else if (value < 18+70) { value += 15; } else if (value < 18+90) { value += 6; } else if (value < 18+100) { value++; } } } /* Return the result */ return (value); } /* * Roll for a characters stats * * For efficiency, we include a chunk of "calc_bonuses()". */ static void get_stats(void) { int i, j; int bonus; int dice[18]; /* Roll and verify some stats */ while (TRUE) { /* Roll some dice */ for (j = i = 0; i < 18; i++) { /* Roll the dice */ dice[i] = randint(3 + i % 3); /* Collect the maximum */ j += dice[i]; } /* Verify totals */ if ((j > 42) && (j < 54)) break; } /* Acquire the stats */ for (i = 0; i < 6; i++) { /* Save that value */ p_ptr->stat_max[i] = base_stats[i]; /* Obtain a "bonus" for "race" and "class" */ bonus = rp_ptr->r_adj[i] + cp_ptr->c_adj[i]; /* Variable stat maxes */ if (p_ptr->maximize) { /* Start fully healed */ p_ptr->stat_cur[i] = p_ptr->stat_max[i]; /* Efficiency -- Apply the racial/class bonuses */ stat_use[i] = modify_stat_value(p_ptr->stat_max[i], bonus); } /* Fixed stat maxes */ else { /* Apply the bonus to the stat (somewhat randomly) */ stat_use[i] = adjust_stat(p_ptr->stat_max[i], bonus); /* Save the resulting stat maximum */ p_ptr->stat_cur[i] = p_ptr->stat_max[i] = stat_use[i]; } } } /* * Roll for some info that the auto-roller ignores */ static void get_extra(void) { int i, j, min_value, max_value; /* Level one (never zero!) */ p_ptr->lev = 1; /* Experience factor */ p_ptr->expfact = rp_ptr->r_exp + cp_ptr->c_exp; /* Hitdice */ p_ptr->hitdie = rp_ptr->r_mhp + cp_ptr->c_mhp; /* Minimum hitpoints at highest level */ min_value = (PY_MAX_LEVEL * (p_ptr->hitdie - 1) * 3) / 8; min_value += PY_MAX_LEVEL; /* Maximum hitpoints at highest level */ max_value = (PY_MAX_LEVEL * (p_ptr->hitdie - 1) * 5) / 8; max_value += PY_MAX_LEVEL; /* Pre-calculate level 1 hitdice */ player_hp[0] = p_ptr->hitdie; /* Roll out the hitpoints */ while (TRUE) { /* Roll the hitpoint values */ for (i = 1; i < PY_MAX_LEVEL; i++) { j = randint(p_ptr->hitdie); player_hp[i] = player_hp[i-1] + j; } /* XXX Could also require acceptable "mid-level" hitpoints */ /* Require "valid" hitpoints at highest level */ if (player_hp[PY_MAX_LEVEL-1] < min_value) continue; if (player_hp[PY_MAX_LEVEL-1] > max_value) continue; /* Acceptable */ break; } } /* * Get the racial history, and social class, using the "history charts". */ static void get_history(void) { int i, n, chart, roll, social_class; char *s, *t; char buf[240]; /* Clear the previous history strings */ for (i = 0; i < 4; i++) history[i][0] = '\0'; /* Clear the history text */ buf[0] = '\0'; /* Initial social class */ social_class = randint(4); /* Starting place */ switch (p_ptr->prace) { case RACE_HUMAN: case RACE_DUNADAN: chart = 1; break; case RACE_HALF_ELF: chart = 4; break; case RACE_ELF: chart = 7; break; case RACE_HOBBIT: chart = 10; break; case RACE_GNOME: chart = 13; break; case RACE_DWARF: chart = 16; break; case RACE_HALF_ORC: chart = 19; break; case RACE_HALF_TROLL: chart = 22; break; case RACE_HIGH_ELF: chart = 25; break; default: chart = 0; } /* Process the history */ while (chart) { /* Start over */ i = 0; /* Roll for nobility */ roll = randint(100); /* Access the proper entry in the table */ while ((chart != bg[i].chart) || (roll > bg[i].roll)) i++; /* Acquire the textual history */ (void)strcat(buf, bg[i].info); /* Add in the social class */ social_class += (int)(bg[i].bonus) - 50; /* Enter the next chart */ chart = bg[i].next; } /* Verify social class */ if (social_class > 100) social_class = 100; else if (social_class < 1) social_class = 1; /* Save the social class */ p_ptr->sc = social_class; /* Skip leading spaces */ for (s = buf; *s == ' '; s++) ; /* Get apparent length */ n = strlen(s); /* Kill trailing spaces */ while ((n > 0) && (s[n-1] == ' ')) s[--n] = '\0'; /* Start at first line */ i = 0; /* Collect the history */ while (TRUE) { /* Extract remaining length */ n = strlen(s); /* All done */ if (n < 60) { /* Save one line of history */ strcpy(history[i++], s); /* All done */ break; } /* Find a reasonable break-point */ for (n = 60; ((n > 0) && (s[n-1] != ' ')); n--) ; /* Save next location */ t = s + n; /* Wipe trailing spaces */ while ((n > 0) && (s[n-1] == ' ')) s[--n] = '\0'; /* Save one line of history */ strcpy(history[i++], s); /* Start next line */ for (s = t; *s == ' '; s++) ; } } /* * Computes character's age, height, and weight */ static void get_ahw(void) { /* Calculate the age */ p_ptr->age = rp_ptr->b_age + randint(rp_ptr->m_age); /* Calculate the height/weight for males */ if (p_ptr->male) { p_ptr->ht = randnor(rp_ptr->m_b_ht, rp_ptr->m_m_ht); p_ptr->wt = randnor(rp_ptr->m_b_wt, rp_ptr->m_m_wt); } /* Calculate the height/weight for females */ else { p_ptr->ht = randnor(rp_ptr->f_b_ht, rp_ptr->f_m_ht); p_ptr->wt = randnor(rp_ptr->f_b_wt, rp_ptr->f_m_wt); } } /* * Clear all the global "character" data */ static void player_wipe() { int i; /* Hack -- zero the struct */ WIPE(p_ptr, player_type); /* Wipe the history */ for (i = 0; i < 4; i++) { strcpy(history[i], ""); } /* No weight */ total_weight = 0; /* No items */ inven_cnt = 0; equip_cnt = 0; /* Clear the inventory */ for (i = 0; i < INVEN_TOTAL; i++) { invwipe(&inventory[i]); } /* Start with no artifacts made yet */ for (i = 0; i < MAX_A_IDX; i++) { artifact_type *a_ptr = &a_info[i]; a_ptr->cur_num = 0; } /* Start with no quests */ for (i = 0; i < MAX_Q_IDX; i++) { q_list[i].level = 0; } /* Add the first quest */ q_list[0].level = 50; /* Add the second quest */ q_list[1].level = 80; /* Add the third quest */ q_list[2].level = 99; /* Add the final quest */ q_list[3].level = 100; /* Reset the "objects" */ for (i = 1; i < MAX_K_IDX; i++) { object_kind *k_ptr = &k_info[i]; /* Reset "tried" */ k_ptr->tried = FALSE; /* Reset "aware" */ k_ptr->aware = FALSE; } /* Reset the "monsters" */ for (i = 1; i < MAX_R_IDX; i++) { monster_race *r_ptr = &r_info[i]; /* Hack -- Reset the counter */ r_ptr->cur_num = 0; /* Hack -- Reset the max counter */ r_ptr->max_num = 100; /* Hack -- Reset the max counter */ if (r_ptr->flags1 & RF1_UNIQUE) r_ptr->max_num = 1; /* Clear player kills */ r_ptr->r_pkills = 0; } /* Hack -- no ghosts */ r_info[MAX_R_IDX-1].max_num = 0; /* Hack -- Well fed player */ p_ptr->food = PY_FOOD_FULL - 1; /* Wipe the spells */ for (i = 0; i < 64; i++) { spell_learned[i] = FALSE; spell_worked[i] = FALSE; spell_forgotten[i] = FALSE; spell_order[i] = 99; } /* Assume no winning game */ total_winner = FALSE; /* Assume no panic save */ panic_save = 0; /* Assume no cheating */ noscore = 0; /* Unset the cheating options */ cheat_peek = FALSE; cheat_hear = FALSE; cheat_room = FALSE; cheat_xtra = FALSE; cheat_know = FALSE; cheat_live = FALSE; } /* * Each player starts out with a few items, given as tval/sval pairs. * In addition, he always has some food and a few torches. */ static byte player_init[MAX_CLASS][3][2] = { { /* Warrior */ { TV_SHIELD, SV_SMALL_METAL_SHIELD }, { TV_SWORD, SV_BROAD_SWORD }, { TV_HARD_ARMOR, SV_CHAIN_MAIL } }, { /* Mage */ { TV_MAGIC_BOOK, 0 }, { TV_SWORD, SV_DAGGER }, { TV_SCROLL, SV_SCROLL_WORD_OF_RECALL } }, { /* Priest */ { TV_PRAYER_BOOK, 0 }, { TV_HAFTED, SV_MACE }, { TV_POTION, SV_POTION_HEALING } }, { /* Rogue */ { TV_MAGIC_BOOK, 0 }, { TV_SWORD, SV_SMALL_SWORD }, { TV_SOFT_ARMOR, SV_SOFT_LEATHER_ARMOR } }, { /* Ranger */ { TV_MAGIC_BOOK, 0 }, { TV_SWORD, SV_BROAD_SWORD }, { TV_BOW, SV_LONG_BOW } }, { /* Paladin */ { TV_PRAYER_BOOK, 0 }, { TV_SWORD, SV_BROAD_SWORD }, { TV_SCROLL, SV_SCROLL_PROTECTION_FROM_EVIL } } }; /* * Init players with some belongings * * Having an item makes the player "aware" of its purpose. */ static void player_outfit() { int i, tv, sv; object_type forge; object_type *i_ptr = &forge; /* Hack -- Give the player some food */ i_ptr->invcopy(lookup_kind(TV_FOOD, SV_FOOD_RATION)); i_ptr->set_number(5); i_ptr->object_aware(); i_ptr->object_known(); inven_carry(i_ptr); /* Hack -- Give the player some torches */ i_ptr->invcopy(lookup_kind(TV_LITE, SV_LITE_TORCH)); i_ptr->set_number(5); i_ptr->set_pval(2500); i_ptr->object_aware(); i_ptr->object_known(); inven_carry(i_ptr); /* Hack -- Give the player three useful objects */ for (i = 0; i < 3; i++) { tv = player_init[p_ptr->pclass][i][0]; sv = player_init[p_ptr->pclass][i][1]; i_ptr->invcopy(lookup_kind(tv, sv)); i_ptr->object_aware(); i_ptr->object_known(); inven_carry(i_ptr); } } /* * Create a character. Then wait for a moment. * * Note that we may be called with "junk" leftover in the various * fields, so we must be sure to clear them first. */ void player_birth() { int i; char c, out_val[40]; bool use_history; int points_used; start_over: /* Clear old information */ player_wipe(); /* Clear some flags */ use_history = FALSE; /* Clear the screen */ clear_screen(); /* Title everything */ show_create_header(); put_str("Name :", 2, 1); put_str("Sex :", 3, 1); put_str("Race :", 4, 1); put_str("Class :", 5, 1); put_str("Preserve :", 6, 1); put_str("Maximize :", 7, 1); /* Dump the default name */ c_put_str(TERM_L_BLUE, player_name, 2, 15); /* Display some helpful information XXX XXX XXX */ /* Choose sex, race, class */ choose_sex(); choose_race(); choose_class(); /* Ask about "preserve" mode */ while (1) { put_str("Use preserve mode? (Y/N/S/Q/?) ", 20, 2); c = inkey(); if (c == ESCAPE) break; else if (strchr("ynYN", c)) break; else if (c == 'S') goto start_over; else if (c == 'Q') quit(NULL); else if (c == '?') do_cmd_help("maxpres.txt"); else bell(); } /* XXX Accept preserve mode */ p_ptr->preserve = ((c == 'Y') || (c == 'y')); /* Add it to the screen */ if (p_ptr->preserve) { c_put_str(TERM_L_BLUE, "Yes", 6, 15); } else { c_put_str(TERM_L_BLUE, "No", 6, 15); } /* Clear */ clear_from(20); /* Ask about maximize mode */ while (1) { put_str("Use maximize mode? (Y/N/S/Q/?) ", 20, 2); c = inkey(); if (c == ESCAPE) break; else if (strchr("ynYN", c)) break; else if (c == 'S') goto start_over; else if (c == 'Q') quit(NULL); else if (c == '?') do_cmd_help("maxpres.txt"); else bell(); } /* XXX Accept maximize mode */ p_ptr->maximize = ((c == 'Y') || (c == 'y')); /* Add it to the screen */ if (p_ptr->maximize) { c_put_str(TERM_L_BLUE, "Yes", 7, 15); } else { c_put_str(TERM_L_BLUE, "No", 7, 15); } /* Clear */ clear_from(20); /* Set up base stats */ for (i = 0; i < 6; i++) base_stats[i] = 12; /* Roll for base hitpoints */ get_extra(); /* Roll for age/height/weight */ get_ahw(); /* Roll for social class */ get_history(); /* Set gold */ p_ptr->au = 100; /* Start with the "Misc" data */ use_history = FALSE; /* Actually Generate */ while (TRUE) { /* No autoroller */ get_stats(); /* Calculate the bonuses, hitpoints, and mana */ p_ptr->update |= PU_BONUS | PU_HP | PU_MANA; /* Update stuff */ update_stuff(); /* "Heal up" the player */ p_ptr->csp = p_ptr->msp; p_ptr->chp = p_ptr->mhp; /* Display the player */ display_player(use_history, FALSE); /* Add "character creation" header */ show_create_header(); /* Calculate points used */ points_used = 0; for (i = 0; i < 6; i++) points_used += stat_points[base_stats[i]]; sprintf(out_val, "Points used: %d of 20", points_used); /* Prepare a prompt (must squeeze everything in) */ Term_putstr(2, 21, -1, TERM_WHITE, "'S'/'s' to modify STR; "); Term_addstr(-1, TERM_WHITE, "'I'/'i' to modify INT; "); Term_addstr(-1, TERM_WHITE, "'W'/'w' to modify WIS"); Term_putstr(2, 22, -1, TERM_WHITE, "'D'/'d' to modify DEX; "); Term_addstr(-1, TERM_WHITE, "'C'/'c' to modify CON; "); Term_addstr(-1, TERM_WHITE, "'R'/'r' to modify CHR"); Term_putstr(2, 23, -1, (points_used <= 20) ? TERM_WHITE : TERM_YELLOW, out_val); Term_putstr(29, 23, -1, TERM_WHITE, "Hit "); if (use_history) Term_addstr(-1, TERM_WHITE, "'H' for Misc., "); else Term_addstr(-1, TERM_WHITE, "'H' for History, "); Term_addstr(-1, TERM_WHITE, "or ESC to Accept: "); /* Prompt and get a command */ c = inkey(); /* Escape accepts the roll */ if (c == ESCAPE) { if (points_used <= 20) break; else { bell(); continue; } } /* Other things */ switch (c) { /* Modify STR */ case 'S': if (base_stats[0] < 17) base_stats[0]++; break; case 's': if (base_stats[0] > 8) base_stats[0]--; break; /* Modify INT */ case 'I': if (base_stats[1] < 17) base_stats[1]++; break; case 'i': if (base_stats[1] > 8) base_stats[1]--; break; /* Modify WIS */ case 'W': if (base_stats[2] < 17) base_stats[2]++; break; case 'w': if (base_stats[2] > 8) base_stats[2]--; break; /* Modify DEX */ case 'D': if (base_stats[3] < 17) base_stats[3]++; break; case 'd': if (base_stats[3] > 8) base_stats[3]--; break; /* Modify CON */ case 'C': if (base_stats[4] < 17) base_stats[4]++; break; case 'c': if (base_stats[4] > 8) base_stats[4]--; break; /* Modify CHR */ case 'R': if (base_stats[5] < 17) base_stats[5]++; break; case 'r': if (base_stats[5] > 8) base_stats[5]--; break; /* Print the History/MiscData */ case 'H': case 'h': use_history = !use_history; break; /* Help */ case '?': do_cmd_help("birth.txt"); break; /* Abort game */ case 'Q': quit(NULL); break; default: /* Warning */ bell(); } } /* Clear from line 20 down */ clear_from(20); /* Get a name, recolor it, prepare savefile */ get_name(); /* Prompt for it */ prt("[ESC to continue, 'S' to start over, 'Q' to suicide]", 23, 10); /* Get a key */ c = inkey(); /* Hack -- Start over */ if (c == 'S') goto start_over; /* Allow Total Suicide */ if (c == 'Q') quit(NULL); /* Note player birth in the message recall */ message_add(" "); message_add(" "); message_add("===================="); message_add(" "); message_add(" "); /* Hack -- outfit the player */ player_outfit(); /* Init the stores */ store_init(); /* Maintain the stores (ten times) */ for (i = 0; i < 10; i++) store_maint(); }