void Character::i_rem_keep_contents( const int pos ) { for( auto &content : i_rem( pos ).contents ) { i_add_or_drop( content ); } }
void map::shoot(game *g, int x, int y, int &dam, bool hit_items, unsigned flags) { if (flags & mfb(WF_AMMO_FLAME) && has_flag(flammable, x, y)) add_field(g, x, y, fd_fire, 2); switch (ter(x, y)) { case t_door_c: case t_door_locked: dam -= rng(15, 30); if (dam > 0) ter(x, y) = t_door_b; break; case t_door_b: if (hit_items || one_in(8)) { // 1 in 8 chance of hitting the door dam -= rng(10, 30); if (dam > 0) ter(x, y) = t_door_frame; } else dam -= rng(0, 1); break; case t_door_boarded: dam -= rng(15, 35); if (dam > 0) ter(x, y) = t_door_b; break; case t_window: dam -= rng(0, 5); if (dam > 0) ter(x, y) = t_window_frame; break; case t_window_boarded: dam -= rng(10, 30); if (dam > 0) ter(x, y) = t_window_frame; break; case t_wall_glass_h: case t_wall_glass_v: dam -= rng(0, 8); if (dam > 0) ter(x, y) = t_floor; break; case t_paper: dam -= rng(4, 16); if (dam > 0) ter(x, y) = t_dirt; if (flags & mfb(WF_AMMO_INCENDIARY)) add_field(g, x, y, fd_fire, 1); break; case t_gas_pump: if (hit_items || one_in(3)) { if (dam > 15) { if (flags & mfb(WF_AMMO_INCENDIARY) || flags & mfb(WF_AMMO_FLAME)) g->explosion(x, y, 40, 0, true); else { for (int i = x - 2; i <= x + 2; i++) { for (int j = y - 2; j <= y + 2; j++) { if (move_cost(i, j) > 0 && one_in(3)) add_item(i, j, g->itypes[itm_gasoline], 0); } } } ter(x, y) = t_gas_pump_smashed; } dam -= 60; } break; case t_vat: if (dam >= 10) { g->sound(x, y, 15, "ke-rash!"); ter(x, y) = t_floor; } else dam = 0; break; default: if (move_cost(x, y) == 0 && !trans(x, y)) dam = 0; // TODO: Bullets can go through some walls? else dam -= (rng(0, 1) * rng(0, 1) * rng(0, 1)); } // Now, destroy items on that tile. if ((move_cost(x, y) == 2 && !hit_items) || !inbounds(x, y)) return; // Items on floor-type spaces won't be shot up. bool destroyed; for (int i = 0; i < i_at(x, y).size(); i++) { destroyed = false; switch (i_at(x, y)[i].type->m1) { case GLASS: case PAPER: if (dam > rng(2, 8) && one_in(i_at(x, y)[i].volume())) destroyed = true; break; case PLASTIC: if (dam > rng(2, 10) && one_in(i_at(x, y)[i].volume() * 3)) destroyed = true; break; case VEGGY: case FLESH: if (dam > rng(10, 40)) destroyed = true; break; case COTTON: case WOOL: i_at(x, y)[i].damage++; if (i_at(x, y)[i].damage >= 5) destroyed = true; break; } if (destroyed) { for (int j = 0; j < i_at(x, y)[i].contents.size(); j++) i_at(x, y).push_back(i_at(x, y)[i].contents[j]); i_rem(x, y, i); i--; } } }
void player::complete_disassemble( int item_pos, const tripoint &loc, bool from_ground, const recipe &dis ) { // Get the proper recipe - the one for disassembly, not assembly const auto dis_requirements = dis.disassembly_requirements(); item &org_item = get_item_for_uncraft( *this, item_pos, loc, from_ground ); bool filthy = org_item.is_filthy(); if( org_item.is_null() ) { add_msg( _( "The item has vanished." ) ); activity.set_to_null(); return; } if( org_item.typeId() != dis.result ) { add_msg( _( "The item might be gone, at least it is not at the expected position anymore." ) ); activity.set_to_null(); return; } // Make a copy to keep its data (damage/components) even after it // has been removed. item dis_item = org_item; float component_success_chance = std::min( std::pow( 0.8, dis_item.damage() ), 1.0 ); add_msg( _( "You disassemble the %s into its components." ), dis_item.tname().c_str() ); // Remove any batteries, ammo and mods first remove_ammo( &dis_item, *this ); remove_radio_mod( dis_item, *this ); if( dis_item.count_by_charges() ) { // remove the charges that one would get from crafting it org_item.charges -= dis.create_result().charges; } // remove the item, except when it's counted by charges and still has some if( !org_item.count_by_charges() || org_item.charges <= 0 ) { if( from_ground ) { g->m.i_rem( loc, item_pos ); } else { i_rem( item_pos ); } } // Consume tool charges for( const auto &it : dis_requirements.get_tools() ) { consume_tools( it ); } // add the components to the map // Player skills should determine how many components are returned int skill_dice = 2 + get_skill_level( dis.skill_used ) * 3; skill_dice += get_skill_level( dis.skill_used ); // Sides on dice is 16 plus your current intelligence ///\EFFECT_INT increases success rate for disassembling items int skill_sides = 16 + int_cur; int diff_dice = dis.difficulty; int diff_sides = 24; // 16 + 8 (default intelligence) // disassembly only nets a bit of practice if( dis.skill_used ) { practice( dis.skill_used, ( dis.difficulty ) * 2, dis.difficulty ); } for( const auto &altercomps : dis_requirements.get_components() ) { const item_comp comp = find_component( altercomps, dis_item ); int compcount = comp.count; item newit( comp.type, calendar::turn ); // Counted-by-charge items that can be disassembled individually // have their component count multiplied by the number of charges. if( dis_item.count_by_charges() && dis.has_flag( "UNCRAFT_SINGLE_CHARGE" ) ) { compcount *= std::min( dis_item.charges, dis.create_result().charges ); } // Compress liquids and counted-by-charges items into one item, // they are added together on the map anyway and handle_liquid // should only be called once to put it all into a container at once. if( newit.count_by_charges() || newit.made_of( LIQUID ) ) { newit.charges = compcount; compcount = 1; } else if( !newit.craft_has_charges() && newit.charges > 0 ) { // tools that can be unloaded should be created unloaded, // tools that can't be unloaded will keep their default charges. newit.charges = 0; } for( ; compcount > 0; compcount-- ) { const bool comp_success = ( dice( skill_dice, skill_sides ) > dice( diff_dice, diff_sides ) ); if( dis.difficulty != 0 && !comp_success ) { add_msg( m_bad, _( "You fail to recover %s." ), newit.tname().c_str() ); continue; } const bool dmg_success = component_success_chance > rng_float( 0, 1 ); if( !dmg_success ) { // Show reason for failure (damaged item, tname contains the damage adjective) //~ %1s - material, %2$s - disassembled item add_msg( m_bad, _( "You fail to recover %1$s from the %2$s." ), newit.tname().c_str(), dis_item.tname().c_str() ); continue; } // Use item from components list, or (if not contained) // use newit, the default constructed. item act_item = newit; if( filthy ) { act_item.item_tags.insert( "FILTHY" ); } for( item::t_item_vector::iterator a = dis_item.components.begin(); a != dis_item.components.end(); ++a ) { if( a->type == newit.type ) { act_item = *a; dis_item.components.erase( a ); break; } } int veh_part = -1; vehicle *veh = g->m.veh_at( pos(), veh_part ); if( veh != nullptr ) { veh_part = veh->part_with_feature( veh_part, "CARGO" ); } if( act_item.made_of( LIQUID ) ) { g->handle_all_liquid( act_item, PICKUP_RANGE ); } else if( veh_part != -1 && veh->add_item( veh_part, act_item ) ) { // add_item did put the items in the vehicle, nothing further to be done } else { // TODO: For items counted by charges, add as much as we can to the vehicle, and // the rest on the ground (see dropping code and @vehicle::add_charges) g->m.add_item_or_charges( pos(), act_item ); } } } if( !dis.learn_by_disassembly.empty() && !knows_recipe( &dis ) ) { if( can_decomp_learn( dis ) ) { // @todo: make this depend on intelligence if( one_in( 4 ) ) { learn_recipe( &recipe_dict[ dis.ident() ] ); add_msg( m_good, _( "You learned a recipe from disassembling it!" ) ); } else { add_msg( m_info, _( "You might be able to learn a recipe if you disassemble another." ) ); } } else { add_msg( m_info, _( "If you had better skills, you might learn a recipe next time." ) ); } } }
bool map::bash(int x, int y, int str, std::string &sound) { sound = ""; for (int i = 0; i < i_at(x, y).size(); i++) { // Destroy glass items (maybe) if (i_at(x, y)[i].made_of(GLASS) && one_in(2)) { if (sound == "") sound = "A " + i_at(x, y)[i].tname() + " shatters! "; else sound = "Some items shatter! "; for (int j = 0; j < i_at(x, y)[i].contents.size(); j++) i_at(x, y).push_back(i_at(x, y)[i].contents[j]); i_rem(x, y, i); i--; } } switch (ter(x, y)) { case t_door_c: case t_door_locked: if (str >= rng(0, 40)) { sound += "smash!"; ter(x, y) = t_door_b; return true; } else { sound += "whump!"; return true; } break; case t_door_b: if (str >= rng(0, 30)) { sound += "crash!"; ter(x, y) = t_door_frame; int num_boards = rng(2, 6); for (int i = 0; i < num_boards; i++) add_item(x, y, (*itypes)[itm_2x4], 0); return true; } else { sound += "wham!"; return true; } break; case t_window: if (str >= rng(0, 6)) { sound += "glass breaking!"; ter(x, y) = t_window_frame; return true; } else { sound += "whack!"; return true; } break; case t_door_boarded: if (str >= dice(3, 50)) { sound += "crash!"; ter(x, y) = t_door_frame; int num_boards = rng(0, 2); for (int i = 0; i < num_boards; i++) add_item(x, y, (*itypes)[itm_2x4], 0); return true; } else { sound += "wham!"; return true; } break; case t_window_boarded: if (str >= dice(3, 30)) { sound += "crash!"; ter(x, y) = t_window_frame; int num_boards = rng(0, 2) * rng(0, 1); for (int i = 0; i < num_boards; i++) add_item(x, y, (*itypes)[itm_2x4], 0); return true; } else { sound += "wham!"; return true; } break; case t_paper: if (str >= dice(2, 6)) { sound += "rrrrip!"; ter(x, y) = t_dirt; return true; } else { sound += "slap!"; return true; } break; case t_toilet: if (str >= dice(8, 10)) { sound += "porcelain breaking!"; ter(x, y) = t_rubble; return true; } else { sound += "whunk!"; return true; } break; case t_dresser: if (str >= dice(3, 45)) { sound += "smash!"; ter(x, y) = t_floor; int num_boards = rng(4, 12); for (int i = 0; i < num_boards; i++) add_item(x, y, (*itypes)[itm_2x4], 0); return true; } else { sound += "whump."; return true; } break; case t_wall_glass_h: case t_wall_glass_v: if (str >= rng(0, 20)) { sound += "glass breaking!"; ter(x, y) = t_floor; return true; } else { sound += "whack!"; return true; } break; case t_reinforced_glass_h: case t_reinforced_glass_v: if (str >= rng(60, 100)) { sound += "glass breaking!"; ter(x, y) = t_floor; return true; } else { sound += "whack!"; return true; } break; case t_tree_young: if (str >= rng(0, 50)) { sound += "crunch!"; ter(x, y) = t_underbrush; int num_sticks = rng(0, 3); for (int i = 0; i < num_sticks; i++) add_item(x, y, (*itypes)[itm_stick], 0); return true; } else { sound += "whack!"; return true; } break; case t_underbrush: if (str >= rng(0, 30) && !one_in(4)) { sound += "crunch."; ter(x, y) = t_dirt; return true; } else { sound += "brush."; return true; } break; case t_marloss: if (str > rng(0, 40)) { sound += "crunch!"; ter(x, y) = t_fungus; return true; } else { sound += "whack!"; return true; } break; case t_vat: if (str >= dice(2, 20)) { sound += "ker-rash!"; ter(x, y) = t_floor; return true; } else { sound += "plunk."; return true; } } if (move_cost(x, y) == 0) { sound += "thump!"; return true; } return false; // If we kick empty space, the action is cancelled }