1
0
Fork 0
mirror of https://codeberg.org/noisytoot/notnotdnethack.git synced 2024-09-19 22:14:48 +01:00
notnotdnethack/win/curses/cursinit.c

1040 lines
34 KiB
C

/* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/
#include "curses.h"
#include "hack.h"
#include "wincurs.h"
#include "cursinit.h"
#include "patchlevel.h"
#include <ctype.h>
/* Global curses variables extern'd in wincurs.h */
boolean counting;
int orig_cursor; /* Preserve initial cursor state */
int term_rows, term_cols; /* size of underlying terminal */
WINDOW *base_term; /* underlying terminal window */
WINDOW *mapwin, *statuswin, *messagewin; /* Main windows */
/* Initialization and startup functions for curses interface */
/* Private declarations */
static void set_window_position(int *, int *, int *, int *, int,
int *, int *, int *, int *, int,
int, int);
/* array to save initial terminal colors for later restoration */
extern struct rgb_color_option *setcolor_opts;
extern struct rgb_color_option *resetcolor_opts;
typedef struct nhrgb_type {
short r;
short g;
short b;
} nhrgb;
nhrgb orig_darkgray;
nhrgb default_colors[16] = {
{50 , 50 , 50 }, // black
{1000, 0 , 0 }, // red
{75 , 630 , 55 }, // green
{480 , 290 , 0 }, // yellow (brown)
{0 , 215 , 855 }, // blue
{530 , 90 , 600 }, // magenta (purple)
{215 , 560 , 823 }, // cyan
{800 , 800 , 800 }, // white
{600 , 600 , 600 }, // bright black (no color)
{1000, 500 , 0 }, // bright red (orange)
{0 , 1000, 0 }, // bright green
{1000, 1000, 0 }, // bright yellow (yellow)
{0 , 0 , 1000}, // bright blue
{1000, 0 , 1000}, // bright magenta
{0 , 1000, 1000}, // bright cyan
{1000, 1000, 1000} // bright white
};
nhrgb orig_colors[16];
/* Banners used for an optional ASCII splash screen */
#define DNETHACK_SPLASH_A \
" _ _ _ _ _ _ _ "
#define DNETHACK_SPLASH_B \
" | || \\ | | | | | | | | | | "
#define DNETHACK_SPLASH_C \
" __| || \\| | ___ | |_ | |__| | __ _ ___ | | __"
#define DNETHACK_SPLASH_D \
" / _` || . ` | / _ \\| __|| __ | / _` | / __|| |/ /"
#define DNETHACK_SPLASH_E \
"| (_| || |\\ || __/| |_ | | | || (_| || (__ | < "
#define DNETHACK_SPLASH_F \
" \\__,_||_| \\_| \\___| \\__||_| |_| \\__,_| \\___||_|\\_\\"
/* win* is size and placement of window to change, x/y/w/h is baseline which can
decrease depending on alignment of win* in orientation.
Negative minh/minw: as much as possible, but at least as much as specified. */
static void
set_window_position(int *winx, int *winy, int *winw, int *winh, int orientation,
int *x, int *y, int *w, int *h, int border_space,
int minh, int minw)
{
*winw = *w;
*winh = *h;
/* Set window height/width */
if (orientation == ALIGN_TOP || orientation == ALIGN_BOTTOM) {
if (minh < 0) {
*winh = (*h - ROWNO - border_space);
if (-minh > *winh)
*winh = -minh;
} else
*winh = minh;
*h -= (*winh + border_space);
} else {
if (minw < 0) {
*winw = (*w - COLNO - border_space);
if (-minw > *winw)
*winw = -minw;
} else
*winw = minw;
*w -= (*winw + border_space);
}
*winx = *w + border_space + *x;
*winy = *h + border_space + *y;
/* Set window position */
if (orientation != ALIGN_RIGHT) {
*winx = *x;
if (orientation == ALIGN_LEFT)
*x += *winw + border_space;
}
if (orientation != ALIGN_BOTTOM) {
*winy = *y;
if (orientation == ALIGN_TOP)
*y += *winh + border_space;
}
}
/* Create the "main" nonvolatile windows used by nethack */
void
curses_create_main_windows(void)
{
int min_message_height = 1;
int message_orientation = 0;
int status_orientation = 0;
int border_space = 0;
int hspace = term_cols - 80;
boolean borders = FALSE;
switch (iflags.wc2_windowborders) {
case 1: /* On */
borders = TRUE;
break;
case 2: /* Off */
borders = FALSE;
break;
case 3: /* Auto */
if ((term_cols > 81) && (term_rows > 25)) {
borders = TRUE;
}
break;
default:
borders = FALSE;
}
if (borders) {
border_space = 2;
hspace -= border_space;
}
if ((term_cols - border_space) < COLNO) {
min_message_height++;
}
/* Determine status window orientation */
if (!iflags.wc_align_status || (iflags.wc_align_status == ALIGN_TOP)
|| (iflags.wc_align_status == ALIGN_BOTTOM)) {
if (!iflags.wc_align_status) {
iflags.wc_align_status = ALIGN_BOTTOM;
}
status_orientation = iflags.wc_align_status;
} else { /* left or right alignment */
/* Max space for player name and title horizontally */
if ((hspace >= 26) && (term_rows >= 24)) {
status_orientation = iflags.wc_align_status;
hspace -= (26 + border_space);
} else {
status_orientation = ALIGN_BOTTOM;
}
}
/* Determine message window orientation */
if (!iflags.wc_align_message || (iflags.wc_align_message == ALIGN_TOP)
|| (iflags.wc_align_message == ALIGN_BOTTOM)) {
if (!iflags.wc_align_message) {
iflags.wc_align_message = ALIGN_TOP;
}
message_orientation = iflags.wc_align_message;
} else { /* left or right alignment */
if ((hspace - border_space) >= 25) { /* Arbitrary */
message_orientation = iflags.wc_align_message;
} else {
message_orientation = ALIGN_TOP;
}
}
/* Figure out window positions and placements. Status and message area can be aligned
based on configuration. The priority alignment-wise is: status > msgarea > game.
Define everything as taking as much space as possible and shrink/move based on
alignment positions. */
int message_x = 0;
int message_y = 0;
int status_x = 0;
int status_y = 0;
int inv_x = 0;
int inv_y = 0;
int map_x = 0;
int map_y = 0;
int message_height = 0;
int message_width = 0;
int status_height = 0;
int status_width = 0;
int inv_height = 0;
int inv_width = 0;
int map_height = (term_rows - border_space);
int map_width = (term_cols - border_space);
boolean status_vertical = FALSE;
boolean msg_vertical = FALSE;
if (status_orientation == ALIGN_LEFT ||
status_orientation == ALIGN_RIGHT)
status_vertical = TRUE;
if (message_orientation == ALIGN_LEFT ||
message_orientation == ALIGN_RIGHT)
msg_vertical = TRUE;
int statusheight = 3;
if (!iflags.classic_status && iflags.statuslines >= 4)
statusheight = 4;
if (iflags.classic_status && iflags.statuslines <= 2)
statusheight = 2;
/* Vertical windows have priority. Otherwise, priotity is:
status > inv > msg */
if (status_vertical)
set_window_position(&status_x, &status_y, &status_width, &status_height,
status_orientation, &map_x, &map_y, &map_width, &map_height,
border_space, statusheight, 26);
if (flags.perm_invent) {
/* Take up all width unless msgbar is also vertical. */
int width = -25;
if (msg_vertical)
width = 25;
set_window_position(&inv_x, &inv_y, &inv_width, &inv_height,
ALIGN_RIGHT, &map_x, &map_y, &map_width, &map_height,
border_space, -1, width);
}
if (msg_vertical)
set_window_position(&message_x, &message_y, &message_width, &message_height,
message_orientation, &map_x, &map_y, &map_width, &map_height,
border_space, -1, -25);
/* Now draw horizontal windows */
if (!status_vertical)
set_window_position(&status_x, &status_y, &status_width, &status_height,
status_orientation, &map_x, &map_y, &map_width, &map_height,
border_space, statusheight, 26);
if (!msg_vertical)
set_window_position(&message_x, &message_y, &message_width, &message_height,
message_orientation, &map_x, &map_y, &map_width, &map_height,
border_space, -1, -25);
if (map_width > COLNO)
map_width = COLNO;
if (map_height > ROWNO)
map_height = ROWNO;
if (curses_get_nhwin(STATUS_WIN)) {
curses_del_nhwin(STATUS_WIN);
curses_del_nhwin(MESSAGE_WIN);
curses_del_nhwin(MAP_WIN);
curses_del_nhwin(INV_WIN);
clear();
}
curses_add_nhwin(STATUS_WIN, status_height, status_width, status_y,
status_x, status_orientation, borders);
curses_add_nhwin(MESSAGE_WIN, message_height, message_width, message_y,
message_x, message_orientation, borders);
if (flags.perm_invent)
curses_add_nhwin(INV_WIN, inv_height, inv_width, inv_y, inv_x,
ALIGN_RIGHT, borders);
curses_add_nhwin(MAP_WIN, map_height, map_width, map_y, map_x, 0, borders);
refresh();
curses_refresh_nethack_windows();
if (iflags.window_inited) {
curses_update_stats();
if (flags.perm_invent)
curses_update_inventory();
} else {
iflags.window_inited = TRUE;
}
}
/* Initialize curses colors to colors used by NetHack */
void
curses_init_nhcolors(void)
{
if (has_colors()) {
use_default_colors();
int i, j;
int cnum = COLORS >= 16 ? 16 : 8;
int clr_remap[16] = {
COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
COLOR_BLUE,
COLOR_MAGENTA, COLOR_CYAN, -1, COLOR_WHITE,
COLOR_RED + 8, COLOR_GREEN + 8, COLOR_YELLOW + 8,
COLOR_BLUE + 8,
COLOR_MAGENTA + 8, COLOR_CYAN + 8, COLOR_WHITE + 8
};
/* standard colors */
for (i=0; i < cnum; i++) {
init_pair(i+1, clr_remap[i], -1);
}
/* with backgrounds */
for (i=0; i < cnum; i++) {
for (j=0; j < cnum; j++) {
if (i != j)
init_pair(j + i*cnum + cnum + 1, clr_remap[j], clr_remap[i]);
else
init_pair(j + i*cnum + cnum + 1, COLOR_BLACK, clr_remap[j]);
}
}
if (can_change_color()) {
for (int nclr = 0; nclr < cnum; nclr++){
color_content(clr_remap[nclr], &(orig_colors[nclr].r), &(orig_colors[nclr].g), &(orig_colors[nclr].b));
if (iflags.classic_colors == TRUE)
init_color(clr_remap[nclr], default_colors[nclr].r, default_colors[nclr].g, default_colors[nclr].b);
}
for (struct rgb_color_option* curr = setcolor_opts; curr; curr = curr->next){
init_color(curr->color, curr->r, curr->g, curr->b);
}
# ifdef USE_DARKGRAY
if (COLORS > 16) {
color_content(CURSES_DARK_GRAY, &orig_darkgray.r,
&orig_darkgray.g, &orig_darkgray.b);
init_color(CURSES_DARK_GRAY, 300, 300, 300);
/* just override black colorpair entry here */
init_pair(1, CURSES_DARK_GRAY, -1);
}
# endif
}
}
}
/* Allow player to pick character's role, race, gender, and alignment.
Borrowed from the Gnome window port. */
void
curses_choose_character(void)
{
int n, i, sel, count_off, pick4u;
int count = 0;
int cur_character = 0;
const char **choices;
int *pickmap;
char *prompt;
char pbuf[QBUFSZ];
char choice[QBUFSZ];
char tmpchoice[QBUFSZ];
#ifdef TUTORIAL_MODE
winid win;
anything any;
menu_item *selected = 0;
#endif
prompt = build_plselection_prompt(pbuf, QBUFSZ, flags.initrole,
flags.initrace, flags.descendant, flags.initgend,
flags.initalign);
/* This part is irritating: we have to strip the choices off of
the string and put them in a separate string in order to use
curses_character_input_dialog for this prompt. */
while (cur_character != '[') {
cur_character = prompt[count];
count++;
}
count_off = count;
while (cur_character != ']') {
tmpchoice[count - count_off] = prompt[count];
count++;
cur_character = prompt[count];
}
tmpchoice[count - count_off] = '\0';
lcase(tmpchoice);
while (!isspace(prompt[count_off])) {
count_off--;
}
prompt[count_off] = '\0';
sprintf(choice, "%s%c", tmpchoice, '\033');
if (strchr(tmpchoice, 't')) { /* Tutorial mode */
mvaddstr(0, 1, "New? Press t to enter a tutorial.");
}
/* Add capital letters as choices that aren't displayed */
for (count = 0; tmpchoice[count]; count++) {
tmpchoice[count] = toupper(tmpchoice[count]);
}
strcat(choice, tmpchoice);
/* prevent an unnecessary prompt */
rigid_role_checks();
if (!flags.randomall &&
(flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE ||
flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {
pick4u = tolower(curses_character_input_dialog(prompt, choice, 'y'));
} else {
pick4u = 'y';
}
if (pick4u == 'q') { /* Quit or cancelled */
clearlocks();
curses_bail(0);
}
if (pick4u == 'y') {
flags.randomall = TRUE;
}
#ifdef TUTORIAL_MODE
else if (pick4u == 't') { /* Tutorial mode in UnNetHack */
clear();
mvaddstr(0, 1, "Choose a character");
refresh();
win = curses_get_wid(NHW_MENU);
curses_create_nhmenu(win);
any.a_int = 1;
curses_add_menu(win, NO_GLYPH, &any, 'v', 0, ATR_NONE,
"lawful female dwarf Valkyrie (uses melee and thrown weapons)",
MENU_UNSELECTED);
any.a_int = 2;
curses_add_menu(win, NO_GLYPH, &any, 'w', 0, ATR_NONE,
"chaotic male elf Wizard (relies mostly on spells)",
MENU_UNSELECTED);
any.a_int = 3;
curses_add_menu(win, NO_GLYPH, &any, 'R', 0, ATR_NONE,
"neutral female human Ranger (good with ranged combat)",
MENU_UNSELECTED);
any.a_int = 4;
curses_add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE,
"quit", MENU_UNSELECTED);
curses_end_menu(win, "What character do you want to try?");
n = curses_select_menu(win, PICK_ONE, &selected);
destroy_nhwindow(win);
if (n != 1 || selected[0].item.a_int == 4) {
clearlocks();
curses_bail(0);
}
switch (selected[0].item.a_int) {
case 1:
flags.initrole = str2role("Valkyrie");
flags.initrace = str2race("dwarf");
flags.initgend = str2gend("female");
flags.initalign = str2align("lawful");
break;
case 2:
flags.initrole = str2role("Wizard");
flags.initrace = str2race("elf");
flags.initgend = str2gend("male");
flags.initalign = str2align("chaotic");
break;
case 3:
flags.initrole = str2role("Ranger");
flags.initrace = str2race("human");
flags.initgend = str2gend("female");
flags.initalign = str2align("neutral");
break;
default:
panic("Impossible menu selection");
break;
}
free((void *) selected);
selected = 0;
flags.tutorial = 1;
}
#endif
clear();
refresh();
if (!flags.randomall && flags.initrole < 0) {
/* select a role */
for (n = 0; roles[n].name.m; n++)
continue;
choices = (const char **) alloc(sizeof (char *) * (n + 1));
pickmap = (int *) alloc(sizeof (int) * (n + 1));
for (;;) {
for (n = 0, i = 0; roles[i].name.m; i++) {
if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) {
if (flags.initgend >= 0 && flags.female && roles[i].name.f)
choices[n] = roles[i].name.f;
else
choices[n] = roles[i].name.m;
pickmap[n++] = i;
}
}
if (n > 0)
break;
else if (flags.initalign >= 0)
flags.initalign = -1; /* reset */
else if (flags.initgend >= 0)
flags.initgend = -1;
else if (flags.initrace >= 0)
flags.initrace = -1;
else
panic("no available ROLE+race+gender+alignment combinations");
}
choices[n] = (const char *) 0;
if (n > 1)
sel =
curses_character_dialog(choices,
"Choose one of the following roles:", FALSE);
else
sel = 0;
if (sel >= 0)
sel = pickmap[sel];
else if (sel == ROLE_NONE) { /* Quit */
clearlocks();
curses_bail(0);
}
free(choices);
free(pickmap);
} else if (flags.initrole < 0)
sel = ROLE_RANDOM;
else
sel = flags.initrole;
if (sel == ROLE_RANDOM) { /* Random role */
sel = pick_role(flags.initrace, flags.initgend,
flags.initalign, PICK_RANDOM);
if (sel < 0)
sel = randrole(0);
}
flags.initrole = sel;
/* Select a race, if necessary */
/* force compatibility with role, try for compatibility with
* pre-selected gender/alignment */
if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
if (flags.initrace == ROLE_RANDOM || flags.randomall) {
flags.initrace = pick_race(flags.initrole, flags.initgend,
flags.initalign, PICK_RANDOM);
if (flags.initrace < 0)
flags.initrace = randrace(flags.initrole);
} else {
/* Count the number of valid races */
n = 0; /* number valid */
for (i = 0; races[i].noun; i++) {
if (ok_race(flags.initrole, i, flags.initgend, flags.initalign))
n++;
}
if (n == 0) {
for (i = 0; races[i].noun; i++) {
if (validrace(flags.initrole, i))
n++;
}
}
choices = (const char **) alloc(sizeof (char *) * (n + 1));
pickmap = (int *) alloc(sizeof (int) * (n + 1));
for (n = 0, i = 0; races[i].noun; i++) {
if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) {
choices[n] = races[i].noun;
pickmap[n++] = i;
}
}
choices[n] = (const char *) 0;
/* Permit the user to pick, if there is more than one */
if (n > 1)
sel =
curses_character_dialog(choices,
"Choose one of the following races:", FALSE);
else
sel = 0;
if (sel >= 0)
sel = pickmap[sel];
else if (sel == ROLE_NONE) { /* Quit */
clearlocks();
curses_bail(0);
}
flags.initrace = sel;
free(choices);
free(pickmap);
}
if (flags.initrace == ROLE_RANDOM) { /* Random role */
sel = pick_race(flags.initrole, flags.initgend,
flags.initalign, PICK_RANDOM);
if (sel < 0)
sel = randrace(flags.initrole);
flags.initrace = sel;
}
}
/* Select a gender, if necessary */
/* force compatibility with role/race, try for compatibility with
* pre-selected alignment */
if (flags.initgend < 0 ||
!validgend(flags.initrole, flags.initrace, flags.initgend)) {
if (flags.initgend == ROLE_RANDOM || flags.randomall) {
flags.initgend = pick_gend(flags.initrole, flags.initrace,
flags.initalign, PICK_RANDOM);
if (flags.initgend < 0)
flags.initgend = randgend(flags.initrole, flags.initrace);
} else {
/* Count the number of valid genders */
n = 0; /* number valid */
for (i = 0; i < ROLE_GENDERS; i++) {
if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign))
n++;
}
if (n == 0) {
for (i = 0; i < ROLE_GENDERS; i++) {
if (validgend(flags.initrole, flags.initrace, i))
n++;
}
}
choices = (const char **) alloc(sizeof (char *) * (n + 1));
pickmap = (int *) alloc(sizeof (int) * (n + 1));
for (n = 0, i = 0; i < ROLE_GENDERS; i++) {
if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) {
choices[n] = genders[i].adj;
pickmap[n++] = i;
}
}
choices[n] = (const char *) 0;
/* Permit the user to pick, if there is more than one */
if (n > 1)
sel =
curses_character_dialog(choices,
"Choose one of the following genders:", FALSE);
else
sel = 0;
if (sel >= 0)
sel = pickmap[sel];
else if (sel == ROLE_NONE) { /* Quit */
clearlocks();
curses_bail(0);
}
flags.initgend = sel;
free(choices);
free(pickmap);
}
if (flags.initgend == ROLE_RANDOM) { /* Random gender */
sel = pick_gend(flags.initrole, flags.initrace,
flags.initalign, PICK_RANDOM);
if (sel < 0)
sel = randgend(flags.initrole, flags.initrace);
flags.initgend = sel;
}
}
/* Select an alignment, if necessary */
/* force compatibility with role/race/gender */
if (flags.initalign < 0 ||
!validalign(flags.initrole, flags.initrace, flags.initalign)) {
if (flags.initalign == ROLE_RANDOM || flags.randomall
|| (flags.initrole != ROLE_NONE
&& roles[flags.initrole].malenum == PM_EXILE)) {
flags.initalign = pick_align(flags.initrole, flags.initrace,
flags.initgend, PICK_RANDOM);
if (flags.initalign < 0)
flags.initalign = randalign(flags.initrole, flags.initrace);
} else {
/* Count the number of valid alignments */
n = 0; /* number valid */
for (i = 0; i < ROLE_ALIGNS; i++) {
if (ok_align(flags.initrole, flags.initrace, flags.initgend, i))
n++;
}
if (n == 0) {
for (i = 0; i < ROLE_ALIGNS; i++)
if (validalign(flags.initrole, flags.initrace, i))
n++;
}
choices = (const char **) alloc(sizeof (char *) * (n + 1));
pickmap = (int *) alloc(sizeof (int) * (n + 1));
for (n = 0, i = 0; i < ROLE_ALIGNS; i++) {
if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) {
choices[n] = aligns[i].adj;
pickmap[n++] = i;
}
}
choices[n] = (const char *) 0;
/* Permit the user to pick, if there is more than one */
if (n > 1)
sel =
curses_character_dialog(choices,
"Choose one of the following alignments:", FALSE);
else
sel = 0;
if (sel >= 0)
sel = pickmap[sel];
else if (sel == ROLE_NONE) { /* Quit */
clearlocks();
curses_bail(0);
}
flags.initalign = sel;
free(choices);
free(pickmap);
}
if (flags.initalign == ROLE_RANDOM) {
sel = pick_align(flags.initrole, flags.initrace,
flags.initgend, PICK_RANDOM);
if (sel < 0)
sel = randalign(flags.initrole, flags.initrace);
flags.initalign = sel;
}
}
/* Select a species, if necessary */
/* force compatibility with role/race/gender */
if (flags.initspecies < 0 ||
!validspecies(flags.initrole, flags.initrace, flags.initgend, flags.initspecies)) {
if (flags.initspecies == ROLE_RANDOM || flags.randomall){
flags.initspecies = pick_species(flags.initrole, flags.initrace,
flags.initgend, PICK_RANDOM);
if (flags.initspecies < 0)
flags.initspecies = randspecies(flags.initrole, flags.initrace, flags.initgend);
} else {
/* Count the number of valid species */
n = 0; /* number valid */
for (i = 0; i < ROLE_SPECIES; i++) {
if (validspecies(flags.initrole, flags.initrace, flags.initgend, i))
n++;
}
choices = (const char **) alloc(sizeof (char *) * (n + 1));
pickmap = (int *) alloc(sizeof (int) * (n + 1));
for (n = 0, i = 0; i < ROLE_SPECIES; i++) {
if (validspecies(flags.initrole, flags.initrace, flags.initgend, i)) {
choices[n] = species[i].name;
pickmap[n++] = i;
}
}
choices[n] = (const char *) 0;
pickmap[n] = 0;
/* Permit the user to pick, if there is more than one */
if (n > 1)
sel =
curses_character_dialog(choices,
"Choose one of the following species:", TRUE);
else
sel = 0;
if (sel >= 0)
sel = pickmap[sel];
else if (sel == ROLE_NONE) { /* Quit */
clearlocks();
curses_bail(0);
}
flags.initspecies = sel;
free(choices);
free(pickmap);
}
if (flags.initspecies == ROLE_RANDOM) {
sel = pick_species(flags.initrole, flags.initrace,
flags.initgend, PICK_RANDOM);
if (sel < 0)
sel = randspecies(flags.initrole, flags.initrace, flags.initgend);
flags.initspecies = sel;
}
}
/* Select descendant status, if necessary */
if (flags.descendant < 0){
if (flags.descendant == ROLE_RANDOM || flags.randomall || flags.initrole < 0 || !validdescendant(flags.initrole)) {
flags.descendant = 0; // never randomly roll descendant
} else {
/* Always 2 options - yn */
choices = (const char **) alloc(sizeof (char *) * (3));
pickmap = (int *) alloc(sizeof (int) * (3));
char * terms[] = {"Inherit from a past adventurer (start with an heirloom artifact but low stats and dangerous foes)",
"No past inheritance", NULL};
for (i = 0; i < 2; i++) {
choices[i] = terms[i];
pickmap[i] = i;
}
choices[i] = (const char *) 0;
sel = curses_character_dialog(choices, "Choose one of the following inheritances:", FALSE);
if (sel >= 0) sel = pickmap[sel];
else if (sel == ROLE_NONE) { /* Quit */
clearlocks();
curses_bail(0);
}
/* invert y/n for the sanity for putting "yes" as the first option, but 0 as the default */
if (sel == 0) sel = 1;
else if (sel == 1) sel = 0;
else if (sel == ROLE_RANDOM) sel = rn2(2);
flags.descendant = sel;
free(choices);
free(pickmap);
}
}
}
/* Prompt user for character race, role, alignment, or gender */
int
curses_character_dialog(const char **choices, const char *prompt, boolean inorder)
{
int count, count2, ret, curletter;
char used_letters[52];
anything identifier;
menu_item *selected = NULL;
winid wid = curses_get_wid(NHW_MENU);
identifier.a_void = 0;
curses_start_menu(wid);
for (count = 0; choices[count]; count++) {
curletter = tolower(choices[count][0]);
if(!inorder){
for (count2 = 0; count2 < count; count2++) {
if (curletter == used_letters[count2]) {
curletter = toupper(curletter);
}
}
} else curletter = 'a' + count;
identifier.a_int = (count + 1); /* Must be non-zero */
curses_add_menu(wid, NO_GLYPH, &identifier, curletter, 0,
A_NORMAL, choices[count], FALSE);
used_letters[count] = curletter;
}
/* Random Selection */
identifier.a_int = ROLE_RANDOM;
curses_add_menu(wid, NO_GLYPH, &identifier, '*', 0, A_NORMAL, "Random",
FALSE);
/* Quit prompt */
identifier.a_int = ROLE_NONE;
curses_add_menu(wid, NO_GLYPH, &identifier, 'q', 0, A_NORMAL, "Quit",
FALSE);
curses_end_menu(wid, prompt);
ret = curses_select_menu(wid, PICK_ONE, &selected);
if (ret == 1) {
ret = (selected->item.a_int);
} else { /* Cancelled selection */
ret = ROLE_NONE;
}
if (ret > 0) {
ret--;
}
free(selected);
return ret;
}
/* Initialize and display options appropriately */
void
curses_init_options(void)
{
set_wc_option_mod_status(WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_COLOR |
WC_HILITE_PET | WC_POPUP_DIALOG, SET_IN_GAME);
set_wc2_option_mod_status(WC2_GUICOLOR, SET_IN_GAME);
/* Remove a few options that are irrelevant to this windowport */
set_option_mod_status("DECgraphics", SET_IN_FILE);
set_option_mod_status("eight_bit_tty", SET_IN_FILE);
/* Add those that are */
set_option_mod_status("classic_status", SET_IN_GAME);
/* Make sure that DECgraphics is not set to true via the config
file, as this will cause display issues. We can't disable it in
options.c in case the game is compiled with both tty and curses. */
if (iflags.DECgraphics) {
switch_graphics(CURS_GRAPHICS);
}
#ifdef PDCURSES
/* PDCurses for SDL, win32 and OS/2 has the ability to set the
terminal size programatically. If the user does not specify a
size in the config file, we will set it to a nice big 110x32 to
take advantage of some of the nice features of this windowport. */
if (iflags.wc2_term_cols == 0) {
iflags.wc2_term_cols = 110;
}
if (iflags.wc2_term_rows == 0) {
iflags.wc2_term_rows = 32;
}
resize_term(iflags.wc2_term_rows, iflags.wc2_term_cols);
getmaxyx(base_term, term_rows, term_cols);
/* This is needed for an odd bug with PDCurses-SDL */
switch_graphics(ASCII_GRAPHICS);
if (iflags.IBMgraphics) {
switch_graphics(IBM_GRAPHICS);
} else if (iflags.supports_utf8 && !iflags.cursesgraphics) {
switch_graphics(UTF8_GRAPHICS);
} else if (iflags.cursesgraphics) {
switch_graphics(CURS_GRAPHICS);
} else {
switch_graphics(ASCII_GRAPHICS);
}
#endif /* PDCURSES */
if (!iflags.wc2_windowborders) {
iflags.wc2_windowborders = 3; /* Set to auto if not specified */
}
if (!iflags.wc2_petattr) {
iflags.wc2_petattr = A_REVERSE;
} else { /* Pet attribute specified, so hilite_pet should be true */
iflags.hilite_pet = TRUE;
}
#ifdef NCURSES_MOUSE_VERSION
if (iflags.wc_mouse_support) {
mousemask(BUTTON1_CLICKED, NULL);
}
#endif
}
/* Display an ASCII splash screen if the splash_screen option is set */
void
curses_display_splash_window(void)
{
int x_start;
int y_start;
curses_get_window_xy(MAP_WIN, &x_start, &y_start);
if ((term_cols < 70) || (term_rows < 20)) {
iflags.wc_splash_screen = FALSE; /* No room for s.s. */
}
curses_toggle_color_attr(stdscr, CLR_WHITE, A_NORMAL, ON);
if (iflags.wc_splash_screen) {
mvaddstr(y_start, x_start, DNETHACK_SPLASH_A);
mvaddstr(y_start + 1, x_start, DNETHACK_SPLASH_B);
mvaddstr(y_start + 2, x_start, DNETHACK_SPLASH_C);
mvaddstr(y_start + 3, x_start, DNETHACK_SPLASH_D);
mvaddstr(y_start + 4, x_start, DNETHACK_SPLASH_E);
mvaddstr(y_start + 5, x_start, DNETHACK_SPLASH_F);
y_start += 7;
}
curses_toggle_color_attr(stdscr, CLR_WHITE, A_NORMAL, OFF);
#ifdef COPYRIGHT_BANNER_A
mvaddstr(y_start, x_start, COPYRIGHT_BANNER_A);
y_start++;
#endif
#ifdef COPYRIGHT_BANNER_B
mvaddstr(y_start, x_start, COPYRIGHT_BANNER_B);
y_start++;
#endif
#ifdef COPYRIGHT_BANNER_C
mvaddstr(y_start, x_start, COPYRIGHT_BANNER_C);
y_start++;
#endif
#ifdef COPYRIGHT_BANNER_D
mvaddstr(y_start, x_start, COPYRIGHT_BANNER_D);
y_start++;
#endif
#ifdef COPYRIGHT_BANNER_E
mvaddstr(y_start, x_start, COPYRIGHT_BANNER_E);
y_start++;
#endif
refresh();
}
/* Resore colors and cursor state before exiting */
void
curses_cleanup(void)
{
if (has_colors() && can_change_color()) {
int cnum = COLORS >= 16 ? 16 : 8;
int clr_remap[16] = {
COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
COLOR_BLUE,
COLOR_MAGENTA, COLOR_CYAN, -1, COLOR_WHITE,
COLOR_RED + 8, COLOR_GREEN + 8, COLOR_YELLOW + 8,
COLOR_BLUE + 8,
COLOR_MAGENTA + 8, COLOR_CYAN + 8, COLOR_WHITE + 8
};
for (int nclr = 0; nclr < cnum; nclr++){
init_color(clr_remap[nclr], orig_colors[nclr].r, orig_colors[nclr].g, orig_colors[nclr].b);
}
for (struct rgb_color_option* curr = resetcolor_opts; curr; curr = curr->next){
init_color(curr->color, curr->r, curr->g, curr->b);
}
# ifdef USE_DARKGRAY
if (COLORS > 16) {
init_color(CURSES_DARK_GRAY, orig_darkgray.r,
orig_darkgray.g, orig_darkgray.b);
}
# endif
}
}