/* 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" -*-*/
/* NetHack 5.0 cursinit.c */
/* Copyright (c) Karl Garrison, 2010. */
/* NetHack may be freely redistributed.  See license for details. */

#include "curses.h"
#include "hack.h"
#include "wincurs.h"
#include "cursinit.h"

/* 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);

#if 0   /* no longer used */
typedef struct nhrgb_type {
    short r;
    short g;
    short b;
} nhrgb;
#endif

/* Banners used for an optional ASCII splash screen */

#define NETHACK_SPLASH_A \
" _   _        _    _    _               _    "

#define NETHACK_SPLASH_B \
"| \\ | |      | |  | |  | |             | |   "

#define NETHACK_SPLASH_C \
"|  \\| |  ___ | |_ | |__| |  __ _   ___ | | __"

#define NETHACK_SPLASH_D \
"| . ` | / _ \\| __||  __  | / _` | / __|| |/ /"

#define NETHACK_SPLASH_E \
"| |\\  ||  __/| |_ | |  | || (_| || (__ |   < "

#define NETHACK_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, noperminv_borders = FALSE;

    switch (iflags.wc2_windowborders) {
    default:
    case 0:                     /* Off */
        borders = FALSE;
        break;

    case 3:
        noperminv_borders = TRUE;
        FALLTHROUGH;
        /*FALLTHRU*/
    case 1:                     /* On */
        borders = TRUE;
        break;

    case 4:
        noperminv_borders = TRUE;
        FALLTHROUGH;
        /*FALLTHRU*/
    case 2:                     /* Auto */
        borders = (term_cols >= 80 + 2 && term_rows >= 24 + 2);
        break;
    }

    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_BOTTOM;
    if (iflags.wc_align_status == ALIGN_TOP
        || 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.
         * [Width of 26 gives enough room for a 24 character
         * hitpoint bar (horizontal layout uses 30 for that) and
         * can accommodate widest field ("Experience  : 30/123456789")
         * other than title without truncating anything.
         * Height originally required at least 24 lines, but 21
         * suffices and 20 can be made to work by suppressing score.]
         */
        if (hspace >= 26 && term_rows >= 20) {
            status_orientation = iflags.wc_align_status;
            hspace -= (26 + border_space);
        } else {
            /* orientation won't match option setting, making 'O' command's
               list of settings seem inaccurate; but leaving the requested
               setting in iflags might allow it to take effect if the main
               window gets resized */
            status_orientation = ALIGN_BOTTOM;
        }
    }

    /* Determine message window orientation */
    if (!iflags.wc_align_message)
        iflags.wc_align_message = ALIGN_TOP;
    if (iflags.wc_align_message == ALIGN_TOP
        || iflags.wc_align_message == ALIGN_BOTTOM) {
        message_orientation = iflags.wc_align_message;
    } else { /* left or right alignment */
        if ((hspace - border_space) >= 25) {    /* Arbitrary */
            message_orientation = iflags.wc_align_message;
        } else {
            /* orientation won't match option setting (see above) */
            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);
        int statusheight = (iflags.wc2_statuslines < 3) ? 2 : 3;
        boolean status_vertical = (status_orientation == ALIGN_LEFT
                                   || status_orientation == ALIGN_RIGHT);
        boolean msg_vertical = (message_orientation == ALIGN_LEFT
                                || message_orientation == ALIGN_RIGHT);

        /* Vertical windows have priority. Otherwise, priority 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, 20, 26);

        if (iflags.perm_invent) {
            /* Take up all width unless msgbar is also vertical. */
            int width = msg_vertical ? 25 : -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);
            /* suppress borders on perm_invent window, part I */
            if (noperminv_borders)
                inv_width += border_space, inv_height += border_space; /*+=2*/
        }

        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, 0);

        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);
            /* 'count window' overlays last line of mesg win;
               asking it to display a Null string removes it */
            curses_count_window((char *) 0);
            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 (iflags.perm_invent)
            curses_add_nhwin(INV_WIN, inv_height, inv_width, inv_y, inv_x,
                             ALIGN_RIGHT,
                             /* suppress perm_invent borders, part II */
                             borders && !noperminv_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 (iflags.perm_invent)
                curses_update_inventory();
        } else {
            iflags.window_inited = TRUE;
        }
    */
    }
}

