示例#1
0
/* display a selection menu for tilesets */
static void
select_tileset_value(union nh_optvalue *value, struct nh_option_desc *option)
{
    struct nh_menulist menu;
    int i;

    int tc;
    struct tileset_description *tilesets = get_tileset_descriptions(&tc);
    struct tileset_description tilesets_copy[tc];
    memcpy(tilesets_copy, tilesets, sizeof tilesets_copy);
    free(tilesets);

    init_menulist(&menu);

    add_menu_txt(&menu, option->helptxt, MI_TEXT);
    add_menu_txt(&menu, "", MI_TEXT);

    for (i = 0; i < tc; i++)
        add_menu_item(&menu, i + 1, tilesets_copy[i].desc, 0, 0);

    int pick_list[1];
    curses_display_menu(&menu, option->name, PICK_ONE, PLHINT_RIGHT, pick_list,
                        curses_menu_callback);

    const char *newname = option->value.s;
    if (pick_list[0] != CURSES_MENU_CANCELLED)
        newname = tilesets_copy[pick_list[0] - 1].basename;

    value->s = malloc(strlen(newname) + 1);
    strcpy(value->s, newname);
}
示例#2
0
void
doprev_message(void)
{
    struct nh_menuitem *items;
    char buf[MSGLEN + 1];
    int icount, size, i;

    icount = 0;
    size = 10;
    items = malloc(size * sizeof (struct nh_menuitem));

    for (i = 0; i < histsize; i++) {
        int pos = histpos + i + 1;

        if (pos >= histsize)    /* wrap around eventually */
            pos -= histsize;

        if (!msghistory[pos].turn)
            continue;

        snprintf(buf, MSGLEN + 1, "T:%d\t%s", msghistory[pos].turn,
                 msghistory[pos].msg);
        add_menu_txt(items, size, icount, buf, MI_TEXT);
    }

    curses_display_menu(items, icount, "Message history:", PICK_NONE,
                        PLHINT_ANYWHERE, NULL);
    free(items);
}
示例#3
0
/* display a selection menu for enum options */
static void
select_enum_value(union nh_optvalue *value, struct nh_option_desc *option)
{
    struct nh_menulist menu;
    int i, selectidx;

    init_menulist(&menu);

    add_menu_txt(&menu, option->helptxt, MI_TEXT);
    add_menu_txt(&menu, "", MI_TEXT);

    for (i = 0; i < option->e.numchoices; i++) {
        char capbuf[QBUFSZ];
        const char *cap;

        if (option->value.e == option->e.choices[i].id) {
            snprintf(capbuf, QBUFSZ, "%s (set)", option->e.choices[i].caption);
            cap = capbuf;
        } else {
            cap = option->e.choices[i].caption;
        }
        /* don't use the choice ids directly, 0 is a valid value for those */
        add_menu_item(&menu, i + 1, cap, 0, 0);
    }

    int pick_list[1];
    curses_display_menu(&menu, option->name, PICK_ONE, PLHINT_RIGHT, pick_list,
                        curses_menu_callback);

    value->e = option->value.e; /* in case of ESC */
    if (pick_list[0] != CURSES_MENU_CANCELLED) {
        selectidx = pick_list[0] - 1;
        value->e = option->e.choices[selectidx].id;
    }
}
示例#4
0
static void autopickup_rules_help(void)
{
    struct nh_menuitem items[] = {
	{0, MI_TEXT, "自动拾取规则只有当开启自动拾取功能时生效。"},
	{0, MI_TEXT, "当自动拾取功能开启时,你走到一件物品上方,这件物品"},
	{0, MI_TEXT, "将与每个规则相比较,直到有一个规则满足。"},
	{0, MI_TEXT, "如果存在一个满足的规则,与此规则相对应的动作将被执"},
	{0, MI_TEXT, "行,然后其他的规矩将被忽略。"},
	{0, MI_TEXT, ""},
	{0, MI_TEXT, "每个规则都可以匹配物体名称、类型或祝福状态的任意组"},
	{0, MI_TEXT, "何(包括未知的情况)。"},
	{0, MI_TEXT, "可以设置一个规则来匹配任意的情况。"},
	{0, MI_TEXT, ""},
	{0, MI_TEXT, "加入你的匹配规则像这样:"},
	{0, MI_TEXT, " 1. IF name matches \"*lizard*\" AND type is \"food\": < GRAB"},
	{0, MI_TEXT, " 2. IF name matches \"*corpse*\" AND type is \"food\":   LEAVE >"},
	{0, MI_TEXT, " 3. IF type is \"food\":                             < GRAB"},
	{0, MI_TEXT, ""},
	{0, MI_TEXT, "“newt corpse”将不满足规则1,但是会满足规则2。"},
	{0, MI_TEXT, "它将不会被拾取,规则3也将被忽略。"},
	{0, MI_TEXT, "(严格地说,\"type is food\"这条规则并不是必须"},
	{0, MI_TEXT, "的;它在这只是为了让例子更有趣一些。)"},
	{0, MI_TEXT, ""},
	{0, MI_TEXT, "“dagger”将不会匹配上述任何一种情况,所有它将不会"},
	{0, MI_TEXT, "被自动拾取。"},
	{0, MI_TEXT, ""},
	{0, MI_TEXT, "你可以在列表中选择一个已存在的规则来编辑它,修改它"},
	{0, MI_TEXT, "的条件,或者删除它。"},
    };
    curses_display_menu(items, listlen(items), "自动拾取规则帮助:", PICK_NONE, NULL);
}
示例#5
0
static void
show_replay_help(void)
{
    static struct nh_menuitem items[] = {
        {0, MI_TEXT, "KEY_RIGHT or SPACE\t- advance one move"},
        {0, MI_TEXT, "KEY_LEFT\t- go back one move"},
        {0, MI_TEXT, "g\t- go to any move"},
        {0, MI_TEXT, "ESC\t- leave the replay"},
        {0, MI_TEXT, ""},
        {0, MI_TEXT,
         "Informational game commands like \"inventory\" or \"discoveries\" will also work"}
    };
    curses_display_menu(items, 6, "Replay help:", PICK_NONE, PLHINT_INFO, NULL);
}
示例#6
0
void
print_options(void)
{
    struct nh_menulist menu;
    int i;
    char buf[BUFSZ];
    struct nh_option_desc *options = curses_get_nh_opts();

    init_menulist(&menu);

    add_menu_txt(&menu, "Birth options:", MI_HEADING);
    for (i = 0; options[i].name; i++) {
        if (options[i].birth_option != nh_birth_lasting)
            continue;
        snprintf(buf, BUFSZ, "%s\t%s", options[i].name, options[i].helptxt);
        add_menu_txt(&menu, buf, MI_TEXT);
    }
    add_menu_txt(&menu, "", MI_TEXT);

    add_menu_txt(&menu, "Game creation options:", MI_HEADING);
    for (i = 0; options[i].name; i++) {
        if (options[i].birth_option != nh_birth_creation)
            continue;
        snprintf(buf, BUFSZ, "%s\t%s", options[i].name, options[i].helptxt);
        add_menu_txt(&menu, buf, MI_TEXT);
    }
    add_menu_txt(&menu, "", MI_TEXT);

    add_menu_txt(&menu, "Game options:", MI_HEADING);
    for (i = 0; options[i].name; i++) {
        if (options[i].birth_option != nh_birth_ingame)
            continue;
        snprintf(buf, BUFSZ, "%s\t%s", options[i].name, options[i].helptxt);
        add_menu_txt(&menu, buf, MI_TEXT);
    }
    add_menu_txt(&menu, "", MI_TEXT);

    /* add UI specific options */
    add_menu_txt(&menu, "Interface options:", MI_HEADING);
    for (i = 0; curses_options[i].name; i++) {
        snprintf(buf, BUFSZ, "%s\t%s", curses_options[i].name,
                 curses_options[i].helptxt);
        add_menu_txt(&menu, buf, MI_TEXT);
    }

    curses_display_menu(&menu, "Available options:", PICK_NONE,
                        PLHINT_ANYWHERE, NULL, null_menu_callback);

    curses_free_nh_opts(options);
}
示例#7
0
static enum nh_bucstatus get_autopickup_buc(enum nh_bucstatus cur)
{
    struct nh_menuitem items[] = {
	{B_DONT_CARE + 1,MI_NORMAL, "all", 'a'},
	{B_BLESSED + 1,	MI_NORMAL, "blessed", 'b'},
	{B_CURSED + 1,	MI_NORMAL, "cursed", 'c'},
	{B_UNCURSED + 1,MI_NORMAL, "uncursed", 'u'},
	{B_UNKNOWN + 1,	MI_NORMAL, "unknown", 'U'}
    };
    int n, selected[1];
    n = curses_display_menu(items, 5, "Beatitude match:", PICK_ONE, selected);
    if (n <= 0)
	return cur;
    return selected[0]-1;
}
示例#8
0
static enum msgtype_action get_msgtype_action(enum msgtype_action current)
{
    struct nh_menuitem items[] = {
	{MSGTYPE_DEFAULT + 1,	MI_NORMAL, "DEFAULT", 'd'},
	{MSGTYPE_MORE + 1,	MI_NORMAL, "MORE", 'm'},
	{MSGTYPE_NO_REPEAT + 1,	MI_NORMAL, "NO REPEAT", 'r'},
	{MSGTYPE_HIDE + 1,	MI_NORMAL, "HIDE", 'h'},
    };
    int n, selected[1];
    char query[QBUFSZ];
    sprintf(query, "Message type action: (currently %s)",
	    msgtype_action_string(current));
    n = curses_display_menu(items, listlen(items), query, PICK_ONE, selected);
    if (n <= 0)
	return current;
    return selected[0] - 1;
}
示例#9
0
void
net_loadgame(void)
{
    char buf[BUFSZ];
    struct nhnet_game *gamelist;
    struct nh_menulist menu;
    int id, size, i, ret, pick[1];

    gamelist = nhnet_list_games(FALSE, FALSE, &size);
    if (!gamelist) {
        curses_msgwin("Failed to retrieve the list of saved games.",
                      krc_notification);
        return;
    }
    if (!size) {
        curses_msgwin("No saved games found.", krc_notification);
        return;
    }

    init_menulist(&menu);

    for (i = 0; i < size; i++) {
        if (gamelist[i].status == LS_DONE || gamelist[i].status == LS_INVALID)
            continue;
        describe_game(buf, gamelist[i].status, &gamelist[i].i);
        id = (gamelist[i].status == LS_IN_PROGRESS) ? 0 : gamelist[i].gameid;
        add_menu_item(&menu, id, buf, 0, FALSE);
    }

    curses_display_menu(&menu, "saved games", PICK_ONE, PLHINT_ANYWHERE, pick,
                        curses_menu_callback);

    if (*pick == CURSES_MENU_CANCELLED)
        return;

    id = pick[0];

    create_game_windows();

    ret = playgame(id, FM_PLAY);

    destroy_game_windows();
    cleanup_messages();

    game_ended(ret, NULL, TRUE);
}
示例#10
0
static void
autopickup_rules_help(void)
{
    struct nh_menuitem items[] = {
        {0, MI_TEXT,
         "The autopickup rules are only active if autopickup is on."},
        {0, MI_TEXT,
         "If autopickup is on and you walk onto an item, the item is compared"},
        {0, MI_TEXT, "to each rule in turn until a matching rule is found."},
        {0, MI_TEXT,
         "If a match is found, the action specified in that rule is taken"},
        {0, MI_TEXT, "and no other rules are considered."},
        {0, MI_TEXT, ""},
        {0, MI_TEXT,
         "Each rule may match any combination of object name, object type,"},
        {0, MI_TEXT, "and object blessing (including unknown)."},
        {0, MI_TEXT, "A rule that specifies none of these matches everything."},
        {0, MI_TEXT, ""},
        {0, MI_TEXT, "Suppose your rules look like this:"},
        {0, MI_TEXT,
         " 1. IF name matches \"*lizard*\" AND type is \"food\": < GRAB"},
        {0, MI_TEXT,
         " 2. IF name matches \"*corpse*\" AND type is \"food\":   LEAVE >"},
        {0, MI_TEXT,
         " 3. IF type is \"food\":                             < GRAB"},
        {0, MI_TEXT, ""},
        {0, MI_TEXT,
         "A newt corpse will not match rule 1, but rule 2 applies, so"},
        {0, MI_TEXT, "it won't be picked up and rule 3 won't be considered."},
        {0, MI_TEXT,
         "(Strictly speaking, the \"type is food\" part of these rules is not"},
        {0, MI_TEXT, "necessary; it's purpose here is to make the example more "
         "interesting.)"},
        {0, MI_TEXT, ""},
        {0, MI_TEXT,
         "A dagger will not match any of these rules and so it won't"},
        {0, MI_TEXT, "be picked up either."},
        {0, MI_TEXT, ""},
        {0, MI_TEXT,
         "You may select any existing rule to edit it, change its position"},
        {0, MI_TEXT, "in the list, or delete it."},
    };
    curses_display_menu(STATIC_MENULIST(items), "Autopickup rules help:",
                        PICK_NONE, PLHINT_LEFT, NULL, null_menu_callback);
}
示例#11
0
static enum nh_bucstatus
get_autopickup_buc(enum nh_bucstatus cur)
{
    struct nh_menuitem items[] = {
        {B_DONT_CARE + 1, MI_NORMAL, "all", 'a'},
        {B_BLESSED + 1, MI_NORMAL, "blessed", 'b'},
        {B_CURSED + 1, MI_NORMAL, "cursed", 'c'},
        {B_UNCURSED + 1, MI_NORMAL, "uncursed", 'u'},
        {B_UNKNOWN + 1, MI_NORMAL, "unknown", 'U'}
    };
    int selected[1];

    curses_display_menu(STATIC_MENULIST(items), "Beatitude match:",
                        PICK_ONE, PLHINT_RIGHT, selected, curses_menu_callback);
    if (*selected == CURSES_MENU_CANCELLED)
        return cur;
    return selected[0] - 1;
}
示例#12
0
static int get_autopickup_oclass(struct nh_autopick_option *desc, int cur)
{
    int i, n, size, icount, selected[1];
    struct nh_menuitem *items;
    
    size = desc->numclasses;
    items = malloc(sizeof(struct nh_menuitem) * size);
    icount = 0;
    
    for (i = 0; i < desc->numclasses; i++)
	add_menu_item(items, size, icount, desc->classes[i].id,
		      desc->classes[i].caption, (char)desc->classes[i].id, 0);
	
    n = curses_display_menu(items, icount, "Object class match:", PICK_ONE, selected);
    free(items);
    if (n <= 0)
	return cur;
    return selected[0];
}
示例#13
0
static int
get_autopickup_oclass(struct nh_autopick_option *desc, int cur)
{
    int i, selected[1];
    struct nh_menulist menu;

    init_menulist(&menu);

    for (i = 0; i < desc->numclasses; i++)
        add_menu_item(&menu, desc->classes[i].id, desc->classes[i].caption,
                      (char)desc->classes[i].id, 0);

    curses_display_menu(&menu, "Object class match:", PICK_ONE,
                        PLHINT_RIGHT, selected, curses_menu_callback);

    if (*selected == CURSES_MENU_CANCELLED)
        return cur;
    return selected[0];
}
示例#14
0
/* display a selecton menu for boolean options */
static void
select_boolean_value(union nh_optvalue *value, struct nh_option_desc *option)
{
    struct nh_menulist menu;
    int pick_list[1];

    init_menulist(&menu);

    add_menu_txt(&menu, option->helptxt, MI_TEXT);
    add_menu_txt(&menu, "", MI_TEXT);
    add_menu_item(&menu, 1, option->value.b ? "true (set)" : "true", 't', 0);
    add_menu_item(&menu, 2, option->value.b ? "false" : "false (set)", 'f', 0);

    curses_display_menu(&menu, option->name, PICK_ONE, PLHINT_RIGHT,
                        pick_list, curses_menu_callback);

    value->b = option->value.b; /* in case of ESC */
    if (pick_list[0] != CURSES_MENU_CANCELLED)
        value->b = pick_list[0] == 1;
}
示例#15
0
static void msgtype_help(void)
{
    struct nh_menuitem items[] = {
	{0, MI_TEXT, "消息类型能让你将某些消息在游戏中以不同的方式"},
	{0, MI_TEXT, "显示出来,像暂停等待输入 --More--,"},
	{0, MI_TEXT, "重复崩溃的消息或者隐藏的消息入口。"},
	{0, MI_TEXT, ""},
	{0, MI_TEXT, "一个匹配的消息可能的动作:"},
	{0, MI_TEXT, "    DEFAULT    视为一条普通的消息"},
	{0, MI_TEXT, "    MORE       在这条消息之后用 --More-- 暂停"},
	{0, MI_TEXT, "    NO REPEAT  隐藏这条消息的重复部分"},
	{0, MI_TEXT, "    HIDE       完全隐藏这条消息"},
	{0, MI_TEXT, ""},
	{0, MI_TEXT, "被匹配的消息的排序模式:"},
	{0, MI_TEXT, "    ?                    匹配任何单个字符"},
	{0, MI_TEXT, "    *                    匹配任何长度的字符串"},
	{0, MI_TEXT, "    所有其他的字符匹配它自己"},
	{0, MI_TEXT, ""},
	{0, MI_TEXT, "选择一个已有的项来编辑,重排或者删除它。"},
    };
    curses_display_menu(items, listlen(items), "消息类型帮助:",
			PICK_NONE, NULL);
}
示例#16
0
/* display a selecton menu for boolean options */
static void select_boolean_value(union nh_optvalue *value, struct nh_option_desc *option)
{
    struct nh_menuitem *items;
    int icount, size;
    int n, pick_list[2];

    icount = 0; size = 4;
    items = malloc(sizeof(struct nh_menuitem) * size);

    add_menu_txt(items, size, icount, option->helptxt, MI_TEXT);
    add_menu_txt(items, size, icount, "", MI_TEXT);
    add_menu_item(items, size, icount, 1,
		  option->value.b ? "是(已设)" : "是", 't', 0);
    add_menu_item(items, size, icount, 2,
		  option->value.b ? "否" : "否(已设)", 'f', 0);

    n = curses_display_menu(items, icount, option->name, PICK_ONE, pick_list);
    free(items);

    value->b = option->value.b; /* in case of ESC */
    if (n == 1)
	value->b = pick_list[0] == 1;
}
示例#17
0
/* display a selection menu for enum options */
static void select_enum_value(union nh_optvalue *value, struct nh_option_desc *option)
{
    struct nh_menuitem *items;
    int icount, size;
    int i, n, selectidx, *pick_list;

    icount = 0; size = 10;
    items = malloc(sizeof(struct nh_menuitem) * size);

    add_menu_txt(items, size, icount, option->helptxt, MI_TEXT);
    add_menu_txt(items, size, icount, "", MI_TEXT);

    for (i = 0; i < option->e.numchoices; i++) {
	char capbuf[QBUFSZ];
	char *cap;
	if (option->value.e == option->e.choices[i].id) {
	    snprintf(capbuf, QBUFSZ, "%s(已设)", option->e.choices[i].caption);
	    cap = capbuf;
	} else {
	    cap = option->e.choices[i].caption;
	}
	/* don't use the choice ids directly, 0 is a valid value for those */
	add_menu_item(items, size, icount, i+1, cap, 0, 0);
    }

    pick_list = malloc(sizeof(int) * icount);
    n = curses_display_menu(items, icount, option->name, PICK_ONE, pick_list);
    free(items);

    value->e = option->value.e; /* in case of ESC */
    if (n == 1) {
	selectidx = pick_list[0] - 1;
	value->e = option->e.choices[selectidx].id;
    }
    free(pick_list);
}
示例#18
0
void print_options(void)
{
    struct nh_menuitem *items;
    int i, icount, size;
    char buf[BUFSZ];
    struct nh_option_desc *options;

    icount = 0; size = 10;
    items = malloc(sizeof(struct nh_menuitem) * size);
    
    add_menu_txt(items, size, icount, "创建人物设置:", MI_HEADING);
    options = nh_get_options(CURRENT_BIRTH_OPTIONS);
    for (i = 0; options[i].name; i++) {
	snprintf(buf, BUFSZ, "%s\t%s", options[i].name, options[i].helptxt);
	add_menu_txt(items, size, icount, buf, MI_TEXT);
    }
    add_menu_txt(items, size, icount, "", MI_TEXT);
    
    add_menu_txt(items, size, icount, "游戏设置:", MI_HEADING);
    options = nh_get_options(GAME_OPTIONS);
    for (i = 0; options[i].name; i++) {
	snprintf(buf, BUFSZ, "%s\t%s", options[i].name, options[i].helptxt);
	add_menu_txt(items, size, icount, buf, MI_TEXT);
    }
    add_menu_txt(items, size, icount, "", MI_TEXT);

    /* add UI specific options */
    add_menu_txt(items, size, icount, "界面设置:", MI_HEADING);
    for (i = 0; curses_options[i].name; i++) {
	snprintf(buf, BUFSZ, "%s\t%s", curses_options[i].name, curses_options[i].helptxt);
	add_menu_txt(items, size, icount, buf, MI_TEXT);
    }

    curses_display_menu(items, icount, "可用选项:", PICK_NONE, NULL);
    free(items);
}
示例#19
0
void
net_replay(void)
{
    char buf[BUFSZ];
    struct nhnet_game *gamelist;
    struct nh_menulist menu;
    int pick[1];
    int i, gamecount, gameid, want_done, show_all;

    want_done = FALSE;
    show_all = TRUE;
    while (1) {
        gamelist = nhnet_list_games(want_done, show_all, &gamecount);

        init_menulist(&menu);

        if (!gamecount)
            add_menu_txt(&menu, "(No games in this list)",
                         MI_NORMAL);

        /* add all the files to the menu */
        for (i = 0; i < gamecount; i++) {
            describe_game(buf, gamelist[i].status, &gamelist[i].i);
            add_menu_item(&menu, gamelist[i].gameid, buf, 0,
                          FALSE);
        }

        add_menu_txt(&menu, "", MI_NORMAL);
        if (want_done)
            add_menu_item(&menu, -1, show_all ? "Watch current games" :
                          "Replay your unfinished games", '!', FALSE);
        else
            add_menu_item(&menu, -1,
                          "Replay a completed game", '!', FALSE);

        if (show_all)
            add_menu_item(&menu, -2, want_done ? "View your completed games" :
                          "View your saved games", '#', FALSE);
        else
            add_menu_item(&menu, -2, "View games from other players",
                          '#', FALSE);

        curses_display_menu(&menu, want_done ? show_all ?
                            "Completed games by other players" :
                            "Your completed games" : show_all ?
                            "Pick a current game to watch" :
                            "Replay your saved games", PICK_ONE,
                            PLHINT_ANYWHERE, pick, curses_menu_callback);
        if (pick[0] == CURSES_MENU_CANCELLED)
            return;

        if (pick[0] == -1) {
            want_done = !want_done;
            if (want_done)
                show_all = FALSE; /* will normally be intended */
            continue;
        } else if (pick[0] == -2) {
            show_all = !show_all;
            continue;
        } else
            gameid = pick[0];

        break;
    }

    create_game_windows();

    /* If the game is over, we want to replay (nothing to watch). If it's our
       game, we want to replay (not much point in watching yourself). Otherwise,
       we start in watch mode; the player can change to replay mode from the
       watch menu. */
    int ret = playgame(gameid, show_all && !want_done ? FM_WATCH : FM_REPLAY);

    destroy_game_windows();
    cleanup_messages();

    game_ended(ret, NULL, TRUE);
}
示例#20
0
static void
edit_ap_rule(struct nh_autopick_option *desc, struct nh_autopickup_rules *ar,
             int ruleno)
{
    struct nh_autopickup_rule *r = &ar->rules[ruleno];
    struct nh_autopickup_rule tmprule;
    struct nh_menulist menu;
    int i, selected[1], newpos, allocsize;
    char query[BUFSZ], buf[BUFSZ];
    const char *classname;

    do {
        init_menulist(&menu);

        snprintf(buf, ARRAY_SIZE(buf), "rule position:\t[%d]", ruleno + 1);
        add_menu_item(&menu, 1, buf, 0, 0);

        snprintf(buf, ARRAY_SIZE(buf), "name pattern:\t[%s]", r->pattern);
        add_menu_item(&menu, 2, buf, 0, 0);

        classname = NULL;
        for (i = 0; i < desc->numclasses && !classname; i++)
            if (desc->classes[i].id == r->oclass)
                classname = desc->classes[i].caption;
        snprintf(buf, ARRAY_SIZE(buf), "object type:\t[%s]", classname);
        add_menu_item(&menu, 3, buf, 0, 0);

        snprintf(buf, ARRAY_SIZE(buf), "beatitude:\t[%s]", bucnames[r->buc]);
        add_menu_item(&menu, 4, buf, 0, 0);

        snprintf(buf, ARRAY_SIZE(buf), "action:\t[%s]", r->action == AP_GRAB ? "GRAB" : "LEAVE");
        add_menu_item(&menu, 5, buf, 0, 0);
        add_menu_txt(&menu, "", MI_TEXT);
        add_menu_item(&menu, 6, "delete this rule", 'x', 0);

        curses_display_menu(&menu, "Edit rule:", PICK_ONE, PLHINT_RIGHT,
                            selected, curses_menu_callback);
        if (*selected == CURSES_MENU_CANCELLED)
            return;

        switch (selected[0]) {
            /* move this rule */
        case 1:
            snprintf(query, ARRAY_SIZE(query), "New rule position: (1 - %d), currently: %d",
                    ar->num_rules, ruleno + 1);
            newpos = ar->num_rules;
            curses_getline(query, &newpos, rule_position_callback);
            newpos--;
            if (newpos == ruleno || newpos < 0)
                break;

            tmprule = ar->rules[ruleno];
            /* shift the rules around */
            if (newpos > ruleno) {
                for (i = ruleno; i < newpos; i++)
                    ar->rules[i] = ar->rules[i + 1];
            } else {
                for (i = ruleno; i > newpos; i--)
                    ar->rules[i] = ar->rules[i - 1];
            }
            ar->rules[newpos] = tmprule;
            return;

            /* edit the pattern */
        case 2:
            snprintf(query, ARRAY_SIZE(query), "New name pattern (empty matches everything):");
            curses_getline(query, r->pattern, rule_pattern_callback);
            break;

            /* edit object class match */
        case 3:
            r->oclass = get_autopickup_oclass(desc, r->oclass);
            break;

            /* edit beatitude match */
        case 4:
            r->buc = get_autopickup_buc(r->buc);
            break;

            /* toggle action */
        case 5:
            if (r->action == AP_GRAB)
                r->action = AP_LEAVE;
            else
                r->action = AP_GRAB;
            break;

            /* delete */
        case 6:
            for (i = ruleno; i < ar->num_rules - 1; i++)
                ar->rules[i] = ar->rules[i + 1];
            ar->num_rules--;
            allocsize = ar->num_rules;
            if (allocsize < 1)
                allocsize = 1;
            ar->rules =
                realloc(ar->rules,
                        allocsize * sizeof (struct nh_autopickup_rule));
            return;
        }

    } while (1);
}
示例#21
0
static void show_autopickup_menu(struct nh_option_desc *opt)
{
    struct nh_menuitem *items;
    int i, j, n, icount, size, menusize, parts, selected[1], id;
    struct nh_autopickup_rule *r;
    char buf[BUFSZ];
    struct nh_autopickup_rule *rule;
    union nh_optvalue value;
    
    /* clone autopickup rules */
    value.ar = malloc(sizeof(struct nh_autopickup_rules));
    value.ar->num_rules = 0;
    value.ar->rules = NULL;
    if (opt->value.ar){
	value.ar->num_rules = opt->value.ar->num_rules;
	size = value.ar->num_rules * sizeof(struct nh_autopickup_rule);
	value.ar->rules = malloc(size);
	memcpy(value.ar->rules, opt->value.ar->rules, size);
    }
    
    menusize = value.ar->num_rules + 4;
    items = malloc(sizeof(struct nh_menuitem) * menusize);

    selected[0] = 0;
    do {
	icount = 0;
	
	add_menu_txt(items, menusize, icount, "Pos\tRule\tAction", MI_HEADING);
	
	/* list the rules in human-readable form */
	for (i = 0; i < value.ar->num_rules; i++) {
	    r = &value.ar->rules[i];
	    parts = 0;
	    sprintf(buf, "%2d.\tIF ", i+1);
	    
	    if (strlen(r->pattern)) {
		parts++;
		sprintf(buf + strlen(buf), "name matches \"%s\"", r->pattern);
	    }
	    
	    if (r->oclass != OCLASS_ANY) {
		char *classname = NULL;
		for (j = 0; j < opt->a.numclasses && !classname; j++)
		    if (opt->a.classes[j].id == r->oclass)
			classname = opt->a.classes[j].caption;
		
		if (parts++)
		    strcat(buf, " AND ");
		sprintf(buf + strlen(buf), "type is \"%s\"", classname);
	    }
	    
	    if (r->buc != B_DONT_CARE) {
		if (parts++)
		    strcat(buf, " AND ");
		sprintf(buf + strlen(buf), "beatitude is %s", bucnames[r->buc]);
	    }
	    
	    if (!parts)
		sprintf(buf, "%2d.\teverything", i+1);
	    
	    if (r->action == AP_GRAB)
		sprintf(buf + strlen(buf), ":\t< GRAB");
	    else
		sprintf(buf + strlen(buf), ":\t  LEAVE >");
	    
	    add_menu_item(items, menusize, icount, i+1, buf, 0, 0);
	}
	
	add_menu_txt(items, menusize, icount, "", MI_TEXT);
	add_menu_item(items, menusize, icount, -1, "add a new rule", '!', 0);
	add_menu_item(items, menusize, icount, -2, "help", '?', 0);
	
	/* If the previous selection was to add a rule, scroll to the bottom now
	 * so that the player can see it. */
	if (selected[0] == -1) {
	    n = curses_display_menu_bottom(items, icount, "Autopickup rules:",
					   PICK_ONE, selected);
	} else {
	    n = curses_display_menu(items, icount, "Autopickup rules:",
				    PICK_ONE, selected);
	}
	if (n <= 0)
	    break;
	
	/* add or edit a rule */
	id = selected[0];
	if (id == -1) {
	    /* create a new rule */
	    id = value.ar->num_rules;
	    value.ar->num_rules++;
	    size = value.ar->num_rules * sizeof(struct nh_autopickup_rule);
	    value.ar->rules = realloc(value.ar->rules, size);
	    
	    rule = &value.ar->rules[id];
	    rule->pattern[0] = '\0';
	    rule->oclass = OCLASS_ANY;
	    rule->buc = B_DONT_CARE;
	    rule->action = AP_GRAB;
	} else if (id == -2) {
	    autopickup_rules_help();
	    continue;
	} else
	    id--;
	
	edit_ap_rule(&opt->a, value.ar, id);
    } while (n > 0);
    
    nh_set_option(opt->name, value, FALSE);
    
    free(value.ar->rules);
    free(value.ar);
    free(items);
}
示例#22
0
static void edit_ap_rule(struct nh_autopick_option *desc,
			 struct nh_autopickup_rules *ar, int ruleno)
{
    struct nh_autopickup_rule *r = &ar->rules[ruleno];
    struct nh_autopickup_rule tmprule;
    struct nh_menuitem *items;
    int i, icount, size = 7, n, selected[1], newpos;
    char query[BUFSZ], buf[BUFSZ], *classname;
    
