/** * Handle input and update display * */ void uilist::query( bool loop, int timeout ) { keypress = 0; if( entries.empty() ) { ret = UILIST_ERROR; return; } ret = UILIST_WAIT_INPUT; input_context ctxt( input_category ); ctxt.register_updown(); ctxt.register_action( "PAGE_UP" ); ctxt.register_action( "PAGE_DOWN" ); ctxt.register_action( "SCROLL_UP" ); ctxt.register_action( "SCROLL_DOWN" ); if( allow_cancel ) { ctxt.register_action( "QUIT" ); } ctxt.register_action( "CONFIRM" ); ctxt.register_action( "FILTER" ); ctxt.register_action( "ANY_INPUT" ); ctxt.register_action( "HELP_KEYBINDINGS" ); for( const auto &additional_action : additional_actions ) { ctxt.register_action( additional_action.first, additional_action.second ); } hotkeys = ctxt.get_available_single_char_hotkeys( hotkeys ); show(); #if defined(__ANDROID__) for( const auto &entry : entries ) { if( entry.hotkey > 0 && entry.enabled ) { ctxt.register_manual_key( entry.hotkey, entry.txt ); } } #endif do { const auto action = ctxt.handle_input( timeout ); const auto event = ctxt.get_raw_input(); keypress = event.get_first_input(); const auto iter = keymap.find( keypress ); if( scrollby( scroll_amount_from_action( action ) ) ) { /* nothing */ } else if( action == "HELP_KEYBINDINGS" ) { /* nothing, handled by input_context */ } else if( filtering && action == "FILTER" ) { inputfilter(); } else if( iter != keymap.end() ) { selected = iter->second; if( entries[ selected ].enabled ) { ret = entries[ selected ].retval; // valid } else if( allow_disabled ) { ret = entries[selected].retval; // disabled } } else if( !fentries.empty() && action == "CONFIRM" ) { if( entries[ selected ].enabled ) { ret = entries[ selected ].retval; // valid } else if( allow_disabled ) { ret = entries[selected].retval; // disabled } } else if( allow_cancel && action == "QUIT" ) { ret = UILIST_CANCEL; } else if( action == "TIMEOUT" ) { ret = UILIST_TIMEOUT; } else { bool unhandled = callback == nullptr || !callback->key( ctxt, event, selected, this ); if( unhandled && allow_anykey ) { ret = UILIST_UNBOUND; } } show(); } while( loop && ret == UILIST_WAIT_INPUT ); }
void player::power_bionics() { std::vector <bionic *> passive = filtered_bionics( my_bionics, TAB_PASSIVE ); std::vector <bionic *> active = filtered_bionics( my_bionics, TAB_ACTIVE ); bionic *bio_last = NULL; bionic_tab_mode tab_mode = TAB_ACTIVE; //added title_tab_height for the tabbed bionic display int TITLE_HEIGHT = 2; int TITLE_TAB_HEIGHT = 3; // Main window /** Total required height is: * top frame line: + 1 * height of title window: + TITLE_HEIGHT * height of tabs: + TITLE_TAB_HEIGHT * height of the biggest list of active/passive bionics: + bionic_count * bottom frame line: + 1 * TOTAL: TITLE_HEIGHT + TITLE_TAB_HEIGHT + bionic_count + 2 */ const int HEIGHT = std::min( TERMY, std::max( FULL_SCREEN_HEIGHT, TITLE_HEIGHT + TITLE_TAB_HEIGHT + ( int )my_bionics.size() + 2 ) ); const int WIDTH = FULL_SCREEN_WIDTH + ( TERMX - FULL_SCREEN_WIDTH ) / 2; const int START_X = ( TERMX - WIDTH ) / 2; const int START_Y = ( TERMY - HEIGHT ) / 2; //wBio is the entire bionic window WINDOW *wBio = newwin( HEIGHT, WIDTH, START_Y, START_X ); WINDOW_PTR wBioptr( wBio ); const int LIST_HEIGHT = HEIGHT - TITLE_HEIGHT - TITLE_TAB_HEIGHT - 2; const int DESCRIPTION_WIDTH = WIDTH - 2 - 40; const int DESCRIPTION_START_Y = START_Y + TITLE_HEIGHT + TITLE_TAB_HEIGHT + 1; const int DESCRIPTION_START_X = START_X + 1 + 40; //w_description is the description panel that is controlled with ! key WINDOW *w_description = newwin( LIST_HEIGHT, DESCRIPTION_WIDTH, DESCRIPTION_START_Y, DESCRIPTION_START_X ); WINDOW_PTR w_descriptionptr( w_description ); // Title window const int TITLE_START_Y = START_Y + 1; const int HEADER_LINE_Y = TITLE_HEIGHT + TITLE_TAB_HEIGHT + 1; WINDOW *w_title = newwin( TITLE_HEIGHT, WIDTH - 2, TITLE_START_Y, START_X + 1 ); WINDOW_PTR w_titleptr( w_title ); const int TAB_START_Y = TITLE_START_Y + 2; //w_tabs is the tab bar for passive and active bionic groups WINDOW *w_tabs = newwin( TITLE_TAB_HEIGHT, WIDTH - 2, TAB_START_Y, START_X + 1 ); WINDOW_PTR w_tabsptr( w_tabs ); int scroll_position = 0; int cursor = 0; //generate the tab title string and a count of the bionics owned bionic_menu_mode menu_mode = ACTIVATING; // offset for display: bionic with index i is drawn at y=list_start_y+i // drawing the bionics starts with bionic[scroll_position] const int list_start_y = HEADER_LINE_Y;// - scroll_position; int half_list_view_location = LIST_HEIGHT / 2; int max_scroll_position = std::max( 0, ( tab_mode == TAB_ACTIVE ? ( int )active.size() : ( int )passive.size() ) - LIST_HEIGHT ); input_context ctxt( "BIONICS" ); ctxt.register_updown(); ctxt.register_action( "ANY_INPUT" ); ctxt.register_action( "TOGGLE_EXAMINE" ); ctxt.register_action( "REASSIGN" ); ctxt.register_action( "REMOVE" ); ctxt.register_action( "NEXT_TAB" ); ctxt.register_action( "PREV_TAB" ); ctxt.register_action( "CONFIRM" ); ctxt.register_action( "HELP_KEYBINDINGS" ); bool recalc = false; bool redraw = true; for( ;; ) { if( recalc ) { passive = filtered_bionics( my_bionics, TAB_PASSIVE ); active = filtered_bionics( my_bionics, TAB_ACTIVE ); if( active.empty() && !passive.empty() ) { tab_mode = TAB_PASSIVE; } if( --cursor < 0 ) { cursor = 0; } if( scroll_position > max_scroll_position && cursor - scroll_position < LIST_HEIGHT - half_list_view_location ) { scroll_position--; } recalc = false; // bionics were modified, so it's necessary to redraw the screen redraw = true; } //track which list we are looking at std::vector<bionic *> *current_bionic_list = ( tab_mode == TAB_ACTIVE ? &active : &passive ); max_scroll_position = std::max( 0, ( int )current_bionic_list->size() - LIST_HEIGHT ); if( redraw ) { redraw = false; werase( wBio ); draw_border( wBio, BORDER_COLOR, _( " BIONICS " ) ); // Draw symbols to connect additional lines to border mvwputch( wBio, HEADER_LINE_Y - 1, 0, BORDER_COLOR, LINE_XXXO ); // |- mvwputch( wBio, HEADER_LINE_Y - 1, WIDTH - 1, BORDER_COLOR, LINE_XOXX ); // -| if( current_bionic_list->empty() ) { std::string msg; switch( tab_mode ) { case TAB_ACTIVE: msg = _( "No activatable bionics installed." ); break; case TAB_PASSIVE: msg = _( "No passive bionics installed." ); break; } fold_and_print( wBio, list_start_y, 2, WIDTH - 3, c_ltgray, msg ); } else { for( size_t i = scroll_position; i < current_bionic_list->size(); i++ ) { if( list_start_y + static_cast<int>( i ) - scroll_position == HEIGHT - 1 ) { break; } const bool is_highlighted = cursor == static_cast<int>( i ); const nc_color col = get_bionic_text_color( *( *current_bionic_list )[i], is_highlighted ); const std::string desc = string_format( "%c %s", ( *current_bionic_list )[i]->invlet, build_bionic_powerdesc_string( *( *current_bionic_list )[i] ).c_str() ); trim_and_print( wBio, list_start_y + i - scroll_position, 2, WIDTH - 3, col, "%s", desc.c_str() ); // draw bodyparts if( is_highlighted && menu_mode != EXAMINING ) { int max_width = 0; std::vector<std::string>bps; for( int i = 0; i < num_bp; ++i ) { const body_part bp = bp_aBodyPart[i]; const int total = get_total_bionics_slots( bp ); const std::string s = string_format( "%s: %d/%d", body_part_name_as_heading( bp, 1 ).c_str(), total - get_free_bionics_slots( bp ), total ); bps.push_back( s ); max_width = std::max( max_width, utf8_width( s ) ); } const int pos_x = WIDTH - 2 - max_width; const std::string bio_id = ( *current_bionic_list )[i]->id; draw_connectors( wBio, list_start_y + i - scroll_position, utf8_width( desc ) + 3, pos_x - 2, bio_id ); for( int i = 0; i < num_bp; ++i ) { mvwprintz( wBio, i + list_start_y, pos_x, bionic_info( bio_id ).occupied_bodyparts.count( bp_aBodyPart[i] ) > 0 ? c_yellow : c_ltgray, "%s", bps[i].c_str() ); } } } } draw_scrollbar( wBio, cursor, LIST_HEIGHT, current_bionic_list->size(), list_start_y ); } wrefresh( wBio ); draw_bionics_tabs( w_tabs, active.size(), passive.size(), tab_mode ); draw_bionics_titlebar( w_title, this, menu_mode ); if( menu_mode == EXAMINING && !current_bionic_list->empty() ) { draw_description( w_description, *( *current_bionic_list )[cursor] ); } const std::string action = ctxt.handle_input(); const long ch = ctxt.get_raw_input().get_first_input(); bionic *tmp = NULL; bool confirmCheck = false; if( menu_mode == REASSIGNING ) { menu_mode = ACTIVATING; tmp = bionic_by_invlet( ch ); if( tmp == nullptr ) { // Selected an non-existing bionic (or escape, or ...) continue; } redraw = true; const long newch = popup_getkey( _( "%s; enter new letter." ), bionic_info( tmp->id ).name.c_str() ); wrefresh( wBio ); if( newch == ch || newch == ' ' || newch == KEY_ESCAPE ) { continue; } if( !bionic_chars.valid( newch ) ) { popup( _( "Invalid bionic letter. Only those characters are valid:\n\n%s" ), bionic_chars.get_allowed_chars().c_str() ); continue; } bionic *otmp = bionic_by_invlet( newch ); if( otmp != nullptr ) { std::swap( tmp->invlet, otmp->invlet ); } else { tmp->invlet = newch; } // TODO: show a message like when reassigning a key to an item? } else if( action == "NEXT_TAB" ) { redraw = true; scroll_position = 0; cursor = 0; if( tab_mode == TAB_ACTIVE ) { tab_mode = TAB_PASSIVE; } else { tab_mode = TAB_ACTIVE; } } else if( action == "PREV_TAB" ) { redraw = true; scroll_position = 0; cursor = 0; if( tab_mode == TAB_PASSIVE ) { tab_mode = TAB_ACTIVE; } else { tab_mode = TAB_PASSIVE; } } else if( action == "DOWN" ) { redraw = true; if( static_cast<size_t>( cursor ) < current_bionic_list->size() - 1 ) { cursor++; } if( scroll_position < max_scroll_position && cursor - scroll_position > LIST_HEIGHT - half_list_view_location ) { scroll_position++; } } else if( action == "UP" ) { redraw = true; if( cursor > 0 ) { cursor--; } if( scroll_position > 0 && cursor - scroll_position < half_list_view_location ) { scroll_position--; } } else if( action == "REASSIGN" ) { menu_mode = REASSIGNING; } else if( action == "TOGGLE_EXAMINE" ) { // switches between activation and examination menu_mode = menu_mode == ACTIVATING ? EXAMINING : ACTIVATING; redraw = true; } else if( action == "REMOVE" ) { menu_mode = REMOVING; redraw = true; } else if( action == "HELP_KEYBINDINGS" ) { redraw = true; } else if( action == "CONFIRM" ) { confirmCheck = true; } else { confirmCheck = true; } //confirmation either occurred by pressing enter where the bionic cursor is, or the hotkey was selected if( confirmCheck ) { auto &bio_list = tab_mode == TAB_ACTIVE ? active : passive; if( action == "CONFIRM" && !current_bionic_list->empty() ) { tmp = bio_list[cursor]; } else { tmp = bionic_by_invlet( ch ); if( tmp && tmp != bio_last ) { // new bionic selected, update cursor and scroll position int temp_cursor = 0; for( temp_cursor = 0; temp_cursor < ( int )bio_list.size(); temp_cursor++ ) { if( bio_list[temp_cursor] == tmp ) { break; } } // if bionic is not found in current list, ignore the attempt to view/activate if( temp_cursor >= ( int )bio_list.size() ) { continue; } //relocate cursor to the bionic that was found cursor = temp_cursor; scroll_position = 0; while( scroll_position < max_scroll_position && cursor - scroll_position > LIST_HEIGHT - half_list_view_location ) { scroll_position++; } } } if( !tmp ) { // entered a key that is not mapped to any bionic, // -> leave screen break; } bio_last = tmp; const std::string &bio_id = tmp->id; const bionic_data &bio_data = bionic_info( bio_id ); if( menu_mode == REMOVING ) { recalc = uninstall_bionic( bio_id ); redraw = true; continue; } if( menu_mode == ACTIVATING ) { if( bio_data.activated ) { int b = tmp - &my_bionics[0]; if( tmp->powered ) { deactivate_bionic( b ); } else { activate_bionic( b ); } // update message log and the menu g->refresh_all(); redraw = true; continue; } else { popup( _( "You can not activate %s!\n" "To read a description of %s, press '!', then '%c'." ), bio_data.name.c_str(), bio_data.name.c_str(), tmp->invlet ); redraw = true; } } else if( menu_mode == EXAMINING ) { // Describing bionics, allow user to jump to description key redraw = true; if( action != "CONFIRM" ) { for( size_t i = 0; i < active.size(); i++ ) { if( active[i] == tmp ) { tab_mode = TAB_ACTIVE; cursor = static_cast<int>( i ); int max_scroll_check = std::max( 0, ( int )active.size() - LIST_HEIGHT ); if( static_cast<int>( i ) > max_scroll_check ) { scroll_position = max_scroll_check; } else { scroll_position = i; } break; } } for( size_t i = 0; i < passive.size(); i++ ) { if( passive[i] == tmp ) { tab_mode = TAB_PASSIVE; cursor = static_cast<int>( i ); int max_scroll_check = std::max( 0, ( int )passive.size() - LIST_HEIGHT ); if( static_cast<int>( i ) > max_scroll_check ) { scroll_position = max_scroll_check; } else { scroll_position = i; } break; } } } } } } }
void construction_menu() { static bool hide_unconstructable = false; // only display constructions the player can theoretically perform std::vector<std::string> available; std::map<std::string, std::vector<std::string>> cat_available; load_available_constructions( available, cat_available, hide_unconstructable ); if( available.empty() ) { popup( _( "You can not construct anything here." ) ); return; } int w_height = TERMY; if( ( int )available.size() + 2 < w_height ) { w_height = available.size() + 2; } if( w_height < FULL_SCREEN_HEIGHT ) { w_height = FULL_SCREEN_HEIGHT; } const int w_width = std::max( FULL_SCREEN_WIDTH, TERMX * 2 / 3); const int w_y0 = ( TERMY > w_height ) ? ( TERMY - w_height ) / 2 : 0; const int w_x0 = ( TERMX > w_width ) ? ( TERMX - w_width ) / 2 : 0; WINDOW_PTR w_con_ptr {newwin( w_height, w_width, w_y0, w_x0 )}; WINDOW *const w_con = w_con_ptr.get(); const int w_list_width = int( .375 * w_width ); const int w_list_height = w_height - 4; const int w_list_x0 = 1; WINDOW_PTR w_list_ptr {newwin( w_list_height, w_list_width, w_y0 + 3, w_x0 + w_list_x0 )}; WINDOW *const w_list = w_list_ptr.get(); draw_grid( w_con, w_list_width + w_list_x0 ); //tabcount needs to be increased to add more categories int tabcount = 10; std::string construct_cat[] = {_( "All" ), _( "Constructions" ), _( "Furniture" ), _( "Digging and Mining" ), _( "Repairing" ), _( "Reinforcing" ), _( "Decorative" ), _( "Farming and Woodcutting" ), _( "Others" ), _( "Filter" ) }; bool update_info = true; bool update_cat = true; bool isnew = true; int tabindex = 0; int select = 0; int offset = 0; bool exit = false; std::string category_name = ""; std::vector<std::string> constructs; //storage for the color text so it can be scrolled std::vector< std::vector < std::string > > construct_buffers; std::vector<std::string> full_construct_buffer; std::vector<int> construct_buffer_breakpoints; int total_project_breakpoints = 0; int current_construct_breakpoint = 0; bool previous_hide_unconstructable = false; //track the cursor to determine when to refresh the list of construction recipes int previous_tabindex = -1; int previous_select = -1; const inventory &total_inv = g->u.crafting_inventory(); input_context ctxt( "CONSTRUCTION" ); ctxt.register_action( "UP", _( "Move cursor up" ) ); ctxt.register_action( "DOWN", _( "Move cursor down" ) ); ctxt.register_action( "RIGHT", _( "Move tab right" ) ); ctxt.register_action( "LEFT", _( "Move tab left" ) ); ctxt.register_action( "PAGE_UP" ); ctxt.register_action( "PAGE_DOWN" ); ctxt.register_action( "CONFIRM" ); ctxt.register_action( "TOGGLE_UNAVAILABLE_CONSTRUCTIONS" ); ctxt.register_action( "QUIT" ); ctxt.register_action( "HELP_KEYBINDINGS" ); ctxt.register_action( "FILTER" ); std::string filter; int previous_index = 0; do { if( update_cat ) { update_cat = false; switch( tabindex ) { case 0: category_name = "ALL"; break; case 1: category_name = "CONSTRUCT"; break; case 2: category_name = "FURN"; break; case 3: category_name = "DIG"; break; case 4: category_name = "REPAIR"; break; case 5: category_name = "REINFORCE"; break; case 6: category_name = "DECORATE"; break; case 7: category_name = "FARM_WOOD"; break; case 8: category_name = "OTHER"; break; case 9: category_name = "FILTER"; break; } if( category_name == "ALL" ) { constructs = available; previous_index = tabindex; } else if( category_name == "FILTER" ) { constructs.clear(); std::copy_if( available.begin(), available.end(), std::back_inserter( constructs ), [&](const std::string &a){ return lcmatch(a, filter); } ); } else { constructs = cat_available[category_name]; previous_index = tabindex; } if( isnew ){ if( !uistate.last_construction.empty() ){ select = std::distance(constructs.begin(), std::find( constructs.begin(), constructs.end(), uistate.last_construction )); } filter = uistate.construction_filter; } } // Erase existing tab selection & list of constructions mvwhline( w_con, 1, 1, ' ', w_list_width ); werase( w_list ); // Print new tab listing mvwprintz( w_con, 1, 1, c_yellow, "<< %s >>", construct_cat[tabindex].c_str() ); // Determine where in the master list to start printing calcStartPos( offset, select, w_list_height, constructs.size() ); // Print the constructions between offset and max (or how many will fit) for( size_t i = 0; ( int )i < w_list_height && ( i + offset ) < constructs.size(); i++ ) { int current = i + offset; std::string con_name = constructs[current]; bool highlight = ( current == select ); trim_and_print( w_list, i, 0, w_list_width, construction_color( con_name, highlight ), "%s", con_name.c_str() ); } if( update_info ) { update_info = false; // Clear out lines for tools & materials const int pos_x = w_list_width + w_list_x0 + 2; const int available_window_width = w_width - pos_x - 1; for( int i = 1; i < w_height - 1; i++ ) { mvwhline( w_con, i, pos_x, ' ', available_window_width ); } nc_color color_stage = c_white; std::vector<std::string> notes; notes.push_back( string_format( _( "Press %s or %s to tab." ), ctxt.get_desc( "LEFT" ).c_str(), ctxt.get_desc( "RIGHT" ).c_str() ) ); notes.push_back( string_format( _( "Press %s to search." ), ctxt.get_desc( "FILTER" ).c_str() ) ); notes.push_back( string_format( _( "Press %s to toggle unavailable constructions." ), ctxt.get_desc( "TOGGLE_UNAVAILABLE_CONSTRUCTIONS" ).c_str() ) ); notes.push_back( string_format( _( "Press %s to view and edit key-bindings." ), ctxt.get_desc( "HELP_KEYBINDINGS" ).c_str() ) ); //leave room for top and bottom UI text const int available_buffer_height = w_height - 3 - 3 - (int)notes.size(); // print the hotkeys regardless of if there are constructions for( size_t i = 0; i < notes.size(); ++i ) { trim_and_print( w_con, w_height - 1 - (int)notes.size() + (int)i, pos_x, available_window_width, c_white, "%s", notes[i].c_str() ); } if( !constructs.empty() ) { if( select >= (int) constructs.size() ){ select = 0; } std::string current_desc = constructs[select]; // Print construction name trim_and_print( w_con, 1, pos_x, available_window_width, c_white, "%s", current_desc.c_str() ); //only reconstruct the project list when moving away from the current item, or when changing the display mode if( previous_select != select || previous_tabindex != tabindex || previous_hide_unconstructable != hide_unconstructable ) { previous_select = select; previous_tabindex = tabindex; previous_hide_unconstructable = hide_unconstructable; //construct the project list buffer // Print stages and their requirement. std::vector<construction *> options = constructions_by_desc( current_desc ); construct_buffers.clear(); total_project_breakpoints = 0; current_construct_breakpoint = 0; construct_buffer_breakpoints.clear(); full_construct_buffer.clear(); int stage_counter = 0; for( std::vector<construction *>::iterator it = options.begin(); it != options.end(); ++it ) { stage_counter++; construction *current_con = *it; if( hide_unconstructable && !can_construct( *current_con ) ) { continue; } // Update the cached availability of components and tools in the requirement object current_con->requirements->can_make_with_inventory( total_inv ); std::vector<std::string> current_buffer; std::ostringstream current_line; // display result only if more than one step. // Assume single stage constructions should be clear // in their description what their result is. if( current_con->post_terrain != "" && options.size() > 1 ) { //also print out stage number when multiple stages are available current_line << _( "Stage #" ) << stage_counter; current_buffer.push_back( current_line.str() ); current_line.str( "" ); std::string result_string; if( current_con->post_is_furniture ) { result_string = furn_str_id( current_con->post_terrain ).obj().name; } else { result_string = ter_str_id( current_con->post_terrain ).obj().name; } current_line << "<color_" << string_from_color( color_stage ) << ">" << string_format( _( "Result: %s" ), result_string.c_str() ) << "</color>"; std::vector<std::string> folded_result_string = foldstring( current_line.str(), available_window_width ); current_buffer.insert( current_buffer.end(), folded_result_string.begin(), folded_result_string.end() ); } current_line.str( "" ); // display required skill and difficulty int pskill = g->u.get_skill_level( current_con->skill ); int diff = ( current_con->difficulty > 0 ) ? current_con->difficulty : 0; current_line << "<color_" << string_from_color( ( pskill >= diff ? c_white : c_red ) ) << ">" << string_format( _( "Skill Req: %d (%s)" ), diff, current_con->skill.obj().name().c_str() ) << "</color>"; current_buffer.push_back( current_line.str() ); // TODO: Textify pre_flags to provide a bit more information. // Example: First step of dig pit could say something about // requiring diggable ground. current_line.str( "" ); if( current_con->pre_terrain != "" ) { std::string require_string; if( current_con->pre_is_furniture ) { require_string = furn_str_id( current_con->pre_terrain ).obj().name; } else { require_string = ter_str_id( current_con->pre_terrain ).obj().name; } current_line << "<color_" << string_from_color( color_stage ) << ">" << string_format( _( "Requires: %s" ), require_string.c_str() ) << "</color>"; std::vector<std::string> folded_result_string = foldstring( current_line.str(), available_window_width ); current_buffer.insert( current_buffer.end(), folded_result_string.begin(), folded_result_string.end() ); } // get pre-folded versions of the rest of the construction project to be displayed later // get time needed std::vector<std::string> folded_time = current_con->get_folded_time_string( available_window_width ); current_buffer.insert( current_buffer.end(), folded_time.begin(), folded_time.end() ); std::vector<std::string> folded_tools = current_con->requirements->get_folded_tools_list( available_window_width, color_stage, total_inv ); current_buffer.insert( current_buffer.end(), folded_tools.begin(), folded_tools.end() ); std::vector<std::string> folded_components = current_con->requirements->get_folded_components_list( available_window_width, color_stage, total_inv ); current_buffer.insert( current_buffer.end(), folded_components.begin(), folded_components.end() ); construct_buffers.push_back( current_buffer ); } //determine where the printing starts for each project, so it can be scrolled to those points size_t current_buffer_location = 0; for( size_t i = 0; i < construct_buffers.size(); i++ ) { construct_buffer_breakpoints.push_back( static_cast<int>( current_buffer_location ) ); full_construct_buffer.insert( full_construct_buffer.end(), construct_buffers[i].begin(), construct_buffers[i].end() ); //handle text too large for one screen if( construct_buffers[i].size() > static_cast<size_t>( available_buffer_height ) ) { construct_buffer_breakpoints.push_back( static_cast<int>( current_buffer_location + static_cast<size_t>( available_buffer_height ) ) ); } current_buffer_location += construct_buffers[i].size(); if( i < construct_buffers.size() - 1 ) { full_construct_buffer.push_back( std::string( "" ) ); current_buffer_location++; } } total_project_breakpoints = static_cast<int>( construct_buffer_breakpoints.size() ); } if( current_construct_breakpoint > 0 ) { // Print previous stage indicator if breakpoint is past the beginning trim_and_print( w_con, 2, pos_x, available_window_width, c_white, _( "Press %s to show previous stage(s)." ), ctxt.get_desc( "PAGE_UP" ).c_str() ); } if( static_cast<size_t>( construct_buffer_breakpoints[current_construct_breakpoint] + available_buffer_height ) < full_construct_buffer.size() ) { // Print next stage indicator if more breakpoints are remaining after screen height trim_and_print( w_con, w_height - 2 - (int)notes.size(), pos_x, available_window_width, c_white, _( "Press %s to show next stage(s)." ), ctxt.get_desc( "PAGE_DOWN" ).c_str() ); } // Leave room for above/below indicators int ypos = 3; nc_color stored_color = color_stage; for( size_t i = static_cast<size_t>( construct_buffer_breakpoints[current_construct_breakpoint] ); i < full_construct_buffer.size(); i++ ) { //the value of 3 is from leaving room at the top of window if( ypos > available_buffer_height + 3 ) { break; } print_colored_text( w_con, ypos++, ( w_list_width + w_list_x0 + 2 ), stored_color, color_stage, full_construct_buffer[i] ); } } } // Finished updating draw_scrollbar( w_con, select, w_list_height, constructs.size(), 3 ); wrefresh( w_con ); wrefresh( w_list ); const std::string action = ctxt.handle_input(); if( action == "FILTER" ){ filter = string_input_popup( _( "Search" ), 50, filter, "", _( "Filter" ), 100, false ); if( !filter.empty() ){ update_info = true; update_cat = true; tabindex = 9; select = 0; }else if( previous_index !=9 ){ tabindex = previous_index; update_info = true; update_cat = true; select = 0; } uistate.construction_filter = filter; } else if( action == "DOWN" ) { update_info = true; if( select < ( int )constructs.size() - 1 ) { select++; } else { select = 0; } } else if( action == "UP" ) { update_info = true; if( select > 0 ) { select--; } else { select = constructs.size() - 1; } } else if( action == "LEFT" ) { update_info = true; update_cat = true; select = 0; tabindex--; if( tabindex < 0 ) { tabindex = tabcount - 1; } } else if( action == "RIGHT" ) { update_info = true; update_cat = true; select = 0; tabindex = ( tabindex + 1 ) % tabcount; } else if( action == "PAGE_UP" ) { update_info = true; if( current_construct_breakpoint > 0 ) { current_construct_breakpoint--; } if( current_construct_breakpoint < 0 ) { current_construct_breakpoint = 0; } } else if( action == "PAGE_DOWN" ) { update_info = true; if( current_construct_breakpoint < total_project_breakpoints - 1 ) { current_construct_breakpoint++; } if( current_construct_breakpoint >= total_project_breakpoints ) { current_construct_breakpoint = total_project_breakpoints - 1; } } else if( action == "QUIT" ) { exit = true; } else if( action == "HELP_KEYBINDINGS" ) { draw_grid( w_con, w_list_width + w_list_x0 ); } else if( action == "TOGGLE_UNAVAILABLE_CONSTRUCTIONS" ) { update_info = true; update_cat = true; hide_unconstructable = !hide_unconstructable; select = 0; offset = 0; load_available_constructions( available, cat_available, hide_unconstructable ); } else if( action == "CONFIRM" ) { if( constructs.empty() || select >= (int) constructs.size() ){ continue;// Nothing to be done here } if( player_can_build( g->u, total_inv, constructs[select] ) ) { place_construction( constructs[select] ); uistate.last_construction = constructs[select]; exit = true; } else { popup( _( "You can't build that!" ) ); draw_grid( w_con, w_list_width + w_list_x0 ); update_info = true; } } } while( !exit ); w_list_ptr.reset(); w_con_ptr.reset(); g->refresh_all(); }
void input_context::display_help() { inp_mngr.set_timeout(-1); // Shamelessly stolen from help.cpp WINDOW *w_help = newwin(FULL_SCREEN_HEIGHT - 2, FULL_SCREEN_WIDTH - 2, 1 + (int)((TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0), 1 + (int)((TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0)); // has the user changed something? bool changed = false; // keybindings before the user changed anything. input_manager::t_action_contexts old_action_contexts(inp_mngr.action_contexts); // current status: adding/removing/showing keybindings enum { s_remove, s_add, s_add_global, s_show } status = s_show; // copy of registered_actions, but without the ANY_INPUT and COORDINATE, which should not be shown std::vector<std::string> org_registered_actions(registered_actions); std::vector<std::string>::iterator any_input = std::find(org_registered_actions.begin(), org_registered_actions.end(), ANY_INPUT); if (any_input != org_registered_actions.end()) { org_registered_actions.erase(any_input); } std::vector<std::string>::iterator coordinate = std::find(org_registered_actions.begin(), org_registered_actions.end(), COORDINATE); if (coordinate != org_registered_actions.end()) { org_registered_actions.erase(coordinate); } // colors of the keybindings static const nc_color global_key = c_ltgray; static const nc_color local_key = c_ltgreen; static const nc_color unbound_key = c_ltred; // (vertical) scroll offset size_t scroll_offset = 0; // height of the area usable for display of keybindings, excludes headers & borders const size_t display_height = FULL_SCREEN_HEIGHT - 2 - 2; // -2 for the border // width of the legend const size_t legwidth = FULL_SCREEN_WIDTH - 51 - 2; // keybindings help std::ostringstream legend; legend << "<color_" << string_from_color(unbound_key) << ">" << _("Unbound keys") << "</color>\n"; legend << "<color_" << string_from_color(local_key) << ">" << _("Keybinding active only on this screen") << "</color>\n"; legend << "<color_" << string_from_color(global_key) << ">" << _("Keybinding active globally") << "</color>\n"; legend << _("Press - to remove keybinding\nPress + to add local keybinding\nPress = to add global keybinding\n"); input_context ctxt("HELP_KEYBINDINGS"); ctxt.register_action("UP", _("Scroll up")); ctxt.register_action("DOWN", _("Scroll down")); ctxt.register_action("PAGE_DOWN"); ctxt.register_action("PAGE_UP"); ctxt.register_action("REMOVE"); ctxt.register_action("ADD_LOCAL"); ctxt.register_action("ADD_GLOBAL"); ctxt.register_action("QUIT"); ctxt.register_action("ANY_INPUT"); if (category != "HELP_KEYBINDINGS") { // avoiding inception! ctxt.register_action("HELP_KEYBINDINGS"); } std::string hotkeys = ctxt.get_available_single_char_hotkeys(display_help_hotkeys); while(true) { werase(w_help); draw_border(w_help); draw_scrollbar(w_help, scroll_offset, display_height, org_registered_actions.size() - display_height, 1); mvwprintz(w_help, 0, (FULL_SCREEN_WIDTH - utf8_width(_("Keybindings"))) / 2 - 1, c_ltred, " %s ", _("Keybindings")); fold_and_print(w_help, 1, 51, legwidth, c_white, legend.str()); for (size_t i = 0; i + scroll_offset < org_registered_actions.size() && i < display_height; i++) { const std::string &action_id = org_registered_actions[i + scroll_offset]; bool overwrite_default; const action_attributes &attributes = inp_mngr.get_action_attributes(action_id, category, &overwrite_default); char invlet; if (i < hotkeys.size()) { invlet = hotkeys[i]; } else { invlet = ' '; } if (status == s_add_global && overwrite_default) { // We're trying to add a global, but this action has a local // defined, so gray out the invlet. mvwprintz(w_help, i + 1, 2, c_dkgray, "%c ", invlet); } else if (status == s_add || status == s_add_global) { mvwprintz(w_help, i + 1, 2, c_blue, "%c ", invlet); } else if (status == s_remove) { mvwprintz(w_help, i + 1, 2, c_blue, "%c ", invlet); } else { mvwprintz(w_help, i + 1, 2, c_blue, " "); } nc_color col; if (attributes.input_events.empty()) { col = unbound_key; } else if (overwrite_default) { col = local_key; } else { col = global_key; } mvwprintz(w_help, i + 1, 4, col, "%s: ", get_action_name(action_id).c_str()); mvwprintz(w_help, i + 1, 30, col, "%s", get_desc(action_id).c_str()); } wrefresh(w_help); refresh(); // In addition to the modifiable hotkeys, we also check for hardcoded // keys, e.g. '+', '-', '=', in order to prevent the user from // entering an unrecoverable state. const std::string action = ctxt.handle_input(); const long raw_input_char = ctxt.get_raw_input().get_first_input(); if (action == "ADD_LOCAL" || raw_input_char == '+') { status = s_add; } else if (action == "ADD_GLOBAL" || raw_input_char == '=') { status = s_add_global; } else if (action == "REMOVE" || raw_input_char == '-') { status = s_remove; } else if (action == "ANY_INPUT") { const size_t hotkey_index = hotkeys.find_first_of(raw_input_char); if (status == s_show || hotkey_index == std::string::npos ) { continue; } const size_t action_index = hotkey_index + scroll_offset; if( action_index >= org_registered_actions.size() ) { continue; } const std::string &action_id = org_registered_actions[action_index]; // Check if this entry is local or global. bool is_local = false; inp_mngr.get_action_attributes(action_id, category, &is_local); const std::string name = get_action_name(action_id); if (status == s_remove && (!OPTIONS["QUERY_KEYBIND_REMOVAL"] || query_yn(_("Clear keys for %s?"), name.c_str()))) { // If it's global, reset the global actions. std::string category_to_access = category; if (!is_local) { category_to_access = default_context_id; } inp_mngr.remove_input_for_action(action_id, category_to_access); changed = true; } else if (status == s_add_global && is_local) { // Disallow adding global actions to an action that already has a local defined. popup(_("There are already local keybindings defined for this action, please remove them first.")); } else if (status == s_add || status == s_add_global) { const long newbind = popup_getkey(_("New key for %s:"), name.c_str()); const input_event new_event(newbind, CATA_INPUT_KEYBOARD); const std::string conflicts = get_conflicts(new_event); const bool has_conflicts = !conflicts.empty(); bool resolve_conflicts = false; if (has_conflicts) { resolve_conflicts = query_yn( _("This key conflicts with %s. Remove this key from the conflicting command(s), and continue?"), conflicts.c_str()); } if (!has_conflicts || resolve_conflicts) { if (resolve_conflicts) { clear_conflicting_keybindings(new_event); } // We might be adding a local or global action. std::string category_to_access = category; if (status == s_add_global) { category_to_access = default_context_id; } inp_mngr.add_input_for_action(action_id, category_to_access, new_event); changed = true; } } status = s_show; } else if (action == "DOWN") { if (scroll_offset < org_registered_actions.size() - display_height) { scroll_offset++; } } else if (action == "UP") { if (scroll_offset > 0) { scroll_offset--; } } else if (action == "PAGE_DOWN") { if( scroll_offset + display_height < org_registered_actions.size() ) { scroll_offset += std::min(display_height, org_registered_actions.size() - display_height - scroll_offset); } else if( org_registered_actions.size() > display_height ) { scroll_offset = 0; } } else if( action == "PAGE_UP" ) { if( scroll_offset >= display_height ) { scroll_offset -= display_height; } else if( scroll_offset > 0 ) { scroll_offset = 0; } else if( org_registered_actions.size() > display_height ) { scroll_offset = org_registered_actions.size() - display_height; } } else if (action == "QUIT") { if (status != s_show) { status = s_show; } else { break; } } else if (action == "HELP_KEYBINDINGS") { // update available hotkeys in case they've changed hotkeys = ctxt.get_available_single_char_hotkeys(display_help_hotkeys); } } if (changed && query_yn(_("Save changes?"))) { try { inp_mngr.save(); } catch(std::exception &err) { popup(_("saving keybindings failed: %s"), err.what()); } catch(std::string &err) { popup(_("saving keybindings failed: %s"), err.c_str()); } } else if(changed) { inp_mngr.action_contexts.swap(old_action_contexts); } werase(w_help); wrefresh(w_help); delwin(w_help); }
SICALLBACK ToonixLighter_Term( CRef& in_ctxt ) { Context ctxt(in_ctxt); CleanUpLighterUserData(ctxt); return CStatus::OK; }
int worldfactory::show_worldgen_tab_modselection(WINDOW *win, WORLDPTR world) { // Use active_mod_order of the world, // saves us from writting 'world->active_mod_order' all the time. std::vector<std::string> &active_mod_order = world->active_mod_order; { std::vector<std::string> tmp_mod_order; // clear active_mod_order and re-add all the mods, his ensures // that changes (like changing depencies) get updated tmp_mod_order.swap(active_mod_order); for(size_t i = 0; i < tmp_mod_order.size(); i++) { mman_ui->try_add(tmp_mod_order[i], active_mod_order); } } const int iOffsetX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0; const int iOffsetY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0; // lots of small windows so that each section can be drawn to independently of the others as necessary WINDOW *w_header1, *w_header2, *w_shift, *w_list, *w_active, *w_description; w_header1 = newwin(1, FULL_SCREEN_WIDTH / 2 - 5, 3 + iOffsetY, 1 + iOffsetX); w_header2 = newwin(1, FULL_SCREEN_WIDTH / 2 - 4, 3 + iOffsetY, FULL_SCREEN_WIDTH / 2 + 3 + iOffsetX); w_shift = newwin(13, 5, 3 + iOffsetY, FULL_SCREEN_WIDTH / 2 - 3 + iOffsetX); w_list = newwin(11, FULL_SCREEN_WIDTH / 2 - 4, 5 + iOffsetY, iOffsetX); w_active = newwin(11, FULL_SCREEN_WIDTH / 2 - 4, 5 + iOffsetY, FULL_SCREEN_WIDTH / 2 + 2 + iOffsetX); w_description = newwin(4, FULL_SCREEN_WIDTH - 2, 19 + iOffsetY, 1 + iOffsetX); draw_modselection_borders(win); std::vector<std::string> headers; headers.push_back(_("Mod List")); headers.push_back(_("Mod Load Order")); std::vector<WINDOW *> header_windows; header_windows.push_back(w_header1); header_windows.push_back(w_header2); int tab_output = 0; int last_active_header = 0; size_t active_header = 0; size_t useable_mod_count = mman_ui->usable_mods.size(); int startsel[2] = {0, 0}; int cursel[2] = {0, 0}; bool redraw_headers = true; bool redraw_shift = true; bool redraw_description = true; bool redraw_list = true; bool redraw_active = true; bool selection_changed = false; input_context ctxt("MODMANAGER_DIALOG"); ctxt.register_cardinal(); ctxt.register_action("HELP_KEYBINDINGS"); ctxt.register_action("QUIT"); ctxt.register_action("NEXT_TAB"); ctxt.register_action("PREV_TAB"); ctxt.register_action("CONFIRM"); ctxt.register_action("ADD_MOD"); ctxt.register_action("REMOVE_MOD"); ctxt.register_action("SAVE_DEFAULT_MODS"); while (tab_output == 0) { if (redraw_headers) { for (size_t i = 0; i < headers.size(); ++i) { werase(header_windows[i]); const int header_x = (getmaxx(header_windows[i]) - headers[i].size()) / 2; mvwprintz(header_windows[i], 0, header_x , c_cyan, "%s", headers[i].c_str()); if (active_header == i) { mvwputch(header_windows[i], 0, header_x - 3, c_red, '<'); mvwputch(header_windows[i], 0, header_x + headers[i].size() + 2, c_red, '>'); } wrefresh(header_windows[i]); } redraw_list = true; redraw_active = true; redraw_shift = true; redraw_headers = false; } if (selection_changed) { if (active_header == 0) { redraw_list = true; } if (active_header == 1) { redraw_shift = true; redraw_active = true; } selection_changed = false; redraw_description = true; } if (redraw_description) { werase(w_description); MOD_INFORMATION *selmod = NULL; if (mman_ui->usable_mods.empty()) { // Do nothing, leave selmod == NULL } else if (active_header == 0) { selmod = mman->mod_map[mman_ui->usable_mods[cursel[0]]]; } else if (!active_mod_order.empty()) { selmod = mman->mod_map[active_mod_order[cursel[1]]]; } if (selmod != NULL) { fold_and_print(w_description, 0, 1, getmaxx(w_description) - 1, c_white, mman_ui->get_information(selmod)); } redraw_description = false; wrefresh(w_description); } if (redraw_list) { werase(w_list); calcStartPos(startsel[0], cursel[0], getmaxy(w_list), useable_mod_count); if (useable_mod_count == 0) { center_print(w_list, 0, c_red, _("--NO AVAILABLE MODS--")); } else { std::stringstream list_output; for (size_t i = startsel[0], c = 0; i < useable_mod_count && c < getmaxy(w_list); ++i, ++c) { if ((ssize_t)i != cursel[0]) { list_output << std::string(3, ' '); } else { if (active_header == 0) { list_output << "<color_yellow>"; } else { list_output << "<color_blue>"; } list_output << ">></color> "; } list_output << mman->mod_map[mman_ui->usable_mods[i]]->name << "\n"; } fold_and_print(w_list, 0, 1, getmaxx(w_list) - 1, c_white, list_output.str()); } draw_scrollbar(w_list, cursel[0], getmaxy(w_list), useable_mod_count, 0, 0); wrefresh(w_list); } if (redraw_active) { werase(w_active); const int active_count = active_mod_order.size(); calcStartPos(startsel[1], cursel[1], getmaxy(w_active), active_count); if (active_count == 0) { center_print(w_active, 0, c_red, _("--NO ACTIVE MODS--")); } else { std::stringstream list_output; for (int i = startsel[1], c = 0; i < active_count && c < getmaxy(w_active); ++i, ++c) { if (i != cursel[1]) { list_output << std::string(3, ' '); } else { if (active_header == 1) { list_output << "<color_yellow>"; } else { list_output << "<color_blue>"; } list_output << ">></color> "; } list_output << mman->mod_map[active_mod_order[i]]->name << "\n"; } fold_and_print(w_active, 0, 1, getmaxx(w_active) - 1, c_white, list_output.str()); } draw_scrollbar(w_active, cursel[1], getmaxy(w_active), active_count, 0, 0); wrefresh(w_active); } if (redraw_shift) { werase(w_shift); if (active_header == 1) { std::stringstream shift_display; // get shift information for whatever is visible in the active list for (size_t i = startsel[1], c = 0; i < active_mod_order.size() && c < getmaxy(w_active); ++i, ++c) { if (mman_ui->can_shift_up(i, active_mod_order)) { shift_display << "<color_blue>+</color> "; } else { shift_display << "<color_dkgray>+</color> "; } if (mman_ui->can_shift_down(i, active_mod_order)) { shift_display << "<color_blue>-</color>"; } else { shift_display << "<color_dkgray>-</color>"; } shift_display << "\n"; } fold_and_print(w_shift, 2, 1, getmaxx(w_shift), c_white, shift_display.str()); } redraw_shift = false; wrefresh(w_shift); } refresh(); last_active_header = active_header; const int next_header = (active_header == 1) ? 0 : 1; const int prev_header = (active_header == 0) ? 1 : 0; int selection = (active_header == 0) ? cursel[0] : cursel[1]; int last_selection = selection; unsigned int next_selection = selection + 1; int prev_selection = selection - 1; if (active_header == 0) { next_selection = (next_selection >= useable_mod_count) ? 0 : next_selection; prev_selection = (prev_selection < 0) ? useable_mod_count - 1 : prev_selection; } else { next_selection = (next_selection >= active_mod_order.size()) ? 0 : next_selection; prev_selection = (prev_selection < 0) ? active_mod_order.size() - 1 : prev_selection; } const std::string action = ctxt.handle_input(); if (action == "DOWN") { selection = next_selection; } else if (action == "UP") { selection = prev_selection; } else if (action == "RIGHT") { active_header = next_header; } else if (action == "LEFT") { active_header = prev_header; } else if (action == "CONFIRM") { if (active_header == 0 && !mman_ui->usable_mods.empty()) { // try-add mman_ui->try_add(mman_ui->usable_mods[cursel[0]], active_mod_order); redraw_active = true; redraw_shift = true; } else if (active_header == 1 && !active_mod_order.empty()) { // try-rem mman_ui->try_rem(cursel[1], active_mod_order); redraw_active = true; redraw_shift = true; if (active_mod_order.empty()) { // switch back to other list, we can't change // anything in the empty active mods list. active_header = 0; } } } else if (action == "ADD_MOD") { if (active_header == 1 && active_mod_order.size() > 1) { mman_ui->try_shift('+', cursel[1], active_mod_order); redraw_active = true; redraw_shift = true; } } else if (action == "REMOVE_MOD") { if (active_header == 1 && active_mod_order.size() > 1) { mman_ui->try_shift('-', cursel[1], active_mod_order); redraw_active = true; redraw_shift = true; } } else if (action == "NEXT_TAB") { tab_output = 1; } else if (action == "PREV_TAB") { tab_output = -1; } else if (action == "SAVE_DEFAULT_MODS") { if(mman->set_default_mods(active_mod_order)) { popup(_("Saved list of active mods as default")); draw_modselection_borders(win); redraw_headers = true; } } else if (action == "QUIT") { tab_output = -999; } // RESOLVE INPUTS if (last_active_header != (ssize_t)active_header) { redraw_headers = true; redraw_shift = true; redraw_description = true; } if (last_selection != selection) { if (active_header == 0) { redraw_list = true; cursel[0] = selection; } else { redraw_active = true; redraw_shift = true; cursel[1] = selection; } redraw_description = true; } if (active_mod_order.empty()) { redraw_active = true; cursel[1] = 0; } if (active_header == 1) { if (active_mod_order.empty()) { cursel[1] = 0; } else { if (cursel[1] < 0) { cursel[1] = 0; } else if (cursel[1] >= (ssize_t)active_mod_order.size()) { cursel[1] = active_mod_order.size() - 1; } } } // end RESOLVE INPUTS } werase(w_header1); werase(w_header2); werase(w_shift); werase(w_list); werase(w_active); werase(w_description); delwin(w_header1); delwin(w_header2); delwin(w_shift); delwin(w_list); delwin(w_active); delwin(w_description); return tab_output; }
void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) { auto global_rules_old = global_rules; auto character_rules_old = character_rules; const int header_height = 4; const int content_height = FULL_SCREEN_HEIGHT - 2 - header_height; const int offset_x = ( TERMX > FULL_SCREEN_WIDTH ) ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; const int offset_y = ( TERMY > FULL_SCREEN_HEIGHT ) ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; enum Columns : int { COLUMN_RULE, COLUMN_ATTITUDE, COLUMN_PROXIMITY, COLUMN_WHITE_BLACKLIST, }; std::map<int, int> column_pos; column_pos[COLUMN_RULE] = 4; column_pos[COLUMN_ATTITUDE] = 48; column_pos[COLUMN_PROXIMITY] = 59; column_pos[COLUMN_WHITE_BLACKLIST] = 66; const int num_columns = column_pos.size(); catacurses::window w_help = catacurses::newwin( ( FULL_SCREEN_HEIGHT / 2 ) - 2, FULL_SCREEN_WIDTH * 3 / 4, 7 + offset_y + ( FULL_SCREEN_HEIGHT / 2 ) / 2, offset_x + 19 / 2 ); catacurses::window w_border = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, offset_y, offset_x ); catacurses::window w_header = catacurses::newwin( header_height, FULL_SCREEN_WIDTH - 2, 1 + offset_y, 1 + offset_x ); catacurses::window w = catacurses::newwin( content_height, FULL_SCREEN_WIDTH - 2, header_height + 1 + offset_y, 1 + offset_x ); draw_border( w_border, BORDER_COLOR, custom_name_in ); mvwputch( w_border, 3, 0, c_light_gray, LINE_XXXO ); // |- mvwputch( w_border, 3, 79, c_light_gray, LINE_XOXX ); // -| for( auto &column : column_pos ) { mvwputch( w_border, FULL_SCREEN_HEIGHT - 1, column.second + 1, c_light_gray, LINE_XXOX ); // _|_ } wrefresh( w_border ); static const std::vector<std::string> hotkeys = {{ _( "<A>dd" ), _( "<R>emove" ), _( "<C>opy" ), _( "<M>ove" ), _( "<E>nable" ), _( "<D>isable" ), _( "<T>est" ) } }; int tmpx = 0; for( auto &hotkey : hotkeys ) { tmpx += shortcut_print( w_header, 0, tmpx, c_white, c_light_green, hotkey ) + 2; } tmpx = 0; tmpx += shortcut_print( w_header, 1, tmpx, c_white, c_light_green, _( "<+-> Move up/down" ) ) + 2; tmpx += shortcut_print( w_header, 1, tmpx, c_white, c_light_green, _( "<Enter>-Edit" ) ) + 2; shortcut_print( w_header, 1, tmpx, c_white, c_light_green, _( "<Tab>-Switch Page" ) ); for( int i = 0; i < 78; i++ ) { mvwputch( w_header, 2, i, c_light_gray, LINE_OXOX ); // Draw line under header } for( auto &pos : column_pos ) { mvwputch( w_header, 2, pos.second, c_light_gray, LINE_OXXX ); mvwputch( w_header, 3, pos.second, c_light_gray, LINE_XOXO ); } mvwprintz( w_header, 3, 1, c_white, "#" ); mvwprintz( w_header, 3, column_pos[COLUMN_RULE] + 4, c_white, _( "Rules" ) ); mvwprintz( w_header, 3, column_pos[COLUMN_ATTITUDE] + 2, c_white, _( "Attitude" ) ); mvwprintz( w_header, 3, column_pos[COLUMN_PROXIMITY] + 2, c_white, _( "Dist" ) ); mvwprintz( w_header, 3, column_pos[COLUMN_WHITE_BLACKLIST] + 2, c_white, _( "B/W" ) ); wrefresh( w_header ); int tab = GLOBAL_TAB; int line = 0; int column = 0; int start_pos = 0; bool changes_made = false; input_context ctxt( "SAFEMODE" ); ctxt.register_cardinal(); ctxt.register_action( "CONFIRM" ); ctxt.register_action( "QUIT" ); ctxt.register_action( "NEXT_TAB" ); ctxt.register_action( "PREV_TAB" ); ctxt.register_action( "ADD_DEFAULT_RULESET" ); ctxt.register_action( "ADD_RULE" ); ctxt.register_action( "REMOVE_RULE" ); ctxt.register_action( "COPY_RULE" ); ctxt.register_action( "ENABLE_RULE" ); ctxt.register_action( "DISABLE_RULE" ); ctxt.register_action( "MOVE_RULE_UP" ); ctxt.register_action( "MOVE_RULE_DOWN" ); ctxt.register_action( "TEST_RULE" ); ctxt.register_action( "HELP_KEYBINDINGS" ); if( is_safemode_in ) { ctxt.register_action( "SWITCH_SAFEMODE_OPTION" ); ctxt.register_action( "SWAP_RULE_GLOBAL_CHAR" ); } while( true ) { int locx = 17; locx += shortcut_print( w_header, 2, locx, c_white, ( tab == GLOBAL_TAB ) ? hilite( c_white ) : c_white, _( "[<Global>]" ) ) + 1; shortcut_print( w_header, 2, locx, c_white, ( tab == CHARACTER_TAB ) ? hilite( c_white ) : c_white, _( "[<Character>]" ) ); locx = 55; mvwprintz( w_header, 0, locx, c_white, _( "Safe Mode enabled:" ) ); locx += shortcut_print( w_header, 1, locx, ( ( get_option<bool>( "SAFEMODE" ) ) ? c_light_green : c_light_red ), c_white, ( ( get_option<bool>( "SAFEMODE" ) ) ? _( "True" ) : _( "False" ) ) ); locx += shortcut_print( w_header, 1, locx, c_white, c_light_green, " " ); locx += shortcut_print( w_header, 1, locx, c_white, c_light_green, _( "<S>witch" ) ); shortcut_print( w_header, 1, locx, c_white, c_light_green, " " ); wrefresh( w_header ); // Clear the lines for( int i = 0; i < content_height; i++ ) { for( int j = 0; j < 79; j++ ) { mvwputch( w, i, j, c_black, ' ' ); } for( auto &pos : column_pos ) { mvwputch( w, i, pos.second, c_light_gray, LINE_XOXO ); } } auto ¤t_tab = ( tab == GLOBAL_TAB ) ? global_rules : character_rules; if( tab == CHARACTER_TAB && g->u.name.empty() ) { character_rules.clear(); mvwprintz( w, 8, 15, c_white, _( "Please load a character first to use this page!" ) ); } else if( empty() ) { mvwprintz( w, 8, 15, c_white, _( "Safe Mode manager currently inactive." ) ); mvwprintz( w, 9, 15, c_white, _( "Default rules are used. Add a rule to activate." ) ); mvwprintz( w, 10, 15, c_white, _( "Press ~ to add a default ruleset to get started." ) ); } draw_scrollbar( w_border, line, content_height, current_tab.size(), 5 ); wrefresh( w_border ); calcStartPos( start_pos, line, content_height, current_tab.size() ); // display safe mode for( int i = start_pos; i < static_cast<int>( current_tab.size() ); i++ ) { if( i >= start_pos && i < start_pos + std::min( content_height, static_cast<int>( current_tab.size() ) ) ) { auto rule = current_tab[i]; nc_color line_color = ( rule.active ) ? c_white : c_light_gray; mvwprintz( w, i - start_pos, 1, line_color, "%d", i + 1 ); mvwprintz( w, i - start_pos, 5, c_yellow, ( line == i ) ? ">> " : " " ); auto draw_column = [&]( Columns column_in, const std::string & text_in ) { mvwprintz( w, i - start_pos, column_pos[column_in] + 2, ( line == i && column == column_in ) ? hilite( line_color ) : line_color, text_in ); }; draw_column( COLUMN_RULE, ( rule.rule.empty() ) ? _( "<empty rule>" ) : rule.rule ); draw_column( COLUMN_ATTITUDE, Creature::get_attitude_ui_data( rule.attitude ).first ); draw_column( COLUMN_PROXIMITY, ( !rule.whitelist ) ? to_string( rule.proximity ) : "---" ); draw_column( COLUMN_WHITE_BLACKLIST, ( rule.whitelist ) ? _( "Whitelist" ) : _( "Blacklist" ) ); } } wrefresh( w ); const std::string action = ctxt.handle_input(); if( action == "NEXT_TAB" ) { tab++; if( tab >= MAX_TAB ) { tab = 0; line = 0; } } else if( action == "PREV_TAB" ) { tab--; if( tab < 0 ) { tab = MAX_TAB - 1; line = 0; } } else if( action == "QUIT" ) { break; } else if( tab == CHARACTER_TAB && g->u.name.empty() ) { //Only allow loaded games to use the char sheet } else if( action == "DOWN" ) { line++; if( line >= static_cast<int>( current_tab.size() ) ) { line = 0; } } else if( action == "UP" ) { line--; if( line < 0 ) { line = current_tab.size() - 1; } } else if( action == "ADD_DEFAULT_RULESET" ) { changes_made = true; current_tab.push_back( rules_class( "*", true, false, Creature::A_HOSTILE, 0 ) ); line = current_tab.size() - 1; } else if( action == "ADD_RULE" ) { changes_made = true; current_tab.push_back( rules_class( "", true, false, Creature::A_HOSTILE, get_option<int>( "SAFEMODEPROXIMITY" ) ) ); line = current_tab.size() - 1; } else if( action == "REMOVE_RULE" && !current_tab.empty() ) { changes_made = true; current_tab.erase( current_tab.begin() + line ); if( line > static_cast<int>( current_tab.size() ) - 1 ) { line--; } if( line < 0 ) { line = 0; } } else if( action == "COPY_RULE" && !current_tab.empty() ) { changes_made = true; current_tab.push_back( current_tab[line] ); line = current_tab.size() - 1; } else if( action == "SWAP_RULE_GLOBAL_CHAR" && !current_tab.empty() ) { if( ( tab == GLOBAL_TAB && !g->u.name.empty() ) || tab == CHARACTER_TAB ) { changes_made = true; //copy over auto &temp_rules_from = ( tab == GLOBAL_TAB ) ? global_rules : character_rules; auto &temp_rules_to = ( tab == GLOBAL_TAB ) ? character_rules : global_rules; temp_rules_to.push_back( temp_rules_from[line] ); //remove old temp_rules_from.erase( temp_rules_from.begin() + line ); line = temp_rules_from.size() - 1; tab = ( tab == GLOBAL_TAB ) ? CHARACTER_TAB : GLOBAL_TAB; } } else if( action == "CONFIRM" && !current_tab.empty() ) { changes_made = true; if( column == COLUMN_RULE ) { fold_and_print( w_help, 1, 1, 999, c_white, _( "* is used as a Wildcard. A few Examples:\n" "\n" "human matches every NPC\n" "zombie matches the monster name exactly\n" "acidic zo* matches monsters beginning with 'acidic zo'\n" "*mbie matches monsters ending with 'mbie'\n" "*cid*zo*ie multiple * are allowed\n" "AcI*zO*iE case insensitive search" ) ); draw_border( w_help ); wrefresh( w_help ); current_tab[line].rule = wildcard_trim_rule( string_input_popup() .title( _( "Safe Mode Rule:" ) ) .width( 30 ) .text( current_tab[line].rule ) .query_string() ); } else if( column == COLUMN_WHITE_BLACKLIST ) { current_tab[line].whitelist = !current_tab[line].whitelist; } else if( column == COLUMN_ATTITUDE ) { auto &attitude = current_tab[line].attitude; switch( attitude ) { case Creature::A_HOSTILE: attitude = Creature::A_NEUTRAL; break; case Creature::A_NEUTRAL: attitude = Creature::A_FRIENDLY; break; case Creature::A_FRIENDLY: attitude = Creature::A_ANY; break; case Creature::A_ANY: attitude = Creature::A_HOSTILE; } } else if( column == COLUMN_PROXIMITY && !current_tab[line].whitelist ) { const auto text = string_input_popup() .title( _( "Proximity Distance (0=max view distance)" ) ) .width( 4 ) .text( to_string( current_tab[line].proximity ) ) .description( _( "Option: " ) + to_string( get_option<int>( "SAFEMODEPROXIMITY" ) ) + " " + get_options().get_option( "SAFEMODEPROXIMITY" ).getDefaultText() ) .max_length( 3 ) .only_digits( true ) .query_string(); if( text.empty() ) { current_tab[line].proximity = get_option<int>( "SAFEMODEPROXIMITY" ); } else { //Let the options class handle the validity of the new value auto temp_option = get_options().get_option( "SAFEMODEPROXIMITY" ); temp_option.setValue( text ); current_tab[line].proximity = atoi( temp_option.getValue().c_str() ); } } } else if( action == "ENABLE_RULE" && !current_tab.empty() ) { changes_made = true; current_tab[line].active = true; } else if( action == "DISABLE_RULE" && !current_tab.empty() ) { changes_made = true; current_tab[line].active = false; } else if( action == "LEFT" ) { column--; if( column < 0 ) { column = num_columns - 1; } } else if( action == "RIGHT" ) { column++; if( column >= num_columns ) { column = 0; } } else if( action == "MOVE_RULE_UP" && !current_tab.empty() ) { changes_made = true; if( line < static_cast<int>( current_tab.size() ) - 1 ) { std::swap( current_tab[line], current_tab[line + 1] ); line++; column = 0; } } else if( action == "MOVE_RULE_DOWN" && !current_tab.empty() ) { changes_made = true; if( line > 0 ) { std::swap( current_tab[line], current_tab[line - 1] ); line--; column = 0; } } else if( action == "TEST_RULE" && !current_tab.empty() ) { test_pattern( tab, line ); } else if( action == "SWITCH_SAFEMODE_OPTION" ) { get_options().get_option( "SAFEMODE" ).setNext(); get_options().save(); } } if( !changes_made ) { return; } if( query_yn( _( "Save changes?" ) ) ) { if( is_safemode_in ) { save_global(); if( !g->u.name.empty() ) { save_character(); } } else { create_rules(); } } else { global_rules = global_rules_old; character_rules = character_rules_old; } }
// Update ============================================================================= CStatus gStretchOp2Multi_Update( CRef& in_ctxt ) { OperatorContext ctxt( in_ctxt ); // User Datas ------------------------------------ CValue::siPtrType pUserData = ctxt.GetUserData(); OpUserData* pOpState = (OpUserData*)pUserData; if ( pOpState == NULL || pOpState->index >= 2) { // First time called pOpState = new OpUserData(); ctxt.PutUserData( (CValue::siPtrType)pOpState ); // Inputs --------------------------------------- KinematicState kRoot(ctxt.GetInputValue(0)); KinematicState kCtrl(ctxt.GetInputValue(1)); CTransformation tRoot(kRoot.GetTransform()); CTransformation tCtrl(kCtrl.GetTransform()); CVector3 vRoot = tRoot.GetTranslation(); CVector3 vCtrl = tCtrl.GetTranslation(); CMatrix4 mRoot = tRoot.GetMatrix4(); CMatrix4 mRootNeg; mRootNeg.Invert(mRoot); double dRestLength = ctxt.GetParameterValue(L"restlength"); double dScale = ctxt.GetParameterValue(L"scale"); double dSoftness = ctxt.GetParameterValue(L"soft"); double dMaxStretch = ctxt.GetParameterValue(L"maxstretch"); // Distance with MaxStretch --------------------- dRestLength = dRestLength * dScale - .00001; CVector3 vDistance; vDistance.MulByMatrix4(vCtrl, mRootNeg); double dDistance = vDistance.GetLength(); double dDistance2 = dDistance; if (dDistance > (dRestLength * dMaxStretch)) { vDistance.NormalizeInPlace(); vDistance.ScaleInPlace(dRestLength * dMaxStretch); dDistance = dRestLength * dMaxStretch; } Application app; app.LogMessage(L"dist : "+CString(dDistance)); app.LogMessage(L"dist2 : "+CString(dDistance2)); // Adapt Softness value to chain length -------- dSoftness = dSoftness * dRestLength *.1; // Stretch and softness ------------------------ /// We use the real distance from root to controler to calculate the softness /// This way we have softness working even when there is no stretch double dStretch = dDistance/dRestLength; if (dStretch < 1) dStretch = 1; double da = dRestLength - dSoftness; if (dSoftness > 0 && dDistance2 > da) { double newlen = dSoftness*(1.0 - exp(-(dDistance2 -da)/dSoftness)) + da; dStretch = dDistance / newlen; } double dScaleX = dStretch * dScale; app.LogMessage(L"scalex : "+CString(dScaleX)); // Effector Position ---------------------------- CTransformation t; vDistance.MulByMatrix4(vDistance, mRoot); t.SetTranslation(vDistance); pOpState->index = 0; pOpState->t = t; pOpState->dLength0 = dScaleX; } // Outputs ------------------------------------- CRef outputPortRef=ctxt.GetOutputPort(); OutputPort OutPort(outputPortRef); // Effector Transform if (OutPort.GetIndex() == 2) { KinematicState kOut = ctxt.GetOutputTarget(); kOut.PutTransform(pOpState->t); } // Bone 0 Length else if (OutPort.GetIndex() == 3) { OutPort.PutValue(pOpState->dLength0); } pOpState->index += 1; return CStatus::OK; }
// Update ================================================================================= CStatus gStretchOp2_Update( CRef& in_ctxt ) { OperatorContext ctxt( in_ctxt ); // User Datas ------------------------------------ CValue::siPtrType pUserData = ctxt.GetUserData(); OpUserData* pOpState = (OpUserData*)pUserData; if ( pOpState == NULL || pOpState->index >= 4) { // First time called pOpState = new OpUserData(); ctxt.PutUserData( (CValue::siPtrType)pOpState ); // Inputs --------------------------------------- KinematicState kRoot(ctxt.GetInputValue(0)); KinematicState kCtrl(ctxt.GetInputValue(1)); CTransformation tRoot(kRoot.GetTransform()); CTransformation tCtrl(kCtrl.GetTransform()); CVector3 vRoot = tRoot.GetTranslation(); CVector3 vCtrl = tCtrl.GetTranslation(); CMatrix4 mRoot = tRoot.GetMatrix4(); CMatrix4 mRootNeg; mRootNeg.Invert(mRoot); double dRest0 = ctxt.GetParameterValue(L"rest0"); double dRest1 = ctxt.GetParameterValue(L"rest1"); double dPrefRot = ctxt.GetParameterValue(L"prefrot"); double dScale0 = ctxt.GetParameterValue(L"scale0"); double dScale1 = ctxt.GetParameterValue(L"scale1"); double dSoftness = ctxt.GetParameterValue(L"soft"); double dMaxStretch = ctxt.GetParameterValue(L"maxstretch"); double dSlide = ctxt.GetParameterValue(L"slide"); double dReverse = ctxt.GetParameterValue(L"reverse"); // Distance with MaxStretch --------------------- double dRestLength = dRest0 * dScale0 + dRest1 * dScale1; CVector3 vDistance; vDistance.MulByMatrix4(vCtrl, mRootNeg); double dDistance = vDistance.GetLength(); double dDistance2 = dDistance; if (dDistance > (dRestLength * dMaxStretch)) { vDistance.NormalizeInPlace(); vDistance.ScaleInPlace(dRestLength * dMaxStretch); dDistance = dRestLength * dMaxStretch; } // Adapt Softness value to chain length -------- dSoftness *= dRestLength*.1; // Stretch and softness ------------------------ /// We use the real distance from root to controler to calculate the softness /// This way we have softness working even when there is no stretch double dStretch = dDistance/dRestLength; if (dStretch < 1) dStretch = 1; double da = dRestLength - dSoftness; if (dSoftness > 0 && dDistance2 > da) { double newlen = dSoftness*(1.0 - exp(-(dDistance2 -da)/dSoftness)) + da; dStretch = dDistance / newlen; } double dLength0 = dRest0 * dStretch * dScale0; double dLength1 = dRest1 * dStretch * dScale1; // Reverse ------------------------------------- double d = dDistance/(dLength0 + dLength1); double dScale; if (dReverse < 0.5) dScale = 1-(dReverse*2 * (1-d)); else dScale = 1-((1-dReverse)*2 * (1-d)); dLength0 *= dScale; dLength1 *= dScale; dPrefRot = -(dReverse-0.5) * 2 * dPrefRot; // Slide --------------------------------------- double dAdd; if (dSlide < .5) dAdd = (dLength0 * (dSlide*2)) - (dLength0); else dAdd = (dLength1 * (dSlide*2)) - (dLength1); dLength0 += dAdd; dLength1 -= dAdd; // Effector Position ---------------------------- CTransformation t; vDistance.MulByMatrix4(vDistance, mRoot); t.SetTranslation(vDistance); pOpState->index = 0; pOpState->t = t; pOpState->dLength0 = dLength0; pOpState->dLength1 = dLength1; pOpState->dPrefRot = dPrefRot; } // Outputs ------------------------------------- CRef outputPortRef=ctxt.GetOutputPort(); OutputPort OutPort(outputPortRef); // Effector Transform if (OutPort.GetIndex() == 2) { KinematicState kOut = ctxt.GetOutputTarget(); kOut.PutTransform(pOpState->t); } // Bone 0 Length else if (OutPort.GetIndex() == 3) { OutPort.PutValue(pOpState->dLength0); } // Bone 1 Length else if (OutPort.GetIndex() == 4) { OutPort.PutValue(pOpState->dLength1); } // Bone 1 PrefRot else if (OutPort.GetIndex() == 5) { OutPort.PutValue(pOpState->dPrefRot); } pOpState->index += 1; return CStatus::OK; }
// Pick up items at (pos). void Pickup::pick_up( const tripoint &p, int min ) { int cargo_part = -1; const optional_vpart_position vp = g->m.veh_at( p ); vehicle *const veh = veh_pointer_or_null( vp ); bool from_vehicle = false; if( min != -1 ) { veh_interact_results get_items_from = ITEMS_FROM_GROUND; if( veh != nullptr ) { get_items_from = veh->interact_with( p, vp->part_index() ); } switch( get_items_from ) { case DONE: return; case ITEMS_FROM_CARGO: { const cata::optional<vpart_reference> carg = vp.part_with_feature( "CARGO", false ); cargo_part = carg ? carg->part_index() : -1; from_vehicle = cargo_part >= 0; break; } case ITEMS_FROM_GROUND: // Nothing to change, default is to pick from ground anyway. if( g->m.has_flag( "SEALED", p ) ) { return; } break; } } if( !from_vehicle ) { bool isEmpty = ( g->m.i_at( p ).empty() ); // Hide the pickup window if this is a toilet and there's nothing here // but water. if( ( !isEmpty ) && g->m.furn( p ) == f_toilet ) { isEmpty = true; for( const item &maybe_water : g->m.i_at( p ) ) { if( maybe_water.typeId() != "water" ) { isEmpty = false; break; } } } if( isEmpty && ( min != -1 || !get_option<bool>( "AUTO_PICKUP_ADJACENT" ) ) ) { return; } } // which items are we grabbing? std::vector<item> here; if( from_vehicle ) { auto vehitems = veh->get_items( cargo_part ); here.resize( vehitems.size() ); std::copy( vehitems.begin(), vehitems.end(), here.begin() ); } else { auto mapitems = g->m.i_at( p ); here.resize( mapitems.size() ); std::copy( mapitems.begin(), mapitems.end(), here.begin() ); } if( min == -1 ) { // Recursively pick up adjacent items if that option is on. if( get_option<bool>( "AUTO_PICKUP_ADJACENT" ) && g->u.pos() == p ) { //Autopickup adjacent direction adjacentDir[8] = {NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, NORTHWEST}; for( auto &elem : adjacentDir ) { tripoint apos = tripoint( direction_XY( elem ), 0 ); apos += p; pick_up( apos, min ); } } // Bail out if this square cannot be auto-picked-up if( g->check_zone( zone_type_id( "NO_AUTO_PICKUP" ), p ) ) { return; } else if( g->m.has_flag( "SEALED", p ) ) { return; } } // Not many items, just grab them if( static_cast<int>( here.size() ) <= min && min != -1 ) { g->u.assign_activity( activity_id( "ACT_PICKUP" ) ); g->u.activity.placement = p - g->u.pos(); g->u.activity.values.push_back( from_vehicle ); // Only one item means index is 0. g->u.activity.values.push_back( 0 ); // auto-pickup means pick up all. g->u.activity.values.push_back( 0 ); return; } std::vector<std::list<item_idx>> stacked_here; for( size_t i = 0; i < here.size(); i++ ) { item &it = here[i]; bool found_stack = false; for( auto &stack : stacked_here ) { if( stack.begin()->_item.stacks_with( it ) ) { item_idx el = { it, i }; stack.push_back( el ); found_stack = true; break; } } if( !found_stack ) { std::list<item_idx> newstack; newstack.push_back( { it, i } ); stacked_here.push_back( newstack ); } } std::reverse( stacked_here.begin(), stacked_here.end() ); if( min != -1 ) { // don't bother if we're just autopickuping g->temp_exit_fullscreen(); } // Otherwise, we have Autopickup, 2 or more items and should list them, etc. int maxmaxitems = TERMY; int itemsH = std::min( 25, TERMY / 2 ); int pickupBorderRows = 3; // The pickup list may consume the entire terminal, minus space needed for its // header/footer and the item info window. int minleftover = itemsH + pickupBorderRows; if( maxmaxitems > TERMY - minleftover ) { maxmaxitems = TERMY - minleftover; } const int minmaxitems = 9; std::vector<pickup_count> getitem( stacked_here.size() ); int maxitems = stacked_here.size(); maxitems = ( maxitems < minmaxitems ? minmaxitems : ( maxitems > maxmaxitems ? maxmaxitems : maxitems ) ); int itemcount = 0; if( min == -1 ) { //Auto Pickup, select matching items if( !select_autopickup_items( stacked_here, getitem ) ) { // If we didn't find anything, bail out now. return; } } else { int pickupH = maxitems + pickupBorderRows; int pickupW = 44; int itemsW = pickupW; catacurses::window w_pickup = catacurses::newwin( pickupH, pickupW, 0, 0 ); catacurses::window w_item_info = catacurses::newwin( TERMY - pickupH, pickupW, pickupH, 0 ); std::string action; long raw_input_char = ' '; input_context ctxt( "PICKUP" ); ctxt.register_action( "UP" ); ctxt.register_action( "DOWN" ); ctxt.register_action( "RIGHT" ); ctxt.register_action( "LEFT" ); ctxt.register_action( "NEXT_TAB", _( "Next page" ) ); ctxt.register_action( "PREV_TAB", _( "Previous page" ) ); ctxt.register_action( "SCROLL_UP" ); ctxt.register_action( "SCROLL_DOWN" ); ctxt.register_action( "CONFIRM" ); ctxt.register_action( "SELECT_ALL" ); ctxt.register_action( "QUIT", _( "Cancel" ) ); ctxt.register_action( "ANY_INPUT" ); ctxt.register_action( "HELP_KEYBINDINGS" ); ctxt.register_action( "FILTER" ); #if defined(__ANDROID__) ctxt.allow_text_entry = true; // allow user to specify pickup amount #endif int start = 0; int cur_it = 0; bool update = true; mvwprintw( w_pickup, 0, 0, _( "PICK" ) ); int selected = 0; int iScrollPos = 0; std::string filter; std::string new_filter; std::vector<int> matches;//Indexes of items that match the filter bool filter_changed = true; if( g->was_fullscreen ) { g->draw_ter(); } // Now print the two lists; those on the ground and about to be added to inv // Continue until we hit return or space do { const std::string pickup_chars = ctxt.get_available_single_char_hotkeys( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:;" ); int idx = -1; for( int i = 1; i < pickupH; i++ ) { mvwprintw( w_pickup, i, 0, " " ); } if( action == "ANY_INPUT" && raw_input_char >= '0' && raw_input_char <= '9' ) { int raw_input_char_value = static_cast<char>( raw_input_char ) - '0'; itemcount *= 10; itemcount += raw_input_char_value; if( itemcount < 0 ) { itemcount = 0; } } else if( action == "SCROLL_UP" ) { iScrollPos--; } else if( action == "SCROLL_DOWN" ) { iScrollPos++; } else if( action == "PREV_TAB" ) { if( start > 0 ) { start -= maxitems; } else { start = static_cast<int>( ( matches.size() - 1 ) / maxitems ) * maxitems; } selected = start; mvwprintw( w_pickup, maxitems + 2, 0, " " ); } else if( action == "NEXT_TAB" ) { if( start + maxitems < static_cast<int>( matches.size() ) ) { start += maxitems; } else { start = 0; } iScrollPos = 0; selected = start; mvwprintw( w_pickup, maxitems + 2, pickupH, " " ); } else if( action == "UP" ) { selected--; iScrollPos = 0; if( selected < 0 ) { selected = matches.size() - 1; start = static_cast<int>( matches.size() / maxitems ) * maxitems; if( start >= static_cast<int>( matches.size() ) ) { start -= maxitems; } } else if( selected < start ) { start -= maxitems; } } else if( action == "DOWN" ) { selected++; iScrollPos = 0; if( selected >= static_cast<int>( matches.size() ) ) { selected = 0; start = 0; } else if( selected >= start + maxitems ) { start += maxitems; } } else if( selected >= 0 && selected < static_cast<int>( matches.size() ) && ( ( action == "RIGHT" && !getitem[matches[selected]].pick ) || ( action == "LEFT" && getitem[matches[selected]].pick ) ) ) { idx = selected; } else if( action == "FILTER" ) { new_filter = filter; string_input_popup popup; popup .title( _( "Set filter" ) ) .width( 30 ) .edit( new_filter ); if( !popup.canceled() ) { filter_changed = true; } else { wrefresh( g->w_terrain ); g->draw_panels(); } } else if( action == "ANY_INPUT" && raw_input_char == '`' ) { std::string ext = string_input_popup() .title( _( "Enter 2 letters (case sensitive):" ) ) .width( 3 ) .max_length( 2 ) .query_string(); if( ext.size() == 2 ) { int p1 = pickup_chars.find( ext.at( 0 ) ); int p2 = pickup_chars.find( ext.at( 1 ) ); if( p1 != -1 && p2 != -1 ) { idx = pickup_chars.size() + ( p1 * pickup_chars.size() ) + p2; } } } else if( action == "ANY_INPUT" ) { idx = ( raw_input_char <= 127 ) ? pickup_chars.find( raw_input_char ) : -1; iScrollPos = 0; } if( idx >= 0 && idx < static_cast<int>( matches.size() ) ) { size_t true_idx = matches[idx]; if( itemcount != 0 || getitem[true_idx].count == 0 ) { item &temp = stacked_here[true_idx].begin()->_item; int amount_available = temp.count_by_charges() ? temp.charges : stacked_here[true_idx].size(); if( itemcount >= amount_available ) { itemcount = 0; } getitem[true_idx].count = itemcount; itemcount = 0; } // Note: this might not change the value of getitem[idx] at all! getitem[true_idx].pick = ( action == "RIGHT" ? true : ( action == "LEFT" ? false : !getitem[true_idx].pick ) ); if( action != "RIGHT" && action != "LEFT" ) { selected = idx; start = static_cast<int>( idx / maxitems ) * maxitems; } if( !getitem[true_idx].pick ) { getitem[true_idx].count = 0; } update = true; } if( filter_changed ) { matches.clear(); while( matches.empty() ) { auto filter_func = item_filter_from_string( new_filter ); for( size_t index = 0; index < stacked_here.size(); index++ ) { if( filter_func( stacked_here[index].begin()->_item ) ) { matches.push_back( index ); } } if( matches.empty() ) { popup( _( "Your filter returned no results" ) ); wrefresh( g->w_terrain ); g->draw_panels(); // The filter must have results, or simply be emptied or canceled, // as this screen can't be reached without there being // items available string_input_popup popup; popup .title( _( "Set filter" ) ) .width( 30 ) .edit( new_filter ); if( popup.canceled() ) { new_filter = filter; filter_changed = false; } } } if( filter_changed ) { filter = new_filter; filter_changed = false; selected = 0; start = 0; iScrollPos = 0; } wrefresh( g->w_terrain ); g->draw_panels(); } item &selected_item = stacked_here[matches[selected]].begin()->_item; werase( w_item_info ); if( selected >= 0 && selected <= static_cast<int>( stacked_here.size() ) - 1 ) { std::vector<iteminfo> vThisItem; std::vector<iteminfo> vDummy; selected_item.info( true, vThisItem ); draw_item_info( w_item_info, "", "", vThisItem, vDummy, iScrollPos, true, true ); } draw_custom_border( w_item_info, 0 ); mvwprintw( w_item_info, 0, 2, "< " ); trim_and_print( w_item_info, 0, 4, itemsW - 8, c_white, "%s >", selected_item.display_name() ); wrefresh( w_item_info ); if( action == "SELECT_ALL" ) { int count = 0; for( auto i : matches ) { if( getitem[i].pick ) { count++; } getitem[i].pick = true; } if( count == static_cast<int>( stacked_here.size() ) ) { for( size_t i = 0; i < stacked_here.size(); i++ ) { getitem[i].pick = false; } } update = true; } for( cur_it = start; cur_it < start + maxitems; cur_it++ ) { mvwprintw( w_pickup, 1 + ( cur_it % maxitems ), 0, " " ); if( cur_it < static_cast<int>( matches.size() ) ) { int true_it = matches[cur_it]; item &this_item = stacked_here[ true_it ].begin()->_item; nc_color icolor = this_item.color_in_inventory(); if( cur_it == selected ) { icolor = hilite( c_white ); } if( cur_it < static_cast<int>( pickup_chars.size() ) ) { mvwputch( w_pickup, 1 + ( cur_it % maxitems ), 0, icolor, static_cast<char>( pickup_chars[cur_it] ) ); } else if( cur_it < static_cast<int>( pickup_chars.size() ) + static_cast<int> ( pickup_chars.size() ) * static_cast<int>( pickup_chars.size() ) ) { int p = cur_it - pickup_chars.size(); int p1 = p / pickup_chars.size(); int p2 = p % pickup_chars.size(); mvwprintz( w_pickup, 1 + ( cur_it % maxitems ), 0, icolor, "`%c%c", static_cast<char>( pickup_chars[p1] ), static_cast<char>( pickup_chars[p2] ) ); } else { mvwputch( w_pickup, 1 + ( cur_it % maxitems ), 0, icolor, ' ' ); } if( getitem[true_it].pick ) { if( getitem[true_it].count == 0 ) { wprintz( w_pickup, c_light_blue, " + " ); } else { wprintz( w_pickup, c_light_blue, " # " ); } } else { wprintw( w_pickup, " - " ); } std::string item_name; if( stacked_here[true_it].begin()->_item.ammo_type() == "money" ) { //Count charges // TODO: transition to the item_location system used for the inventory unsigned long charges_total = 0; for( const auto &item : stacked_here[true_it] ) { charges_total += item._item.charges; } //Picking up none or all the cards in a stack if( !getitem[true_it].pick || getitem[true_it].count == 0 ) { item_name = stacked_here[true_it].begin()->_item.display_money( stacked_here[true_it].size(), charges_total ); } else { unsigned long charges = 0; int c = getitem[true_it].count; for( auto it = stacked_here[true_it].begin(); it != stacked_here[true_it].end() && c > 0; ++it, --c ) { charges += it->_item.charges; } item_name = string_format( _( "%s of %s" ), stacked_here[true_it].begin()->_item.display_money( getitem[true_it].count, charges ), format_money( charges_total ) ); } } else { item_name = this_item.display_name( stacked_here[true_it].size() ); } if( stacked_here[true_it].size() > 1 ) { item_name = string_format( "%d %s", stacked_here[true_it].size(), item_name ); } if( get_option<bool>( "ITEM_SYMBOLS" ) ) { item_name = string_format( "%s %s", this_item.symbol(), item_name ); } trim_and_print( w_pickup, 1 + ( cur_it % maxitems ), 6, pickupW - 4, icolor, item_name ); } } mvwprintw( w_pickup, maxitems + 1, 0, _( "[%s] Unmark" ), ctxt.get_desc( "LEFT", 1 ) ); center_print( w_pickup, maxitems + 1, c_light_gray, string_format( _( "[%s] Help" ), ctxt.get_desc( "HELP_KEYBINDINGS", 1 ) ) ); right_print( w_pickup, maxitems + 1, 0, c_light_gray, string_format( _( "[%s] Mark" ), ctxt.get_desc( "RIGHT", 1 ) ) ); mvwprintw( w_pickup, maxitems + 2, 0, _( "[%s] Prev" ), ctxt.get_desc( "PREV_TAB", 1 ) ); center_print( w_pickup, maxitems + 2, c_light_gray, string_format( _( "[%s] All" ), ctxt.get_desc( "SELECT_ALL", 1 ) ) ); right_print( w_pickup, maxitems + 2, 0, c_light_gray, string_format( _( "[%s] Next" ), ctxt.get_desc( "NEXT_TAB", 1 ) ) ); if( update ) { // Update weight & volume information update = false; for( int i = 9; i < pickupW; ++i ) { mvwaddch( w_pickup, 0, i, ' ' ); } units::mass weight_picked_up = 0_gram; units::volume volume_picked_up = 0_ml; for( size_t i = 0; i < getitem.size(); i++ ) { if( getitem[i].pick ) { item temp = stacked_here[i].begin()->_item; if( temp.count_by_charges() && getitem[i].count < temp.charges && getitem[i].count != 0 ) { temp.charges = getitem[i].count; } int num_picked = std::min( stacked_here[i].size(), getitem[i].count == 0 ? stacked_here[i].size() : getitem[i].count ); weight_picked_up += temp.weight() * num_picked; volume_picked_up += temp.volume() * num_picked; } } auto weight_predict = g->u.weight_carried() + weight_picked_up; auto volume_predict = g->u.volume_carried() + volume_picked_up; mvwprintz( w_pickup, 0, 5, weight_predict > g->u.weight_capacity() ? c_red : c_white, _( "Wgt %.1f" ), round_up( convert_weight( weight_predict ), 1 ) ); wprintz( w_pickup, c_white, "/%.1f", round_up( convert_weight( g->u.weight_capacity() ), 1 ) ); std::string fmted_volume_predict = format_volume( volume_predict ); mvwprintz( w_pickup, 0, 18, volume_predict > g->u.volume_capacity() ? c_red : c_white, _( "Vol %s" ), fmted_volume_predict ); std::string fmted_volume_capacity = format_volume( g->u.volume_capacity() ); wprintz( w_pickup, c_white, "/%s", fmted_volume_capacity ); } wrefresh( w_pickup ); action = ctxt.handle_input(); raw_input_char = ctxt.get_raw_input().get_first_input(); } while( action != "QUIT" && action != "CONFIRM" ); bool item_selected = false; // Check if we have selected an item. for( auto selection : getitem ) { if( selection.pick ) { item_selected = true; } } if( action != "CONFIRM" || !item_selected ) { w_pickup = catacurses::window(); w_item_info = catacurses::window(); add_msg( _( "Never mind." ) ); g->reenter_fullscreen(); g->refresh_all(); return; } } // At this point we've selected our items, register an activity to pick them up. g->u.assign_activity( activity_id( "ACT_PICKUP" ) ); g->u.activity.placement = p - g->u.pos(); g->u.activity.values.push_back( from_vehicle ); if( min == -1 ) { // Auto pickup will need to auto resume since there can be several of them on the stack. g->u.activity.auto_resume = true; } std::vector<std::pair<int, int>> pick_values; for( size_t i = 0; i < stacked_here.size(); i++ ) { const auto &selection = getitem[i]; if( !selection.pick ) { continue; } const auto &stack = stacked_here[i]; // Note: items can be both charged and stacked // For robustness, let's assume they can be both in the same stack bool pick_all = selection.count == 0; size_t count = selection.count; for( const item_idx &it : stack ) { if( !pick_all && count == 0 ) { break; } if( it._item.count_by_charges() ) { size_t num_picked = std::min( static_cast<size_t>( it._item.charges ), count ); pick_values.push_back( { static_cast<int>( it.idx ), static_cast<int>( num_picked ) } ); count -= num_picked; } else { size_t num_picked = 1; pick_values.push_back( { static_cast<int>( it.idx ), 0 } ); count -= num_picked; } } } // The pickup activity picks up items last-to-first from its values list, so make sure the // higher indices are at the end. std::sort( pick_values.begin(), pick_values.end() ); for( auto &it : pick_values ) { g->u.activity.values.push_back( it.first ); g->u.activity.values.push_back( it.second ); } g->reenter_fullscreen(); }
void TestIt(long p, long r, long c, long _k, long w, long L, Vec<long>& mvec, Vec<long>& gens, Vec<long>& ords, long useCache) { if (lsize(mvec)<1) { // use default values mvec.SetLength(3); gens.SetLength(3); ords.SetLength(3); mvec[0] = 7; mvec[1] = 3; mvec[2] = 221; gens[0] = 3979; gens[1] = 3095; gens[2] = 3760; ords[0] = 6; ords[1] = 2; ords[2] = -8; } if (!noPrint) cout << "*** TestIt" << (dry? " (dry run):" : ":") << " p=" << p << ", r=" << r << ", c=" << c << ", k=" << _k << ", w=" << w << ", L=" << L << ", mvec=" << mvec << ", " << ", useCache = " << useCache << endl; setTimersOn(); setDryRun(false); // Need to get a "real context" to test ThinEvalMap // mvec is supposed to include the prime-power factorization of m long nfactors = mvec.length(); for (long i = 0; i < nfactors; i++) for (long j = i+1; j < nfactors; j++) assert(GCD(mvec[i], mvec[j]) == 1); // multiply all the prime powers to get m itself long m = computeProd(mvec); assert(GCD(p, m) == 1); // build a context with these generators and orders vector<long> gens1, ords1; convert(gens1, gens); convert(ords1, ords); FHEcontext context(m, p, r, gens1, ords1); buildModChain(context, L, c); if (!noPrint) { context.zMStar.printout(); // print structure of Zm* /(p) to cout cout << endl; } long d = context.zMStar.getOrdP(); long phim = context.zMStar.getPhiM(); long nslots = phim/d; setDryRun(dry); // Now we can set the dry-run flag if desired FHESecKey secretKey(context); const FHEPubKey& publicKey = secretKey; secretKey.GenSecKey(w); // A Hamming-weight-w secret key addSome1DMatrices(secretKey); // compute key-switching matrices that we need addFrbMatrices(secretKey); // compute key-switching matrices that we need // GG defines the plaintext space Z_p[X]/GG(X) ZZX GG; GG = context.alMod.getFactorsOverZZ()[0]; EncryptedArray ea(context, GG); zz_p::init(context.alMod.getPPowR()); Vec<zz_p> val0(INIT_SIZE, nslots); for (auto& x: val0) random(x); vector<ZZX> val1; val1.resize(nslots); for (long i = 0; i < nslots; i++) { val1[i] = conv<ZZX>(conv<ZZ>(rep(val0[i]))); } Ctxt ctxt(publicKey); ea.encrypt(ctxt, publicKey, val1); resetAllTimers(); FHE_NTIMER_START(ALL); // Compute homomorphically the transformation that takes the // coefficients packed in the slots and produces the polynomial // corresponding to cube if (!noPrint) CheckCtxt(ctxt, "init"); if (!noPrint) cout << "build ThinEvalMap\n"; ThinEvalMap map(ea, /*minimal=*/false, mvec, /*invert=*/false, /*build_cache=*/false); // compute the transformation to apply if (!noPrint) cout << "apply ThinEvalMap\n"; if (useCache) map.upgrade(); map.apply(ctxt); // apply the transformation to ctxt if (!noPrint) CheckCtxt(ctxt, "ThinEvalMap"); if (!noPrint) cout << "check results\n"; if (!noPrint) cout << "build ThinEvalMap\n"; ThinEvalMap imap(ea, /*minimal=*/false, mvec, /*invert=*/true, /*build_cache=*/false); // compute the transformation to apply if (!noPrint) cout << "apply ThinEvalMap\n"; if (useCache) imap.upgrade(); imap.apply(ctxt); // apply the transformation to ctxt if (!noPrint) { CheckCtxt(ctxt, "ThinEvalMap"); cout << "check results\n"; } #if 1 /* create dirty version of ctxt */ Vec<zz_pX> dirty_val0; dirty_val0.SetLength(nslots); for (long i = 0; i < nslots; i++) { random(dirty_val0[i], d); SetCoeff(dirty_val0[i], 0, val0[i]); } vector<ZZX> dirty_val1; dirty_val1.resize(nslots); for (long i = 0; i < nslots; i++) { dirty_val1[i] = conv<ZZX>(dirty_val0[i]); } Ctxt dirty_ctxt(publicKey); ea.encrypt(dirty_ctxt, publicKey, dirty_val1); EvalMap dirty_map(ea, /*minimal=*/false, mvec, /*invert=*/false, /*build_cache=*/false); dirty_map.apply(dirty_ctxt); imap.apply(dirty_ctxt); #endif vector<ZZX> val2; ea.decrypt(ctxt, secretKey, val2); if (val1 == val2) cout << "ThinEvalMap: GOOD\n"; else cout << "ThinEvalMap: BAD\n"; #if 1 vector<ZZX> dirty_val2; ea.decrypt(dirty_ctxt, secretKey, dirty_val2); if (val1 == dirty_val2) cout << "ThinEvalMap: GOOD\n"; else cout << "ThinEvalMap: BAD\n"; #endif FHE_NTIMER_STOP(ALL); if (!noPrint) { cout << "\n*********\n"; printAllTimers(); cout << endl; } }
void Messages::display_messages() { WINDOW_PTR w_ptr {newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0, (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0)}; WINDOW *const w = w_ptr.get(); input_context ctxt("MESSAGE_LOG"); ctxt.register_action("UP", _("Scroll up")); ctxt.register_action("DOWN", _("Scroll down")); ctxt.register_action("QUIT"); ctxt.register_action("HELP_KEYBINDINGS"); int offset = 0; const int maxlength = FULL_SCREEN_WIDTH - 2 - 1; const int bottom = FULL_SCREEN_HEIGHT - 2; const int msg_count = size(); for (;;) { werase(w); draw_border(w); mvwprintz(w, bottom + 1, 32, c_red, _("Press %s to return"), ctxt.get_desc("QUIT").c_str()); draw_scrollbar(w, offset, bottom, msg_count, 1); int line = 1; int lasttime = -1; for( int i = offset; i < msg_count; ++i ) { if (line > bottom) { break; } const game_message &m = player_messages.impl_->history(i); const nc_color col = msgtype_to_color( m.type, false ); const calendar timepassed = calendar::turn - m.timestamp_in_turns; if (timepassed.get_turn() > lasttime) { mvwprintz(w, line++, 3, c_ltblue, _("%s ago:"), timepassed.textify_period().c_str()); lasttime = timepassed.get_turn(); } nc_color col_out = col; for( const std::string &folded : foldstring(m.get_with_count(), maxlength) ) { if (line > bottom) { break; } print_colored_text( w, line++, 1, col_out, col, folded ); } } if (offset + 1 < msg_count) { mvwprintz(w, bottom + 1, 5, c_magenta, "vvv"); } if (offset > 0) { mvwprintz(w, bottom + 1, maxlength - 3, c_magenta, "^^^"); } wrefresh(w); const std::string &action = ctxt.handle_input(); if (action == "DOWN" && offset + 1 < msg_count) { offset++; } else if (action == "UP" && offset > 0) { offset--; } else if (action == "QUIT") { break; } } player_messages.impl_->curmes = calendar::turn.get_turn(); }
// TODO: Shunt redundant drawing code elsewhere std::vector<point> game::target(int &x, int &y, int lowx, int lowy, int hix, int hiy, std::vector <monster> t, int &target, item *relevent) { std::vector<point> ret; int tarx, tary, junk, tart; int range=(hix-u.posx); // First, decide on a target among the monsters, if there are any in range if (!t.empty()) { // Check for previous target if (target == -1) { // If no previous target, target the closest there is double closest = -1; double dist; for (int i = 0; i < t.size(); i++) { dist = rl_dist(t[i].posx(), t[i].posy(), u.posx, u.posy); if (closest < 0 || dist < closest) { closest = dist; target = i; } } } x = t[target].posx(); y = t[target].posy(); } else target = -1; // No monsters in range, don't use target, reset to -1 bool sideStyle = use_narrow_sidebar(); int height = 13; int width = getmaxx(w_messages); int top = sideStyle ? getbegy(w_messages) : (getbegy(w_minimap) + getmaxy(w_minimap)); int left = getbegx(w_messages); WINDOW* w_target = newwin(height, width, top, left); draw_border(w_target); mvwprintz(w_target, 0, 2, c_white, "< "); if (!relevent) { // currently targetting vehicle to refill with fuel wprintz(w_target, c_red, _("Select a vehicle")); } else { if (relevent == &u.weapon && relevent->is_gun()) { wprintz(w_target, c_red, _("Firing %s (%d)"), // - %s (%d)", u.weapon.tname().c_str(),// u.weapon.curammo->name.c_str(), u.weapon.charges); } else { wprintz(w_target, c_red, _("Throwing %s"), relevent->tname().c_str()); } } wprintz(w_target, c_white, " >"); /* Annoying clutter @ 2 3 4. */ int text_y = getmaxy(w_target) - 4; if (is_mouse_enabled()) { --text_y; } mvwprintz(w_target, text_y++, 1, c_white, _("Move cursor to target with directional keys")); if (relevent) { mvwprintz(w_target, text_y++, 1, c_white, _("'<' '>' Cycle targets; 'f' or '.' to fire")); mvwprintz(w_target, text_y++, 1, c_white, _("'0' target self; '*' toggle snap-to-target")); } if (is_mouse_enabled()) { mvwprintz(w_target, text_y++, 1, c_white, _("Mouse: LMB: Target, Wheel: Cycle, RMB: Fire")); } wrefresh(w_target); bool snap_to_target = OPTIONS["SNAP_TO_TARGET"]; do { if (m.sees(u.posx, u.posy, x, y, -1, tart)) ret = line_to(u.posx, u.posy, x, y, tart); else ret = line_to(u.posx, u.posy, x, y, 0); if(trigdist && trig_dist(u.posx,u.posy, x,y) > range) { bool cont=true; int cx=x; int cy=y; for (int i = 0; i < ret.size() && cont; i++) { if(trig_dist(u.posx,u.posy, ret[i].x, ret[i].y) > range) { ret.resize(i); cont=false; } else { cx=0+ret[i].x; cy=0+ret[i].y; } } x=cx;y=cy; } point center; if (snap_to_target) center = point(x, y); else center = point(u.posx + u.view_offset_x, u.posy + u.view_offset_y); // Clear the target window. for (int i = 1; i < getmaxy(w_target) - 5; i++) { for (int j = 1; j < getmaxx(w_target) - 2; j++) mvwputch(w_target, i, j, c_white, ' '); } /* Start drawing w_terrain things -- possibly move out to centralized draw_terrain_window function as they all should be roughly similar*/ m.build_map_cache(); // part of the SDLTILES drawing code m.draw(w_terrain, center); // embedded in SDL drawing code // Draw the Monsters for (int i = 0; i < num_zombies(); i++) { if (u_see(&(zombie(i)))) { zombie(i).draw(w_terrain, center.x, center.y, false); } } // Draw the NPCs for (int i = 0; i < active_npc.size(); i++) { if (u_see(active_npc[i]->posx, active_npc[i]->posy)) active_npc[i]->draw(w_terrain, center.x, center.y, false); } if (x != u.posx || y != u.posy) { // Draw the player int atx = POSX + u.posx - center.x, aty = POSY + u.posy - center.y; if (atx >= 0 && atx < TERRAIN_WINDOW_WIDTH && aty >= 0 && aty < TERRAIN_WINDOW_HEIGHT) mvwputch(w_terrain, aty, atx, u.color(), '@'); // Only draw a highlighted trajectory if we can see the endpoint. // Provides feedback to the player, and avoids leaking information about tiles they can't see. draw_line(x, y, center, ret); /* if (u_see( x, y)) { for (int i = 0; i < ret.size(); i++) { int mondex = mon_at(ret[i].x, ret[i].y), npcdex = npc_at(ret[i].x, ret[i].y); // NPCs and monsters get drawn with inverted colors if (mondex != -1 && u_see(&(zombie(mondex)))) zombie(mondex).draw(w_terrain, center.x, center.y, true); else if (npcdex != -1) active_npc[npcdex]->draw(w_terrain, center.x, center.y, true); else m.drawsq(w_terrain, u, ret[i].x, ret[i].y, true,true,center.x, center.y); } } //*/ // Print to target window if (!relevent) { // currently targetting vehicle to refill with fuel vehicle *veh = m.veh_at(x, y); if (veh) { mvwprintw(w_target, 1, 1, _("There is a %s"), veh->name.c_str()); } } else if (relevent == &u.weapon && relevent->is_gun()) { // firing a gun mvwprintw(w_target, 1, 1, _("Range: %d"), rl_dist(u.posx, u.posy, x, y)); // get the current weapon mode or mods std::string mode = ""; if (u.weapon.mode == "MODE_BURST") { mode = _("Burst"); } else { item* gunmod = u.weapon.active_gunmod(); if (gunmod != NULL) { mode = gunmod->type->name; } } if (mode != "") { mvwprintw(w_target, 1, 14, _("Firing mode: %s"), mode.c_str()); } } else { // throwing something mvwprintw(w_target, 1, 1, _("Range: %d"), rl_dist(u.posx, u.posy, x, y)); } const int zid = mon_at(x, y); if (zid == -1) { if (snap_to_target) mvwputch(w_terrain, POSY, POSX, c_red, '*'); else mvwputch(w_terrain, POSY + y - center.y, POSX + x - center.x, c_red, '*'); } else { if (u_see(&(zombie(zid)))) { zombie(zid).print_info(w_target,2); } } } wrefresh(w_target); wrefresh(w_terrain); wrefresh(w_status); refresh(); input_context ctxt("TARGET"); // "ANY_INPUT" should be added before any real help strings // Or strings will be writen on window border. ctxt.register_action("ANY_INPUT"); ctxt.register_directions(); ctxt.register_action("COORDINATE"); ctxt.register_action("SELECT"); ctxt.register_action("FIRE"); ctxt.register_action("NEXT_TARGET"); ctxt.register_action("PREV_TARGET"); ctxt.register_action("WAIT"); ctxt.register_action("CENTER"); ctxt.register_action("TOGGLE_SNAP_TO_TARGET"); ctxt.register_action("HELP_KEYBINDINGS"); ctxt.register_action("QUIT"); const std::string& action = ctxt.handle_input(); tarx = 0; tary = 0; // Our coordinates will either be determined by coordinate input(mouse), // by a direction key, or by the previous value. if (action == "SELECT" && ctxt.get_coordinates(g->w_terrain, tarx, tary)) { if (!OPTIONS["USE_TILES"] && snap_to_target) { // Snap to target doesn't currently work with tiles. tarx += x - u.posx; tary += y - u.posy; } tarx -= x; tary -= y; } else { ctxt.get_direction(tarx, tary, action); if(tarx == -2) { tarx = 0; tary = 0; } } /* More drawing to terrain */ if (tarx != 0 || tary != 0) { int mondex = mon_at(x, y), npcdex = npc_at(x, y); if (mondex != -1 && u_see(&(zombie(mondex)))) zombie(mondex).draw(w_terrain, center.x, center.y, false); else if (npcdex != -1) active_npc[npcdex]->draw(w_terrain, center.x, center.y, false); else if (m.sees(u.posx, u.posy, x, y, -1, junk)) m.drawsq(w_terrain, u, x, y, false, true, center.x, center.y); else mvwputch(w_terrain, POSY, POSX, c_black, 'X'); x += tarx; y += tary; if (x < lowx) x = lowx; else if (x > hix) x = hix; if (y < lowy) y = lowy; else if (y > hiy) y = hiy; } else if ((action == "PREV_TARGET") && (target != -1)) { target--; if (target == -1) target = t.size() - 1; x = t[target].posx(); y = t[target].posy(); } else if ((action == "NEXT_TARGET") && (target != -1)) { target++; if (target == t.size()) target = 0; x = t[target].posx(); y = t[target].posy(); } else if (action == "WAIT" || action == "FIRE") { for (int i = 0; i < t.size(); i++) { if (t[i].posx() == x && t[i].posy() == y) target = i; } if (u.posx == x && u.posy == y) ret.clear(); break; } else if (action == "CENTER") { x = u.posx; y = u.posy; ret.clear(); } else if (action == "TOGGLE_SNAP_TO_TARGET") snap_to_target = !snap_to_target; else if (action == "QUIT") { // return empty vector (cancel) ret.clear(); break; } } while (true); return ret; }
void Messages::display_messages() { catacurses::window w = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, ( TERMY > FULL_SCREEN_HEIGHT ) ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0, ( TERMX > FULL_SCREEN_WIDTH ) ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ); input_context ctxt( "MESSAGE_LOG" ); ctxt.register_action( "UP", _( "Scroll up" ) ); ctxt.register_action( "DOWN", _( "Scroll down" ) ); ctxt.register_action( "QUIT" ); ctxt.register_action( "HELP_KEYBINDINGS" ); /* Right-Aligning Time Epochs For Readability * ========================================== * Given display_messages(); right-aligns epochs, we must declare one quick variable first: * max_padlength refers to the length of the LONGEST possible unit of time returned by to_string_clipped() any language has to offer. * This variable is, for now, set to '10', which seems most reasonable. * * The reason right-aligned epochs don't use a "shortened version" (e.g. only showing the first letter) boils down to: * 1. The first letter of every time unit being unique is a property that might not carry across to other languages. * 2. Languages where displayed characters change depending on the characters preceding/following it will become unclear. * 3. Some polymorphic languages might not be able to appropriately convey meaning with one character (FRS is not a linguist- correct her on this if needed.) * * This right padlength is then incorporated into a so-called 'epoch_format' which, in turn, will be used to format the correct epoch. * If an external language introduces time units longer than 10 characters in size, consider altering these variables. * The game (likely) shan't segfault, though the text may appear a bit messed up if these variables aren't set properly. */ const int max_padlength = 10; /* Dealing With Screen Extremities * =============================== * 'maxlength' corresponds to the most extreme length a log message may be before foldstring() wraps it around to two or more lines. * The numbers subtracted from FULL_SCREEN_WIDTH are - in order: * '-2' the characters reserved for the borders of the box, both on the left and right side. * '-1' the leftmost guide character that's drawn on screen. * '-4' the padded three-digit number each epoch starts with. * '-max_padlength' the characters of space that are allocated to time units (e.g. "years", "minutes", etc.) * * 'bottom' works much like 'maxlength', but instead it refers to the amount of lines that the message box may hold. */ const int maxlength = FULL_SCREEN_WIDTH - 2 - 1 - 4 - max_padlength; const int bottom = FULL_SCREEN_HEIGHT - 2; const int msg_count = size(); /* Dealing With Scroll Direction * ============================= * Much like how the sidebar can have variable scroll direction, so will the message box. * To properly differentiate the two methods of displaying text, we will label them NEWEST-TOP, and OLDEST-TOP. This labeling should be self explanatory. * * Note that 'offset' tracks only our current position in the list; it shan't at all affect the manner in which the messages are drawn. * Messages are always drawn top-to-bottom. If NEWEST-TOP is used, then the top line (line=1) corresponds to the newest message. The one further down the second-newest, etc. * If the OLDEST-TOP method is used, then the top line (line=1) corresponds to the oldest message, and the bottom one to the newest. * The 'for (;;)' block below is nearly completely method-agnostic, save for the `player_messages.impl_->history(i)` call. * * In case of NEWEST-TOP, the 'i' variable easily enough corresponds to the newest message. * In case of OLDEST-TOP, the 'i' variable must be flipped- meaning the highest value of 'i' returns the result for the lowest value of 'i', etc. * To achieve this, the 'flip_message' variable is set to either the value of 'msg_count', or '0'. This variable is then subtracted from 'i' in each call to player_messages.impl_->history(); * * 'offset' refers to the corresponding message that will be displayed at the very TOP of the message box window. * NEWEST-TOP: 'offset' starts simply at '0' - the very top of the window. * OLDEST-TOP: 'offset' is set to the maximum value it could possibly be. That is- 'msg_count-bottom'. This way, the screen starts with the scrollbar all the way down. * 'retrieve_history' refers to the line that should be displayed- this is either 'i' if it's NEWEST-TOP, or a flipped version of 'i' if it's OLDEST-TOP. */ int offset = log_from_top ? 0 : ( msg_count - bottom ); const int flip = log_from_top ? 0 : msg_count - 1; for( ;; ) { werase( w ); draw_border( w ); mvwprintz( w, bottom + 1, 32, c_red, _( "Press %s to return" ), ctxt.get_desc( "QUIT" ).c_str() ); draw_scrollbar( w, offset, bottom, msg_count, 1, 0, c_white, true ); int line = 1; int lasttime = -1; for( int i = offset; i < msg_count; ++i ) { const int retrieve_history = abs( i - flip ); if( line > bottom ) { break; // This statement makes it so that no non-existent messages are printed (which usually results in a segfault) } else if( retrieve_history >= msg_count ) { continue; } const game_message &m = player_messages.impl_->history( retrieve_history ); const calendar timepassed = calendar::turn - m.timestamp_in_turns; std::string long_ago = to_string_clipped( time_duration::from_turns( timepassed ) ); nc_color col = msgtype_to_color( m.type, false ); // Here we separate the unit and amount from one another so that they can be properly padded when they're drawn on the screen. // Note that the very first character of 'unit' is often a space (except for languages where the time unit directly follows the number.) const auto amount_len = long_ago.find_first_not_of( "0123456789" ); std::string amount = long_ago.substr( 0, amount_len ); std::string unit = long_ago.substr( amount_len ); if( timepassed.get_turn() != lasttime ) { right_print( w, line, 2, c_light_blue, string_format( _( "%-3s%-10s" ), amount.c_str(), unit.c_str() ) ); lasttime = timepassed.get_turn(); } nc_color col_out = col; for( const std::string &folded : foldstring( m.get_with_count(), maxlength ) ) { if( line > bottom ) { break; } print_colored_text( w, line, 2, col_out, col, folded ); // So-called special "markers"- alternating '=' and '-'s at the edges of te message window so players can properly make sense of which message belongs to which time interval. // The '+offset%4' in the calculation makes it so that the markings scroll along with the messages. // On lines divisible by 4, draw a dark gray '-' at both horizontal extremes of the window. if( ( line + offset % 4 ) % 4 == 0 ) { mvwprintz( w, line, 1, c_dark_gray, "-" ); mvwprintz( w, line, FULL_SCREEN_WIDTH - 2, c_dark_gray, "-" ); // On lines divisible by 2 (but not 4), draw a light gray '=' at the horizontal extremes of the window. } else if( ( line + offset % 4 ) % 2 == 0 ) { mvwprintz( w, line, 1, c_light_gray, "=" ); mvwprintz( w, line, FULL_SCREEN_WIDTH - 2, c_light_gray, "=" ); } // Only now are we done with this line: line++; } } if( offset < msg_count - bottom ) { mvwprintz( w, bottom + 1, 5, c_magenta, "vvv" ); } if( offset > 0 ) { mvwprintz( w, bottom + 1, FULL_SCREEN_WIDTH - 8, c_magenta, "^^^" ); } wrefresh( w ); const std::string &action = ctxt.handle_input(); if( action == "DOWN" && offset < msg_count - bottom ) { offset++; } else if( action == "UP" && offset > 0 ) { offset--; } else if( action == "QUIT" ) { break; } } player_messages.impl_->curmes = calendar::turn.get_turn(); }
WORLDPTR worldfactory::pick_world( bool show_prompt ) { std::map<std::string, WORLDPTR> worlds = get_all_worlds(); std::vector<std::string> world_names = all_worldnames; // Filter out special worlds (TUTORIAL | DEFENSE) from world_names. for (std::vector<std::string>::iterator it = world_names.begin(); it != world_names.end();) { if (*it == "TUTORIAL" || *it == "DEFENSE") { it = world_names.erase(it); } else { ++it; } } // If there is only one world to pick from, autoreturn it. if (world_names.size() == 1) { return worlds[world_names[0]]; } // If there are no worlds to pick from, immediately try to make one. else if (world_names.empty()) { return make_new_world( show_prompt ); } // If we're skipping prompts, just return the first one. else if( !show_prompt ) { return worlds[world_names[0]]; } const int iTooltipHeight = 3; const int iContentHeight = FULL_SCREEN_HEIGHT - 3 - iTooltipHeight; const unsigned int num_pages = world_names.size() / iContentHeight + 1; // at least 1 page const int iOffsetX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0; const int iOffsetY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0; std::map<int, bool> mapLines; mapLines[3] = true; std::map<int, std::vector<std::string> > world_pages; unsigned int worldnum = 0; for (size_t i = 0; i < num_pages; ++i) { for (int j = 0; j < iContentHeight && worldnum < world_names.size(); ++j) { world_pages[i].push_back(world_names[worldnum++]); } } unsigned int sel = 0, selpage = 0; WINDOW *w_worlds_border = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, iOffsetY, iOffsetX); WINDOW *w_worlds_tooltip = newwin(iTooltipHeight, FULL_SCREEN_WIDTH - 2, 1 + iOffsetY, 1 + iOffsetX); WINDOW *w_worlds_header = newwin(1, FULL_SCREEN_WIDTH - 2, 1 + iTooltipHeight + iOffsetY, 1 + iOffsetX); WINDOW *w_worlds = newwin(iContentHeight, FULL_SCREEN_WIDTH - 2, iTooltipHeight + 2 + iOffsetY, 1 + iOffsetX); draw_border(w_worlds_border); mvwputch(w_worlds_border, 4, 0, BORDER_COLOR, LINE_XXXO); // |- mvwputch(w_worlds_border, 4, FULL_SCREEN_WIDTH - 1, BORDER_COLOR, LINE_XOXX); // -| for (std::map<int, bool>::iterator iter = mapLines.begin(); iter != mapLines.end(); ++iter) { mvwputch(w_worlds_border, FULL_SCREEN_HEIGHT - 1, iter->first + 1, BORDER_COLOR, LINE_XXOX); // _|_ } center_print(w_worlds_border, 0, c_ltred, _(" WORLD SELECTION ")); wrefresh(w_worlds_border); for (int i = 0; i < 78; i++) { if (mapLines[i]) { mvwputch(w_worlds_header, 0, i, BORDER_COLOR, LINE_OXXX); } else { mvwputch(w_worlds_header, 0, i, BORDER_COLOR, LINE_OXOX); // Draw header line } } wrefresh(w_worlds_header); input_context ctxt("PICK_WORLD_DIALOG"); ctxt.register_updown(); ctxt.register_action("HELP_KEYBINDINGS"); ctxt.register_action("QUIT"); ctxt.register_action("NEXT_TAB"); ctxt.register_action("PREV_TAB"); ctxt.register_action("CONFIRM"); std::stringstream sTemp; while(true) { //Clear the lines for (int i = 0; i < iContentHeight; i++) { for (int j = 0; j < 79; j++) { if (mapLines[j]) { mvwputch(w_worlds, i, j, BORDER_COLOR, LINE_XOXO); } else { mvwputch(w_worlds, i, j, c_black, ' '); } if (i < iTooltipHeight) { mvwputch(w_worlds_tooltip, i, j, c_black, ' '); } } } //Draw World Names for (size_t i = 0; i < world_pages[selpage].size(); ++i) { sTemp.str(""); sTemp << i + 1; mvwprintz(w_worlds, i, 0, c_white, "%s", sTemp.str().c_str()); mvwprintz(w_worlds, i, 4, c_white, ""); if (i == sel) { wprintz(w_worlds, c_yellow, ">> "); } else { wprintz(w_worlds, c_yellow, " "); } wprintz(w_worlds, c_white, "%s (%i)", (world_pages[selpage])[i].c_str(), world_generator->all_worlds[((world_pages[selpage])[i])]->world_saves.size()); } //Draw Tabs mvwprintz(w_worlds_header, 0, 7, c_white, ""); for (size_t i = 0; i < num_pages; ++i) { nc_color tabcolor = (selpage == i) ? hilite(c_white) : c_white; if (!world_pages[i].empty()) { //skip empty pages wprintz(w_worlds_header, c_white, "["); wprintz(w_worlds_header, tabcolor, _("Page %d"), i + 1); wprintz(w_worlds_header, c_white, "]"); wputch(w_worlds_header, BORDER_COLOR, LINE_OXOX); } } wrefresh(w_worlds_header); fold_and_print(w_worlds_tooltip, 0, 0, 78, c_white, _("Pick a world to enter game")); wrefresh(w_worlds_tooltip); wrefresh(w_worlds); const std::string action = ctxt.handle_input(); if (action == "QUIT") { break; } else if (!world_pages[selpage].empty() && action == "DOWN") { sel++; if (sel >= world_pages[selpage].size()) { sel = 0; } } else if (!world_pages[selpage].empty() && action == "UP") { if (sel == 0) { sel = world_pages[selpage].size() - 1; } else { sel--; } } else if (action == "NEXT_TAB") { sel = 0; do { //skip empty pages selpage++; if (selpage >= world_pages.size()) { selpage = 0; } } while(world_pages[selpage].empty()); } else if (action == "PREV_TAB") { sel = 0; do { //skip empty pages if (selpage != 0) { selpage--; } else { selpage = world_pages.size() - 1; } } while(world_pages[selpage].empty()); } else if (action == "CONFIRM") { // we are wanting to get out of this by confirmation, so ask if we want to load the level [y/n prompt] and if yes exit if (query_yn(_("Do you want to start the game in world [%s]?"), world_pages[selpage][sel].c_str())) { werase(w_worlds); werase(w_worlds_border); werase(w_worlds_header); werase(w_worlds_tooltip); return all_worlds[world_pages[selpage][sel]];//sel + selpage * iContentHeight; } } } werase(w_worlds); werase(w_worlds_border); werase(w_worlds_header); werase(w_worlds_tooltip); return NULL; }
// Testing the I/O of the important classes of the library // (context, keys, ciphertexts). int main(int argc, char *argv[]) { ArgMapping amap; long r=1; long p=2; long c = 2; long w = 64; long L = 5; amap.arg("p", p, "plaintext base"); amap.arg("r", r, "lifting"); amap.arg("c", c, "number of columns in the key-switching matrices"); amap.parse(argc, argv); long ptxtSpace = power_long(p,r); FHEcontext* contexts[N_TESTS]; FHESecKey* sKeys[N_TESTS]; Ctxt* ctxts[N_TESTS]; EncryptedArray* eas[N_TESTS]; vector<ZZX> ptxts[N_TESTS]; // first loop: generate stuff and write it to cout // open file for writing {fstream keyFile("iotest.txt", fstream::out|fstream::trunc); assert(keyFile.is_open()); for (long i=0; i<N_TESTS; i++) { long m = ms[i][1]; cout << "Testing IO: m="<<m<<", p^r="<<p<<"^"<<r<<endl; if (i==N_TESTS-1) { // test bootstrapping data I/O Vec<long> mvec(INIT_SIZE,2); mvec[0] = ms[i][4]; mvec[1] = ms[i][5]; vector<long> gens(2); gens[0] = ms[i][6]; gens[1] = ms[i][7]; vector<long> ords(2); ords[0] = ms[i][8]; ords[1] = ms[i][9]; contexts[i] = new FHEcontext(m, p, r, gens, ords); buildModChain(*contexts[i], L, c); // Set the modulus chain contexts[i]->makeBootstrappable(mvec); } else { contexts[i] = new FHEcontext(m, p, r); buildModChain(*contexts[i], L, c); // Set the modulus chain } // Output the FHEcontext to file writeContextBase(keyFile, *contexts[i]); keyFile << *contexts[i] << endl; sKeys[i] = new FHESecKey(*contexts[i]); const FHEPubKey& publicKey = *sKeys[i]; sKeys[i]->GenSecKey(w,ptxtSpace); // A Hamming-weight-w secret key addSome1DMatrices(*sKeys[i]);// compute key-switching matrices that we need eas[i] = new EncryptedArray(*contexts[i]); long nslots = eas[i]->size(); // Output the secret key to file, twice. Below we will have two copies // of most things. keyFile << *sKeys[i] << endl;; keyFile << *sKeys[i] << endl;; vector<ZZX> b; long p2r = eas[i]->getContext().alMod.getPPowR(); ZZX poly = RandPoly(0,to_ZZ(p2r)); // choose a random constant polynomial eas[i]->decode(ptxts[i], poly); ctxts[i] = new Ctxt(publicKey); eas[i]->encrypt(*ctxts[i], publicKey, ptxts[i]); eas[i]->decrypt(*ctxts[i], *sKeys[i], b); assert(ptxts[i].size() == b.size()); for (long j = 0; j < nslots; j++) assert (ptxts[i][j] == b[j]); // output the plaintext keyFile << "[ "; for (long j = 0; j < nslots; j++) keyFile << ptxts[i][j] << " "; keyFile << "]\n"; eas[i]->encode(poly,ptxts[i]); keyFile << poly << endl; // Output the ciphertext to file keyFile << *ctxts[i] << endl; keyFile << *ctxts[i] << endl; cerr << "okay " << i << endl; } keyFile.close();} cerr << "so far, so good\n"; // second loop: read from input and repeat the computation // open file for read {fstream keyFile("iotest.txt", fstream::in); for (long i=0; i<N_TESTS; i++) { // Read context from file unsigned long m1, p1, r1; vector<long> gens, ords; readContextBase(keyFile, m1, p1, r1, gens, ords); FHEcontext tmpContext(m1, p1, r1, gens, ords); keyFile >> tmpContext; assert (*contexts[i] == tmpContext); cerr << i << ": context matches input\n"; // We define some things below wrt *contexts[i], not tmpContext. // This is because the various operator== methods check equality of // references, not equality of the referenced FHEcontext objects. FHEcontext& context = *contexts[i]; FHESecKey secretKey(context); FHESecKey secretKey2(tmpContext); const FHEPubKey& publicKey = secretKey; const FHEPubKey& publicKey2 = secretKey2; keyFile >> secretKey; keyFile >> secretKey2; assert(secretKey == *sKeys[i]); cerr << " secret key matches input\n"; EncryptedArray ea(context); EncryptedArray ea2(tmpContext); long nslots = ea.size(); // Read the plaintext from file vector<ZZX> a; a.resize(nslots); assert(nslots == (long)ptxts[i].size()); seekPastChar(keyFile, '['); // defined in NumbTh.cpp for (long j = 0; j < nslots; j++) { keyFile >> a[j]; assert(a[j] == ptxts[i][j]); } seekPastChar(keyFile, ']'); cerr << " ptxt matches input\n"; // Read the encoded plaintext from file ZZX poly1, poly2; keyFile >> poly1; eas[i]->encode(poly2,a); assert(poly1 == poly2); cerr << " eas[i].encode(a)==poly1 okay\n"; ea.encode(poly2,a); assert(poly1 == poly2); cerr << " ea.encode(a)==poly1 okay\n"; ea2.encode(poly2,a); assert(poly1 == poly2); cerr << " ea2.encode(a)==poly1 okay\n"; eas[i]->decode(a,poly1); assert(nslots == (long)a.size()); for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]); cerr << " eas[i].decode(poly1)==ptxts[i] okay\n"; ea.decode(a,poly1); assert(nslots == (long)a.size()); for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]); cerr << " ea.decode(poly1)==ptxts[i] okay\n"; ea2.decode(a,poly1); assert(nslots == (long)a.size()); for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]); cerr << " ea2.decode(poly1)==ptxts[i] okay\n"; // Read ciperhtext from file Ctxt ctxt(publicKey); Ctxt ctxt2(publicKey2); keyFile >> ctxt; keyFile >> ctxt2; assert(ctxts[i]->equalsTo(ctxt,/*comparePkeys=*/false)); cerr << " ctxt matches input\n"; sKeys[i]->Decrypt(poly2,*ctxts[i]); assert(poly1 == poly2); cerr << " sKeys[i]->decrypt(*ctxts[i]) == poly1 okay\n"; secretKey.Decrypt(poly2,*ctxts[i]); assert(poly1 == poly2); cerr << " secretKey.decrypt(*ctxts[i]) == poly1 okay\n"; secretKey.Decrypt(poly2,ctxt); assert(poly1 == poly2); cerr << " secretKey.decrypt(ctxt) == poly1 okay\n"; secretKey2.Decrypt(poly2,ctxt2); assert(poly1 == poly2); cerr << " secretKey2.decrypt(ctxt2) == poly1 okay\n"; eas[i]->decrypt(ctxt, *sKeys[i], a); assert(nslots == (long)a.size()); for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]); cerr << " eas[i].decrypt(ctxt, *sKeys[i])==ptxts[i] okay\n"; ea.decrypt(ctxt, secretKey, a); assert(nslots == (long)a.size()); for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]); cerr << " ea.decrypt(ctxt, secretKey)==ptxts[i] okay\n"; ea2.decrypt(ctxt2, secretKey2, a); assert(nslots == (long)a.size()); for (long j = 0; j < nslots; j++) assert(a[j] == ptxts[i][j]); cerr << " ea2.decrypt(ctxt2, secretKey2)==ptxts[i] okay\n"; cerr << "test "<<i<<" okay\n\n"; }} unlink("iotest.txt"); // clean up before exiting }
int worldfactory::show_worldgen_tab_options(WINDOW *win, WORLDPTR world) { const int iTooltipHeight = 1; const int iContentHeight = FULL_SCREEN_HEIGHT - 3 - iTooltipHeight; const int iOffsetX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0; const int iOffsetY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0; WINDOW *w_options = newwin(iContentHeight, FULL_SCREEN_WIDTH - 2, iTooltipHeight + 2 + iOffsetY, 1 + iOffsetX); std::stringstream sTemp; std::map<int, bool> mapLines; mapLines[3] = true; mapLines[60] = true; // only populate once if (world->world_options.empty()) { for (std::map<std::string, cOpt>::iterator it = OPTIONS.begin(); it != OPTIONS.end(); ++it) { if (it->second.getPage() == "world_default") { world->world_options[it->first] = it->second; } } } std::vector<std::string> keys; for (std::map<std::string, cOpt>::iterator it = world->world_options.begin(); it != world->world_options.end(); ++it) { keys.push_back(it->first); } for (std::map<int, bool>::iterator mLine = mapLines.begin(); mLine != mapLines.end(); ++mLine) { if (mLine->second) { mvwputch(win, 2, mLine->first + 1, BORDER_COLOR, LINE_OXXX); // -.- mvwputch(win, FULL_SCREEN_HEIGHT - 1, mLine->first + 1, BORDER_COLOR, LINE_XXOX); // _|_ } } wrefresh(win); refresh(); input_context ctxt("WORLDGEN_OPTION_DIALOG"); ctxt.register_cardinal(); ctxt.register_action("HELP_KEYBINDINGS"); ctxt.register_action("QUIT"); ctxt.register_action("NEXT_TAB"); ctxt.register_action("PREV_TAB"); unsigned int sel = 0; unsigned int curoption = 0; do { for (int i = 0; i < iContentHeight; i++) { for (int j = 0; j < 79; j++) { if (mapLines[j]) { mvwputch(w_options, i, j, BORDER_COLOR, LINE_XOXO); } else { mvwputch(w_options, i, j, c_black, ' '); } } } curoption = 0; for (std::map<std::string, cOpt>::iterator it = world->world_options.begin(); it != world->world_options.end(); ++it) { nc_color cLineColor = c_ltgreen; sTemp.str(""); sTemp << curoption + 1; mvwprintz(w_options, curoption , 0, c_white, "%s", sTemp.str().c_str()); mvwprintz(w_options, curoption , 4, c_white, ""); if (sel == curoption) { wprintz(w_options, c_yellow, ">> "); } else { wprintz(w_options, c_yellow, " "); } wprintz(w_options, c_white, "%s", (it->second.getMenuText()).c_str()); if (it->second.getValue() == "False") { cLineColor = c_ltred; } mvwprintz(w_options, curoption, 62, (sel == curoption) ? hilite(cLineColor) : cLineColor, "%s", (it->second.getValueName()).c_str()); ++curoption; } wrefresh(w_options); refresh(); const std::string action = ctxt.handle_input(); if (action == "DOWN") { sel++; if (sel >= world->world_options.size()) { sel = 0; } } else if (action == "UP") { if (sel == 0) { sel = world->world_options.size() - 1; } else { sel--; } } else if (!world->world_options.empty() && action == "LEFT") { world->world_options[keys[sel]].setPrev(); } else if (!world->world_options.empty() && action == "RIGHT") { world->world_options[keys[sel]].setNext(); } else if (action == "PREV_TAB") { werase(w_options); delwin(w_options); return -1; } else if (action == "NEXT_TAB") { werase(w_options); delwin(w_options); return 1; } else if (action == "QUIT") { return -999; } } while (true); return 0; }
void player::power_bionics() { std::vector <bionic *> passive; std::vector <bionic *> active; for (std::vector<bionic>::iterator it = my_bionics.begin(); it != my_bionics.end(); ++it) { if (!bionics[it->id]->activated) { passive.push_back(&*it); } else { active.push_back(&*it); } } // maximal number of rows in both columns const int bionic_count = std::max(passive.size(), active.size()); int TITLE_HEIGHT = 2; int DESCRIPTION_HEIGHT = 5; // Main window /** Total required height is: * top frame line: + 1 * height of title window: + TITLE_HEIGHT * line after the title: + 1 * line with active/passive bionic captions: + 1 * height of the biggest list of active/passive bionics: + bionic_count * line before bionic description: + 1 * height of description window: + DESCRIPTION_HEIGHT * bottom frame line: + 1 * TOTAL: TITLE_HEIGHT + bionic_count + DESCRIPTION_HEIGHT + 5 */ int HEIGHT = std::min(TERMY, std::max(FULL_SCREEN_HEIGHT, TITLE_HEIGHT + bionic_count + DESCRIPTION_HEIGHT + 5)); int WIDTH = FULL_SCREEN_WIDTH + (TERMX - FULL_SCREEN_WIDTH) / 2; int START_X = (TERMX - WIDTH) / 2; int START_Y = (TERMY - HEIGHT) / 2; WINDOW *wBio = newwin(HEIGHT, WIDTH, START_Y, START_X); // Description window @ the bottom of the bio window int DESCRIPTION_START_Y = START_Y + HEIGHT - DESCRIPTION_HEIGHT - 1; int DESCRIPTION_LINE_Y = DESCRIPTION_START_Y - START_Y - 1; WINDOW *w_description = newwin(DESCRIPTION_HEIGHT, WIDTH - 2, DESCRIPTION_START_Y, START_X + 1); // Title window int TITLE_START_Y = START_Y + 1; int HEADER_LINE_Y = TITLE_HEIGHT + 1; // + lines with text in titlebar, local WINDOW *w_title = newwin(TITLE_HEIGHT, WIDTH - 2, TITLE_START_Y, START_X + 1); int scroll_position = 0; int second_column = 32 + (TERMX - FULL_SCREEN_WIDTH) / 4; // X-coordinate of the list of active bionics input_context ctxt("BIONICS"); ctxt.register_updown(); ctxt.register_action("ANY_INPUT"); ctxt.register_action("TOOGLE_EXAMINE"); ctxt.register_action("REASSIGN"); ctxt.register_action("REMOVE"); ctxt.register_action("HELP_KEYBINDINGS"); bool redraw = true; std::string menu_mode = "activating"; while(true) { // offset for display: bionic with index i is drawn at y=list_start_y+i // drawing the bionics starts with bionic[scroll_position] const int list_start_y = HEADER_LINE_Y + 2 - scroll_position; int max_scroll_position = HEADER_LINE_Y + 2 + bionic_count - ((menu_mode == "examining") ? DESCRIPTION_LINE_Y : (HEIGHT - 1)); if(redraw) { redraw = false; werase(wBio); draw_border(wBio); // Draw line under title mvwhline(wBio, HEADER_LINE_Y, 1, LINE_OXOX, WIDTH - 2); // Draw symbols to connect additional lines to border mvwputch(wBio, HEADER_LINE_Y, 0, BORDER_COLOR, LINE_XXXO); // |- mvwputch(wBio, HEADER_LINE_Y, WIDTH - 1, BORDER_COLOR, LINE_XOXX); // -| // Captions mvwprintz(wBio, HEADER_LINE_Y + 1, 2, c_ltblue, _("Passive:")); mvwprintz(wBio, HEADER_LINE_Y + 1, second_column, c_ltblue, _("Active:")); draw_exam_window(wBio, DESCRIPTION_LINE_Y, menu_mode == "examining"); nc_color type; if (passive.empty()) { mvwprintz(wBio, list_start_y, 2, c_ltgray, _("None")); } else { for (size_t i = scroll_position; i < passive.size(); i++) { if (list_start_y + static_cast<int>(i) == (menu_mode == "examining" ? DESCRIPTION_LINE_Y : HEIGHT - 1)) { break; } if (bionics[passive[i]->id]->power_source) { type = c_ltcyan; } else { type = c_cyan; } mvwprintz(wBio, list_start_y + i, 2, type, "%c %s", passive[i]->invlet, bionics[passive[i]->id]->name.c_str()); } } if (active.empty()) { mvwprintz(wBio, list_start_y, second_column, c_ltgray, _("None")); } else { for (size_t i = scroll_position; i < active.size(); i++) { if (list_start_y + static_cast<int>(i) == (menu_mode == "examining" ? DESCRIPTION_LINE_Y : HEIGHT - 1)) { break; } if (active[i]->powered && !bionics[active[i]->id]->power_source) { type = c_red; } else if (bionics[active[i]->id]->power_source && !active[i]->powered) { type = c_ltcyan; } else if (bionics[active[i]->id]->power_source && active[i]->powered) { type = c_ltgreen; } else { type = c_ltred; } mvwputch(wBio, list_start_y + i, second_column, type, active[i]->invlet); mvwprintz(wBio, list_start_y + i, second_column + 2, type, (active[i]->powered ? _("%s - ON") : _("%s - %d PU / %d turns")), bionics[active[i]->id]->name.c_str(), bionics[active[i]->id]->power_cost, bionics[active[i]->id]->charge_time); } } // Scrollbar if(scroll_position > 0) { mvwputch(wBio, HEADER_LINE_Y + 2, 0, c_ltgreen, '^'); } if(scroll_position < max_scroll_position && max_scroll_position > 0) { mvwputch(wBio, (menu_mode == "examining" ? DESCRIPTION_LINE_Y : HEIGHT - 1) - 1, 0, c_ltgreen, 'v'); } } wrefresh(wBio); show_bionics_titlebar(w_title, this, menu_mode); const std::string action = ctxt.handle_input(); const long ch = ctxt.get_raw_input().get_first_input(); bionic *tmp = NULL; if (menu_mode == "reassigning") { menu_mode = "activating"; tmp = bionic_by_invlet(ch); if(tmp == 0) { // Selected an non-existing bionic (or escape, or ...) continue; } redraw = true; const char newch = popup_getkey(_("%s; enter new letter."), bionics[tmp->id]->name.c_str()); wrefresh(wBio); if(newch == ch || newch == ' ' || newch == KEY_ESCAPE) { continue; } bionic *otmp = bionic_by_invlet(newch); // if there is already a bionic with the new invlet, the invlet // is considered valid. if(otmp == 0 && inv_chars.find(newch) == std::string::npos) { // TODO separate list of letters for bionics popup(_("%c is not a valid inventory letter."), newch); continue; } if(otmp != 0) { std::swap(tmp->invlet, otmp->invlet); } else { tmp->invlet = newch; } // TODO: show a message like when reassigning a key to an item? } else if (action == "DOWN") { if(scroll_position < max_scroll_position) { scroll_position++; redraw = true; } } else if (action == "UP") { if(scroll_position > 0) { scroll_position--; redraw = true; } } else if (action == "REASSIGN") { menu_mode = "reassigning"; } else if (action == "TOOGLE_EXAMINE") { // switches between activation and examination menu_mode = menu_mode == "activating" ? "examining" : "activating"; werase(w_description); draw_exam_window(wBio, DESCRIPTION_LINE_Y, false); redraw = true; } else if (action == "REMOVE") { menu_mode = "removing"; redraw = true; } else if (action == "HELP_KEYBINDINGS") { redraw = true; } else { tmp = bionic_by_invlet(ch); if(tmp == 0) { // entered a key that is not mapped to any bionic, // -> leave screen break; } const std::string &bio_id = tmp->id; const bionic_data &bio_data = *bionics[bio_id]; if (menu_mode == "removing") { uninstall_bionic(bio_id); break; } if (menu_mode == "activating") { if (bio_data.activated) { itype_id weapon_id = weapon.type->id; int b = tmp - &my_bionics[0]; if (tmp->powered) { tmp->powered = false; add_msg(m_neutral, _("%s powered off."), bio_data.name.c_str()); deactivate_bionic(b); } else if (power_level >= bio_data.power_cost || (weapon_id == "bio_claws_weapon" && bio_id == "bio_claws_weapon") || (weapon_id == "bio_blade_weapon" && bio_id == "bio_blade_weapon")) { // this will clear the bionics menu for targeting purposes werase(wBio); wrefresh(wBio); delwin(w_title); delwin(w_description); delwin(wBio); g->draw(); activate_bionic(b); if (bio_id == "bio_cqb") { pick_style(); } } else { popup( _( "You don't have enough power to activate the %s." ), bio_data.name.c_str() ); redraw = true; continue; } // Action done, leave screen break; } else { popup(_("\ You can not activate %s! To read a description of \ %s, press '!', then '%c'."), bio_data.name.c_str(), bio_data.name.c_str(), tmp->invlet); redraw = true; } } if (menu_mode == "examining") { // Describing bionics, not activating them! draw_exam_window(wBio, DESCRIPTION_LINE_Y, true); // Clear the lines first werase(w_description); fold_and_print(w_description, 0, 0, WIDTH - 2, c_ltblue, bio_data.description); wrefresh(w_description); } } } //if we activated a bionic, already killed the windows if(!(menu_mode == "activating")) { werase(wBio); wrefresh(wBio); delwin(w_title); delwin(w_description); delwin(wBio); } }
void safemode::test_pattern( const int tab_in, const int row_in ) { std::vector<std::string> creature_list; auto &temp_rules = ( tab_in == GLOBAL_TAB ) ? global_rules : character_rules; if( temp_rules[row_in].rule.empty() ) { return; } if( g->u.name.empty() ) { popup( _( "No monsters loaded. Please start a game first." ) ); return; } //Loop through all monster mtypes for( const auto &mtype : MonsterGenerator::generator().get_all_mtypes() ) { std::string creature_name = mtype.nname(); if( wildcard_match( creature_name, temp_rules[row_in].rule ) ) { creature_list.push_back( creature_name ); } } const int offset_x = 15 + ( ( TERMX > FULL_SCREEN_WIDTH ) ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ); const int offset_y = 5 + ( ( TERMY > FULL_SCREEN_HEIGHT ) ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0 ); int start_pos = 0; const int content_height = FULL_SCREEN_HEIGHT - 8; const int content_width = FULL_SCREEN_WIDTH - 30; const catacurses::window w_test_rule_border = catacurses::newwin( content_height + 2, content_width, offset_y, offset_x ); const catacurses::window w_test_rule_content = catacurses::newwin( content_height, content_width - 2, 1 + offset_y, 1 + offset_x ); int nmatch = creature_list.size(); const std::string buf = string_format( ngettext( "%1$d monster matches: %2$s", "%1$d monsters match: %2$s", nmatch ), nmatch, temp_rules[row_in].rule.c_str() ); draw_border( w_test_rule_border, BORDER_COLOR, buf, hilite( c_white ) ); center_print( w_test_rule_border, content_height + 1, red_background( c_white ), _( "Lists monsters regardless of their attitude." ) ); wrefresh( w_test_rule_border ); int line = 0; input_context ctxt( "SAFEMODE_TEST" ); ctxt.register_updown(); ctxt.register_action( "QUIT" ); while( true ) { // Clear the lines for( int i = 0; i < content_height; i++ ) { for( int j = 0; j < 79; j++ ) { mvwputch( w_test_rule_content, i, j, c_black, ' ' ); } } calcStartPos( start_pos, line, content_height, creature_list.size() ); // display safe mode for( int i = start_pos; i < static_cast<int>( creature_list.size() ); i++ ) { if( i >= start_pos && i < start_pos + std::min( content_height, static_cast<int>( creature_list.size() ) ) ) { nc_color line_color = c_white; mvwprintz( w_test_rule_content, i - start_pos, 0, line_color, "%d", i + 1 ); mvwprintz( w_test_rule_content, i - start_pos, 4, line_color, "" ); wprintz( w_test_rule_content, c_yellow, ( line == i ) ? ">> " : " " ); wprintz( w_test_rule_content, ( line == i ) ? hilite( line_color ) : line_color, creature_list[i] ); } } wrefresh( w_test_rule_content ); const std::string action = ctxt.handle_input(); if( action == "DOWN" ) { line++; if( line >= static_cast<int>( creature_list.size() ) ) { line = 0; } } else if( action == "UP" ) { line--; if( line < 0 ) { line = creature_list.size() - 1; } } else { break; } } }
void testCtxt(long m, long p, long widthBound, long L, long r) { if (!noPrint) cout << "@testCtxt(m="<<m<<",p="<<p<<",depth="<<widthBound<< ",r="<<r<<")"; FHEcontext context(m,p,r); EncryptedArray ea(context); // Use G(X)=X for this ea object // Some arbitrary initial plaintext array vector<long> in(ea.size()); for (long i=0; i<ea.size(); i++) in[i] = i % p; // Setup generator-descriptors for the PAlgebra generators Vec<GenDescriptor> vec(INIT_SIZE, ea.dimension()); for (long i=0; i<ea.dimension(); i++) vec[i] = GenDescriptor(/*order=*/ea.sizeOfDimension(i), /*good=*/ ea.nativeDimension(i), /*genIdx=*/i); // Some default for the width-bound, if not provided if (widthBound<=0) widthBound = 1+log2((double)ea.size()); // Get the generator-tree structures and the corresponding hypercube GeneratorTrees trees; long cost = trees.buildOptimalTrees(vec, widthBound); if (!noPrint) { context.zMStar.printout(); cout << ": trees=" << trees << endl; cout << " cost =" << cost << endl; } // Vec<long> dims; // trees.getCubeDims(dims); // CubeSignature sig(dims); // 1/2 prime per level should be more or less enough, here we use 1 per layer if (L<=0) L = (1+trees.numLayers())*context.BPL(); buildModChain(context, /*nLevels=*/L, /*nDigits=*/3); if (!noPrint) cout << "**Using "<<L<<" and " << context.ctxtPrimes.card() << " Ctxt-primes\n"; // Generate a sk/pk pair FHESecKey secretKey(context); const FHEPubKey& publicKey = secretKey; secretKey.GenSecKey(); // A +-1/0 secret key Ctxt ctxt(publicKey); for (long cnt=0; cnt<3; cnt++) { resetAllTimers(); // Choose a random permutation Permut pi; randomPerm(pi, trees.getSize()); // Build a permutation network for pi PermNetwork net; net.buildNetwork(pi, trees); // make sure we have the key-switching matrices needed for this network addMatrices4Network(secretKey, net); // Apply the permutation pi to the plaintext vector<long> out1(ea.size()); vector<long> out2(ea.size()); applyPermToVec(out1, in, pi); // direct application // Encrypt plaintext array, then apply permutation network to ciphertext ea.encrypt(ctxt, publicKey, in); if (!noPrint) cout << " ** applying permutation network to ciphertext... " << flush; double t = GetTime(); net.applyToCtxt(ctxt, ea); // applying permutation netwrok t = GetTime() -t; if (!noPrint) cout << "done in " << t << " seconds" << endl; ea.decrypt(ctxt, secretKey, out2); if (out1==out2) cout << "GOOD\n"; else { cout << "************ BAD\n"; } // printAllTimers(); } }
void test_pattern(int iCurrentPage, int iCurrentLine) { std::vector<std::string> vMatchingItems; std::string sItemName = ""; if (vAutoPickupRules[iCurrentPage][iCurrentLine].sRule == "") { return; } //Loop through all itemfactory items //TODO: somehow generate damaged, fitting or container items for (std::vector<std::string>::iterator it = standard_itype_ids.begin(); it != standard_itype_ids.end(); ++it) { sItemName = item_controller->find_template(*it)->nname(1); if (vAutoPickupRules[iCurrentPage][iCurrentLine].bActive && auto_pickup_match(sItemName, vAutoPickupRules[iCurrentPage][iCurrentLine].sRule)) { vMatchingItems.push_back(sItemName); } } const int iOffsetX = 15 + ((TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0); const int iOffsetY = 5 + ((TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0); int iStartPos = 0; const int iContentHeight = FULL_SCREEN_HEIGHT - 8; const int iContentWidth = FULL_SCREEN_WIDTH - 30; std::stringstream sTemp; WINDOW *w_test_rule_border = newwin(iContentHeight + 2, iContentWidth, iOffsetY, iOffsetX); WINDOW *w_test_rule_content = newwin(iContentHeight, iContentWidth - 2, 1 + iOffsetY, 1 + iOffsetX); draw_border(w_test_rule_border); int nmatch = vMatchingItems.size(); std::string buf = string_format(ngettext("%1$d item matches: %2$s", "%1$d items match: %2$s", nmatch), nmatch, vAutoPickupRules[iCurrentPage][iCurrentLine].sRule.c_str()); mvwprintz(w_test_rule_border, 0, iContentWidth / 2 - utf8_width(buf.c_str()) / 2, hilite(c_white), "%s", buf.c_str()); mvwprintz(w_test_rule_border, iContentHeight + 1, 1, red_background(c_white), _("Won't display damaged, fits and can/bottle items")); wrefresh(w_test_rule_border); iCurrentLine = 0; input_context ctxt("AUTO_PICKUP_TEST"); ctxt.register_updown(); ctxt.register_action("QUIT"); while(true) { // Clear the lines for (int i = 0; i < iContentHeight; i++) { for (int j = 0; j < 79; j++) { mvwputch(w_test_rule_content, i, j, c_black, ' '); } } calcStartPos(iStartPos, iCurrentLine, iContentHeight, vMatchingItems.size()); // display auto pickup for (int i = iStartPos; i < vMatchingItems.size(); i++) { if (i >= iStartPos && i < iStartPos + ((iContentHeight > vMatchingItems.size()) ? vMatchingItems.size() : iContentHeight)) { nc_color cLineColor = c_white; sTemp.str(""); sTemp << i + 1; mvwprintz(w_test_rule_content, i - iStartPos, 0, cLineColor, "%s", sTemp.str().c_str()); mvwprintz(w_test_rule_content, i - iStartPos, 4, cLineColor, ""); if (iCurrentLine == i) { wprintz(w_test_rule_content, c_yellow, ">> "); } else { wprintz(w_test_rule_content, c_yellow, " "); } wprintz(w_test_rule_content, (iCurrentLine == i) ? hilite(cLineColor) : cLineColor, vMatchingItems[i].c_str()); } } wrefresh(w_test_rule_content); const std::string action = ctxt.handle_input(); if (action == "DOWN") { iCurrentLine++; if (iCurrentLine >= vMatchingItems.size()) { iCurrentLine = 0; } } else if (action == "UP") { iCurrentLine--; if (iCurrentLine < 0) { iCurrentLine = vMatchingItems.size() - 1; } } else { break; } } werase(w_test_rule_border); werase(w_test_rule_content); }
void color_manager::show_gui() { const int iHeaderHeight = 4; const int iContentHeight = FULL_SCREEN_HEIGHT - 2 - iHeaderHeight; const int iOffsetX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0; const int iOffsetY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0; std::vector<int> vLines; vLines.push_back(-1); vLines.push_back(48); const int iTotalCols = vLines.size(); WINDOW *w_colors_help = newwin((FULL_SCREEN_HEIGHT / 2) - 2, FULL_SCREEN_WIDTH * 3 / 4, 7 + iOffsetY + (FULL_SCREEN_HEIGHT / 2) / 2, iOffsetX + 19 / 2); WINDOW_PTR w_colors_helpptr( w_colors_help ); WINDOW *w_colors_border = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, iOffsetY, iOffsetX); WINDOW_PTR w_colors_borderptr( w_colors_border ); WINDOW *w_colors_header = newwin(iHeaderHeight, FULL_SCREEN_WIDTH - 2, 1 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_colors_headerptr( w_colors_header ); WINDOW *w_colors = newwin(iContentHeight, FULL_SCREEN_WIDTH - 2, iHeaderHeight + 1 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_colorsptr( w_colors ); draw_border(w_colors_border); mvwputch(w_colors_border, 3, 0, c_ltgray, LINE_XXXO); // |- mvwputch(w_colors_border, 3, 79, c_ltgray, LINE_XOXX); // -| for (int i = 0; i < 78; i++) { mvwputch(w_colors_header, 2, i, c_ltgray, LINE_OXOX); // Draw line under header } for( auto &iCol : vLines ) { if ( iCol > -1 ) { mvwputch(w_colors_border, FULL_SCREEN_HEIGHT - 1, iCol + 1, c_ltgray, LINE_XXOX); // _|_ mvwputch(w_colors_header, 2, iCol, c_ltgray, LINE_OXXX); mvwputch(w_colors_header, 3, iCol, c_ltgray, LINE_XOXO); } } mvwprintz(w_colors_border, 0, 32, c_ltred, _(" COLOR MANAGER ")); wrefresh(w_colors_border); int tmpx = 0; tmpx += shortcut_print(w_colors_header, 0, tmpx, c_white, c_ltgreen, _("<R>emove custom color")) + 2; tmpx += shortcut_print(w_colors_header, 0, tmpx, c_white, c_ltgreen, _("<Arrow Keys> To navigate")) + 2; tmpx += shortcut_print(w_colors_header, 0, tmpx, c_white, c_ltgreen, _("<Enter>-Edit")) + 2; shortcut_print(w_colors_header, 0, tmpx, c_white, c_ltgreen, _("Load <T>emplate")); mvwprintz(w_colors_header, 1, 0, c_white, _("Some color changes may require a restart.")); mvwprintz(w_colors_header, 3, 3, c_white, _("Colorname")); mvwprintz(w_colors_header, 3, 21, c_white, _("Normal")); mvwprintz(w_colors_header, 3, 52, c_white, _("Invert")); wrefresh(w_colors_header); int iCurrentLine = 0; int iCurrentCol = 1; int iStartPos = 0; const int iMaxColors = color_array.size(); bool bStuffChanged = false; input_context ctxt("COLORS"); ctxt.register_cardinal(); ctxt.register_action("CONFIRM"); ctxt.register_action("QUIT"); ctxt.register_action("REMOVE_CUSTOM"); ctxt.register_action("LOAD_TEMPLATE"); ctxt.register_action("HELP_KEYBINDINGS"); std::map<std::string, color_struct> name_color_map; for( const auto &pr : name_map ) { name_color_map[pr.first] = color_array[pr.second]; } while(true) { // Clear all lines for (int i = 0; i < iContentHeight; i++) { for (int j = 0; j < 79; j++) { mvwputch(w_colors, i, j, c_black, ' '); for( auto &iCol : vLines ) { if ( iCol == j ) { mvwputch(w_colors, i, j, c_ltgray, LINE_XOXO); } } } } calcStartPos(iStartPos, iCurrentLine, iContentHeight, iMaxColors); //Draw Scrollbar draw_scrollbar(w_colors_border, iCurrentLine, iContentHeight, iMaxColors, 5); auto iter = name_color_map.begin(); std::advance( iter, iStartPos ); std::string sActive = ""; // display colormanager for (int i=iStartPos; iter != name_color_map.end(); ++iter, ++i) { if (i >= iStartPos && i < iStartPos + ((iContentHeight > iMaxColors) ? iMaxColors : iContentHeight)) { auto &entry = iter->second; if (iCurrentLine == i) { sActive = iter->first; mvwprintz(w_colors, i - iStartPos, vLines[iCurrentCol-1] + 2, c_yellow, ">"); } mvwprintz(w_colors, i - iStartPos, 3, c_white, iter->first.c_str()); //colorname mvwprintz(w_colors, i - iStartPos, 21, entry.color, _("default")); //default color if ( !entry.name_custom.empty() ) { mvwprintz(w_colors, i - iStartPos, 30, name_color_map[entry.name_custom].color, entry.name_custom.c_str()); //custom color } mvwprintz(w_colors, i - iStartPos, 52, entry.invert, _("default")); //invert default color if ( !entry.name_invert_custom.empty() ) { mvwprintz(w_colors, i - iStartPos, 61, name_color_map[entry.name_invert_custom].color, entry.name_invert_custom.c_str()); //invert custom color } } } wrefresh(w_colors); const std::string action = ctxt.handle_input(); if (action == "QUIT") { break; } else if (action == "UP") { iCurrentLine--; if (iCurrentLine < 0) { iCurrentLine = iMaxColors - 1; } } else if (action == "DOWN") { iCurrentLine++; if (iCurrentLine >= (int)iMaxColors) { iCurrentLine = 0; } } else if (action == "LEFT") { iCurrentCol--; if (iCurrentCol < 1) { iCurrentCol = iTotalCols; } } else if (action == "RIGHT") { iCurrentCol++; if (iCurrentCol > iTotalCols) { iCurrentCol = 1; } } else if (action == "REMOVE_CUSTOM") { auto &entry = name_color_map[sActive]; if ( iCurrentCol == 1 && !entry.name_custom.empty() ) { bStuffChanged = true; entry.name_custom = ""; } else if ( iCurrentCol == 2 && !entry.name_invert_custom.empty() ) { bStuffChanged = true; entry.name_invert_custom = ""; } finalize(); // Need to recalculate caches } else if (action == "LOAD_TEMPLATE") { auto vFiles = get_files_from_path(".json", FILENAMES["color_templates"], false, true); if ( vFiles.size() > 0 ) { uimenu ui_templates; ui_templates.w_y = iHeaderHeight + 1 + iOffsetY; ui_templates.w_height = 18; ui_templates.return_invalid = true; ui_templates.text = _("Color templates:"); for ( const auto& filename : vFiles ) { ui_templates.addentry( filename.substr(filename.find_last_of("/") + 1) ); } ui_templates.addentry(std::string(_("Cancel"))); ui_templates.query(); if ( (size_t)ui_templates.ret < vFiles.size() ) { bStuffChanged = true; clear(); load_default(); load_custom(vFiles[ui_templates.ret]); name_color_map.clear(); for( const auto &pr : name_map ) { name_color_map[pr.first] = color_array[pr.second]; } } } finalize(); // Need to recalculate caches } else if (action == "CONFIRM") { uimenu ui_colors; ui_colors.w_y = iHeaderHeight + 1 + iOffsetY; ui_colors.w_height = 18; ui_colors.return_invalid = true; std::string sColorType = _("Normal"); std::string sSelected = name_color_map[sActive].name_custom; if ( iCurrentCol == 2 ) { sColorType = _("Invert"); sSelected = name_color_map[sActive].name_invert_custom; } ui_colors.text = string_format( _("Custom %s color:"), sColorType.c_str() ); int i = 0; for ( auto &iter : name_color_map ) { std::string sColor = iter.first; std::string sType = _("default"); std::string name_custom = ""; if ( sSelected == sColor ) { ui_colors.selected = i; } if ( !iter.second.name_custom.empty() ) { name_custom = " <color_" + iter.second.name_custom + ">" + iter.second.name_custom + "</color>"; } ui_colors.addentry(string_format( "%-17s <color_%s>%s</color>%s", iter.first.c_str(), sColor.c_str(), sType.c_str(), name_custom.c_str() ) ); i++; } ui_colors.addentry(std::string(_("Cancel"))); ui_colors.query(); if ( (size_t)ui_colors.ret < name_color_map.size() ) { bStuffChanged = true; iter = name_color_map.begin(); std::advance( iter, ui_colors.ret ); auto &entry = name_color_map[sActive]; if ( iCurrentCol == 1 ) { entry.name_custom = iter->first; } else if ( iCurrentCol == 2 ) { entry.name_invert_custom = iter->first; } } finalize(); // Need to recalculate caches } } if( bStuffChanged && query_yn(_("Save changes?") ) ) { for( const auto &pr : name_color_map ) { color_id id = name_to_id( pr.first ); color_array[id].name_custom = pr.second.name_custom; color_array[id].name_invert_custom = pr.second.name_invert_custom; } finalize(); save_custom(); clear(); load_default(); load_custom(); } }
void player::power_mutations() { if( !is_player() ) { // TODO: Implement NPCs activating muts return; } std::vector <std::string> passive; std::vector <std::string> active; for( auto &mut : my_mutations ) { if (!mutation_branch::get( mut.first ).activated) { passive.push_back(mut.first); } else { active.push_back(mut.first); } // New mutations are initialized with no key at all, so we have to do this here. if( mut.second.key == ' ' ) { for( const auto &letter : mutation_chars ) { if( trait_by_invlet( letter ).empty() ) { mut.second.key = letter; break; } } } } // maximal number of rows in both columns const int mutations_count = std::max(passive.size(), active.size()); int TITLE_HEIGHT = 2; int DESCRIPTION_HEIGHT = 5; // Main window /** Total required height is: * top frame line: + 1 * height of title window: + TITLE_HEIGHT * line after the title: + 1 * line with active/passive mutation captions: + 1 * height of the biggest list of active/passive mutations: + mutations_count * line before mutation description: + 1 * height of description window: + DESCRIPTION_HEIGHT * bottom frame line: + 1 * TOTAL: TITLE_HEIGHT + mutations_count + DESCRIPTION_HEIGHT + 5 */ int HEIGHT = std::min(TERMY, std::max(FULL_SCREEN_HEIGHT, TITLE_HEIGHT + mutations_count + DESCRIPTION_HEIGHT + 5)); int WIDTH = FULL_SCREEN_WIDTH + (TERMX - FULL_SCREEN_WIDTH) / 2; int START_X = (TERMX - WIDTH) / 2; int START_Y = (TERMY - HEIGHT) / 2; WINDOW *wBio = newwin(HEIGHT, WIDTH, START_Y, START_X); // Description window @ the bottom of the bio window int DESCRIPTION_START_Y = START_Y + HEIGHT - DESCRIPTION_HEIGHT - 1; int DESCRIPTION_LINE_Y = DESCRIPTION_START_Y - START_Y - 1; WINDOW *w_description = newwin(DESCRIPTION_HEIGHT, WIDTH - 2, DESCRIPTION_START_Y, START_X + 1); // Title window int TITLE_START_Y = START_Y + 1; int HEADER_LINE_Y = TITLE_HEIGHT + 1; // + lines with text in titlebar, local WINDOW *w_title = newwin(TITLE_HEIGHT, WIDTH - 2, TITLE_START_Y, START_X + 1); int scroll_position = 0; int second_column = 32 + (TERMX - FULL_SCREEN_WIDTH) / 4; // X-coordinate of the list of active mutations input_context ctxt("MUTATIONS"); ctxt.register_updown(); ctxt.register_action("ANY_INPUT"); ctxt.register_action("TOGGLE_EXAMINE"); ctxt.register_action("REASSIGN"); ctxt.register_action("HELP_KEYBINDINGS"); bool redraw = true; std::string menu_mode = "activating"; while(true) { // offset for display: mutation with index i is drawn at y=list_start_y+i // drawing the mutation starts with mutation[scroll_position] const int list_start_y = HEADER_LINE_Y + 2 - scroll_position; int max_scroll_position = HEADER_LINE_Y + 2 + mutations_count - ((menu_mode == "examining") ? DESCRIPTION_LINE_Y : (HEIGHT - 1)); if(redraw) { redraw = false; werase(wBio); draw_border(wBio); // Draw line under title mvwhline(wBio, HEADER_LINE_Y, 1, LINE_OXOX, WIDTH - 2); // Draw symbols to connect additional lines to border mvwputch(wBio, HEADER_LINE_Y, 0, BORDER_COLOR, LINE_XXXO); // |- mvwputch(wBio, HEADER_LINE_Y, WIDTH - 1, BORDER_COLOR, LINE_XOXX); // -| // Captions mvwprintz(wBio, HEADER_LINE_Y + 1, 2, c_ltblue, _("Passive:")); mvwprintz(wBio, HEADER_LINE_Y + 1, second_column, c_ltblue, _("Active:")); draw_exam_window(wBio, DESCRIPTION_LINE_Y, menu_mode == "examining"); nc_color type; if (passive.empty()) { mvwprintz(wBio, list_start_y, 2, c_ltgray, _("None")); } else { for (size_t i = scroll_position; i < passive.size(); i++) { const auto &md = mutation_branch::get( passive[i] ); const auto &td = my_mutations[passive[i]]; if (list_start_y + static_cast<int>(i) == (menu_mode == "examining" ? DESCRIPTION_LINE_Y : HEIGHT - 1)) { break; } type = c_cyan; mvwprintz(wBio, list_start_y + i, 2, type, "%c %s", td.key, md.name.c_str()); } } if (active.empty()) { mvwprintz(wBio, list_start_y, second_column, c_ltgray, _("None")); } else { for (size_t i = scroll_position; i < active.size(); i++) { const auto &md = mutation_branch::get( active[i] ); const auto &td = my_mutations[active[i]]; if (list_start_y + static_cast<int>(i) == (menu_mode == "examining" ? DESCRIPTION_LINE_Y : HEIGHT - 1)) { break; } if (!td.powered) { type = c_red; }else if (td.powered) { type = c_ltgreen; } else { type = c_ltred; } // TODO: track resource(s) used and specify mvwputch( wBio, list_start_y + i, second_column, type, td.key ); std::stringstream mut_desc; mut_desc << md.name; if ( md.cost > 0 && md.cooldown > 0 ) { mut_desc << string_format( _(" - %d RU / %d turns"), md.cost, md.cooldown ); } else if ( md.cost > 0 ) { mut_desc << string_format( _(" - %d RU"), md.cost ); } else if ( md.cooldown > 0 ) { mut_desc << string_format( _(" - %d turns"), md.cooldown ); } if ( td.powered ) { mut_desc << _(" - Active"); } mvwprintz( wBio, list_start_y + i, second_column + 2, type, mut_desc.str().c_str() ); } } // Scrollbar if(scroll_position > 0) { mvwputch(wBio, HEADER_LINE_Y + 2, 0, c_ltgreen, '^'); } if(scroll_position < max_scroll_position && max_scroll_position > 0) { mvwputch(wBio, (menu_mode == "examining" ? DESCRIPTION_LINE_Y : HEIGHT - 1) - 1, 0, c_ltgreen, 'v'); } } wrefresh(wBio); show_mutations_titlebar(w_title, this, menu_mode); const std::string action = ctxt.handle_input(); const long ch = ctxt.get_raw_input().get_first_input(); if (menu_mode == "reassigning") { menu_mode = "activating"; const auto mut_id = trait_by_invlet( ch ); if( mut_id.empty() ) { // Selected an non-existing mutation (or escape, or ...) continue; } redraw = true; const long newch = popup_getkey(_("%s; enter new letter."), mutation_branch::get_name( mut_id ).c_str()); wrefresh(wBio); if(newch == ch || newch == ' ' || newch == KEY_ESCAPE) { continue; } if( !mutation_chars.valid( newch ) ) { popup( _("Invalid mutation letter. Only those characters are valid:\n\n%s"), mutation_chars.get_allowed_chars().c_str() ); continue; } const auto other_mut_id = trait_by_invlet( newch ); if( !other_mut_id.empty() ) { std::swap(my_mutations[mut_id].key, my_mutations[other_mut_id].key); } else { my_mutations[mut_id].key = newch; } // TODO: show a message like when reassigning a key to an item? } else if (action == "DOWN") { if(scroll_position < max_scroll_position) { scroll_position++; redraw = true; } } else if (action == "UP") { if(scroll_position > 0) { scroll_position--; redraw = true; } } else if (action == "REASSIGN") { menu_mode = "reassigning"; } else if (action == "TOGGLE_EXAMINE") { // switches between activation and examination menu_mode = menu_mode == "activating" ? "examining" : "activating"; werase(w_description); draw_exam_window(wBio, DESCRIPTION_LINE_Y, false); redraw = true; }else if (action == "HELP_KEYBINDINGS") { redraw = true; } else { const auto mut_id = trait_by_invlet( ch ); if( mut_id.empty() ) { // entered a key that is not mapped to any mutation, // -> leave screen break; } const auto &mut_data = mutation_branch::get( mut_id ); if (menu_mode == "activating") { if (mut_data.activated) { if (my_mutations[mut_id].powered) { add_msg_if_player(m_neutral, _("You stop using your %s."), mut_data.name.c_str()); deactivate_mutation( mut_id ); delwin(w_title); delwin(w_description); delwin(wBio); // Action done, leave screen break; } else if( (!mut_data.hunger || get_hunger() <= 400) && (!mut_data.thirst || get_thirst() <= 400) && (!mut_data.fatigue || get_fatigue() <= 400) ) { // this will clear the mutations menu for targeting purposes werase(wBio); wrefresh(wBio); delwin(w_title); delwin(w_description); delwin(wBio); g->draw(); add_msg_if_player( m_neutral, _("You activate your %s."), mut_data.name.c_str() ); activate_mutation( mut_id ); // Action done, leave screen break; } else { popup( _( "You don't have enough in you to activate your %s!" ), mut_data.name.c_str() ); redraw = true; continue; } } else { popup(_("\ You cannot activate %s! To read a description of \ %s, press '!', then '%c'."), mut_data.name.c_str(), mut_data.name.c_str(), my_mutations[mut_id].key ); redraw = true; } } if (menu_mode == "examining") { // Describing mutations, not activating them! draw_exam_window(wBio, DESCRIPTION_LINE_Y, true); // Clear the lines first werase(w_description); fold_and_print(w_description, 0, 0, WIDTH - 2, c_ltblue, mut_data.description); wrefresh(w_description); } } } //if we activated a mutation, already killed the windows if(!(menu_mode == "activating")) { werase(wBio); wrefresh(wBio); delwin(w_title); delwin(w_description); delwin(wBio); } }
const recipe *select_crafting_recipe( int &batch_size ) { if( normalized_names.empty() ) { translate_all(); } const int headHeight = 3; const int subHeadHeight = 2; const int freeWidth = TERMX - FULL_SCREEN_WIDTH; bool isWide = ( TERMX > FULL_SCREEN_WIDTH && freeWidth > 15 ); const int width = isWide ? ( freeWidth > FULL_SCREEN_WIDTH ? FULL_SCREEN_WIDTH * 2 : TERMX ) : FULL_SCREEN_WIDTH; const int wStart = ( TERMX - width ) / 2; const int tailHeight = isWide ? 3 : 4; const int dataLines = TERMY - ( headHeight + subHeadHeight ) - tailHeight; const int dataHalfLines = dataLines / 2; const int dataHeight = TERMY - ( headHeight + subHeadHeight ); const int infoWidth = width - FULL_SCREEN_WIDTH - 1; const recipe *last_recipe = nullptr; WINDOW *w_head = newwin( headHeight, width, 0, wStart ); WINDOW_PTR w_head_ptr( w_head ); WINDOW *w_subhead = newwin( subHeadHeight, width, 3, wStart ); WINDOW_PTR w_subhead_ptr( w_subhead ); WINDOW *w_data = newwin( dataHeight, width, headHeight + subHeadHeight, wStart ); WINDOW_PTR w_data_ptr( w_data ); int item_info_x = infoWidth; int item_info_y = dataHeight - 3; int item_info_width = wStart + width - infoWidth; int item_info_height = headHeight + subHeadHeight; if( !isWide ) { item_info_x = 1; item_info_y = 1; item_info_width = 1; item_info_height = 1; } WINDOW *w_iteminfo = newwin( item_info_y, item_info_x, item_info_height, item_info_width ); WINDOW_PTR w_iteminfo_ptr( w_iteminfo ); list_circularizer<std::string> tab( craft_cat_list ); list_circularizer<std::string> subtab( craft_subcat_list[tab.cur()] ); std::vector<const recipe *> current; std::vector<bool> available; const int componentPrintHeight = dataHeight - tailHeight - 1; //preserves component color printout between mode rotations nc_color rotated_color = c_white; int previous_item_line = -1; std::string previous_tab = ""; std::string previous_subtab = ""; item tmp; int line = 0, ypos, scroll_pos = 0; bool redraw = true; bool keepline = false; bool done = false; bool batch = false; int batch_line = 0; int display_mode = 0; const recipe *chosen = NULL; std::vector<iteminfo> thisItem, dummy; input_context ctxt( "CRAFTING" ); ctxt.register_cardinal(); ctxt.register_action( "QUIT" ); ctxt.register_action( "CONFIRM" ); ctxt.register_action( "CYCLE_MODE" ); ctxt.register_action( "SCROLL_UP" ); ctxt.register_action( "SCROLL_DOWN" ); ctxt.register_action( "PREV_TAB" ); ctxt.register_action( "NEXT_TAB" ); ctxt.register_action( "FILTER" ); ctxt.register_action( "RESET_FILTER" ); ctxt.register_action( "HELP_RECIPE" ); ctxt.register_action( "HELP_KEYBINDINGS" ); ctxt.register_action( "CYCLE_BATCH" ); const inventory &crafting_inv = g->u.crafting_inventory(); const std::vector<npc *> helpers = g->u.get_crafting_helpers(); std::string filterstring = ""; const auto &available_recipes = g->u.get_available_recipes( crafting_inv, &helpers ); std::map<const recipe *, bool> availability_cache; do { if( redraw ) { // When we switch tabs, redraw the header redraw = false; if( ! keepline ) { line = 0; } else { keepline = false; } if( display_mode > 2 ) { display_mode = 2; } TAB_MODE m = ( batch ) ? BATCH : ( filterstring == "" ) ? NORMAL : FILTERED; draw_recipe_tabs( w_head, tab.cur(), m ); draw_recipe_subtabs( w_subhead, tab.cur(), subtab.cur(), m ); available.clear(); if( batch ) { current.clear(); for( int i = 1; i <= 20; i++ ) { current.push_back( chosen ); available.push_back( chosen->requirements().can_make_with_inventory( crafting_inv, i ) ); } } else { if( filterstring.empty() ) { current = available_recipes.in_category( tab.cur(), subtab.cur() != "CSC_ALL" ? subtab.cur() : "" ); } else { auto qry = trim( filterstring ); if( qry.size() > 2 && qry[1] == ':' ) { switch( qry[0] ) { case 't': current = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::tool ); break; case 'c': current = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::component ); break; case 's': current = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::skill ); break; case 'q': current = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::quality ); break; case 'Q': current = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::quality_result ); break; default: current.clear(); } } else { current = available_recipes.search( qry ); } } available.reserve( current.size() ); // cache recipe availability on first display for( const auto e : current ) { if( !availability_cache.count( e ) ) { availability_cache.emplace( e, e->requirements().can_make_with_inventory( crafting_inv ) ); } } std::stable_sort( current.begin(), current.end(), []( const recipe * a, const recipe * b ) { return b->difficulty < a->difficulty; } ); std::stable_sort( current.begin(), current.end(), [&]( const recipe * a, const recipe * b ) { return availability_cache[a] && !availability_cache[b]; } ); std::transform( current.begin(), current.end(), std::back_inserter( available ), [&]( const recipe * e ) { return availability_cache[e]; } ); } // current/available have been rebuilt, make sure our cursor is still in range if( current.empty() ) { line = 0; } else { line = std::min( line, ( int )current.size() - 1 ); } } // Clear the screen of recipe data, and draw it anew werase( w_data ); if( isWide ) { werase( w_iteminfo ); } if( isWide ) { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "Press <ENTER> to attempt to craft object." ) ); wprintz( w_data, c_white, " " ); if( filterstring != "" ) { wprintz( w_data, c_white, _( "[E]: Describe, [F]ind, [R]eset, [m]ode, %s [?] keybindings" ), ( batch ) ? _( "cancel [b]atch" ) : _( "[b]atch" ) ); } else { wprintz( w_data, c_white, _( "[E]: Describe, [F]ind, [m]ode, %s [?] keybindings" ), ( batch ) ? _( "cancel [b]atch" ) : _( "[b]atch" ) ); } } else { if( filterstring != "" ) { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "[E]: Describe, [F]ind, [R]eset, [m]ode, [b]atch [?] keybindings" ) ); } else { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "[E]: Describe, [F]ind, [m]ode, [b]atch [?] keybindings" ) ); } mvwprintz( w_data, dataLines + 2, 5, c_white, _( "Press <ENTER> to attempt to craft object." ) ); } // Draw borders for( int i = 1; i < width - 1; ++i ) { // _ mvwputch( w_data, dataHeight - 1, i, BORDER_COLOR, LINE_OXOX ); } for( int i = 0; i < dataHeight - 1; ++i ) { // | mvwputch( w_data, i, 0, BORDER_COLOR, LINE_XOXO ); mvwputch( w_data, i, width - 1, BORDER_COLOR, LINE_XOXO ); } mvwputch( w_data, dataHeight - 1, 0, BORDER_COLOR, LINE_XXOO ); // _| mvwputch( w_data, dataHeight - 1, width - 1, BORDER_COLOR, LINE_XOOX ); // |_ int recmin = 0, recmax = current.size(); if( recmax > dataLines ) { if( line <= recmin + dataHalfLines ) { for( int i = recmin; i < recmin + dataLines; ++i ) { std::string tmp_name = item::nname( current[i]->result ); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, i - recmin, 2, c_dkgray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, i - recmin, 2, ( available[i] ? h_white : h_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, i - recmin, 2, ( available[i] ? c_white : c_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } else if( line >= recmax - dataHalfLines ) { for( int i = recmax - dataLines; i < recmax; ++i ) { std::string tmp_name = item::nname( current[i]->result ); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, dataLines + i - recmax, 2, c_ltgray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, dataLines + i - recmax, 2, ( available[i] ? h_white : h_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, dataLines + i - recmax, 2, ( available[i] ? c_white : c_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } else { for( int i = line - dataHalfLines; i < line - dataHalfLines + dataLines; ++i ) { std::string tmp_name = item::nname( current[i]->result ); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, dataHalfLines + i - line, 2, c_ltgray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, dataHalfLines + i - line, 2, ( available[i] ? h_white : h_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, dataHalfLines + i - line, 2, ( available[i] ? c_white : c_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } } else { for( size_t i = 0; i < current.size() && i < ( size_t )dataHeight + 1; ++i ) { std::string tmp_name = item::nname( current[i]->result ); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), ( int )i + 1, tmp_name.c_str() ); } if( ( int )i == line ) { mvwprintz( w_data, i, 2, ( available[i] ? h_white : h_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, i, 2, ( available[i] ? c_white : c_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } if( !current.empty() ) { int pane = FULL_SCREEN_WIDTH - 30 - 1; int count = batch ? line + 1 : 1; // batch size nc_color col = available[ line ] ? c_white : c_ltgray; const auto &req = current[ line ]->requirements(); draw_can_craft_indicator( w_head, 0, *current[line] ); wrefresh( w_head ); ypos = 0; std::vector<std::string> component_print_buffer; auto tools = req.get_folded_tools_list( pane, col, crafting_inv, count ); auto comps = req.get_folded_components_list( pane, col, crafting_inv, count ); component_print_buffer.insert( component_print_buffer.end(), tools.begin(), tools.end() ); component_print_buffer.insert( component_print_buffer.end(), comps.begin(), comps.end() ); if( !g->u.knows_recipe( current[line] ) ) { component_print_buffer.push_back( _( "Recipe not memorized yet" ) ); } //handle positioning of component list if it needed to be scrolled int componentPrintOffset = 0; if( display_mode > 2 ) { componentPrintOffset = ( display_mode - 2 ) * componentPrintHeight; } if( component_print_buffer.size() < static_cast<size_t>( componentPrintOffset ) ) { componentPrintOffset = 0; if( previous_tab != tab.cur() || previous_subtab != subtab.cur() || previous_item_line != line ) { display_mode = 2; } else { display_mode = 0; } } //only used to preserve mode position on components when //moving to another item and the view is already scrolled previous_tab = tab.cur(); previous_subtab = subtab.cur(); previous_item_line = line; if( display_mode == 0 ) { mvwprintz( w_data, ypos++, 30, col, _( "Skills used: %s" ), ( !current[line]->skill_used ? _( "N/A" ) : current[line]->skill_used.obj().name().c_str() ) ); mvwprintz( w_data, ypos++, 30, col, _( "Required skills: %s" ), ( current[line]->required_skills_string().c_str() ) ); mvwprintz( w_data, ypos++, 30, col, _( "Difficulty: %d" ), current[ line ]->difficulty ); if( !current[line]->skill_used ) { mvwprintz( w_data, ypos++, 30, col, _( "Your skill level: N/A" ) ); } else { mvwprintz( w_data, ypos++, 30, col, _( "Your skill level: %d" ), // Macs don't seem to like passing this as a class, so force it to int ( int )g->u.get_skill_level( current[line]->skill_used ) ); } ypos += current[line]->print_time( w_data, ypos, 30, pane, col, count ); mvwprintz( w_data, ypos++, 30, col, _( "Dark craftable? %s" ), current[line]->has_flag( "BLIND_EASY" ) ? _( "Easy" ) : current[line]->has_flag( "BLIND_HARD" ) ? _( "Hard" ) : _( "Impossible" ) ); ypos += current[line]->print_items( w_data, ypos, 30, col, ( batch ) ? line + 1 : 1 ); } //color needs to be preserved in case part of the previous page was cut off nc_color stored_color = col; if( display_mode > 2 ) { stored_color = rotated_color; } else { rotated_color = col; } int components_printed = 0; for( size_t i = static_cast<size_t>( componentPrintOffset ); i < component_print_buffer.size(); i++ ) { if( ypos >= componentPrintHeight ) { break; } components_printed++; print_colored_text( w_data, ypos++, 30, stored_color, col, component_print_buffer[i] ); } if( ypos >= componentPrintHeight && component_print_buffer.size() > static_cast<size_t>( components_printed ) ) { mvwprintz( w_data, ypos++, 30, col, _( "v (more)" ) ); rotated_color = stored_color; } if( isWide ) { if( last_recipe != current[line] ) { last_recipe = current[line]; tmp = current[line]->create_result(); tmp.info( true, thisItem ); } draw_item_info( w_iteminfo, tmp.tname(), tmp.type_name(), thisItem, dummy, scroll_pos, true, true, true, false, true ); } } draw_scrollbar( w_data, line, dataLines, recmax, 0 ); wrefresh( w_data ); if( isWide ) { wrefresh( w_iteminfo ); } const std::string action = ctxt.handle_input(); if( action == "CYCLE_MODE" ) { display_mode = display_mode + 1; if( display_mode <= 0 ) { display_mode = 0; } } else if( action == "LEFT" ) { subtab.prev(); redraw = true; } else if( action == "SCROLL_UP" ) { scroll_pos--; } else if( action == "SCROLL_DOWN" ) { scroll_pos++; } else if( action == "PREV_TAB" ) { tab.prev(); subtab = list_circularizer<std::string>( craft_subcat_list[tab.cur()] );//default ALL redraw = true; } else if( action == "RIGHT" ) { subtab.next(); redraw = true; } else if( action == "NEXT_TAB" ) { tab.next(); subtab = list_circularizer<std::string>( craft_subcat_list[tab.cur()] );//default ALL redraw = true; } else if( action == "DOWN" ) { line++; } else if( action == "UP" ) { line--; } else if( action == "CONFIRM" ) { if( available.empty() || !available[line] ) { popup( _( "You can't do that!" ) ); } else if( !current[line]->check_eligible_containers_for_crafting( ( batch ) ? line + 1 : 1 ) ) { ; // popup is already inside check } else { chosen = current[line]; batch_size = ( batch ) ? line + 1 : 1; done = true; } } else if( action == "HELP_RECIPE" ) { if( current.empty() ) { popup( _( "Nothing selected!" ) ); redraw = true; continue; } tmp = current[line]->create_result(); full_screen_popup( "%s\n%s", tmp.type_name( 1 ).c_str(), tmp.info( true ).c_str() ); redraw = true; keepline = true; } else if( action == "FILTER" ) { filterstring = string_input_popup( _( "Search:" ), 85, filterstring, _( "Special prefixes for requirements:\n" " [t] search tools\n" " [c] search components\n" " [q] search qualities\n" " [s] search skills\n" "Special prefixes for results:\n" " [Q] search qualities\n" "Examples:\n" " t:soldering iron\n" " c:two by four\n" " q:metal sawing\n" " s:cooking\n" " Q:fine bolt turning" ) ); redraw = true; } else if( action == "QUIT" ) { chosen = nullptr; done = true; } else if( action == "RESET_FILTER" ) { filterstring = ""; redraw = true; } else if( action == "CYCLE_BATCH" ) { if( current.empty() ) { popup( _( "Nothing selected!" ) ); redraw = true; continue; } batch = !batch; if( batch ) { batch_line = line; chosen = current[batch_line]; } else { line = batch_line; keepline = true; } redraw = true; } if( line < 0 ) { line = current.size() - 1; } else if( line >= ( int )current.size() ) { line = 0; } } while( !done ); return chosen; }
robot_finds_kitten::robot_finds_kitten( const catacurses::window &w ) { #ifdef __ANDROID__ input_context ctxt( "IUSE_SOFTWARE_KITTEN" ); #endif ret = false; char ktile[83] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#&()*+./:;=?![]{|}y"; int used_messages[MAXMESSAGES]; rfkLINES = 20; rfkCOLS = 60; const int numbogus = 20; nummessages = 201; empty.x = -1; empty.y = -1; empty.color = nc_color(); empty.character = ' '; for( int c = 0; c < rfkCOLS; c++ ) { for( int c2 = 0; c2 < rfkLINES; c2++ ) { rfkscreen[c][c2] = EMPTY; } } /* Create an array to ensure we don't get duplicate messages. */ for( int c = 0; c < nummessages; c++ ) { used_messages[c] = 0; bogus_messages[c] = 0; bogus[c] = empty; } /* Now we initialize the various game OBJECTs. * Assign a position to the player. */ robot.x = rand() % rfkCOLS; robot.y = rand() % ( rfkLINES - 3 ) + 3; robot.character = '#'; robot.color = c_white; rfkscreen[robot.x][robot.y] = ROBOT; /* Assign the kitten a unique position. */ do { kitten.x = rand() % rfkCOLS; kitten.y = rand() % ( rfkLINES - 3 ) + 3; } while( rfkscreen[kitten.x][kitten.y] != EMPTY ); /* Assign the kitten a character and a color. */ do { kitten.character = ktile[rand() % 82]; } while( kitten.character == '#' || kitten.character == ' ' ); do { kitten.color = all_colors.get_random(); } while( kitten.color == c_black ); rfkscreen[kitten.x][kitten.y] = KITTEN; /* Now, initialize non-kitten OBJECTs. */ for( int c = 0; c < numbogus; c++ ) { /* Assign a unique position. */ do { bogus[c].x = rand() % rfkCOLS; bogus[c].y = ( rand() % ( rfkLINES - 3 ) ) + 3; } while( rfkscreen[bogus[c].x][bogus[c].y] != EMPTY ); rfkscreen[bogus[c].x][bogus[c].y] = c + 2; /* Assign a character. */ do { bogus[c].character = ktile[rand() % 82]; } while( bogus[c].character == '#' || bogus[c].character == ' ' ); do { bogus[c].color = all_colors.get_random(); } while( bogus[c].color == c_black ); /* Assign a unique message. */ int index = 0; do { index = rand() % nummessages; } while( used_messages[index] != 0 ); bogus_messages[c] = index; used_messages[index] = 1; } instructions( w ); werase( w ); mvwprintz( w, 0, 0, c_white, _( "robotfindskitten v22July2008 - press q to quit." ) ); for( int c = 0; c < rfkCOLS; c++ ) { mvwputch( w, 2, c, BORDER_COLOR, '_' ); } wmove( w, kitten.y, kitten.x ); draw_kitten( w ); for( int c = 0; c < numbogus; c++ ) { mvwputch( w, bogus[c].y, bogus[c].x, bogus[c].color, bogus[c].character ); } wmove( w, robot.y, robot.x ); draw_robot( w ); int old_x = robot.x; int old_y = robot.y; wrefresh( w ); /* Now the fun begins. */ int input = inp_mngr.get_input_event().get_first_input(); // @todo: use input context while( input != 'q' && input != 'Q' && input != KEY_ESCAPE ) { process_input( input, w ); if( ret ) { break; } /* Redraw robot, where available */ if( !( old_x == robot.x && old_y == robot.y ) ) { wmove( w, old_y, old_x ); wputch( w, c_white, ' ' ); wmove( w, robot.y, robot.x ); draw_robot( w ); rfkscreen[old_x][old_y] = EMPTY; rfkscreen[robot.x][robot.y] = ROBOT; old_x = robot.x; old_y = robot.y; } wrefresh( w ); // TODO: use input context / rewrite loop so this is only called at one place input = inp_mngr.get_input_event().get_first_input(); } }
//-------------------------------------------------------------------------------------------- bool tile_dictionary_load_vfs( const char * filename, tile_dictionary_t * pdict, int max_dict_size ) { /// @author ZZ /// @details This function loads fan types for the terrain Uint32 cnt, entry, vertices, commandsize; int fantype_count, fantype_offset, fantype; int command_count, command; int definition_count; int itmp; float ftmp; if ( NULL == pdict ) return false; // "delete" the old list *pdict = tile_dictionary_t(); if ( !VALID_CSTR( filename ) ) return false; // handle default parameters if ( max_dict_size < 0 ) { max_dict_size = MAP_FAN_TYPE_MAX; } // Try to open a context. ReadContext ctxt(filename); if (!ctxt.ensureOpen()) { Log::get().error("unable to load tile definitions file `%s`\n", filename); return false; } fantype_count = vfs_get_next_int(ctxt); fantype_offset = 2 * std::pow( 2.0f, std::floor( std::log( fantype_count ) / std::log( 2.0f ) ) ); definition_count = 2 * fantype_offset; if ( definition_count > MAP_FAN_TYPE_MAX ) { Log::get().error( "%s - tile dictionary has too many tile definitions (%d/%d).\n", __FUNCTION__, definition_count, MAP_FAN_TYPE_MAX ); return false; } else if ( definition_count > max_dict_size ) { Log::get().error( "%s - the number of tile difinitions has exceeded the requested number (%d/%d).\n", __FUNCTION__, definition_count, max_dict_size ); return false; } pdict->offset = fantype_offset; pdict->def_count = definition_count; for ( fantype = 0; fantype < fantype_count; fantype++ ) { tile_definition_t& pdef_sml = pdict->def_lst[fantype]; tile_definition_t& pdef_big = pdict->def_lst[fantype + fantype_offset]; vertices = vfs_get_next_int(ctxt); pdef_sml.numvertices = vertices; pdef_big.numvertices = vertices; // Dupe for ( cnt = 0; cnt < vertices; cnt++ ) { itmp = vfs_get_next_int(ctxt); pdef_sml.ref[cnt] = itmp; pdef_sml.grid_ix[cnt] = itmp & 3; pdef_sml.grid_iy[cnt] = ( itmp >> 2 ) & 3; ftmp = vfs_get_next_float(ctxt); pdef_sml.u[cnt] = ftmp; ftmp = vfs_get_next_float(ctxt); pdef_sml.v[cnt] = ftmp; // Dupe pdef_big.ref[cnt] = pdef_sml.ref[cnt]; pdef_big.grid_ix[cnt] = pdef_sml.grid_ix[cnt]; pdef_big.grid_iy[cnt] = pdef_sml.grid_iy[cnt]; pdef_big.u[cnt] = pdef_sml.u[cnt]; pdef_big.v[cnt] = pdef_sml.v[cnt]; } command_count = vfs_get_next_int(ctxt); pdef_sml.command_count = command_count; pdef_big.command_count = command_count; // Dupe for ( entry = 0, command = 0; command < command_count; command++ ) { commandsize = vfs_get_next_int(ctxt); pdef_sml.command_entries[command] = commandsize; pdef_big.command_entries[command] = commandsize; // Dupe for ( cnt = 0; cnt < commandsize; cnt++ ) { itmp = vfs_get_next_int(ctxt); pdef_sml.command_verts[entry] = itmp; pdef_big.command_verts[entry] = itmp; // Dupe entry++; } } } pdict->loaded = true; tile_dictionary_finalize( pdict ); return true; }
void faction_manager::display() const { std::vector<const faction *> valfac; // Factions that we know of. for( const faction &elem : factions ) { if( elem.known_by_u ) { valfac.push_back( &elem ); } } if( valfac.empty() ) { // We don't know of any factions! popup( _( "You don't know of any factions. Press Spacebar..." ) ); return; } catacurses::window w_list = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, ( ( TERMY > FULL_SCREEN_HEIGHT ) ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0 ), ( TERMX > FULL_SCREEN_WIDTH ) ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ); catacurses::window w_info = catacurses::newwin( FULL_SCREEN_HEIGHT - 2, FULL_SCREEN_WIDTH - 1 - MAX_FAC_NAME_SIZE, 1 + ( ( TERMY > FULL_SCREEN_HEIGHT ) ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0 ), MAX_FAC_NAME_SIZE + ( ( TERMX > FULL_SCREEN_WIDTH ) ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ) ); const int maxlength = FULL_SCREEN_WIDTH - 1 - MAX_FAC_NAME_SIZE; size_t sel = 0; bool redraw = true; input_context ctxt( "FACTIONS" ); ctxt.register_action( "UP", _( "Move cursor up" ) ); ctxt.register_action( "DOWN", _( "Move cursor down" ) ); ctxt.register_action( "QUIT" ); ctxt.register_action( "HELP_KEYBINDINGS" ); while( true ) { const faction &cur_frac = *valfac[sel]; if( redraw ) { werase( w_list ); draw_border( w_list ); mvwprintz( w_list, 1, 1, c_white, _( "FACTIONS:" ) ); for( size_t i = 0; i < valfac.size(); i++ ) { nc_color col = ( i == sel ? h_white : c_white ); mvwprintz( w_list, i + 2, 1, col, _( valfac[i]->name.c_str() ) ); } wrefresh( w_list ); werase( w_info ); mvwprintz( w_info, 0, 0, c_white, _( "Ranking: %s" ), fac_ranking_text( cur_frac.likes_u ) ); mvwprintz( w_info, 1, 0, c_white, _( "Respect: %s" ), fac_respect_text( cur_frac.respects_u ) ); mvwprintz( w_info, 2, 0, c_white, _( "Wealth: %s" ), fac_wealth_text( cur_frac.wealth, cur_frac.size ) ); mvwprintz( w_info, 3, 0, c_white, _( "Food Supply: %s" ), fac_food_supply_text( cur_frac.food_supply, cur_frac.size ) ); mvwprintz( w_info, 4, 0, c_white, _( "Combat Ability: %s" ), fac_combat_ability_text( cur_frac.combat_ability ) ); fold_and_print( w_info, 6, 0, maxlength, c_white, cur_frac.describe() ); wrefresh( w_info ); redraw = false; } const std::string action = ctxt.handle_input(); if( action == "DOWN" ) { mvwprintz( w_list, sel + 2, 1, c_white, cur_frac.name ); sel = ( sel + 1 ) % valfac.size(); redraw = true; } else if( action == "UP" ) { mvwprintz( w_list, sel + 2, 1, c_white, cur_frac.name ); sel = ( sel + valfac.size() - 1 ) % valfac.size(); redraw = true; } else if( action == "HELP_KEYBINDINGS" ) { redraw = true; } else if( action == "QUIT" ) { break; } else if( action == "CONFIRM" ) { break; } } }
int worldfactory::show_worldgen_tab_confirm(WINDOW *win, WORLDPTR world) { const int iTooltipHeight = 1; const int iContentHeight = FULL_SCREEN_HEIGHT - 3 - iTooltipHeight; const int iOffsetX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0; const int iOffsetY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0; WINDOW *w_confirmation = newwin(iContentHeight, FULL_SCREEN_WIDTH - 2, iTooltipHeight + 2 + iOffsetY, 1 + iOffsetX); unsigned namebar_y = 1; unsigned namebar_x = 3 + utf8_width(_("World Name:")); int line = 1; bool noname = false; input_context ctxt("WORLDGEN_CONFIRM_DIALOG"); // Disabled because it conflicts with the "pick random world name" option, // feel free to enable it and change its keybinding in keybindings.json // ctxt.register_action("HELP_KEYBINDINGS"); ctxt.register_action("QUIT"); ctxt.register_action("ANY_INPUT"); ctxt.register_action("NEXT_TAB"); ctxt.register_action("PREV_TAB"); ctxt.register_action("PICK_RANDOM_WORLDNAME"); std::string worldname = world->world_name; do { mvwprintz(w_confirmation, namebar_y, 2, c_white, _("World Name:")); mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, "______________________________"); fold_and_print(w_confirmation, 3, 2, 76, c_ltgray, _("Press <color_yellow>?</color> to pick a random name for your world.")); fold_and_print(w_confirmation, FULL_SCREEN_HEIGHT / 2 - 2, 2, 76, c_ltgray, _("\ Press <color_yellow>></color> when you are satisfied with the world as it is and are ready \ to continue, or <color_yellow><</color> to go back and review your world.")); if (!noname) { mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, "%s", worldname.c_str()); if (line == 1) { wprintz(w_confirmation, h_ltgray, "_"); } } if (noname) { mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, "______________________________"); noname = false; } wrefresh(win); wrefresh(w_confirmation); refresh(); const std::string action = ctxt.handle_input(); if (action == "NEXT_TAB") { if (worldname.empty()) { mvwprintz(w_confirmation, namebar_y, namebar_x, h_ltgray, _("______NO NAME ENTERED!!!!_____")); noname = true; wrefresh(w_confirmation); if (!query_yn(_("Are you SURE you're finished? World name will be randomly generated."))) { continue; } else { world->world_name = pick_random_name(); if (!valid_worldname(world->world_name)) { continue; } return 1; } } else if (query_yn(_("Are you SURE you're finished?")) && valid_worldname(worldname)) { world->world_name = worldname; werase(w_confirmation); delwin(w_confirmation); return 1; } else { continue; } } else if (action == "PREV_TAB") { world->world_name = worldname; werase(w_confirmation); delwin(w_confirmation); return -1; } else if (action == "PICK_RANDOM_WORLDNAME") { mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, "______________________________"); world->world_name = worldname = pick_random_name(); } else if (action == "QUIT") { world->world_name = worldname; // cache the current worldname just in case they say No to the exit query return -999; } else if (action == "ANY_INPUT") { const long ch = ctxt.get_raw_input().get_first_input(); switch (line) { case 1: if (ch == KEY_BACKSPACE || ch == 127) { if (!worldname.empty()) { //erase utf8 character TODO: make a function while(!worldname.empty() && ((unsigned char)worldname[worldname.size() - 1]) >= 128 && ((unsigned char)worldname[(int)worldname.size() - 1]) <= 191) { worldname.erase(worldname.size() - 1); } worldname.erase(worldname.size() - 1); mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, "______________________________ "); mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, "%s", worldname.c_str()); wprintz(w_confirmation, h_ltgray, "_"); } } else if (is_char_allowed(ch) && utf8_width(worldname.c_str()) < 30) { worldname.push_back(ch); } else if(ch == KEY_F(2)) { std::string tmp = get_input_string_from_file(); int tmplen = utf8_width(tmp.c_str()); if(tmplen > 0 && tmplen + utf8_width(worldname.c_str()) < 30) { worldname.append(tmp); } } //experimental unicode input else if(ch > 127) { std::string tmp = utf32_to_utf8(ch); int tmplen = utf8_width(tmp.c_str()); if(tmplen > 0 && tmplen + utf8_width(worldname.c_str()) < 30) { worldname.append(tmp); } } break; } } } while (true); return 0; }
void auto_pickup::show( const std::string &custom_name, bool is_autopickup ) { save_reset_changes(false); const int iHeaderHeight = 4; const int iContentHeight = FULL_SCREEN_HEIGHT - 2 - iHeaderHeight; const int iOffsetX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0; const int iOffsetY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0; std::map<int, bool> mapLines; mapLines[4] = true; mapLines[50] = true; mapLines[54] = true; const int iTotalCols = mapLines.size() - 1; WINDOW *w_help = newwin((FULL_SCREEN_HEIGHT / 2) - 2, FULL_SCREEN_WIDTH * 3 / 4, 7 + iOffsetY + (FULL_SCREEN_HEIGHT / 2) / 2, iOffsetX + 19 / 2); WINDOW_PTR w_helpptr( w_help ); WINDOW *w_border = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, iOffsetY, iOffsetX); WINDOW_PTR w_borderptr( w_border ); WINDOW *w_header = newwin(iHeaderHeight, FULL_SCREEN_WIDTH - 2, 1 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_headerptr( w_header ); WINDOW *w = newwin(iContentHeight, FULL_SCREEN_WIDTH - 2, iHeaderHeight + 1 + iOffsetY, 1 + iOffsetX); WINDOW_PTR wptr( w ); draw_border(w_border); mvwputch(w_border, 3, 0, c_ltgray, LINE_XXXO); // |- mvwputch(w_border, 3, 79, c_ltgray, LINE_XOXX); // -| for( auto &mapLine : mapLines ) { mvwputch( w_border, FULL_SCREEN_HEIGHT - 1, mapLine.first + 1, c_ltgray, LINE_XXOX ); // _|_ } mvwprintz(w_border, 0, 29, c_ltred, custom_name.c_str() ); wrefresh(w_border); int tmpx = 0; tmpx += shortcut_print(w_header, 0, tmpx, c_white, c_ltgreen, _("<A>dd")) + 2; tmpx += shortcut_print(w_header, 0, tmpx, c_white, c_ltgreen, _("<R>emove")) + 2; tmpx += shortcut_print(w_header, 0, tmpx, c_white, c_ltgreen, _("<C>opy")) + 2; tmpx += shortcut_print(w_header, 0, tmpx, c_white, c_ltgreen, _("<M>ove")) + 2; tmpx += shortcut_print(w_header, 0, tmpx, c_white, c_ltgreen, _("<E>nable")) + 2; tmpx += shortcut_print(w_header, 0, tmpx, c_white, c_ltgreen, _("<D>isable")) + 2; shortcut_print(w_header, 0, tmpx, c_white, c_ltgreen, _("<T>est")); tmpx = 0; tmpx += shortcut_print(w_header, 1, tmpx, c_white, c_ltgreen, _("<+-> Move up/down")) + 2; tmpx += shortcut_print(w_header, 1, tmpx, c_white, c_ltgreen, _("<Enter>-Edit")) + 2; shortcut_print(w_header, 1, tmpx, c_white, c_ltgreen, _("<Tab>-Switch Page")); for (int i = 0; i < 78; i++) { if (mapLines[i]) { mvwputch(w_header, 2, i, c_ltgray, LINE_OXXX); mvwputch(w_header, 3, i, c_ltgray, LINE_XOXO); } else { mvwputch(w_header, 2, i, c_ltgray, LINE_OXOX); // Draw line under header } } mvwprintz(w_header, 3, 1, c_white, "#"); mvwprintz(w_header, 3, 8, c_white, _("Rules")); mvwprintz(w_header, 3, 51, c_white, _("I/E")); wrefresh(w_header); int iCurrentPage = 1; int iCurrentLine = 0; int iCurrentCol = 1; int iStartPos = 0; bool bStuffChanged = false; input_context ctxt("AUTO_PICKUP"); ctxt.register_cardinal(); ctxt.register_action("CONFIRM"); ctxt.register_action("QUIT"); ctxt.register_action("NEXT_TAB"); ctxt.register_action("PREV_TAB"); ctxt.register_action("ADD_RULE"); ctxt.register_action("REMOVE_RULE"); ctxt.register_action("COPY_RULE"); ctxt.register_action("ENABLE_RULE"); ctxt.register_action("DISABLE_RULE"); ctxt.register_action("MOVE_RULE_UP"); ctxt.register_action("MOVE_RULE_DOWN"); ctxt.register_action("TEST_RULE"); ctxt.register_action("HELP_KEYBINDINGS"); if( is_autopickup ) { ctxt.register_action("SWITCH_AUTO_PICKUP_OPTION"); ctxt.register_action("SWAP_RULE_GLOBAL_CHAR"); } std::ostringstream sTemp; while(true) { int locx = 17; locx += shortcut_print(w_header, 2, locx, c_white, (iCurrentPage == 1) ? hilite(c_white) : c_white, _("[<Global>]")) + 1; shortcut_print(w_header, 2, locx, c_white, (iCurrentPage == 2) ? hilite(c_white) : c_white, _("[<Character>]")); locx = 55; mvwprintz(w_header, 0, locx, c_white, _("Auto pickup enabled:")); locx += shortcut_print(w_header, 1, locx, ((OPTIONS["AUTO_PICKUP"]) ? c_ltgreen : c_ltred), c_white, ((OPTIONS["AUTO_PICKUP"]) ? _("True") : _("False"))); locx += shortcut_print(w_header, 1, locx, c_white, c_ltgreen, " "); locx += shortcut_print(w_header, 1, locx, c_white, c_ltgreen, _("<S>witch")); shortcut_print(w_header, 1, locx, c_white, c_ltgreen, " "); wrefresh(w_header); // Clear the lines for (int i = 0; i < iContentHeight; i++) { for (int j = 0; j < 79; j++) { if (mapLines[j]) { mvwputch(w, i, j, c_ltgray, LINE_XOXO); } else { mvwputch(w, i, j, c_black, ' '); } } } const bool currentPageNonEmpty = !vRules[iCurrentPage].empty(); if (iCurrentPage == 2 && g->u.name == "") { vRules[2].clear(); mvwprintz(w, 8, 15, c_white, _("Please load a character first to use this page!")); } draw_scrollbar(w_border, iCurrentLine, iContentHeight, vRules[iCurrentPage].size(), 5); wrefresh(w_border); calcStartPos(iStartPos, iCurrentLine, iContentHeight, vRules[iCurrentPage].size()); // display auto pickup for (int i = iStartPos; i < (int)vRules[iCurrentPage].size(); i++) { if (i >= iStartPos && i < iStartPos + ((iContentHeight > (int)vRules[iCurrentPage].size()) ? (int)vRules[iCurrentPage].size() : iContentHeight)) { nc_color cLineColor = (vRules[iCurrentPage][i].bActive) ? c_white : c_ltgray; sTemp.str(""); sTemp << i + 1; mvwprintz(w, i - iStartPos, 1, cLineColor, "%s", sTemp.str().c_str()); mvwprintz(w, i - iStartPos, 5, cLineColor, ""); if (iCurrentLine == i) { wprintz(w, c_yellow, ">> "); } else { wprintz(w, c_yellow, " "); } wprintz(w, (iCurrentLine == i && iCurrentCol == 1) ? hilite(cLineColor) : cLineColor, "%s", ((vRules[iCurrentPage][i].sRule == "") ? _("<empty rule>") : vRules[iCurrentPage][i].sRule).c_str()); mvwprintz(w, i - iStartPos, 52, (iCurrentLine == i && iCurrentCol == 2) ? hilite(cLineColor) : cLineColor, "%s", ((vRules[iCurrentPage][i].bExclude) ? rm_prefix(_("<Exclude>E")).c_str() : rm_prefix( _("<Include>I")).c_str())); } } wrefresh(w); const std::string action = ctxt.handle_input(); if (action == "NEXT_TAB") { iCurrentPage++; if (iCurrentPage > 2) { iCurrentPage = 1; iCurrentLine = 0; } } else if (action == "PREV_TAB") { iCurrentPage--; if (iCurrentPage < 1) { iCurrentPage = 2; iCurrentLine = 0; } } else if (action == "QUIT") { break; } else if (iCurrentPage == 2 && g->u.name.empty()) { //Only allow loaded games to use the char sheet } else if (action == "DOWN") { iCurrentLine++; iCurrentCol = 1; if (iCurrentLine >= (int)vRules[iCurrentPage].size()) { iCurrentLine = 0; } } else if (action == "UP") { iCurrentLine--; iCurrentCol = 1; if (iCurrentLine < 0) { iCurrentLine = vRules[iCurrentPage].size() - 1; } } else if (action == "ADD_RULE") { bStuffChanged = true; vRules[iCurrentPage].push_back(cRules("", true, false)); iCurrentLine = vRules[iCurrentPage].size() - 1; } else if (action == "REMOVE_RULE" && currentPageNonEmpty) { bStuffChanged = true; vRules[iCurrentPage].erase(vRules[iCurrentPage].begin() + iCurrentLine); if (iCurrentLine > (int)vRules[iCurrentPage].size() - 1) { iCurrentLine--; } if(iCurrentLine < 0){ iCurrentLine = 0; } } else if (action == "COPY_RULE" && currentPageNonEmpty) { bStuffChanged = true; vRules[iCurrentPage].push_back(cRules( vRules[iCurrentPage][iCurrentLine].sRule, vRules[iCurrentPage][iCurrentLine].bActive, vRules[iCurrentPage][iCurrentLine].bExclude)); iCurrentLine = vRules[iCurrentPage].size() - 1; } else if (action == "SWAP_RULE_GLOBAL_CHAR" && currentPageNonEmpty) { if ((iCurrentPage == 1 && g->u.name != "") || iCurrentPage == 2) { bStuffChanged = true; //copy over vRules[(iCurrentPage == 1) ? 2 : 1].push_back(cRules( vRules[iCurrentPage][iCurrentLine].sRule, vRules[iCurrentPage][iCurrentLine].bActive, vRules[iCurrentPage][iCurrentLine].bExclude)); //remove old vRules[iCurrentPage].erase(vRules[iCurrentPage].begin() + iCurrentLine); iCurrentLine = vRules[(iCurrentPage == 1) ? 2 : 1].size() - 1; iCurrentPage = (iCurrentPage == 1) ? 2 : 1; } } else if (action == "CONFIRM" && currentPageNonEmpty) { bStuffChanged = true; if (iCurrentCol == 1) { fold_and_print(w_help, 1, 1, 999, c_white, _( "* is used as a Wildcard. A few Examples:\n" "\n" "wooden arrow matches the itemname exactly\n" "wooden ar* matches items beginning with wood ar\n" "*rrow matches items ending with rrow\n" "*avy fle*fi*arrow multiple * are allowed\n" "heAVY*woOD*arrOW case insensitive search\n" "") ); draw_border(w_help); wrefresh(w_help); vRules[iCurrentPage][iCurrentLine].sRule = trim_rule(string_input_popup(_("Pickup Rule:"), 30, vRules[iCurrentPage][iCurrentLine].sRule)); } else if (iCurrentCol == 2) { vRules[iCurrentPage][iCurrentLine].bExclude = !vRules[iCurrentPage][iCurrentLine].bExclude; } } else if (action == "ENABLE_RULE" && currentPageNonEmpty) { bStuffChanged = true; vRules[iCurrentPage][iCurrentLine].bActive = true; } else if (action == "DISABLE_RULE" && currentPageNonEmpty) { bStuffChanged = true; vRules[iCurrentPage][iCurrentLine].bActive = false; } else if (action == "LEFT") { iCurrentCol--; if (iCurrentCol < 1) { iCurrentCol = iTotalCols; } } else if (action == "RIGHT") { iCurrentCol++; if (iCurrentCol > iTotalCols) { iCurrentCol = 1; } } else if (action == "MOVE_RULE_UP" && currentPageNonEmpty) { bStuffChanged = true; if (iCurrentLine < (int)vRules[iCurrentPage].size() - 1) { std::swap(vRules[iCurrentPage][iCurrentLine], vRules[iCurrentPage][iCurrentLine + 1]); iCurrentLine++; iCurrentCol = 1; } } else if (action == "MOVE_RULE_DOWN" && currentPageNonEmpty) { bStuffChanged = true; if (iCurrentLine > 0) { std::swap(vRules[iCurrentPage][iCurrentLine], vRules[iCurrentPage][iCurrentLine - 1]); iCurrentLine--; iCurrentCol = 1; } } else if (action == "TEST_RULE" && currentPageNonEmpty) { test_pattern(iCurrentPage, iCurrentLine); } else if (action == "SWITCH_OPTION") { // @todo Now that NPCs use this function, it could be used for them too OPTIONS["AUTO_PICKUP"].setNext(); get_options().save(); } } if( !bStuffChanged ) { return; } if( query_yn( _("Save changes?") ) ) { // NPC pickup rules don't need to be saved explicitly if( is_autopickup ) { save( false ); if( g->u.name != "" ) { save(true); } } else { merge_vector(); create_rules(); } } else { save_reset_changes( true ); } }
void Messages::display_messages() { WINDOW *w = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0, (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0); size_t offset = 0; const int maxlength = FULL_SCREEN_WIDTH - 2 - 1; const int bottom = FULL_SCREEN_HEIGHT - 2; input_context ctxt("MESSAGE_LOG"); ctxt.register_action("UP", _("Scroll up")); ctxt.register_action("DOWN", _("Scroll down")); ctxt.register_action("QUIT"); ctxt.register_action("HELP_KEYBINDINGS"); while(true) { werase(w); draw_border(w); mvwprintz(w, FULL_SCREEN_HEIGHT - 1, 32, c_red, _("Press %s to return"), ctxt.get_desc("QUIT").c_str()); draw_scrollbar(w, offset, FULL_SCREEN_HEIGHT - 2, size(), 1); int line = 1; int lasttime = -1; for (size_t i = offset; i < size() && line <= bottom; i++) { const game_message &m = player_messages.messages[size() - i - 1]; const std::string mstr = m.get_with_count(); const nc_color col = m.get_color(); calendar timepassed = calendar::turn - m.turn; if (int(timepassed) > lasttime) { mvwprintz(w, line, 3, c_ltblue, _("%s ago:"), timepassed.textify_period().c_str()); line++; lasttime = int(timepassed); } std::vector<std::string> folded = foldstring(mstr, maxlength); for (size_t j = 0; j < folded.size() && line <= bottom; j++, line++) { mvwprintz(w, line, 1, col, "%s", folded[j].c_str()); } } if (offset + 1 < size()) { mvwprintz(w, FULL_SCREEN_HEIGHT - 1, 5, c_magenta, "vvv"); } if (offset > 0) { mvwprintz(w, FULL_SCREEN_HEIGHT - 1, FULL_SCREEN_WIDTH - 6, c_magenta, "^^^"); } wrefresh(w); const std::string action = ctxt.handle_input(); if (action == "DOWN" && offset + 1 < size()) { offset++; } else if (action == "UP" && offset > 0) { offset--; } else if (action == "QUIT") { break; } } player_messages.curmes = int(calendar::turn); werase(w); delwin(w); }