static int pairs_used = 0;
static int colors_used = 0;

/* create a new color */
int
curses_init_rgb(int r, int g, int b)
{
    if (!can_change_color())
        return 0;

    if (colors_used < COLORS - 1) {
        colors_used++;
        init_color(colors_used, r*4, g*4, b*4);
        return colors_used;
    }
    return 0;
}

/* create a new foreground/background combination */
int
curses_init_pair(int fg, int bg)
{
    if (pairs_used < COLOR_PAIRS - 1) {
        pairs_used++;
        init_pair(pairs_used, fg, bg);
        return pairs_used;
    }
    return 0;
}

/* Initialize curses colors to colors used by NetHack */
void
curses_init_nhcolors(void)
{
    /* COLOR_foo + 8 means COLOR | A_BOLD when COLORS < 16 */
    /* otherwise assume the terminal has least 16 different colors */
    /* these map to the NetHack CLR_ defines */
    static const int fg_clr[16] = {
        COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
        COLOR_BLUE,  COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE,
        -1, COLOR_RED + 8, COLOR_GREEN + 8, COLOR_YELLOW + 8,
        COLOR_BLUE + 8, COLOR_MAGENTA + 8, COLOR_CYAN + 8, COLOR_WHITE + 8
    };
    static const int bg_clr[8] = {
        -1, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
        COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
    };
    int bg, nhclr;
    int maxc = (COLORS >= 16) ? 16 : 8;

    if (!has_colors())
        return;

    use_default_colors();

    for (nhclr = CLR_BLACK; nhclr < maxc; nhclr++) {
        for (bg = 0; bg < 8; bg++) {
            init_pair((maxc * bg) + nhclr + 1, fg_clr[nhclr], bg_clr[bg]);
        }
    }

#ifdef USE_DARKGRAY
    if (COLORS >= 16) {
        if (iflags.wc2_darkgray) {
            init_pair(CLR_BLACK + 1, COLOR_BLACK + 8, -1);
        }
    }
#endif
    colors_used = maxc;
    pairs_used = (maxc * 8) + 16 + 1;
}

#if 0   /* curses_choose_character + curses_character_dialog no longer used */

/* 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];

    prompt = build_plselection_prompt(pbuf, QBUFSZ, flags.initrole,
                                      flags.initrace, 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';
    Snprintf(choice, sizeof(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;
    }

    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:");
        else
            sel = 0;
        if (sel >= 0)
            sel = pickmap[sel];
        else if (sel == ROLE_NONE) {    /* Quit */
            clearlocks();
            curses_bail(0);
        }
        free((genericptr_t) choices);
        free((genericptr_t) 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(FALSE);
    }

    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:");
            else
                sel = 0;
            if (sel >= 0)
                sel = pickmap[sel];
            else if (sel == ROLE_NONE) {        /* Quit */
                clearlocks();
                curses_bail(0);
            }
            flags.initrace = sel;
            free((genericptr_t) choices);
            free((genericptr_t) 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:");
            else
                sel = 0;
            if (sel >= 0)
                sel = pickmap[sel];
            else if (sel == ROLE_NONE) {        /* Quit */
                clearlocks();
                curses_bail(0);
            }
            flags.initgend = sel;
            free((genericptr_t) choices);
            free((genericptr_t) 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.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:");
            else
                sel = 0;
            if (sel >= 0)
                sel = pickmap[sel];
            else if (sel == ROLE_NONE) {        /* Quit */
                clearlocks();
                curses_bail(0);
            }
            flags.initalign = sel;
            free((genericptr_t) choices);
            free((genericptr_t) 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;
        }
    }
    return;
}

