/* * This is called when we receive a request for a command in the birth * process. * The birth process continues until we send a final character confirmation * command (or quit), so this is effectively called in a loop by the main * game. * * We're imposing a step-based system onto the main game here, so we need * to keep track of where we're up to, where each step moves on to, etc. */ errr get_birth_command(bool wait) { static enum birth_stage current_stage = BIRTH_RESET; static enum birth_stage prev; static enum birth_stage roller = BIRTH_RESET; enum birth_stage next = current_stage; switch (current_stage) { case BIRTH_RESET: { cmd_insert(CMD_BIRTH_RESET); roller = BIRTH_RESET; if (quickstart_allowed) next = BIRTH_QUICKSTART; else next = BIRTH_SEX_CHOICE; break; } case BIRTH_QUICKSTART: { display_player(0); next = get_quickstart_command(); break; } case BIRTH_SEX_CHOICE: case BIRTH_CLASS_CHOICE: case BIRTH_RACE_CHOICE: case BIRTH_ROLLER_CHOICE: { menu_type *menu = &sex_menu; cmd_code command = CMD_CHOOSE_SEX; Term_clear(); print_menu_instructions(); if (current_stage > BIRTH_SEX_CHOICE) { menu_refresh(&sex_menu, FALSE); menu = &race_menu; command = CMD_CHOOSE_RACE; } if (current_stage > BIRTH_RACE_CHOICE) { menu_refresh(&race_menu, FALSE); menu = &class_menu; command = CMD_CHOOSE_CLASS; } if (current_stage > BIRTH_CLASS_CHOICE) { menu_refresh(&class_menu, FALSE); menu = &roller_menu; command = CMD_NULL; } next = menu_question(current_stage, menu, command); if (next == BIRTH_BACK) next = current_stage - 1; /* Make sure that the character gets reset before quickstarting */ if (next == BIRTH_QUICKSTART) next = BIRTH_RESET; break; } case BIRTH_POINTBASED: { roller = BIRTH_POINTBASED; if (prev > BIRTH_POINTBASED) point_based_start(); next = point_based_command(); if (next == BIRTH_BACK) next = BIRTH_ROLLER_CHOICE; if (next != BIRTH_POINTBASED) point_based_stop(); break; } case BIRTH_ROLLER: { roller = BIRTH_ROLLER; next = roller_command(prev < BIRTH_ROLLER); if (next == BIRTH_BACK) next = BIRTH_ROLLER_CHOICE; break; } case BIRTH_NAME_CHOICE: { if (prev < BIRTH_NAME_CHOICE) display_player(0); next = get_name_command(); if (next == BIRTH_BACK) next = roller; break; } case BIRTH_FINAL_CONFIRM: { if (prev < BIRTH_FINAL_CONFIRM) display_player(0); next = get_confirm_command(); if (next == BIRTH_BACK) next = BIRTH_NAME_CHOICE; break; } default: { /* Remove dodgy compiler warning, */ } } prev = current_stage; current_stage = next; return 0; }
/* Allow the user to select from the current menu, and return the corresponding command to the game. Some actions are handled entirely by the UI (displaying help text, for instance). */ static enum birth_stage menu_question(enum birth_stage current, menu_type *current_menu, cmd_code choice_command) { struct birthmenu_data *menu_data = current_menu->menu_data; int cursor = current_menu->cursor; ui_event_data cx; enum birth_stage next = BIRTH_RESET; /* Print the question currently being asked. */ clear_question(); Term_putstr(QUESTION_COL, QUESTION_ROW, -1, TERM_YELLOW, menu_data->hint); current_menu->cmd_keys = "?=*\r\n\x18"; /* ?, ,= *, \n, <ctl-X> */ while (next == BIRTH_RESET) { button_kill_all(); button_add("[ENTER]", '\r'); if (menu_data->allow_random) button_add("[RANDOM]", '*'); button_add("[ESCAPE]", ESCAPE); button_add("[OPTIONS]", '='); button_add("[HELP]", '?'); button_add("[QUIT]", '\x18'); /* CTRL-X */ event_signal(EVENT_MOUSEBUTTONS); /* Display the menu, wait for a selection of some sort to be made. */ cx = menu_select(current_menu, &cursor, EVT_CMD); /* As all the menus are displayed in "hierarchical" style, we allow use of "back" (left arrow key or equivalent) to step back in the proces as well as "escape". */ if (cx.type == EVT_BACK || cx.type == EVT_ESCAPE || cx.key == ESCAPE) { next = BIRTH_BACK; } /* '\xff' or DEFINED_XFF is a mouse selection, '\r' a keyboard one. */ else if (cx.key == DEFINED_XFF || cx.key == '\r') { if (current == BIRTH_ROLLER_CHOICE) { if (cursor) { /* Do a first roll of the stats */ cmd_insert(CMD_ROLL_STATS); next = current + 2; } else { /* * Make sure we've got a point-based char to play with. * We call point_based_start here to make sure we get * an update on the points totals before trying to * display the screen. The call to CMD_RESET_STATS * forces a rebuying of the stats to give us up-to-date * totals. This is, it should go without saying, a hack. */ point_based_start(); cmd_insert(CMD_RESET_STATS, TRUE); next = current + 1; } } else { cmd_insert(choice_command, cursor); next = current + 1; } } /* '*' chooses an option at random from those the game's provided. */ else if (cx.key == '*' && menu_data->allow_random) { current_menu->cursor = randint0(current_menu->count); cmd_insert(choice_command, current_menu->cursor); menu_refresh(current_menu); next = current + 1; } else if (cx.key == '=') { do_cmd_options(); next = current; } else if (cx.key == KTRL('X')) { cmd_insert(CMD_QUIT); next = BIRTH_COMPLETE; } else if (cx.key == '?') { do_cmd_help(); } } return next; }
/* Allow the user to select from the current menu, and return the corresponding command to the game. Some actions are handled entirely by the UI (displaying help text, for instance). */ static enum birth_stage menu_question(enum birth_stage current, menu_type *current_menu, cmd_code choice_command) { struct birthmenu_data *menu_data = menu_priv(current_menu); ui_event cx; enum birth_stage next = BIRTH_RESET; /* Print the question currently being asked. */ clear_question(); Term_putstr(QUESTION_COL, QUESTION_ROW, -1, TERM_YELLOW, menu_data->hint); current_menu->cmd_keys = "?=*\x18"; /* ?, =, *, <ctl-X> */ while (next == BIRTH_RESET) { /* Display the menu, wait for a selection of some sort to be made. */ cx = menu_select(current_menu, EVT_KBRD, FALSE); /* As all the menus are displayed in "hierarchical" style, we allow use of "back" (left arrow key or equivalent) to step back in the proces as well as "escape". */ if (cx.type == EVT_ESCAPE) { next = BIRTH_BACK; } else if (cx.type == EVT_SELECT) { if (current == BIRTH_ROLLER_CHOICE) { cmd_insert(CMD_FINALIZE_OPTIONS); if (current_menu->cursor) { /* Do a first roll of the stats */ cmd_insert(CMD_ROLL_STATS); next = current + 2; } else { /* * Make sure we've got a point-based char to play with. * We call point_based_start here to make sure we get * an update on the points totals before trying to * display the screen. The call to CMD_RESET_STATS * forces a rebuying of the stats to give us up-to-date * totals. This is, it should go without saying, a hack. */ point_based_start(); cmd_insert(CMD_RESET_STATS); cmd_set_arg_choice(cmd_get_top(), 0, TRUE); next = current + 1; } } else { cmd_insert(choice_command); cmd_set_arg_choice(cmd_get_top(), 0, current_menu->cursor); next = current + 1; } } else if (cx.type == EVT_KBRD) { /* '*' chooses an option at random from those the game's provided. */ if (cx.key.code == '*' && menu_data->allow_random) { current_menu->cursor = randint0(current_menu->count); cmd_insert(choice_command); cmd_set_arg_choice(cmd_get_top(), 0, current_menu->cursor); menu_refresh(current_menu, FALSE); next = current + 1; } else if (cx.key.code == '=') { do_cmd_options_birth(); next = current; } else if (cx.key.code == KTRL('X')) { cmd_insert(CMD_QUIT); next = BIRTH_COMPLETE; } else if (cx.key.code == '?') { do_cmd_help(); } } } return next; }
/** * This is called when we receive a request for a command in the birth * process. * The birth process continues until we send a final character confirmation * command (or quit), so this is effectively called in a loop by the main * game. * * We're imposing a step-based system onto the main game here, so we need * to keep track of where we're up to, where each step moves on to, etc. */ int textui_do_birth(void) { enum birth_stage current_stage = BIRTH_RESET; enum birth_stage prev; enum birth_stage roller = BIRTH_RESET; enum birth_stage next = current_stage; bool done = FALSE; cmdq_push(CMD_BIRTH_INIT); cmdq_execute(CMD_BIRTH); while (!done) { switch (current_stage) { case BIRTH_RESET: { cmdq_push(CMD_BIRTH_RESET); roller = BIRTH_RESET; if (quickstart_allowed) next = BIRTH_QUICKSTART; else next = BIRTH_RACE_CHOICE; break; } case BIRTH_QUICKSTART: { display_player(0); next = textui_birth_quickstart(); if (next == BIRTH_COMPLETE) done = TRUE; break; } case BIRTH_CLASS_CHOICE: case BIRTH_RACE_CHOICE: case BIRTH_ROLLER_CHOICE: { struct menu *menu = &race_menu; cmd_code command = CMD_CHOOSE_RACE; Term_clear(); print_menu_instructions(); if (current_stage > BIRTH_RACE_CHOICE) { menu_refresh(&race_menu, FALSE); menu = &class_menu; command = CMD_CHOOSE_CLASS; } if (current_stage > BIRTH_CLASS_CHOICE) { menu_refresh(&class_menu, FALSE); menu = &roller_menu; } next = menu_question(current_stage, menu, command); if (next == BIRTH_BACK) next = current_stage - 1; /* Make sure the character gets reset before quickstarting */ if (next == BIRTH_QUICKSTART) next = BIRTH_RESET; break; } case BIRTH_POINTBASED: { roller = BIRTH_POINTBASED; if (prev > BIRTH_POINTBASED) point_based_start(); next = point_based_command(); if (next == BIRTH_BACK) next = BIRTH_ROLLER_CHOICE; if (next != BIRTH_POINTBASED) point_based_stop(); break; } case BIRTH_ROLLER: { roller = BIRTH_ROLLER; next = roller_command(prev < BIRTH_ROLLER); if (next == BIRTH_BACK) next = BIRTH_ROLLER_CHOICE; break; } case BIRTH_NAME_CHOICE: { if (prev < BIRTH_NAME_CHOICE) display_player(0); next = get_name_command(); if (next == BIRTH_BACK) next = roller; break; } case BIRTH_HISTORY_CHOICE: { if (prev < BIRTH_HISTORY_CHOICE) display_player(0); next = get_history_command(); if (next == BIRTH_BACK) next = BIRTH_NAME_CHOICE; break; } case BIRTH_FINAL_CONFIRM: { if (prev < BIRTH_FINAL_CONFIRM) display_player(0); next = get_confirm_command(); if (next == BIRTH_BACK) next = BIRTH_HISTORY_CHOICE; if (next == BIRTH_COMPLETE) done = TRUE; break; } default: { /* Remove dodgy compiler warning, */ } } prev = current_stage; current_stage = next; /* Execute whatever commands have been sent */ cmdq_execute(CMD_BIRTH); } return 0; }