void initoptions(void) { int i; iflags.travelcc.x = iflags.travelcc.y = -1; flags.warnlevel = 1; flags.warntype = 0L; /* init flags.inv_order this way, as setting it via the option * requires a preexisting order */ memcpy(flags.inv_order, def_inv_order, sizeof flags.inv_order); /* since this is done before init_objects(), do partial init here */ objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD; strncpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ); fruitadd(pl_fruit); /* init from option definitions */ for (i = 0; birth_options[i].name; i++) nh_set_option(birth_options[i].name, birth_options[i].value, FALSE); for (i = 0; options[i].name; i++) nh_set_option(options[i].name, options[i].value, FALSE); /* at this point the user may no longer change their birth options. * active_birth_options will recieve birth option changes made during * log replay, so that we can show the user what birth options the * loaded game was started with */ active_birth_options = clone_optlist(birth_options); }
void init_options(void) { int i; find_option("name")->s.maxlen = PL_NSIZ; find_option("dungeon_name")->e = dungeon_name_spec; find_option("menu_headings")->e = menu_headings_spec; find_option("msgheight")->i.min = 0; find_option("msgheight")->i.max = MAX_MSGLINES; find_option("msghistory")->i.min = 20; /* arbitrary min/max values */ find_option("msghistory")->i.max = 20000; find_option("graphics")->e = graphics_spec; find_option("optstyle")->e = optstyle_spec; find_option("scores_top")->i.max = 10000; find_option("scores_around")->i.max = 100; #if defined(PDCURSES) && defined(WIN32) find_option("win_width")->i.min = COLNO; /* can never be narrower than COLNO */ find_option("win_width")->i.max = 100 + COLNO; /* 100 chars wide sidebar already looks pretty silly */ find_option("win_height")->i.min = ROWNO + 3; find_option("win_height")->i.max = 70; /* ROWNO + max msgheight + extra for status and frame */ #endif nh_setup_ui_options(curses_options, boolopt_map, option_change_callback); /* set up option defaults; this is necessary for options that are not * specified in the config file */ for (i = 0; curses_options[i].name; i++) nh_set_option(curses_options[i].name, curses_options[i].value, FALSE); read_ui_config(); }
nh_bool nhnet_set_option(const char *name, union nh_optvalue value, nh_bool isstr) { int ret, i; json_t *jmsg, *joval, *jobj; struct nh_option_desc *gameopts, *birthopts, *opt; struct nh_autopickup_rule *r; ret = nh_set_option(name, value, isstr); if (!nhnet_active()) return ret; if (!api_entry()) return FALSE; gameopts = nhnet_get_options(GAME_OPTIONS); birthopts = nhnet_get_options(CURRENT_BIRTH_OPTIONS); opt = NULL; for (i = 0; gameopts[i].name && !opt; i++) if (!strcmp(name, gameopts[i].name)) opt = &gameopts[i]; for (i = 0; birthopts[i].name && !opt; i++) if (!strcmp(name, birthopts[i].name)) opt = &birthopts[i]; if (opt) { if (isstr || opt->type == OPTTYPE_STRING) joval = json_string(value.s); else if (opt->type == OPTTYPE_INT || opt->type == OPTTYPE_ENUM || opt->type == OPTTYPE_BOOL) { joval = json_integer(value.i); } else if (opt->type == OPTTYPE_AUTOPICKUP_RULES) { joval = json_array(); for (i = 0; value.ar && i < value.ar->num_rules; i++) { r = &value.ar->rules[i]; jobj = json_pack("{ss,si,si,si}", "pattern", r->pattern, "oclass", r->oclass, "buc", r->buc, "action", r->action); json_array_append_new(joval, jobj); } } jmsg = json_pack("{ss,so,si}", "name", name, "value", joval, "isstr", isstr); jmsg = send_receive_msg("set_option", jmsg); if (json_unpack(jmsg, "{si,so!}", "return", &ret, "option", &jobj) == -1) { print_error("Bad response in nhnet_set_option"); } else { free_option_data(opt); read_json_option(jobj, opt); } json_decref(jmsg); } api_exit(); return ret; }
void initoptions(void) { int i; iflags.travelcc.x = iflags.travelcc.y = -1; flags.warnlevel = 1; flags.warntype = 0L; /* init flags.inv_order this way, as setting it via the option * requires a preexisting order */ memcpy(flags.inv_order, def_inv_order, sizeof flags.inv_order); fruitadd(obj_descr[SLIME_MOLD].oc_name); strncpy(pl_fruit, obj_descr[SLIME_MOLD].oc_name, PL_FSIZ); /* init from option definitions */ for (i = 0; birth_options[i].name; i++) nh_set_option(birth_options[i].name, birth_options[i].value, FALSE); for (i = 0; options[i].name; i++) nh_set_option(options[i].name, options[i].value, FALSE); if (!active_birth_options) { /* at this point the user may no longer change their birth options. * active_birth_options will recieve birth option changes made during * log replay, so that we can show the user what birth options the * loaded game was started with */ active_birth_options = clone_optlist(birth_options); } else { /* the switch to alternate birth options has already happened, * so make sure those settings are active instead. */ for (i = 0; active_birth_options[i].name; i++) { nh_set_option(active_birth_options[i].name, active_birth_options[i].value, FALSE); } } }
/* parse a single line from the config file and set the option */ static void read_config_line(char* line) { char *comment, *delim, *name, *value; 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((unsigned char)*name)) name++; while (isspace((unsigned char)*delim)) *delim-- = '\0'; /* remove spaces around value */ delim = value; while (*delim) delim++; delim--; while (isspace((unsigned char)*value)) value++; while (isspace((unsigned char)*delim)) *delim-- = '\0'; /* value may be enclosed with double quotes (") */ if (*value == '"' && *delim == '"') { value++; *delim ='\0'; } optval.s = value; nh_set_option(name, optval, TRUE); }
static void ccmd_set_option(json_t * params) { const char *optname, *optstr, *pattern; json_t *jmsg, *joval, *jopt; int isstr, i, ret; const struct nh_option_desc *gameopt, *birthopt, *option; union nh_optvalue value; struct nh_autopickup_rules ar = { NULL, 0 }; struct nh_autopickup_rule *r; if (json_unpack (params, "{ss,so,si*}", "name", &optname, "value", &joval, "isstr", &isstr) == -1) exit_client("Bad parameters for set_option"); /* find the option_desc for the options that should be set; the option type is required in order to decode the option value. */ gameopt = nh_get_options(GAME_OPTIONS); birthopt = nh_get_options(gameid ? ACTIVE_BIRTH_OPTIONS : CURRENT_BIRTH_OPTIONS); option = find_option(optname, gameopt, birthopt); if (!option) { jmsg = json_pack("{si,so}", "return", FALSE, "option", json_object()); client_msg("set_option", jmsg); return; } /* decode the option value depending on the option type */ if (isstr || option->type == OPTTYPE_STRING) { if (!json_is_string(joval)) exit_client("could not decode option string"); value.s = (char *)json_string_value(joval); } else if (option->type == OPTTYPE_INT || option->type == OPTTYPE_ENUM || option->type == OPTTYPE_BOOL) { if (!json_is_integer(joval)) exit_client("could not decode option value"); value.i = json_integer_value(joval); } else if (option->type == OPTTYPE_AUTOPICKUP_RULES) { if (!json_is_array(joval)) exit_client("could not decode option"); ar.num_rules = json_array_size(joval); ar.rules = malloc(sizeof (struct nh_autopickup_rule) * ar.num_rules); if (ar.num_rules) { value.ar = &ar; for (i = 0; i < ar.num_rules; i++) { r = &ar.rules[i]; if (json_unpack (json_array_get(joval, i), "{ss,si,si,si}", "pattern", &pattern, "oclass", &r->oclass, "buc", &r->buc, "action", &r->action) == -1) exit_client("Error unpacking autopickup rule"); strncpy(r->pattern, pattern, sizeof (r->pattern) - 1); } } else value.ar = NULL; } ret = nh_set_option(optname, value, isstr); if (option->type == OPTTYPE_AUTOPICKUP_RULES) free(ar.rules); gameopt = nh_get_options(GAME_OPTIONS); birthopt = nh_get_options(gameid ? ACTIVE_BIRTH_OPTIONS : CURRENT_BIRTH_OPTIONS); option = find_option(optname, gameopt, birthopt); jopt = json_option(option); optstr = nh_get_option_string(option); if (ret == TRUE) db_set_option(user_info.uid, optname, option->type, optstr); /* return the altered option struct and the string representation to the client. The intent is to save some network round trips and make a separate get_option_string message unneccessary */ jmsg = json_pack("{si,so}", "return", ret, "option", jopt); client_msg("set_option", jmsg); }
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); }
/* 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; }
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); }
nh_bool curses_set_option(const char *name, union nh_optvalue value) { nh_bool game_option = FALSE; struct nh_option_desc *option = nhlib_find_option(curses_options, name); if (!option) { if (game_is_running) return nh_set_option(name, value); /* If the game is not running, update our local copy of options. */ if (!nh_options || !(option = nhlib_find_option(nh_options, name))) { return FALSE; } game_option = TRUE; } if ((int)option->type == OPTTYPE_KEYMAP) { return FALSE; } if (!nhlib_option_value_ok(option, value)) return FALSE; nhlib_copy_option_value(option, value); if (game_option) return TRUE; /* In case the option affects graphics; this is pretty cheap if we don't do it every turn */ mark_mapwin_for_full_refresh(); if (option->type == OPTTYPE_BOOL) { nh_bool *var = nhlib_find_boolopt(boolopt_map, option->name); if (!var) { curses_impossible("missing boolean option"); return FALSE; } *var = value.b; if (!strcmp(option->name, "status3")) { rebuild_ui(); } else if (!strcmp(option->name, "darkgray")) { set_darkgray(); draw_map(player.x, player.y); } else if (!strcmp(option->name, "mouse")) { uncursed_enable_mouse(option->value.b); } } else if (!strcmp(option->name, "comment")) { /* do nothing */ } else if (!strcmp(option->name, "tileset")) { if (settings.tileset) free(settings.tileset); settings.tileset = malloc(strlen(option->value.s) + 1); strcpy(settings.tileset, option->value.s); rebuild_ui(); } else if (!strcmp(option->name, "border")) { settings.whichframes = option->value.e; rebuild_ui(); } else if (!strcmp(option->name, "menu_headings")) { settings.menu_headings = option->value.e; } else if (!strcmp(option->name, "palette")) { settings.palette = option->value.e; setup_palette(); if (ui_flags.initialized) { /* * - We don't want to install a palette as a result of the default * setting of "palette", because some terminals cannot handle a * palette reset, and thus we need to ensure that we've loaded * the user's palette setting before palette initialization. * * - Besides, clear() will crash with an uninitialized libuncursed. * So we have to delay this anyway. */ clear(); refresh(); rebuild_ui(); } } else if (!strcmp(option->name, "animation")) { settings.animation = option->value.e; } else if (!strcmp(option->name, "sidebar")) { settings.sidebar = option->value.e; rebuild_ui(); } else if (!strcmp(option->name, "scores_top")) { settings.end_top = option->value.i; } else if (!strcmp(option->name, "scores_around")) { settings.end_around = option->value.i; } else if (!strcmp(option->name, "networkmotd")) { settings.show_motd = option->value.e; } else if (!strcmp(option->name, "menupaging")) { settings.menupaging = option->value.e; } else if (!strcmp(option->name, "optstyle")) { settings.optstyle = option->value.e; } else if (!strcmp(option->name, "msgheight")) { settings.msgheight = option->value.i; rebuild_ui(); } else if (!strcmp(option->name, "msghistory")) { settings.msghistory = option->value.i; alloc_hist_array(); } else return FALSE; return TRUE; }