Beispiel #1
0
void
curses_impossible(const char *msg)
{
    curses_msgwin("Impossible state detected in the client.", krc_notification);
    curses_msgwin(msg, krc_notification);
    curses_msgwin("You may wish to save and restart the client.",
                  krc_notification);
}
Beispiel #2
0
static void validate_character_presets(const struct nh_roles_info *ri,
				       int *initrole, int *initrace,
				       int *initgend, int *initalign)
{
    struct nh_listitem list[1];
    char listbuffer[256];
    
    list[0].caption = listbuffer;
    
    /* throw out obviously invalid values */
    if (*initrole < ROLE_RANDOM || *initrole >= ri->num_roles)
	*initrole = ROLE_NONE;
    if (*initrace < ROLE_RANDOM || *initrace >= ri->num_races)
	*initrace = ROLE_NONE;
    if (*initgend < ROLE_RANDOM || *initgend >= ri->num_genders)
	*initgend = ROLE_NONE;
    if (*initalign < ROLE_RANDOM || *initalign >= ri->num_aligns)
	*initalign = ROLE_NONE;
    
    /* catch mutually incompatible character options (male valkyrie) */
    if (!is_valid_character(ri, *initrole, *initrace, *initgend, *initalign)) {
	/* always keep the role */
	if (is_valid_character(ri, *initrole, *initrace, *initgend, ROLE_NONE)) {
	    curses_msgwin("Incompatible alignment!");
	    *initalign = ROLE_NONE;
	} else if (is_valid_character(ri, *initrole, *initrace, ROLE_NONE, *initalign)) {
	    curses_msgwin("Incompatible gender!");
	    *initgend = ROLE_NONE;
	} else if (is_valid_character(ri, *initrole, ROLE_NONE, *initgend, *initalign)) {
	    curses_msgwin("Incompatible race!");
	    *initrace = ROLE_NONE;
	} else {
	    curses_msgwin("Incompatible character presets!");
	    *initrace = ROLE_NONE;
	    *initgend = ROLE_NONE;
	    *initalign = ROLE_NONE;
	}
    }
    
    /* if there is only one possible option for any attribute, choose it here */
    if ((*initrole == ROLE_NONE || *initrole == ROLE_RANDOM) &&
	get_valid_roles(ri, *initrace, *initgend, *initalign, list, 1) == 1)
	*initrole = list[0].id;
    
    if ((*initrace == ROLE_NONE || *initrace == ROLE_RANDOM) &&
	get_valid_races(ri, *initrole, *initgend, *initalign, list, 1) == 1)
	*initrace = list[0].id;
    
    if ((*initgend == ROLE_NONE || *initgend == ROLE_RANDOM) &&
	get_valid_genders(ri, *initrole, *initrace, *initalign, list, 1) == 1)
	*initgend = list[0].id;
    
    if ((*initalign == ROLE_NONE || *initalign == ROLE_RANDOM) &&
	get_valid_aligns(ri, *initrole, *initrace, *initgend, list, 1) == 1)
	*initalign = list[0].id;
}
Beispiel #3
0
enum nh_direction curses_getdir(const char *query, nh_bool restricted)
{
    int key;
    enum nh_direction dir;
    
    key = curses_msgwin(query ? query : "In what direction?");
    if (key == '.' || key == 's')
	    return DIR_SELF;
    
    dir = key_to_dir(key);
    if (dir == DIR_NONE)
	curses_msgwin("What a strange direction!");
    
