/** * Remove a keymap. Return true if one was removed. */ public static bool remove(int keymap, keypress trigger) { Keymap k; Keymap prev = null; Misc.assert(keymap >= 0 && keymap < (int)Mode.MAX); for (k = keymaps[keymap]; k != null; k = k.next) { if (k.key.code == trigger.code && k.key.mods == trigger.mods) { if (prev != null) { prev.next = k.next; } else { keymaps[keymap] = k.next; } return(true); } prev = k; } return(false); }
/** * Find a keymap, given a keypress. */ public static keypress[] find(int keymap, keypress kc) { Keymap k; Misc.assert(keymap >= 0 && keymap < (int)Keymap.Mode.MAX); for (k = keymaps[keymap]; k != null; k = k.next) { if (k.key.code == kc.code && k.key.mods == kc.mods) { return(k.actions); } } return(null); }
/** * Add a keymap to the mappings table. */ public static void add(int keymap, keypress trigger, keypress[] actions, bool user) { Keymap k = new Keymap(); Misc.assert(keymap >= 0 && keymap < (int)Mode.MAX); remove(keymap, trigger); k.key = trigger; k.actions = make(actions); k.user = user; k.next = keymaps[keymap]; keymaps[keymap] = k; return; }
/** * Duplicate a given keypress string and return the duplicate. */ public static keypress[] make(keypress[] actions) { keypress[] newk; int n = actions.Length; /* Make room for the terminator */ //No terminator, we are smart... //n += 1; newk = new keypress[n]; for (int i = 0; i < n; i++) { newk[i] = actions[i]; } return(newk); }
/* * Search the monster, item, and feature types to find the * meaning for the given symbol. * * Note: We currently search items first, then features, then * monsters, and we return the first hit for a symbol. * This is to prevent mimics and lurkers from matching * a symbol instead of the item or feature it is mimicking. * * Todo: concatenate all matches into buf. This will be much * easier once we can loop through item tvals instead of items * (see note below.) * * Todo: Should this take the user's pref files into account? */ private static void lookup_symbol(keypress sym, string buf) { throw new NotImplementedException(); //int i; //monster_base *race; ///* Look through items */ ///* Note: We currently look through all items, and grab the tval when we find a match. //It would make more sense to loop through tvals, but then we need to associate //a display character with each tval. */ //for (i = 1; i < z_info.k_max; i++) { // if (k_info[i].d_char == (char)sym.code) { // strnfmt(buf, max, "%c - %s.", (char)sym.code, tval_find_name(k_info[i].tval)); // return; // } //} ///* Look through features */ ///* Note: We need a better way of doing this. Currently '#' matches secret door, //and '^' matches trap door (instead of the more generic "trap"). */ //for (i = 1; i < z_info.f_max; i++) { // if (f_info[i].d_char == (char)sym.code) { // strnfmt(buf, max, "%c - %s.", (char)sym.code, f_info[i].name); // return; // } //} ///* Look through monster templates */ //for (race = rb_info; race; race = race.next){ // if ((char)sym.code == race.d_char) { // strnfmt(buf, max, "%c - %s.", (char)sym.code, race.text); // return; // } //} ///* No matches */ //strnfmt(buf, max, "%c - %s.", (char)sym.code, "Unknown Symbol"); //return; }
/** * 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); }
/** * Duplicate a given keypress string and return the duplicate. */ public static keypress[] make(keypress[] actions) { keypress[] newk; int n = actions.Length; /* Make room for the terminator */ //No terminator, we are smart... //n += 1; newk = new keypress[n]; for (int i = 0; i < n; i++){ newk[i] = actions[i]; } return newk; }
/** * Find a keymap, given a keypress. */ public static keypress[] find(int keymap, keypress kc) { Keymap k; Misc.assert(keymap >= 0 && keymap < (int)Keymap.Mode.MAX); for (k = keymaps[keymap]; k != null; k = k.next) { if (k.key.code == kc.code && k.key.mods == kc.mods) return k.actions; } return null; }
/* * Process a command in a store * * Note that we must allow the use of a few "special" commands in the stores * which are not allowed in the dungeon, and we must disable some commands * which are allowed in the dungeon but not in the stores, to prevent chaos. */ static bool store_process_command_key(keypress kp) { Command_Code cmd = 0; char key = (char)kp.code; //Had to extract the non-constant cases if(key == UIEvent.KTRL('D') || /* roguelike */ key == 'k') { TextUI.cmd_destroy(); } else if(key == UIEvent.KTRL('E')) { Command_Info.toggle_inven_equip(); } else if(key == UIEvent.KTRL('P')) { Do_Command.messages(); } else { /* Process the keycode */ switch ((char)kp.code) { case 'T': /* roguelike */ case 't': cmd = Command_Code.TAKEOFF; break; case 'P': /* roguelike */ case 'b': TextUI.spell_browse(); break; case '~': TextUI.browse_knowledge(); break; case 'I': TextUI.obj_examine(); break; case 'w': cmd = Command_Code.WIELD; break; case '{': cmd = Command_Code.INSCRIBE; break; case '}': cmd = Command_Code.UNINSCRIBE; break; case 'e': Do_Command.equip(); break; case 'i': Do_Command.inven(); break; case 'C': Do_Command.change_name(); break; case ')': Do_Command.save_screen(); break; default: return false; } } if(cmd != 0) Game_Command.insert_repeated(cmd, 0); return true; }
/* * Return a new position in the menu based on the key * pressed and the flags and various handler functions. */ int get_cursor_key(int top, keypress key) { int i; int n = (this.filter_list != null) ? this.filter_count : this.count; if ((this.flags & (int)menu_type_flags.MN_CASELESS_TAGS) != 0) key.code = (keycode_t)Char.ToUpper((char)key.code); //man that is a lot of work in C#... if ((this.flags & (int)menu_type_flags.MN_NO_TAGS) != 0) { return -1; } else if ((this.flags & (int)menu_type_flags.MN_REL_TAGS) != 0) { for (i = 0; i < n; i++) { char c = this.skin.get_tag(this, i); if ((this.flags & (int)menu_type_flags.MN_CASELESS_TAGS) != 0 && c != '\0') c = Char.ToUpper(c); if (c != '\0' && c == (char)key.code) return i + this.top; } } else if ((this.flags & (int)menu_type_flags.MN_PVT_TAGS) == 0 && (this.selections != null && this.selections.Length > 0)) { for (i = 0; i < selections.Length; i++) { char c = this.selections[i]; if ((this.flags & (int)menu_type_flags.MN_CASELESS_TAGS) != 0) c = Char.ToUpper(c); if (c == (char)key.code) return i; } } else if (this.row_funcs.get_tag != null) { for (i = 0; i < n; i++) { int oid = (this.filter_list != null) ? this.filter_list[i] : i; char c = this.row_funcs.get_tag(this, oid); if ((this.flags & (int)menu_type_flags.MN_CASELESS_TAGS) != 0 && c != '\0') c = Char.ToUpper(c); if (c != '\0' && c == (char)key.code) return i; } } return -1; }
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); }
/* * Examine a grid, return a keypress. * * The "mode" argument contains the "TARGET_LOOK" bit flag, which * indicates that the "space" key should scan through the contents * of the grid, instead of simply returning immediately. This lets * the "look" command get complete information, without making the * "target" command annoying. * * The "info" argument contains the "commands" which should be shown * inside the "[xxx]" text. This string must never be empty, or grids * containing monsters will be displayed with an extra comma. * * Note that if a monster is in the grid, we update both the monster * recall info and the health bar info to track that monster. * * This function correctly handles multiple objects per grid, and objects * and terrain features in the same grid, though the latter never happens. * * This function must handle blindness/hallucination. */ static keypress set_interactive_aux(int y, int x, int mode) { short this_o_idx = 0, next_o_idx = 0; string s1, s2, s3; bool boring; int feat; int[] floor_list = new int[Misc.MAX_FLOOR_STACK]; int floor_num; keypress query = new keypress(); string out_val = "";//new char[256]; string coords;//new char[20]; /* Describe the square location */ coords = coords_desc(y, x); /* Repeat forever */ while (true) { /* Paranoia */ query.code = (keycode_t)' '; /* Assume boring */ boring = true; /* Default */ s1 = "You see "; s2 = ""; s3 = ""; /* The player */ if (Cave.cave.m_idx[y][x] < 0) { /* Description */ s1 = "You are "; /* Preposition */ s2 = "on "; } /* Hallucination messes things up */ if (Misc.p_ptr.timed[(int)Timed_Effect.IMAGE] != 0) { throw new NotImplementedException(); //const char *name = "something strange"; ///* Display a message */ //if (p_ptr.wizard) // strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", // s1, s2, s3, name, coords, y, x); //else // strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", // s1, s2, s3, name, coords); //prt(out_val, 0, 0); //move_cursor_relative(y, x); //query = inkey(); ///* Stop on everything but "return" */ //if (query.code == '\n' || query.code == '\r') // continue; //return query; } /* Actual monsters */ if (Cave.cave.m_idx[y][x] > 0) { Monster.Monster m_ptr = Cave.cave_monster(Cave.cave, Cave.cave.m_idx[y][x]); Monster_Race r_ptr = Misc.r_info[m_ptr.r_idx]; /* Visible */ if (m_ptr.ml && !m_ptr.unaware) { bool recall = false; //char m_name[80]; string m_name; /* Not boring */ boring = false; /* Get the monster name ("a kobold") */ m_name = m_ptr.monster_desc(Monster.Monster.Desc.IND2); /* Hack -- track this monster race */ Cave.monster_race_track(m_ptr.r_idx); /* Hack -- health bar for this monster */ Cave.health_track(Misc.p_ptr, Cave.cave.m_idx[y][x]); /* Hack -- handle stuff */ Misc.p_ptr.handle_stuff(); /* Interact */ while (true) { /* Recall */ if (recall) { /* Save screen */ Utilities.screen_save(); /* Recall on screen */ Monster_Lore.screen_roff(m_ptr.r_idx); /* Command */ query = Utilities.inkey(); /* Load screen */ Utilities.screen_load(); } /* Normal */ else { //char buf[80]; string buf; /* Describe the monster */ buf = look_mon_desc(Cave.cave.m_idx[y][x]); /* Describe, and prompt for recall */ if (Misc.p_ptr.wizard) { out_val = String.Format("{0}{1}{2}{3} ({4}), {5} ({6}:{7}).", s1, s2, s3, m_name, buf, coords, y, x); } else { out_val = String.Format("{0}{1}{2}{3} ({4}), {5}.", s1, s2, s3, m_name, buf, coords); } Utilities.prt(out_val, 0, 0); /* Place cursor */ Cave.move_cursor_relative(y, x); /* Command */ query = Utilities.inkey(); } /* Normal commands */ if (query.code == (keycode_t)'r') recall = !recall; else break; } /* Stop on everything but "return"/"space" */ if ((char)query.code != '\n' && (char)query.code != '\r' && (char)query.code != ' ') break; /* Sometimes stop at "space" key */ if (((char)query.code == ' ') && (mode & (LOOK)) == 0) break; /* Take account of gender */ if (r_ptr.flags.has(Monster_Flag.FEMALE.value)) s1 = "She is "; else if (r_ptr.flags.has(Monster_Flag.MALE.value)) s1 = "He is "; else s1 = "It is "; /* Use a verb */ s2 = "carrying "; /* Scan all objects being carried */ for (this_o_idx = m_ptr.hold_o_idx; this_o_idx != 0; this_o_idx = next_o_idx) { string o_name; //char o_name[80]; Object.Object o_ptr; /* Get the object */ o_ptr = Object.Object.byid(this_o_idx); /* Get the next object */ next_o_idx = o_ptr.next_o_idx; /* Obtain an object description */ o_name = o_ptr.object_desc(Object.Object.Detail.PREFIX | Object.Object.Detail.FULL); /* Describe the object */ if (Misc.p_ptr.wizard) { out_val = String.Format("{0}{1}{2}{3}, {4} ({5}:{6}).", s1, s2, s3, o_name, coords, y, x); } /* Disabled since monsters now carry their drops else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, o_name, coords); } */ Utilities.prt(out_val, 0, 0); Cave.move_cursor_relative(y, x); query = Utilities.inkey(); /* Stop on everything but "return"/"space" */ if (((char)query.code != '\n') && ((char)query.code != '\r') && ((char)query.code != ' ')) break; /* Sometimes stop at "space" key */ if (((char)query.code == ' ') && (mode & (LOOK)) == 0) break; /* Change the intro */ s2 = "also carrying "; } /* Double break */ if (this_o_idx != 0) break; /* Use a preposition */ s2 = "on "; } } /* Assume not floored */ floor_num = Object.Object.scan_floor(floor_list, floor_list.Length, y, x, 0x02); /* Scan all marked objects in the grid */ if ((floor_num > 0) && ((Misc.p_ptr.timed[(int)Timed_Effect.BLIND] == 0) || (y == Misc.p_ptr.py && x == Misc.p_ptr.px))) { /* Not boring */ boring = false; Cave.track_object(-floor_list[0]); Misc.p_ptr.handle_stuff(); /* If there is more than one item... */ if (floor_num > 1) while (true) { /* Describe the pile */ if (Misc.p_ptr.wizard) { out_val = String.Format("{0}{1}{2}a pile of {3} objects, {4} ({5}:{6}).", s1, s2, s3, floor_num, coords, y, x); } else { out_val = String.Format("{0}{1}{2}a pile of {3} objects, {4}.", s1, s2, s3, floor_num, coords); } Utilities.prt(out_val, 0, 0); Cave.move_cursor_relative(y, x); query = Utilities.inkey(); /* Display objects */ if ((char)query.code == 'r') { int rdone = 0; int pos; while (rdone == 0) { /* Save screen */ Utilities.screen_save(); /* Display */ Object.Object.show_floor(floor_list, floor_num, Object.Object.olist_detail_t.OLIST_WEIGHT | Object.Object.olist_detail_t.OLIST_GOLD); /* Describe the pile */ Utilities.prt(out_val, 0, 0); query = Utilities.inkey(); /* Load screen */ Utilities.screen_load(); pos = (char)query.code - 'a'; if (0 <= pos && pos < floor_num) { Cave.track_object(-floor_list[pos]); Misc.p_ptr.handle_stuff(); continue; } rdone = 1; } /* Now that the user's done with the display loop, let's */ /* the outer loop over again */ continue; } /* Done */ break; } /* Only one object to display */ else { //char o_name[80]; string o_name; /* Get the single object in the list */ Object.Object o_ptr = Object.Object.byid((short)floor_list[0]); /* Not boring */ boring = false; /* Obtain an object description */ o_name = o_ptr.object_desc(Object.Object.Detail.PREFIX | Object.Object.Detail.FULL); /* Describe the object */ if (Misc.p_ptr.wizard) { out_val = String.Format("{0}{1}{2}{3}, {4} ({5}:{6}).", s1, s2, s3, o_name, coords, y, x); } else { out_val = String.Format("{0}{1}{2}{3}, {4}.", s1, s2, s3, o_name, coords); } Utilities.prt(out_val, 0, 0); Cave.move_cursor_relative(y, x); query = Utilities.inkey(); /* Stop on everything but "return"/"space" */ if (((char)query.code != '\n') && ((char)query.code != '\r') && ((char)query.code != ' ')) break; /* Sometimes stop at "space" key */ if (((char)query.code == ' ') && (mode & (LOOK)) == 0) break; /* Change the intro */ s1 = "It is "; /* Plurals */ if (o_ptr.number != 1) s1 = "They are "; /* Preposition */ s2 = "on "; } } /* Double break */ if (this_o_idx != 0) break; /* Feature (apply "mimic") */ feat = Misc.f_info[Cave.cave.feat[y][x]].mimic; /* Require knowledge about grid, or ability to see grid */ if ((Cave.cave.info[y][x] & (Cave.CAVE_MARK)) == 0 && !Cave.player_can_see_bold(y,x)) { /* Forget feature */ feat = Cave.FEAT_NONE; } /* Terrain feature if needed */ if (boring || (feat > Cave.FEAT_INVIS)) { string name = Misc.f_info[feat].name; /* Hack -- handle unknown grids */ if (feat == Cave.FEAT_NONE) name = "unknown grid"; /* Pick a prefix */ if (s2 != null && (feat >= Cave.FEAT_DOOR_HEAD)) s2 = "in "; /* Pick proper indefinite article */ s3 = ("aeiouAEIOU".Contains(name[0])) ? "an " : "a "; /* Hack -- special introduction for store doors */ if ((feat >= Cave.FEAT_SHOP_HEAD) && (feat <= Cave.FEAT_SHOP_TAIL)) { s3 = "the entrance to the "; } /* Display a message */ if (Misc.p_ptr.wizard) { out_val = String.Format("{0}{1}{2}{3}, {4} ({5}:{6}).", s1, s2, s3, name, coords, y, x); } else { out_val = String.Format("{0}{1}{2}{3}, {4}.", s1, s2, s3, name, coords); } Utilities.prt(out_val, 0, 0); Cave.move_cursor_relative(y, x); query = Utilities.inkey(); /* Stop on everything but "return"/"space" */ if (((char)query.code != '\n') && ((char)query.code != '\r') && ((char)query.code != ' ')) break; } /* Stop on everything but "return" */ if (((char)query.code != '\n') && ((char)query.code != '\r')) break; } /* Keep going */ return (query); }
/* * Request a command from the user. * * Note that "caret" ("^") is treated specially, and is used to * allow manual input of control characters. This can be used * on many machines to request repeated tunneling (Ctrl-H) and * on the Macintosh to request "Control-Caret". * * Note that "backslash" is treated specially, and is used to bypass any * keymap entry for the following character. This is useful for macros. */ static ui_event get_command() { int mode = (int)(Option.rogue_like_commands.value ? Keymap.Mode.ROGUE : Keymap.Mode.ORIG); keypress[] tmp = new keypress[2] { new keypress(), new keypress() }; ui_event ke = new ui_event(); //ui_event ret = ke; keypress[] act = null; /* Get command */ while (true) { /* Hack -- no flush needed */ Term.msg_flag = false; /* Activate "command mode" */ Utilities.inkey_flag = true; /* Get a command */ ke = Utilities.inkey_ex(); if (ke.type == ui_event_type.EVT_KBRD) { bool keymap_ok = true; switch ((char)ke.key.code) { case '0': { int count = TextUI.get_count(); throw new NotImplementedException(); //if (count == -1 || !get_com_ex("Command: ", &ke)) // continue; //else // p_ptr.command_arg = count; //break; } case '\\': { /* Allow keymaps to be bypassed */ throw new NotImplementedException(); //(void)get_com_ex("Command: ", &ke); //keymap_ok = false; //break; } case '^': { throw new NotImplementedException(); ///* Allow "control chars" to be entered */ //if (get_com("Control: ", &ke.key)) // ke.key.code = KTRL(ke.key.code); //break; } } /* Find any relevant keymap */ if (keymap_ok) { act = Keymap.find(mode, ke.key); //if (act == null) { // ret = ke; //} } } /* Erase the message line */ Utilities.prt("", 0, 0); if (ke.type == ui_event_type.EVT_BUTTON) { /* Buttons are always specified in standard keyset */ act = tmp; tmp[0] = ke.key; } /* Apply keymap if not inside a keymap already */ if (ke.key.code != (keycode_t)0 && act != null && Utilities.inkey_next == null) { //int n = 0; //while (n < act.Length && act[n] != null)//act[n].type // n++; ///* Make room for the terminator */ //n += 1; /* Install the keymap */ for (int q = 0; q < act.Length; q++) //It used to check for q < n instead { request_command_buffer[q] = act[q]; //memcpy(request_command_buffer, act, n); } /* Start using the buffer */ Utilities.inkey_next = new List <keypress>(request_command_buffer); /* Continue */ //ret.type = ke.type; //ret.mouse = ke.mouse; //ret.key = act[0]; continue; } /* Done */ break; } return(ke); }
/** * Remove a keymap. Return true if one was removed. */ public static bool remove(int keymap, keypress trigger) { Keymap k; Keymap prev = null; Misc.assert(keymap >= 0 && keymap < (int)Mode.MAX); for (k = keymaps[keymap]; k != null; k = k.next) { if (k.key.code == trigger.code && k.key.mods == trigger.mods) { if (prev != null) prev.next = k.next; else keymaps[keymap] = k.next; return true; } prev = k; } return false; }
/* * Return a new position in the menu based on the key * pressed and the flags and various handler functions. */ int get_cursor_key(int top, keypress key) { int i; int n = (this.filter_list != null) ? this.filter_count : this.count; if ((this.flags & (int)menu_type_flags.MN_CASELESS_TAGS) != 0) { key.code = (keycode_t)Char.ToUpper((char)key.code); //man that is a lot of work in C#... } if ((this.flags & (int)menu_type_flags.MN_NO_TAGS) != 0) { return(-1); } else if ((this.flags & (int)menu_type_flags.MN_REL_TAGS) != 0) { for (i = 0; i < n; i++) { char c = this.skin.get_tag(this, i); if ((this.flags & (int)menu_type_flags.MN_CASELESS_TAGS) != 0 && c != '\0') { c = Char.ToUpper(c); } if (c != '\0' && c == (char)key.code) { return(i + this.top); } } } else if ((this.flags & (int)menu_type_flags.MN_PVT_TAGS) == 0 && (this.selections != null && this.selections.Length > 0)) { for (i = 0; i < selections.Length; i++) { char c = this.selections[i]; if ((this.flags & (int)menu_type_flags.MN_CASELESS_TAGS) != 0) { c = Char.ToUpper(c); } if (c == (char)key.code) { return(i); } } } else if (this.row_funcs.get_tag != null) { for (i = 0; i < n; i++) { int oid = (this.filter_list != null) ? this.filter_list[i] : i; char c = this.row_funcs.get_tag(this, oid); if ((this.flags & (int)menu_type_flags.MN_CASELESS_TAGS) != 0 && c != '\0') { c = Char.ToUpper(c); } if (c != '\0' && c == (char)key.code) { return(i); } } } return(-1); }
public ui_event() { type = ui_event_type.EVT_NONE; key = null; mouse = null; }