void inventory_selector::display(bool show_worn) const { const size_t ¤t_page_offset = in_inventory ? current_page_offset_i : current_page_offset_w; werase(w_inv); mvwprintw(w_inv, 0, 0, title.c_str()); if (multidrop) { mvwprintw(w_inv, 1, 0, _("To drop x items, type a number and then the item hotkey.")); } std::string msg_str; nc_color msg_color; if (inCategoryMode) { msg_str = _("Category selection; [TAB] switches mode, arrows select."); msg_color = c_white_red; } else { msg_str = _("Item selection; [TAB] switches mode, arrows select."); msg_color = h_white; } mvwprintz(w_inv, items_per_page + 4, FULL_SCREEN_WIDTH - utf8_width(msg_str), msg_color, msg_str.c_str()); print_left_column(); if(show_worn) { print_middle_column(); } print_right_column(); const size_t max_size = in_inventory ? items.size() : worn.size(); const size_t max_pages = (max_size + items_per_page - 1) / items_per_page; mvwprintw(w_inv, items_per_page + 4, 1, _("Page %d/%d"), current_page_offset / items_per_page + 1, max_pages); if (multidrop) { // Make copy, remove to be dropped items from that // copy and let the copy recalculate the volume capacity // (can be affected by various traits). player tmp = g->u; // first round: remove weapon & worn items, start with larges worn index for( const auto &elem : dropping ) { if( elem.first == -1 && elem.second == -1 ) { tmp.remove_weapon(); } else if( elem.first == -1 && elem.second != -1 ) { tmp.weapon.charges -= elem.second; } else if( elem.first < 0 ) { tmp.i_rem( elem.first ); } } remove_dropping_items(tmp); print_inv_weight_vol(tmp.weight_carried(), tmp.volume_carried(), tmp.volume_capacity()); } else { print_inv_weight_vol(g->u.weight_carried(), g->u.volume_carried(), g->u.volume_capacity()); } if (!multidrop && !compare) { mvwprintw(w_inv, 1, 61, _("Hotkeys: %d/%d "), g->u.allocated_invlets().size(), inv_chars.size()); } wrefresh(w_inv); }
void print_inv_statics(game *g, WINDOW* w_inv, std::string title, std::vector<char> dropped_items) { // Print our header mvwprintw(w_inv, 0, 0, title.c_str()); print_inv_weight_vol(g, w_inv, g->u.weight_carried(), g->u.volume_carried()); // Print our weapon int n_items = 0; mvwprintz(w_inv, 2, 45, c_magenta, "WEAPON:"); int dropping_weapon = false; for (int i = 0; i < dropped_items.size() && !dropping_weapon; i++) { if (dropped_items[i] == g->u.weapon.invlet) dropping_weapon = true; } if (g->u.is_armed()) { n_items++; if (dropping_weapon) mvwprintz(w_inv, 3, 45, c_white, "%c + %s", g->u.weapon.invlet, g->u.weapname().c_str()); else mvwprintz(w_inv, 3, 45, g->u.weapon.color_in_inventory(&(g->u)), "%c - %s", g->u.weapon.invlet, g->u.weapname().c_str()); } else if (g->u.weapon.is_style()) { n_items++; mvwprintz(w_inv, 3, 45, c_ltgray, "%c - %s", g->u.weapon.invlet, g->u.weapname().c_str()); } else mvwprintz(w_inv, 3, 45, c_ltgray, g->u.weapname().c_str()); // Print worn items if (g->u.worn.size() > 0) mvwprintz(w_inv, 5, 45, c_magenta, "ITEMS WORN:"); for (int i = 0; i < g->u.worn.size(); i++) { n_items++; bool dropping_armor = false; for (int j = 0; j < dropped_items.size() && !dropping_armor; j++) { if (dropped_items[j] == g->u.worn[i].invlet) dropping_armor = true; } if (dropping_armor) mvwprintz(w_inv, 6 + i, 45, c_white, "%c + %s", g->u.worn[i].invlet, g->u.worn[i].tname(g).c_str()); else mvwprintz(w_inv, 6 + i, 45, c_ltgray, "%c - %s", g->u.worn[i].invlet, g->u.worn[i].tname(g).c_str()); } // Print items carried for (std::string::const_iterator invlet = inv_chars.begin(); invlet != inv_chars.end(); invlet++) { n_items += ((g->u.inv.item_by_letter(*invlet).is_null()) ? 0 : 1); } mvwprintw(w_inv, 1, 62, "Items: %d/%d ", n_items, inv_chars.size()); }
// dropped_weapon==0 -> weapon is not dropped // dropped_weapon==-1 -> weapon is dropped (whole stack) // dropped_weapon>0 -> part of the weapon stack is dropped void print_inv_statics(WINDOW* w_inv, std::string title, std::vector<char> dropped_items, int dropped_weapon) { // Print our header mvwprintw(w_inv, 0, 0, title.c_str()); print_inv_weight_vol(w_inv, g->u.weight_carried(), g->u.volume_carried(), calc_volume_capacity(dropped_items)); // Print our weapon int n_items = 0; mvwprintz(w_inv, 2, 45, c_magenta, _("WEAPON:")); if (g->u.is_armed()) { n_items++; if (dropped_weapon != 0) mvwprintz(w_inv, 3, 45, c_white, "%c %c %s", g->u.weapon.invlet, dropped_weapon == -1 ? '+' : '#', g->u.weapname().c_str()); else mvwprintz(w_inv, 3, 45, g->u.weapon.color_in_inventory(), "%c - %s", g->u.weapon.invlet, g->u.weapname().c_str()); } else mvwprintz(w_inv, 3, 45, c_ltgray, g->u.weapname().c_str()); // Print worn items if (g->u.worn.size() > 0) mvwprintz(w_inv, 5, 45, c_magenta, _("ITEMS WORN:")); for (int i = 0; i < g->u.worn.size(); i++) { n_items++; bool dropped_armor = false; for (int j = 0; j < dropped_items.size() && !dropped_armor; j++) { if (dropped_items[j] == g->u.worn[i].invlet) dropped_armor = true; } if (dropped_armor) mvwprintz(w_inv, 6 + i, 45, c_white, "%c + %s", g->u.worn[i].invlet, g->u.worn[i].tname().c_str()); else mvwprintz(w_inv, 6 + i, 45, c_ltgray, "%c - %s", g->u.worn[i].invlet, g->u.worn[i].tname().c_str()); } // Print items carried for (std::string::const_iterator invlet = inv_chars.begin(); invlet != inv_chars.end(); ++invlet) { n_items += ((g->u.inv.item_by_letter(*invlet).is_null()) ? 0 : 1); } mvwprintw(w_inv, 1, 61, _("Hotkeys: %d/%d "), n_items, inv_chars.size()); }
std::vector<item> game::multidrop() { u.inv.sort(); u.inv.restack(&u); WINDOW* w_inv = newwin(((VIEWY < 12) ? 25 : VIEWY*2+1), ((VIEWX < 12) ? 80 : VIEWX*2+56), VIEW_OFFSET_Y, VIEW_OFFSET_X); const int maxitems = (VIEWY < 12) ? 20 : VIEWY*2-4; // Number of items to show at one time. std::map<char, int> dropping; // Count of how many we'll drop from each stack int count = 0; // The current count std::vector<char> weapon_and_armor; // Always single, not counted bool warned_about_bionic = false; // Printed add_msg re: dropping bionics print_inv_statics(this, w_inv, "Multidrop:", weapon_and_armor); int base_weight = u.weight_carried(); int base_volume = u.volume_carried(); int ch = (int)'.'; int start = 0, cur_it; invslice stacks = u.inv.slice(0, u.inv.size()); std::vector<int> firsts = find_firsts(stacks); do { inventory drop_subset = u.inv.subset(dropping); int new_weight = base_weight - drop_subset.weight(); int new_volume = base_volume - drop_subset.volume(); for (int i = 0; i < weapon_and_armor.size(); ++i) { new_weight -= u.i_at(weapon_and_armor[i]).weight(); } print_inv_weight_vol(this, w_inv, new_weight, new_volume); if (( ch == '<' || ch == KEY_PPAGE ) && start > 0) { for (int i = 1; i < maxitems+4; i++) mvwprintz(w_inv, i, 0, c_black, " "); start -= maxitems; if (start < 0) start = 0; mvwprintw(w_inv, maxitems + 4, 0, " "); } if (( ch == '>' || ch == KEY_NPAGE ) && cur_it < u.inv.size()) { start = cur_it; mvwprintw(w_inv, maxitems + 4, 12, " "); for (int i = 1; i < maxitems+4; i++) mvwprintz(w_inv, i, 0, c_black, " "); } int cur_line = 2; for (cur_it = start; cur_it < start + maxitems && cur_line < maxitems+3; cur_it++) { // Clear the current line; mvwprintw(w_inv, cur_line, 0, " "); // Print category header for (int i = 1; i < iCategorieNum; i++) { if (cur_it == firsts[i-1]) { mvwprintz(w_inv, cur_line, 0, c_magenta, CATEGORIES[i].c_str()); cur_line++; } } if (cur_it < stacks.size()) { item& it = stacks[cur_it]->front(); mvwputch (w_inv, cur_line, 0, c_white, it.invlet); char icon = '-'; if (dropping[it.invlet] >= (it.count_by_charges() ? it.charges : stacks[cur_it]->size())) icon = '+'; else if (dropping[it.invlet] > 0) icon = '#'; nc_color col = (dropping[it.invlet] == 0 ? c_ltgray : c_white); mvwprintz(w_inv, cur_line, 1, col, " %c %s", icon, it.tname(this).c_str()); if (stacks[cur_it]->size() > 1) wprintz(w_inv, col, " [%d]", stacks[cur_it]->size()); if (it.charges > 0) wprintz(w_inv, col, " (%d)", it.charges); else if (it.contents.size() == 1 && it.contents[0].charges > 0) wprintw(w_inv, " (%d)", it.contents[0].charges); } cur_line++; } if (start > 0) mvwprintw(w_inv, maxitems + 4, 0, "< Go Back"); if (cur_it < u.inv.size()) mvwprintw(w_inv, maxitems + 4, 12, "> More items"); wrefresh(w_inv); ch = input(); if (ch >= '0'&& ch <= '9') { ch = (char)ch - '0'; count *= 10; count += ch; } else if (u.has_item(ch)) { item& it = u.inv.item_by_letter(ch); if (it.is_null()) { // Not from inventory int found = false; for (int i = 0; i < weapon_and_armor.size() && !found; i++) { if (weapon_and_armor[i] == ch) { weapon_and_armor.erase(weapon_and_armor.begin() + i); found = true; print_inv_statics(this, w_inv, "Multidrop:", weapon_and_armor); } } if (!found) { if ( ch == u.weapon.invlet && std::find(unreal_itype_ids.begin(), unreal_itype_ids.end(), u.weapon.type->id) != unreal_itype_ids.end()){ if (!warned_about_bionic) add_msg("You cannot drop your %s.", u.weapon.tname(this).c_str()); warned_about_bionic = true; } else { weapon_and_armor.push_back(ch); print_inv_statics(this, w_inv, "Multidrop:", weapon_and_armor); } } } else { int index = -1; for (int i = 0; i < stacks.size(); ++i) { if (stacks[i]->front().invlet == it.invlet) { index = i; break; } } if (index == -1) { debugmsg("Inventory got out of sync with inventory slice?"); } if (count == 0) { if (it.count_by_charges()) { if (dropping[it.invlet] == 0) dropping[it.invlet] = -1; else dropping[it.invlet] = 0; } else { if (dropping[it.invlet] == 0) dropping[it.invlet] = stacks[index]->size(); else dropping[it.invlet] = 0; } } else if (count >= stacks[index]->size() && !it.count_by_charges()) dropping[it.invlet] = stacks[index]->size(); else dropping[it.invlet] = count; count = 0; } } } while (ch != '\n' && ch != KEY_ESCAPE && ch != ' '); werase(w_inv); delwin(w_inv); erase(); refresh_all(); std::vector<item> ret; if (ch != '\n') return ret; // Canceled! for (std::map<char,int>::iterator it = dropping.begin(); it != dropping.end(); it++) { if (it->second == -1) ret.push_back( u.inv.remove_item_by_letter( it->first)); else if (it->second && u.inv.item_by_letter( it->first).count_by_charges()) { int charges = u.inv.item_by_letter( it->first).charges;// >= it->second ? : it->second; ret.push_back( u.inv.remove_item_by_charges( it->first, it->second > charges ? charges : it->second)); } else if (it->second) for (int j = it->second; j > 0; j--) ret.push_back( u.inv.remove_item_by_letter( it->first)); } for (int i = 0; i < weapon_and_armor.size(); i++) ret.push_back(u.i_rem(weapon_and_armor[i])); return ret; }
std::vector<item> game::multidrop() { WINDOW* w_inv = newwin(TERRAIN_WINDOW_HEIGHT, TERRAIN_WINDOW_WIDTH + (use_narrow_sidebar() ? 45 : 55), VIEW_OFFSET_Y, VIEW_OFFSET_X); const int maxitems = TERRAIN_WINDOW_HEIGHT - 5; u.inv.restack(&u); u.inv.sort(); int drp_line_width=getmaxx(w_inv)-90; const std::string drp_line_padding = ( drp_line_width > 1 ? std::string(drp_line_width, ' ') : " "); std::map<int, int> dropping; // Count of how many we'll drop from each position int count = 0; // The current count std::vector<char> weapon_and_armor; // Always single, not counted bool warned_about_bionic = false; // Printed add_msg re: dropping bionics print_inv_statics(this, w_inv, _("Multidrop:"), weapon_and_armor); int base_weight = u.weight_carried(); int base_volume = u.volume_carried(); int ch = (int)'.'; int start = 0, cur_it = 0, max_it; indexed_invslice stacks = u.inv.slice_filter(); CategoriesVector CATEGORIES; std::vector<int> firsts = find_firsts(stacks, CATEGORIES); int selected = -1; int selected_pos = INT_MIN; int next_category_at = 0; int prev_category_at = 0; bool inCategoryMode = false; std::vector<int> category_order; category_order.reserve(firsts.size()); // Items are not guaranteed to be in the same order as their categories, in fact they almost never are. // So we sort the categories by which items actually show up first in the inventory. for (int current_item = 0; current_item < u.inv.size(); ++current_item) { for (int i = 1; i < CATEGORIES.size(); ++i) { if (current_item == firsts[i - 1]) { category_order.push_back(i - 1); } } } do { // Find the inventory position of the first item in the previous and next category (in relation // to the currently selected category). for (int i = 0; i < category_order.size(); ++i) { if (selected > firsts[category_order[i]] && prev_category_at <= firsts[category_order[i]]) { prev_category_at = firsts[category_order[i]]; } if (selected < firsts[category_order[i]] && next_category_at <= selected) { next_category_at = firsts[category_order[i]]; } } inventory drop_subset = u.inv.subset(dropping); int new_weight = base_weight - drop_subset.weight(); int new_volume = base_volume - drop_subset.volume(); for (int i = 0; i < weapon_and_armor.size(); ++i) { new_weight -= u.i_at(weapon_and_armor[i]).weight(); } print_inv_weight_vol(this, w_inv, new_weight, new_volume); int cur_line = 2; max_it = 0; int drp_line = 1; // Print weapon to be dropped, the first position is reserved for high visibility mvwprintw(w_inv, 0, 90, "%s", drp_line_padding.c_str()); bool dropping_w = false; for (int k = 0; k < weapon_and_armor.size() && !dropping_w; k++) { if (weapon_and_armor[k] == u.weapon.invlet) { dropping_w = true; } if (dropping_w && u.is_armed()) { mvwprintz(w_inv, 0, 90, c_ltblue, "%c + %s", u.weapon.invlet, u.weapname().c_str()); } } // Print worn items to be dropped if(dropping_w) { mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str()); drp_line++; } bool dropping_a = false; if (u.worn.size() > 0){ for (int k = 0; k < u.worn.size(); k++) { bool dropping_w = false; for (int j = 0; j < weapon_and_armor.size() && !dropping_w; j++) { if (weapon_and_armor[j] == u.worn[k].invlet) { dropping_w = true; dropping_a = true; mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str()); mvwprintz(w_inv, drp_line, 90, c_cyan, "%c + %s", u.worn[k].invlet, u.worn[k].tname().c_str()); drp_line++; } } } } if(dropping_a) { mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str()); drp_line++; } for (cur_it = start; cur_it < start + maxitems && cur_line < maxitems+3; cur_it++) { // Clear the current line; mvwprintw(w_inv, cur_line, 0, " "); mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str()); mvwprintw(w_inv, drp_line + 1, 90, "%s", drp_line_padding.c_str()); // Print category header for (int i = 1; i < CATEGORIES.size(); i++) { if (cur_it == firsts[i-1]) { mvwprintz(w_inv, cur_line, 0, c_magenta, CATEGORIES[i].name.c_str()); cur_line++; } } if ( selected < start && selected > -1 ) selected = start; if (cur_it < stacks.size()) { item& it = stacks[cur_it].first->front(); if( cur_it == selected) { selected_pos = stacks[cur_it].second; } nc_color selected_line_color = inCategoryMode ? c_white_red : h_white; mvwputch (w_inv, cur_line, 0, (cur_it == selected ? selected_line_color : c_white), it.invlet); char icon = '-'; if (dropping[cur_it] >= (it.count_by_charges() ? it.charges : stacks[cur_it].first->size())) { icon = '+'; } else if (dropping[cur_it] > 0) { icon = '#'; } nc_color col = ( cur_it == selected ? selected_line_color : (dropping[cur_it] == 0 ? c_ltgray : c_white ) ); mvwprintz(w_inv, cur_line, 1, col, " %c %s", icon, it.tname().c_str()); if (stacks[cur_it].first->size() > 1) { wprintz(w_inv, col, " x %d", stacks[cur_it].first->size()); } if (it.charges > 0) { wprintz(w_inv, col, " (%d)", it.charges); } else if (it.contents.size() == 1 && it.contents[0].charges > 0) { wprintw(w_inv, " (%d)", it.contents[0].charges); } if (icon=='+'||icon=='#') { mvwprintz(w_inv, drp_line, 90, col, "%c %c %s", it.invlet, icon, it.tname().c_str()); if (icon=='+') { if (stacks[cur_it].first->size() > 1) { wprintz(w_inv, col, " x %d", stacks[cur_it].first->size()); } if (it.charges > 0) { wprintz(w_inv, col, " (%d)", it.charges); } } if (icon=='#') { wprintz(w_inv, col, " {%d}", dropping[cur_it]); } drp_line++; } } cur_line++; max_it=cur_it; } if (inCategoryMode) { mvwprintz(w_inv, maxitems + 4, 32, c_white_red, _("In category select mode! Press [SPACE] to enter item select mode.")); } else { mvwprintz(w_inv, maxitems + 4, 32, h_white, _("In item select mode! Press [SPACE] to enter category select mode.")); } if (start > 0) { mvwprintw(w_inv, maxitems + 4, 0, _("< Go Back")); } if (cur_it < u.inv.size()) { mvwprintw(w_inv, maxitems + 4, 12, _("> More items")); } wrefresh(w_inv); /* back to (int)getch() as input() mangles arrow keys ch = input(); */ ch = getch(); if (ch == ' ') { inCategoryMode = !inCategoryMode; } else if ( ch == '<' || ch == KEY_PPAGE ) { if( start > 0) { for (int i = 1; i < maxitems+4; i++) mvwprintz(w_inv, i, 0, c_black, " "); start -= maxitems; if (start < 0) start = 0; mvwprintw(w_inv, maxitems + 4, 0, " "); if ( selected > -1 ) selected = start; // oy, the cheese } } else if ( ch == '>' || ch == KEY_NPAGE ) { if ( cur_it < u.inv.size()) { start = cur_it; mvwprintw(w_inv, maxitems + 4, 12, " "); for (int i = 1; i < maxitems+4; i++) mvwprintz(w_inv, i, 0, c_black, " "); if ( selected < start && selected > -1 ) selected = start; } } else if ( ch == KEY_DOWN ) { if ( selected < 0 ) { selected = start; } else { if (inCategoryMode) { selected < firsts[category_order[category_order.size() - 1]] ? selected = next_category_at : 0; } else { selected++; } next_category_at = prev_category_at = 0; } if ( selected > max_it ) { if( cur_it < u.inv.size() ) { start = cur_it; mvwprintw(w_inv, maxitems + 4, 12, " "); for (int i = 1; i < maxitems+4; i++) mvwprintz(w_inv, i, 0, c_black, " "); } else { selected = u.inv.size() - 1; // wraparound? } } } else if ( ch == KEY_UP ) { inCategoryMode ? selected = prev_category_at : selected--; next_category_at = prev_category_at = 0; if ( selected < -1 ) { selected = -1; // wraparound? } else if ( selected < start ) { if ( start > 0 ) { for (int i = 1; i < maxitems+4; i++) mvwprintz(w_inv, i, 0, c_black, " "); start -= maxitems; if (start < 0) start = 0; mvwprintw(w_inv, maxitems + 4, 0, " "); } } } else if (ch >= '0'&& ch <= '9') { ch = (char)ch - '0'; count *= 10; count += ch; } else { // todo: reformat and maybe rewrite item* it; int it_pos; if ( ch == '\t' || ch == KEY_RIGHT || ch == KEY_LEFT ) { it_pos = selected_pos; it = &u.inv.find_item(it_pos); } else { it = &u.inv.item_by_letter((char)ch); it_pos = u.inv.position_by_item(it); } if (it == 0 || it->is_null()) { // Not from inventory int found = false; for (int i = 0; i < weapon_and_armor.size() && !found; i++) { if (weapon_and_armor[i] == ch) { weapon_and_armor.erase(weapon_and_armor.begin() + i); found = true; print_inv_statics(this, w_inv, _("Multidrop:"), weapon_and_armor); } } if (!found) { if ( ch == u.weapon.invlet && std::find(unreal_itype_ids.begin(), unreal_itype_ids.end(), u.weapon.type->id) != unreal_itype_ids.end()){ if (!warned_about_bionic) add_msg(_("You cannot drop your %s."), u.weapon.tname().c_str()); warned_about_bionic = true; } else { weapon_and_armor.push_back(ch); print_inv_statics(this, w_inv, _("Multidrop:"), weapon_and_armor); } } } else { int index = -1; for (int i = 0; i < stacks.size(); ++i) { if (stacks[i].first->front().invlet == it->invlet) { index = i; break; } } if (index == -1) { debugmsg("Inventory got out of sync with inventory slice?"); } if (count == 0) { if (it->count_by_charges()) { if (dropping[it_pos] == 0) { dropping[it_pos] = -1; } else { dropping[it_pos] = 0; } } else { if (dropping[it_pos] == 0) { dropping[it_pos] = stacks[index].first->size(); } else { dropping[it_pos] = 0; } } } else if (count >= stacks[index].first->size() && !it->count_by_charges()) { dropping[it_pos] = stacks[index].first->size(); } else { dropping[it_pos] = count; } count = 0; } } } while (ch != '\n' && ch != KEY_ESCAPE); werase(w_inv); delwin(w_inv); erase(); refresh_all(); std::vector<item> ret; if (ch != '\n') return ret; // Canceled! // We iterate backwards because deletion will invalidate later indices. for (std::map<int,int>::reverse_iterator it = dropping.rbegin(); it != dropping.rend(); ++it) { if (it->second == -1) ret.push_back( u.inv.remove_item( it->first)); else if (it->second && u.inv.find_item( it->first).count_by_charges()) { int charges = u.inv.find_item( it->first).charges;// >= it->second ? : it->second; ret.push_back( u.inv.reduce_charges( it->first, it->second > charges ? charges : it->second)); } else if (it->second) for (int j = it->second; j > 0; j--) ret.push_back( u.inv.remove_item( it->first)); } for (int i = 0; i < weapon_and_armor.size(); i++) { int wornpos = u.invlet_to_position(weapon_and_armor[i]); if (wornpos == INT_MIN || !u.takeoff(this, wornpos, true)) { continue; } // Item could have been dropped after taking it off if (&u.inv.item_by_letter(weapon_and_armor[i]) != &u.inv.nullitem) { ret.push_back(u.i_rem(weapon_and_armor[i])); } } return ret; }
std::vector<item> game::multidrop() { WINDOW* w_inv = newwin(TERRAIN_WINDOW_HEIGHT, TERRAIN_WINDOW_WIDTH + (use_narrow_sidebar() ? 45 : 55), VIEW_OFFSET_Y, VIEW_OFFSET_X); const int maxitems = TERRAIN_WINDOW_HEIGHT - 5; u.inv.restack(&u); u.inv.sort(); int drp_line_width=getmaxx(w_inv)-90; const std::string drp_line_padding = ( drp_line_width > 1 ? std::string(drp_line_width, ' ') : " "); std::map<char, int> dropping; // Count of how many we'll drop from each stack int count = 0; // The current count std::vector<char> weapon_and_armor; // Always single, not counted bool warned_about_bionic = false; // Printed add_msg re: dropping bionics print_inv_statics(this, w_inv, _("Multidrop:"), weapon_and_armor); int base_weight = u.weight_carried(); int base_volume = u.volume_carried(); int ch = (int)'.'; int start = 0, cur_it = 0, max_it; invslice stacks = u.inv.slice(0, u.inv.size()); std::vector<int> firsts = find_firsts(stacks); int selected=-1; int selected_char=(int)' '; do { inventory drop_subset = u.inv.subset(dropping); int new_weight = base_weight - drop_subset.weight(); int new_volume = base_volume - drop_subset.volume(); for (int i = 0; i < weapon_and_armor.size(); ++i) { new_weight -= u.i_at(weapon_and_armor[i]).weight(); } print_inv_weight_vol(this, w_inv, new_weight, new_volume); int cur_line = 2; max_it = 0; int drp_line = 1; // Print weapon to be dropped, the first position is reserved for high visibility mvwprintw(w_inv, 0, 90, "%s", drp_line_padding.c_str()); bool dropping_w = false; for (int k = 0; k < weapon_and_armor.size() && !dropping_w; k++) { if (weapon_and_armor[k] == u.weapon.invlet) { dropping_w = true; } if (dropping_w && u.is_armed()) { mvwprintz(w_inv, 0, 90, c_ltblue, "%c + %s", u.weapon.invlet, u.weapname().c_str()); } } // Print worn items to be dropped if(dropping_w) { mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str()); drp_line++; } bool dropping_a = false; if (u.worn.size() > 0){ for (int k = 0; k < u.worn.size(); k++) { bool dropping_w = false; for (int j = 0; j < weapon_and_armor.size() && !dropping_w; j++) { if (weapon_and_armor[j] == u.worn[k].invlet) { dropping_w = true; dropping_a = true; mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str()); mvwprintz(w_inv, drp_line, 90, c_cyan, "%c + %s", u.worn[k].invlet, u.worn[k].tname(this).c_str()); drp_line++; } } } } if(dropping_a) { mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str()); drp_line++; } for (cur_it = start; cur_it < start + maxitems && cur_line < maxitems+3; cur_it++) { // Clear the current line; mvwprintw(w_inv, cur_line, 0, " "); mvwprintw(w_inv, drp_line, 90, "%s", drp_line_padding.c_str()); mvwprintw(w_inv, drp_line + 1, 90, "%s", drp_line_padding.c_str()); // Print category header for (int i = 1; i < iCategorieNum; i++) { if (cur_it == firsts[i-1]) { mvwprintz(w_inv, cur_line, 0, c_magenta, _(CATEGORIES[i].c_str())); cur_line++; } } if ( selected < start && selected > -1 ) selected = start; if (cur_it < stacks.size()) { item& it = stacks[cur_it]->front(); if(cur_it==selected) selected_char=(int)it.invlet; mvwputch (w_inv, cur_line, 0, (cur_it == selected ? h_white : c_white), it.invlet); char icon = '-'; if (dropping[it.invlet] >= (it.count_by_charges() ? it.charges : stacks[cur_it]->size())) icon = '+'; else if (dropping[it.invlet] > 0) icon = '#'; nc_color col = ( cur_it == selected ? h_white : (dropping[it.invlet] == 0 ? c_ltgray : c_white ) ); mvwprintz(w_inv, cur_line, 1, col, " %c %s", icon, it.tname(this).c_str()); if (stacks[cur_it]->size() > 1) wprintz(w_inv, col, " [%d]", stacks[cur_it]->size()); if (it.charges > 0) wprintz(w_inv, col, " (%d)", it.charges); else if (it.contents.size() == 1 && it.contents[0].charges > 0) wprintw(w_inv, " (%d)", it.contents[0].charges); if (icon=='+'||icon=='#') { mvwprintz(w_inv, drp_line, 90, col, "%c %c %s", it.invlet, icon, it.tname(this).c_str()); if (icon=='+'){ if (stacks[cur_it]->size() > 1) wprintz(w_inv, col, " [%d]", stacks[cur_it]->size()); if (it.charges > 0) wprintz(w_inv, col, " (%d)", it.charges); } if (icon=='#') { wprintz(w_inv, col, " {%d}", dropping[it.invlet]); } drp_line++; } } cur_line++; max_it=cur_it; } if (start > 0) mvwprintw(w_inv, maxitems + 4, 0, _("< Go Back")); if (cur_it < u.inv.size()) mvwprintw(w_inv, maxitems + 4, 12, _("> More items")); wrefresh(w_inv); /* back to (int)getch() as input() mangles arrow keys ch = input(); */ ch = getch(); if ( ch == '<' || ch == KEY_PPAGE ) { if( start > 0) { for (int i = 1; i < maxitems+4; i++) mvwprintz(w_inv, i, 0, c_black, " "); start -= maxitems; if (start < 0) start = 0; mvwprintw(w_inv, maxitems + 4, 0, " "); if ( selected > -1 ) selected = start; // oy, the cheese } } else if ( ch == '>' || ch == KEY_NPAGE ) { if ( cur_it < u.inv.size()) { start = cur_it; mvwprintw(w_inv, maxitems + 4, 12, " "); for (int i = 1; i < maxitems+4; i++) mvwprintz(w_inv, i, 0, c_black, " "); if ( selected < start && selected > -1 ) selected = start; } } else if ( ch == KEY_DOWN ) { if ( selected < 0 ) { selected = start; } else { selected++; } if ( selected > max_it ) { if( cur_it < u.inv.size() ) { start = cur_it; mvwprintw(w_inv, maxitems + 4, 12, " "); for (int i = 1; i < maxitems+4; i++) mvwprintz(w_inv, i, 0, c_black, " "); } else { selected = u.inv.size() - 1; // wraparound? } } } else if ( ch == KEY_UP ) { selected--; if ( selected < -1 ) { selected = -1; // wraparound? } else if ( selected < start ) { if ( start > 0 ) { for (int i = 1; i < maxitems+4; i++) mvwprintz(w_inv, i, 0, c_black, " "); start -= maxitems; if (start < 0) start = 0; mvwprintw(w_inv, maxitems + 4, 0, " "); } } } else if (ch >= '0'&& ch <= '9') { ch = (char)ch - '0'; count *= 10; count += ch; } else { // todo: reformat and maybe rewrite if ( ch == '\t' || ch == KEY_RIGHT || ch == KEY_LEFT ) { ch = selected_char; } if (u.has_item(ch)) { item& it = u.inv.item_by_letter(ch); if (it.is_null()) { // Not from inventory int found = false; for (int i = 0; i < weapon_and_armor.size() && !found; i++) { if (weapon_and_armor[i] == ch) { weapon_and_armor.erase(weapon_and_armor.begin() + i); found = true; print_inv_statics(this, w_inv, _("Multidrop:"), weapon_and_armor); } } if (!found) { if ( ch == u.weapon.invlet && std::find(unreal_itype_ids.begin(), unreal_itype_ids.end(), u.weapon.type->id) != unreal_itype_ids.end()){ if (!warned_about_bionic) add_msg(_("You cannot drop your %s."), u.weapon.tname(this).c_str()); warned_about_bionic = true; } else { weapon_and_armor.push_back(ch); print_inv_statics(this, w_inv, _("Multidrop:"), weapon_and_armor); } } } else { int index = -1; for (int i = 0; i < stacks.size(); ++i) { if (stacks[i]->front().invlet == it.invlet) { index = i; break; } } if (index == -1) { debugmsg("Inventory got out of sync with inventory slice?"); } if (count == 0) { if (it.count_by_charges()) { if (dropping[it.invlet] == 0) dropping[it.invlet] = -1; else dropping[it.invlet] = 0; } else { if (dropping[it.invlet] == 0) dropping[it.invlet] = stacks[index]->size(); else dropping[it.invlet] = 0; } } else if (count >= stacks[index]->size() && !it.count_by_charges()) dropping[it.invlet] = stacks[index]->size(); else dropping[it.invlet] = count; count = 0; } } } } while (ch != '\n' && ch != KEY_ESCAPE && ch != ' '); werase(w_inv); delwin(w_inv); erase(); refresh_all(); std::vector<item> ret; if (ch != '\n') return ret; // Canceled! for (std::map<char,int>::iterator it = dropping.begin(); it != dropping.end(); ++it) { if (it->second == -1) ret.push_back( u.inv.remove_item_by_letter( it->first)); else if (it->second && u.inv.item_by_letter( it->first).count_by_charges()) { int charges = u.inv.item_by_letter( it->first).charges;// >= it->second ? : it->second; ret.push_back( u.inv.remove_item_by_charges( it->first, it->second > charges ? charges : it->second)); } else if (it->second) for (int j = it->second; j > 0; j--) ret.push_back( u.inv.remove_item_by_letter( it->first)); } for (int i = 0; i < weapon_and_armor.size(); i++) { if (!u.takeoff(this, weapon_and_armor[i], true)) { continue; } // Item could have been dropped after taking it off if (&u.inv.item_by_letter(weapon_and_armor[i]) != &u.inv.nullitem) { ret.push_back(u.i_rem(weapon_and_armor[i])); } } return ret; }
void inventory_selector::display( const std::string &title, selector_mode mode ) const { werase(w_inv); mvwprintw(w_inv, 0, 0, title.c_str()); // Position of inventory columns is adaptive. They're aligned to the left if they occupy less than 2/3 of the screen. // Otherwise they're aligned symmetrically to the center of the screen. static const float min_ratio_to_center = 1.f / 3; const int free_space = getmaxx( w_inv ) - get_columns_width(); const bool center_align = std::abs( float( free_space ) / getmaxx( w_inv ) ) <= min_ratio_to_center; const int max_gap = ( columns.size() > 1 ) ? free_space / ( columns.size() - 1 ) : 0; const int gap = center_align ? max_gap : std::min<int>( max_gap, 4 ); const int gap_rounding_error = ( center_align && columns.size() > 1 ) ? free_space % ( columns.size() - 1 ) : 0; size_t x = 1; size_t y = 2; size_t active_x = 0; for( const auto &column : columns ) { if( &column == &columns.back() ) { x += gap_rounding_error; } if( !is_active_column( *column ) ) { column->draw( w_inv, x, y ); } else { active_x = x; } if( column->pages_count() > 1 ) { mvwprintw( w_inv, getmaxy( w_inv ) - 2, x, _( "Page %d/%d" ), column->page_index() + 1, column->pages_count() ); } x += column->get_width() + gap; } get_active_column().draw( w_inv, active_x, y ); if( mode == SM_PICK ) { mvwprintw(w_inv, 1, 61, _("Hotkeys: %d/%d "), u.allocated_invlets().size(), inv_chars.size()); } if (mode == SM_MULTIDROP) { // Make copy, remove to be dropped items from that // copy and let the copy recalculate the volume capacity // (can be affected by various traits). player tmp = u; // first round: remove weapon & worn items, start with larges worn index for( const auto &elem : dropping ) { if( elem.first == -1 && elem.second == -1 ) { tmp.remove_weapon(); } else if( elem.first == -1 && elem.second != -1 ) { tmp.weapon.charges -= elem.second; } else if( elem.first < 0 ) { tmp.i_rem( elem.first ); } } remove_dropping_items(tmp); print_inv_weight_vol(tmp.weight_carried(), tmp.volume_carried(), tmp.volume_capacity()); mvwprintw(w_inv, 1, 0, _("To drop x items, type a number and then the item hotkey.")); } else { print_inv_weight_vol(u.weight_carried(), u.volume_carried(), u.volume_capacity()); } if( empty() ) { center_print( w_inv, getmaxy( w_inv ) / 2, c_dkgray, _( "Your inventory is empty." ) ); } const std::string msg_str = ( navigation == navigation_mode::CATEGORY ) ? _( "Category selection; [TAB] switches mode, arrows select." ) : _( "Item selection; [TAB] switches mode, arrows select." ); const nc_color msg_color = ( navigation == navigation_mode::CATEGORY ) ? h_white : c_ltgray; if( center_align ) { center_print( w_inv, getmaxy( w_inv ) - 1, msg_color, msg_str.c_str() ); } else { trim_and_print( w_inv, getmaxy( w_inv ) - 1, 1, getmaxx( w_inv ), msg_color, msg_str.c_str() ); } wrefresh(w_inv); }