void inventory_selector::display(bool show_worn) const
{
    const size_t &current_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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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);
}