Пример #1
0
int player::get_acquirable_energy( const item &it, rechargeable_cbm cbm ) const
{
    switch( cbm ) {
        case rechargeable_cbm::none:
            break;

        case rechargeable_cbm::battery:
            return std::min<long>( it.charges, std::numeric_limits<int>::max() );

        case rechargeable_cbm::reactor:
            if( it.charges > 0 ) {
                const auto iter = plut_charges.find( it.typeId() );
                return iter != plut_charges.end() ? it.charges * iter->second : 0;
            }

            break;

        case rechargeable_cbm::furnace: {
            int amount = ( it.volume() / 250_ml + it.weight() / 1_gram ) / 9;

            // @todo JSONize.
            if( it.made_of( material_id( "leather" ) ) ) {
                amount /= 4;
            }
            if( it.made_of( material_id( "wood" ) ) ) {
                amount /= 2;
            }

            return amount;
        }
    }

    return 0;
}
Пример #2
0
void drop_or_handle( const item &newit, player &p )
{
    if( newit.made_of( LIQUID ) && &p == &g->u ) { // TODO: what about NPCs?
        g->handle_all_liquid( newit, PICKUP_RANGE );
    } else {
        item tmp( newit );
        p.i_add_or_drop( tmp );
    }
}
Пример #3
0
bool vehicle_part::can_reload( const item &obj ) const
{
    // first check part is not destroyed and can contain ammo
    if( !is_fuel_store() ) {
        return false;
    }

    if( !obj.is_null() ) {
        const itype_id obj_type = obj.typeId();
        if( is_reactor() ) {
            return base.is_reloadable_with( obj_type );
        }

        // forbid filling tanks with solids or non-material things
        if( is_tank() && ( obj.made_of( SOLID ) || obj.made_of( PNULL ) ) ) {
            return false;
        }
        // forbid putting liquids, gasses, and plasma in things that aren't tanks
        else if( !obj.made_of( SOLID ) && !is_tank() ) {
            return false;
        }
        // prevent mixing of different ammo
        if( ammo_current() != "null" && ammo_current() != obj_type ) {
            return false;
        }
        // For storage with set type, prevent filling with different types
        if( info().fuel_type != fuel_type_none && info().fuel_type != obj_type ) {
            return false;
        }
        // don't fill magazines with inappropriate fuel
        if( !is_tank() && !base.is_reloadable_with( obj_type ) ) {
            return false;
        }
    }

    return ammo_remaining() < ammo_capacity();
}
Пример #4
0
void Item_modifier::modify(item &new_item) const
{
    if(new_item.is_null()) {
        return;
    }
    int dm = (damage.first == damage.second) ? damage.first : rng(damage.first, damage.second);
    if(dm >= -1 && dm <= 4) {
        new_item.damage = dm;
    }
    long ch = (charges.first == charges.second) ? charges.first : rng(charges.first, charges.second);
    if(ch != -1) {
        it_tool *t = dynamic_cast<it_tool *>(new_item.type);
        it_gun *g = dynamic_cast<it_gun *>(new_item.type);
        if(new_item.count_by_charges()) {
            // food, ammo
            new_item.charges = ch;
        } else if(t != NULL) {
            new_item.charges = std::min(ch, t->max_charges);
        } else if(g != NULL && ammo.get() != NULL) {
            item am = ammo->create_single(new_item.bday);
            it_ammo *a = dynamic_cast<it_ammo *>(am.type);
            if(!am.is_null() && a != NULL) {
                new_item.curammo = a;
                new_item.charges = std::min<long>(am.charges, new_item.clip_size());
            }
        }
    }
    if(container.get() != NULL) {
        item cont = container->create_single(new_item.bday);
        if (!cont.is_null()) {
            if (new_item.made_of(LIQUID)) {
                LIQUID_FILL_ERROR err;
                int rc = cont.get_remaining_capacity_for_liquid(new_item, err);
                if(rc > 0 && (new_item.charges > rc || ch == -1)) {
                    // make sure the container is not over-full.
                    // fill up the container (if using default charges)
                    new_item.charges = rc;
                }
            }
            cont.put_in(new_item);
            new_item = cont;
        }
    }
    if (contents.get() != NULL) {
        Item_spawn_data::ItemList contentitems = contents->create(new_item.bday);
        new_item.contents.insert(new_item.contents.end(), contentitems.begin(), contentitems.end());
    }
}
Пример #5
0
void set_item_inventory( item &newit )
{
    if( newit.made_of( LIQUID ) ) {
        g->handle_all_liquid( newit, PICKUP_RANGE );
    } else {
        g->u.inv.assign_empty_invlet( newit );
        // We might not have space for the item
        if( !g->u.can_pickVolume( newit ) ) { //Accounts for result_mult
            add_msg( _( "There's no room in your inventory for the %s, so you drop it." ),
                     newit.tname().c_str() );
            g->m.add_item_or_charges( g->u.pos(), newit );
        } else if( !g->u.can_pickWeight( newit, !get_option<bool>( "DANGEROUS_PICKUPS" ) ) ) {
            add_msg( _( "The %s is too heavy to carry, so you drop it." ),
                     newit.tname().c_str() );
            g->m.add_item_or_charges( g->u.pos(), newit );
        } else {
            newit = g->u.i_add( newit );
            add_msg( m_info, "%c - %s", newit.invlet == 0 ? ' ' : newit.invlet, newit.tname().c_str() );
        }
    }
}
Пример #6
0
void Item_modifier::modify(item &new_item) const
{

    if(new_item.is_null()) {
        return;
    }

    new_item.damage = std::min( std::max( (int) rng( damage.first, damage.second ), MIN_ITEM_DAMAGE ), MAX_ITEM_DAMAGE );

    long ch = (charges.first == charges.second) ? charges.first : rng(charges.first, charges.second);

    if(ch != -1) {
        if( new_item.count_by_charges() || new_item.made_of( LIQUID ) ) {
            // food, ammo
            // count_by_charges requires that charges is at least 1. It makes no sense to
            // spawn a "water (0)" item.
            new_item.charges = std::max( 1l, ch );
        } else if( new_item.is_tool() ) {
            const auto qty = std::min( ch, new_item.ammo_capacity() );
            new_item.charges = qty;
            if( new_item.ammo_type() != "NULL" && qty > 0 ) {
                new_item.ammo_set( new_item.ammo_type(), qty );
            }
        } else if( !new_item.is_gun() ) {
            //not gun, food, ammo or tool. 
            new_item.charges = ch;
        }
    }
    
    if( new_item.is_gun() && ( ammo.get() != nullptr || ch > 0 ) ) {
        if( ammo.get() == nullptr ) {
            // In case there is no explicit ammo item defined, use the default ammo
            if( new_item.ammo_type() != "NULL" ) {
                new_item.charges = ch;
                new_item.set_curammo( new_item.ammo_type() );
            }
        } else {
            const item am = ammo->create_single( new_item.bday );
            new_item.set_curammo( am );
            // Prefer explicit charges of the gun, else take the charges of the ammo item,
            // Gun charges are easier to define: {"item":"gun","charge":10,"ammo-item":"ammo"}
            if( ch > 0 ) {
                new_item.charges = ch;
            } else {
                new_item.charges = am.charges;
            }
        }
        // Make sure the item is in valid state
        if( new_item.ammo_data() && new_item.magazine_integral() ) {
            new_item.charges = std::min( new_item.charges, new_item.ammo_capacity() );
        } else {
            new_item.charges = 0;
        }
    }

    if(container.get() != NULL) {
        item cont = container->create_single(new_item.bday);
        if (!cont.is_null()) {
            if (new_item.made_of(LIQUID)) {
                long rc = cont.get_remaining_capacity_for_liquid(new_item);
                if(rc > 0 && (new_item.charges > rc || ch == -1)) {
                    // make sure the container is not over-full.
                    // fill up the container (if using default charges)
                    new_item.charges = rc;
                }
            }
            cont.put_in(new_item);
            new_item = cont;
        }
    }
    if (contents.get() != NULL) {
        Item_spawn_data::ItemList contentitems = contents->create(new_item.bday);
        new_item.contents.insert(new_item.contents.end(), contentitems.begin(), contentitems.end());
    }
}
Пример #7
0
void Pickup::pick_one_up( const tripoint &pickup_target, item &newit, vehicle *veh,
                          int cargo_part, int index, int quantity, bool &got_water,
                          bool &offered_swap, PickupMap &mapPickup, bool autopickup )
{
    player &u = g->u;
    int moves_taken = 100;
    bool picked_up = false;
    pickup_answer option = CANCEL;
    item leftovers = newit;

    if( newit.invlet != '\0' &&
        u.invlet_to_position( newit.invlet ) != INT_MIN ) {
        // Existing invlet is not re-usable, remove it and let the code in player.cpp/inventory.cpp
        // add a new invlet, otherwise keep the (usable) invlet.
        newit.invlet = '\0';
    }

    if( quantity != 0 && newit.count_by_charges() ) {
        // Reinserting leftovers happens after item removal to avoid stacking issues.
        leftovers.charges = newit.charges - quantity;
        if( leftovers.charges > 0 ) {
            newit.charges = quantity;
        }
    } else {
        leftovers.charges = 0;
    }

    if( newit.made_of( LIQUID ) ) {
        got_water = true;
    } else if( !u.can_pickWeight( newit, false ) ) {
        add_msg( m_info, _( "The %s is too heavy!" ), newit.display_name().c_str() );
    } else if( newit.is_ammo() && ( newit.ammo_type() == ammotype( "arrow" ) ||
                                    newit.ammo_type() == ammotype( "bolt" ) ) ) {
        // @todo Make quiver code generic so that ammo pouches can use it too
        //add ammo to quiver
        int quivered = handle_quiver_insertion( newit, moves_taken, picked_up );

        if( quivered > 0 ) {
            quantity = quivered;
            //already picked up some for quiver so use special case handling
            picked_up = true;
            option = NUM_ANSWERS;
        }
        if( newit.charges > 0 ) {
            if( !u.can_pickVolume( newit ) ) {
                if( !autopickup ) {
                    // Silence some messaging if we're doing autopickup.
                    add_msg( m_info, ngettext( "There's no room in your inventory for the %s.",
                                               "There's no room in your inventory for the %s.",
                                               newit.charges ), newit.tname( newit.charges ).c_str() );
                }
            } else {
                // Add to inventory instead
                option = STASH;
            }
        }
        if( option == NUM_ANSWERS ) {
            //not picking up the rest so
            //update the charges for the item that gets re-added to the game map
            leftovers.charges = newit.charges;
        }
    } else if( newit.is_bucket() && !newit.is_container_empty() ) {
        if( !autopickup ) {
            const std::string &explain = string_format( _( "Can't stash %s while it's not empty" ),
                                         newit.display_name().c_str() );
            option = handle_problematic_pickup( newit, offered_swap, explain );
        } else {
            option = CANCEL;
        }
    } else if( !u.can_pickVolume( newit ) ) {
        if( !autopickup ) {
            const std::string &explain = string_format( _( "Not enough capacity to stash %s" ),
                                         newit.display_name().c_str() );
            option = handle_problematic_pickup( newit, offered_swap, explain );
        } else {
            option = CANCEL;
        }
    } else {
        option = STASH;
    }

    switch( option ) {
        case NUM_ANSWERS:
            // Some other option
            break;
        case CANCEL:
            picked_up = false;
            break;
        case WEAR:
            picked_up = u.wear_item( newit );
            break;
        case WIELD:
            picked_up = u.wield( newit );
            if( !picked_up ) {
                break;
            }

            if( u.weapon.invlet ) {
                add_msg( m_info, _( "Wielding %c - %s" ), u.weapon.invlet,
                         u.weapon.display_name().c_str() );
            } else {
                add_msg( m_info, _( "Wielding - %s" ), u.weapon.display_name().c_str() );
            }
            break;
        case SPILL:
            if( newit.is_container_empty() ) {
                debugmsg( "Tried to spill contents from an empty container" );
                break;
            }

            picked_up = newit.spill_contents( u );
            if( !picked_up ) {
                break;
            }
        // Intentional fallthrough
        case STASH:
            auto &entry = mapPickup[newit.tname()];
            entry.second += newit.count_by_charges() ? newit.charges : 1;
            entry.first = u.i_add( newit );
            picked_up = true;
            break;
    }

    if( picked_up ) {
        Pickup::remove_from_map_or_vehicle( pickup_target, veh, cargo_part, moves_taken, index );
    }
    if( leftovers.charges > 0 ) {
        bool to_map = veh == nullptr;
        if( !to_map ) {
            to_map = !veh->add_item( cargo_part, leftovers );
        }
        if( to_map ) {
            g->m.add_item_or_charges( pickup_target, leftovers );
        }
    }
}
Пример #8
0
void Pickup::pick_one_up( const tripoint &pickup_target, item &newit, vehicle *veh,
                          int cargo_part, int index, int quantity, bool &got_water,
                          bool &offered_swap, PickupMap &mapPickup, bool autopickup )
{
    int moves_taken = 100;
    bool picked_up = false;
    item leftovers = newit;

    if( newit.invlet != '\0' &&
        g->u.invlet_to_position( newit.invlet ) != INT_MIN ) {
        // Existing invlet is not re-usable, remove it and let the code in player.cpp/inventory.cpp
        // add a new invlet, otherwise keep the (usable) invlet.
        newit.invlet = '\0';
    }

    if( quantity != 0 && newit.count_by_charges() ) {
        // Reinserting leftovers happens after item removal to avoid stacking issues.
        leftovers.charges = newit.charges - quantity;
        if( leftovers.charges > 0 ) {
            newit.charges = quantity;
        }
    } else {
        leftovers.charges = 0;
    }

    if( newit.made_of(LIQUID) ) {
        got_water = true;
    } else if (!g->u.can_pickWeight(newit.weight(), false)) {
        add_msg(m_info, _("The %s is too heavy!"), newit.display_name().c_str());
    } else if( newit.is_ammo() && (newit.ammo_type() == "arrow" || newit.ammo_type() == "bolt")) {
        //add ammo to quiver
        int quivered = handle_quiver_insertion( newit, moves_taken, picked_up);
        if( newit.charges > 0) {
            if(!g->u.can_pickVolume( newit.volume())) {
                if(quivered > 0) {
                    //update the charges for the item that gets re-added to the game map
                    quantity = quivered;
                    leftovers.charges = newit.charges;
                }
                if( !autopickup ) {
                    // Silence some messaging if we're doing autopickup.
                    add_msg(m_info, ngettext("There's no room in your inventory for the %s.",
                                             "There's no room in your inventory for the %s.",
                                             newit.charges), newit.tname(newit.charges).c_str());
                }
            } else {
                //add to inventory instead
                item &it = g->u.i_add(newit);
                picked_up = true;

                //display output message
                PickupMap map_pickup;
                int charges = (newit.count_by_charges()) ? newit.charges : 1;
                map_pickup.insert(std::pair<std::string, ItemCount>(newit.tname(), ItemCount(it, charges)));
                show_pickup_message(map_pickup);
            }
        }
    } else if (!g->u.can_pickVolume(newit.volume())) {
        if( !autopickup ) {
            // Armor can be instantly worn
            if (newit.is_armor() &&
                query_yn(_("Put on the %s?"),
                         newit.display_name().c_str())) {
                if (g->u.wear_item(newit)) {
                    picked_up = true;
                }
            } else if (g->u.is_armed()) {
                if (!g->u.weapon.has_flag("NO_UNWIELD")) {
                    if( !offered_swap ) {
                        offered_swap = true;
                        if ( g->u.weapon.type->id != newit.type->id &&
                             query_yn(_("No space for %1$s; wield instead? (drops %2$s)"),
                                      newit.display_name().c_str(),
                                      g->u.weapon.display_name().c_str()) ) {
                            picked_up = true;
                            g->m.add_item_or_charges( pickup_target,
                                                      g->u.remove_weapon(), 1 );
                            g->u.inv.assign_empty_invlet( newit, true ); // force getting an invlet.
                            g->u.wield( &( g->u.i_add(newit) ) );

                            if (newit.invlet) {
                                add_msg(m_info, _("Wielding %c - %s"), newit.invlet,
                                        newit.display_name().c_str());
                            } else {
                                add_msg(m_info, _("Wielding - %s"), newit.display_name().c_str());
                            }
                        }
                    }
                } else {
                    add_msg(m_info, _("There's no room in your inventory for the %s "
                                      "and you can't unwield your %s."),
                            newit.display_name().c_str(),
                            g->u.weapon.display_name().c_str());
                }
            } else if( !g->u.is_armed()  ) {
                if (g->u.keep_hands_free) {
                    add_msg(m_info, _("There's no room in your inventory for the %s "
                                      "and you have decided to keep your hands free."),
                            newit.display_name().c_str());
                } else {
                    g->u.inv.assign_empty_invlet(newit, true);  // force getting an invlet.
                    g->u.wield(&(g->u.i_add(newit)));
                    picked_up = true;

                    if (newit.invlet) {
                        add_msg(m_info, _("Wielding %c - %s"), newit.invlet,
                                newit.display_name().c_str());
                    } else {
                        add_msg(m_info, _("Wielding - %s"), newit.display_name().c_str());
                    }
                }
            } // end of if unarmed
        } // end of if !autopickup
    } else {
        auto &entry = mapPickup[newit.tname()];
        entry.second += newit.count_by_charges() ? newit.charges : 1;
        entry.first = g->u.i_add(newit);
        picked_up = true;
    }

    if(picked_up) {
        Pickup::remove_from_map_or_vehicle(pickup_target,
                                           veh, cargo_part, moves_taken, index);
    }
    if( leftovers.charges > 0 ) {
        bool to_map = veh == nullptr;
        if( !to_map ) {
            to_map = !veh->add_item( cargo_part, leftovers );
        }
        if( to_map ) {
            g->m.add_item_or_charges( pickup_target, leftovers );
        }
    }
}
Пример #9
0
void game::throw_item(player &p, int tarx, int tary, item &thrown,
                      std::vector<point> &trajectory)
{
 int deviation = 0;
 int trange = 1.5 * rl_dist(p.posx, p.posy, tarx, tary);

// Throwing attempts below "Basic Competency" level are extra-bad
 int skillLevel = p.skillLevel("throw");

 if (skillLevel < 3)
  deviation += rng(0, 8 - skillLevel);

 if (skillLevel < 8)
  deviation += rng(0, 8 - skillLevel);
 else
  deviation -= skillLevel - 6;

 deviation += p.throw_dex_mod();

 if (p.per_cur < 6)
  deviation += rng(0, 8 - p.per_cur);
 else if (p.per_cur > 8)
  deviation -= p.per_cur - 8;

 deviation += rng(0, p.encumb(bp_hands) * 2 + p.encumb(bp_eyes) + 1);
 if (thrown.volume() > 5)
  deviation += rng(0, 1 + (thrown.volume() - 5) / 4);
 if (thrown.volume() == 0)
  deviation += rng(0, 3);

 deviation += rng(0, 1 + abs(p.str_cur - thrown.weight()));

 double missed_by = .01 * deviation * trange;
 bool missed = false;
 int tart;

 if (missed_by >= 1) {
// We missed D:
// Shoot a random nearby space?
  if (missed_by > 9)
   missed_by = 9;
  tarx += rng(0 - int(sqrt(double(missed_by))), int(sqrt(double(missed_by))));
  tary += rng(0 - int(sqrt(double(missed_by))), int(sqrt(double(missed_by))));
  if (m.sees(p.posx, p.posy, tarx, tary, -1, tart))
   trajectory = line_to(p.posx, p.posy, tarx, tary, tart);
  else
   trajectory = line_to(p.posx, p.posy, tarx, tary, 0);
  missed = true;
  if (!p.is_npc())
   add_msg("You miss!");
 } else if (missed_by >= .6) {
// Hit the space, but not necessarily the monster there
  missed = true;
  if (!p.is_npc())
   add_msg("You barely miss!");
 }

 std::string message;
 int dam = (thrown.weight() / 4 + thrown.type->melee_dam / 2 + p.str_cur / 2) /
            double(2 + double(thrown.volume() / 4));
 if (dam > thrown.weight() * 3)
  dam = thrown.weight() * 3;

 int i = 0, tx = 0, ty = 0;
 for (i = 0; i < trajectory.size() && dam > -10; i++) {
  message = "";
  double goodhit = missed_by;
  tx = trajectory[i].x;
  ty = trajectory[i].y;
// If there's a monster in the path of our item, and either our aim was true,
//  OR it's not the monster we were aiming at and we were lucky enough to hit it
  if (mon_at(tx, ty) != -1 &&
      (!missed || one_in(7 - int(z[mon_at(tx, ty)].type->size)))) {
   if (rng(0, 100) < 20 + skillLevel * 12 &&
       thrown.type->melee_cut > 0) {
    if (!p.is_npc()) {
     message += " You cut the ";
     message += z[mon_at(tx, ty)].name();
     message += "!";
    }
    if (thrown.type->melee_cut > z[mon_at(tx, ty)].armor_cut())
     dam += (thrown.type->melee_cut - z[mon_at(tx, ty)].armor_cut());
   }
   if (thrown.made_of(GLASS) && !thrown.active && // active = molotov, etc.
       rng(0, thrown.volume() + 8) - rng(0, p.str_cur) < thrown.volume()) {
    if (u_see(tx, ty))
     add_msg("The %s shatters!", thrown.tname().c_str());
    for (int i = 0; i < thrown.contents.size(); i++)
     m.add_item(tx, ty, thrown.contents[i]);
    sound(tx, ty, 16, "glass breaking!");
    int glassdam = rng(0, thrown.volume() * 2);
    if (glassdam > z[mon_at(tx, ty)].armor_cut())
     dam += (glassdam - z[mon_at(tx, ty)].armor_cut());
   } else
    m.add_item(tx, ty, thrown);
   if (i < trajectory.size() - 1)
    goodhit = double(double(rand() / RAND_MAX) / 2);
   if (goodhit < .1 && !z[mon_at(tx, ty)].has_flag(MF_NOHEAD)) {
    message = "Headshot!";
    dam = rng(dam, dam * 3);
    p.practice(turn, "throw", 5);
   } else if (goodhit < .2) {
    message = "Critical!";
    dam = rng(dam, dam * 2);
    p.practice(turn, "throw", 2);
   } else if (goodhit < .4)
    dam = rng(int(dam / 2), int(dam * 1.5));
   else if (goodhit < .5) {
    message = "Grazing hit.";
    dam = rng(0, dam);
   }
   if (!p.is_npc())
    add_msg("%s You hit the %s for %d damage.",
            message.c_str(), z[mon_at(tx, ty)].name().c_str(), dam);
   else if (u_see(tx, ty))
    add_msg("%s hits the %s for %d damage.", message.c_str(),
            z[mon_at(tx, ty)].name().c_str(), dam);
   if (z[mon_at(tx, ty)].hurt(dam))
    kill_mon(mon_at(tx, ty), !p.is_npc());
   return;
  } else // No monster hit, but the terrain might be.
   m.shoot(this, tx, ty, dam, false, 0);
  if (m.move_cost(tx, ty) == 0) {
   if (i > 0) {
    tx = trajectory[i - 1].x;
    ty = trajectory[i - 1].y;
   } else {
    tx = u.posx;
    ty = u.posy;
   }
   i = trajectory.size();
  }
 }
 if (m.move_cost(tx, ty) == 0) {
  if (i > 1) {
   tx = trajectory[i - 2].x;
   ty = trajectory[i - 2].y;
  } else {
   tx = u.posx;
   ty = u.posy;
  }
 }
 if (thrown.made_of(GLASS) && !thrown.active && // active means molotov, etc
     rng(0, thrown.volume() + 8) - rng(0, p.str_cur) < thrown.volume()) {
  if (u_see(tx, ty))
   add_msg("The %s shatters!", thrown.tname().c_str());
  for (int i = 0; i < thrown.contents.size(); i++)
   m.add_item(tx, ty, thrown.contents[i]);
  sound(tx, ty, 16, "glass breaking!");
 } else {
  sound(tx, ty, 8, "thud.");
  m.add_item(tx, ty, thrown);
 }
}
Пример #10
0
void pick_one_up( const tripoint &pickup_target, item &newit, vehicle *veh,
                  int cargo_part, int index, int quantity, bool &got_water,
                  bool &offered_swap, PickupMap &mapPickup, bool autopickup )
{
    player &u = g->u;
    int moves_taken = 100;
    bool picked_up = false;
    pickup_answer option = CANCEL;
    item leftovers = newit;

    if( newit.invlet != '\0' &&
        u.invlet_to_position( newit.invlet ) != INT_MIN ) {
        // Existing invlet is not re-usable, remove it and let the code in player.cpp/inventory.cpp
        // add a new invlet, otherwise keep the (usable) invlet.
        newit.invlet = '\0';
    }

    if( quantity != 0 && newit.count_by_charges() ) {
        // Reinserting leftovers happens after item removal to avoid stacking issues.
        leftovers.charges = newit.charges - quantity;
        if( leftovers.charges > 0 ) {
            newit.charges = quantity;
        }
    } else {
        leftovers.charges = 0;
    }

    if( newit.made_of( LIQUID ) ) {
        got_water = true;
    } else if( !u.can_pickWeight( newit, false ) ) {
        add_msg( m_info, _( "The %s is too heavy!" ), newit.display_name().c_str() );
    } else if( newit.is_bucket() && !newit.is_container_empty() ) {
        if( !autopickup ) {
            const std::string &explain = string_format( _( "Can't stash %s while it's not empty" ),
                                         newit.display_name().c_str() );
            option = handle_problematic_pickup( newit, offered_swap, explain );
        } else {
            option = CANCEL;
        }
    } else if( !u.can_pickVolume( newit ) ) {
        if( !autopickup ) {
            const std::string &explain = string_format( _( "Not enough capacity to stash %s" ),
                                         newit.display_name().c_str() );
            option = handle_problematic_pickup( newit, offered_swap, explain );
        } else {
            option = CANCEL;
        }
    } else {
        option = STASH;
    }

    switch( option ) {
        case NUM_ANSWERS:
            // Some other option
            break;
        case CANCEL:
            picked_up = false;
            break;
        case WEAR:
            picked_up = u.wear_item( newit );
            break;
        case WIELD:
            picked_up = u.wield( newit );
            if( !picked_up ) {
                break;
            }

            if( u.weapon.invlet ) {
                add_msg( m_info, _( "Wielding %c - %s" ), u.weapon.invlet,
                         u.weapon.display_name().c_str() );
            } else {
                add_msg( m_info, _( "Wielding - %s" ), u.weapon.display_name().c_str() );
            }
            break;
        case SPILL:
            if( newit.is_container_empty() ) {
                debugmsg( "Tried to spill contents from an empty container" );
                break;
            }

            picked_up = newit.spill_contents( u );
            if( !picked_up ) {
                break;
            }
        // Intentional fallthrough
        case STASH:
            auto &entry = mapPickup[newit.tname()];
            entry.second += newit.count_by_charges() ? newit.charges : 1;
            entry.first = u.i_add( newit );
            picked_up = true;
            break;
    }

    if( picked_up ) {
        remove_from_map_or_vehicle( pickup_target, veh, cargo_part, moves_taken, index );
    }
    if( leftovers.charges > 0 ) {
        bool to_map = veh == nullptr;
        if( !to_map ) {
            to_map = !veh->add_item( cargo_part, leftovers );
        }
        if( to_map ) {
            g->m.add_item_or_charges( pickup_target, leftovers );
        }
    }
}
Пример #11
0
void Item_modifier::modify(item &new_item) const
{

    if(new_item.is_null()) {
        return;
    }

    new_item.damage = std::min( std::max( (int) rng( damage.first, damage.second ), MIN_ITEM_DAMAGE ), MAX_ITEM_DAMAGE );

    long ch = (charges.first == charges.second) ? charges.first : rng(charges.first, charges.second);
    const auto g = new_item.type->gun.get();
    const auto t = dynamic_cast<const it_tool *>(new_item.type);
   
    if(ch != -1) {
        if( new_item.count_by_charges() || new_item.made_of( LIQUID ) ) {
            // food, ammo
            // count_by_charges requires that charges is at least 1. It makes no sense to
            // spawn a "water (0)" item.
            new_item.charges = std::max( 1l, ch );
        } else if(t != NULL) {
            new_item.charges = std::min(ch, t->max_charges);
        } else if (g == nullptr){
            //not gun, food, ammo or tool. 
            new_item.charges = ch;
        }
    }
    
    if( g != nullptr && ( ammo.get() != nullptr || ch > 0 ) ) {
        if( ammo.get() == nullptr ) {
            // In case there is no explicit ammo item defined, use the default ammo
            const auto ammoid = default_ammo( g->ammo );
            if ( !ammoid.empty() ) {
                new_item.set_curammo( ammoid );
                new_item.charges = ch;
            }
        } else {
            const item am = ammo->create_single( new_item.bday );
            new_item.set_curammo( am );
            // Prefer explicit charges of the gun, else take the charges of the ammo item,
            // Gun charges are easier to define: {"item":"gun","charge":10,"ammo-item":"ammo"}
            if( ch > 0 ) {
                new_item.charges = ch;
            } else {
                new_item.charges = am.charges;
            }
        }
        // Make sure the item is in a valid state curammo==0 <=> charges==0 and respect clip size
        if( !new_item.has_curammo() ) {
            new_item.charges = 0;
        } else {
            new_item.charges = std::min<long>( new_item.charges, new_item.clip_size() );
        }
    }
    if(container.get() != NULL) {
        item cont = container->create_single(new_item.bday);
        if (!cont.is_null()) {
            if (new_item.made_of(LIQUID)) {
                long rc = cont.get_remaining_capacity_for_liquid(new_item);
                if(rc > 0 && (new_item.charges > rc || ch == -1)) {
                    // make sure the container is not over-full.
                    // fill up the container (if using default charges)
                    new_item.charges = rc;
                }
            }
            cont.put_in(new_item);
            new_item = cont;
        }
    }
    if (contents.get() != NULL) {
        Item_spawn_data::ItemList contentitems = contents->create(new_item.bday);
        new_item.contents.insert(new_item.contents.end(), contentitems.begin(), contentitems.end());
    }
}
Пример #12
0
void Item_modifier::modify( item &new_item ) const
{

    if( new_item.is_null() ) {
        return;
    }

    new_item.set_damage( rng( damage.first, damage.second ) );

    long ch = ( charges.first == charges.second ) ? charges.first : rng( charges.first,
              charges.second );

    if( ch != -1 ) {
        if( new_item.count_by_charges() || new_item.made_of( LIQUID ) ) {
            // food, ammo
            // count_by_charges requires that charges is at least 1. It makes no sense to
            // spawn a "water (0)" item.
            new_item.charges = std::max( 1l, ch );
        } else if( new_item.is_tool() ) {
            const auto qty = std::min( ch, new_item.ammo_capacity() );
            new_item.charges = qty;
            if( new_item.ammo_type() && qty > 0 ) {
                new_item.ammo_set( new_item.ammo_type()->default_ammotype(), qty );
            }
        } else if( !new_item.is_gun() ) {
            //not gun, food, ammo or tool.
            new_item.charges = ch;
        }
    }

    if( ch > 0 && ( new_item.is_gun() || new_item.is_magazine() ) ) {
        if( ammo == nullptr ) {
            // In case there is no explicit ammo item defined, use the default ammo
            if( new_item.ammo_type() ) {
                new_item.ammo_set( new_item.ammo_type()->default_ammotype(), ch );
            }
        } else {
            const item am = ammo->create_single( new_item.birthday() );
            new_item.ammo_set( am.typeId(), ch );
        }
        // Make sure the item is in valid state
        if( new_item.ammo_data() && new_item.magazine_integral() ) {
            new_item.charges = std::min( new_item.charges, new_item.ammo_capacity() );
        } else {
            new_item.charges = 0;
        }
    }

    if( new_item.is_tool() || new_item.is_gun() || new_item.is_magazine() ) {
        bool spawn_ammo = rng( 0, 99 ) < with_ammo && new_item.ammo_remaining() == 0 && ch == -1 &&
                          ( !new_item.is_tool() || new_item.type->tool->rand_charges.empty() );
        bool spawn_mag  = rng( 0, 99 ) < with_magazine && !new_item.magazine_integral() &&
                          !new_item.magazine_current();

        if( spawn_mag ) {
            new_item.contents.emplace_back( new_item.magazine_default(), new_item.birthday() );
        }

        if( spawn_ammo ) {
            if( ammo ) {
                const item am = ammo->create_single( new_item.birthday() );
                new_item.ammo_set( am.typeId() );
            } else {
                new_item.ammo_set( new_item.ammo_type()->default_ammotype() );
            }
        }
    }

    if( container != nullptr ) {
        item cont = container->create_single( new_item.birthday() );
        if( !cont.is_null() ) {
            if( new_item.made_of( LIQUID ) ) {
                long rc = cont.get_remaining_capacity_for_liquid( new_item );
                if( rc > 0 && ( new_item.charges > rc || ch == -1 ) ) {
                    // make sure the container is not over-full.
                    // fill up the container (if using default charges)
                    new_item.charges = rc;
                }
            }
            cont.put_in( new_item );
            new_item = cont;
        }
    }

    if( contents != nullptr ) {
        Item_spawn_data::ItemList contentitems = contents->create( new_item.birthday() );
        new_item.contents.insert( new_item.contents.end(), contentitems.begin(), contentitems.end() );
    }

    for( auto &flag : custom_flags ) {
        new_item.set_flag( flag );
    }
}
Пример #13
0
void game::throw_item(player &p, int tarx, int tary, item &thrown,
                      std::vector<point> &trajectory)
{
    int deviation = 0;
    int trange = 1.5 * rl_dist(p.posx, p.posy, tarx, tary);
    std::set<std::string> no_effects;

    // Throwing attempts below "Basic Competency" level are extra-bad
    int skillLevel = p.skillLevel("throw");

    if (skillLevel < 3) {
        deviation += rng(0, 8 - skillLevel);
    }

    if (skillLevel < 8) {
        deviation += rng(0, 8 - skillLevel);
    } else {
        deviation -= skillLevel - 6;
    }

    deviation += p.throw_dex_mod();

    if (p.per_cur < 6) {
        deviation += rng(0, 8 - p.per_cur);
    } else if (p.per_cur > 8) {
        deviation -= p.per_cur - 8;
    }

    deviation += rng(0, p.encumb(bp_hands) * 2 + p.encumb(bp_eyes) + 1);
    if (thrown.volume() > 5) {
        deviation += rng(0, 1 + (thrown.volume() - 5) / 4);
    }
    if (thrown.volume() == 0) {
        deviation += rng(0, 3);
    }

    deviation += rng(0, std::max( 0, p.str_cur - thrown.weight() / 113 ) );

    double missed_by = .01 * deviation * trange;
    bool missed = false;
    int tart;

    if (missed_by >= 1) {
        // We missed D:
        // Shoot a random nearby space?
        if (missed_by > 9) {
            missed_by = 9;
        }

        tarx += rng(0 - int(sqrt(double(missed_by))), int(sqrt(double(missed_by))));
        tary += rng(0 - int(sqrt(double(missed_by))), int(sqrt(double(missed_by))));
        if (m.sees(p.posx, p.posy, tarx, tary, -1, tart)) {
            trajectory = line_to(p.posx, p.posy, tarx, tary, tart);
        } else {
            trajectory = line_to(p.posx, p.posy, tarx, tary, 0);
        }
        missed = true;
        add_msg_if_player(&p,_("You miss!"));
    } else if (missed_by >= .6) {
        // Hit the space, but not necessarily the monster there
        missed = true;
        add_msg_if_player(&p,_("You barely miss!"));
    }

    std::string message;
    int real_dam = (thrown.weight() / 452 + thrown.type->melee_dam / 2 + p.str_cur / 2) /
               double(2 + double(thrown.volume() / 4));
    if (real_dam > thrown.weight() / 40) {
        real_dam = thrown.weight() / 40;
    }
    if (p.has_active_bionic("bio_railgun") && (thrown.made_of("iron") || thrown.made_of("steel"))) {
        real_dam *= 2;
    }
    int dam = real_dam;

    int i = 0, tx = 0, ty = 0;
    for (i = 0; i < trajectory.size() && dam >= 0; i++) {
        message = "";
        double goodhit = missed_by;
        tx = trajectory[i].x;
        ty = trajectory[i].y;

        const int zid = mon_at(tx, ty);

        // If there's a monster in the path of our item, and either our aim was true,
        //  OR it's not the monster we were aiming at and we were lucky enough to hit it
        if (zid != -1 && (!missed || one_in(7 - int(zombie(zid).type->size)))) {
            monster &z = zombie(zid);
            if (rng(0, 100) < 20 + skillLevel * 12 && thrown.type->melee_cut > 0) {
                if (!p.is_npc()) {
                    message += string_format(_(" You cut the %s!"), z.name().c_str());
                }
                if (thrown.type->melee_cut > z.get_armor_cut(bp_torso)) {
                    dam += (thrown.type->melee_cut - z.get_armor_cut(bp_torso));
                }
            }
            if (thrown.made_of("glass") && !thrown.active && // active = molotov, etc.
                rng(0, thrown.volume() + 8) - rng(0, p.str_cur) < thrown.volume()) {
                if (u_see(tx, ty)) {
                    add_msg(_("The %s shatters!"), thrown.tname().c_str());
                }

                for (int i = 0; i < thrown.contents.size(); i++) {
                    m.add_item_or_charges(tx, ty, thrown.contents[i]);
                }

                sound(tx, ty, 16, _("glass breaking!"));
                int glassdam = rng(0, thrown.volume() * 2);
                if (glassdam > z.get_armor_cut(bp_torso)) {
                    dam += (glassdam - z.get_armor_cut(bp_torso));
                }
            } else {
                m.add_item_or_charges(tx, ty, thrown);
            }

            if (i < trajectory.size() - 1) {
                goodhit = double(double(rand() / RAND_MAX) / 2);
            }

            if (goodhit < .1 && !z.has_flag(MF_NOHEAD)) {
                message = _("Headshot!");
                dam = rng(dam, dam * 3);
                p.practice(turn, "throw", 5);
                p.lifetime_stats()->headshots++;
            } else if (goodhit < .2) {
                message = _("Critical!");
                dam = rng(dam, dam * 2);
                p.practice(turn, "throw", 2);
            } else if (goodhit < .4) {
                dam = rng(int(dam / 2), int(dam * 1.5));
            } else if (goodhit < .5) {
                message = _("Grazing hit.");
                dam = rng(0, dam);
            }
            if (u_see(tx, ty)) {
                g->add_msg_player_or_npc(&p,
                    _("%s You hit the %s for %d damage."),
                    _("%s <npcname> hits the %s for %d damage."),
                    message.c_str(), z.name().c_str(), dam);
            }
            if (z.hurt(dam, real_dam)) {
                z.die(&p);
            }
            return;
        } else { // No monster hit, but the terrain might be.
            m.shoot(tx, ty, dam, false, no_effects);
        }
        // Collide with impassable terrain
        if (m.move_cost(tx, ty) == 0) {
            if (i > 0) {
                tx = trajectory[i - 1].x;
                ty = trajectory[i - 1].y;
            } else {
                tx = u.posx;
                ty = u.posy;
            }
            i = trajectory.size();
        }
        if (p.has_active_bionic("bio_railgun") &&
            (thrown.made_of("iron") || thrown.made_of("steel"))) {
            m.add_field(tx, ty, fd_electricity, rng(2,3));
        }
    }
    if (thrown.made_of("glass") && !thrown.active && // active means molotov, etc
        rng(0, thrown.volume() + 8) - rng(0, p.str_cur) < thrown.volume()) {
        if (u_see(tx, ty)) {
            add_msg(_("The %s shatters!"), thrown.tname().c_str());
        }

        for (int i = 0; i < thrown.contents.size(); i++) {
            m.add_item_or_charges(tx, ty, thrown.contents[i]);
        }
        sound(tx, ty, 16, _("glass breaking!"));
    } else {
        if(m.has_flag("LIQUID", tx, ty)) {
            sound(tx, ty, 10, _("splash!"));
        } else {
            sound(tx, ty, 8, _("thud."));
        }
        m.add_item_or_charges(tx, ty, thrown);
    }
}