    items = malloc(sizeof(struct nh_menuitem) * size);
    
    do {
	icount = 0;
	sprintf(buf, "rule position:\t[%d]", ruleno + 1);
	add_menu_item(items, size, icount, 1, buf, 0, 0);
	
	sprintf(buf, "name pattern:\t[%s]", r->pattern);
	add_menu_item(items, size, icount, 2, buf, 0, 0);
	
	classname = NULL;
	for (i = 0; i < desc->numclasses && !classname; i++)
	    if (desc->classes[i].id == r->oclass)
		classname = desc->classes[i].caption;
	sprintf(buf, "object type:\t[%s]", classname);
	add_menu_item(items, size, icount, 3, buf, 0, 0);
	
	sprintf(buf, "beatitude:\t[%s]", bucnames[r->buc]);
	add_menu_item(items, size, icount, 4, buf, 0, 0);
	
	sprintf(buf, "action:\t[%s]", r->action == AP_GRAB ? "GRAB" : "LEAVE");
	add_menu_item(items, size, icount, 5, buf, 0, 0);
	add_menu_txt(items, size, icount, "", MI_TEXT);
	add_menu_item(items, size, icount, 6, "delete this rule", 'x', 0);
	
	n = curses_display_menu(items, icount, "Edit rule:", PICK_ONE, selected);
	if (n <= 0)
	    break;
	
	switch (selected[0]) {
	    /* move this rule */
	    case 1:
		sprintf(query, "New rule position: (1 - %d), currently: %d",
			ar->num_rules, ruleno + 1);
		buf[0] = '\0';
		curses_getline(query, buf);
		if (!*buf || *buf == '\033')
		    break;
		newpos = atoi(buf);
		if (newpos <= 0 || newpos > ar->num_rules) {
		    curses_msgwin("Invalid rule position.");
		    break;
		}
		newpos--;
		if (newpos == ruleno)
		    break;
		
		tmprule = ar->rules[ruleno];
		/* shift the rules around */
		if (newpos > ruleno) {
		    for (i = ruleno; i < newpos; i++)
			ar->rules[i] = ar->rules[i+1];
		} else {
		    for (i = ruleno; i > newpos; i--)
			ar->rules[i] = ar->rules[i-1];
		}
		ar->rules[newpos] = tmprule;
		goto out;
		
	    /* edit the pattern */
	    case 2:
		sprintf(query, "New name pattern (empty matches everything):");
		buf[0] = '\0';
		curses_getline(query, buf);
		if (*buf != '\033')
		    strncpy(r->pattern, buf, sizeof(r->pattern));
		r->pattern[sizeof(r->pattern)-1] = '\0';
		break;
	    
	    /* edit object class match */
	    case 3:
		r->oclass = get_autopickup_oclass(desc, r->oclass);
		break;
	    
	    /* edit beatitude match */
	    case 4:
		r->buc = get_autopickup_buc(r->buc);
		break;
		
	    /* toggle action */
	    case 5:
		if (r->action == AP_GRAB)
		    r->action = AP_LEAVE;
		else
		    r->action = AP_GRAB;
		break;
		
	    /* delete */
	    case 6:
		for (i = ruleno; i < ar->num_rules - 1; i++)
		    ar->rules[i] = ar->rules[i+1];
		ar->num_rules--;
		ar->rules = realloc(ar->rules, ar->num_rules * sizeof(struct nh_autopickup_rule));
		goto out; /* break just beaks the switch .. doh */
	}
	
    } while (n > 0);
out:
    free(items);
}
示例#23
0
static void msgtype_edit_rule(struct nh_msgtype_rules *mt_rules, int ruleno)
{
    struct nh_msgtype_rule *rule;
    /* Menu variables. */
    struct nh_menuitem *items;
    int icount, menusize, selected[1], n;

    rule = &mt_rules->rules[ruleno];

    menusize = 5;
    items = malloc(sizeof(struct nh_menuitem) * menusize);

    do {
	char buf[BUFSZ], query[BUFSZ];
	int i;
	icount = 0;

	sprintf(buf, "Position:\t[%d]", ruleno + 1);
	add_menu_item(items, menusize, icount, 1, buf, 0, 0);

	sprintf(buf, "Action:\t[%s]", msgtype_action_string(rule->action));
	add_menu_item(items, menusize, icount, 2, buf, 0, 0);

	sprintf(buf, "Pattern:\t[%s]", rule->pattern);
	add_menu_item(items, menusize, icount, 3, buf, 0, 0);

	add_menu_txt(items, menusize, icount, "", MI_TEXT);
	add_menu_item(items, menusize, icount, 4, "Delete this match", '!', 0);

	n = curses_display_menu(items, icount, "Edit match:", PICK_ONE, selected);
	if (n > 0) {
	    switch (selected[0]) {
	    case 1:	/* change position */
		{
		    int newpos;
		    struct nh_msgtype_rule tmprule;

		    sprintf(query, "New match position: (1 - %d, currently %d)",
			    mt_rules->num_rules, ruleno + 1);
		    buf[0] = '\0';
		    curses_getline(query, buf);
		    if (!*buf || *buf == '\033')
			break;

		    newpos = atoi(buf);
		    if (newpos <= 0 || newpos > mt_rules->num_rules) {
			curses_msgwin("Invalid match position.");
			break;
		    }

		    newpos--;
		    if (newpos == ruleno)
			break;

		    tmprule = mt_rules->rules[ruleno];
		    /* Shuffle rules in-between. */
		    if (newpos > ruleno) {
			for (i = ruleno; i < newpos; i++)
			    mt_rules->rules[i] = mt_rules->rules[i + 1];
		    } else {
			for (i = ruleno; i > newpos; i--)
			    mt_rules->rules[i] = mt_rules->rules[i - 1];
		    }
		    mt_rules->rules[newpos] = tmprule;

		    /* Exit menu do-while (n > 0) */
		    n = 0;
		}
		break;

	    case 2:	/* change action */
		rule->action = get_msgtype_action(rule->action);
		break;

	    case 3:	/* change pattern */
		snprintf(query, BUFSZ, "New match pattern: (currently \"%s\")",
			 rule->pattern);
		buf[0] = '\0';
		curses_getline(query, buf);
		if (*buf != '\033') {
		    /* Replace the same chars as msgtype_to_string to reduce
		     * player surprise when loading a game and viewing msgtypes. */
		    for (i = 0; i < sizeof(buf); i++) {
			if (buf[i] == '"' || buf[i] == '|' || buf[i] == ';')
			    buf[i] = '?';
		    }
		    strncpy(rule->pattern, buf, sizeof(rule->pattern));
		}
		rule->pattern[sizeof(rule->pattern) - 1] = '\0';
		break;

	    case 4:	/* delete match */
		/* Shuffle rules down. */
		for (i = ruleno; i < mt_rules->num_rules - 1; i++)
		    mt_rules->rules[i] = mt_rules->rules[i + 1];
		mt_rules->num_rules--;
		mt_rules->rules = realloc(mt_rules->rules, mt_rules->num_rules *
					  sizeof(struct nh_msgtype_rule));
		/* Exit menu do-while (n > 0) */
		n = 0;
		break;

	    default:
		curses_msgwin("无效的消息类型匹配目录选择。");
	    }
	}
    } while (n > 0);

    free(items);
}
示例#24
0
static nh_bool tutorial_player_selection(int *out_role, int *out_race,
					 int *out_gend, int *out_align)
{
    const struct nh_roles_info *ri;
    struct nh_menuitem items[4];	/* 3 options + quit */
    int pick_list[2];
    int result;

    ri = nh_get_roles();
    if (!ri)
	return FALSE;

    set_menuitem(&items[0], 1, MI_NORMAL,
		 "lawful female dwarf Valkyrie (uses melee and thrown weapons)",
		 'v', 0);
    set_menuitem(&items[1], 2, MI_NORMAL,
		 "chaotic male elf Wizard      (relies mostly on spells)",
		 'w', 0);
    set_menuitem(&items[2], 3, MI_NORMAL,
		 "neutral female human Ranger  (good with ranged combat)",
		 'R', 0);
    set_menuitem(&items[3], 4, MI_NORMAL,
		 "quit",
		 'q', 0);

    result = curses_display_menu(items, 4, "Choose a character", PICK_ONE, pick_list);
    if (result == -1 || pick_list[0] == -1)
	return FALSE;

    switch (pick_list[0]) {
    case 1:
	if (!find_role(ri, "Valkyrie", out_role) ||
	    !find_race(ri, "dwarf", out_race) ||
	    !find_gend(ri, "female", out_gend) ||
	    !find_align(ri, "lawful", out_align))
	    return FALSE;
	break;
    case 2:
	if (!find_role(ri, "Wizard", out_role) ||
	    !find_race(ri, "elf", out_race) ||
	    !find_gend(ri, "male", out_gend) ||
	    !find_align(ri, "chaotic", out_align))
	    return FALSE;
	break;
    case 3:
	if (!find_role(ri, "Ranger", out_role) ||
	    !find_race(ri, "human", out_race) ||
	    !find_gend(ri, "female", out_gend) ||
	    !find_align(ri, "neutral", out_align))
	    return FALSE;
	break;
    case 4:
    default:
	return FALSE;
	break;
    }

    if (!is_valid_character(ri, *out_role, *out_race, *out_gend, *out_align))
	return FALSE;

    return TRUE;
}
示例#25
0
nh_bool player_selection(int *out_role, int *out_race, int *out_gend,
			 int *out_align, int randomall, nh_bool tutorial)
{
    struct nh_menuitem *items;
    int icount, size;
    int i, k, n, listlen, id;
    char pick4u = 'n', thisch, lastch = 0;
    char pbuf[QBUFSZ], plbuf[QBUFSZ];
    struct nh_listitem list[LISTSZ]; /* need enough space for lists of roles or races */
    char listbuffers[LISTSZ][256];
    int pick_list[2];
    int initrole, initrace, initgend, initalign;
    const struct nh_roles_info *ri = nh_get_roles();
    
    if (tutorial)
	return tutorial_player_selection(out_role, out_race, out_gend, out_align);
    
    initrole = *out_role; initrace = *out_race;
    initalign = *out_align; initgend = *out_gend;
    if (initrole == ROLE_NONE) initrole = ri->def_role;
    if (initrace == ROLE_NONE) initrace = ri->def_race;
    if (initgend == ROLE_NONE) initgend = ri->def_gend;
    if (initalign == ROLE_NONE) initalign = ri->def_align;
    
    validate_character_presets(ri, &initrole, &initrace, &initgend, &initalign);
    
    for (i = 0; i < LISTSZ; i++) {
	listbuffers[i][0] = '\0';
	list[i].caption = listbuffers[i];
    }
    
    srandom(time(NULL));
    
    /* Should we randomly pick for the player? */
    if (!randomall &&
	(initrole == ROLE_NONE || initrace == ROLE_NONE ||
	    initgend == ROLE_NONE || initalign == ROLE_NONE)) {
	char *prompt = nh_build_plselection_prompt(pbuf, QBUFSZ, initrole,
			    initrace, initgend, initalign);

	pick4u = curses_yn_function(prompt, "ynq", 'y');	
	if (pick4u != 'y' && pick4u != 'n')
	    return FALSE;
    }

    nh_root_plselection_prompt(plbuf, QBUFSZ - 1,
		    initrole, initrace, initgend, initalign);
    icount = 0; size = 10;
    items = malloc(sizeof(struct nh_menuitem) * size);

    /* Select a role, if necessary */
    /* if pre-selected race/gender/alignment are still set after
     * validate_character_presets we know they're OK */
    if (initrole < 0) {
	listlen = get_valid_roles(ri, initrace, initgend, initalign, list, LISTSZ);
	
	/* Process the choice */
	if (pick4u == 'y' || initrole == ROLE_RANDOM || randomall) {
	    /* Pick a random role */
	    initrole = list[random() % listlen].id;
	} else {
	    /* Prompt for a role */
	    for (i = 0; i < listlen; i++) {
		id = list[i].id + 1; /* list[i].id starts at 0 */
		thisch = tolower((unsigned char)*list[i].caption);
		if (thisch == lastch)
		    thisch = toupper((unsigned char)thisch);
		add_menu_item(items, size, icount, id, list[i].caption + 2, thisch, 0);
		lastch = thisch;
	    }
	    pick_list[0] = id = list[random() % listlen].id+1;
	    add_menu_item(items, size, icount, id, "随机", '*', 0);
	    add_menu_item(items, size, icount, -1, "退出", 'q', 0);
	    
	    sprintf(pbuf, "为你的%s选择一个角色", plbuf);
	    n = curses_display_menu(items, icount, pbuf, PICK_ONE, pick_list);

	    /* Process the choice */
	    if (n == -1 || pick_list[0] == -1)
		goto give_up;		/* Selected quit */

	    initrole = pick_list[0] - 1;
	    icount = 0;
	}
	nh_root_plselection_prompt(plbuf, QBUFSZ - 1,
		    initrole, initrace, initgend, initalign);
    }
    
    /* Select a race, if necessary */
    if (initrace < 0) {
	listlen = get_valid_races(ri, initrole, initgend, initalign, list, LISTSZ);
	
	if (pick4u == 'y' || initrace == ROLE_RANDOM || randomall) {
	    initrace = list[random() % listlen].id;
	} else {	/* pick4u == 'n' */
	    /* Count the number of valid races */
	    k = list[0].id;	/* valid race */

	    /* Permit the user to pick, if there is more than one */
	    if (listlen > 1) {
		for (i = 0; i < listlen; i++) {
		    id = list[i].id + 1;
		    add_menu_item(items, size, icount, id, list[i].caption + 2,
				  list[i].caption[0], 0);
		}
		pick_list[0] = id = list[random() % listlen].id+1;
		add_menu_item(items, size, icount, id, "随机", '*', 0);
		add_menu_item(items, size, icount, -1, "退出", 'q', 0);

		sprintf(pbuf, "为你的%s选择一个种族", plbuf);
		n = curses_display_menu(items, icount, pbuf, PICK_ONE, pick_list);
		
		if (n == -1 || pick_list[0] == -1)
		    goto give_up;		/* Selected quit */

		k = pick_list[0] - 1;
		icount = 0;
	    }
	    initrace = k;
	}
	nh_root_plselection_prompt(plbuf, QBUFSZ - 1,
		    initrole, initrace, initgend, initalign);
    }

    /* Select a gender, if necessary */
    if (initgend < 0) {
	listlen = get_valid_genders(ri, initrole, initrace, initalign, list, LISTSZ);

	if (pick4u == 'y' || initgend == ROLE_RANDOM || randomall) {
	    initgend = list[random() % listlen].id;
	} else {	/* pick4u == 'n' */
	    /* Count the number of valid genders */
	    k = list[0].id;	/* valid gender */

	    /* Permit the user to pick, if there is more than one */
	    if (listlen > 1) {
		for (i = 0; i < listlen; i++) {
		    id = list[i].id + 1;
		    add_menu_item(items, size, icount, id, list[i].caption + 2,
				  list[i].caption[0], 0);
		}
		pick_list[0] = id = list[random() % listlen].id+1;
		add_menu_item(items, size, icount, id, "随机", '*', 0);
		add_menu_item(items, size, icount, -1, "退出", 'q', 0);

		sprintf(pbuf, "为你的%s选择一个性别", plbuf);
		n = curses_display_menu(items, icount, pbuf, PICK_ONE, pick_list);
		
		if (n == -1 || pick_list[0] == -1)
		    goto give_up;		/* Selected quit */

		k = pick_list[0] - 1;
		icount = 0;
	    }
	    initgend = k;
	}
	nh_root_plselection_prompt(plbuf, QBUFSZ - 1,
		    initrole, initrace, initgend, initalign);
    }

    /* Select an alignment, if necessary */
    if (initalign < 0) {
	listlen = get_valid_aligns(ri, initrole, initrace, initgend, list, LISTSZ);
	
	if (pick4u == 'y' || initalign == ROLE_RANDOM || randomall) {
	    initalign = list[random() % listlen].id;
	} else {	/* pick4u == 'n' */
	    /* Count the number of valid alignments */
	    k = list[0].id;	/* valid alignment */

	    /* Permit the user to pick, if there is more than one */
	    if (listlen > 1) {
		for (i = 0; i < listlen; i++) {
		    id = list[i].id + 1;
		    add_menu_item(items, size, icount, id, list[i].caption + 2,
				  list[i].caption[0], 0);
		}
		pick_list[0] = id = list[random() % listlen].id+1;
		add_menu_item(items, size, icount, id, "随机", '*', 0);
		add_menu_item(items, size, icount, -1, "退出", 'q', 0);
		
		sprintf(pbuf, "为你的%s选择一个阵营", plbuf);
		n = curses_display_menu(items, icount, pbuf, PICK_ONE, pick_list);
		
		if (n == -1 || pick_list[0] == -1)
		    goto give_up;		/* Selected quit */

		k = pick_list[0] - 1;
	    }
	    initalign = k;
	}
    }
    
    *out_role = initrole;
    *out_race = initrace;
    *out_gend = initgend;
    *out_align = initalign;
    
    free(items);
    return TRUE;
    
give_up:
    free(items);
    return FALSE;
}
示例#26
0
static void
show_autopickup_menu(struct nh_option_desc *opt)
{
    struct nh_menulist menu;
    int i, j, parts, selected[1], id;
    struct nh_autopickup_rule *r;
    char buf[BUFSZ];
    struct nh_autopickup_rule *rule;
    union nh_optvalue value;

    /* clone autopickup rules */
    value.ar = malloc(sizeof (struct nh_autopickup_rules));
    value.ar->num_rules = 0;
    value.ar->rules = NULL;
    if (opt->value.ar) {
        int size;
        value.ar->num_rules = opt->value.ar->num_rules;
        size = value.ar->num_rules * sizeof (struct nh_autopickup_rule);
        value.ar->rules = malloc(size);
        memcpy(value.ar->rules, opt->value.ar->rules, size);
    }

    do {
        init_menulist(&menu);

        add_menu_txt(&menu, "Pos\tRule\tAction", MI_HEADING);

        /* list the rules in human-readable form */
        for (i = 0; i < value.ar->num_rules; i++) {
            r = &value.ar->rules[i];
            parts = 0;
            snprintf(buf, ARRAY_SIZE(buf), "%2d.\tIF ", i + 1);

            if (strlen(r->pattern)) {
                parts++;
                sprintf(buf + strlen(buf), "name matches \"%s\"", r->pattern);
            }

            if (r->oclass != OCLASS_ANY) {
                const char *classname = NULL;

                for (j = 0; j < opt->a.numclasses && !classname; j++)
                    if (opt->a.classes[j].id == r->oclass)
                        classname = opt->a.classes[j].caption;

                if (parts++)
                    strcat(buf, " AND ");
                sprintf(buf + strlen(buf), "type is \"%s\"", classname);
            }

            if (r->buc != B_DONT_CARE) {
                if (parts++)
                    strcat(buf, " AND ");
                sprintf(buf + strlen(buf), "beatitude is %s", bucnames[r->buc]);
            }

            if (!parts)
                snprintf(buf, ARRAY_SIZE(buf), "%2d.\teverything", i + 1);

            if (r->action == AP_GRAB)
                sprintf(buf + strlen(buf), ":\t< GRAB");
            else
                sprintf(buf + strlen(buf), ":\t  LEAVE >");

            add_menu_item(&menu, i + 1, buf, 0, 0);
        }

        add_menu_txt(&menu, "", MI_TEXT);
        add_menu_item(&menu, -1, "add a new rule", '!', 0);
        add_menu_item(&menu, -2, "help", '?', 0);

        /* TODO */
        curses_display_menu(&menu, "Autopickup rules:", PICK_ONE,
                            PLHINT_RIGHT, selected, curses_menu_callback);
        if (*selected == CURSES_MENU_CANCELLED)
            break;

        /* add or edit a rule */
        id = selected[0];
        if (id == -1) {
            int size;

            /* create a new rule */
            id = value.ar->num_rules;
            value.ar->num_rules++;
            size = value.ar->num_rules * sizeof (struct nh_autopickup_rule);
            value.ar->rules = realloc(value.ar->rules, size);

            rule = &value.ar->rules[id];
            memset(rule->pattern, 0, sizeof(rule->pattern));
            rule->oclass = OCLASS_ANY;
            rule->buc = B_DONT_CARE;
            rule->action = AP_GRAB;
        } else if (id == -2) {
            autopickup_rules_help();
            continue;
        } else
            id--;

        edit_ap_rule(&opt->a, value.ar, id);
    } while (1);

    curses_set_option(opt->name, value);

    free(value.ar->rules);
    free(value.ar);
}
示例#27
0
int
network_motd(void)
{
    char errmsg[256];
    char motdmsg[4096];
    int fd = -1;

    if (settings.show_motd == MOTD_TRUE) {

        fd = connect_server(MOTD_SERVER, MOTD_PORT, FALSE,
                            errmsg, sizeof errmsg);
        if (fd == -1)
            fd = connect_server(MOTD_SERVER, MOTD_PORT, TRUE,
                                errmsg, sizeof errmsg);
        
        errmsg[sizeof errmsg - 1] = '\0';

        if (fd == -1) {
            strcpy(motdmsg, "Could not connect to <" MOTD_SERVER "> to "
                   "receive a Message of the Day: ");
            strcat(motdmsg, errmsg);
        } else {
            /* We want to receive until the connection closes (which causes
               either EPIPE on abnormal shutdown, or 0 on normal shutdown). So
               continue until we get an error message other than EINTR or the
               buffer fills (indicating a malicious connection; I'm not planning
               on sending malicious packets from motd.nethack4.org, especially
               as I wrote this code and so know it wouldn't work, but it's worth
               allowing for the possibility that someone else intercepts the
               connection). */
            int recvlen = 0;
            int rv;
            while (recvlen < sizeof motdmsg &&
                   (((rv = recv(fd, motdmsg + recvlen,
                                (sizeof motdmsg) - recvlen, 0))) > 0 ||
                    errno == EINTR))
                recvlen += rv < 0 ? 0 : rv;
            if (recvlen >= sizeof motdmsg)
                recvlen = -1 + sizeof motdmsg;

            motdmsg[recvlen] = '\0';
        }

        close(fd);
    } else if (settings.show_motd == MOTD_FALSE) {
        return 1;
    } else {
        /* It's a bad idea to do network connections without asking the user for
           permission first. (Arguably we could make an exception for
           connection-only mode, but that connects to localhost, which is not
           quite the same thing as connecting to the Internet, so I'd rather
           make absolutely sure we aren't doing connections unsolicited.)

           Note that nothing is sent (other than the fact that the connection
           exists); the nethack4 binary just creates the connection, then reads
           from it. */
        strcpy(motdmsg, "The Message of the Day system connects to the "
               "Internet to receive gameplay tips and announcements (such "
               "as tournament information or release announcements). Do you "
               "want to turn it on? (You can change this later with the "
               "\x0enetwork_motd\x0f option.)");
    }

    /* SI/SO in the output indicate bold text. This isn't implemented yet.  Also
       strip out all other unprintable characters for security reasons. We just
       use the ASCII space-to-tilde range for printables; we're not expecting
       any control characters but SI/SO, not even newlines. */
    char *f, *t;
    f = t = motdmsg;
    while (*f) {
        if (*f >= ' ' && *f <= '~')
            *(t++) = *f;
        f++;
    }
    *t = '\0';

    int outcount;
    char **outlines;
    wrap_text(COLNO-6, motdmsg, &outcount, &outlines);

    struct nh_menulist menu;
    int i;

    init_menulist(&menu);

    for (i = 0; i < outcount; i++)
        add_menu_txt(&menu, outlines[i], MI_TEXT);

    free_wrap(outlines);

    if (settings.show_motd == MOTD_ASK) {
        add_menu_txt(&menu, "", MI_TEXT);
        add_menu_item(&menu, 1,
                      "Yes, I'd like announcements and gameplay tips",
                      'y', FALSE);
        add_menu_item(&menu, 2,
                      "No, please don't connect to the MotD server",
                      'n', FALSE);

        curses_display_menu(&menu, "Message of the Day", PICK_ONE,
                            PLHINT_ANYWHERE, &i, curses_menu_callback);

        if (i == 1) {
            curses_set_option("networkmotd",
                              (union nh_optvalue){.e = MOTD_TRUE});
示例#28
0
static void show_msgtype_menu(struct nh_option_desc *opt)
{
    /* msgtype option variables. */
    union nh_optvalue value;
    unsigned int size;
    /* Menu variables. */
    struct nh_menuitem *items;
    int icount, menusize, selected[1], n;

    /* Clone msgtype rules. */
    value.mt = malloc(sizeof(struct nh_msgtype_rules));
    if (opt->value.mt) {
	value.mt->num_rules = opt->value.mt->num_rules;
	size = value.mt->num_rules * sizeof(struct nh_msgtype_rule);
	value.mt->rules = malloc(size);
	memcpy(value.mt->rules, opt->value.mt->rules, size);
    } else {
	value.mt->num_rules = 0;
	value.mt->rules = NULL;
    }

    menusize = value.mt->num_rules + 4;
    items = malloc(sizeof(struct nh_menuitem) * menusize);

    selected[0] = 0;
    do {
	int i, id;
	icount = 0;

	add_menu_txt(items, menusize, icount, "Pos\tAction\tPattern", MI_HEADING);

	for (i = 0; i < value.mt->num_rules; i++) {
	    /* position (3) + '.' (1) + '\t' (1) + pattern (119) + '\t' (1) +
	     * "NO REPEAT" (9) + null (1) */
	    char buf[134];
	    struct nh_msgtype_rule *r = &value.mt->rules[i];
	    sprintf(buf, "%2d.\t%s\t%s", i + 1, msgtype_action_string(r->action),
		    r->pattern);
	    add_menu_item(items, menusize, icount, i + 1, buf, 0, 0);
	}

	add_menu_txt(items, menusize, icount, "", MI_TEXT);
	add_menu_item(items, menusize, icount, -1, "add new match", '+', 0);
	add_menu_item(items, menusize, icount, -2, "help", '?', 0);

	/* If the previous selection was to add a rule, scroll to the bottom now
	 * so that the player can see it. */
	if (selected[0] == -1) {
	    n = curses_display_menu_bottom(items, icount, "Message types:",
					   PICK_ONE, selected);
	} else {
	    n = curses_display_menu(items, icount, "Message types:",
				    PICK_ONE, selected);
	}
	if (n > 0) {
	    id = selected[0];
	    if (id == -2) {
		msgtype_help();
	    } else if (id == -1) {
		/* add new match */
		if (value.mt->num_rules >= MSGTYPE_MAX_RULES) {
		    curses_msgwin("Maximum number of rules reached.");
		} else {
		    struct nh_msgtype_rule *r;
		    id = value.mt->num_rules;

		    value.mt->num_rules++;
		    size = value.mt->num_rules * sizeof(struct nh_msgtype_rule);
		    value.mt->rules = realloc(value.mt->rules, size);

		    r = &value.mt->rules[id];
		    r->pattern[0] = '\0';
		    r->action = MSGTYPE_DEFAULT;
		}
	    } else {
		/* edit existing match */
		msgtype_edit_rule(value.mt, id - 1);
	    }
	}
    } while (n > 0);

    nh_set_option(opt->name, value, FALSE);

    if (value.mt->rules)
	free(value.mt->rules);
    free(value.mt);
    free(items);
}
示例#29
0
void
replay(void)
{
    char buf[BUFSZ];
    fnchar logdir[BUFSZ], savedir[BUFSZ], filename[1024], *dir, **files;
    struct nh_menuitem *items;
    int i, n, fd, icount, size, filecount, pick[1];
    enum nh_log_status status;
    struct nh_game_info gi;

    if (!get_gamedir(LOG_DIR, logdir))
        logdir[0] = '\0';
    if (!get_gamedir(SAVE_DIR, savedir))
        savedir[0] = '\0';

    if (*logdir)
        dir = logdir;
    else if (*savedir)
        dir = savedir;
    else {
        curses_msgwin("There are no games to replay.");
        return;
    }

    while (1) {
        filename[0] = '\0';
        files = list_gamefiles(dir, &filecount);
        /* make sure there are some files to show */
        if (!filecount) {
            if (dir == savedir) {
                curses_msgwin("There are no saved games to replay.");
                savedir[0] = '\0';
            } else {
                curses_msgwin("There are no completed games to replay.");
                logdir[0] = '\0';
            }

            dir = (dir == savedir) ? logdir : savedir;
            if (!*dir)
                return;
            continue;
        }

        icount = 0;
        size = filecount + 2;
        items = malloc(size * sizeof (struct nh_menuitem));

        /* add all the files to the menu */
        for (i = 0; i < filecount; i++) {
            fd = sys_open(files[i], O_RDWR, 0660);
            status = nh_get_savegame_status(fd, &gi);
            close(fd);

            describe_game(buf, status, &gi);
            add_menu_item(items, size, icount,
                          (status == LS_IN_PROGRESS) ? 0 : icount + 1, buf, 0,
                          FALSE);
        }

        if (dir == logdir && *savedir) {
            add_menu_txt(items, size, icount, "", MI_NORMAL);
            add_menu_item(items, size, icount, -1, "View saved games instead",
                          '!', FALSE);
        } else if (dir == savedir && *logdir) {
            add_menu_txt(items, size, icount, "", MI_NORMAL);
            add_menu_item(items, size, icount, -1, "View saved games instead",
                          '!', FALSE);
        }

        n = curses_display_menu(items, icount, "Pick a game to view", PICK_ONE,
                                PLHINT_ANYWHERE, pick);
        free(items);
        filename[0] = '\0';
        if (n > 0 && pick[0] != -1)
            fnncat(filename, files[pick[0] - 1],
                   sizeof (filename) / sizeof (fnchar) - 1);

        for (i = 0; i < filecount; i++)
            free(files[i]);
        free(files);

        if (n <= 0)
            return;

        if (pick[0] == -1) {
            dir = (dir == savedir) ? logdir : savedir;
            continue;
        }

        /* we have a valid filename */
        break;
    }

    fd = sys_open(filename, O_RDWR, 0660);
    replay_commandloop(fd);
    close(fd);
}
示例#30
0
nh_bool loadgame(void)
{
    char buf[BUFSZ];
    fnchar savedir[BUFSZ], filename[1024], **files;
    struct nh_menuitem *items;
    int size, icount, fd, i, n, ret, pick[1];
    enum nh_log_status status;
    struct nh_game_info gi;

    if (!get_gamedir(SAVE_DIR, savedir)) {
        curses_raw_print("Could not find or create the save directory.");
        return FALSE;
    }

    files = list_gamefiles(savedir, &size);
    if (!size) {
        curses_msgwin("No saved games found.");
        return FALSE;
    }

    icount = 0;
    items = malloc(size * sizeof(struct nh_menuitem));

    for (i = 0; i < size; i++) {
        fd = sys_open(files[i], O_RDWR, FILE_OPEN_MASK);
        status = nh_get_savegame_status(fd, &gi);
        close(fd);

        describe_game(buf, status, &gi);
        add_menu_item(items, size, icount, (status == LS_IN_PROGRESS) ? 0 : icount + 1,
                      buf, 0, FALSE);
    }

    n = curses_display_menu(items, icount, "saved games", PICK_ONE, pick);
    free(items);
    filename[0] = '\0';
    if (n > 0)
        fnncat(filename, files[pick[0]-1], sizeof(filename)/sizeof(fnchar)-1);

    for (i = 0; i < icount; i++)
        free(files[i]);
    free(files);
    if (n <= 0)
        return FALSE;

    fd = sys_open(filename, O_RDWR, FILE_OPEN_MASK);
    create_game_windows();
    if (nh_restore_game(fd, NULL, FALSE) != GAME_RESTORED) {
        destroy_game_windows();
        close(fd);
        if (curses_yn_function("Failed to load the save. Do you wish to delete the file?", "yn", 'n') == 'y')
            unlink(filename);
        return FALSE;
    }

    load_keymap(); /* need to load the keymap after the game has been started */
    ret = commandloop();
    free_keymap();
    close(fd);

    destroy_game_windows();
    cleanup_messages();
    game_ended(ret, filename);

    return TRUE;
}