Exemplo n.º 1
0
void Character::i_rem_keep_contents( const int pos )
{
    for( auto &content : i_rem( pos ).contents ) {
        i_add_or_drop( content );
    }
}
Exemplo n.º 2
0
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--;
        }
    }
}
Exemplo n.º 3
0
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." ) );
        }
    }
}
Exemplo n.º 4
0
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
}