示例#1
0
void nhnet_describe_pos(int x, int y, struct nh_desc_buf *bufs)
{
    const char *bgdesc, *trapdesc, *objdesc, *mondesc, *invisdesc, *effectdesc;
    json_t *jmsg;

    if (!nhnet_active())
        return nh_describe_pos(x, y, bufs);

    if (!api_entry())
        return;

    jmsg = send_receive_msg("describe_pos", json_pack("{si,si}", "x", x, "y", y));
    json_unpack(jmsg, "{ss,ss,ss,ss,ss,ss,si!}",
                "bgdesc", &bgdesc,	"trapdesc", &trapdesc,
                "objdesc", &objdesc,	"mondesc", &mondesc,
                "invisdesc", &invisdesc,"effectdesc", &effectdesc,
                "objcount", &bufs->objcount);

    strncpy(bufs->bgdesc, bgdesc, BUFSZ-1);
    strncpy(bufs->trapdesc, trapdesc, BUFSZ-1);
    strncpy(bufs->objdesc, objdesc, BUFSZ-1);
    strncpy(bufs->mondesc, mondesc, BUFSZ-1);
    strncpy(bufs->invisdesc, invisdesc, BUFSZ-1);
    strncpy(bufs->effectdesc, effectdesc, BUFSZ-1);
    json_decref(jmsg);

    api_exit();
}
示例#2
0
static void
ccmd_describe_pos(json_t * params)
{
    struct nh_desc_buf db;
    int x, y, is_in;
    json_t *jmsg;

    if (json_unpack(params, "{si,si,si*}", "x", &x, "y", &y, "is_in", &is_in) ==
        -1)
        exit_client("Bad parameters for describe_pos");

    nh_describe_pos(x, y, &db, is_in ? &is_in : NULL);
    jmsg =
        json_pack("{ss,ss,ss,ss,ss,ss,si,si}", "bgdesc", db.bgdesc, "trapdesc",
                  db.trapdesc, "objdesc", db.objdesc, "mondesc", db.mondesc,
                  "invisdesc", db.invisdesc, "effectdesc", db.effectdesc,
                  "objcount", db.objcount, "in", is_in);
    client_msg("describe_pos", jmsg);
}
示例#3
0
void
draw_extrawin(enum keyreq_context context)
{
    if (!ui_flags.ingame)
        return;

    /* Which window do we draw our hints onto? Nearly always, it's extrawin.
       However, during getpos() calls, the hints are particularly important
       (because this is how farlooking is done with keyboard controls), so we
       steal the space used by statuswin if we don't have an extrawin to draw
       onto. The y height is read from the appropriate field of ui_flags; both
       the windows are width ui_flags.mapwidth, so we don't need to record
       that. */

    int y_remaining = ui_flags.extraheight;
    int y = 0;

    WINDOW *win = extrawin;
    if (!y_remaining && context == krc_getpos) {
        y_remaining = ui_flags.statusheight;
        win = statuswin;
    }

    if (!y_remaining)
        return;

    int y_insert_line = 0; /* insert one line here if there's room */
    int y_fill_line = 0;   /* if there's still room, insert it here */

    /* Modal windows are allowed to steal any space they feel like. Nearly
       always, this will avoid the extrawin, but it can overlap in some cases
       (e.g. an inventory window full of inventory on a terminal that is both
       very tall and very narrow). In such cases, drawing the extra window would
       be a) difficult (due to handling the overlap correctly while also
       handling mouse regions correctly), and b) pointless, because the user
       wouldn't be able to see the information it was trying to give.  So just
       leave it alone. */
    struct gamewin *gw;
    for (gw = firstgw; gw; gw = gw->next) {
        if (!gw->win)
            continue;

        int t, l, h, w, t2, l2, h2, w2;
        getmaxyx(gw->win, h, w);
        getbegyx(gw->win, t, l);
        getmaxyx(win, h2, w2);
        getbegyx(win, t2, l2);

        if (range_overlap(t, h, t2, h2) && range_overlap(l, w, l2, w2))
            return;
    }

    /* We're OK to start drawing, and we can refresh win as much as we like
       without it overwriting anyone else's space. Because draw_extrawin is
       called from nh_wgetch (i.e. very very late), we can also set mouse
       regions without a modal dialog box turning them back off. */
    werase(win);

    /* We fit as many hints as we can into the space provided (that is, while
       y_remaining is stil positive), starting with the most important and
       moving down to progressively less important ones as time goes on. */

#define spend_one_line()                        \
    do {                                        \
        if (!y_remaining--) {                   \
            wnoutrefresh(win);                  \
            return;                             \
        }                                       \
        wmove(win, y++, 0);                     \
    } while(0)

    /* Most important: map hover (i.e. mouselook). This also handles keyboard
       look in the case of the getpos prompt (which basically hijacks the hover
       information, reporting whichever of the keyboard or mouse produced input
       last). Note that the mouse doesn't confirm a location in getpos unless
       you actually press it, nor move the cursor, so pressing . doesn't
       necessarily get the position that's being hinted. */
    if (ui_flags.maphoverx != -1) {

        spend_one_line();

        struct nh_desc_buf descbuf;
        nh_describe_pos(ui_flags.maphoverx, ui_flags.maphovery,
                        &descbuf, NULL);

        int x_remaining = ui_flags.mapwidth - 1;
        nh_bool first = TRUE;
        int l;

#define place_desc_message(s)                   \
        do {                                    \
            l = strlen(s);                      \
            if (l && !first) l += 2;            \
            if (l && l <= x_remaining) {        \
                if (!first)                     \
                    waddstr(win, "; ");         \
                waddstr(win, s);                \
                x_remaining -= l;               \
                first = FALSE;                  \
            }                                   \
        } while(0)

        place_desc_message(descbuf.effectdesc);
        place_desc_message(descbuf.invisdesc);
        place_desc_message(descbuf.mondesc);
        place_desc_message(descbuf.objdesc);
        place_desc_message(descbuf.trapdesc);
        /* We could suppress this if feature_described, but it probably looks a
           little better to list every layer. */
        place_desc_message(descbuf.bgdesc);

    }

    ui_flags.extrawin_populated = TRUE;

    y_fill_line = y;

    /* Next most important: keymaps for unusual contexts.

       These have to be kept under 78 characters long, and are written as two
       lines of 40 and 38 respectively for easier counting. If using hintline(),
       as many lines from the start as will fit will be displayed. */

#define hintline(s) do { spend_one_line(); nh_waddstr(win, s); } while(0)

    nh_bool draw_direction_rose = FALSE;

    if (ui_flags.current_followmode == FM_REPLAY &&
        !ui_flags.in_zero_time_command) {
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Use the movement keys to move through th"
                 "e history of the game."                );
    } else if (ui_flags.current_followmode == FM_WATCH &&
               !ui_flags.in_zero_time_command) {
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("You are viewing this game, and cannot us"
                 "e input that changes the game state."  );
    } else switch (context) {
    case krc_getdir:
    case krc_get_movecmd_direction:
        draw_direction_rose = TRUE;
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Press a direction key or ESC to cancel." );
        break;

    case krc_getlin:
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Enter text at the prompt, then press Ret"
                 "urn. Edit with Left/Right/BkSp/Delete.");
        break;

    case krc_yn:
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Press 'y' for Yes or 'n' for No."        );
        break;
    case krc_ynq:
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Press 'y' for Yes or 'n' for No. Press '"
                 "q' to cancel."                         );
        break;
    case krc_yn_generic:
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Please press one of the keys listed."    );
        break;

    case krc_count:
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Type a count to specify how many turns t"
                 "o perform a command for."              );
        hintline("For some commands, like \"throw\", this in"
                 "stead limits how many items to use."   );
        /* Diagnose a common misconfiguration, and specify a workaround for
           it. */
        hintline("If you were trying to move using the num"
                 "eric keypad, turn off NumLock."        );
        break;

    case krc_interrupt_long_action:
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("To interrupt the command, press any key "
                 "or click on the map."                  );
        break;

    case krc_getpos:
        draw_direction_rose = TRUE;
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Move the cursor with the direction keys."
                 " When done, confirm with . , : or ;"   );
        hintline("Press the letter of a dungeon symbol to "
                 "select it or m/M to move to a monster.");
        hintline("Alternatively, you can click on the map "
                 "to select a location.");
        break;

    case krc_menu:
    case krc_objmenu:
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Scroll the menu with '<' and '>'. Press "
                 "Return when finished or ESC to cancel.");
        hintline("^:scroll to top   |:scroll to end   .:s"
                 "elect all   -:select none"             );
        break;

    case krc_prevmsg:
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Scroll the list of messages with '<' and"
                 "'>'. Press Return when finished."      );
        break;

    case krc_more:
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Press Space to see the remaining message"
                 "s, or ESC to skip messages this turn." );
        break;
    case krc_moretab:
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("This is an important message. Press Tab "
                 "to dismiss it."                        );
        break;

    case krc_pause_map:
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("When you finish looking at the map, pres"
                 "s any key or click on it to continue." );
        break;

    case krc_query_key_inventory:
    case krc_query_key_inventory_or_floor:
    case krc_query_key_inventory_nullable:
        /* This is only used for inventory queries, so can explain
           their specific rules. */
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Please specify an item. You can type its"
                 " inventory letter, if you know it."    );
        if (context == krc_query_key_inventory_or_floor)
            /* ----- "1234567890123456789012345678901234567890" */
            hintline("To use an item on the floor, press ','." );
        else if (context == krc_query_key_inventory_nullable)
            hintline("You can also choose 'no item' by pressin"
                     "g '-'."                                 );
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Press '?' for a list of sensible options"
                 ", or '*' to select something else."    );
        break;

    case krc_query_key_symbol:
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Please type an object or monster symbol.");
        break;

    case krc_query_key_letter_reassignment:
        /* ----- "1234567890123456789012345678901234567890" */
        hintline("Please type the letter (\"a\"-\"z\" or \"A\"-\""
                 "Z\") that you would like to use."       );
        break;

    case krc_get_command:
        /* more complex than just simple hint lines will allow */
        draw_direction_rose = 1;
        break;

    /* These are either fully explained, or there's no way to react to them
       anyway. */
    case krc_notification:
    case krc_keybinding:
        break;
    }

    if (draw_direction_rose && y_remaining >= 3) {

        /* Draw three direction roses: function keys, keypad keys, and main
           keyboard. First, we find out what the direction key bindings are
           right now. (TODO: Is this too inefficient? It's of the order of 15000
           function calls, which is quite a lot to happen on every mouse
           movement. Perhaps we could cache it somehow.) (TODO: Handle
           key names that overflow horizontally.) */
        int dirkey[3][9] = {{0}};
        int key, upkey = 0, downkey = 0, selfkey = 0;
        int x = 8;
        int xg;
        int kg;
        int i;
        nh_bool first = TRUE;

        if (context == krc_get_command) {
            mvwaddstr(win, y + 0, 0, "Move or ");
            mvwaddstr(win, y + 1, 0, " attack ");
            mvwaddstr(win, y + 2, 0, " using: ");
        }

        for (key = KEY_MAX; key; key--) {
            if (settings.alt_is_esc && key == (KEY_ALT | (key & 0xff)))
                continue;
            switch (key_to_dir(key, NULL)) {
            case DIR_NW: dirkey[classify_key(key)][0] = key; break;
            case DIR_N : dirkey[classify_key(key)][3] = key; break;
            case DIR_NE: dirkey[classify_key(key)][6] = key; break;
            case DIR_W : dirkey[classify_key(key)][1] = key; break;
            case DIR_E : dirkey[classify_key(key)][7] = key; break;
            case DIR_SW: dirkey[classify_key(key)][2] = key; break;
            case DIR_S : dirkey[classify_key(key)][5] = key; break;
            case DIR_SE: dirkey[classify_key(key)][8] = key; break;
            case DIR_UP: upkey = key; break;
            case DIR_DOWN: downkey = key; break;
            case DIR_SELF: selfkey = key; break;
            default: break;
            }
        }

        for (kg = 0; kg < 3; kg++) {
            int kc = 0;
            int xmax = 0;
            for (i = 0; i < 9; i++) kc += !!dirkey[kg][i];
            if (i >= 4) {
                if (first)
                    first = FALSE;
                else {
                    mvwaddstr(win, y+1, x, "or");
                    x += 3;
                }
                for (xg = 0; xg < 9; xg += 3) {
                    for (i = 0; i < 3; i++) {
                        wmove(win, y+i, x);
                        int l = nh_waddkey(win, dirkey[kg][xg+i]);
                        if (l > xmax)
                            xmax = l;
                    }
                    x += xmax + 1;
                }
            }
        }

        x += 3;

        if (upkey) {
            wmove(win, y+0, x);
            nh_waddkey(win, upkey);
            waddstr(win, " up");
        }
        if (selfkey) {
            wmove(win, y+1, x);
            nh_waddkey(win, selfkey);
            waddstr(win, " self");
        }
        if (downkey) {
            wmove(win, y+2, x);
            nh_waddkey(win, downkey);
            waddstr(win, " down");
        }

        y_remaining -= 3;
        y += 3;
    }

    y_insert_line = y;

    if (context == krc_get_command) {
        int x = 0, i, j;

        y_remaining--; /* count a potential incomplete line */

#define hintbinding(k,s) do {                    \
            int l = strlen(friendly_keyname(k)); \
            l += strlen(s) + 1;                  \
            if (x + l > ui_flags.mapwidth) {     \
                spend_one_line();                \
                x = 0;                           \
            }                                    \
            wmove(win, y, x);                    \
            nh_waddkey(win, k);                  \
            wprintw(win, ":%s", s);              \
            x += l + 2;                          \
        } while(0)