/* Prompt user for character race, role, alignment, or gender */
int
curses_character_dialog(const char **choices, const char *prompt)
{
    int count, count2, ret, curletter;
    char used_letters[invlet_basic]; /* a..zA..Z */
    anything identifier;
    menu_item *selected = NULL;
    winid wid = curses_get_wid(NHW_MENU);
    int clr = NO_COLOR;

    identifier.a_void = 0;
    curses_start_menu(wid, MENU_BEHAVE_STANDARD);

    for (count = 0; choices[count]; count++) {
        curletter = tolower(choices[count][0]);
        for (count2 = 0; count2 < count; count2++) {
            if (curletter == used_letters[count2]) {
                curletter = toupper(curletter);
            }
        }

        identifier.a_int = (count + 1); /* Must be non-zero */
        curses_add_menu(wid, &nul_glyphinfo, &identifier, curletter, 0,
                        A_NORMAL, clr, choices[count], MENU_ITEMFLAGS_NONE);
        used_letters[count] = curletter;
    }

    /* Random Selection */
    identifier.a_int = ROLE_RANDOM;
    curses_add_menu(wid, &nul_glyphinfo, &identifier, '*', 0,
                    A_NORMAL, clr, "Random", MENU_ITEMFLAGS_NONE);

    /* Quit prompt */
    identifier.a_int = ROLE_NONE;
    curses_add_menu(wid, &nul_glyphinfo, &identifier, 'q', 0,
                    A_NORMAL, clr, "Quit", MENU_ITEMFLAGS_NONE);
    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((genericptr_t) selected);
    return ret;
}

#endif /* 0 */

/* Initialize and display options appropriately */
void
curses_init_options(void)
{
    /* change these from set_gameview to set_in_game */
    set_wc_option_mod_status(WC_ALIGN_MESSAGE | WC_ALIGN_STATUS, set_in_game);

    /* Remove a few options that are irrelevant to this windowport */
    set_option_mod_status("eight_bit_tty", set_in_config);

    /* If we don't have a symset defined, load the curses symset by default */
    if (!gs.symset[PRIMARYSET].explicitly)
        load_symset("curses", PRIMARYSET);
    if (!gs.symset[ROGUESET].explicitly)
        load_symset("default", ROGUESET);

#ifdef PDCURSES
    /* PDCurses for SDL, win32 and OS/2 has the ability to set the
       terminal size programmatically.  If the user does not specify a
       size in the config file, we will set it to a nice big 32x110 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 */
/* How to deal with this?
    switch_graphics(ASCII_GRAPHICS);
    if (iflags.IBMgraphics) {
        switch_graphics(IBM_GRAPHICS);
    } else if (iflags.cursesgraphics) {
        switch_graphics(CURS_GRAPHICS);
    } else {
        switch_graphics(ASCII_GRAPHICS);
    }
*/
#endif /* PDCURSES */

    /* FIXME: this overrides explicit OPTIONS=!use_inverse */
    iflags.wc_inverse = TRUE; /* aka iflags.use_inverse; default is False */

    /* curses doesn't support 's' (single message at a time; successive
       ^P's go back to earlier messages) and 'c' (combination; single
       on first and second of consecutive ^P's, full on third) */
    if (iflags.prevmsg_window != 'f')
        iflags.prevmsg_window = 'r';

#ifdef NCURSES_MOUSE_VERSION
    if (iflags.wc_mouse_support) {
        curses_mouse_support(iflags.wc_mouse_support);
    }
#else
    iflags.wc_mouse_support = 0;
#endif
}

/* Display an ASCII splash screen if the splash_screen option is set */
void
curses_display_splash_window(void)
{
     int i, x_start, 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. */
    }

    if (iflags.wc_splash_screen) {
         if (iflags.wc2_guicolor)
              curses_toggle_color_attr(stdscr, CLR_WHITE, A_NORMAL, ON);
        mvaddstr(y_start, x_start, NETHACK_SPLASH_A);
        mvaddstr(y_start + 1, x_start, NETHACK_SPLASH_B);
        mvaddstr(y_start + 2, x_start, NETHACK_SPLASH_C);
        mvaddstr(y_start + 3, x_start, NETHACK_SPLASH_D);
        mvaddstr(y_start + 4, x_start, NETHACK_SPLASH_E);
        mvaddstr(y_start + 5, x_start, NETHACK_SPLASH_F);
        y_start += 7;
    }
    if (iflags.wc2_guicolor)
         curses_toggle_color_attr(stdscr, CLR_WHITE, A_NORMAL, OFF);

    for (i = 1; i <= 4; ++i) {
         mvaddstr(y_start, x_start, copyright_banner_line(i));
         y_start++;
    }

    refresh();
}

/* Restore colors and cursor state before exiting */
void
curses_cleanup(void)
{
}
