/* start_game: Start a new game * parameters: name, role, race, gend, align, playmode */ static void ccmd_start_game(json_t * params) { char filename[1024], basename[1024], path[1024]; json_t *j_msg; const char *name; int role, race, gend, align, mode, fd, ret; long t; if (json_unpack (params, "{ss,si,si,si,si,si*}", "name", &name, "role", &role, "race", &race, "gender", &gend, "alignment", &align, "mode", &mode) == -1) exit_client("Bad set of parameters for start_game"); /* reset cached display data from a previous game */ reset_cached_diplaydata(); if (mode == MODE_WIZARD && !user_info.can_debug) mode = MODE_EXPLORE; t = (long)time(NULL); snprintf(path, 1024, "%s/save/%s/", settings.workdir, user_info.username); snprintf(basename, 1024, "%ld_%s.nhgame", t, name); snprintf(filename, 1024, "%s%s", path, basename); mkdir(path, 0755); /* should already exist unless something went wrong while upgrading */ fd = open(filename, O_EXCL | O_CREAT | O_RDWR, 0600); if (fd == -1) exit_client("Could not create the logfile"); ret = nh_start_game(fd, name, role, race, gend, align, mode); if (ret) { struct nh_roles_info *ri = nh_get_roles(); const char *rolename = (gend && ri->rolenames_f[role]) ? ri-> rolenames_f[role] : ri->rolenames_m[role]; gamefd = fd; gameid = db_add_new_game(user_info.uid, basename, rolename, ri->racenames[race], ri->gendnames[gend], ri->alignnames[align], mode, name, player_info.level_desc); log_msg("%s has started a new game (%d) as %s", user_info.username, gameid, name); j_msg = json_pack("{si,si}", "return", ret, "gameid", gameid); } else { close(fd); unlink(filename); j_msg = json_pack("{si,si}", "return", ret, "gameid", -1); } client_msg("start_game", j_msg); }
struct nh_roles_info *nhnet_get_roles(void) { struct nh_roles_info *ri = NULL; json_t *jmsg, *jroles_m, *jroles_f, *jraces, *jgenders, *jaligns, *jmatrix; nh_bool *matrix; int i, size; if (!nhnet_active()) return nh_get_roles(); if (!api_entry()) return NULL; jmsg = send_receive_msg("get_roles", json_object()); ri = xmalloc(sizeof(struct nh_roles_info)); if (json_unpack(jmsg, "{si,si,si,si,si,si,si,si,so,so,so,so,so,so}", "num_roles", &ri->num_roles, "num_races", &ri->num_races, "num_genders", &ri->num_genders, "num_aligns", &ri->num_aligns, "def_role", &ri->def_role, "def_race", &ri->def_race, "def_gend", &ri->def_gend, "def_align", &ri->def_align, "rolenames_m", &jroles_m, "rolenames_f", &jroles_f, "racenames", &jraces, "gendnames", &jgenders, "alignnames", &jaligns, "matrix", &jmatrix) == -1 || !json_is_array(jroles_m) || !json_is_array(jroles_f) || !json_is_array(jraces) || !json_is_array(jgenders) || !json_is_array(jaligns) || !json_is_array(jmatrix) || json_array_size(jroles_m) != ri->num_roles || json_array_size(jroles_f) != ri->num_roles || json_array_size(jraces) != ri->num_races || json_array_size(jgenders) != ri->num_genders || json_array_size(jaligns) != ri->num_aligns) { print_error("Incorrect return object in nhnet_get_roles"); ri = NULL; } else { ri->rolenames_m = read_string_array(jroles_m); ri->rolenames_f = read_string_array(jroles_f); ri->racenames = read_string_array(jraces); ri->gendnames = read_string_array(jgenders); ri->alignnames = read_string_array(jaligns); size = json_array_size(jmatrix); matrix = xmalloc(size * sizeof(nh_bool)); for (i = 0; i < size; i++) matrix[i] = json_integer_value(json_array_get(jmatrix, i)); ri->matrix = matrix; } json_decref(jmsg); api_exit(); return ri; }
static void ccmd_get_roles(json_t * params) { int i, len; struct nh_roles_info *ri; json_t *jmsg, *jarr, *j_tmp; void *iter; iter = json_object_iter(params); if (iter) exit_client("non-empty parameter list for get_roles"); ri = nh_get_roles(); jmsg = json_pack("{si,si,si,si,si,si,si,si}", "num_roles", ri->num_roles, "num_races", ri->num_races, "num_genders", ri->num_genders, "num_aligns", ri->num_aligns, "def_role", ri->def_role, "def_race", ri->def_race, "def_gend", ri->def_gend, "def_align", ri->def_align); /* rolenames_m */ jarr = json_array(); for (i = 0; i < ri->num_roles; i++) { j_tmp = ri->rolenames_m[i] ? json_string(ri->rolenames_m[i]) : json_null(); json_array_append_new(jarr, j_tmp); } json_object_set_new(jmsg, "rolenames_m", jarr); /* rolenames_f */ jarr = json_array(); for (i = 0; i < ri->num_roles; i++) { j_tmp = ri->rolenames_f[i] ? json_string(ri->rolenames_f[i]) : json_null(); json_array_append_new(jarr, j_tmp); } json_object_set_new(jmsg, "rolenames_f", jarr); /* racenames */ jarr = json_array(); for (i = 0; i < ri->num_races; i++) { j_tmp = ri->racenames[i] ? json_string(ri->racenames[i]) : json_null(); json_array_append_new(jarr, j_tmp); } json_object_set_new(jmsg, "racenames", jarr); /* gendnames */ jarr = json_array(); for (i = 0; i < ri->num_genders; i++) { j_tmp = ri->gendnames[i] ? json_string(ri->gendnames[i]) : json_null(); json_array_append_new(jarr, j_tmp); } json_object_set_new(jmsg, "gendnames", jarr); /* alignnames */ jarr = json_array(); for (i = 0; i < ri->num_aligns; i++) { j_tmp = ri->alignnames[i] ? json_string(ri->alignnames[i]) : json_null(); json_array_append_new(jarr, j_tmp); } json_object_set_new(jmsg, "alignnames", jarr); /* matrix */ len = ri->num_roles * ri->num_races * ri->num_genders * ri->num_aligns; jarr = json_array(); for (i = 0; i < len; i++) { json_array_append_new(jarr, json_integer(ri->matrix[i])); } json_object_set_new(jmsg, "matrix", jarr); client_msg("get_roles", jmsg); }
static void process_args(int argc, char *argv[]) { int i; const struct nh_roles_info *ri = nh_get_roles(); /* * Process options. */ while (argc > 1 && argv[1][0] == '-') { argv++; argc--; switch (argv[0][1]) { case '-': if (!strcmp(argv[0], "--help")) { puts("Usage: nethack4 [--interface PLUGIN] [OPTIONS]"); puts(""); puts("-k connection-only mode"); puts("-D start games in wizard mode"); puts("-X start games in explore mode"); puts("-u name specify player name"); puts("-p role specify role"); puts("-r race specify race"); puts("-@ specify a random character"); puts("-H dir override the playfield location"); puts("-U dir override the user directory"); puts("-Z disable suspending the process"); puts(""); puts("PLUGIN can be any libuncursed plugin that is installed"); puts("on your system; examples may include 'tty' and 'sdl'."); exit(0); } else if (!strcmp(argv[0], "--version")) { printf("NetHack 4 version %d.%d.%d\n", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); exit(0); } break; case 'k': ui_flags.connection_only = 1; break; case 'D': ui_flags.playmode = MODE_WIZARD; break; case 'X': ui_flags.playmode = MODE_EXPLORE; break; case 'u': if (argv[0][2]) strncpy(cmdline_name, argv[0] + 2, sizeof (cmdline_name) - 1); else if (argc > 1) { argc--; argv++; strncpy(cmdline_name, argv[0], sizeof (cmdline_name) - 1); } else printf("Player name expected after -u"); break; case 'p': /* profession (role) */ if (argv[0][2]) { i = str2role(ri, &argv[0][2]); if (i >= 0) cmdline_role = i; } else if (argc > 1) { argc--; argv++; i = str2role(ri, argv[0]); if (i >= 0) cmdline_role = i; } break; case 'r': /* race */ if (argv[0][2]) { i = str2race(ri, &argv[0][2]); if (i >= 0) cmdline_race = i; } else if (argc > 1) { argc--; argv++; i = str2race(ri, argv[0]); if (i >= 0) cmdline_race = i; } break; case '@': random_player = TRUE; break; case 'H': #ifdef UNIX if (setregid(getgid(), getgid()) < 0) exit(14); #endif if (argv[0][2]) { override_hackdir = argv[0] + 2; } else if (argc > 1) { argc--; argv++; override_hackdir = argv[0]; } break; case 'U': #ifdef UNIX if (setregid(getgid(), getgid()) < 0) exit(14); #endif if (argv[0][2]) { override_userdir = argv[0] + 2; } else if (argc > 1) { argc--; argv++; override_userdir = argv[0]; } break; case 'Z': ui_flags.no_stop = 1; break; default: i = str2role(ri, argv[0]); if (i >= 0) cmdline_role = i; } } }
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; }
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; }