#define hintcmd(s,d) do {                                         \
            int key;                                              \
            for (key = 0; key <= KEY_MAX; key++) {                \
                if (settings.alt_is_esc &&                        \
                    key == (KEY_ALT | (key & 0xff)))              \
                    continue;                                     \
                if (keymap[key] && !strcmp(keymap[key]->name, s)) \
                    break;                                        \
            }                                                     \
            if (key <= KEY_MAX)                                   \
                hintbinding(key, d);                              \
        } while (0)

        /* Some bindings we always want to show. */
        hintcmd("help", "help");
        hintcmd("mainmenu", "menu");
        if (!ui_flags.sidebarwidth)
            hintcmd("inventory", "inventory");

        if (ui_flags.current_followmode == FM_PLAY) {

            hintcmd("search", "search/wait");

            /* TODO: only if we have spells and at least 5 Pw */
            hintcmd("cast", "cast spell");

            /* Context-sensitive bindings. */

            /* Status effects. */
            if (player_has_status("Blind"))
                hintcmd("grope", "feel the ground");

            /* TODO: "creamed" isn't distinguished from other causes of
               blindness, so we can't mention "wipe". */

            /* Things we're standing on. */
            i = player.x;
            j = player.y;

            if (apikey_is_at("chest", i, j) ||
                apikey_is_at("large box", i, j)) {
                hintcmd("apply", "open a container");
                hintcmd("force", "force a container open");
            }
            if (apikey_is_at("fountain", i, j)) {
                hintcmd("dip", "dip");
                hintcmd("drink", "drink");
            } else if (apikey_is_at("sink", i, j)) {
                hintcmd("drink", "drink");
            }
            if (apikey_is_at("altar", i, j)) {
                hintcmd("offer", "make a sacrifice");
            }

            if (apikey_is_at("throne", i, j)) {
                hintcmd("sit", "sit");
            }

            /* Eating's normally done via itemactions, but corpses are more
               reasonable to eat from the floor. */
            if (apikey_is_at("corpse", i, j)) {
                hintcmd("eat", "eat");
            }

            if (branding_is_at(NH_BRANDING_TRAPPED, i, j)) {
                hintcmd("sit", "trigger trap");
            }

            /* Things we're next to. */
#define nearbyxy                                                        \
            for (i = player.x - 1; i <= player.x + 1; i++)              \
                for (j = player.y - 1; j <= player.y + 1; j++)          \
                    if (i >= 0 && i < COLNO && j >= 0 && j < ROWNO)

#define hintcmdbreak(s,d) do { hintcmd(s,d); i = j = INT_MAX - 1; } while(0)

            nearbyxy if (monflag_is_at(MON_TAME, i, j) ||
                         monflag_is_at(MON_PEACEFUL, i, j)) {
                hintcmdbreak("chat", "chat");
            }

            /* TODO: Riding; we really need a MON_SADDLED branding */

            nearbyxy if (branding_is_at(NH_BRANDING_TRAPPED, i, j)) {
                hintcmdbreak("idtrap", "examine trap");
                hintcmdbreak("untrap", "disarm trap");
            }

            nearbyxy if ((apikey_is_at("vcdoor", i, j) ||
                          apikey_is_at("hcdoor", i, j)) &&
                         branding_is_at(NH_BRANDING_LOCKED, i, j)) {
                hintcmdbreak("kick", "kick open a door");
                hintcmdbreak("open", "unlock a door");
            }

            nearbyxy if (apikey_is_at("vodoor", i, j) ||
                         apikey_is_at("hodoor", i, j)) {
                hintcmdbreak("open", "close a door");
            }

            nearbyxy if (apikey_is_at("chest", i, j) ||
                         apikey_is_at("large box", i, j)) {
                hintcmdbreak("kick", "kick open a container");
            }

            nearbyxy if (apikey_is_at("shopkeeper", i, j)) {
                hintcmdbreak("pay", "pay for items");
            }

            /* Low-priority bindings. */
            if (!player_has_status("Blind"))
                hintcmd("lookhere", "describe this square");
            hintcmd("autoexplore", "autoexplore");
            hintcmd("pray", "pray for help");
            hintcmd("prevmsg", "review messages");
            hintcmd("moveonly", "move without fighting");
            hintcmd("fight", "force an attack");
            hintcmd("elbereth", "write Elbereth");

        } else {
示例#4
0
文件: pager.c 项目: FredrIQ/nethack4
/* quick: use cursor && don't search for "more info" */
static int
do_look(boolean quick, const struct nh_cmd_arg *arg)
{
    const char *out_str;
    const char *firstmatch;
    int i, ans = 0, objplur = 0, is_in;
    coord cc;   /* screen pos of unknown glyph */
    boolean save_verbose;       /* saved value of flags.verbose */
    boolean from_screen;        /* question from the screen */
    struct nh_desc_buf descbuf;
    struct obj *otmp;

    if (arg->argtype & CMD_ARG_OBJ) {
        from_screen = FALSE;
    } else if (quick || (arg->argtype & CMD_ARG_POS)) {
        from_screen = TRUE;     /* yes, we want to use the cursor */
    } else {
        i = ynq("Specify unknown object by cursor?");
        if (i == 'q')
            return 0;
        from_screen = (i == 'y');
    }

    if (from_screen) {
        cc.x = u.ux;
        cc.y = u.uy;
    } else {
        if (arg->argtype & CMD_ARG_OBJ) {
            static const char allowall[] = { ALL_CLASSES, 0 };
            out_str = simple_typename(getargobj(arg, allowall, "explain")->otyp);
        } else {
            out_str = getarglin(arg, "Specify what? (type the word)");
            if (out_str[0] == '\0' || out_str[0] == '\033')
                return 0;
        }

        /* the ability to specify symbols is gone: it is simply impossible to
           know how the window port is displaying things (tiles?) and even if
           charaters are used it may not be possible to type them (utf8) */

        checkfile(out_str, NULL, !(arg->argtype & CMD_ARG_OBJ), TRUE);
        return 0;
    }
    /* Save the verbose flag, we change it later. */
    save_verbose = flags.verbose;
    flags.verbose = flags.verbose && !quick;

    /* 
     * we're identifying from the screen.
     */
    do {
        /* Reset some variables. */
        firstmatch = NULL;
        objplur = 0;

        if (flags.verbose)
            pline("Please move the cursor to %s.", what_is_an_unknown_object);
        else
            pline("Pick an object.");

        ans = getargpos(arg, &cc, FALSE, what_is_an_unknown_object);
        if (ans == NHCR_CLIENT_CANCEL || cc.x < 0) {
            flags.verbose = save_verbose;
            if (flags.verbose)
                pline(quick ? "Never mind." : "Done.");
            return 0;   /* done */
        }
        flags.verbose = FALSE;  /* only print long question once */

        nh_describe_pos(cc.x, cc.y, &descbuf, &is_in);

        otmp = vobj_at(cc.x, cc.y);
        if (otmp && is_plural(otmp))
            objplur = 1;

        out_str = "";
        if (append_str(&out_str, descbuf.effectdesc, 0, 0))
            if (!firstmatch)
                firstmatch = descbuf.effectdesc;

        if (append_str(&out_str, descbuf.invisdesc, 0, 0))
            if (!firstmatch)
                firstmatch = descbuf.invisdesc;

        /* We already have a/an added by describe_mon; don't add it again,
           because that'll fail in cases like "Dudley's ghost" */
        if (append_str(&out_str, descbuf.mondesc, 1, 0))
            if (!firstmatch)
                firstmatch = descbuf.mondesc;

        if (append_str(&out_str, descbuf.objdesc, objplur, 0))
            if (!firstmatch)
                firstmatch = descbuf.objdesc;

        if (append_str(&out_str, descbuf.trapdesc, 0, 0))
            if (!firstmatch)
                firstmatch = descbuf.trapdesc;

        if (!descbuf.feature_described &&
            append_str(&out_str, descbuf.bgdesc, 0, is_in))
            if (!firstmatch)
                firstmatch = descbuf.bgdesc;

        /* Finally, print out our explanation. */
        if (firstmatch) {
            pline("%s.", msgupcasefirst(out_str));
            /* check the data file for information about this thing */
            if (firstmatch && ans != NHCR_CONTINUE &&
                (ans == NHCR_MOREINFO ||
                 ans == NHCR_MOREINFO_CONTINUE || !quick)) {
                checkfile(firstmatch, NULL, FALSE,
                          ans == NHCR_MOREINFO ||
                          ans == NHCR_MOREINFO_CONTINUE);
            }
        } else {
            pline("I've never heard of such things.");
        }
    } while (ans == NHCR_CONTINUE || ans == NHCR_MOREINFO_CONTINUE);

    flags.verbose = save_verbose;
    if (!quick && flags.verbose)
        pline("Done.");

    return 0;
}
示例#5
0
文件: pager.c 项目: DanielT/NitroHack
/* quick: use cursor && don't search for "more info" */
static int do_look(boolean quick)
{
    char out_str[BUFSZ];
    char firstmatch[BUFSZ];
    int i, ans = 0, objplur = 0;
    int found;		/* count of matching syms found */
    coord cc;		/* screen pos of unknown glyph */
    boolean save_verbose;	/* saved value of flags.verbose */
    boolean from_screen;	/* question from the screen */
    struct nh_desc_buf descbuf;
    struct obj *otmp;

    if (quick) {
	from_screen = TRUE;	/* yes, we want to use the cursor */
    } else {
	i = ynq("Specify unknown object by cursor?");
	if (i == 'q') return 0;
	from_screen = (i == 'y');
    }

    if (from_screen) {
	cc.x = u.ux;
	cc.y = u.uy;
    } else {
	getlin("Specify what? (type the word)", out_str);
	if (out_str[0] == '\0' || out_str[0] == '\033')
	    return 0;

	/* the ability to specify symbols is gone: it is simply impossible to
	 * know how the window port is displaying things (tiles?) and even if
	 * charaters are used it may not be possible to type them (utf8)
	 */
	
	checkfile(out_str, NULL, TRUE, TRUE);
	return 0;
    }
    /* Save the verbose flag, we change it later. */
    save_verbose = flags.verbose;
    flags.verbose = flags.verbose && !quick;
    
    /*
     * we're identifying from the screen.
     */
    do {
	/* Reset some variables. */
	found = 0;
	out_str[0] = '\0';
	objplur = 0;

	if (flags.verbose)
	    pline("Please move the cursor to %s.",
		    what_is_an_unknown_object);
	else
	    pline("Pick an object.");

	ans = getpos(&cc, FALSE, what_is_an_unknown_object);
	if (ans < 0 || cc.x < 0) {
	    flags.verbose = save_verbose;
	    return 0;	/* done */
	}
	flags.verbose = FALSE;	/* only print long question once */

	nh_describe_pos(cc.x, cc.y, &descbuf);
	
	otmp = vobj_at(cc.x, cc.y);
	if (otmp && is_plural(otmp))
	    objplur = 1;
	
	out_str[0] = '\0';
	if (append_str(out_str, descbuf.effectdesc, 0))
	    if (++found == 1)
		strcpy (firstmatch, descbuf.effectdesc);
	
	if (append_str(out_str, descbuf.invisdesc, 0))
	    if (++found == 1)
		strcpy (firstmatch, descbuf.invisdesc);
	
	if (append_str(out_str, descbuf.mondesc, 0))
	    if (++found == 1)
		strcpy (firstmatch, descbuf.mondesc);
	
	if (append_str(out_str, descbuf.objdesc, objplur))
	    if (++found == 1)
		strcpy (firstmatch, descbuf.objdesc);
	
	if (append_str(out_str, descbuf.trapdesc, 0))
	    if (++found == 1)
		strcpy (firstmatch, descbuf.trapdesc);
	
	if (append_str(out_str, descbuf.bgdesc, 0))
	    if (!found) {
		found++; /* only increment found if nothing else was seen,
		so that checkfile can be called below */
		strcpy (firstmatch, descbuf.bgdesc);
	    }
	

	/* Finally, print out our explanation. */
	if (found) {
	    out_str[0] = highc(out_str[0]);
	    pline("%s.", out_str);
	    /* check the data file for information about this thing */
	    if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE &&
			(ans == LOOK_VERBOSE || !quick)) {
		checkfile(firstmatch, NULL, FALSE, ans == LOOK_VERBOSE);
	    }
	} else {
	    pline("I've never heard of such things.");
	}
    } while (!quick && ans != LOOK_ONCE);

    flags.verbose = save_verbose;

    return 0;
}
示例#6
0
int
curses_getpos(int *x, int *y, nh_bool force, const char *goal)
{
    int result = 0;
    int cx, cy;
    int key, dx, dy;
    int sidx;
    static const char pick_chars[] = " \r\n.,;:";
    static const int pick_vals[] = {1, 1, 1, 1, 2, 3, 4};
    const char *cp;
    char printbuf[BUFSZ];
    char *matching = NULL;
    enum nh_direction dir;
    struct coord *monpos = NULL;
    int moncount, monidx;
    int firstmove = 1;

    werase(statuswin);
    mvwaddstr(statuswin, 0, 0,
              "Move the cursor with the direction keys. Press "
              "the letter of a dungeon symbol");
    mvwaddstr(statuswin, 1, 0,
              "to select it or use m to move to a nearby "
              "monster. Finish with one of .,;:");
    wrefresh(statuswin);

    cx = *x >= 1 ? *x : player.x;
    cy = *y >= 0 ? *y : player.y;
    wmove(mapwin, cy, cx - 1);

    while (1) {
        if (!firstmove) {
            struct nh_desc_buf descbuf;
            int mx = 0, my = 0;

            nh_describe_pos(cx, cy, &descbuf, NULL);

            werase(statuswin);
            place_desc_message(statuswin, &mx, &my, descbuf.effectdesc);
            place_desc_message(statuswin, &mx, &my, descbuf.invisdesc);
            place_desc_message(statuswin, &mx, &my, descbuf.mondesc);
            place_desc_message(statuswin, &mx, &my, descbuf.objdesc);
            place_desc_message(statuswin, &mx, &my, descbuf.trapdesc);
            place_desc_message(statuswin, &mx, &my, descbuf.bgdesc);
            wrefresh(statuswin);

            wmove(mapwin, cy, cx - 1);
        }
        firstmove = 0;
        dx = dy = 0;
        key = get_map_key(FALSE);
        if (key == KEY_ESC) {
            cx = cy = -10;
            result = -1;
            break;
        }

        if ((cp = strchr(pick_chars, (char)key)) != 0) {
            /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
            result = pick_vals[cp - pick_chars];
            break;
        }

        dir = key_to_dir(key);
        if (dir != DIR_NONE) {
            dx = xdir[dir];
            dy = ydir[dir];
        } else if ((dir = key_to_dir(tolower((char)key))) != DIR_NONE) {
            /* a shifted movement letter */
            dx = xdir[dir] * 8;
            dy = ydir[dir] * 8;
        }

        if (dx || dy) {
            /* truncate at map edge */
            if (cx + dx < 1)
                dx = 1 - cx;
            if (cx + dx > COLNO - 1)
                dx = COLNO - 1 - cx;
            if (cy + dy < 0)
                dy = -cy;
            if (cy + dy > ROWNO - 1)
                dy = ROWNO - 1 - cy;
            cx += dx;
            cy += dy;
            goto nxtc;
        }

        if (key == 'm') {
            if (!monpos) {
                int i, j;

                moncount = 0;
                for (i = 0; i < ROWNO; i++)
                    for (j = 0; j < COLNO; j++)
                        if (display_buffer[i][j].mon &&
                            (j != player.x || i != player.y))
                            moncount++;
                monpos = malloc(moncount * sizeof (struct coord));
                monidx = 0;
                for (i = 0; i < ROWNO; i++)
                    for (j = 0; j < COLNO; j++)
                        if (display_buffer[i][j].mon &&
                            (j != player.x || i != player.y)) {
                            monpos[monidx].x = j;
                            monpos[monidx].y = i;
                            monidx++;
                        }
                monidx = 0;
                qsort(monpos, moncount, sizeof (struct coord),
                      compare_coord_dist);
            }

            if (moncount) {     /* there is at least one monster to move to */
                cx = monpos[monidx].x;
                cy = monpos[monidx].y;
                monidx = (monidx + 1) % moncount;
            }
        } else {
            int k = 0, tx, ty;
            int pass, lo_x, lo_y, hi_x, hi_y;

            matching = malloc(default_drawing->num_bgelements);
            memset(matching, 0, default_drawing->num_bgelements);
            for (sidx = default_drawing->bg_feature_offset;
                 sidx < default_drawing->num_bgelements; sidx++)
                if (key == default_drawing->bgelements[sidx].ch)
                    matching[sidx] = (char)++k;
            if (k) {
                for (pass = 0; pass <= 1; pass++) {
                    /* pass 0: just past current pos to lower right; pass 1:
                       upper left corner to current pos */
                    lo_y = (pass == 0) ? cy : 0;
                    hi_y = (pass == 0) ? ROWNO - 1 : cy;
                    for (ty = lo_y; ty <= hi_y; ty++) {
                        lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1;
                        hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1;
                        for (tx = lo_x; tx <= hi_x; tx++) {
                            k = display_buffer[ty][tx].bg;
                            if (k && matching[k]) {
                                cx = tx;
                                cy = ty;
                                goto nxtc;
                            }
                        }       /* column */
                    }   /* row */
                }       /* pass */
                sprintf(printbuf, "Can't find dungeon feature '%c'.",
                        (char)key);
                curses_msgwin(printbuf);
            } else {
                sprintf(printbuf, "Unknown direction%s.",
                        !force ? " (ESC to abort)" : "");
                curses_msgwin(printbuf);
            }
        }
        if (force)
            goto nxtc;
        cx = -1;
        cy = 0;
        result = 0;     /* not -1 */
        break;

    nxtc:
        wmove(mapwin, cy, cx - 1);
        wrefresh(mapwin);
    }

    *x = cx;
    *y = cy;
    if (monpos)
        free(monpos);
    if (matching)
        free(matching);
    curses_update_status(NULL); /* clear the help message */
    return result;
}