/* * Get the next game command, with 'wait' indicating whether we * are prepared to wait for a command or require a quick return with * no command. */ public static Game_Command get(cmd_context c, ref Game_Command cmd, bool wait) { /* If we're repeating, just pull the last command again. */ if (repeating) { cmd = cmd_queue[prev_cmd_idx(cmd_tail)]; return(cmd); } /* If there are no commands queued, ask the UI for one. */ if (cmd_head == cmd_tail) { cmd_get_hook(c, wait); } /* If we have a command ready, set it and return success. */ if (cmd_head != cmd_tail) { cmd = cmd_queue[cmd_tail++]; if (cmd_tail == CMD_QUEUE_SIZE) { cmd_tail = 0; } return(cmd); } /* Failure to get a command. */ return(null); }
public static void cmd_rest() { /* Prompt for time if needed */ if (Misc.p_ptr.command_arg <= 0) { string p = "Rest (0-9999, '!' for HP or SP, '*' for HP and SP, '&' as needed): "; string out_val = "& "; //char out_val[5] = "& "; /* Ask for duration */ if (!Utilities.get_string(p, ref out_val, 4)) { return; } /* Rest until done */ if (out_val[0] == '&') { Game_Command.insert(Command_Code.REST); Game_Command.get_top().set_arg_choice(0, (int)Misc.REST.COMPLETE); } /* Rest a lot */ else if (out_val[0] == '*') { Game_Command.insert(Command_Code.REST); Game_Command.get_top().set_arg_choice(0, (int)Misc.REST.ALL_POINTS); } /* Rest until HP or SP filled */ else if (out_val[0] == '!') { Game_Command.insert(Command_Code.REST); Game_Command.get_top().set_arg_choice(0, (int)Misc.REST.SOME_POINTS); } /* Rest some */ else { int turns = int.Parse(out_val); if (turns <= 0) { return; } if (turns > 9999) { turns = 9999; } Game_Command.insert(Command_Code.REST); Game_Command.get_top().set_arg_choice(0, (int)turns); } } }
/* * Hack -- main Angband initialization entry point * * Verify some files, display the "news.txt" file, create * the high score file, initialize all internal arrays, and * load the basic "user pref files". * * Be very careful to keep track of the order in which things * are initialized, in particular, the only thing *known* to * be available when this function is called is the "z-term.c" * package, and that may not be fully initialized until the * end of this function, when the default "user pref files" * are loaded and "Term_xtra(TERM_XTRA_REACT,0)" is called. * * Note that this function attempts to verify the "news" file, * and the game aborts (cleanly) on failure, since without the * "news" file, it is likely that the "lib" folder has not been * correctly located. Otherwise, the news file is displayed for * the user. * * Note that this function attempts to verify (or create) the * "high score" file, and the game aborts (cleanly) on failure, * since one of the most common "extraction" failures involves * failing to extract all sub-directories (even empty ones), such * as by failing to use the "-d" option of "pkunzip", or failing * to use the "save empty directories" option with "Compact Pro". * This error will often be caught by the "high score" creation * code below, since the "lib/apex" directory, being empty in the * standard distributions, is most likely to be "lost", making it * impossible to create the high score file. * * Note that various things are initialized by this function, * including everything that was once done by "init_some_arrays". * * This initialization involves the parsing of special files * in the "lib/edit" directories. * * Note that the "template" files are initialized first, since they * often contain errors. This means that macros and message recall * and things like that are not available until after they are done. * * We load the default "user pref files" here in case any "color" * changes are needed before character creation. * * Note that the "graf-xxx.prf" file must be loaded separately, * if needed, in the first (?) pass through "TERM_XTRA_REACT". */ public static bool init_angband() { Game_Event.signal(Game_Event.Event_Type.ENTER_INIT); /*** Initialize some arrays ***/ Init.arrays(); /*** Load default user pref files ***/ /* Initialize feature info */ Game_Event.signal_string(Game_Event.Event_Type.INITSTATUS, "Loading basic user pref file..."); /* Process that file */ Prefs.process_pref_file("pref.prf", false, false); /* Done */ Game_Event.signal_string(Game_Event.Event_Type.INITSTATUS, "Initialization complete"); /* Sneakily init command list */ Command.Init(); //#ifdef ALLOW_BORG /* apw */ // /* Allow the screensaver to do its work */ // if (screensaver) // { // event_signal(EVENT_LEAVE_INIT); // return !file_exists(savefile); // } //#endif /* ALLOW_BORG */ /* Ask for a "command" until we get one we like. */ while (true) { Game_Command command_req = new Game_Command(); if (Game_Command.get(cmd_context.CMD_INIT, ref command_req, true) == null) { continue; } else if (command_req.command == Command_Code.QUAFF) { Utilities.quit(); } else if (command_req.command == Command_Code.NEWGAME) { Game_Event.signal(Game_Event.Event_Type.LEAVE_INIT); return(true); } else if (command_req.command == Command_Code.LOADFILE) { Game_Event.signal(Game_Event.Event_Type.LEAVE_INIT); return(false); } } }
/* ------------------------------------------------------------------------ * Final confirmation of character. * ------------------------------------------------------------------------ */ static birth_stage get_confirm_command() { Player.Player p_ptr = Player.Player.instance; string prompt = "['ESC' to step back, 'S' to start over, or any other key to continue]"; keypress ke; birth_stage next; /* Prompt for it */ Utilities.prt(prompt, Term.instance.hgt - 1, Term.instance.wid / 2 - (prompt.Length / 2)); /* Buttons */ Button.button_kill_all(); Button.button_add("[Continue]", 'q'); Button.button_add("[ESC]", (char)keycode_t.ESCAPE); Button.button_add("[S]", 'S'); p_ptr.redraw_stuff(); /* Get a key */ ke = Utilities.inkey(); /* Start over */ if (ke.code == (keycode_t)'S' || ke.code == (keycode_t)'s') { next = birth_stage.BIRTH_RESET; } else if (ke.code == (keycode_t)UIEvent.KTRL('X')) { Game_Command.insert(Command_Code.QUIT); next = birth_stage.BIRTH_COMPLETE; } else if (ke.code == keycode_t.ESCAPE) { next = birth_stage.BIRTH_BACK; } else { Game_Command.insert(Command_Code.ACCEPT_CHARACTER); next = birth_stage.BIRTH_COMPLETE; } /* Buttons */ Button.button_kill_all(); p_ptr.redraw_stuff(); /* Clear prompt */ Utilities.clear_from(23); return(next); }
/* * Inserts a command in the queue to be carried out, with the given * number of repeats. */ public static int insert_repeated(Command_Code c, int nrepeats) { Game_Command cmd = new Game_Command(); if (cmd_idx(c) == -1) { return(1); } cmd.command = c; cmd.nrepeats = nrepeats; return(cmd_insert_s(ref cmd)); }
/* * Remove any pending repeats from the current command. */ public static void cancel_repeat() { Game_Command cmd = cmd_queue[prev_cmd_idx(cmd_tail)]; if (cmd.nrepeats != 0 || repeating) { /* Cancel */ cmd.nrepeats = 0; repeating = false; /* Redraw the state (later) */ Misc.p_ptr.redraw |= (Misc.PR_STATE); } }
/* * Insert the given command into the command queue. */ static int cmd_insert_s(ref Game_Command cmd) { /* If queue full, return error */ if (cmd_head + 1 == cmd_tail) { return(1); } if (cmd_head + 1 == CMD_QUEUE_SIZE && cmd_tail == 0) { return(1); } /* Insert command into queue. */ if (cmd.command != Command_Code.REPEAT) { cmd_queue[cmd_head] = cmd; } else { int cmd_prev = cmd_head - 1; //was previously just "repeat_prev_allowed" if (!repeat_prev_allowed) { return(1); } /* If we're repeating a command, we duplicate the previous command * in the next command "slot". */ if (cmd_prev < 0) { cmd_prev = CMD_QUEUE_SIZE - 1; } if (cmd_queue[cmd_prev].command != Command_Code.NULL) { cmd_queue[cmd_head] = cmd_queue[cmd_prev]; } } /* Advance point in queue, wrapping around at the end */ cmd_head++; if (cmd_head == CMD_QUEUE_SIZE) { cmd_head = 0; } return(0); }
/* * Update the number of repeats pending for the current command. */ public static void set_repeat(int nrepeats) { Game_Command cmd = cmd_queue[prev_cmd_idx(cmd_tail)]; cmd.nrepeats = nrepeats; if (nrepeats != 0) { repeating = true; } else { repeating = false; } /* Redraw the state (later) */ Misc.p_ptr.redraw |= (Misc.PR_STATE); }
/* ------------------------------------------------------------------------ * Asking for the player's chosen name. * ------------------------------------------------------------------------ */ static birth_stage get_name_command() { birth_stage next; string name = ""; if (Utilities.get_name(ref name, 32)) { Game_Command.insert(Command_Code.NAME_CHOICE); Game_Command.get_top().set_arg_choice(0, name); next = birth_stage.BIRTH_FINAL_CONFIRM; } else { next = birth_stage.BIRTH_BACK; } return(next); }
/* * Pass the appropriate "Initialisation screen" command to the game, * getting user input if needed. */ static int get_init_cmd() { /* Wait for response */ Utilities.pause_line(Term.instance); if (new_game) { Game_Command.insert(Command_Code.NEWGAME); } else { /* This might be modified to supply the filename in future. */ Game_Command.insert(Command_Code.LOADFILE); } /* Everything's OK. */ return(0); }
/** * Process a textui keypress. */ static bool process_key(keypress kp) { Command_Info cmd; /* XXXmacro this needs rewriting */ char c = (char)kp.code; if (c == '\n' || c == '\r') { c = TextUI.action_menu_choose(); } if (c == '\0' || c == (char)keycode_t.ESCAPE || c == ' ' || c == '\a') { return(true); } cmd = Command.converted_list[c]; if (cmd == null) { return(false); } if (Command.key_confirm_command(c) && (cmd.prereq == null || cmd.prereq())) { if (cmd.hook != null) { cmd.hook(); } else if (cmd.cmd != Command_Code.NULL) { Game_Command.insert_repeated(cmd.cmd, Misc.p_ptr.command_arg); } } return(true); }
/* * Request a game command from the uI and carry out whatever actions * go along with it. */ public static void process_command(cmd_context ctx, bool no_request) { Game_Command cmd = new Game_Command(); /* Reset so that when selecting items, we look in the default location */ Misc.p_ptr.command_wrk = 0; /* If we've got a command to process, do it. */ if (get(ctx, ref cmd, !no_request) != null) //Was ==null... { int oldrepeats = cmd.nrepeats; int idx = cmd_idx(cmd.command); int i; if (idx == -1) return; for (i = 0; i < item_selector.Length; i++) { item_selector_type itms = item_selector[i]; if (itms.command != cmd.command) continue; if (!cmd.arg_present[0]) { int item = 0; Misc.item_tester_hook = itms.filter; if (!Object.Object.get_item(ref item, itms.prompt, itms.noop, cmd.command, itms.mode)) return; cmd.set_arg_item(0, item); } } /* XXX avoid dead objects from being re-used on repeat. * this needs to be expanded into a general safety-check * on args */ if ((game_cmds[idx].arg_type[0] == cmd_arg_type.arg_ITEM) && cmd.arg_present[0]) { Object.Object o_ptr = Object.Object.object_from_item_idx(cmd.arg[0].value); if (o_ptr.kind == null) return; } /* Do some sanity checking on those arguments that might have been declared as "unknown", such as directions and targets. */ switch (cmd.command) { case Command_Code.INSCRIBE: { throw new NotImplementedException(); //char o_name[80]; //char tmp[80] = ""; //object_type *o_ptr = object_from_item_idx(cmd.arg[0].item); //object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); //msg("Inscribing %s.", o_name); //message_flush(); ///* Use old inscription */ //if (o_ptr.note) // strnfmt(tmp, sizeof(tmp), "%s", quark_str(o_ptr.note)); ///* Get a new inscription (possibly empty) */ //if (!get_string("Inscription: ", tmp, sizeof(tmp))) // return; //cmd_set_arg_string(cmd, 1, tmp); //break; } case Command_Code.OPEN: { throw new NotImplementedException(); //if (Option.easy_open.value && (!cmd.arg_present[0] || // cmd.arg[0].value == (int)Direction.UNKNOWN)) //{ // int y, x; // int n_closed_doors, n_locked_chests; // throw new NotImplementedException(); // n_closed_doors = count_feats(&y, &x, cave_iscloseddoor, false); // n_locked_chests = count_chests(&y, &x, false); // if (n_closed_doors + n_locked_chests == 1) // cmd_set_arg_direction(cmd, 0, coords_to_dir(y, x)); //} //goto get_dir; } case Command_Code.CLOSE: { throw new NotImplementedException(); //if (OPT(easy_open) && (!cmd.arg_present[0] || // cmd.arg[0].direction == DIR_UNKNOWN)) //{ // int y, x; // /* Count open doors */ // if (count_feats(&y, &x, cave_isopendoor, false) == 1) // cmd_set_arg_direction(cmd, 0, coords_to_dir(y, x)); //} //goto get_dir; } case Command_Code.DISARM: { throw new NotImplementedException(); //if (OPT(easy_open) && (!cmd.arg_present[0] || // cmd.arg[0].direction == DIR_UNKNOWN)) //{ // int y, x; // int n_visible_traps, n_trapped_chests; // n_visible_traps = count_feats(&y, &x, cave_isknowntrap, true); // n_trapped_chests = count_chests(&y, &x, true); // if (n_visible_traps + n_trapped_chests == 1) // cmd_set_arg_direction(cmd, 0, coords_to_dir(y, x)); //} //goto get_dir; } case Command_Code.TUNNEL: case Command_Code.WALK: case Command_Code.RUN: case Command_Code.JUMP: case Command_Code.BASH: case Command_Code.ALTER: case Command_Code.JAM: { get_dir: /* Direction hasn't been specified, so we ask for one. */ if (!cmd.arg_present[0] || cmd.arg[0].value == (int)Direction.UNKNOWN) { int dir; if (!Xtra2.get_rep_dir(out dir)) return; cmd.set_arg_direction(0, dir); } break; } case Command_Code.DROP: { throw new NotImplementedException(); //if (!cmd.arg_present[1]) //{ // object_type *o_ptr = object_from_item_idx(cmd.arg[0].item); // int amt = get_quantity(null, o_ptr.number); // if (amt <= 0) // return; // cmd_set_arg_number(cmd, 1, amt); //} //break; } /* * These take an item number and a "target" as arguments, * though a target isn't always actually needed, so we'll * only prompt for it via callback if the item being used needs it. */ case Command_Code.USE_WAND: case Command_Code.USE_ROD: case Command_Code.QUAFF: case Command_Code.ACTIVATE: case Command_Code.READ_SCROLL: case Command_Code.FIRE: case Command_Code.THROW: { bool get_target = false; Object.Object o_ptr = Object.Object.object_from_item_idx(cmd.arg[0].value); /* If we couldn't resolve the item, then abort this */ if (o_ptr.kind == null) break; /* Thrown objects always need an aim, others might, depending * on the object */ if (o_ptr.needs_aim() || cmd.command == Command_Code.THROW) { if(!cmd.arg_present[1]) { get_target = true; } else if(cmd.arg[1].value == (int)Direction.UNKNOWN) { get_target = true; } else if(cmd.arg[1].value == (int)Direction.TARGET && !Target.okay()) { get_target = true; } } cmd.arg[1] = new cmd_arg(); cmd.arg[1].value = 0; if (get_target && !Xtra2.get_aim_dir(ref cmd.arg[1].value)) return; Misc.p_ptr.confuse_dir(ref cmd.arg[1].value, false); cmd.arg_present[1] = true; break; } /* This takes a choice and a direction. */ case Command_Code.CAST: { throw new NotImplementedException(); //bool get_target = false; //if (spell_needs_aim(Misc.p_ptr.Class.spell_book, cmd.arg[0].choice)) //{ // if (!cmd.arg_present[1]) // get_target = true; // if (cmd.arg[1].direction == DIR_UNKNOWN) // get_target = true; // if (cmd.arg[1].direction == DIR_TARGET && !target_okay()) // get_target = true; //} //if (get_target && !get_aim_dir(&cmd.arg[1].direction)) // return; //player_confuse_dir(p_ptr, &cmd.arg[1].direction, false); //cmd.arg_present[1] = true; //break; } case Command_Code.WIELD: { Object.Object o_ptr = Object.Object.object_from_item_idx(cmd.arg[0].value); int slot = o_ptr.wield_slot(); /* Usually if the slot is taken we'll just replace the item in the slot, * but in some cases we need to ask the user which slot they actually * want to replace */ if (Misc.p_ptr.inventory[slot].kind != null) { if (o_ptr.tval == Object.TVal.TV_RING) { string q = "Replace which ring? "; string s = "Error in obj_wield, please report"; Misc.item_tester_hook = Object.Object.obj_is_ring; if (!Object.Object.get_item(ref slot, q, s, Command_Code.WIELD, Misc.USE_EQUIP)) return; } if (o_ptr.is_ammo() && !Misc.p_ptr.inventory[slot].similar(o_ptr, Object.Object.object_stack_t.OSTACK_QUIVER)) { string q = "Replace which ammunition? "; string s = "Error in obj_wield, please report"; Misc.item_tester_hook = Object.Object.obj_is_ammo; if (!Object.Object.get_item(ref slot, q, s, Command_Code.WIELD, Misc.USE_EQUIP)) return; } } /* Set relevant slot */ cmd.set_arg_number(1, slot); break; } default: { /* I can see the point of the compiler warning, but still... */ break; } } /* Command repetition */ if (game_cmds[idx].repeat_allowed) { /* Auto-repeat only if there isn't already a repeat length. */ if (game_cmds[idx].nrepeats > 0 && cmd.nrepeats == 0) Game_Command.set_repeat(game_cmds[idx].nrepeats); } else { cmd.nrepeats = 0; repeating = false; } /* * The command gets to unset this if it isn't appropriate for * the user to repeat it. */ repeat_prev_allowed = true; if (game_cmds[idx].fn != null) game_cmds[idx].fn(cmd.command, cmd.arg); /* If the command hasn't changed nrepeats, count this execution. */ if (cmd.nrepeats > 0 && oldrepeats == Game_Command.get_nrepeats()) Game_Command.set_repeat(oldrepeats - 1); } }
/* * Create a new character. * * Note that we may be called with "junk" leftover in the various * fields, so we must be sure to clear them first. */ public static void player_birth(bool quickstart_allowed) { Game_Command blank = new Game_Command(Command_Code.NULL, null, null, false, 0); Game_Command cmd = blank; short[] stats = new short[(int)Stat.Max]; int[] points_spent = new int[(int)Stat.Max]; int points_left = 0; string buf; int success; bool rolled_stats = false; /* * The last character displayed, to allow the user to flick between two. * We rely on prev.age being zero to determine whether there is a stored * character or not, so initialise it here. */ Birther prev = new Birther(); /* * If quickstart is allowed, we store the old character in this, * to allow for it to be reloaded if we step back that far in the * birth process. */ Birther quickstart_prev = new Birther(); /* * If there's a quickstart character, store it for later use. * If not, default to whatever the first of the choices is. */ if(quickstart_allowed) { quickstart_prev.save_roller_data(); } else { Player.Player.instance.psex = 0; /* XXX default race/class */ Player.Player.instance.Class = Misc.classes; Player.Player.instance.Race = Misc.races; Player.Player.instance.generate(null, null, null); } /* Handle incrementing name suffix */ buf = Utilities.find_roman_suffix_start(Player_Other.instance.full_name); if (buf != null) { /* Try to increment the roman suffix */ success = Utilities.int_to_roman((Utilities.roman_to_int(buf) + 1), buf); if (success == 0) Utilities.msg("Sorry, could not deal with suffix"); } /* We're ready to start the interactive birth process. */ Game_Event.signal_flag(Game_Event.Event_Type.ENTER_BIRTH, quickstart_allowed); /* * Loop around until the UI tells us we have an acceptable character. * Note that it is possible to quit from inside this loop. */ while (cmd.command != Command_Code.ACCEPT_CHARACTER) { /* Grab a command from the queue - we're happy to wait for it. */ if (Game_Command.get(cmd_context.CMD_BIRTH, ref cmd, true) == null) continue; if (cmd.command == Command_Code.BIRTH_RESET) { Player.Player.instance.generate(null, null, null); reset_stats(stats, points_spent, ref points_left); do_birth_reset(quickstart_allowed, quickstart_prev); rolled_stats = false; } else if (cmd.command == Command_Code.CHOOSE_SEX) { Player.Player.instance.psex = (byte)cmd.arg[0].value; Player.Player.instance.generate(null, null, null); } else if (cmd.command == Command_Code.CHOOSE_RACE) { Player.Player.instance.generate(null, Player_Race.player_id2race(cmd.arg[0].value), null); reset_stats(stats, points_spent, ref points_left); generate_stats(stats, points_spent, ref points_left); rolled_stats = false; } else if (cmd.command == Command_Code.CHOOSE_CLASS) { Player.Player.instance.generate(null, null, Player_Class.player_id2class(cmd.arg[0].value)); reset_stats(stats, points_spent, ref points_left); generate_stats(stats, points_spent, ref points_left); rolled_stats = false; } else if (cmd.command == Command_Code.FINALIZE_OPTIONS) { /* Reset score options from cheat options */ for (int i = Option.CHEAT; i < Option.CHEAT + Option.N_OPTS_CHEAT; i++) { Player_Other.instance.opt[Option.SCORE + (i - Option.CHEAT)] = Player_Other.instance.opt[i]; } } else if (cmd.command == Command_Code.BUY_STAT) { /* .choice is the stat to buy */ if (!rolled_stats) buy_stat((Stat)cmd.arg[0].value, stats, points_spent, ref points_left); } else if (cmd.command == Command_Code.SELL_STAT) { /* .choice is the stat to sell */ if (!rolled_stats) sell_stat((Stat)cmd.arg[0].value, stats, points_spent, ref points_left); } else if (cmd.command == Command_Code.RESET_STATS) { /* .choice is whether to regen stats */ reset_stats(stats, points_spent, ref points_left); if (cmd.arg[0].value == 1) generate_stats(stats, points_spent, ref points_left); rolled_stats = false; } else if (cmd.command == Command_Code.ROLL_STATS) { throw new NotImplementedException(); //int i; //save_roller_data(&prev); ///* Get a new character */ //get_stats(stats); ///* Update stats with bonuses, etc. */ //get_bonuses(); ///* There's no real need to do this here, but it's tradition. */ //get_ahw(Player.Player.instance); //Player.Player.instance.history = get_history(Player.Player.instance.race.history, &Player.Player.instance.sc); //Player.Player.instance.sc_birth = Player.Player.instance.sc; //event_signal(EVENT_GOLD); //event_signal(EVENT_AC); //event_signal(EVENT_HP); //event_signal(EVENT_STATS); ///* Give the UI some dummy info about the points situation. */ //points_left = 0; //for (i = 0; i < A_MAX; i++) //{ // points_spent[i] = 0; //} //event_signal_birthpoints(points_spent, points_left); ///* Lock out buying and selling of stats based on rolled stats. */ //rolled_stats = true; } else if (cmd.command == Command_Code.PREV_STATS) { throw new NotImplementedException(); ///* Only switch to the stored "previous" // character if we've actually got one to load. */ //if (prev.age) //{ // load_roller_data(&prev, &prev); // get_bonuses(); //} //event_signal(EVENT_GOLD); //event_signal(EVENT_AC); //event_signal(EVENT_HP); //event_signal(EVENT_STATS); } else if (cmd.command == Command_Code.NAME_CHOICE) { /* Set player name */ Player_Other.instance.full_name = cmd.arg[0].text; //string_free((void *) cmd.arg[0].string); /* Don't change savefile name. If the UI wants it changed, they can do it. XXX (Good idea?) */ Files.process_player_name(false); } /* Various not-specific-to-birth commands. */ else if (cmd.command == Command_Code.HELP) { throw new NotImplementedException(); //char buf[80]; //strnfmt(buf, sizeof(buf), "birth.txt"); //screen_save(); //show_file(buf, null, 0, 0); //screen_load(); } else if (cmd.command == Command_Code.QUIT) { Utilities.quit(); } } roll_hp(); Squelch.birth_init(); /* Clear old messages, add new starting message */ History.clear(); History.add("Began the quest to destroy Morgoth.", History.PLAYER_BIRTH, null); /* Reset message prompt (i.e. no extraneous -more-s) */ Term.msg_flag = true; /* Note player birth in the message recall */ Message.add(" ", Message_Type.MSG_GENERIC); Message.add(" ", Message_Type.MSG_GENERIC); Message.add("====================", Message_Type.MSG_GENERIC); Message.add(" ", Message_Type.MSG_GENERIC); Message.add(" ", Message_Type.MSG_GENERIC); /* Give the player some money */ get_money(); /* Outfit the player, if they can sell the stuff */ if (!Option.birth_no_selling.value) player_outfit(Player.Player.instance); /* Initialise the stores */ Store.reset(); /* Now we're really done.. */ Game_Event.signal(Game_Event.Event_Type.LEAVE_BIRTH); }
/* * Move player in the given direction. * * This routine should only be called when energy has been expended. * * Note that this routine handles monsters in the destination grid, * and also handles attempting to move into walls/doors/rubble/etc. */ public static void move_player(int dir, bool disarm) { int py = Misc.p_ptr.py; int px = Misc.p_ptr.px; int y = py + Misc.ddy[dir]; int x = px + Misc.ddx[dir]; int m_idx = Cave.cave.m_idx[y][x]; /* Attack monsters */ if (m_idx > 0) { /* Mimics surprise the player */ if (Monster.Monster.is_mimicking(m_idx)) { throw new NotImplementedException(); //become_aware(m_idx); ///* Mimic wakes up */ //mon_clear_timed(m_idx, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, false); } else { Attack.py_attack(y, x); } } /* Optionally alter traps/doors on movement */ else if (disarm && (Cave.cave.info[y][x] & Cave.CAVE_MARK) != 0 && (Cave.cave_isknowntrap(Cave.cave, y, x) || Cave.cave_iscloseddoor(Cave.cave, y, x))) { /* Auto-repeat if not already repeating */ if (Game_Command.get_nrepeats() == 0) { Game_Command.set_repeat(99); } Do_Command.alter_aux(dir); } /* Cannot walk through walls */ else if (!Cave.cave_floor_bold(y, x)) { /* Disturb the player */ Cave.disturb(Misc.p_ptr, 0, 0); /* Notice unknown obstacles */ if ((Cave.cave.info[y][x] & Cave.CAVE_MARK) == 0) { /* Rubble */ if (Cave.cave.feat[y][x] == Cave.FEAT_RUBBLE) { Utilities.msgt(Message_Type.MSG_HITWALL, "You feel a pile of rubble blocking your way."); Cave.cave.info[y][x] |= (Cave.CAVE_MARK); Cave.cave_light_spot(Cave.cave, y, x); } /* Closed door */ else if (Cave.cave.feat[y][x] < Cave.FEAT_SECRET) { Utilities.msgt(Message_Type.MSG_HITWALL, "You feel a door blocking your way."); Cave.cave.info[y][x] |= (Cave.CAVE_MARK); Cave.cave_light_spot(Cave.cave, y, x); } /* Wall (or secret door) */ else { Utilities.msgt(Message_Type.MSG_HITWALL, "You feel a wall blocking your way."); Cave.cave.info[y][x] |= (Cave.CAVE_MARK); Cave.cave_light_spot(Cave.cave, y, x); } } /* Mention known obstacles */ else { if (Cave.cave.feat[y][x] == Cave.FEAT_RUBBLE) { Utilities.msgt(Message_Type.MSG_HITWALL, "There is a pile of rubble blocking your way."); } else if (Cave.cave.feat[y][x] < Cave.FEAT_SECRET) { Utilities.msgt(Message_Type.MSG_HITWALL, "There is a door blocking your way."); } else { Utilities.msgt(Message_Type.MSG_HITWALL, "There is a wall blocking your way."); } } } /* Normal movement */ else { /* See if trap detection status will change */ bool old_dtrap = ((Cave.cave.info2[py][px] & (Cave.CAVE2_DTRAP)) != 0); bool new_dtrap = ((Cave.cave.info2[y][x] & (Cave.CAVE2_DTRAP)) != 0); /* Note the change in the detect status */ if (old_dtrap != new_dtrap) { Misc.p_ptr.redraw |= (Misc.PR_DTRAP); } /* Disturb player if the player is about to leave the area */ if (Option.disturb_detect.value && Misc.p_ptr.running != 0 && !Misc.p_ptr.running_firststep && old_dtrap && !new_dtrap) { Cave.disturb(Misc.p_ptr, 0, 0); return; } /* Move player */ Monster.Monster.monster_swap(py, px, y, x); /* New location */ y = py = Misc.p_ptr.py; x = px = Misc.p_ptr.px; /* Searching */ if (Misc.p_ptr.searching != 0 || (Misc.p_ptr.state.skills[(int)Skill.SEARCH_FREQUENCY] >= 50) || Random.one_in_(50 - Misc.p_ptr.state.skills[(int)Skill.SEARCH_FREQUENCY])) { search(false); } /* Handle "store doors" */ if ((Cave.cave.feat[Misc.p_ptr.py][Misc.p_ptr.px] >= Cave.FEAT_SHOP_HEAD) && (Cave.cave.feat[Misc.p_ptr.py][Misc.p_ptr.px] <= Cave.FEAT_SHOP_TAIL)) { /* Disturb */ Cave.disturb(Misc.p_ptr, 0, 0); Game_Command.insert(Command_Code.ENTER_STORE); } /* All other grids (including traps) */ else { /* Handle objects (later) */ Misc.p_ptr.notice |= (Misc.PN_PICKUP); } /* Discover invisible traps */ if (Cave.cave.feat[y][x] == Cave.FEAT_INVIS) { /* Disturb */ Cave.disturb(Misc.p_ptr, 0, 0); /* Message */ Utilities.msg("You found a trap!"); /* Pick a trap */ Trap.pick_trap(y, x); /* Hit the trap */ Trap.hit_trap(y, x); } /* Set off an visible trap */ else if (Cave.cave_isknowntrap(Cave.cave, y, x)) { /* Disturb */ Cave.disturb(Misc.p_ptr, 0, 0); throw new NotImplementedException(); /* Hit the trap */ //hit_trap(y, x); } } Misc.p_ptr.running_firststep = false; }
/* * Prints Searching, Resting, or 'count' status * Display is always exactly 10 characters wide (see below) * * This function was a major bottleneck when resting, so a lot of * the text formatting code was optimized in place below. */ static int prt_state(int row, int col) { ConsoleColor attr = ConsoleColor.White; string text = ""; //16 /* Resting */ if (Misc.p_ptr.resting != 0) { int i; int n = Misc.p_ptr.resting; /* Start with "Rest" */ text = "Rest "; /* Extensive (timed) rest */ if (n >= 1000) { i = n / 100; if (i >= 10) { int q = i / 10; if (q >= 10) { text += Basic.I2D(q / 10); //text[5] = Basic.I2D(q / 10); } else { text += " "; } text += Basic.I2D(q % 10); } else { text += " "; } text += Basic.I2D(i % 10) + "00"; //text[9] = '0'; //text[8] = '0'; //text[7] = I2D(i % 10); } /* Long (timed) rest */ else if (n >= 100) { text += " "; i = n; text += Basic.I2D(i / 100); text += Basic.I2D((i / 10) % 10); text += Basic.I2D(i % 10); //text[9] = Basic.I2D(i % 10); //i = i / 10; //text[8] = Basic.I2D(i % 10); //text[7] = Basic.I2D(i / 10); } /* Medium (timed) rest */ else if (n >= 10) { text += " "; i = n; text += Basic.I2D(i / 10); text += Basic.I2D(i % 10); //text[9] = I2D(i % 10); //text[8] = I2D(i / 10); } /* Short (timed) rest */ else if (n > 0) { text += " "; i = n; text += Basic.I2D(i); //text[9] = I2D(i); } /* Rest until healed */ else if (n == -1) { text += "*****"; //text[5] = text[6] = text[7] = text[8] = text[9] = '*'; } /* Rest until done */ else if (n == -2) { text += "&&&&&"; //text[5] = text[6] = text[7] = text[8] = text[9] = '&'; } /* Rest until HP or SP filled */ else if (n == -3) { text += "!!!!!"; //text[5] = text[6] = text[7] = text[8] = text[9] = '!'; } } /* Repeating */ else if (Game_Command.get_nrepeats() != 0) { int nrepeats = Game_Command.get_nrepeats(); if (nrepeats > 999) { text = "Rep. " + nrepeats / 100 + "00"; } else { text = "Repeat " + nrepeats; } } /* Searching */ else if (Misc.p_ptr.searching != 0) { text = "Searching "; } /* Display the info (or blanks) */ Utilities.c_put_str(attr, text, row, col); return(text.Length); }
/* * Request a game command from the uI and carry out whatever actions * go along with it. */ public static void process_command(cmd_context ctx, bool no_request) { Game_Command cmd = new Game_Command(); /* Reset so that when selecting items, we look in the default location */ Misc.p_ptr.command_wrk = 0; /* If we've got a command to process, do it. */ if (get(ctx, ref cmd, !no_request) != null) //Was ==null... { int oldrepeats = cmd.nrepeats; int idx = cmd_idx(cmd.command); int i; if (idx == -1) { return; } for (i = 0; i < item_selector.Length; i++) { item_selector_type itms = item_selector[i]; if (itms.command != cmd.command) { continue; } if (!cmd.arg_present[0]) { int item = 0; Misc.item_tester_hook = itms.filter; if (!Object.Object.get_item(ref item, itms.prompt, itms.noop, cmd.command, itms.mode)) { return; } cmd.set_arg_item(0, item); } } /* XXX avoid dead objects from being re-used on repeat. * this needs to be expanded into a general safety-check * on args */ if ((game_cmds[idx].arg_type[0] == cmd_arg_type.arg_ITEM) && cmd.arg_present[0]) { Object.Object o_ptr = Object.Object.object_from_item_idx(cmd.arg[0].value); if (o_ptr.kind == null) { return; } } /* Do some sanity checking on those arguments that might have * been declared as "unknown", such as directions and targets. */ switch (cmd.command) { case Command_Code.INSCRIBE: { throw new NotImplementedException(); //char o_name[80]; //char tmp[80] = ""; //object_type *o_ptr = object_from_item_idx(cmd.arg[0].item); //object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); //msg("Inscribing %s.", o_name); //message_flush(); ///* Use old inscription */ //if (o_ptr.note) // strnfmt(tmp, sizeof(tmp), "%s", quark_str(o_ptr.note)); ///* Get a new inscription (possibly empty) */ //if (!get_string("Inscription: ", tmp, sizeof(tmp))) // return; //cmd_set_arg_string(cmd, 1, tmp); //break; } case Command_Code.OPEN: { throw new NotImplementedException(); //if (Option.easy_open.value && (!cmd.arg_present[0] || // cmd.arg[0].value == (int)Direction.UNKNOWN)) //{ // int y, x; // int n_closed_doors, n_locked_chests; // throw new NotImplementedException(); // n_closed_doors = count_feats(&y, &x, cave_iscloseddoor, false); // n_locked_chests = count_chests(&y, &x, false); // if (n_closed_doors + n_locked_chests == 1) // cmd_set_arg_direction(cmd, 0, coords_to_dir(y, x)); //} //goto get_dir; } case Command_Code.CLOSE: { throw new NotImplementedException(); //if (OPT(easy_open) && (!cmd.arg_present[0] || // cmd.arg[0].direction == DIR_UNKNOWN)) //{ // int y, x; // /* Count open doors */ // if (count_feats(&y, &x, cave_isopendoor, false) == 1) // cmd_set_arg_direction(cmd, 0, coords_to_dir(y, x)); //} //goto get_dir; } case Command_Code.DISARM: { throw new NotImplementedException(); //if (OPT(easy_open) && (!cmd.arg_present[0] || // cmd.arg[0].direction == DIR_UNKNOWN)) //{ // int y, x; // int n_visible_traps, n_trapped_chests; // n_visible_traps = count_feats(&y, &x, cave_isknowntrap, true); // n_trapped_chests = count_chests(&y, &x, true); // if (n_visible_traps + n_trapped_chests == 1) // cmd_set_arg_direction(cmd, 0, coords_to_dir(y, x)); //} //goto get_dir; } case Command_Code.TUNNEL: case Command_Code.WALK: case Command_Code.RUN: case Command_Code.JUMP: case Command_Code.BASH: case Command_Code.ALTER: case Command_Code.JAM: { get_dir: /* Direction hasn't been specified, so we ask for one. */ if (!cmd.arg_present[0] || cmd.arg[0].value == (int)Direction.UNKNOWN) { int dir; if (!Xtra2.get_rep_dir(out dir)) { return; } cmd.set_arg_direction(0, dir); } break; } case Command_Code.DROP: { throw new NotImplementedException(); //if (!cmd.arg_present[1]) //{ // object_type *o_ptr = object_from_item_idx(cmd.arg[0].item); // int amt = get_quantity(null, o_ptr.number); // if (amt <= 0) // return; // cmd_set_arg_number(cmd, 1, amt); //} //break; } /* * These take an item number and a "target" as arguments, * though a target isn't always actually needed, so we'll * only prompt for it via callback if the item being used needs it. */ case Command_Code.USE_WAND: case Command_Code.USE_ROD: case Command_Code.QUAFF: case Command_Code.ACTIVATE: case Command_Code.READ_SCROLL: case Command_Code.FIRE: case Command_Code.THROW: { bool get_target = false; Object.Object o_ptr = Object.Object.object_from_item_idx(cmd.arg[0].value); /* If we couldn't resolve the item, then abort this */ if (o_ptr.kind == null) { break; } /* Thrown objects always need an aim, others might, depending * on the object */ if (o_ptr.needs_aim() || cmd.command == Command_Code.THROW) { if (!cmd.arg_present[1]) { get_target = true; } else if (cmd.arg[1].value == (int)Direction.UNKNOWN) { get_target = true; } else if (cmd.arg[1].value == (int)Direction.TARGET && !Target.okay()) { get_target = true; } } cmd.arg[1] = new cmd_arg(); cmd.arg[1].value = 0; if (get_target && !Xtra2.get_aim_dir(ref cmd.arg[1].value)) { return; } Misc.p_ptr.confuse_dir(ref cmd.arg[1].value, false); cmd.arg_present[1] = true; break; } /* This takes a choice and a direction. */ case Command_Code.CAST: { throw new NotImplementedException(); //bool get_target = false; //if (spell_needs_aim(Misc.p_ptr.Class.spell_book, cmd.arg[0].choice)) //{ // if (!cmd.arg_present[1]) // get_target = true; // if (cmd.arg[1].direction == DIR_UNKNOWN) // get_target = true; // if (cmd.arg[1].direction == DIR_TARGET && !target_okay()) // get_target = true; //} //if (get_target && !get_aim_dir(&cmd.arg[1].direction)) // return; //player_confuse_dir(p_ptr, &cmd.arg[1].direction, false); //cmd.arg_present[1] = true; //break; } case Command_Code.WIELD: { Object.Object o_ptr = Object.Object.object_from_item_idx(cmd.arg[0].value); int slot = o_ptr.wield_slot(); /* Usually if the slot is taken we'll just replace the item in the slot, * but in some cases we need to ask the user which slot they actually * want to replace */ if (Misc.p_ptr.inventory[slot].kind != null) { if (o_ptr.tval == Object.TVal.TV_RING) { string q = "Replace which ring? "; string s = "Error in obj_wield, please report"; Misc.item_tester_hook = Object.Object.obj_is_ring; if (!Object.Object.get_item(ref slot, q, s, Command_Code.WIELD, Misc.USE_EQUIP)) { return; } } if (o_ptr.is_ammo() && !Misc.p_ptr.inventory[slot].similar(o_ptr, Object.Object.object_stack_t.OSTACK_QUIVER)) { string q = "Replace which ammunition? "; string s = "Error in obj_wield, please report"; Misc.item_tester_hook = Object.Object.obj_is_ammo; if (!Object.Object.get_item(ref slot, q, s, Command_Code.WIELD, Misc.USE_EQUIP)) { return; } } } /* Set relevant slot */ cmd.set_arg_number(1, slot); break; } default: { /* I can see the point of the compiler warning, but still... */ break; } } /* Command repetition */ if (game_cmds[idx].repeat_allowed) { /* Auto-repeat only if there isn't already a repeat length. */ if (game_cmds[idx].nrepeats > 0 && cmd.nrepeats == 0) { Game_Command.set_repeat(game_cmds[idx].nrepeats); } } else { cmd.nrepeats = 0; repeating = false; } /* * The command gets to unset this if it isn't appropriate for * the user to repeat it. */ repeat_prev_allowed = true; if (game_cmds[idx].fn != null) { game_cmds[idx].fn(cmd.command, cmd.arg); } /* If the command hasn't changed nrepeats, count this execution. */ if (cmd.nrepeats > 0 && oldrepeats == Game_Command.get_nrepeats()) { Game_Command.set_repeat(oldrepeats - 1); } } }
public static int get_birth_command(bool wait) { birth_stage next = current_stage; switch (current_stage) { case birth_stage.BIRTH_RESET: { Game_Command.insert(Command_Code.BIRTH_RESET); roller = birth_stage.BIRTH_RESET; if (quickstart_allowed) { next = birth_stage.BIRTH_QUICKSTART; } else { next = birth_stage.BIRTH_SEX_CHOICE; } break; } case birth_stage.BIRTH_QUICKSTART: { Files.display_player(0); next = get_quickstart_command(); break; } case birth_stage.BIRTH_SEX_CHOICE: case birth_stage.BIRTH_CLASS_CHOICE: case birth_stage.BIRTH_RACE_CHOICE: case birth_stage.BIRTH_ROLLER_CHOICE: { Menu_Type menu = sex_menu; Command_Code command = Command_Code.CHOOSE_SEX; Term.clear(); print_menu_instructions(); if (current_stage > birth_stage.BIRTH_SEX_CHOICE) { sex_menu.refresh(false); menu = race_menu; command = Command_Code.CHOOSE_RACE; } if (current_stage > birth_stage.BIRTH_RACE_CHOICE) { race_menu.refresh(false); menu = class_menu; command = Command_Code.CHOOSE_CLASS; } if (current_stage > birth_stage.BIRTH_CLASS_CHOICE) { class_menu.refresh(false); menu = roller_menu; command = Command_Code.NULL; } next = menu_question(current_stage, menu, command); if (next == birth_stage.BIRTH_BACK) { next = current_stage - 1; } /* Make sure that the character gets reset before quickstarting */ if (next == birth_stage.BIRTH_QUICKSTART) { next = birth_stage.BIRTH_RESET; } break; } case birth_stage.BIRTH_POINTBASED: { roller = birth_stage.BIRTH_POINTBASED; if (prev > birth_stage.BIRTH_POINTBASED) { point_based_start(); } next = point_based_command(); if (next == birth_stage.BIRTH_BACK) { next = birth_stage.BIRTH_ROLLER_CHOICE; } if (next != birth_stage.BIRTH_POINTBASED) { point_based_stop(); } break; } case birth_stage.BIRTH_ROLLER: { roller = birth_stage.BIRTH_ROLLER; next = roller_command(prev < birth_stage.BIRTH_ROLLER); if (next == birth_stage.BIRTH_BACK) { next = birth_stage.BIRTH_ROLLER_CHOICE; } break; } case birth_stage.BIRTH_NAME_CHOICE: { if (prev < birth_stage.BIRTH_NAME_CHOICE) { Files.display_player(0); } next = get_name_command(); if (next == birth_stage.BIRTH_BACK) { next = roller; } break; } case birth_stage.BIRTH_FINAL_CONFIRM: { if (prev < birth_stage.BIRTH_FINAL_CONFIRM) { Files.display_player(0); } next = get_confirm_command(); if (next == birth_stage.BIRTH_BACK) { next = birth_stage.BIRTH_NAME_CHOICE; } break; } } prev = current_stage; current_stage = next; return(0); }
/* * Returns the number of repeats left for the current command. * i.e. zero if not repeating. */ public static int get_nrepeats() { Game_Command cmd = cmd_queue[prev_cmd_idx(cmd_tail)]; return(cmd.nrepeats); }
/* 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 birth_stage menu_question(birth_stage current, Menu_Type current_menu, Command_Code choice_command) { birthmenu_data menu_data = current_menu.menu_data as birthmenu_data; birth_stage next = birth_stage.BIRTH_RESET; /* Print the question currently being asked. */ clear_question(); Term.putstr(QUESTION_COL, QUESTION_ROW, -1, ConsoleColor.Yellow, menu_data.hint); current_menu.cmd_keys = "?=*\x18"; /* ?, =, *, <ctl-X> */ while (next == birth_stage.BIRTH_RESET) { /* Display the menu, wait for a selection of some sort to be made. */ ui_event cx = current_menu.select(ui_event_type.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 == ui_event_type.EVT_ESCAPE) { next = birth_stage.BIRTH_BACK; } else if (cx.type == ui_event_type.EVT_SELECT) { if (current == birth_stage.BIRTH_ROLLER_CHOICE) { Game_Command.insert(Command_Code.FINALIZE_OPTIONS); if (current_menu.cursor != 0) { /* Do a first roll of the stats */ Game_Command.insert(Command_Code.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(); Game_Command.insert(Command_Code.RESET_STATS); Game_Command.get_top().set_arg_choice(0, 1); next = current + 1; } } else { Game_Command.insert(choice_command); Game_Command.get_top().set_arg_choice(0, current_menu.cursor); next = current + 1; } } else if (cx.type == ui_event_type.EVT_KBRD) { /* '*' chooses an option at random from those the game's provided. */ if (cx.key.code == (keycode_t)'*' && menu_data.allow_random) { current_menu.cursor = Random.randint0(current_menu.count); Game_Command.insert(choice_command); Game_Command.get_top().set_arg_choice(0, current_menu.cursor); current_menu.refresh(false); next = current + 1; } else if (cx.key.code == (keycode_t)'=') { Do_Command.options_birth(); next = current; } else if (cx.key.code == (keycode_t)UIEvent.KTRL('X')) { Game_Command.insert(Command_Code.QUIT); next = birth_stage.BIRTH_COMPLETE; } else if (cx.key.code == (keycode_t)'?') { Do_Command.help(); } } } return(next); }
static birth_stage point_based_command() { birth_stage next = birth_stage.BIRTH_POINTBASED; /* point_based_display();*/ /* Place cursor just after cost of current stat */ /* Draw the Selection Cursor */ new Region(COSTS_COL + 4, COSTS_ROW, 1, 6).erase(); Utilities.put_str("<", COSTS_ROW + stat, COSTS_COL + 4); /* Get key */ keypress ch = Utilities.inkey(); if (ch.code == (keycode_t)UIEvent.KTRL('X')) { Game_Command.insert(Command_Code.QUIT); next = birth_stage.BIRTH_COMPLETE; } /* Go back a step, or back to the start of this step */ else if (ch.code == keycode_t.ESCAPE) { next = birth_stage.BIRTH_BACK; } else if (ch.code == (keycode_t)'r' || ch.code == (keycode_t)'R') { Game_Command.insert(Command_Code.RESET_STATS); Game_Command.get_top().set_arg_choice(0, 0); } /* Done */ else if ((ch.code == (keycode_t)'\r') || (ch.code == (keycode_t)'\n')) { next = birth_stage.BIRTH_NAME_CHOICE; } else { int dir = Utilities.target_dir(ch); /* Prev stat, looping round to the bottom when going off the top */ if (dir == 8) { stat = (stat + (int)Stat.Max - 1) % (int)Stat.Max; } /* Next stat, looping round to the top when going off the bottom */ if (dir == 2) { stat = (stat + 1) % (int)Stat.Max; } /* Decrease stat (if possible) */ if (dir == 4) { Game_Command.insert(Command_Code.SELL_STAT); Game_Command.get_top().set_arg_choice(0, stat); } /* Increase stat (if possible) */ if (dir == 6) { Game_Command.insert(Command_Code.BUY_STAT); Game_Command.get_top().set_arg_choice(0, stat); } } return(next); }
/* * Create a new character. * * Note that we may be called with "junk" leftover in the various * fields, so we must be sure to clear them first. */ public static void player_birth(bool quickstart_allowed) { Game_Command blank = new Game_Command(Command_Code.NULL, null, null, false, 0); Game_Command cmd = blank; short[] stats = new short[(int)Stat.Max]; int[] points_spent = new int[(int)Stat.Max]; int points_left = 0; string buf; int success; bool rolled_stats = false; /* * The last character displayed, to allow the user to flick between two. * We rely on prev.age being zero to determine whether there is a stored * character or not, so initialise it here. */ Birther prev = new Birther(); /* * If quickstart is allowed, we store the old character in this, * to allow for it to be reloaded if we step back that far in the * birth process. */ Birther quickstart_prev = new Birther(); /* * If there's a quickstart character, store it for later use. * If not, default to whatever the first of the choices is. */ if (quickstart_allowed) { quickstart_prev.save_roller_data(); } else { Player.Player.instance.psex = 0; /* XXX default race/class */ Player.Player.instance.Class = Misc.classes; Player.Player.instance.Race = Misc.races; Player.Player.instance.generate(null, null, null); } /* Handle incrementing name suffix */ buf = Utilities.find_roman_suffix_start(Player_Other.instance.full_name); if (buf != null) { /* Try to increment the roman suffix */ success = Utilities.int_to_roman((Utilities.roman_to_int(buf) + 1), buf); if (success == 0) { Utilities.msg("Sorry, could not deal with suffix"); } } /* We're ready to start the interactive birth process. */ Game_Event.signal_flag(Game_Event.Event_Type.ENTER_BIRTH, quickstart_allowed); /* * Loop around until the UI tells us we have an acceptable character. * Note that it is possible to quit from inside this loop. */ while (cmd.command != Command_Code.ACCEPT_CHARACTER) { /* Grab a command from the queue - we're happy to wait for it. */ if (Game_Command.get(cmd_context.CMD_BIRTH, ref cmd, true) == null) { continue; } if (cmd.command == Command_Code.BIRTH_RESET) { Player.Player.instance.generate(null, null, null); reset_stats(stats, points_spent, ref points_left); do_birth_reset(quickstart_allowed, quickstart_prev); rolled_stats = false; } else if (cmd.command == Command_Code.CHOOSE_SEX) { Player.Player.instance.psex = (byte)cmd.arg[0].value; Player.Player.instance.generate(null, null, null); } else if (cmd.command == Command_Code.CHOOSE_RACE) { Player.Player.instance.generate(null, Player_Race.player_id2race(cmd.arg[0].value), null); reset_stats(stats, points_spent, ref points_left); generate_stats(stats, points_spent, ref points_left); rolled_stats = false; } else if (cmd.command == Command_Code.CHOOSE_CLASS) { Player.Player.instance.generate(null, null, Player_Class.player_id2class(cmd.arg[0].value)); reset_stats(stats, points_spent, ref points_left); generate_stats(stats, points_spent, ref points_left); rolled_stats = false; } else if (cmd.command == Command_Code.FINALIZE_OPTIONS) { /* Reset score options from cheat options */ for (int i = Option.CHEAT; i < Option.CHEAT + Option.N_OPTS_CHEAT; i++) { Player_Other.instance.opt[Option.SCORE + (i - Option.CHEAT)] = Player_Other.instance.opt[i]; } } else if (cmd.command == Command_Code.BUY_STAT) { /* .choice is the stat to buy */ if (!rolled_stats) { buy_stat((Stat)cmd.arg[0].value, stats, points_spent, ref points_left); } } else if (cmd.command == Command_Code.SELL_STAT) { /* .choice is the stat to sell */ if (!rolled_stats) { sell_stat((Stat)cmd.arg[0].value, stats, points_spent, ref points_left); } } else if (cmd.command == Command_Code.RESET_STATS) { /* .choice is whether to regen stats */ reset_stats(stats, points_spent, ref points_left); if (cmd.arg[0].value == 1) { generate_stats(stats, points_spent, ref points_left); } rolled_stats = false; } else if (cmd.command == Command_Code.ROLL_STATS) { throw new NotImplementedException(); //int i; //save_roller_data(&prev); ///* Get a new character */ //get_stats(stats); ///* Update stats with bonuses, etc. */ //get_bonuses(); ///* There's no real need to do this here, but it's tradition. */ //get_ahw(Player.Player.instance); //Player.Player.instance.history = get_history(Player.Player.instance.race.history, &Player.Player.instance.sc); //Player.Player.instance.sc_birth = Player.Player.instance.sc; //event_signal(EVENT_GOLD); //event_signal(EVENT_AC); //event_signal(EVENT_HP); //event_signal(EVENT_STATS); ///* Give the UI some dummy info about the points situation. */ //points_left = 0; //for (i = 0; i < A_MAX; i++) //{ // points_spent[i] = 0; //} //event_signal_birthpoints(points_spent, points_left); ///* Lock out buying and selling of stats based on rolled stats. */ //rolled_stats = true; } else if (cmd.command == Command_Code.PREV_STATS) { throw new NotImplementedException(); ///* Only switch to the stored "previous" // character if we've actually got one to load. */ //if (prev.age) //{ // load_roller_data(&prev, &prev); // get_bonuses(); //} //event_signal(EVENT_GOLD); //event_signal(EVENT_AC); //event_signal(EVENT_HP); //event_signal(EVENT_STATS); } else if (cmd.command == Command_Code.NAME_CHOICE) { /* Set player name */ Player_Other.instance.full_name = cmd.arg[0].text; //string_free((void *) cmd.arg[0].string); /* Don't change savefile name. If the UI wants it changed, they can do it. XXX (Good idea?) */ Files.process_player_name(false); } /* Various not-specific-to-birth commands. */ else if (cmd.command == Command_Code.HELP) { throw new NotImplementedException(); //char buf[80]; //strnfmt(buf, sizeof(buf), "birth.txt"); //screen_save(); //show_file(buf, null, 0, 0); //screen_load(); } else if (cmd.command == Command_Code.QUIT) { Utilities.quit(); } } roll_hp(); Squelch.birth_init(); /* Clear old messages, add new starting message */ History.clear(); History.add("Began the quest to destroy Morgoth.", History.PLAYER_BIRTH, null); /* Reset message prompt (i.e. no extraneous -more-s) */ Term.msg_flag = true; /* Note player birth in the message recall */ Message.add(" ", Message_Type.MSG_GENERIC); Message.add(" ", Message_Type.MSG_GENERIC); Message.add("====================", Message_Type.MSG_GENERIC); Message.add(" ", Message_Type.MSG_GENERIC); Message.add(" ", Message_Type.MSG_GENERIC); /* Give the player some money */ get_money(); /* Outfit the player, if they can sell the stuff */ if (!Option.birth_no_selling.value) { player_outfit(Player.Player.instance); } /* Initialise the stores */ Store.reset(); /* Now we're really done.. */ Game_Event.signal(Game_Event.Event_Type.LEAVE_BIRTH); }
/* * Insert the given command into the command queue. */ static int cmd_insert_s(ref Game_Command cmd) { /* If queue full, return error */ if (cmd_head + 1 == cmd_tail) return 1; if (cmd_head + 1 == CMD_QUEUE_SIZE && cmd_tail == 0) return 1; /* Insert command into queue. */ if (cmd.command != Command_Code.REPEAT) { cmd_queue[cmd_head] = cmd; } else { int cmd_prev = cmd_head - 1; //was previously just "repeat_prev_allowed" if (!repeat_prev_allowed) return 1; /* If we're repeating a command, we duplicate the previous command in the next command "slot". */ if (cmd_prev < 0) cmd_prev = CMD_QUEUE_SIZE - 1; if (cmd_queue[cmd_prev].command != Command_Code.NULL) cmd_queue[cmd_head] = cmd_queue[cmd_prev]; } /* Advance point in queue, wrapping around at the end */ cmd_head++; if (cmd_head == CMD_QUEUE_SIZE) cmd_head = 0; return 0; }
/* * Inserts a command in the queue to be carried out, with the given * number of repeats. */ public static int insert_repeated(Command_Code c, int nrepeats) { Game_Command cmd = new Game_Command(); if (cmd_idx(c) == -1) return 1; cmd.command = c; cmd.nrepeats = nrepeats; return cmd_insert_s(ref cmd); }
/* * Get the next game command, with 'wait' indicating whether we * are prepared to wait for a command or require a quick return with * no command. */ public static Game_Command get(cmd_context c, ref Game_Command cmd, bool wait) { /* If we're repeating, just pull the last command again. */ if (repeating) { cmd = cmd_queue[prev_cmd_idx(cmd_tail)]; return cmd; } /* If there are no commands queued, ask the UI for one. */ if (cmd_head == cmd_tail) cmd_get_hook(c, wait); /* If we have a command ready, set it and return success. */ if (cmd_head != cmd_tail) { cmd = cmd_queue[cmd_tail++]; if (cmd_tail == CMD_QUEUE_SIZE) cmd_tail = 0; return cmd; } /* Failure to get a command. */ return null; }