    return dir;
}
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);
}
Beispiel #5
0
static void
rule_pattern_callback(const char *str, void *pat_void)
{
    char *pat = pat_void;

    if (*str == '\033')
        return;
    if (strlen(str) >= AUTOPICKUP_PATTERNSZ) {
        curses_msgwin("That pattern is too long.", krc_notification);
        return;
    }

    memset(pat, 0, AUTOPICKUP_PATTERNSZ);
    strcpy(pat, str);
}
Beispiel #6
0
/* pos holds maximum position on call, chosen position or -1 on return */
static void
rule_position_callback(const char *str, void *pos_void)
{
    int *pos = pos_void;
    long l;

    if (!*str || *str == '\033') {
        *pos = -1;
        return;
    }

    l = strtol(str, NULL, 0);
    if (l >= 1 && l <= *pos)
        *pos = (int)l;
    else {
        curses_msgwin("Invalid rule position.", krc_notification);
        *pos = -1;
    }
}
Beispiel #7
0
/* open a config file and separate it into lines for read_config_line() */
static void
read_config_file(const fnchar * filename)
{
    FILE *fp;
    int fsize;
    char *line;

    fp = fopen(filename, "rb");
    if (!fp)
        return;

    /* obtain file size. */
    fseek(fp, 0, SEEK_END);
    fsize = ftell(fp);
    rewind(fp);

    if (!fsize) {       /* truncated config file */
        fclose(fp);
        return;
    }

    char buf[fsize + 1];

    if (fread(buf, 1, fsize, fp) < fsize) {
        /* This can only happen if the file shrinks while it's open; let's just
           not read the file at all, because it's probably corrupted */
        curses_msgwin("warning: corrupted configuration file",
                      krc_notification);
        fclose(fp);
        return;
    }
    fclose(fp);

    buf[fsize] = '\0';

    /* each option is expected to have the following format: * name=value\n */
    line = strtok(buf, "\n");
    do {
        read_config_line(line);

        line = strtok(NULL, "\n");
    } while (line);
}
Beispiel #8
0
int
main(int argc, char *argv[])
{
    srand(time(NULL));

    char **gamepaths;
    int i;
    nh_bool init_ok;

    umask(0777 & ~FCMASK);

    /* this can change argc and *argv, so must come first */
    initialize_uncursed(&argc, argv);

    process_args(argc, argv);   /* grab -U, -H, -k, --help early */
    init_options();
    gamepaths = init_game_paths(argv[0]);

    nh_lib_init(&curses_windowprocs, (const char * const*)gamepaths);
    init_curses_ui(gamepaths[DATAPREFIX]);
    init_ok = read_nh_config();
    for (i = 0; i < PREFIX_COUNT; i++)
        free(gamepaths[i]);
    free(gamepaths);


    process_args(argc, argv);   /* other command line options */
    init_displaychars();

    if (init_ok)
        mainmenu();
    else
        curses_msgwin("Could not initialize game options!", krc_notification);

    exit_curses_ui();
    nh_lib_exit();
    free_displaychars();

    exit(EXIT_SUCCESS);
     /*NOTREACHED*/ return 0;
}
Beispiel #9
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);
}
Beispiel #10
0
void
replay_commandloop(int fd)
{
    int key, move, count;
    char buf[BUFSZ], qbuf[BUFSZ];
    nh_bool ret, firsttime = TRUE;
    struct nh_replay_info rinfo;
    struct nh_cmd_arg noarg;
    struct nh_cmd_desc *cmd;

    create_game_windows();
    if (!nh_view_replay_start(fd, &curses_replay_windowprocs, &rinfo))
        return;
    load_keymap();

    while (1) {
        draw_msgwin();
        curses_update_status(NULL);
        draw_sidebar();
        draw_replay_info(&rinfo);
        if (firsttime)
            show_replay_help();
        firsttime = FALSE;

        key = get_map_key(TRUE);
        switch (key) {
            /* step forward */
        case KEY_RIGHT:
        case ' ':
            ret = nh_view_replay_step(&rinfo, REPLAY_FORWARD, 1);
            draw_replay_info(&rinfo);
            if (ret == FALSE) {
                key =
                    curses_msgwin("You have reached the end of this game. "
                                  "Go back or press ESC to exit.");
                if (key == KEY_ESC)
                    goto out;
            }
            break;

            /* step backward */
        case KEY_LEFT:
            nh_view_replay_step(&rinfo, REPLAY_BACKWARD, 1);
            draw_replay_info(&rinfo);
            break;

        case KEY_ESC:
            goto out;

        case 'g':
            strncpy(qbuf, "What move do you want to jump to?", BUFSZ);
            if (rinfo.max_moves > 0)
                sprintf(qbuf + strlen(qbuf), " (Max: %d)", rinfo.max_moves);

            curses_getline(qbuf, buf);
            if (buf[0] == '\033' || !(move = atoi(buf)))
                break;
            nh_view_replay_step(&rinfo, REPLAY_GOTO, move);
            break;

        case KEY_F(12):        /* timetest! */
            if (allow_timetest())
                timetest(fd, &rinfo);
            break;

        default:
            count = 0;
            noarg.argtype = CMD_ARG_NONE;
            cmd = keymap[key];
            if (!cmd)
                break;
            if (cmd->flags & CMD_UI)
                handle_internal_cmd(&cmd, &noarg, &count);
            if (cmd)
                nh_command(cmd->name, count, &noarg);
            break;
        }
    }

out:
    nh_view_replay_finish();
    free_keymap();
    destroy_game_windows();
    cleanup_messages();
}
Beispiel #11
0
static void
timetest(int fd, struct nh_replay_info *rinfo)
{
    char buf[BUFSZ];
    hp_time t_start, t_end;
    long ms;
    int mmax, initial, revpos;

    initial = rinfo->moves;
    nh_view_replay_step(rinfo, REPLAY_GOTO, 0);

    /* run forward */
    gettime(&t_start);
    while (rinfo->actions < rinfo->max_actions) {
        nh_view_replay_step(rinfo, REPLAY_FORWARD, 1);
        curses_update_status(NULL);
        draw_replay_info(rinfo);
        doupdate();
    }
    draw_msgwin();
    gettime(&t_end);
    ms = clock_delta_ms(&t_start, &t_end);
    snprintf(buf, BUFSZ,
             "%d actions replayed with display in %ld ms. (%ld actions/sec)",
             rinfo->max_actions, ms, rinfo->max_actions * 1000 / ms);
    curses_msgwin(buf);

    /* reset the entire replay state to delete checkpoints */
    mmax = rinfo->moves;        /* max_moves may not be available if this is a
                                   replay of a crashed game */
    nh_view_replay_finish();
    nh_view_replay_start(fd, &curses_replay_windowprocs, rinfo);

    /* run forward without showing the map etc. */
    gettime(&t_start);
    nh_view_replay_step(rinfo, REPLAY_GOTO, mmax);
    gettime(&t_end);
    ms = clock_delta_ms(&t_start, &t_end);
    snprintf(buf, BUFSZ,
             "%d actions replayed without display in %ld ms. (%ld actions/sec)",
             rinfo->actions, ms, rinfo->actions * 1000 / ms);
    curses_msgwin(buf);

    /* run backward */
    revpos = rinfo->actions;
    gettime(&t_start);
    while (rinfo->actions > 0 && revpos < rinfo->actions + 1000) {
        nh_view_replay_step(rinfo, REPLAY_BACKWARD, 1);
        curses_update_status(NULL);
        draw_msgwin();
        draw_replay_info(rinfo);
        doupdate();
    }
    gettime(&t_end);
    ms = clock_delta_ms(&t_start, &t_end);
    snprintf(buf, BUFSZ,
             "%d actions replayed backward with display in %ld ms. (%ld actions/sec)",
             revpos - rinfo->actions, ms,
             (revpos - rinfo->actions) * 1000 / ms);
    curses_msgwin(buf);

    nh_view_replay_step(rinfo, REPLAY_GOTO, initial);
}
Beispiel #12
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);
}
Beispiel #13
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);
}
Beispiel #14
0
/* get a new value of the appropriate type for the given option */
static nh_bool get_option_value(struct win_menu *mdat, int idx)
{
    char buf[BUFSZ], query[BUFSZ];
    union nh_optvalue value;
    struct nh_option_desc *option, *optlist;
    int listid = mdat->items[idx].id >> 10;
    int id = mdat->items[idx].id & 0x1ff;
    char strbuf[BUFSZ];
    int prev_optstyle = settings.optstyle;
    
    switch (listid) {
	case ACT_BIRTH_OPTS:
	    optlist = nh_get_options(ACTIVE_BIRTH_OPTIONS); break;
	case CUR_BIRTH_OPTS:
	    optlist = nh_get_options(CURRENT_BIRTH_OPTIONS); break;
	case GAME_OPTS:
	    optlist = nh_get_options(GAME_OPTIONS); break;
	case UI_OPTS:
	    optlist = curses_options; break;
	    
	default:
	    return FALSE;
    }
    
    option = &optlist[id];
    value.s = strbuf;
    
    switch ((int)option->type) {
	case OPTTYPE_BOOL:
	    select_boolean_value(&value, option);
	    break;
	    
	case OPTTYPE_INT:
	    sprintf(query, "New value for %s (number from %d to %d)",
		    option->name, option->i.min, option->i.max);
	    sprintf(buf, "%d", value.i);
	    curses_getline(query, buf);
	    if (buf[0] == '\033')
		return FALSE;
	    sscanf(buf, "%d", &value.i);
	    break;
	    
	case OPTTYPE_ENUM:
	    select_enum_value(&value, option);
	    break;
	    
	case OPTTYPE_STRING:
	    sprintf(query, "New value for %s (text)", option->name);
	    curses_getline(query, value.s);
	    if (value.s[0] == '\033')
		return FALSE;
	    break;
	    
	case OPTTYPE_AUTOPICKUP_RULES:
	    show_autopickup_menu(option);
	    return FALSE;
	    
	case OPTTYPE_MSGTYPE:
	    show_msgtype_menu(option);
	    return FALSE;
	    
	case OPTTYPE_KEYMAP:
	    show_keymap_menu(FALSE);
	    return FALSE;
	    
	default:
	    return FALSE;
    }
    
    if (!nh_set_option(option->name, value, FALSE)) {
	sprintf(strbuf, "new value for %s rejected", option->name);
	curses_msgwin(strbuf);
    } else
	print_option_string(option, mdat->items[idx].caption);
    
    /* special case: directly redo option menu appearance */
    if (settings.optstyle != prev_optstyle)
	return TRUE;
    
    return FALSE;
}
Beispiel #15
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);
}
Beispiel #16
0
/* parse a single line from the config file and set the option */
static void
read_config_line(char *line)
{
    char *comment, *delim, *name, *value;
    struct nh_option_desc *option;
    struct nh_option_desc *optlist = NULL;
    union nh_optvalue optval;

    comment = strchr(line, '#');
    if (comment)
        *comment = '\0';
    delim = strchr(line, '=');
    if (!delim)
        return; /* could whine about junk chars in the config, but why bother */

    name = line;
    value = delim + 1;
    *delim-- = '\0';

    /* remove space around name */
    while (isspace(*name))
        name++;
    while (isspace(*delim))
        *delim-- = '\0';

    /* remove spaces around value */
    delim = value;
    while (*delim)
        delim++;
    delim--;

    while (isspace(*value))
        value++;
    while (isspace(*delim))
        *delim-- = '\0';

    /* value may be enclosed with double quotes (") */
    if (*value == '"' && *delim == '"') {
        value++;
        *delim = '\0';
    }

    /* Find an options list with which to parse this option name. */
    option = nhlib_find_option(curses_options, name);
    if (!option) {
        optlist = curses_get_nh_opts();
        if (optlist)
            option = nhlib_find_option(optlist, name);
    }

    if (!option) {
#if 0
        curses_msgwin("Unknown option in config file:", krc_notification);
        curses_msgwin(name, krc_notification);
#endif
        return;
    }

    optval = nhlib_string_to_optvalue(option, value);
    curses_set_option(name, optval);
    if (option->type == OPTTYPE_AUTOPICKUP_RULES) {
        free(optval.ar->rules);
        free(optval.ar);
    }

    if (optlist)
        curses_free_nh_opts(optlist);
}
Beispiel #17
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;
}
Beispiel #18
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;
}
Beispiel #19
0
/* get a new value of the appropriate type for the given option */
static nh_bool
query_new_value(struct win_menu *mdat, int idx)
{
    struct nh_option_desc *option, *optlist;
    struct nh_option_desc optioncopy;
    struct nh_option_desc *optioncopy_p = &optioncopy;
    int listid = mdat->items[idx].id >> 10;
    int id = mdat->items[idx].id & 0x1ff;
    int prev_optstyle = settings.optstyle;
    enum nh_menupaging prev_menupaging = settings.menupaging;
    nh_bool prev_menuborder = settings.whichframes != FRAME_NONE;
    nh_bool ret = FALSE;

    switch (listid) {
    case BIRTH_OPTS:
    case CREATION_OPTS:
    case GAME_OPTS:
        optlist = curses_get_nh_opts();
        break;
    case UI_OPTS:
        optlist = curses_options;
        break;

    default:
        return FALSE;
    }

    option = &optlist[id];
    /* optioncopy holds the new option we're planning to set */
    optioncopy = *option;

    switch ((int)optioncopy.type) {
    case OPTTYPE_BOOL:
        select_boolean_value(&optioncopy.value, &optioncopy);
        break;

    case OPTTYPE_INT:
        if (optioncopy.i.min >= -2147483647-1 &&
            optioncopy.i.max <= 2147483647)
        {
            /* Maximum length of a number as text is 11 chars */
            char query[11 + 1 + strlen(optioncopy.name) +
                       sizeof "New value for  (number from  to )"];
            sprintf(query, "New value for %s (number from %d to %d)",
                    optioncopy.name, optioncopy.i.min, optioncopy.i.max);
            curses_getline(query, &optioncopy_p, getlin_option_callback);
        }
        break;

    case OPTTYPE_ENUM:
        select_enum_value(&optioncopy.value, option);
        break;

    case OPTTYPE_STRING:
        if (!strcmp(optioncopy.name, "tileset")) {
            select_tileset_value(&optioncopy.value, option);
        } else {
            char query[strlen(optioncopy.name) + 1 +
                       sizeof "New value for  (text)"];
            sprintf(query, "New value for %s (text)", optioncopy.name);
            optioncopy.value.s = NULL;
            curses_getline(query, &optioncopy_p, getlin_option_callback);
        }
        break;

    case OPTTYPE_AUTOPICKUP_RULES:
        show_autopickup_menu(option);
        goto free;

    case OPTTYPE_KEYMAP:
        show_keymap_menu(FALSE);
        goto free;

    default:
        goto free;
    }

    /* getlin_option_callback NULLs out optioncopy_p to indicate that setting
       was cancelled */
    if (optioncopy_p && !curses_set_option(optioncopy.name, optioncopy.value)) {
        char query[strlen(optioncopy.name) + 1 +
                   sizeof "new value for  rejected"];
        sprintf(query, "new value for %s rejected", optioncopy.name);
        curses_msgwin(query, krc_notification);
    } else if (optioncopy_p) {
        if (listid != UI_OPTS) {
            curses_free_nh_opts(optlist);
            optlist = curses_get_nh_opts();
            option = &optlist[id];
        }

        print_option_string(option, mdat->items[idx].caption);
    }

    /* We need to deallocate any string that might have been allocated by
       the getlin callback. */
    if (optioncopy.type == OPTTYPE_STRING && optioncopy.value.s)
        free(optioncopy.value.s);

    /* If we're changing the option menu appearance, or if we changed game
       options, we need to reload and redraw the menu. */
    if (settings.optstyle != prev_optstyle ||
        settings.menupaging != prev_menupaging ||
        (settings.whichframes != FRAME_NONE) != prev_menuborder ||
        (game_is_running && listid != UI_OPTS))
        ret = TRUE;

free:
    if (listid != UI_OPTS)
        curses_free_nh_opts(optlist);

    return ret;
}