/* Explosion Animation */ void game::draw_explosion(int x, int y, int radius, nc_color col) { timespec ts; // Timespec for the animation of the explosion ts.tv_sec = 0; ts.tv_nsec = EXPLOSION_SPEED; const int ypos = POSY + (y - (u.posy + u.view_offset_y)); const int xpos = POSX + (x - (u.posx + u.view_offset_x)); for (int i = 1; i <= radius; i++) { mvwputch(w_terrain, ypos - i, xpos - i, col, '/'); mvwputch(w_terrain, ypos - i, xpos + i, col, '\\'); mvwputch(w_terrain, ypos + i, xpos - i, col, '\\'); mvwputch(w_terrain, ypos + i, xpos + i, col, '/'); for (int j = 1 - i; j < 0 + i; j++) { mvwputch(w_terrain, ypos - i, xpos + j, col, '-'); mvwputch(w_terrain, ypos + i, xpos + j, col, '-'); mvwputch(w_terrain, ypos + j, xpos - i, col, '|'); mvwputch(w_terrain, ypos + j, xpos + i, col, '|'); } wrefresh(w_terrain); nanosleep(&ts, NULL); } }
void monster::draw(WINDOW *w, int plx, int ply, bool inv) { int x = SEEX + posx - plx; int y = SEEY + posy - ply; nc_color color = type->color; // see if it's possible to draw a graphical sprite if(type->sprite) { if(draw_object(w, x, y, type->sprite)) return; } if (friendly != 0 && !inv) mvwputch_hi(w, y, x, color, type->sym); else if (inv) mvwputch_inv(w, y, x, color, type->sym); else { color = color_with_effects(); mvwputch(w, y, x, color, type->sym); } }
void hit_animation(int iX, int iY, nc_color cColor, char cTile, int iTimeout) { WINDOW *w_hit = newwin(1, 1, iY + VIEW_OFFSET_Y, iX + VIEW_OFFSET_X); if (w_hit == NULL) { return; //we passed in negative values (semi-expected), so let's not segfault } w_hit_animation = w_hit; mvwputch(w_hit, 0, 0, cColor, cTile); wrefresh(w_hit); if (iTimeout <= 0 || iTimeout > 999) { iTimeout = 70; } timeout(iTimeout); getch(); //using this, because holding down a key with nanosleep can get yourself killed timeout(-1); w_hit_animation = NULL; }
/* Bullet Animation */ void game::draw_bullet(player &p, int tx, int ty, int i, std::vector<point> trajectory, char bullet, timespec &ts) { if (u_see(tx, ty)) { if (i > 0) { m.drawsq(w_terrain, u, trajectory[i-1].x, trajectory[i-1].y, false, true, u.posx + u.view_offset_x, u.posy + u.view_offset_y); } /* char bullet = '*'; if (is_aflame) bullet = '#'; */ mvwputch(w_terrain, POSY + (ty - (u.posy + u.view_offset_y)), POSX + (tx - (u.posx + u.view_offset_x)), c_red, bullet); wrefresh(w_terrain); if (&p == &u) nanosleep(&ts, NULL); } }
void game::draw_weather(weather_printable wPrint) { if (use_tiles) { std::string weather_name; switch(wPrint.wtype) { // Acid weathers, uses acid droplet tile, fallthrough intended case WEATHER_ACID_DRIZZLE: case WEATHER_ACID_RAIN: weather_name = "weather_acid_drop"; break; // Normal rainy weathers, uses normal raindrop tile, fallthrough intended case WEATHER_DRIZZLE: case WEATHER_RAINY: case WEATHER_THUNDER: case WEATHER_LIGHTNING: weather_name = "weather_rain_drop"; break; // Snowy weathers, uses snowflake tile, fallthrough intended case WEATHER_FLURRIES: case WEATHER_SNOW: case WEATHER_SNOWSTORM: weather_name = "weather_snowflake"; break; default: break; } tilecontext->init_draw_weather(wPrint, weather_name); } else { for (std::vector<std::pair<int, int> >::iterator weather_iterator = wPrint.vdrops.begin(); weather_iterator != wPrint.vdrops.end(); ++weather_iterator) { mvwputch(w_terrain, weather_iterator->second, weather_iterator->first, wPrint.colGlyph, wPrint.cGlyph); } } }
// need to have a version where there is no player defined, possibly. That way shrapnel works as intended void game::draw_bullet(player &p, int tx, int ty, int i, std::vector<point> trajectory, char bullet_char, timespec &ts) { if (u_see(tx, ty)) { std::string bullet;// = "animation_bullet_normal"; switch(bullet_char) { case '*': bullet = "animation_bullet_normal"; break; case '#': bullet = "animation_bullet_flame"; break; case '`': bullet = "animation_bullet_shrapnel"; break; } mvwputch(w_terrain, ty + VIEWY - u.posy - u.view_offset_y, tx + VIEWX - u.posx - u.view_offset_x, c_red, bullet_char); // pass to tilecontext tilecontext->init_draw_bullet(tx, ty, bullet); wrefresh(w_terrain); if (&p == &u) nanosleep(&ts, NULL); tilecontext->void_bullet(); } }
static void draw_recipe_subtabs( const catacurses::window &w, std::string tab, std::string subtab, const recipe_subset &available_recipes, TAB_MODE mode ) { werase( w ); int width = getmaxx( w ); for( int i = 0; i < width; i++ ) { if( i == 0 ) { mvwputch( w, 2, i, BORDER_COLOR, LINE_XXXO ); } else if( i == width ) { mvwputch( w, 2, i, BORDER_COLOR, LINE_XOXX ); } else { mvwputch( w, 2, i, BORDER_COLOR, LINE_OXOX ); } } for( int i = 0; i < 3; i++ ) { mvwputch( w, i, 0, BORDER_COLOR, LINE_XOXO ); // |^ mvwputch( w, i, width - 1, BORDER_COLOR, LINE_XOXO ); // ^| } switch( mode ) { case NORMAL: { int pos_x = 2;//draw the tabs on each other int tab_step = 3;//step between tabs, two for tabs border for( const auto stt : craft_subcat_list[tab] ) { bool empty = available_recipes.empty_category( tab, stt != "CSC_ALL" ? stt : "" ); draw_subtab( w, pos_x, normalized_names[stt], subtab == stt, true, empty ); pos_x += utf8_width( normalized_names[stt] ) + tab_step; } break; } case FILTERED: case BATCH: werase( w ); for( int i = 0; i < 3; i++ ) { mvwputch( w, i, 0, BORDER_COLOR, LINE_XOXO ); // |^ mvwputch( w, i, width - 1, BORDER_COLOR, LINE_XOXO ); // ^| } break; } wrefresh( w ); }
/* Bullet Animation */ void game::draw_bullet(Creature &p, int tx, int ty, int i, std::vector<point> trajectory, char bullet, timespec &ts) { if (u.sees(tx, ty)) { if (i > 0) { m.drawsq(w_terrain, u, trajectory[i - 1].x, trajectory[i - 1].y, false, true, u.posx() + u.view_offset_x, u.posy() + u.view_offset_y); } /* char bullet = '*'; if (is_aflame) bullet = '#'; */ mvwputch(w_terrain, POSY + (ty - (u.posy() + u.view_offset_y)), POSX + (tx - (u.posx() + u.view_offset_x)), c_red, bullet); wrefresh(w_terrain); if( p.is_player() && ts.tv_nsec != 0 ) { nanosleep(&ts, NULL); } } }
/* Monster hit animation */ void game::draw_hit_mon(int x, int y, monster m, bool dead) { if (use_tiles) { //int iTimeout = 0; tilecontext->init_draw_hit(x, y, monster_names[m.type->id]); wrefresh(w_terrain); timespec tspec; tspec.tv_sec = 0; tspec.tv_nsec = BULLET_SPEED; nanosleep(&tspec, NULL); /* nc_color cMonColor = m.type->color; char sMonSym = m.symbol(); hit_animation(x, y, red_background(cMonColor), dead?'%':sMonSym); */ /* x + VIEWX - u.posx - u.view_offset_x, y + VIEWY - u.posy - u.view_offset_y, */ mvwputch(w_terrain, x + VIEWX - u.posx - u.view_offset_x, y + VIEWY - u.posy - u.view_offset_y, c_white, ' '); wrefresh(w_terrain); } else { nc_color cMonColor = m.type->color; char sMonSym = m.symbol(); hit_animation(x + VIEWX - u.posx - u.view_offset_x, y + VIEWY - u.posy - u.view_offset_y, red_background(cMonColor), dead?'%':sMonSym); } }
void inventory_selector::print_column(const itemstack_vector &items, size_t y, size_t w, size_t selected, size_t current_page_offset) const { nc_color selected_line_color = inCategoryMode ? c_white_red : h_white; if ((&items == &this->items) != in_inventory) { selected_line_color = inCategoryMode ? c_ltgray_red : h_ltgray; } int cur_line = 2; for (size_t a = 0; a + current_page_offset < items.size() && a < items_per_page; a++, cur_line++) { const itemstack_or_category &cur_entry = items[a + current_page_offset]; if (cur_entry.category == NULL) { continue; } if (cur_entry.it == NULL) { const std::string name = trim_to(cur_entry.category->name, w); mvwprintz(w_inv, cur_line, y, c_magenta, "%s", name.c_str()); continue; } const item &it = *cur_entry.it; std::string item_name = it.display_name(); if (cur_entry.slice != NULL) { const size_t count = cur_entry.slice->size(); if (count > 1) { item_name = string_format("%d %s", count, it.display_name(count).c_str()); } } nc_color name_color = it.color_in_inventory(); nc_color invlet_color = c_white; if (a + current_page_offset == selected) { name_color = selected_line_color; invlet_color = selected_line_color; } item_name = get_drop_icon(dropping.find(cur_entry.item_pos)) + item_name; item_name = trim_to(item_name, w - 2); // 2 for the invlet & space if (it.invlet != 0) { mvwputch(w_inv, cur_line, y, invlet_color, it.invlet); } mvwprintz(w_inv, cur_line, y + 2, name_color, "%s", item_name.c_str()); } }
void editmap::uber_draw_ter( WINDOW *w, map *m ) { point center = target; point start = point(center.x - getmaxx(w) / 2, center.y - getmaxy(w) / 2); point end = point(center.x + getmaxx(w) / 2, center.y + getmaxy(w) / 2); /* // pending filter options bool draw_furn=true; bool draw_ter=true; bool draw_trp=true; bool draw_fld=true; bool draw_veh=true; */ bool draw_itm = true; bool game_map = ( ( m == &g->m || w == g->w_terrain ) ? true : false ); const int msize = SEEX * MAPSIZE; for (int x = start.x, sx = 0; x <= end.x; x++, sx++) { for (int y = start.y, sy = 0; y <= end.y; y++, sy++) { nc_color col = c_dkgray; long sym = ( game_map ? '%' : ' ' ); if ( x >= 0 && x < msize && y >= 0 && y < msize ) { if ( game_map ) { int mon_idx = g->mon_at(x, y); int npc_idx = g->npc_at(x, y); if ( mon_idx >= 0 ) { g->zombie(mon_idx).draw(w, center.x, center.y, false); } else if ( npc_idx >= 0 ) { g->active_npc[npc_idx]->draw(w, center.x, center.y, false); } else { m->drawsq(w, g->u, x, y, false, draw_itm, center.x, center.y, false, true); } } else { m->drawsq(w, g->u, x, y, false, draw_itm, center.x, center.y, false, true); } } else { mvwputch(w, sy, sx, col, sym); } } } }
std::string string_input_popup(std::string title, int max_length, std::string input) { std::string ret = input; int startx = title.size() + 2; WINDOW *w = newwin(3, 80, (TERMY-3)/2, ((TERMX > 80) ? (TERMX-80)/2 : 0)); wborder(w, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); for (int i = startx + 1; i < 79; i++) mvwputch(w, 1, i, c_ltgray, '_'); mvwprintz(w, 1, 1, c_ltred, "%s", title.c_str()); if (input != "") mvwprintz(w, 1, startx, c_magenta, "%s", input.c_str()); int posx = startx + input.size(); mvwputch(w, 1, posx, h_ltgray, '_'); do { wrefresh(w); long ch = getch(); if (ch == 27) { // Escape werase(w); wrefresh(w); delwin(w); refresh(); return ""; } else if (ch == '\n') { werase(w); wrefresh(w); delwin(w); refresh(); return ret; } else if ((ch == KEY_BACKSPACE || ch == 127) && posx > startx) { // Move the cursor back and re-draw it ret = ret.substr(0, ret.size() - 1); mvwputch(w, 1, posx, c_ltgray, '_'); posx--; mvwputch(w, 1, posx, h_ltgray, '_'); } else if(ret.size() < max_length || max_length == 0) { ret += ch; mvwputch(w, 1, posx, c_magenta, ch); posx++; mvwputch(w, 1, posx, h_ltgray, '_'); } } while (true); }
void sokoban_game::draw_level(WINDOW *w_sokoban) { const int iOffsetX = (FULL_SCREEN_WIDTH - 2 - mLevelInfo[iCurrentLevel]["MaxLevelX"]) / 2; const int iOffsetY = (FULL_SCREEN_HEIGHT - 2 - mLevelInfo[iCurrentLevel]["MaxLevelY"]) / 2; for (std::map<int, std::map<int, std::string> >::iterator iterY = mLevel.begin(); iterY != mLevel.end(); ++iterY) { for (std::map<int, std::string>::iterator iterX = (iterY->second).begin(); iterX != (iterY->second).end(); ++iterX) { std::string sTile = iterX->second; if (sTile == "#") { mvwputch(w_sokoban, iOffsetY + (iterY->first), iOffsetX + (iterX->first), c_white, get_wall_connection(iterY->first, iterX->first)); } else { nc_color cCol = c_white; if (sTile == "." || sTile == "*" || sTile == "+") { cCol = red_background(c_white); } if (sTile == ".") { sTile = " "; } if (sTile == "*") { sTile = "$"; } if (sTile == "+") { sTile = "@"; } mvwprintz(w_sokoban, iOffsetY + (iterY->first), iOffsetX + (iterX->first), cCol, sTile.c_str()); } } } }
std::string string_input_popup(int max_length, const char *mes, ...) { std::string ret; va_list ap; va_start(ap, mes); char buff[1024]; vsprintf(buff, mes, ap); va_end(ap); int startx = strlen(buff) + 2; WINDOW* w = newwin(3, 80, 11, 0); wborder(w, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); mvwprintz(w, 1, 1, c_ltred, "%s", buff); for (int i = startx + 1; i < 79; i++) mvwputch(w, 1, i, c_ltgray, '_'); int posx = startx; mvwputch(w, 1, posx, h_ltgray, '_'); do { wrefresh(w); long ch = getch(); if (ch == 27) { // Escape werase(w); wrefresh(w); delwin(w); refresh(); return ""; } else if (ch == '\n') { werase(w); wrefresh(w); delwin(w); refresh(); return ret; } else if ((ch == KEY_BACKSPACE || ch == 127) && posx > startx) { // Move the cursor back and re-draw it ret = ret.substr(0, ret.size() - 1); mvwputch(w, 1, posx, c_ltgray, '_'); posx--; mvwputch(w, 1, posx, h_ltgray, '_'); } else if(ret.size() < max_length || max_length == 0) { ret += ch; mvwputch(w, 1, posx, c_magenta, ch); posx++; mvwputch(w, 1, posx, h_ltgray, '_'); } } while (true); }
/* Tiles version of Explosion Animation */ void game::draw_explosion(int x, int y, int radius, nc_color col) { timespec ts; // Timespec for the animation of the explosion ts.tv_sec = 0; ts.tv_nsec = EXPLOSION_SPEED; // added offset values to keep from calculating the same value over and over again. const int offset_x = VIEWX - u.posx - u.view_offset_x; const int offset_y = VIEWY - u.posy - u.view_offset_y; for (int i = 1; i <= radius; i++) { mvwputch(w_terrain, y - i + offset_y, x - i + offset_x, col, '/'); mvwputch(w_terrain, y - i + offset_y, x + i + offset_x, col,'\\'); mvwputch(w_terrain, y + i + offset_y, x - i + offset_x, col,'\\'); mvwputch(w_terrain, y + i + offset_y, x + i + offset_x, col, '/'); for (int j = 1 - i; j < 0 + i; j++) { mvwputch(w_terrain, y - i + offset_y, x + j + offset_x, col,'-'); mvwputch(w_terrain, y + i + offset_y, x + j + offset_x, col,'-'); mvwputch(w_terrain, y + j + offset_y, x - i + offset_x, col,'|'); mvwputch(w_terrain, y + j + offset_y, x + i + offset_x, col,'|'); } tilecontext->init_explosion(x, y, i); //tilecontext->draw_explosion_frame(x, y, radius, offset_x, offset_y); wrefresh(w_terrain); nanosleep(&ts, NULL); } tilecontext->void_explosion(); }
static void draw_recipe_subtabs( WINDOW *w, std::string tab, std::string subtab, TAB_MODE mode ) { werase( w ); int width = getmaxx( w ); for( int i = 0; i < width; i++ ) { if( i == 0 ) { mvwputch( w, 2, i, BORDER_COLOR, LINE_XXXO ); } else if( i == width ) { mvwputch( w, 2, i, BORDER_COLOR, LINE_XOXX ); } else { mvwputch( w, 2, i, BORDER_COLOR, LINE_OXOX ); } } for( int i = 0; i < 3; i++ ) { mvwputch( w, i, 0, BORDER_COLOR, LINE_XOXO ); // |^ mvwputch( w, i, width - 1, BORDER_COLOR, LINE_XOXO ); // ^| } switch( mode ) { case NORMAL: { int pos_x = 2;//draw the tabs on each other int tab_step = 3;//step between tabs, two for tabs border for( const auto stt : craft_subcat_list[tab] ) { draw_subtab( w, pos_x, normalized_names[stt], subtab == stt ); pos_x += utf8_width( normalized_names[stt] ) + tab_step; } break; } case FILTERED: case BATCH: werase( w ); for( int i = 0; i < 3; i++ ) { mvwputch( w, i, 0, BORDER_COLOR, LINE_XOXO ); // |^ mvwputch( w, i, width - 1, BORDER_COLOR, LINE_XOXO ); // ^| } break; } wrefresh( w ); }
// draws footsteps that have been created by monsters moving about void game::draw_footsteps() { std::queue<point> step_tiles; for (int i = 0; i < footsteps.size(); i++) { if (!u_see(footsteps_source[i]->posx(),footsteps_source[i]->posy())){ std::vector<point> unseen_points; for (int j = 0; j < footsteps[i].size(); j++){ if (!u_see(footsteps[i][j].x,footsteps[i][j].y)){ unseen_points.push_back(point(footsteps[i][j].x, footsteps[i][j].y)); } } if (use_tiles){ if (unseen_points.size() > 0){ step_tiles.push(unseen_points[rng(0, unseen_points.size()-1)]); } }else{ if (unseen_points.size() > 0){ point selected = unseen_points[rng(0,unseen_points.size() - 1)]; mvwputch(w_terrain, POSY + (selected.y - (u.posy + u.view_offset_y)), POSX + (selected.x - (u.posx + u.view_offset_x)), c_yellow, '?'); } } } } if (use_tiles){ tilecontext->init_draw_footsteps(step_tiles); } footsteps.clear(); footsteps_source.clear(); wrefresh(w_terrain); return; }
int worldfactory::show_worldgen_tab_options(WINDOW *win, WORLDPTR world) { const int iTooltipHeight = 4; const int iContentHeight = FULL_SCREEN_HEIGHT - 5 - 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 + 4 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_optionsptr( w_options ); WINDOW *w_options_tooltip = newwin(iTooltipHeight - 2, FULL_SCREEN_WIDTH - 2, 3 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_options_tooltipptr( w_options_tooltip ); WINDOW *w_options_header = newwin(1, FULL_SCREEN_WIDTH - 2, iTooltipHeight + 3 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_options_headerptr( w_options_header ); std::stringstream sTemp; std::map<int, bool> mapLines; mapLines[4] = true; mapLines[60] = true; for( auto &mapLine : mapLines ) { mvwputch( win, FULL_SCREEN_HEIGHT - 1, mapLine.first + 1, BORDER_COLOR, LINE_XXOX ); // _|_ } for (int i = 0; i < 78; i++) { if (mapLines[i]) { mvwputch(w_options_header, 0, i, BORDER_COLOR, LINE_OXXX); } else { mvwputch(w_options_header, 0, i, BORDER_COLOR, LINE_OXOX); // Draw header line } } mvwputch(win, iTooltipHeight + 3, 0, BORDER_COLOR, LINE_XXXO); // |- mvwputch(win, iTooltipHeight + 3, 79, BORDER_COLOR, LINE_XOXX); // -| wrefresh(win); wrefresh(w_options_header); 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"); int iStartPos = 0; int iCurrentLine = 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, ' '); } if (i < iTooltipHeight) { mvwputch(w_options_tooltip, i, j, c_black, ' '); } } } calcStartPos(iStartPos, iCurrentLine, iContentHeight, mPageItems[iWorldOptPage].size()); //Draw options int iBlankOffset = 0; for (int i = iStartPos; i < iStartPos + ((iContentHeight > (int)mPageItems[iWorldOptPage].size()) ? (int)mPageItems[iWorldOptPage].size() : iContentHeight); i++) { nc_color cLineColor = c_ltgreen; if (world->world_options[mPageItems[iWorldOptPage][i]].getMenuText() == "") { iBlankOffset++; continue; } sTemp.str(""); sTemp << i + 1 - iBlankOffset; mvwprintz(w_options, i - iStartPos, 1, c_white, sTemp.str().c_str()); mvwprintz(w_options, i - iStartPos, 5, c_white, ""); if (iCurrentLine == i) { wprintz(w_options, c_yellow, ">> "); } else { wprintz(w_options, c_yellow, " "); } wprintz(w_options, c_white, "%s", (world->world_options[mPageItems[iWorldOptPage][i]].getMenuText()).c_str()); if (world->world_options[mPageItems[iWorldOptPage][i]].getValue() == "false") { cLineColor = c_ltred; } mvwprintz(w_options, i - iStartPos, 62, (iCurrentLine == i) ? hilite(cLineColor) : cLineColor, "%s", (world->world_options[mPageItems[iWorldOptPage][i]].getValueName()).c_str()); } //Draw Scrollbar draw_scrollbar(win, iCurrentLine, iContentHeight, mPageItems[iWorldOptPage].size(), iTooltipHeight + 4, 0, BORDER_COLOR); fold_and_print(w_options_tooltip, 0, 0, 78, c_white, "%s #%s", world->world_options[mPageItems[iWorldOptPage][iCurrentLine]].getTooltip().c_str(), world->world_options[mPageItems[iWorldOptPage][iCurrentLine]].getDefaultText().c_str()); wrefresh(w_options_tooltip); wrefresh(w_options); refresh(); const std::string action = ctxt.handle_input(); if (action == "DOWN") { do { iCurrentLine++; if (iCurrentLine >= (int)mPageItems[iWorldOptPage].size()) { iCurrentLine = 0; } } while(world->world_options[mPageItems[iWorldOptPage][iCurrentLine]].getMenuText() == ""); } else if (action == "UP") { do { iCurrentLine--; if (iCurrentLine < 0) { iCurrentLine = mPageItems[iWorldOptPage].size() - 1; } } while(world->world_options[mPageItems[iWorldOptPage][iCurrentLine]].getMenuText() == ""); } else if (!mPageItems[iWorldOptPage].empty() && action == "RIGHT") { world->world_options[mPageItems[iWorldOptPage][iCurrentLine]].setNext(); } else if (!mPageItems[iWorldOptPage].empty() && action == "LEFT") { world->world_options[mPageItems[iWorldOptPage][iCurrentLine]].setPrev(); } else if (action == "PREV_TAB") { return -1; } else if (action == "NEXT_TAB") { return 1; } else if (action == "QUIT") { return -999; } } while (true); return 0; }
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 if (world_need_lua_build(*it)) { 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( auto &mapLine : mapLines ) { mvwputch( w_worlds_border, FULL_SCREEN_HEIGHT - 1, mapLine.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, ""); std::string world_name = (world_pages[selpage])[i]; size_t saves_num = world_generator->all_worlds[world_name]->world_saves.size(); if (i == sel) { wprintz(w_worlds, c_yellow, ">> "); } else { wprintz(w_worlds, c_yellow, " "); } if (world_need_lua_build(world_name)) { wprintz(w_worlds, c_dkgray, "%s (%i)", world_name.c_str(), saves_num); } else { wprintz(w_worlds, c_white, "%s (%i)", world_name.c_str(), saves_num); } } //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") { if (world_need_lua_build(world_pages[selpage][sel])) { popup(_("Can't start in world [%s]. Some of mods require Lua support."), world_pages[selpage][sel].c_str()); continue; } // 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; }
void worldfactory::draw_modselection_borders(WINDOW *win, input_context *ctxtp) { // make appropriate lines: X & Y coordinate of starting point, length, horizontal/vertical type int xs[] = {1, 1, (FULL_SCREEN_WIDTH / 2) + 2, (FULL_SCREEN_WIDTH / 2) - 4, (FULL_SCREEN_WIDTH / 2) + 2 }; int ys[] = {FULL_SCREEN_HEIGHT - 8, 4, 4, 3, 3}; int ls[] = {FULL_SCREEN_WIDTH - 2, (FULL_SCREEN_WIDTH / 2) - 4, (FULL_SCREEN_WIDTH / 2) - 3, FULL_SCREEN_HEIGHT - 11, 1 }; bool hv[] = {true, true, true, false, false}; // horizontal line = true, vertical line = false for (int i = 0; i < 5; ++i) { int x = xs[i]; int y = ys[i]; int l = ls[i]; if (hv[i]) { for (int j = 0; j < l; ++j) { mvwputch(win, y, x + j, BORDER_COLOR, LINE_OXOX); // _ } } else { for (int j = 0; j < l; ++j) { mvwputch(win, y + j, x, BORDER_COLOR, LINE_XOXO); // | } } } // Add in connective characters mvwputch(win, 4, 0, BORDER_COLOR, LINE_XXXO); mvwputch(win, FULL_SCREEN_HEIGHT - 8, 0, BORDER_COLOR, LINE_XXXO); mvwputch(win, 4, FULL_SCREEN_WIDTH / 2 + 2, BORDER_COLOR, LINE_XXXO); mvwputch(win, 4, FULL_SCREEN_WIDTH - 1, BORDER_COLOR, LINE_XOXX); mvwputch(win, FULL_SCREEN_HEIGHT - 8, FULL_SCREEN_WIDTH - 1, BORDER_COLOR, LINE_XOXX); mvwputch(win, 4, FULL_SCREEN_WIDTH / 2 - 4, BORDER_COLOR, LINE_XOXX); mvwputch(win, 2, FULL_SCREEN_WIDTH / 2 - 4, BORDER_COLOR, LINE_OXXX); // -.- mvwputch(win, 2, FULL_SCREEN_WIDTH / 2 + 2, BORDER_COLOR, LINE_OXXX); // -.- mvwputch(win, FULL_SCREEN_HEIGHT - 8, FULL_SCREEN_WIDTH / 2 - 4, BORDER_COLOR, LINE_XXOX); // _|_ mvwputch(win, FULL_SCREEN_HEIGHT - 8, FULL_SCREEN_WIDTH / 2 + 2, BORDER_COLOR, LINE_XXOX); // _|_ // Add tips & hints fold_and_print(win, FULL_SCREEN_HEIGHT - 7, 2, getmaxx(win) - 4, c_green, _("Press %s to save the list of active mods as default. Press %s for help."), ctxtp->get_desc("SAVE_DEFAULT_MODS").c_str(), ctxtp->get_desc("HELP_KEYBINDINGS").c_str() ); wrefresh(win); refresh(); }
void game::compare(int iCompareX, int iCompareY) { int examx, examy; int ch = (int)'.'; if (iCompareX != -999 && iCompareX != -999) { examx = iCompareX; examy = iCompareY; } else { mvwprintw(w_terrain, 0, 0, "Compare where? (Direction button)"); wrefresh(w_terrain); ch = input(); last_action += ch; if (ch == KEY_ESCAPE || ch == 'q') return; if (ch == '\n' || ch == 'I') ch = '.'; get_direction(this, examx, examy, ch); if (examx == -2 || examy == -2) { add_msg("Invalid direction."); return; } } examx += u.posx; examy += u.posy; std::vector <item> here = m.i_at(examx, examy); std::vector <item> grounditems; //Filter out items with the same name (keep only one of them) std::map <std::string, bool> dups; for (int i = 0; i < here.size(); i++) { if (!dups[here[i].tname(this).c_str()]) { grounditems.push_back(here[i]); dups[here[i].tname(this).c_str()] = true; } } //Only the first 10 Items due to numbering 0-9 const int groundsize = (grounditems.size() > 10 ? 10 : grounditems.size()); u.inv.sort(); u.inv.restack(&u); invslice stacks = u.inv.slice(0, u.inv.size()); WINDOW* w_inv = newwin(TERMY-VIEW_OFFSET_Y*2, TERMX-VIEW_OFFSET_X*2, VIEW_OFFSET_Y, VIEW_OFFSET_X); int maxitems = TERMY-5-VIEW_OFFSET_Y*2; // Number of items to show at one time. std::vector<int> compare_list; // Count of how many we'll drop from each stack bool bFirst = false; // First Item selected bool bShowCompare = false; char cLastCh; compare_list.resize(u.inv.size() + groundsize, 0); std::vector<char> weapon_and_armor; // Always single, not counted print_inv_statics(this, w_inv, "Compare:", weapon_and_armor); // Gun, ammo, weapon, armor, food, tool, book, other std::vector<int> first = find_firsts(stacks); std::vector<int> firsts; if (groundsize > 0) { firsts.push_back(0); } for (int i = 0; i < first.size(); i++) { firsts.push_back((first[i] >= 0) ? first[i]+groundsize : -1); } ch = '.'; int start = 0, cur_it; do { 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() + groundsize) { 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; int iHeaderOffset = (groundsize > 0) ? 0 : 1; 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 = iHeaderOffset; i < iCategorieNum; i++) { if (cur_it == firsts[i-iHeaderOffset]) { mvwprintz(w_inv, cur_line, 0, c_magenta, CATEGORIES[i].c_str()); cur_line++; } } if (cur_it < u.inv.size() + groundsize) { char icon = '-'; if (compare_list[cur_it] == 1) icon = '+'; if (cur_it < groundsize) { mvwputch (w_inv, cur_line, 0, c_white, '1'+((cur_it<9) ? cur_it: -1)); nc_color col = (compare_list[cur_it] == 0 ? c_ltgray : c_white); mvwprintz(w_inv, cur_line, 1, col, " %c %s", icon, grounditems[cur_it].tname(this).c_str()); } else { item& it = stacks[cur_it-groundsize]->front(); mvwputch (w_inv, cur_line, 0, c_white, it.invlet); nc_color col = (compare_list[cur_it] == 0 ? c_ltgray : c_white); mvwprintz(w_inv, cur_line, 1, col, " %c %s", icon, it.tname(this).c_str()); if (stacks[cur_it-groundsize]->size() > 1) wprintz(w_inv, col, " [%d]", stacks[cur_it-groundsize]->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() + groundsize) mvwprintw(w_inv, maxitems + 4, 12, "> More items"); wrefresh(w_inv); ch = getch(); if (u.has_item(ch)) { item& it = u.inv.item_by_letter(ch); if (it.is_null()) { // Not from inventory bool 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; bFirst = false; print_inv_statics(this, w_inv, "Compare:", 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()){ //Do Bionic stuff here?! } else { if (!bFirst) { weapon_and_armor.push_back(ch); print_inv_statics(this, w_inv, "Compare:", weapon_and_armor); bFirst = true; cLastCh = ch; } else { bShowCompare = true; } } } } 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 (compare_list[index+groundsize] == 1) { compare_list[index+groundsize] = 0; bFirst = false; } else { if (!bFirst) { compare_list[index+groundsize] = 1; bFirst = true; cLastCh = ch; } else { bShowCompare = true; } } } } else if ((ch >= '1' && ch <= '9' && ch-'1' < groundsize) || (ch == '0' && groundsize == 10)) { //Ground Items int iZero = 0; if (ch == '0') { iZero = 10; } if (compare_list[ch-'1'+iZero] == 1) { compare_list[ch-'1'+iZero] = 0; bFirst = false; } else { if (!bFirst) { compare_list[ch-'1'+iZero] = 1; bFirst = true; cLastCh = ch; } else { bShowCompare = true; } } } if (bShowCompare) { std::vector<iteminfo> vItemLastCh, vItemCh; std::string sItemLastCh, sItemCh; if (cLastCh >= '0' && cLastCh <= '9') { int iZero = 0; if (cLastCh == '0') { iZero = 10; } grounditems[cLastCh-'1'+iZero].info(true, &vItemLastCh); sItemLastCh = grounditems[cLastCh-'1'+iZero].tname(this); } else { u.i_at(cLastCh).info(true, &vItemLastCh); sItemLastCh = u.i_at(cLastCh).tname(this); } if (ch >= '0' && ch <= '9') { int iZero = 0; if (ch == '0') { iZero = 10; } grounditems[ch-'1'+iZero].info(true, &vItemCh); sItemCh = grounditems[ch-'1'+iZero].tname(this); } else { u.i_at(ch).info(true, &vItemCh); sItemCh = u.i_at(ch).tname(this); } compare_split_screen_popup(0, (TERMX-VIEW_OFFSET_X*2)/2, TERMY-VIEW_OFFSET_Y*2, sItemLastCh, vItemLastCh, vItemCh); compare_split_screen_popup((TERMX-VIEW_OFFSET_X*2)/2, (TERMX-VIEW_OFFSET_X*2)/2, TERMY-VIEW_OFFSET_Y*2, sItemCh, vItemCh, vItemLastCh); wclear(w_inv); print_inv_statics(this, w_inv, "Compare:", weapon_and_armor); bShowCompare = false; } } while (ch != '\n' && ch != KEY_ESCAPE && ch != ' '); werase(w_inv); delwin(w_inv); erase(); refresh_all(); }
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; }
char game::inv_type(std::string title, item_cat inv_item_type) { // this function lists inventory objects by type // refer to enum item_cat in itype.h for list of categories 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. int ch = (int)'.'; int start = 0, cur_it; u.inv.sort(); u.inv.restack(&u); std::vector<char> null_vector; print_inv_statics(this, w_inv, title, null_vector); // Gun, ammo, weapon, armor, food, tool, book, other // Create the reduced inventory inventory reduced_inv = u.inv.filter_by_category(inv_item_type, u); invslice slice = reduced_inv.slice(0, reduced_inv.size()); std::vector<int> firsts = find_firsts(slice); do { if (( ch == '<' || ch == KEY_PPAGE ) && start > 0) { // Clear lines and shift 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 < reduced_inv.size()) { // Clear lines and shift 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, " "); 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 < slice.size()) { item& it = slice[cur_it]->front(); mvwputch (w_inv, cur_line, 0, c_white, it.invlet); mvwprintz(w_inv, cur_line, 1, it.color_in_inventory(&u), " %s", it.tname(this).c_str()); if (slice[cur_it]->size() > 1) wprintw(w_inv, " [%d]", slice[cur_it]->size()); if (it.charges > 0) wprintw(w_inv, " (%d)", it.charges); else if (it.contents.size() == 1 && it.contents[0].charges > 0) wprintw(w_inv, " (%d)", it.contents[0].charges); cur_line++; } // cur_line++; } if (start > 0) mvwprintw(w_inv, maxitems + 4, 0, "< Go Back"); if (cur_it < reduced_inv.size()) mvwprintw(w_inv, maxitems + 4, 12, "> More items"); wrefresh(w_inv); ch = getch(); } while (ch == '<' || ch == '>' || ch == KEY_NPAGE || ch == KEY_PPAGE ); werase(w_inv); delwin(w_inv); erase(); refresh_all(); return (char)ch; }
void game::construction_menu() { int iMaxY = TERMY; if (constructions.size()+2 < iMaxY) iMaxY = constructions.size()+2; if (iMaxY < 25) iMaxY = 25; WINDOW *w_con = newwin(iMaxY, 80, (TERMY > iMaxY) ? (TERMY-iMaxY)/2 : 0, (TERMX > 80) ? (TERMX-80)/2 : 0); wborder(w_con, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); mvwprintz(w_con, 0, 8, c_ltred, " Construction "); mvwputch(w_con, 0, 30, c_ltgray, LINE_OXXX); mvwputch(w_con, iMaxY-1, 30, c_ltgray, LINE_XXOX); for (int i = 1; i < iMaxY-1; i++) mvwputch(w_con, i, 30, c_ltgray, LINE_XOXO); mvwprintz(w_con, 1, 31, c_white, "Difficulty:"); wrefresh(w_con); bool update_info = true; int select = 0; int chosen = 0; long ch; bool exit = false; inventory total_inv = crafting_inventory(); do { // Erase existing list of constructions for (int i = 1; i < iMaxY-1; i++) { for (int j = 1; j < 30; j++) mvwputch(w_con, i, j, c_black, ' '); } // Determine where in the master list to start printing //int offset = select - 11; int offset = 0; if (select >= iMaxY-2) offset = select - iMaxY + 3; // Print the constructions between offset and max (or how many will fit) for (int i = 0; i < iMaxY-2 && (i + offset) < constructions.size(); i++) { int current = i + offset; nc_color col = (player_can_build(u, total_inv, constructions[current]) ? c_white : c_dkgray); // Map menu items to hotkey letters, skipping j, k, l, and q. unsigned char hotkey = 97 + current; if (hotkey > 122) hotkey = hotkey - 58; if (current == select) col = hilite(col); mvwprintz(w_con, 1 + i, 1, col, "%c %s", hotkey, constructions[current]->name.c_str()); } if (update_info) { update_info = false; constructable* current_con = constructions[select]; // Print difficulty int pskill = u.skillLevel("carpentry"); int diff = current_con->difficulty > 0 ? current_con->difficulty : 0; mvwprintz(w_con, 1, 43, (pskill >= diff ? c_white : c_red), "%d ", diff); // Clear out lines for tools & materials for (int i = 2; i < iMaxY-1; i++) { for (int j = 31; j < 79; j++) mvwputch(w_con, i, j, c_black, ' '); } // Print stages and their requirements int posx = 33, posy = 2; for (int n = 0; n < current_con->stages.size(); n++) { nc_color color_stage = (player_can_build(u, total_inv, current_con, n, false, true) ? c_white : c_dkgray); mvwprintz(w_con, posy, 31, color_stage, "Stage %d: %s", n + 1, current_con->stages[n].terrain == t_null? "" : terlist[current_con->stages[n].terrain].name.c_str()); posy++; // Print tools construction_stage stage = current_con->stages[n]; bool has_tool[10] = {stage.tools[0].empty(), stage.tools[1].empty(), stage.tools[2].empty(), stage.tools[3].empty(), stage.tools[4].empty(), stage.tools[5].empty(), stage.tools[6].empty(), stage.tools[7].empty(), stage.tools[8].empty(), stage.tools[9].empty()}; posy++; posx = 33; for (int i = 0; i < 9 && !has_tool[i]; i++) { mvwprintz(w_con, posy, posx-2, c_white, ">"); for (int j = 0; j < stage.tools[i].size(); j++) { itype_id tool = stage.tools[i][j].type; nc_color col = c_red; if (total_inv.has_amount(tool, 1)) { has_tool[i] = true; col = c_green; } int length = item_controller->find_template(tool)->name.length(); if (posx + length > 79) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, col, item_controller->find_template(tool)->name.c_str()); posx += length + 1; // + 1 for an empty space if (j < stage.tools[i].size() - 1) { // "OR" if there's more if (posx > 77) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, c_white, "OR"); posx += 3; } } posy += 2; posx = 33; } // Print components posx = 33; bool has_component[10] = {stage.components[0].empty(), stage.components[1].empty(), stage.components[2].empty(), stage.components[3].empty(), stage.components[4].empty(), stage.components[5].empty(), stage.components[6].empty(), stage.components[7].empty(), stage.components[8].empty(), stage.components[9].empty()}; for (int i = 0; i < 10; i++) { if (has_component[i]) continue; mvwprintz(w_con, posy, posx-2, c_white, ">"); for (int j = 0; j < stage.components[i].size() && i < 10; j++) { nc_color col = c_red; component comp = stage.components[i][j]; if (( item_controller->find_template(comp.type)->is_ammo() && total_inv.has_charges(comp.type, comp.count)) || (!item_controller->find_template(comp.type)->is_ammo() && total_inv.has_amount(comp.type, comp.count))) { has_component[i] = true; col = c_green; } int length = item_controller->find_template(comp.type)->name.length(); if (posx + length > 79) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, col, "%s x%d", item_controller->find_template(comp.type)->name.c_str(), comp.count); posx += length + 3; // + 2 for " x", + 1 for an empty space // Add more space for the length of the count if (comp.count < 10) posx++; else if (comp.count < 100) posx += 2; else posx += 3; if (j < stage.components[i].size() - 1) { // "OR" if there's more if (posx > 77) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, c_white, "OR"); posx += 3; } } posx = 33; posy += 2; } } wrefresh(w_con); } // Finished updating ch = getch(); switch (ch) { case KEY_DOWN: update_info = true; if (select < constructions.size() - 1) select++; else select = 0; break; case KEY_UP: update_info = true; if (select > 0) select--; else select = constructions.size() - 1; break; case ' ': case KEY_ESCAPE: case 'q': case 'Q': exit = true; break; case '\n': default: if (ch > 64 && ch < 91) //A-Z chosen = ch - 65 + 26; else if (ch > 96 && ch < 123) //a-z chosen = ch - 97; else if (ch == '\n') chosen = select; if (chosen < constructions.size()) { if (player_can_build(u, total_inv, constructions[chosen])) { place_construction(constructions[chosen]); exit = true; } else { popup("You can't build that!"); select = chosen; for (int i = 1; i < iMaxY-1; i++) mvwputch(w_con, i, 30, c_ltgray, LINE_XOXO); update_info = true; } } break; } } while (!exit); for (int i = iMaxY-25; i < iMaxY+1; i++) { for (int j = TERRAIN_WINDOW_WIDTH; j < 81; j++) mvwputch(w_con, i, j, c_black, ' '); } wrefresh(w_con); refresh_all(); }
int worldfactory::show_worldgen_tab_modselection(WINDOW *win, WORLDPTR world) { // Use active_mod_order of the world, // saves us from writing '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 dependencies) get updated tmp_mod_order.swap(active_mod_order); for( auto &elem : tmp_mod_order ) { mman_ui->try_add( elem, active_mod_order ); } } input_context ctxt("MODMANAGER_DIALOG"); ctxt.register_updown(); ctxt.register_action("LEFT", _("Switch to other list")); ctxt.register_action("RIGHT", _("Switch to other list")); ctxt.register_action("HELP_KEYBINDINGS"); ctxt.register_action("QUIT"); ctxt.register_action("NEXT_TAB"); ctxt.register_action("PREV_TAB"); ctxt.register_action("CONFIRM", _("Activate / deactive mod")); ctxt.register_action("ADD_MOD"); ctxt.register_action("REMOVE_MOD"); ctxt.register_action("SAVE_DEFAULT_MODS"); 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, &ctxt); 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; 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) { draw_mod_list( w_list, startsel[0], cursel[0], mman_ui->usable_mods, active_header == 0, _("--NO AVAILABLE MODS--") ); } if (redraw_active) { draw_mod_list( w_active, startsel[1], cursel[1], active_mod_order, active_header == 1, _("--NO ACTIVE MODS--") ); } 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() && (int)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()) { #ifndef LUA if (mman->mod_map[mman_ui->usable_mods[cursel[0]]]->need_lua) { popup(_("Can't add mod. This mod requires Lua support.")); redraw_active = true; redraw_shift = true; draw_modselection_borders(win, &ctxt); continue; } #endif // 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, &ctxt); redraw_headers = true; } } else if (action == "HELP_KEYBINDINGS") { // Redraw all the things! redraw_headers = true; redraw_shift = true; redraw_description = true; redraw_list = true; redraw_active = true; draw_worldgen_tabs( win, 0 ); draw_modselection_borders( win, &ctxt ); } else if (action == "QUIT") { tab_output = -999; } // RESOLVE INPUTS if (last_active_header != (int)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] >= (int)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; }
bool player::install_bionics(game *g, it_bionic* type) { if (type == NULL) { debugmsg("Tried to install NULL bionic"); return false; } std::string bio_name = type->name.substr(5); // Strip off "CBM: " WINDOW* w = newwin(25, 80, 0, 0); int pl_skill = int_cur + skillLevel("electronics").level() * 4 + skillLevel("firstaid").level() * 3 + skillLevel("mechanics").level() * 2; int skint = int(pl_skill / 4); int skdec = int((pl_skill * 10) / 4) % 10; // Header text mvwprintz(w, 0, 0, c_white, "Installing bionics:"); mvwprintz(w, 0, 20, type->color, bio_name.c_str()); // Dividing bars for (int i = 0; i < 80; i++) { mvwputch(w, 1, i, c_ltgray, LINE_OXOX); mvwputch(w, 21, i, c_ltgray, LINE_OXOX); } // Init the list of bionics for (unsigned int i = 1; i < type->options.size(); i++) { bionic_id id = type->options[i]; mvwprintz(w, i + 2, 0, (has_bionic(id) ? c_ltred : c_ltblue), bionics[id].name.c_str()); } // Helper text mvwprintz(w, 2, 40, c_white, "Difficulty of this module: %d", type->difficulty); mvwprintz(w, 3, 40, c_white, "Your installation skill: %d.%d", skint, skdec); mvwprintz(w, 4, 40, c_white, "Installation requires high intelligence,"); mvwprintz(w, 5, 40, c_white, "and skill in electronics, first aid, and"); mvwprintz(w, 6, 40, c_white, "mechanics (in that order of importance)."); int chance_of_success = int((100 * pl_skill) / (pl_skill + 4 * type->difficulty)); mvwprintz(w, 8, 40, c_white, "Chance of success:"); nc_color col_suc; if (chance_of_success >= 95) col_suc = c_green; else if (chance_of_success >= 80) col_suc = c_ltgreen; else if (chance_of_success >= 60) col_suc = c_yellow; else if (chance_of_success >= 35) col_suc = c_ltred; else col_suc = c_red; mvwprintz(w, 8, 59, col_suc, "%d%%%%", chance_of_success); mvwprintz(w, 10, 40, c_white, "Failure may result in crippling damage,"); mvwprintz(w, 11, 40, c_white, "loss of existing bionics, genetic damage"); mvwprintz(w, 12, 40, c_white, "or faulty installation."); wrefresh(w); if (type->id == itm_bionics_battery) { // No selection list; just confirm mvwprintz(w, 2, 0, h_ltblue, "Battery Level +%d", BATTERY_AMOUNT); mvwprintz(w, 22, 0, c_ltblue, "\ Installing this bionic will increase your total battery capacity by %d.\n\ Batteries are necessary for most bionics to function. They also require a\n\ charge mechanism, which must be installed from another CBM.", BATTERY_AMOUNT); char ch; wrefresh(w); do ch = getch(); while (ch != 'q' && ch != '\n' && ch != KEY_ESCAPE); if (ch == '\n') { practice("electronics", (100 - chance_of_success) * 1.5); practice("firstaid", (100 - chance_of_success) * 1.0); practice("mechanics", (100 - chance_of_success) * 0.5); int success = chance_of_success - rng(1, 100); if (success > 0) { g->add_msg("Successfully installed batteries."); max_power_level += BATTERY_AMOUNT; } else bionics_install_failure(g, this, success); werase(w); delwin(w); g->refresh_all(); return true; } werase(w); delwin(w); g->refresh_all(); return false; }
void draw_tabs(WINDOW *w, int active_tab, ...) { int win_width; win_width = getmaxx(w); std::vector<std::string> labels; va_list ap; va_start(ap, active_tab); char *tmp; while (tmp = (char *)va_arg(ap, char*)) labels.push_back((std::string)(tmp)); va_end(ap); // Draw the line under the tabs for (int x = 0; x < win_width; x++) mvwputch(w, 2, x, c_white, LINE_OXOX); int total_width = 0; for (int i = 0; i < labels.size(); i++) total_width += labels[i].length() + 6; // "< |four| >" if (total_width > win_width) { //debugmsg("draw_tabs not given enough space! %s", labels[0]); return; } // Extra "buffer" space per each side of each tab double buffer_extra = (win_width - total_width) / (labels.size() * 2); int buffer = int(buffer_extra); // Set buffer_extra to (0, 1); the "extra" whitespace that builds up buffer_extra = buffer_extra - buffer; int xpos = 0; double savings = 0; for (int i = 0; i < labels.size(); i++) { int length = labels[i].length(); xpos += buffer + 2; savings += buffer_extra; if (savings > 1) { savings--; xpos++; } mvwputch(w, 0, xpos, c_white, LINE_OXXO); mvwputch(w, 1, xpos, c_white, LINE_XOXO); mvwputch(w, 0, xpos + length + 1, c_white, LINE_OOXX); mvwputch(w, 1, xpos + length + 1, c_white, LINE_XOXO); if (i == active_tab) { mvwputch(w, 1, xpos - 2, h_white, '<'); mvwputch(w, 1, xpos + length + 3, h_white, '>'); mvwputch(w, 2, xpos, c_white, LINE_XOOX); mvwputch(w, 2, xpos + length + 1, c_white, LINE_XXOO); mvwprintz(w, 1, xpos + 1, h_white, labels[i].c_str()); for (int x = xpos + 1; x <= xpos + length; x++) { mvwputch(w, 0, x, c_white, LINE_OXOX); mvwputch(w, 2, x, c_black, 'x'); } } else { mvwputch(w, 2, xpos, c_white, LINE_XXOX); mvwputch(w, 2, xpos + length + 1, c_white, LINE_XXOX); mvwprintz(w, 1, xpos + 1, c_white, labels[i].c_str()); for (int x = xpos + 1; x <= xpos + length; x++) mvwputch(w, 0, x, c_white, LINE_OXOX); } xpos += length + 1 + buffer; } }
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; catacurses::window w_head = catacurses::newwin( headHeight, width, 0, wStart ); catacurses::window w_subhead = catacurses::newwin( subHeadHeight, width, 3, wStart ); catacurses::window w_data = catacurses::newwin( dataHeight, width, headHeight + subHeadHeight, wStart ); 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; } catacurses::window w_iteminfo = catacurses::newwin( item_info_y, item_info_x, item_info_height, item_info_width ); 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; int ypos = 0; int scroll_pos = 0; bool redraw = true; bool keepline = false; bool done = false; bool batch = false; bool show_hidden = false; int batch_line = 0; int display_mode = 0; const recipe *chosen = nullptr; std::vector<iteminfo> thisItem; std::vector<iteminfo> 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( "TOGGLE_FAVORITE" ); ctxt.register_action( "HELP_RECIPE" ); ctxt.register_action( "HELP_KEYBINDINGS" ); ctxt.register_action( "CYCLE_BATCH" ); ctxt.register_action( "RELATED_RECIPES" ); ctxt.register_action( "HIDE_SHOW_RECIPE" ); 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.empty() ) ? NORMAL : FILTERED; draw_recipe_tabs( w_head, tab.cur(), m ); draw_recipe_subtabs( w_subhead, tab.cur(), subtab.cur(), available_recipes, m ); show_hidden = false; 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 { std::vector<const recipe *> picking; if( !filterstring.empty() ) { auto qry = trim( filterstring ); if( qry.size() > 2 && qry[1] == ':' ) { switch( qry[0] ) { case 't': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::tool ); break; case 'c': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::component ); break; case 's': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::skill ); break; case 'p': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::primary_skill ); break; case 'Q': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::quality ); break; case 'q': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::quality_result ); break; case 'd': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::description_result ); break; case 'm': { auto &learned = g->u.get_learned_recipes(); if( query_is_yes( qry ) ) { std::set_intersection( available_recipes.begin(), available_recipes.end(), learned.begin(), learned.end(), std::back_inserter( picking ) ); } else { std::set_difference( available_recipes.begin(), available_recipes.end(), learned.begin(), learned.end(), std::back_inserter( picking ) ); } break; } case 'h': { std::copy( available_recipes.begin(), available_recipes.end(), std::back_inserter( picking ) ); if( query_is_yes( qry ) ) { show_hidden = true; } break; } default: current.clear(); } } else { picking = available_recipes.search( qry ); } } else if( subtab.cur() == "CSC_*_FAVORITE" ) { picking = available_recipes.favorite(); } else if( subtab.cur() == "CSC_*_RECENT" ) { picking = available_recipes.recent(); } else { picking = available_recipes.in_category( tab.cur(), subtab.cur() != "CSC_ALL" ? subtab.cur() : "" ); } current.clear(); for( auto i : picking ) { if( ( uistate.hidden_recipes.find( i->ident() ) != uistate.hidden_recipes.end() ) == show_hidden ) { current.push_back( i ); } } if( !show_hidden ) { draw_hidden_amount( w_head, 0, picking.size() - current.size() ); } 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 ) ); } } if( subtab.cur() != "CSC_*_RECENT" ) { 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, static_cast<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.empty() ) { wprintz( w_data, c_white, _( "[E]: Describe, [F]ind, [R]eset, [m]ode, [s]how/hide, Re[L]ated, [*]Favorite, %s [?] keybindings" ), ( batch ) ? _( "cancel [b]atch" ) : _( "[b]atch" ) ); } else { wprintz( w_data, c_white, _( "[E]: Describe, [F]ind, [m]ode, [s]how/hide, Re[L]ated, [*]Favorite, %s [?] keybindings" ), ( batch ) ? _( "cancel [b]atch" ) : _( "[b]atch" ) ); } } else { if( !filterstring.empty() ) { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "[E]: Describe, [F]ind, [R]eset, [m]ode, [s]how/hide, Re[L]ated, [*]Favorite, [b]atch [?] keybindings" ) ); } else { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "[E]: Describe, [F]ind, [m]ode, [s]how/hide, Re[L]ated, [*]Favorite, [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 = current[i]->result_name(); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, i - recmin, 2, c_dark_gray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, i - recmin, 2, ( available[i] ? h_white : h_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, i - recmin, 2, ( available[i] ? c_white : c_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } else if( line >= recmax - dataHalfLines ) { for( int i = recmax - dataLines; i < recmax; ++i ) { std::string tmp_name = current[i]->result_name(); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, dataLines + i - recmax, 2, c_light_gray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, dataLines + i - recmax, 2, ( available[i] ? h_white : h_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, dataLines + i - recmax, 2, ( available[i] ? c_white : c_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } else { for( int i = line - dataHalfLines; i < line - dataHalfLines + dataLines; ++i ) { std::string tmp_name = current[i]->result_name(); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, dataHalfLines + i - line, 2, c_light_gray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, dataHalfLines + i - line, 2, ( available[i] ? h_white : h_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, dataHalfLines + i - line, 2, ( available[i] ? c_white : c_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } } else { for( size_t i = 0; i < current.size() && i < static_cast<size_t>( dataHeight ) + 1; ++i ) { std::string tmp_name = current[i]->result_name(); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), static_cast<int>( i ) + 1, tmp_name.c_str() ); } if( static_cast<int>( i ) == line ) { mvwprintz( w_data, i, 2, ( available[i] ? h_white : h_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, i, 2, ( available[i] ? c_white : c_dark_gray ), 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_light_gray; const auto &req = current[ line ]->requirements(); draw_can_craft_indicator( w_head, 0, *current[line] ); wrefresh( w_head ); ypos = 0; auto qry = trim( filterstring ); std::string qry_comps; if( qry.compare( 0, 2, "c:" ) == 0 ) { qry_comps = qry.substr( 2 ); } 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, qry_comps ); 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" ) ); auto books_with_recipe = g->u.get_books_for_recipe( crafting_inv, current[line] ); std::string enumerated_books = enumerate_as_string( books_with_recipe.begin(), books_with_recipe.end(), []( itype_id type_id ) { return item::find_type( type_id )->nname( 1 ); } ); const std::string text = string_format( _( "Written in: %s" ), enumerated_books.c_str() ); std::vector<std::string> folded_lines = foldstring( text, pane ); component_print_buffer.insert( component_print_buffer.end(), folded_lines.begin(), folded_lines.end() ); } //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; const int xpos = 30; if( display_mode == 0 ) { const int width = getmaxx( w_data ) - xpos - item_info_x; print_colored_text( w_data, ypos++, xpos, col, col, string_format( _( "Primary skill used: <color_cyan>%s</color>" ), ( !current[line]->skill_used ? _( "N/A" ) : current[line]->skill_used.obj().name() ) ) ); auto player_skill = g->u.get_skill_level( current[line]->skill_used ); std::string difficulty_color = current[ line ]->difficulty > player_skill ? "yellow" : "green"; print_colored_text( w_data, ypos++, xpos, col, col, string_format( _( "Difficulty: <color_%s>%d</color>" ), difficulty_color, current[ line ]->difficulty ) ); std::string skill_level_string = current[line]->skill_used ? string_format( _( "Your skill level: <color_%s>%d</color>" ), difficulty_color, player_skill ) : _( "Your skill level: <color_yellow>N/A</color>" ); print_colored_text( w_data, ypos++, xpos, col, col, skill_level_string ); ypos += fold_and_print( w_data, ypos, xpos, width, col, _( "Other skills used: %s" ), current[line]->required_skills_string( &g->u ) ); const int expected_turns = g->u.expected_time_to_craft( *current[line], count ) / to_moves<int>( 1_turns ); ypos += fold_and_print( w_data, ypos, xpos, pane, col, _( "Time to complete: <color_cyan>%s</color>" ), to_string( time_duration::from_turns( expected_turns ) ) ); print_colored_text( w_data, ypos++, xpos, col, col, string_format( _( "Dark craftable? <color_cyan>%s</color>" ), current[line]->has_flag( "BLIND_EASY" ) ? _( "Easy" ) : current[line]->has_flag( "BLIND_HARD" ) ? _( "Hard" ) : _( "Impossible" ) ) ); ypos += print_items( *current[line], w_data, ypos, xpos, 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++, xpos, stored_color, col, component_print_buffer[i] ); } if( ypos >= componentPrintHeight && component_print_buffer.size() > static_cast<size_t>( components_printed ) ) { mvwprintz( w_data, ypos++, xpos, 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, count ); 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" ) { std::string start = subtab.cur(); do { subtab.prev(); } while( subtab.cur() != start && available_recipes.empty_category( tab.cur(), subtab.cur() != "CSC_ALL" ? subtab.cur() : "" ) ); 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" ) { std::string start = subtab.cur(); do { subtab.next(); } while( subtab.cur() != start && available_recipes.empty_category( tab.cur(), subtab.cur() != "CSC_ALL" ? subtab.cur() : "" ) ); 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( !g->u.check_eligible_containers_for_crafting( *current[line], ( 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" ) { struct SearchPrefix { char key; std::string example; std::string description; }; std::vector<SearchPrefix> prefixes = { { 'q', _( "metal sawing" ), _( "<color_cyan>quality</color> of resulting item" ) }, //~ Example result description search term { 'd', _( "reach attack" ), _( "<color_cyan>full description</color> of resulting item (slow)" ) }, { 'c', _( "two by four" ), _( "<color_cyan>component</color> required to craft" ) }, { 'p', _( "tailoring" ), _( "<color_cyan>primary skill</color> used to craft" ) }, { 's', _( "cooking" ), _( "<color_cyan>any skill</color> used to craft" ) }, { 'Q', _( "fine bolt turning" ), _( "<color_cyan>quality</color> required to craft" ) }, { 't', _( "soldering iron" ), _( "<color_cyan>tool</color> required to craft" ) }, { 'h', _( "yes" ), _( "recipes which are <color_cyan>hidden</color> or not" ) }, { 'm', _( "no" ), _( "recipes which are <color_cyan>memorized</color> or not" ) }, }; int max_example_length = 0; for( const auto &prefix : prefixes ) { max_example_length = std::max( max_example_length, utf8_width( prefix.example ) ); } std::string spaces( max_example_length, ' ' ); std::string description = _( "The default is to search result names. Some single-character prefixes " "can be used with a colon (:) to search in other ways.\n" "\n" "<color_white>Examples:</color>\n" ); { std::string example_name = _( "shirt" ); auto padding = max_example_length - utf8_width( example_name ); description += string_format( _( " <color_white>%s</color>%.*s %s\n" ), example_name, padding, spaces, _( "<color_cyan>name</color> of resulting item" ) ); } for( const auto &prefix : prefixes ) { auto padding = max_example_length - utf8_width( prefix.example ); description += string_format( _( " <color_yellow>%c</color><color_white>:%s</color>%.*s %s\n" ), prefix.key, prefix.example, padding, spaces, prefix.description ); } string_input_popup() .title( _( "Search:" ) ) .width( 85 ) .description( description ) .desc_color( c_light_gray ) .edit( filterstring ); redraw = true; } else if( action == "QUIT" ) { chosen = nullptr; done = true; } else if( action == "RESET_FILTER" ) { filterstring.clear(); 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; } else if( action == "TOGGLE_FAVORITE" ) { keepline = true; redraw = true; if( current.empty() ) { popup( _( "Nothing selected!" ) ); continue; } if( uistate.favorite_recipes.find( current[line]->ident() ) != uistate.favorite_recipes.end() ) { uistate.favorite_recipes.erase( current[line]->ident() ); } else { uistate.favorite_recipes.insert( current[line]->ident() ); } } else if( action == "HIDE_SHOW_RECIPE" ) { if( current.empty() ) { popup( _( "Nothing selected!" ) ); redraw = true; continue; } if( show_hidden ) { uistate.hidden_recipes.erase( current[line]->ident() ); } else { uistate.hidden_recipes.insert( current[line]->ident() ); } redraw = true; } else if( action == "RELATED_RECIPES" ) { if( current.empty() ) { popup( _( "Nothing selected!" ) ); redraw = true; continue; } std::string recipe_name = peek_related_recipe( current[ line ], available_recipes ); if( recipe_name.empty() ) { keepline = true; } else { filterstring = recipe_name; } redraw = true; } if( line < 0 ) { line = current.size() - 1; } else if( line >= static_cast<int>( current.size() ) ) { line = 0; } } while( !done ); return chosen; }
void game::construction_menu() { WINDOW *w_con = newwin(25, 80, 0, 0); wborder(w_con, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); mvwprintz(w_con, 0, 1, c_red, _("Construction")); mvwputch(w_con, 0, 30, c_white, LINE_OXXX); mvwputch(w_con, 24, 30, c_white, LINE_XXOX); for (int i = 1; i < 24; i++) mvwputch(w_con, i, 30, c_white, LINE_XOXO); mvwprintz(w_con, 1, 31, c_white, _("Difficulty:")); wrefresh(w_con); bool update_info = true; int select = 0; char ch; inventory total_inv; total_inv.form_from_map(this, point(u.posx, u.posy), PICKUP_RANGE); total_inv.add_stack(u.inv_dump()); if (u.has_bionic(bio_tools)) { item tools(itypes[itm_toolset], turn); tools.charges = u.power_level; total_inv += tools; } do { // Determine where in the master list to start printing int offset = select - 11; if (offset > constructions.size() - 22) offset = constructions.size() - 22; if (offset < 0) offset = 0; // Print the constructions between offset and max (or how many will fit) for (int i = 0; i < 22 && i + offset < constructions.size(); i++) { int current = i + offset; nc_color col = (player_can_build(u, total_inv, constructions[current], 0) ? c_white : c_dkgray); if (current == select) col = hilite(col); mvwprintz(w_con, 1 + i, 1, col, constructions[current]->name.c_str()); } if (update_info) { update_info = false; constructable* current_con = constructions[select]; // Print difficulty int pskill = u.sklevel[sk_carpentry], diff = current_con->difficulty; mvwprintz(w_con, 1, 43, (pskill >= diff ? c_white : c_red), "%d ", diff); // Clear out lines for tools & materials for (int i = 2; i < 24; i++) { for (int j = 31; j < 79; j++) mvwputch(w_con, i, j, c_black, 'x'); } // Print stages and their requirements int posx = 33, posy = 2; for (int n = 0; n < current_con->stages.size(); n++) { nc_color color_stage = (player_can_build(u, total_inv, current_con, n) ? c_white : c_dkgray); mvwprintz(w_con, posy, 31, color_stage, _("Stage %d: %s"), n + 1, terlist[current_con->stages[n].terrain].name.c_str()); posy++; // Print tools construction_stage stage = current_con->stages[n]; bool has_tool[3] = {stage.tools[0].empty(), stage.tools[1].empty(), stage.tools[2].empty()}; for (int i = 0; i < 3 && !has_tool[i]; i++) { posy++; posx = 33; for (int j = 0; j < stage.tools[i].size(); j++) { itype_id tool = stage.tools[i][j]; nc_color col = c_red; if (total_inv.has_amount(tool, 1)) { has_tool[i] = true; col = c_green; } int length = itypes[tool]->name.length(); if (posx + length > 79) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, col, itypes[tool]->name.c_str()); posx += length + 1; // + 1 for an empty space if (j < stage.tools[i].size() - 1) { // "OR" if there's more if (posx > 77) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, c_white, _("OR")); posx += 3; } } } // Print components posy++; posx = 33; bool has_component[3] = {stage.components[0].empty(), stage.components[1].empty(), stage.components[2].empty()}; for (int i = 0; i < 3; i++) { posx = 33; while (has_component[i]) i++; for (int j = 0; j < stage.components[i].size() && i < 3; j++) { nc_color col = c_red; component comp = stage.components[i][j]; if (( itypes[comp.type]->is_ammo() && total_inv.has_charges(comp.type, comp.count)) || (!itypes[comp.type]->is_ammo() && total_inv.has_amount(comp.type, comp.count))) { has_component[i] = true; col = c_green; } int length = itypes[comp.type]->name.length(); if (posx + length > 79) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, col, "%s x%d", itypes[comp.type]->name.c_str(), comp.count); posx += length + 3; // + 2 for " x", + 1 for an empty space // Add more space for the length of the count if (comp.count < 10) posx++; else if (comp.count < 100) posx += 2; else posx += 3; if (j < stage.components[i].size() - 1) { // "OR" if there's more if (posx > 77) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, c_white, _("OR")); posx += 3; } } posy++; } } wrefresh(w_con); } // Finished updating ch = input(); switch (ch) { case 'j': update_info = true; if (select < constructions.size() - 1) select++; else select = 0; break; case 'k': update_info = true; if (select > 0) select--; else select = constructions.size() - 1; break; case '\n': case 'l': if (player_can_build(u, total_inv, constructions[select], 0)) { place_construction(constructions[select]); ch = 'q'; } else { popup(_("You can't build that!")); for (int i = 1; i < 24; i++) mvwputch(w_con, i, 30, c_white, LINE_XOXO); update_info = true; } break; } } while (ch != 'q' && ch != 'Q' && ch != KEY_ESCAPE); refresh_all(); }
void draw_caravan_borders(WINDOW *w, int current_window) { // First, do the borders for the category window nc_color col = c_ltgray; if (current_window == 0) col = c_yellow; mvwputch(w, 0, 0, col, LINE_OXXO); for (int i = 1; i <= 38; i++) { mvwputch(w, 0, i, col, LINE_OXOX); mvwputch(w, 11, i, col, LINE_OXOX); } for (int i = 1; i <= 10; i++) { mvwputch(w, i, 0, col, LINE_XOXO); mvwputch(w, i, 39, c_yellow, LINE_XOXO); // Shared border, always yellow } mvwputch(w, 11, 0, col, LINE_XXXO); // These are shared with the items window, and so are always "on" mvwputch(w, 0, 39, c_yellow, LINE_OXXX); mvwputch(w, 11, 39, c_yellow, LINE_XOXX); col = (current_window == 1 ? c_yellow : c_ltgray); // Next, draw the borders for the item description window--always "off" & gray for (int i = 12; i <= 23; i++) { mvwputch(w, i, 0, c_ltgray, LINE_XOXO); mvwputch(w, i, 39, col, LINE_XOXO); } for (int i = 1; i <= 38; i++) mvwputch(w, 24, i, c_ltgray, LINE_OXOX); mvwputch(w, 24, 0, c_ltgray, LINE_XXOO); mvwputch(w, 24, 39, c_ltgray, LINE_XXOX); // Finally, draw the item section borders for (int i = 40; i <= 78; i++) { mvwputch(w, 0, i, col, LINE_OXOX); mvwputch(w, 24, i, col, LINE_OXOX); } for (int i = 1; i <= 23; i++) mvwputch(w, i, 79, col, LINE_XOXO); mvwputch(w, 24, 39, col, LINE_XXOX); mvwputch(w, 0, 79, col, LINE_OOXX); mvwputch(w, 24, 79, col, LINE_XOOX); // Quick reminded about help. mvwprintz(w, 24, 2, c_red, "Press ? for help."); wrefresh(w); }