void place_construction( const std::string &desc ) { g->refresh_all(); const inventory &total_inv = g->u.crafting_inventory(); std::vector<construction *> cons = constructions_by_desc( desc ); std::map<tripoint, const construction *> valid; for( const tripoint &p : g->m.points_in_radius( g->u.pos(), 1 ) ) { for( const auto *con : cons ) { if( p != g->u.pos() && can_construct( *con, p ) && player_can_build( g->u, total_inv, *con ) ) { valid[ p ] = con; } } } for( auto &elem : valid ) { g->m.drawsq( g->w_terrain, g->u, elem.first, true, false, g->u.pos() + g->u.view_offset ); } wrefresh( g->w_terrain ); tripoint dirp; if( !choose_adjacent( _( "Construct where?" ), dirp ) ) { return; } if( valid.find( dirp ) == valid.end() ) { add_msg( m_info, _( "You cannot build there!" ) ); return; } const construction &con = *valid.find( dirp )->second; g->u.assign_activity( activity_id( "ACT_BUILD" ), con.adjusted_time(), con.id ); g->u.activity.placement = dirp; }
// x, y = choose_adjacent(query_string, x, y) static int game_choose_adjacent(lua_State *L) { const char* parameter1 = (const char*) lua_tostring(L, 1); int parameter2 = (int) lua_tonumber(L, 2); int parameter3 = (int) lua_tonumber(L, 3); bool success = (bool) choose_adjacent(parameter1, parameter2, parameter3); if(success) { // parameter2 and parameter3 were updated by the call lua_pushnumber(L, parameter2); lua_pushnumber(L, parameter3); return 2; // 2 return values } else { return 0; // 0 return values } }
void game::compare(int iCompareX, int iCompareY) { int examx, examy; if (iCompareX != -999 && iCompareY != -999) { examx = u.posx + iCompareX; examy = u.posy + iCompareY; } else if (!choose_adjacent(_("Compare where?"), examx, examy)) { return; } std::vector <item> &here = m.i_at(examx, examy); typedef std::vector< std::list<item> > pseudo_inventory; pseudo_inventory grounditems; indexed_invslice grounditems_slice; //Filter out items with the same name (keep only one of them) //Only the first 10 Items due to numbering 0-9 std::set<std::string> dups; for (size_t i = 0; i < here.size() && grounditems.size() < 10; i++) { if (dups.count(here[i].tname()) == 0) { grounditems.push_back(std::list<item>(1, here[i])); // invlet: '0' ... '9' grounditems.back().front().invlet = '0' + grounditems.size() - 1; dups.insert(here[i].tname()); } } for (size_t a = 0; a < grounditems.size(); a++) { // avoid INT_MIN, as it can be confused with "no item at all" grounditems_slice.push_back(indexed_invslice::value_type(&grounditems[a], INT_MIN + a + 1)); } static const item_category category_on_ground( "GROUND:", _("GROUND:"), -1000 ); u.inv.restack(&u); u.inv.sort(); const indexed_invslice stacks = u.inv.slice_filter(); inventory_selector inv_s(false, true, _("Compare:")); inv_s.make_item_list(grounditems_slice, &category_on_ground); inv_s.make_item_list(stacks); inv_s.prepare_paging(); inventory_selector::drop_map prev_droppings; while(true) { inv_s.display(); const std::string action = inv_s.ctxt.handle_input(); const long ch = inv_s.ctxt.get_raw_input().get_first_input(); const int item_pos = g->u.invlet_to_position(static_cast<char>(ch)); if (item_pos != INT_MIN) { inv_s.set_to_drop(item_pos, 0); } else if (ch >= '0' && ch <= '9' && (size_t) (ch - '0') < grounditems_slice.size()) { const int ip = ch - '0'; inv_s.set_drop_count(INT_MIN + 1 + ip, 0, grounditems_slice[ip].first->front()); } else if (inv_s.handle_movement(action)) { // continue with comparison below } else if (action == "QUIT") { break; } else if (action == "RIGHT") { inv_s.set_selected_to_drop(0); } if (inv_s.second_item != NULL) { std::vector<iteminfo> vItemLastCh, vItemCh; std::string sItemLastCh, sItemCh; inv_s.first_item->info(true, &vItemCh); sItemCh = inv_s.first_item->tname(); inv_s.second_item->info(true, &vItemLastCh); sItemLastCh = inv_s.second_item->tname(); draw_item_info(0, (TERMX - VIEW_OFFSET_X * 2) / 2, 0, TERMY - VIEW_OFFSET_Y * 2, sItemLastCh, vItemLastCh, vItemCh, -1, true); //without getch() draw_item_info((TERMX - VIEW_OFFSET_X * 2) / 2, (TERMX - VIEW_OFFSET_X * 2) / 2, 0, TERMY - VIEW_OFFSET_Y * 2, sItemCh, vItemCh, vItemLastCh); inv_s.dropping = prev_droppings; inv_s.second_item = NULL; } else { prev_droppings = inv_s.dropping; } } }
void game::place_construction(constructable *con) { refresh_all(); inventory total_inv = crafting_inventory(&u); std::vector<point> valid; for (int x = u.posx - 1; x <= u.posx + 1; x++) { for (int y = u.posy - 1; y <= u.posy + 1; y++) { if (x == u.posx && y == u.posy) y++; construct test; bool place_okay = (test.*(con->able))(this, point(x, y)); for (int i = 0; i < con->stages.size() && !place_okay; i++) { ter_id t = con->stages[i].terrain; furn_id f = con->stages[i].furniture; if ((t != t_null || f != f_null) && (m.ter(x, y) == t || t == t_null) && (m.furn(x, y) == f || f == f_null)) place_okay = true; } if (place_okay) { // Make sure we're not trying to continue a construction that we can't finish int starting_stage = 0, max_stage = -1; for (int i = 0; i < con->stages.size(); i++) { ter_id t = con->stages[i].terrain; furn_id f = con->stages[i].furniture; if ((t != t_null || f != f_null) && (m.ter(x, y) == t || t == t_null) && (m.furn(x, y) == f || f == f_null)) starting_stage = i + 1; } if (starting_stage == con->stages.size() && con->loopstages) starting_stage = 0; // Looping stages for(int i = starting_stage; i < con->stages.size(); i++) { if (player_can_build(u, total_inv, con, i, true, true)) max_stage = i; else break; } if (max_stage >= starting_stage) { valid.push_back(point(x, y)); m.drawsq(w_terrain, u, x, y, true, false); wrefresh(w_terrain); } } } } // snip snip if (con->name == _("Move Furniture") ) { grab(); return; } // int dirx, diry; if (!choose_adjacent(_("Contruct where?"), dirx, diry)) return; bool point_is_okay = false; for (int i = 0; i < valid.size() && !point_is_okay; i++) { if (valid[i].x == dirx && valid[i].y == diry) point_is_okay = true; } if (!point_is_okay) { add_msg(_("You cannot build there!")); return; } // Figure out what stage to start at, and what stage is the maximum int starting_stage = 0, max_stage = 0; for (int i = 0; i < con->stages.size(); i++) { ter_id t = con->stages[i].terrain; furn_id f = con->stages[i].furniture; if ((t != t_null || f != f_null) && (m.ter(dirx, diry) == t || t == t_null) && (m.furn(dirx, diry) == f || f == f_null)) starting_stage = i + 1; if (player_can_build(u, total_inv, con, i, true)) max_stage = i; } if (starting_stage == con->stages.size() && con->loopstages) starting_stage = 0; // Looping stages u.assign_activity(this, ACT_BUILD, con->stages[starting_stage].time * 1000, con->id); u.moves = 0; std::vector<int> stages; for (int i = starting_stage; i <= max_stage; i++) stages.push_back(i); u.activity.values = stages; u.activity.placement = point(dirx, diry); }
void player::activate_mutation( const trait_id &mut ) { const mutation_branch &mdata = mut.obj(); auto &tdata = my_mutations[mut]; int cost = mdata.cost; // You can take yourself halfway to Near Death levels of hunger/thirst. // Fatigue can go to Exhausted. if ((mdata.hunger && get_hunger() >= 700) || (mdata.thirst && get_thirst() >= 260) || (mdata.fatigue && get_fatigue() >= EXHAUSTED)) { // Insufficient Foo to *maintain* operation is handled in player::suffer add_msg_if_player(m_warning, _("You feel like using your %s would kill you!"), mdata.name.c_str()); return; } if (tdata.powered && tdata.charge > 0) { // Already-on units just lose a bit of charge tdata.charge--; } else { // Not-on units, or those with zero charge, have to pay the power cost if (mdata.cooldown > 0) { tdata.charge = mdata.cooldown - 1; } if (mdata.hunger){ mod_hunger(cost); } if (mdata.thirst){ mod_thirst(cost); } if (mdata.fatigue){ mod_fatigue(cost); } tdata.powered = true; // Handle stat changes from activation apply_mods(mut, true); recalc_sight_limits(); } if( mut == trait_WEB_WEAVER ) { g->m.add_field( pos(), fd_web, 1 ); add_msg_if_player(_("You start spinning web with your spinnerets!")); } else if (mut == "BURROW"){ if( is_underwater() ) { add_msg_if_player(m_info, _("You can't do that while underwater.")); tdata.powered = false; return; } tripoint dirp; if (!choose_adjacent(_("Burrow where?"), dirp)) { tdata.powered = false; return; } if( dirp == pos() ) { add_msg_if_player(_("You've got places to go and critters to beat.")); add_msg_if_player(_("Let the lesser folks eat their hearts out.")); tdata.powered = false; return; } time_duration time_to_do = 0_turns; if (g->m.is_bashable(dirp) && g->m.has_flag("SUPPORTS_ROOF", dirp) && g->m.ter(dirp) != t_tree) { // Being better-adapted to the task means that skillful Survivors can do it almost twice as fast. time_to_do = 30_minutes; } else if (g->m.move_cost(dirp) == 2 && g->get_levz() == 0 && g->m.ter(dirp) != t_dirt && g->m.ter(dirp) != t_grass) { time_to_do = 10_minutes; } else { add_msg_if_player(m_info, _("You can't burrow there.")); tdata.powered = false; return; } assign_activity( activity_id( "ACT_BURROW" ), to_moves<int>( time_to_do ), -1, 0 ); activity.placement = dirp; add_msg_if_player(_("You tear into the %s with your teeth and claws."), g->m.tername(dirp).c_str()); tdata.powered = false; return; // handled when the activity finishes } else if( mut == trait_SLIMESPAWNER ) { std::vector<tripoint> valid; for( const tripoint &dest : g->m.points_in_radius( pos(), 1 ) ) { if (g->is_empty(dest)) { valid.push_back( dest ); } } // Oops, no room to divide! if( valid.empty() ) { add_msg_if_player(m_bad, _("You focus, but are too hemmed in to birth a new slimespring!")); tdata.powered = false; return; } add_msg_if_player(m_good, _("You focus, and with a pleasant splitting feeling, birth a new slimespring!")); int numslime = 1; for (int i = 0; i < numslime && !valid.empty(); i++) { const tripoint target = random_entry_removed( valid ); if( monster * const slime = g->summon_mon( mtype_id( "mon_player_blob" ), target ) ) { slime->friendly = -1; } } if (one_in(3)) { //~ Usual enthusiastic slimespring small voices! :D add_msg_if_player(m_good, _("wow! you look just like me! we should look out for each other!")); } else if (one_in(2)) { //~ Usual enthusiastic slimespring small voices! :D add_msg_if_player(m_good, _("come on, big me, let's go!")); } else { //~ Usual enthusiastic slimespring small voices! :D add_msg_if_player(m_good, _("we're a team, we've got this!")); } tdata.powered = false; return; } else if( mut == trait_NAUSEA || mut == trait_VOMITOUS ) { vomit(); tdata.powered = false; return; } else if( mut == trait_M_FERTILE ) { spores(); tdata.powered = false; return; } else if( mut == trait_M_BLOOM ) { blossoms(); tdata.powered = false; return; } else if( mut == trait_SELFAWARE ) { print_health(); tdata.powered = false; return; } else if( !mdata.spawn_item.empty() ) { item tmpitem( mdata.spawn_item ); i_add_or_drop( tmpitem ); add_msg_if_player( _( mdata.spawn_item_message.c_str() ) ); tdata.powered = false; return; } }
void game::compare(int iCompareX, int iCompareY) { int examx, examy; std::vector <item> grounditems; int ch = (int)'.'; if (iCompareX != -999 && iCompareY != -999) { examx = u.posx + iCompareX; examy = u.posy + iCompareY; } else if (!choose_adjacent(_("Compare where?"),examx,examy)) { return; } std::vector <item> here = m.i_at(examx, examy); //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().c_str()]) { grounditems.push_back(here[i]); dups[here[i].tname().c_str()] = true; } } //Only the first 10 Items due to numbering 0-9 const int groundsize = (grounditems.size() > 10 ? 10 : grounditems.size()); u.inv.restack(&u); u.inv.sort(); indexed_invslice stacks = u.inv.slice_filter(); 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 = 0; 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 CategoriesVector CATEGORIES; std::vector<int> first = find_firsts(stacks, CATEGORIES); 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 = 0; 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 < CATEGORIES.size(); i++) { if (cur_it == firsts[i-iHeaderOffset]) { mvwprintz(w_inv, cur_line, 0, c_magenta, CATEGORIES[i].name.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().c_str()); } else { item& it = stacks[cur_it-groundsize].first->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().c_str()); if (stacks[cur_it-groundsize].first->size() > 1) wprintz(w_inv, col, " x %d", stacks[cur_it-groundsize].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); } } 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((char)ch)) { item& it = u.inv.item_by_letter((char)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].first->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(); } else { u.i_at(cLastCh).info(true, &vItemLastCh); sItemLastCh = u.i_at(cLastCh).tname(); } 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(); } else { item& item = u.i_at((char)ch); item.info(true, &vItemCh); sItemCh = item.tname(); } compare_split_screen_popup(0, (TERMX-VIEW_OFFSET_X*2)/2, TERMY-VIEW_OFFSET_Y*2, sItemLastCh, vItemLastCh, vItemCh , -1, true);//without getch() 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(); }
void player::activate_mutation( const std::string &mut ) { const auto &mdata = mutation_branch::get( mut ); auto &tdata = my_mutations[mut]; int cost = mdata.cost; // You can take yourself halfway to Near Death levels of hunger/thirst. // Fatigue can go to Exhausted. if ((mdata.hunger && hunger >= 700) || (mdata.thirst && thirst >= 260) || (mdata.fatigue && fatigue >= 575)) { // Insufficient Foo to *maintain* operation is handled in player::suffer add_msg(m_warning, _("You feel like using your %s would kill you!"), mdata.name.c_str()); return; } if (tdata.powered && tdata.charge > 0) { // Already-on units just lose a bit of charge tdata.charge--; } else { // Not-on units, or those with zero charge, have to pay the power cost if (mdata.cooldown > 0) { tdata.charge = mdata.cooldown - 1; } if (mdata.hunger){ hunger += cost; } if (mdata.thirst){ thirst += cost; } if (mdata.fatigue){ fatigue += cost; } tdata.powered = true; // Handle stat changes from activation apply_mods(mut, true); recalc_sight_limits(); } if( mut == "WEB_WEAVER" ) { g->m.add_field(pos(), fd_web, 1, 0); add_msg(_("You start spinning web with your spinnerets!")); } else if (mut == "BURROW"){ if (g->u.is_underwater()) { add_msg_if_player(m_info, _("You can't do that while underwater.")); tdata.powered = false; return; } int dirx, diry; if (!choose_adjacent(_("Burrow where?"), dirx, diry)) { tdata.powered = false; return; } if (dirx == g->u.posx() && diry == g->u.posy()) { add_msg_if_player(_("You've got places to go and critters to beat.")); add_msg_if_player(_("Let the lesser folks eat their hearts out.")); tdata.powered = false; return; } int turns; if (g->m.is_bashable(dirx, diry) && g->m.has_flag("SUPPORTS_ROOF", dirx, diry) && g->m.ter(dirx, diry) != t_tree) { // Takes about 100 minutes (not quite two hours) base time. // Being better-adapted to the task means that skillful Survivors can do it almost twice as fast. turns = (100000 - 5000 * g->u.skillLevel("carpentry")); } else if (g->m.move_cost(dirx, diry) == 2 && g->get_levz() == 0 && g->m.ter(dirx, diry) != t_dirt && g->m.ter(dirx, diry) != t_grass) { turns = 18000; } else { add_msg_if_player(m_info, _("You can't burrow there.")); tdata.powered = false; return; } g->u.assign_activity(ACT_BURROW, turns, -1, 0); g->u.activity.placement = tripoint(dirx, diry,0); add_msg_if_player(_("You tear into the %s with your teeth and claws."), g->m.tername(dirx, diry).c_str()); tdata.powered = false; return; // handled when the activity finishes } else if (mut == "SLIMESPAWNER") { std::vector<tripoint> valid; for (int x = posx() - 1; x <= posx() + 1; x++) { for (int y = posy() - 1; y <= posy() + 1; y++) { tripoint dest(x, y, posz()); if (g->is_empty(dest)) { valid.push_back( dest ); } } } // Oops, no room to divide! if (valid.size() == 0) { add_msg(m_bad, _("You focus, but are too hemmed in to birth a new slimespring!")); tdata.powered = false; return; } add_msg(m_good, _("You focus, and with a pleasant splitting feeling, birth a new slimespring!")); int numslime = 1; for (int i = 0; i < numslime && !valid.empty(); i++) { const tripoint target = random_entry_removed( valid ); if (g->summon_mon("mon_player_blob", target)) { monster *slime = g->monster_at( target ); slime->friendly = -1; } } //~ Usual enthusiastic slimespring small voices! :D if (one_in(3)) { add_msg(m_good, _("wow! you look just like me! we should look out for each other!")); } else if (one_in(2)) { add_msg(m_good, _("come on, big me, let's go!")); } else { add_msg(m_good, _("we're a team, we've got this!")); } tdata.powered = false; return; } else if (mut == "SHOUT1") { sounds::sound(pos(), 10 + 2 * str_cur, _("You shout loudly!")); tdata.powered = false; return; } else if (mut == "SHOUT2"){ sounds::sound(pos(), 15 + 3 * str_cur, _("You scream loudly!")); tdata.powered = false; return; } else if (mut == "SHOUT3"){ sounds::sound(pos(), 20 + 4 * str_cur, _("You let out a piercing howl!")); tdata.powered = false; return; } else if ((mut == "NAUSEA") || (mut == "VOMITOUS") ){ vomit(); tdata.powered = false; return; } else if (mut == "M_FERTILE"){ spores(); tdata.powered = false; return; } else if (mut == "M_BLOOM"){ blossoms(); tdata.powered = false; return; } else if (mut == "VINES3"){ item newit("vine_30", calendar::turn, false); if (!can_pickVolume(newit.volume())) { //Accounts for result_mult add_msg(_("You detach a vine but don't have room to carry it, so you drop it.")); g->m.add_item_or_charges(posx(), posy(), newit); } else if (!can_pickWeight(newit.weight(), !OPTIONS["DANGEROUS_PICKUPS"])) { add_msg(_("Your freshly-detached vine is too heavy to carry, so you drop it.")); g->m.add_item_or_charges(posx(), posy(), newit); } else { inv.assign_empty_invlet(newit); newit = i_add(newit); add_msg(m_info, "%c - %s", newit.invlet == 0 ? ' ' : newit.invlet, newit.tname().c_str()); } tdata.powered = false; return; } }
// Why put this in a Big Switch? Why not let bionics have pointers to // functions, much like monsters and items? // // Well, because like diseases, which are also in a Big Switch, bionics don't // share functions.... void player::activate_bionic(int b) { bionic bio = my_bionics[b]; int power_cost = bionics[bio.id]->power_cost; if ((weapon.type->id == "bio_claws_weapon" && bio.id == "bio_claws_weapon") || (weapon.type->id == "bio_blade_weapon" && bio.id == "bio_blade_weapon")) { power_cost = 0; } if (power_level < power_cost) { if (my_bionics[b].powered) { add_msg(m_neutral, _("Your %s powers down."), bionics[bio.id]->name.c_str()); my_bionics[b].powered = false; } else { add_msg(m_info, _("You cannot power your %s"), bionics[bio.id]->name.c_str()); } return; } if (my_bionics[b].powered && my_bionics[b].charge > 0) { // Already-on units just lose a bit of charge my_bionics[b].charge--; } else { // Not-on units, or those with zero charge, have to pay the power cost if (bionics[bio.id]->charge_time > 0) { my_bionics[b].powered = true; my_bionics[b].charge = bionics[bio.id]->charge_time - 1; } power_level -= power_cost; } std::vector<point> traj; std::vector<std::string> good; std::vector<std::string> bad; int dirx, diry; item tmp_item; if(bio.id == "bio_painkiller") { pkill += 6; pain -= 2; if (pkill > pain) { pkill = pain; } } else if (bio.id == "bio_nanobots") { rem_disease("bleed"); healall(4); } else if (bio.id == "bio_night") { if (calendar::turn % 5) { add_msg(m_neutral, _("Artificial night generator active!")); } } else if (bio.id == "bio_resonator") { g->sound(posx, posy, 30, _("VRRRRMP!")); for (int i = posx - 1; i <= posx + 1; i++) { for (int j = posy - 1; j <= posy + 1; j++) { g->m.bash( i, j, 40 ); g->m.bash( i, j, 40 ); // Multibash effect, so that doors &c will fall g->m.bash( i, j, 40 ); if (g->m.is_destructable(i, j) && rng(1, 10) >= 4) { g->m.ter_set(i, j, t_rubble); } } } } else if (bio.id == "bio_time_freeze") { moves += power_level; power_level = 0; add_msg(m_good, _("Your speed suddenly increases!")); if (one_in(3)) { add_msg(m_bad, _("Your muscles tear with the strain.")); apply_damage( nullptr, bp_arm_l, rng( 5, 10 ) ); apply_damage( nullptr, bp_arm_r, rng( 5, 10 ) ); apply_damage( nullptr, bp_leg_l, rng( 7, 12 ) ); apply_damage( nullptr, bp_leg_r, rng( 7, 12 ) ); apply_damage( nullptr, bp_torso, rng( 5, 15 ) ); } if (one_in(5)) { add_disease("teleglow", rng(50, 400)); } } else if (bio.id == "bio_teleport") { g->teleport(); add_disease("teleglow", 300); } // TODO: More stuff here (and bio_blood_filter) else if(bio.id == "bio_blood_anal") { WINDOW *w = newwin(20, 40, 3 + ((TERMY > 25) ? (TERMY - 25) / 2 : 0), 10 + ((TERMX > 80) ? (TERMX - 80) / 2 : 0)); draw_border(w); if (has_disease("fungus")) { bad.push_back(_("Fungal Parasite")); } if (has_disease("dermatik")) { bad.push_back(_("Insect Parasite")); } if (has_effect("stung")) { bad.push_back(_("Stung")); } if (has_effect("poison")) { bad.push_back(_("Poison")); } if (radiation > 0) { bad.push_back(_("Irradiated")); } if (has_disease("pkill1")) { good.push_back(_("Minor Painkiller")); } if (has_disease("pkill2")) { good.push_back(_("Moderate Painkiller")); } if (has_disease("pkill3")) { good.push_back(_("Heavy Painkiller")); } if (has_disease("pkill_l")) { good.push_back(_("Slow-Release Painkiller")); } if (has_disease("drunk")) { good.push_back(_("Alcohol")); } if (has_disease("cig")) { good.push_back(_("Nicotine")); } if (has_disease("meth")) { good.push_back(_("Methamphetamines")); } if (has_disease("high")) { good.push_back(_("Intoxicant: Other")); } if (has_disease("weed_high")) { good.push_back(_("THC Intoxication")); } if (has_disease("hallu") || has_disease("visuals")) { bad.push_back(_("Magic Mushroom")); } if (has_disease("iodine")) { good.push_back(_("Iodine")); } if (has_disease("datura")) { good.push_back(_("Anticholinergic Tropane Alkaloids")); } if (has_disease("took_xanax")) { good.push_back(_("Xanax")); } if (has_disease("took_prozac")) { good.push_back(_("Prozac")); } if (has_disease("took_flumed")) { good.push_back(_("Antihistamines")); } if (has_disease("adrenaline")) { good.push_back(_("Adrenaline Spike")); } if (has_disease("tapeworm")) { // This little guy is immune to the blood filter though, as he lives in your bowels. good.push_back(_("Intestinal Parasite")); } if (has_disease("bloodworms")) { good.push_back(_("Hemolytic Parasites")); } if (has_disease("brainworm")) { // This little guy is immune to the blood filter too, as he lives in your brain. good.push_back(_("Intracranial Parasite")); } if (has_disease("paincysts")) { // These little guys are immune to the blood filter too, as they live in your muscles. good.push_back(_("Intramuscular Parasites")); } if (has_disease("tetanus")) { // Tetanus infection. good.push_back(_("Clostridium Tetani Infection")); } if (good.empty() && bad.empty()) { mvwprintz(w, 1, 1, c_white, _("No effects.")); } else { for (unsigned line = 1; line < 39 && line <= good.size() + bad.size(); line++) { if (line <= bad.size()) { mvwprintz(w, line, 1, c_red, "%s", bad[line - 1].c_str()); } else { mvwprintz(w, line, 1, c_green, "%s", good[line - 1 - bad.size()].c_str()); } } } wrefresh(w); refresh(); getch(); delwin(w); } else if(bio.id == "bio_blood_filter") { add_msg(m_neutral, _("You activate your blood filtration system.")); rem_disease("fungus"); rem_disease("dermatik"); rem_disease("bloodworms"); rem_disease("tetanus"); remove_effect("poison"); remove_effect("stung"); rem_disease("pkill1"); rem_disease("pkill2"); rem_disease("pkill3"); rem_disease("pkill_l"); rem_disease("drunk"); rem_disease("cig"); rem_disease("high"); rem_disease("hallu"); rem_disease("visuals"); rem_disease("iodine"); rem_disease("datura"); rem_disease("took_xanax"); rem_disease("took_prozac"); rem_disease("took_flumed"); rem_disease("adrenaline"); rem_disease("meth"); pkill = 0; stim = 0; } else if(bio.id == "bio_evap") { item water = item("water_clean", 0); int humidity = g->weatherGen.get_weather(pos(), calendar::turn).humidity; int water_charges = (humidity * 3.0) / 100.0 + 0.5; // At 50% relative humidity or more, the player will draw 2 units of water // At 16% relative humidity or less, the player will draw 0 units of water water.charges = water_charges; if (water_charges == 0) { add_msg_if_player(m_bad, _("There was not enough moisture in the air from which to draw water!")); } if (g->handle_liquid(water, true, false)) { moves -= 100; } else if (query_yn(_("Drink from your hands?"))) { inv.push_back(water); consume(inv.position_by_type(water.typeId())); moves -= 350; } else if (water.charges == water_charges && water_charges != 0) { power_level += bionics["bio_evap"]->power_cost; } } else if(bio.id == "bio_lighter") { if(!choose_adjacent(_("Start a fire where?"), dirx, diry) || (!g->m.add_field(dirx, diry, fd_fire, 1))) { add_msg_if_player(m_info, _("You can't light a fire there.")); power_level += bionics["bio_lighter"]->power_cost; } } if(bio.id == "bio_leukocyte") { add_msg(m_neutral, _("You activate your leukocyte breeder system.")); g->u.set_healthy(std::min(100, g->u.get_healthy() + 2)); g->u.mod_healthy_mod(20); } if(bio.id == "bio_geiger") { add_msg(m_info, _("Your radiation level: %d"), radiation); } if(bio.id == "bio_radscrubber") { add_msg(m_neutral, _("You activate your radiation scrubber system.")); if (radiation > 4) { radiation -= 5; } else { radiation = 0; } } if(bio.id == "bio_adrenaline") { add_msg(m_neutral, _("You activate your adrenaline pump.")); if (has_disease("adrenaline")) { add_disease("adrenaline", 50); } else { add_disease("adrenaline", 200); } } else if(bio.id == "bio_claws") { if (weapon.type->id == "bio_claws_weapon") { add_msg(m_neutral, _("You withdraw your claws.")); weapon = ret_null; } else if (weapon.has_flag ("NO_UNWIELD")) { add_msg(m_info, _("Deactivate your %s first!"), weapon.tname().c_str()); power_level += bionics[bio.id]->power_cost; return; } else if(weapon.type->id != "null") { add_msg(m_warning, _("Your claws extend, forcing you to drop your %s."), weapon.tname().c_str()); g->m.add_item_or_charges(posx, posy, weapon); weapon = item("bio_claws_weapon", 0); weapon.invlet = '#'; } else { add_msg(m_neutral, _("Your claws extend!")); weapon = item("bio_claws_weapon", 0); weapon.invlet = '#'; } } else if(bio.id == "bio_blade") { if (weapon.type->id == "bio_blade_weapon") { add_msg(m_neutral, _("You retract your blade.")); weapon = ret_null; } else if (weapon.has_flag ("NO_UNWIELD")) { add_msg(m_info, _("Deactivate your %s first!"), weapon.tname().c_str()); power_level += bionics[bio.id]->power_cost; return; } else if(weapon.type->id != "null") { add_msg(m_warning, _("Your blade extends, forcing you to drop your %s."), weapon.tname().c_str()); g->m.add_item_or_charges(posx, posy, weapon); weapon = item("bio_blade_weapon", 0); weapon.invlet = '#'; } else { add_msg(m_neutral, _("You extend your blade!")); weapon = item("bio_blade_weapon", 0); weapon.invlet = '#'; } } else if(bio.id == "bio_blaster") { tmp_item = weapon; weapon = item("bio_blaster_gun", 0); g->refresh_all(); g->plfire(false); if(weapon.charges == 1) { // not fired power_level += bionics[bio.id]->power_cost; } weapon = tmp_item; } else if (bio.id == "bio_laser") { tmp_item = weapon; weapon = item("bio_laser_gun", 0); g->refresh_all(); g->plfire(false); if(weapon.charges == 1) { // not fired power_level += bionics[bio.id]->power_cost; } weapon = tmp_item; } else if(bio.id == "bio_chain_lightning") { tmp_item = weapon; weapon = item("bio_lightning", 0); g->refresh_all(); g->plfire(false); if(weapon.charges == 1) { // not fired power_level += bionics[bio.id]->power_cost; } weapon = tmp_item; } else if (bio.id == "bio_emp") { if(choose_adjacent(_("Create an EMP where?"), dirx, diry)) { g->emp_blast(dirx, diry); } else { power_level += bionics["bio_emp"]->power_cost; } } else if (bio.id == "bio_hydraulics") { add_msg(m_good, _("Your muscles hiss as hydraulic strength fills them!")); // Sound of hissing hydraulic muscle! (not quite as loud as a car horn) g->sound(posx, posy, 19, _("HISISSS!")); } else if (bio.id == "bio_water_extractor") { bool extracted = false; for (std::vector<item>::iterator it = g->m.i_at(posx, posy).begin(); it != g->m.i_at(posx, posy).end(); ++it) { if (it->type->id == "corpse" ) { int avail = 0; if ( it->item_vars.find("remaining_water") != it->item_vars.end() ) { avail = atoi ( it->item_vars["remaining_water"].c_str() ); } else { avail = it->volume() / 2; } if(avail > 0 && query_yn(_("Extract water from the %s"), it->tname().c_str())) { item water = item("water_clean", 0); if (g->handle_liquid(water, true, true)) { moves -= 100; } else if (query_yn(_("Drink directly from the condenser?"))) { inv.push_back(water); consume(inv.position_by_type(water.typeId())); moves -= 350; } extracted = true; avail--; it->item_vars["remaining_water"] = string_format("%d", avail); break; } } } if (!extracted) { power_level += bionics["bio_water_extractor"]->power_cost; } } else if(bio.id == "bio_magnet") { for (int i = posx - 10; i <= posx + 10; i++) { for (int j = posy - 10; j <= posy + 10; j++) { if (g->m.i_at(i, j).size() > 0) { int t; //not sure why map:sees really needs this, but w/e if (g->m.sees(i, j, posx, posy, -1, t)) { traj = line_to(i, j, posx, posy, t); } else { traj = line_to(i, j, posx, posy, 0); } } traj.insert(traj.begin(), point(i, j)); for (unsigned k = 0; k < g->m.i_at(i, j).size(); k++) { if (g->m.i_at(i, j)[k].made_of("iron") || g->m.i_at(i, j)[k].made_of("steel")) { tmp_item = g->m.i_at(i, j)[k]; g->m.i_rem(i, j, k); std::vector<point>::iterator it; for (it = traj.begin(); it != traj.end(); ++it) { int index = g->mon_at(it->x, it->y); if (index != -1) { g->zombie(index).apply_damage( this, bp_torso, tmp_item.weight() / 225 ); g->m.add_item_or_charges(it->x, it->y, tmp_item); break; } else if (it != traj.begin() && g->m.move_cost(it->x, it->y) == 0) { g->m.bash( it->x, it->y, tmp_item.weight() / 225 ); if (g->m.move_cost(it->x, it->y) == 0) { g->m.add_item_or_charges((it - 1)->x, (it - 1)->y, tmp_item); break; } } } if (it == traj.end()) { g->m.add_item_or_charges(posx, posy, tmp_item); } } } } } } else if(bio.id == "bio_lockpick") { if(!choose_adjacent(_("Activate your bio lockpick where?"), dirx, diry)) { power_level += bionics["bio_lockpick"]->power_cost; return; } ter_id type = g->m.ter(dirx, diry); if (type == t_door_locked || type == t_door_locked_alarm || type == t_door_locked_interior ) { moves -= 40; std::string door_name = rm_prefix(_("<door_name>door")); add_msg_if_player(m_neutral, _("With a satisfying click, the lock on the %s opens."), door_name.c_str()); g->m.ter_set(dirx, diry, t_door_c); // Locked metal doors are the Lab and Bunker entries. Those need to stay locked. } else if(type == t_door_bar_locked) { moves -= 40; std::string door_name = rm_prefix(_("<door_name>door")); add_msg_if_player(m_neutral, _("The %s swings open..."), door_name.c_str()); //Could better copy the messages from lockpick.... g->m.ter_set(dirx, diry, t_door_bar_o); } else if(type == t_chaingate_l) { moves -= 40; std::string gate_name = rm_prefix (_("<door_name>gate")); add_msg_if_player(m_neutral, _("With a satisfying click, the lock on the %s opens."), gate_name.c_str()); g->m.ter_set(dirx, diry, t_chaingate_c); } else if(type == t_door_c) { add_msg(m_info, _("That door isn't locked.")); } else { add_msg_if_player(m_neutral, _("You can't unlock that %s."), g->m.tername(dirx, diry).c_str()); } } else if(bio.id == "bio_flashbang") { add_msg_if_player(m_neutral, _("You activate your integrated flashbang generator!")); g->flashbang(posx, posy, true); } else if(bio.id == "bio_shockwave") { g->shockwave(posx, posy, 3, 4, 2, 8, true); add_msg_if_player(m_neutral, _("You unleash a powerful shockwave!")); } }