diff --git a/dat/opthelp b/dat/opthelp index d36e5228b..1fcb803d9 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -56,6 +56,7 @@ pushweapon when wielding a new weapon, put your previously [False] quick_farsight usually skip the chance to browse the map when [False] randomly triggered clairvoyance takes place rawio allow the use of raw I/O [False] +reroll allow rerolling of starting inventory [False] rest_on_space count the space bar as a rest character [False] safe_pet prevent you from (knowingly) attacking your pet(s) [True] safe_wait require use of 'm' prefix before '.' or 's' to [True] diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 95bd7be35..72d3f3be3 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -4556,6 +4556,16 @@ If \f(CRrace\fP is not specified, there is no default value; player will be prompted unless role forces a choice for race. Cannot be set with the \(oq\f(CRO\fP\(cq command. Persistent. +.lp reroll +Allows rerolling your character's starting inventory and attributes (default +false). Persistent. +.lp "" +Note that rerolling your character is not a recommended way to play if aiming +merely to win (a lucky start has a much smaller influence on whether or not +you win the game than your actions later in the game). This option exists +partly as an acknowledgement that some players will insist on doing so anyway, +and partly because rerolling may be necessary for certain types of challenge +games. .lp rest_on_space Make the space bar a synonym for the \(oq.\(cq (#wait) command (default off). Persistent. diff --git a/include/extern.h b/include/extern.h index 831e209db..59e7188af 100644 --- a/include/extern.h +++ b/include/extern.h @@ -258,6 +258,7 @@ extern void free_ebones(struct monst *) NONNULLARG1; /* ### botl.c ### */ +extern char *get_strength_str(void); extern char *do_statusline1(void); extern void check_gold_symbol(void); extern char *do_statusline2(void); @@ -2406,6 +2407,7 @@ extern int query_category(const char *, struct obj *, int, menu_item **, int) NO /* dotypeinv() call query_objlist with NULL arg1 */ extern int query_objlist(const char *, struct obj **, int, menu_item **, int, boolean(*)(struct obj *)) NONNULLARG24; +extern boolean reroll_menu(void); extern struct obj *pick_obj(struct obj *) NONNULLARG1; extern void encumber_msg(void); extern int container_at(coordxy, coordxy, boolean); diff --git a/include/optlist.h b/include/optlist.h index b0bc715f3..0625b1e51 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -608,6 +608,9 @@ static int optfn_##a(int, int, boolean, char *, char *); Off, No, No, No, NoAlias, (boolean *) 0, Term_False, (char *)0) #endif + NHOPTB(reroll, Advanced, 0, opt_in, set_in_config, + Off, Yes, No, No, NoAlias, &u.uroleplay.reroll, Term_False, + "allow rerolling of starting inventory and items") NHOPTB(rest_on_space, Advanced, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, &flags.rest_on_space, Term_False, "space bar is bound to the rest-command") diff --git a/include/patchlevel.h b/include/patchlevel.h index 42485fef6..8034d40d4 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -17,7 +17,7 @@ * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ -#define EDITLEVEL 131 +#define EDITLEVEL 132 /* * Development status possibilities. diff --git a/include/you.h b/include/you.h index efa1baa69..a073e5c57 100644 --- a/include/you.h +++ b/include/you.h @@ -163,11 +163,13 @@ struct u_conduct { /* number of times... */ }; struct u_roleplay { - boolean blind; /* permanently blind */ - boolean nudist; /* has not worn any armor, ever */ - boolean deaf; /* permanently deaf */ - boolean pauper; /* no starting inventory */ - long numbones; /* # of bones files loaded */ + boolean blind; /* permanently blind */ + boolean nudist; /* has not worn any armor, ever */ + boolean deaf; /* permanently deaf */ + boolean pauper; /* no starting inventory */ + boolean reroll; /* starting inventory/attr rerolling enabled */ + long numbones; /* # of bones files loaded */ + long numrerolls; /* # of rerolls used */ }; /*** Unified structure containing role information ***/ diff --git a/src/allmain.c b/src/allmain.c index 6ced3e372..4f5e8cbb6 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -809,11 +809,16 @@ newgame(void) (void) makedog(); u_init_inventory_attrs(); - u_init_skills_discoveries(); docrt(); + flush_screen(1); + bot(); + while (u.uroleplay.reroll && reroll_menu()) { + u_init_inventory_attrs(); + bot(); + } + u_init_skills_discoveries(); if (flags.legacy) { - flush_screen(1); com_pager(u.uroleplay.pauper ? "pauper_legacy" : "legacy"); } diff --git a/src/botl.c b/src/botl.c index f3ad98aa5..f90812f53 100644 --- a/src/botl.c +++ b/src/botl.c @@ -19,9 +19,8 @@ const char *const enc_stat[] = { staticfn const char *rank(void); staticfn void bot_via_windowport(void); staticfn void stat_update_time(void); -staticfn char *get_strength_str(void); -staticfn char * +char * get_strength_str(void) { static char buf[32]; diff --git a/src/insight.c b/src/insight.c index 9f0f71059..9f3763619 100644 --- a/src/insight.c +++ b/src/insight.c @@ -2109,6 +2109,12 @@ show_conduct(int final) if (u.uroleplay.pauper) enl_msg(You_, gi.invent ? "started" : "are", "started out", " without possessions", ""); + if (u.uroleplay.reroll) { + Sprintf(buf, "rerolled your character %ld time%s", + u.uroleplay.numrerolls, plur(u.uroleplay.numrerolls)); + you_have_X(buf); + } + /* nudist is far more than a subset of possessionless, and a much more impressive accomplishment, but showing "started out without possessions" before "faithfully nudist" looks more logical */ diff --git a/src/invent.c b/src/invent.c index abb7d7c39..ddd7ffefb 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2522,6 +2522,81 @@ askchain( return cnt; } + +/* The menu for rerolling attributes and inventory. + + This is similar to the other inventory menus, but simpler to help it fit on + the screen (there's more text around it and rerolling is difficult if you + can't see the whole list at once). + + Returns TRUE (and increases numrerolls) if a reroll was requested. */ +boolean +reroll_menu(void) +{ + winid win; + anything any; + menu_item *pick_list = NULL; + struct obj *otmp; + int tmpglyph; + glyph_info tmpglyphinfo; + char option; + char buf[BUFSZ]; + + win = create_nhwindow(NHW_MENU); + start_menu(win, MENU_BEHAVE_STANDARD); + any = cg.zeroany; + + any.a_char = 'n'; + add_menu(win, &nul_glyphinfo, &any, flags.lootabc ? 0 : 'p', 0, + ATR_NONE, NO_COLOR, "start the game with this character", + MENU_ITEMFLAGS_NONE); + any.a_char = 'y'; + add_menu(win, &nul_glyphinfo, &any, flags.lootabc ? 0 : 'r', 0, + ATR_NONE, NO_COLOR, "reroll another character", + MENU_ITEMFLAGS_NONE); + any.a_char = 0; + add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, NO_COLOR, "", + MENU_ITEMFLAGS_NONE); + + ++gd.distantname; /* avoid adding items to discoveries */ + ++iflags.override_ID; /* identify them */ + for (otmp = gi.invent; otmp; otmp = otmp->nobj) { + tmpglyph = obj_to_glyph(otmp, rn2_on_display_rng); + map_glyphinfo(0, 0, tmpglyph, 0U, &tmpglyphinfo); + add_menu(win, &tmpglyphinfo, &any, 0, 0, + ATR_NONE, NO_COLOR, doname(otmp), MENU_ITEMFLAGS_NONE); + } + --iflags.override_ID; + --gd.distantname; + + add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, NO_COLOR, "", + MENU_ITEMFLAGS_NONE); + Sprintf(buf, "St:%s Dx:%-1d Co:%-1d In:%-1d Wi:%-1d Ch:%-1d", + get_strength_str(), + ACURR(A_DEX), ACURR(A_CON), ACURR(A_INT), ACURR(A_WIS), + ACURR(A_CHA)); + add_menu(win, &nul_glyphinfo, &any, 0, 0, ATR_NONE, NO_COLOR, + buf, MENU_ITEMFLAGS_NONE); + + end_menu(win, "Reroll this character?"); + if (select_menu(win, PICK_ONE, &pick_list) > 0) { + option = pick_list[0].item.a_char; + free((genericptr_t) pick_list); + } else { + /* user closed the menu without selecting; unclear what their choice + is here so ask again; but (e.g. for hangup handling) stop asking if + the user cancels out again */ + option = y_n("Reroll this character?"); + } + destroy_nhwindow(win); + + if (option == 'y') { + ++u.uroleplay.numrerolls; + return TRUE; + } + return FALSE; +} + /* * Object identification routines: */ diff --git a/src/topten.c b/src/topten.c index cb968a726..d6567ea08 100644 --- a/src/topten.c +++ b/src/topten.c @@ -385,6 +385,7 @@ writexlentry(FILE *rfile, struct toptenentry *tt, int how) Fprintf(rfile, "%cwish_cnt=%ld", XLOG_SEP, u.uconduct.wishes); Fprintf(rfile, "%carti_wish_cnt=%ld", XLOG_SEP, u.uconduct.wisharti); Fprintf(rfile, "%cbones=%ld", XLOG_SEP, u.uroleplay.numbones); + Fprintf(rfile, "%crerolls=%ld", XLOG_SEP, u.uroleplay.numrerolls); Fprintf(rfile, "\n"); #undef XLOG_SEP } @@ -400,6 +401,8 @@ encodexlogflags(void) e |= 1L << 1; if (!u.uroleplay.numbones) e |= 1L << 2; + if (u.uroleplay.reroll) + e |= 1L << 3; return e; } @@ -601,6 +604,7 @@ encode_extended_conducts(char *buf) add_achieveX(buf, "pauper", u.uroleplay.pauper); add_achieveX(buf, "bonesless", !flags.bones); add_achieveX(buf, "petless", !u.uconduct.pets); + add_achieveX(buf, "unrerolled", !u.uroleplay.reroll); return buf; }