Exemple #1
0
void remove_ammo( item *dis_item, player &p )
{
    for( auto iter = dis_item->contents.begin(); iter != dis_item->contents.end(); ) {
        if( iter->has_flag( "IRREMOVABLE" ) ) {
            iter++;
            continue;
        }
        drop_or_handle( *iter, p );
        iter = dis_item->contents.erase( iter );
    }

    if( dis_item->has_flag( "NO_UNLOAD" ) ) {
        return;
    }
    if( dis_item->is_gun() && dis_item->ammo_current() != "null" ) {
        item ammodrop( dis_item->ammo_current(), calendar::turn );
        ammodrop.charges = dis_item->charges;
        drop_or_handle( ammodrop, p );
        dis_item->charges = 0;
    }
    if( dis_item->is_tool() && dis_item->charges > 0 && dis_item->ammo_type() ) {
        item ammodrop( default_ammo( dis_item->ammo_type() ), calendar::turn );
        ammodrop.charges = dis_item->charges;
        if( dis_item->ammo_type() == ammotype( "plutonium" ) ) {
            ammodrop.charges /= PLUTONIUM_CHARGES;
        }
        drop_or_handle( ammodrop, p );
        dis_item->charges = 0;
    }
}
Item_spawn_data::ItemList Item_group::create(int birthday, RecursionList &rec) const
{
    ItemList result;
    if (type == G_COLLECTION) {
        for(prop_list::const_iterator a = items.begin(); a != items.end(); ++a) {
            if(rng(0, 99) >= (*a)->probability) {
                continue;
            }
            ItemList tmp = (*a)->create(birthday, rec);
            result.insert(result.end(), tmp.begin(), tmp.end());
        }
    } else if (type == G_DISTRIBUTION) {
        int p = rng(0, sum_prob - 1);
        for(prop_list::const_iterator a = items.begin(); a != items.end(); ++a) {
            p -= (*a)->probability;
            if (p >= 0) {
                continue;
            }
            ItemList tmp = (*a)->create(birthday, rec);
            result.insert(result.end(), tmp.begin(), tmp.end());
            break;
        }
    }
    if (with_ammo && !result.empty()) {
        it_gun *maybe_gun = dynamic_cast<it_gun *>(result.front().type);
        if (maybe_gun != NULL) {
            item ammo(default_ammo(maybe_gun->ammo), birthday);
            // TODO: change the spawn lists to contain proper references to containers
            ammo = ammo.in_its_container();
            result.push_back(ammo);
        }
    }
    return result;
}
Exemple #3
0
void npc::starting_weapon(game *g)
{
 skill best = best_skill();
 int index;
 switch (best) {
 case sk_bashing:
  switch (rng(0, 5)) {
   case 0: weapon.make(g->itypes[itm_hammer]);        break;
   case 1: weapon.make(g->itypes[itm_wrench]);        break;
   case 2: weapon.make(g->itypes[itm_hammer_sledge]); break;
   case 3: weapon.make(g->itypes[itm_pipe]);          break;
   case 4: weapon.make(g->itypes[itm_bat]);           break;
   case 5: weapon.make(g->itypes[itm_crowbar]);       break;
  }
  break;
 case sk_cutting:
  switch (rng(0, 5)) {
   case 0: weapon.make(g->itypes[itm_knife_butcher]); break;
   case 1: weapon.make(g->itypes[itm_hatchet]);       break;
   case 2: weapon.make(g->itypes[itm_ax]);            break;
   case 3: weapon.make(g->itypes[itm_machete]);       break;
   case 4: weapon.make(g->itypes[itm_knife_combat]);  break;
   case 5: weapon.make(g->itypes[itm_katana]);        break;
  }
  break;
 case sk_throw:
// TODO: Some throwing weapons... grenades?
  break;
 case sk_pistol:
  index = rng(0, g->mapitems[mi_pistols].size() - 1);
  weapon.make(g->itypes[(g->mapitems[mi_pistols])[index]]);
  break;
 case sk_shotgun:
  index = rng(0, g->mapitems[mi_shotguns].size() - 1);
  weapon.make(g->itypes[(g->mapitems[mi_shotguns])[index]]);
  break;
 case sk_smg:
  index = rng(0, g->mapitems[mi_smg].size() - 1);
  weapon.make(g->itypes[(g->mapitems[mi_smg])[index]]);
  break;
 case sk_rifle:
  index = rng(0, g->mapitems[mi_rifles].size() - 1);
  weapon.make(g->itypes[(g->mapitems[mi_rifles])[index]]);
  break;
 }
 if (weapon.is_gun()) {
  it_gun* gun = dynamic_cast<it_gun*>(weapon.type);
  weapon.charges = gun->clip;
  weapon.curammo = dynamic_cast<it_ammo*>(g->itypes[default_ammo(gun->ammo)]);
 }
}
Item_spawn_data::ItemList Item_group::create(int birthday, RecursionList &rec) const
{
    ItemList result;
    if (type == G_COLLECTION) {
        for( const auto &elem : items ) {
            if( rng( 0, 99 ) >= ( elem )->probability ) {
                continue;
            }
            ItemList tmp = ( elem )->create( birthday, rec );
            result.insert(result.end(), tmp.begin(), tmp.end());
        }
    } else if (type == G_DISTRIBUTION) {
        int p = rng(0, sum_prob - 1);
        for( const auto &elem : items ) {
            p -= ( elem )->probability;
            if (p >= 0) {
                continue;
            }
            ItemList tmp = ( elem )->create( birthday, rec );
            result.insert(result.end(), tmp.begin(), tmp.end());
            break;
        }
    }

    for( auto& e : result ) {
        bool spawn_ammo = rng( 0, 99 ) < with_ammo;
        bool spawn_mags = rng( 0, 99 ) < with_magazine || spawn_ammo;

        if( spawn_mags && !e.magazine_integral() && !e.magazine_current() ) {
            e.contents.emplace_back( e.magazine_default(), e.bday );
        }
        if( spawn_ammo && e.ammo_capacity() > 0 && e.ammo_remaining() == 0 ) {
            itype_id ammo = default_ammo( e.ammo_type() );
            if( e.magazine_current() ) {
                e.magazine_current()->contents.emplace_back( ammo, e.bday, e.ammo_capacity() );
            } else {
                e.set_curammo( ammo );
                e.charges = e.ammo_capacity();
            }
        }
    }

    return result;
}
Exemple #5
0
Item_spawn_data::ItemList Item_group::create(int birthday, RecursionList &rec) const
{
    ItemList result;
    if (type == G_COLLECTION) {
        for( const auto &elem : items ) {
            if( rng( 0, 99 ) >= ( elem )->probability ) {
                continue;
            }
            ItemList tmp = ( elem )->create( birthday, rec );
            result.insert(result.end(), tmp.begin(), tmp.end());
        }
    } else if (type == G_DISTRIBUTION) {
        int p = rng(0, sum_prob - 1);
        for( const auto &elem : items ) {
            p -= ( elem )->probability;
            if (p >= 0) {
                continue;
            }
            ItemList tmp = ( elem )->create( birthday, rec );
            result.insert(result.end(), tmp.begin(), tmp.end());
            break;
        }
    }
    if (with_ammo && !result.empty()) {
        const auto t = result.front().type;
        if( t->gun ) {
            const std::string ammoid = default_ammo( t->gun->ammo );
            if ( !ammoid.empty() ) {
                item ammo( ammoid, birthday );
                // TODO: change the spawn lists to contain proper references to containers
                ammo = ammo.in_its_container();
                result.push_back( ammo );
            }
        }
    }
    return result;
}
Exemple #6
0
/**
 *Works through cached vehicle definitions and creates vehicle objects from them.
 */
void vehicle_prototype::finalize()
{
    for( auto &vp : vtypes ) {
        std::unordered_set<point> cargo_spots;
        vehicle_prototype &proto = vp.second;
        const vproto_id &id = vp.first;

        // Calls the default constructor to create an empty vehicle. Calling the constructor with
        // the type as parameter would make it look up the type in the map and copy the
        // (non-existing) blueprint.
        proto.blueprint.reset( new vehicle() );
        vehicle &blueprint = *proto.blueprint;
        blueprint.type = id;
        blueprint.name = _(proto.name.c_str());

        for( auto &pt : proto.parts ) {
            auto base = item::find_type( pt.part->item );

            if( !pt.part.is_valid() ) {
                debugmsg("unknown vehicle part %s in %s", pt.part.c_str(), id.c_str());
                continue;
            }

            if( blueprint.install_part( pt.pos.x, pt.pos.y, pt.part ) < 0 ) {
                debugmsg( "init_vehicles: '%s' part '%s'(%d) can't be installed to %d,%d",
                          blueprint.name.c_str(), pt.part.c_str(),
                          blueprint.parts.size(), pt.pos.x, pt.pos.y );
            }

            if( !base->gun ) {
                if( pt.with_ammo  ) {
                    debugmsg( "init_vehicles: non-turret %s with ammo in %s", pt.part.c_str(), id.c_str() );
                }
                if( !pt.ammo_types.empty() ) {
                    debugmsg( "init_vehicles: non-turret %s with ammo_types in %s", pt.part.c_str(), id.c_str() );
                }
                if( pt.ammo_qty.first > 0 || pt.ammo_qty.second > 0 ) {
                    debugmsg( "init_vehicles: non-turret %s with ammo_qty in %s", pt.part.c_str(), id.c_str() );
                }

            } else {
                for( const auto &e : pt.ammo_types ) {
                    auto ammo = item::find_type( e );
                    if( !ammo->ammo && ammo->ammo->type.count( base->gun->ammo ) ) {
                        debugmsg( "init_vehicles: turret %s has invalid ammo_type %s in %s",
                                  pt.part.c_str(), e.c_str(), id.c_str() );
                    }
                }
                if( pt.ammo_types.empty() ) {
                    pt.ammo_types.insert( default_ammo( base->gun->ammo ) );
                }
            }

            if( base->container ) {
                if( !item::type_is_defined( pt.fuel ) ) {
                    debugmsg( "init_vehicles: tank %s specified invalid fuel in %s", pt.part.c_str(), id.c_str() );
                }
            } else {
                if( pt.fuel != "null" ) {
                    debugmsg( "init_vehicles: non-tank %s with fuel in %s", pt.part.c_str(), id.c_str() );
                }
            }

            if( pt.part.obj().has_flag("CARGO") ) {
                cargo_spots.insert( pt.pos );
            }
        }

        for (auto &i : proto.item_spawns) {
            if( cargo_spots.count( i.pos ) == 0 ) {
                debugmsg("Invalid spawn location (no CARGO vpart) in %s (%d, %d): %d%%",
                         proto.name.c_str(), i.pos.x, i.pos.y, i.chance);
            }
            for (auto &j : i.item_ids) {
                if( !item::type_is_defined( j ) ) {
                    debugmsg("unknown item %s in spawn list of %s", j.c_str(), id.c_str());
                }
            }
            for (auto &j : i.item_groups) {
                if (!item_group::group_is_defined(j)) {
                    debugmsg("unknown item group %s in spawn list of %s", j.c_str(), id.c_str());
                }
            }
        }
    }
}
Exemple #7
0
std::vector<item> starting_inv(npc *me, npc_class type, game *g)
{
 int total_space = me->volume_capacity() - 2;
 std::vector<item> ret;
 itype_id tmp;

// First, if we're wielding a gun, get some ammo for it
 if (me->weapon.is_gun()) {
  it_gun *gun = dynamic_cast<it_gun*>(me->weapon.type);
  tmp = default_ammo(gun->ammo);
  if (total_space >= g->itypes[tmp]->volume) {
   ret.push_back(item(g->itypes[tmp], 0));
   total_space -= ret[ret.size() - 1].volume();
  }
  while ((type == NC_COWBOY || type == NC_BOUNTY_HUNTER || !one_in(3)) &&
         !one_in(4) && total_space >= g->itypes[tmp]->volume) {
   ret.push_back(item(g->itypes[tmp], 0));
   total_space -= ret[ret.size() - 1].volume();
  }
 }
 if (type == NC_TRADER) {	// Traders just have tons of random junk
  while (total_space > 0 && !one_in(50)) {
   tmp = itype_id(rng(2, num_items - 1));
// Make sure the item *isn't* in the list of not-okay items
// TODO: Make this more efficient
   for (int i = 0; i < g->mapitems[mi_trader_avoid].size(); i++) {
    if (tmp == g->mapitems[mi_trader_avoid][i]) {
     tmp = itype_id(rng(2, num_items - 1));
     i = 0;
    }
   }
   if (total_space >= g->itypes[tmp]->volume) {
    ret.push_back(item(g->itypes[tmp], 0));
    ret[ret.size() - 1] = ret[ret.size() - 1].in_its_container(&g->itypes);
    total_space -= ret[ret.size() - 1].volume();
   }
  }
  return ret;
 }
 int index;
 items_location from;
 if (type == NC_DOCTOR) {
  while(total_space > 0 && !one_in(10)) {
   if (one_in(3))
    from = mi_softdrugs;
   else
    from = mi_harddrugs;
   index = rng(0, g->mapitems[from].size() - 1);
   tmp = g->mapitems[from][index];
   if (total_space >= g->itypes[tmp]->volume) {
    ret.push_back(item(g->itypes[tmp], 0));
    ret[ret.size() - 1] = ret[ret.size() - 1].in_its_container(&g->itypes);
    total_space -= ret[ret.size() - 1].volume();
   }
  }
 }
// TODO: More specifics.

 while (total_space > 0 && !one_in(8)) {
  tmp = itype_id(rng(2, num_items - 1));
  if (total_space >= g->itypes[tmp]->volume) {
   ret.push_back(item(g->itypes[tmp], 0));
   ret[ret.size() - 1] = ret[ret.size() - 1].in_its_container(&g->itypes);
   total_space -= ret[ret.size() - 1].volume();
  }
 }
 
 return ret;
}
Exemple #8
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());
    }
}
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() && qty > 0 ) {
                new_item.ammo_set( default_ammo( 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() ) {
                new_item.ammo_set( default_ammo( new_item.ammo_type() ), ch );
            }
        } else {
            // 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"}
            const item am = ammo->create_single( new_item.bday );
            new_item.ammo_set( am.typeId(), ch > 0 ? ch : 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());
    }
}
Exemple #10
0
std::vector<item> starting_inv(npc *me, npc_class type, game *g)
{
 int total_space = me->volume_capacity() - 2;
 std::vector<item> ret;
 ret.push_back( item(g->itypes[itm_lighter], 0) );
 itype_id tmp;

// First, if we're wielding a gun, get some ammo for it
 if (me->weapon.is_gun()) {
  it_gun *gun = dynamic_cast<it_gun*>(me->weapon.type);
  tmp = default_ammo(gun->ammo);
  if (total_space >= g->itypes[tmp]->volume) {
   ret.push_back(item(g->itypes[tmp], 0));
   total_space -= ret[ret.size() - 1].volume();
  }
  while ((type == NC_COWBOY || type == NC_BOUNTY_HUNTER || !one_in(3)) &&
         !one_in(4) && total_space >= g->itypes[tmp]->volume) {
   ret.push_back(item(g->itypes[tmp], 0));
   total_space -= ret[ret.size() - 1].volume();
  }
 }
 if (type == NC_TRADER) {	// Traders just have tons of random junk
  while (total_space > 0 && !one_in(50)) {
   tmp = itype_id(rng(2, num_items - 1));
   if (total_space >= g->itypes[tmp]->volume) {
    ret.push_back(item(g->itypes[tmp], 0));
    ret[ret.size() - 1] = ret[ret.size() - 1].in_its_container(&g->itypes);
    total_space -= ret[ret.size() - 1].volume();
   }
  }
 }
 int index;
 items_location from;
 if (type == NC_HACKER) {
  from = mi_npc_hacker;
  while(total_space > 0 && !one_in(10)) {
   index = rng(0, g->mapitems[from].size() - 1);
   tmp = g->mapitems[from][index];
   item tmpit(g->itypes[tmp], 0);
   tmpit = tmpit.in_its_container(&g->itypes);
   if (total_space >= tmpit.volume()) {
    ret.push_back(tmpit);
    total_space -= tmpit.volume();
   }
  }
 }
 if (type == NC_DOCTOR) {
  while(total_space > 0 && !one_in(10)) {
   if (one_in(3))
    from = mi_softdrugs;
   else
    from = mi_harddrugs;
   index = rng(0, g->mapitems[from].size() - 1);
   tmp = g->mapitems[from][index];
   item tmpit(g->itypes[tmp], 0);
   tmpit = tmpit.in_its_container(&g->itypes);
   if (total_space >= tmpit.volume()) {
    ret.push_back(tmpit);
    total_space -= tmpit.volume();
   }
  }
 }
// TODO: More specifics.

 while (total_space > 0 && !one_in(8)) {
  tmp = itype_id(rng(4, num_items - 1));
  if (total_space >= g->itypes[tmp]->volume) {
   ret.push_back(item(g->itypes[tmp], 0));
   ret[ret.size() - 1] = ret[ret.size() - 1].in_its_container(&g->itypes);
   total_space -= ret[ret.size() - 1].volume();
  }
 }

 for (int i = 0; i < ret.size(); i++) {
  for (int j = 0; j < g->mapitems[mi_trader_avoid].size(); j++) {
   if (ret[i].type->id == g->mapitems[mi_trader_avoid][j]) {
    ret.erase(ret.begin() + i);
    i--;
   }
  }
 }
 
 return ret;
}
Exemple #11
0
bool game::dump_stats( const std::string& what, dump_mode mode, const std::vector<std::string> &opts )
{
    try {
        load_core_data();
    } catch( const std::exception &err ) {
        std::cerr << "Error loading data from json: " << err.what() << std::endl;
        return false;
    }
    DynamicDataLoader::get_instance().finalize_loaded_data();

    std::vector<std::string> header;
    std::vector<std::vector<std::string>> rows;

    int scol = 0; // sorting column

    std::map<std::string, standard_npc> test_npcs;
    test_npcs[ "S1" ] = standard_npc( "S1", { "gloves_survivor", "mask_lsurvivor" }, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ );
    test_npcs[ "S2" ] = standard_npc( "S2", { "gloves_fingerless", "sunglasses" }, 4, 8, 8, 8, 10 /* PER 10 */ );
    test_npcs[ "S3" ] = standard_npc( "S3", { "gloves_plate", "helmet_plate" },  4, 10, 8, 8, 8 /* STAT 10 */ );
    test_npcs[ "S4" ] = standard_npc( "S4", {}, 0, 8, 10, 8, 10 /* DEX 10, PER 10 */ );
    test_npcs[ "S5" ] = standard_npc( "S5", {}, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ );
    test_npcs[ "S6" ] = standard_npc( "S6", { "gloves_hsurvivor", "mask_hsurvivor" }, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ );

    std::map<std::string, item> test_items;
    test_items[ "G1" ] = item( "glock_19" ).ammo_set( "9mm" );
    test_items[ "G2" ] = item( "hk_mp5" ).ammo_set( "9mm" );
    test_items[ "G3" ] = item( "ar15" ).ammo_set( "223" );
    test_items[ "G4" ] = item( "remington_700" ).ammo_set( "270" );
    test_items[ "G4" ].emplace_back( "rifle_scope" );

    if( what == "AMMO" ) {
        header = {
            "Name", "Ammo", "Volume", "Weight", "Stack",
            "Range", "Dispersion", "Recoil", "Damage", "Pierce"
        };
        auto dump = [&rows]( const item& obj ) {
            // a common task is comparing ammo by type so ammo has multiple repeat the entry
            for( const auto &e : obj.type->ammo->type ) {
                std::vector<std::string> r;
                r.push_back( obj.tname( 1, false ) );
                r.push_back( e.str() );
                r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) );
                r.push_back( to_string( obj.weight() ) );
                r.push_back( to_string( obj.type->stack_size ) );
                r.push_back( to_string( obj.type->ammo->range ) );
                r.push_back( to_string( obj.type->ammo->dispersion ) );
                r.push_back( to_string( obj.type->ammo->recoil ) );
                r.push_back( to_string( obj.type->ammo->damage ) );
                r.push_back( to_string( obj.type->ammo->pierce ) );
                rows.push_back( r );
            }
        };
        for( auto& e : item_controller->get_all_itypes() ) {
            if( e.second.ammo ) {
                dump( item( e.first, calendar::turn, item::solitary_tag {} ) );
            }
        }

    } else if( what == "ARMOR" ) {
        header = {
            "Name", "Encumber (fit)", "Warmth", "Weight", "Storage", "Coverage", "Bash", "Cut", "Acid", "Fire"
        };
        auto dump = [&rows]( const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( 1, false ) );
            r.push_back( to_string( obj.get_encumber() ) );
            r.push_back( to_string( obj.get_warmth() ) );
            r.push_back( to_string( obj.weight() ) );
            r.push_back( to_string( obj.get_storage() / units::legacy_volume_factor ) );
            r.push_back( to_string( obj.get_coverage() ) );
            r.push_back( to_string( obj.bash_resist() ) );
            r.push_back( to_string( obj.cut_resist() ) );
            r.push_back( to_string( obj.acid_resist() ) );
            r.push_back( to_string( obj.fire_resist() ) );
            rows.push_back( r );
        };

        body_part bp = opts.empty() ? num_bp : get_body_part_token( opts.front() );

        for( auto& e : item_controller->get_all_itypes() ) {
            if( e.second.armor ) {
                item obj( e.first );
                if( bp == num_bp || obj.covers( bp ) ) {
                    if( obj.has_flag( "VARSIZE" ) ) {
                        obj.item_tags.insert( "FIT" );
                    }
                    dump( obj );
                }
            }
        }

    } else if( what == "EDIBLE" ) {
        header = {
            "Name", "Volume", "Weight", "Stack", "Calories", "Quench", "Healthy"
        };
        for( const auto& v : vitamin::all() ) {
             header.push_back( v.second.name() );
        }
        auto dump = [&rows,&test_npcs]( const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( false ) );
            r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) );
            r.push_back( to_string( obj.weight() ) );
            r.push_back( to_string( obj.type->stack_size ) );
            r.push_back( to_string( obj.type->comestible->get_calories() ) );
            r.push_back( to_string( obj.type->comestible->quench ) );
            r.push_back( to_string( obj.type->comestible->healthy ) );
            auto vits = g->u.vitamins_from( obj );
            for( const auto& v : vitamin::all() ) {
                 r.push_back( to_string( vits[ v.first ] ) );
            }
            rows.push_back( r );
        };
        for( auto& e : item_controller->get_all_itypes() ) {
            if( e.second.comestible &&
                ( e.second.comestible->comesttype == "FOOD" ||
                  e.second.comestible->comesttype == "DRINK" ) ) {

                item food( e.first, calendar::turn, item::solitary_tag {} );
                if( g->u.can_eat( food, false, true ) == EDIBLE ) {
                    dump( food );
                }
            }
        }

    } else if( what == "GUN" ) {
        header = {
            "Name", "Ammo", "Volume", "Weight", "Capacity",
            "Range", "Dispersion", "Effective recoil", "Damage", "Pierce",
            "Aim time", "Effective range", "Snapshot range", "Max range"
        };

        std::set<std::string> locations;
        for( const auto& e : item_controller->get_all_itypes() ) {
            if( e.second.gun ) {
                std::transform( e.second.gun->valid_mod_locations.begin(),
                                e.second.gun->valid_mod_locations.end(),
                                std::inserter( locations, locations.begin() ),
                                []( const std::pair<std::string, int>& e ) { return e.first; } );
            }
        }
        for( const auto &e : locations ) {
            header.push_back( e );
        }

        auto dump = [&rows,&locations]( const standard_npc &who, const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( 1, false ) );
            r.push_back( obj.ammo_type() ? obj.ammo_type().str() : "" );
            r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) );
            r.push_back( to_string( obj.weight() ) );
            r.push_back( to_string( obj.ammo_capacity() ) );
            r.push_back( to_string( obj.gun_range() ) );
            r.push_back( to_string( obj.gun_dispersion() ) );
            r.push_back( to_string( obj.gun_recoil( who ) ) );
            r.push_back( to_string( obj.gun_damage() ) );
            r.push_back( to_string( obj.gun_pierce() ) );

            r.push_back( to_string( who.gun_engagement_moves( obj ) ) );

            r.push_back( string_format( "%.1f", who.gun_engagement_range( obj, player::engagement::effective ) ) );
            r.push_back( string_format( "%.1f", who.gun_engagement_range( obj, player::engagement::snapshot ) ) );
            r.push_back( string_format( "%.1f", who.gun_engagement_range( obj, player::engagement::maximum ) ) );

            for( const auto &e : locations ) {
                r.push_back( to_string( obj.type->gun->valid_mod_locations[ e ] ) );
            }
            rows.push_back( r );
        };
        for( const auto& e : item_controller->get_all_itypes() ) {
            if( e.second.gun ) {
                item gun( e.first );
                if( !gun.magazine_integral() ) {
                    gun.emplace_back( gun.magazine_default() );
                }
                gun.ammo_set( default_ammo( gun.ammo_type() ), gun.ammo_capacity() );

                dump( test_npcs[ "S1" ], gun );

                if( gun.type->gun->barrel_length > 0 ) {
                    gun.emplace_back( "barrel_small" );
                    dump( test_npcs[ "S1" ], gun );
                }
            }
        }

    } else if( what == "VEHICLE" ) {
        header = {
            "Name", "Weight (empty)", "Weight (fueled)",
            "Max velocity (mph)", "Safe velocity (mph)", "Acceleration (mph/turn)",
            "Mass coeff %", "Aerodynamics coeff %", "Friction coeff %",
            "Traction coeff % (grass)"
        };
        auto dump = [&rows]( const vproto_id& obj ) {
            auto veh_empty = vehicle( obj, 0, 0 );
            auto veh_fueled = vehicle( obj, 100, 0 );

            std::vector<std::string> r;
            r.push_back( veh_empty.name );
            r.push_back( to_string( veh_empty.total_mass() ) );
            r.push_back( to_string( veh_fueled.total_mass() ) );
            r.push_back( to_string( veh_fueled.max_velocity() / 100 ) );
            r.push_back( to_string( veh_fueled.safe_velocity() / 100 ) );
            r.push_back( to_string( veh_fueled.acceleration() / 100 ) );
            r.push_back( to_string( (int)( 100 * veh_fueled.k_mass() ) ) );
            r.push_back( to_string( (int)( 100 * veh_fueled.k_aerodynamics() ) ) );
            r.push_back( to_string( (int)( 100 * veh_fueled.k_friction() ) ) );
            r.push_back( to_string( (int)( 100 * veh_fueled.k_traction( veh_fueled.wheel_area( false ) / 2.0f ) ) ) );
            rows.push_back( r );
        };
        for( auto& e : vehicle_prototype::get_all() ) {
            dump( e );
        }

    } else if( what == "VPART" ) {
        header = {
            "Name", "Location", "Weight", "Size"
        };
        auto dump = [&rows]( const vpart_info &obj ) {
            std::vector<std::string> r;
            r.push_back( obj.name() );
            r.push_back( obj.location );
            r.push_back( to_string( int( ceil( item( obj.item ).weight() / 1000.0 ) ) ) );
            r.push_back( to_string( obj.size / units::legacy_volume_factor ) );
            rows.push_back( r );
        };
        for( const auto &e : vpart_info::all() ) {
            dump( e.second );
        }

    } else if( what == "AIMING" ) {
        scol = -1; // unsorted output so graph columns have predictable ordering

        const int cycles = 1400;

        header = { "Name" };
        for( int i = 0; i <= cycles; ++i ) {
            header.push_back( to_string( i ) );
        }

        auto dump = [&rows]( const standard_npc &who, const item &gun) {
            std::vector<std::string> r( 1, string_format( "%s %s", who.get_name().c_str(), gun.tname().c_str() ) );
            double penalty = MIN_RECOIL;
            for( int i = 0; i <= cycles; ++i ) {
                penalty -= who.aim_per_move( gun, penalty );
                r.push_back( string_format( "%.2f", who.gun_current_range( gun, penalty ) ) );
            }
            rows.push_back( r );
        };

        if( opts.empty() ) {
            dump( test_npcs[ "S1" ], test_items[ "G1" ] );
            dump( test_npcs[ "S1" ], test_items[ "G2" ] );
            dump( test_npcs[ "S1" ], test_items[ "G3" ] );
            dump( test_npcs[ "S1" ], test_items[ "G4" ] );

        } else {
            for( const auto &str : opts ) {
                auto idx = str.find( ':' );
                if( idx == std::string::npos ) {
                    std::cerr << "cannot parse test case: " << str << std::endl;
                    return false;
                }
                auto test = std::make_pair( test_npcs.find( str.substr( 0, idx ) ),
                                            test_items.find( str.substr( idx + 1 ) ) );

                if( test.first == test_npcs.end() || test.second == test_items.end() ) {
                    std::cerr << "invalid test case: " << str << std::endl;
                    return false;
                }

                dump( test.first->second, test.second->second );
            }
        }

    } else if( what == "EXPLOSIVE" ) {
        header = {
            // @todo Should display more useful data: shrapnel damage, safe range
            "Name", "Power", "Power at 5 tiles", "Power halves at", "Shrapnel count", "Shrapnel mass"
        };

        auto dump = [&rows]( const std::string &name, const explosion_data &ex ) {
            std::vector<std::string> r;
            r.push_back( name );
            r.push_back( to_string( ex.power ) );
            r.push_back( string_format( "%.1f", ex.power_at_range( 5.0f ) ) );
            r.push_back( string_format( "%.1f", ex.expected_range( 0.5f ) ) );
            r.push_back( to_string( ex.shrapnel.count ) );
            r.push_back( to_string( ex.shrapnel.mass ) );
            rows.push_back( r );
        };
        for( const auto& e : item_controller->get_all_itypes() ) {
            const auto &itt = e.second;
            const auto use = itt.get_use( "explosion" );
            if( use != nullptr && use->get_actor_ptr() != nullptr ) {
                const auto actor = dynamic_cast<const explosion_iuse *>( use->get_actor_ptr() );
                if( actor != nullptr ) {
                    dump( itt.nname( 1 ), actor->explosion );
                }
            }

            auto c_ex = dynamic_cast<const explosion_iuse *>( itt.countdown_action.get_actor_ptr() );
            if( c_ex != nullptr ) {
                dump( itt.nname( 1 ), c_ex->explosion );
            }
        }

    } else {
        std::cerr << "unknown argument: " << what << std::endl;
        return false;
    }

    rows.erase( std::remove_if( rows.begin(), rows.end(), []( const std::vector<std::string>& e ) {
        return e.empty();
    } ), rows.end() );

    if( scol >= 0 ) {
        std::sort( rows.begin(), rows.end(), [&scol]( const std::vector<std::string>& lhs, const std::vector<std::string>& rhs ) {
            return lhs[ scol ] < rhs[ scol ];
        } );
    }

    rows.erase( std::unique( rows.begin(), rows.end() ), rows.end() );

    switch( mode ) {
        case dump_mode::TSV:
            rows.insert( rows.begin(), header );
            for( const auto& r : rows ) {
                std::copy( r.begin(), r.end() - 1, std::ostream_iterator<std::string>( std::cout, "\t" ) );
                std::cout << r.back() << "\n";
            }
            break;

        case dump_mode::HTML:
            std::cout << "<table>";

            std::cout << "<thead>";
            std::cout << "<tr>";
            for( const auto& col : header ) {
                std::cout << "<th>" << col << "</th>";
            }
            std::cout << "</tr>";
            std::cout << "</thead>";

            std::cout << "<tdata>";
            for( const auto& r : rows ) {
                std::cout << "<tr>";
                for( const auto& col : r ) {
                    std::cout << "<td>" << col << "</td>";
                }
                std::cout << "</tr>";
            }
            std::cout << "</tdata>";

            std::cout << "</table>";
            break;
    }

    return true;
}
/**
 * Called when the activity timer for installing parts, repairing, etc times
 * out and the the action is complete.
 */
void complete_vehicle (game *g)
{
    if (g->u.activity.values.size() < 8) {
        debugmsg ("Invalid activity ACT_VEHICLE values:%d", g->u.activity.values.size());
        return;
    }
    vehicle *veh = g->m.veh_at (g->u.activity.values[0], g->u.activity.values[1]);
    if (!veh) {
        debugmsg ("Activity ACT_VEHICLE: vehicle not found");
        return;
    }
    char cmd = (char) g->u.activity.index;
    int dx = g->u.activity.values[4];
    int dy = g->u.activity.values[5];
    int vehicle_part = g->u.activity.values[6];
    int type = g->u.activity.values[7];
    std::string part_id = g->u.activity.str_values[0];
    std::vector<component> tools;
    int welder_charges = static_cast<it_tool *>(itypes["welder"])->charges_per_use;
    int welder_crude_charges = static_cast<it_tool *>(itypes["welder_crude"])->charges_per_use;
    int partnum;
    item used_item;
    bool broken;
    int replaced_wheel;
    std::vector<int> parts;
    int dd = 2;
    switch (cmd) {
    case 'i':
        partnum = veh->install_part (dx, dy, part_id);
        if(partnum < 0) {
            debugmsg ("complete_vehicle install part fails dx=%d dy=%d id=%d", dx, dy, part_id.c_str());
        }
        used_item = consume_vpart_item (g, part_id);
        veh->get_part_properties_from_item(g, partnum, used_item); //transfer damage, etc.
        tools.push_back(component("welder", welder_charges));
        tools.push_back(component("welder_crude", welder_crude_charges));
        tools.push_back(component("duct_tape", DUCT_TAPE_USED));
        tools.push_back(component("toolset", welder_charges / 20));
        g->consume_tools(&g->u, tools, true);

        if ( vehicle_part_types[part_id].has_flag("CONE_LIGHT") ) {
            // Need map-relative coordinates to compare to output of look_around.
            int gx, gy;
            // Need to call coord_translate() directly since it's a new part.
            veh->coord_translate(dx, dy, gx, gy);
            // Stash offset and set it to the location of the part so look_around will start there.
            int px = g->u.view_offset_x;
            int py = g->u.view_offset_y;
            g->u.view_offset_x = veh->global_x() + gx - g->u.posx;
            g->u.view_offset_y = veh->global_y() + gy - g->u.posy;
            popup(_("Choose a facing direction for the new headlight."));
            point headlight_target = g->look_around();
            // Restore previous view offsets.
            g->u.view_offset_x = px;
            g->u.view_offset_y = py;

            int delta_x = headlight_target.x - (veh->global_x() + gx);
            int delta_y = headlight_target.y - (veh->global_y() + gy);

            const double PI = 3.14159265358979f;
            int dir = int(atan2(static_cast<float>(delta_y), static_cast<float>(delta_x)) * 180.0 / PI);
            dir -= veh->face.dir();
            while(dir < 0) {
                dir += 360;
            }
            while(dir > 360) {
                dir -= 360;
            }

            veh->parts[partnum].direction = dir;
        }

        g->add_msg (_("You install a %s into the %s."),
                    vehicle_part_types[part_id].name.c_str(), veh->name.c_str());
        g->u.practice (g->turn, "mechanics", vehicle_part_types[part_id].difficulty * 5 + 20);
        break;
    case 'r':
        if (veh->parts[vehicle_part].hp <= 0) {
            veh->break_part_into_pieces(vehicle_part, g->u.posx, g->u.posy);
            used_item = consume_vpart_item (g, veh->parts[vehicle_part].id);
            veh->parts[vehicle_part].bigness = used_item.bigness;
            tools.push_back(component("wrench", -1));
            g->consume_tools(&g->u, tools, true);
            tools.clear();
            dd = 0;
            veh->insides_dirty = true;
        }
        tools.push_back(component("welder", welder_charges));
        tools.push_back(component("welder_crude", welder_crude_charges));
        tools.push_back(component("duct_tape", DUCT_TAPE_USED));
        tools.push_back(component("toolset", welder_charges / 20));
        g->consume_tools(&g->u, tools, true);
        veh->parts[vehicle_part].hp = veh->part_info(vehicle_part).durability;
        g->add_msg (_("You repair the %s's %s."),
                    veh->name.c_str(), veh->part_info(vehicle_part).name.c_str());
        g->u.practice (g->turn, "mechanics", (veh->part_info(vehicle_part).difficulty + dd) * 5 + 20);
        break;
    case 'f':
        if (!g->pl_refill_vehicle(*veh, vehicle_part, true)) {
            debugmsg ("complete_vehicle refill broken");
        }
        g->pl_refill_vehicle(*veh, vehicle_part);
        break;
    case 'o':
        // Dump contents of part at player's feet, if any.
        for (int i = 0; i < veh->parts[vehicle_part].items.size(); i++) {
            g->m.add_item_or_charges (g->u.posx, g->u.posy, veh->parts[vehicle_part].items[i]);
        }
        veh->parts[vehicle_part].items.clear();

        broken = veh->parts[vehicle_part].hp <= 0;
        if (!broken) {
            used_item = veh->item_from_part( vehicle_part );
            // Transfer fuel back to tank
            if (used_item.typeId() == "metal_tank") {
                ammotype desired_liquid = veh->part_info(vehicle_part).fuel_type;
                item liquid( itypes[default_ammo(desired_liquid)], g->turn );

                liquid.charges = veh->parts[vehicle_part].amount;
                veh->parts[vehicle_part].amount = 0;

                used_item.put_in(liquid);
            }
            g->m.add_item_or_charges(g->u.posx, g->u.posy, used_item);
            if(type != SEL_JACK) { // Changing tires won't make you a car mechanic
                g->u.practice (g->turn, "mechanics", 2 * 5 + 20);
            }
        } else {
            veh->break_part_into_pieces(vehicle_part, g->u.posx, g->u.posy);
        }
        if (veh->parts.size() < 2) {
            g->add_msg (_("You completely dismantle the %s."), veh->name.c_str());
            g->u.activity.type = ACT_NULL;
            g->m.destroy_vehicle (veh);
        } else {
            if (broken) {
                g->add_msg(_("You remove the broken %s from the %s."),
                           veh->part_info(vehicle_part).name.c_str(),
                           veh->name.c_str());
            } else {
                g->add_msg(_("You remove the %s from the %s."),
                           veh->part_info(vehicle_part).name.c_str(),
                           veh->name.c_str());
            }
            veh->remove_part (vehicle_part);
        }
        break;
    case 's':
        g->u.siphon( g, veh, "gasoline" );
        break;
    case 'c':
        parts = veh->parts_at_relative( dx, dy );
        if( parts.size() ) {
            item removed_wheel;
            replaced_wheel = veh->part_with_feature( parts[0], "WHEEL", false );
            if( replaced_wheel == -1 ) {
                debugmsg( "no wheel to remove when changing wheels." );
                return;
            }
            broken = veh->parts[replaced_wheel].hp <= 0;
            removed_wheel = veh->item_from_part( replaced_wheel );
            veh->remove_part( replaced_wheel );
            g->add_msg( _("You replace one of the %s's tires with a %s."),
                        veh->name.c_str(), vehicle_part_types[part_id].name.c_str() );
            partnum = veh->install_part( dx, dy, part_id );
            if( partnum < 0 ) {
                debugmsg ("complete_vehicle tire change fails dx=%d dy=%d id=%d", dx, dy, part_id.c_str());
            }
            used_item = consume_vpart_item( g, part_id );
            veh->get_part_properties_from_item( g, partnum, used_item ); //transfer damage, etc.
            // Place the removed wheel on the map last so consume_vpart_item() doesn't pick it.
            if ( !broken ) {
                g->m.add_item_or_charges( g->u.posx, g->u.posy, removed_wheel );
            }
        }
        break;
    case 'd':
        g->u.siphon( g, veh, "water" );
        break;
    }
}
Exemple #13
0
bool game::dump_stats( const std::string& what, dump_mode mode, const std::vector<std::string> &opts )
{
    try {
        load_core_data();
        load_packs( _( "Loading content packs" ), { "dda" } );
        DynamicDataLoader::get_instance().finalize_loaded_data();
    } catch( const std::exception &err ) {
        std::cerr << "Error loading data from json: " << err.what() << std::endl;
        return false;
    }

    std::vector<std::string> header;
    std::vector<std::vector<std::string>> rows;

    int scol = 0; // sorting column

    std::map<std::string, standard_npc> test_npcs;
    test_npcs[ "S1" ] = standard_npc( "S1", { "gloves_survivor", "mask_lsurvivor" }, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ );
    test_npcs[ "S2" ] = standard_npc( "S2", { "gloves_fingerless", "sunglasses" }, 4, 8, 8, 8, 10 /* PER 10 */ );
    test_npcs[ "S3" ] = standard_npc( "S3", { "gloves_plate", "helmet_plate" },  4, 10, 8, 8, 8 /* STAT 10 */ );
    test_npcs[ "S4" ] = standard_npc( "S4", {}, 0, 8, 10, 8, 10 /* DEX 10, PER 10 */ );
    test_npcs[ "S5" ] = standard_npc( "S5", {}, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ );
    test_npcs[ "S6" ] = standard_npc( "S6", { "gloves_hsurvivor", "mask_hsurvivor" }, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ );

    std::map<std::string, item> test_items;
    test_items[ "G1" ] = item( "glock_19" ).ammo_set( "9mm" );
    test_items[ "G2" ] = item( "hk_mp5" ).ammo_set( "9mm" );
    test_items[ "G3" ] = item( "ar15" ).ammo_set( "223" );
    test_items[ "G4" ] = item( "remington_700" ).ammo_set( "270" );
    test_items[ "G4" ].emplace_back( "rifle_scope" );

    if( what == "AMMO" ) {
        header = {
            "Name", "Ammo", "Volume", "Weight", "Stack",
            "Range", "Dispersion", "Recoil", "Damage", "Pierce"
        };
        auto dump = [&rows]( const item& obj ) {
            // a common task is comparing ammo by type so ammo has multiple repeat the entry
            for( const auto &e : obj.type->ammo->type ) {
                std::vector<std::string> r;
                r.push_back( obj.tname( 1, false ) );
                r.push_back( e.str() );
                r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) );
                r.push_back( to_string( to_gram( obj.weight() ) ) );
                r.push_back( to_string( obj.type->stack_size ) );
                r.push_back( to_string( obj.type->ammo->range ) );
                r.push_back( to_string( obj.type->ammo->dispersion ) );
                r.push_back( to_string( obj.type->ammo->recoil ) );
                r.push_back( to_string( obj.type->ammo->damage ) );
                r.push_back( to_string( obj.type->ammo->pierce ) );
                rows.push_back( r );
            }
        };
        for( const itype *e : item_controller->all() ) {
            if( e->ammo ) {
                dump( item( e, calendar::turn, item::solitary_tag {} ) );
            }
        }

    } else if( what == "ARMOR" ) {
        header = {
            "Name", "Encumber (fit)", "Warmth", "Weight", "Storage", "Coverage", "Bash", "Cut", "Acid", "Fire"
        };
        auto dump = [&rows]( const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( 1, false ) );
            r.push_back( to_string( obj.get_encumber() ) );
            r.push_back( to_string( obj.get_warmth() ) );
            r.push_back( to_string( to_gram( obj.weight() ) ) );
            r.push_back( to_string( obj.get_storage() / units::legacy_volume_factor ) );
            r.push_back( to_string( obj.get_coverage() ) );
            r.push_back( to_string( obj.bash_resist() ) );
            r.push_back( to_string( obj.cut_resist() ) );
            r.push_back( to_string( obj.acid_resist() ) );
            r.push_back( to_string( obj.fire_resist() ) );
            rows.push_back( r );
        };

        body_part bp = opts.empty() ? num_bp : get_body_part_token( opts.front() );

        for( const itype *e : item_controller->all() ) {
            if( e->armor ) {
                item obj( e );
                if( bp == num_bp || obj.covers( bp ) ) {
                    if( obj.has_flag( "VARSIZE" ) ) {
                        obj.item_tags.insert( "FIT" );
                    }
                    dump( obj );
                }
            }
        }

    } else if( what == "EDIBLE" ) {
        header = {
            "Name", "Volume", "Weight", "Stack", "Calories", "Quench", "Healthy"
        };
        for( const auto& v : vitamin::all() ) {
             header.push_back( v.second.name() );
        }
        auto dump = [&rows]( const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( false ) );
            r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) );
            r.push_back( to_string( to_gram( obj.weight() ) ) );
            r.push_back( to_string( obj.type->stack_size ) );
            r.push_back( to_string( obj.type->comestible->get_calories() ) );
            r.push_back( to_string( obj.type->comestible->quench ) );
            r.push_back( to_string( obj.type->comestible->healthy ) );
            auto vits = g->u.vitamins_from( obj );
            for( const auto& v : vitamin::all() ) {
                 r.push_back( to_string( vits[ v.first ] ) );
            }
            rows.push_back( r );
        };

        for( const itype *e : item_controller->all() ) {
            item food( e, calendar::turn, item::solitary_tag {} );

            if( food.is_food() && g->u.can_eat( food ) == EDIBLE ) {
                dump( food );
            }
        }

    } else if( what == "GUN" ) {
        header = {
            "Name", "Ammo", "Volume", "Weight", "Capacity",
            "Range", "Dispersion", "Effective recoil", "Damage", "Pierce",
            "Aim time", "Effective range", "Snapshot range", "Max range"
        };

        std::set<std::string> locations;
        for( const itype *e : item_controller->all() ) {
            if( e->gun ) {
                std::transform( e->gun->valid_mod_locations.begin(),
                                e->gun->valid_mod_locations.end(),
                                std::inserter( locations, locations.begin() ),
                                []( const std::pair<gunmod_location, int>& q ) { return q.first.name(); } );
            }
        }
        for( const auto &e : locations ) {
            header.push_back( e );
        }

        auto dump = [&rows,&locations]( const standard_npc &who, const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( 1, false ) );
            r.push_back( obj.ammo_type() ? obj.ammo_type().str() : "" );
            r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) );
            r.push_back( to_string( to_gram( obj.weight() ) ) );
            r.push_back( to_string( obj.ammo_capacity() ) );
            r.push_back( to_string( obj.gun_range() ) );
            r.push_back( to_string( obj.gun_dispersion() ) );
            r.push_back( to_string( obj.gun_recoil( who ) ) );
            r.push_back( to_string( obj.gun_damage() ) );
            r.push_back( to_string( obj.gun_pierce() ) );

            r.push_back( to_string( who.gun_engagement_moves( obj ) ) );

            for( const auto &e : locations ) {
                r.push_back( to_string( obj.type->gun->valid_mod_locations[ e ] ) );
            }
            rows.push_back( r );
        };
        for( const itype *e : item_controller->all() ) {
            if( e->gun ) {
                item gun( e );
                if( !gun.magazine_integral() ) {
                    gun.emplace_back( gun.magazine_default() );
                }
                gun.ammo_set( default_ammo( gun.ammo_type() ), gun.ammo_capacity() );

                dump( test_npcs[ "S1" ], gun );

                if( gun.type->gun->barrel_length > 0 ) {
                    gun.emplace_back( "barrel_small" );
                    dump( test_npcs[ "S1" ], gun );
                }
            }
        }

    } else if( what == "RECIPE" ) {

        // optionally filter recipes to include only those using specified skills
        recipe_subset dict;
        for( const auto &r : recipe_dict ) {
            if( opts.empty() || std::any_of( opts.begin(), opts.end(), [&r]( const std::string &s ) {
                if( r.second.skill_used == skill_id( s ) && r.second.difficulty > 0 ) {
                    return true;
                }
                auto iter = r.second.required_skills.find( skill_id( s ) );
                return iter != r.second.required_skills.end() && iter->second > 0;
            } ) ) {
                dict.include( &r.second );
            }
        }

        // only consider skills that are required by at least one recipe
        std::vector<Skill> sk;
        std::copy_if( Skill::skills.begin(), Skill::skills.end(), std::back_inserter( sk ), [&dict]( const Skill &s ) {
            return std::any_of( dict.begin(), dict.end(), [&s]( const recipe *r ) {
                return r->skill_used == s.ident() || r->required_skills.find( s.ident() ) != r->required_skills.end();
            } );
        } );

        header = { "Result" };

        for( const auto &e : sk ) {
            header.push_back( e.ident().str() );
        }

        for( const recipe *e : dict ) {
            std::vector<std::string> r;
            r.push_back( item::find_type( e->result )->nname( 1 ) );
            for( const auto &s : sk ) {
                if( e->skill_used == s.ident() ) {
                    r.push_back( to_string( e->difficulty ) );
                } else {
                    auto iter = e->required_skills.find( s.ident() );
                    r.push_back( to_string( iter != e->required_skills.end() ? iter->second : 0 ) );
                }
            }
            rows.push_back( r );
        }

    } else if( what == "VEHICLE" ) {
        header = {
            "Name", "Weight (empty)", "Weight (fueled)",
            "Max velocity (mph)", "Safe velocity (mph)", "Acceleration (mph/turn)",
            "Mass coeff %", "Aerodynamics coeff %", "Friction coeff %",
            "Traction coeff % (grass)"
        };
        auto dump = [&rows]( const vproto_id& obj ) {
            auto veh_empty = vehicle( obj, 0, 0 );
            auto veh_fueled = vehicle( obj, 100, 0 );

            std::vector<std::string> r;
            r.push_back( veh_empty.name );
            r.push_back( to_string( to_kilogram( veh_empty.total_mass() ) ) );
            r.push_back( to_string( to_kilogram( veh_fueled.total_mass() ) ) );
            r.push_back( to_string( veh_fueled.max_velocity() / 100 ) );
            r.push_back( to_string( veh_fueled.safe_velocity() / 100 ) );
            r.push_back( to_string( veh_fueled.acceleration() / 100 ) );
            r.push_back( to_string( (int)( 100 * veh_fueled.k_mass() ) ) );
            r.push_back( to_string( (int)( 100 * veh_fueled.k_aerodynamics() ) ) );
            r.push_back( to_string( (int)( 100 * veh_fueled.k_friction() ) ) );
            r.push_back( to_string( (int)( 100 * veh_fueled.k_traction( veh_fueled.wheel_area( false ) / 2.0f ) ) ) );
            rows.push_back( r );
        };
        for( auto& e : vehicle_prototype::get_all() ) {
            dump( e );
        }

    } else if( what == "VPART" ) {
        header = {
            "Name", "Location", "Weight", "Size"
        };
        auto dump = [&rows]( const vpart_info &obj ) {
            std::vector<std::string> r;
            r.push_back( obj.name() );
            r.push_back( obj.location );
            r.push_back( to_string( int( ceil( to_gram( item( obj.item ).weight() ) / 1000.0 ) ) ) );
            r.push_back( to_string( obj.size / units::legacy_volume_factor ) );
            rows.push_back( r );
        };
        for( const auto &e : vpart_info::all() ) {
            dump( e.second );
        }

    } else if( what == "EXPLOSIVE" ) {
        header = {
            // @todo Should display more useful data: shrapnel damage, safe range
            "Name", "Power", "Power at 5 tiles", "Power halves at", "Shrapnel count", "Shrapnel mass"
        };

        auto dump = [&rows]( const std::string &name, const explosion_data &ex ) {
            std::vector<std::string> r;
            r.push_back( name );
            r.push_back( to_string( ex.power ) );
            r.push_back( string_format( "%.1f", ex.power_at_range( 5.0f ) ) );
            r.push_back( string_format( "%.1f", ex.expected_range( 0.5f ) ) );
            r.push_back( to_string( ex.shrapnel.count ) );
            r.push_back( to_string( ex.shrapnel.mass ) );
            rows.push_back( r );
        };
        for( const itype *e : item_controller->all() ) {
            const auto use = e->get_use( "explosion" );
            if( use != nullptr && use->get_actor_ptr() != nullptr ) {
                const auto actor = dynamic_cast<const explosion_iuse *>( use->get_actor_ptr() );
                if( actor != nullptr ) {
                    dump( e->nname( 1 ), actor->explosion );
                }
            }

            auto c_ex = dynamic_cast<const explosion_iuse *>( e->countdown_action.get_actor_ptr() );
            if( c_ex != nullptr ) {
                dump( e->nname( 1 ), c_ex->explosion );
            }
        }

    } else {
        std::cerr << "unknown argument: " << what << std::endl;
        return false;
    }

    rows.erase( std::remove_if( rows.begin(), rows.end(), []( const std::vector<std::string>& e ) {
        return e.empty();
    } ), rows.end() );

    if( scol >= 0 ) {
        std::sort( rows.begin(), rows.end(), [&scol]( const std::vector<std::string>& lhs, const std::vector<std::string>& rhs ) {
            return lhs[ scol ] < rhs[ scol ];
        } );
    }

    rows.erase( std::unique( rows.begin(), rows.end() ), rows.end() );

    switch( mode ) {
        case dump_mode::TSV:
            rows.insert( rows.begin(), header );
            for( const auto& r : rows ) {
                std::copy( r.begin(), r.end() - 1, std::ostream_iterator<std::string>( std::cout, "\t" ) );
                std::cout << r.back() << "\n";
            }
            break;

        case dump_mode::HTML:
            std::cout << "<table>";

            std::cout << "<thead>";
            std::cout << "<tr>";
            for( const auto& col : header ) {
                std::cout << "<th>" << col << "</th>";
            }
            std::cout << "</tr>";
            std::cout << "</thead>";

            std::cout << "<tdata>";
            for( const auto& r : rows ) {
                std::cout << "<tr>";
                for( const auto& col : r ) {
                    std::cout << "<td>" << col << "</td>";
                }
                std::cout << "</tr>";
            }
            std::cout << "</tdata>";

            std::cout << "</table>";
            break;
    }

    return true;
}
Exemple #14
0
// Handles interactions with a vehicle in the examine menu.
// Returns the part number that wil accept items if any, or -1 to indicate no cargo part.
// Returns -2 if a special interaction was performed and the menu should exit.
int Pickup::interact_with_vehicle( vehicle *veh, int posx, int posy, int veh_root_part )
{
    bool from_vehicle = false;

    int k_part = 0;
    int wtr_part = 0;
    int w_part = 0;
    int craft_part = 0;
    int cargo_part = 0;
    int chempart = 0;
    int ctrl_part = 0;
    std::vector<std::string> menu_items;
    std::vector<uimenu_entry> options_message;

    std::vector<item> here_ground = g->m.i_at(posx, posy);
    if( veh ) {
        k_part = veh->part_with_feature(veh_root_part, "KITCHEN");
        wtr_part = veh->part_with_feature(veh_root_part, "FAUCET");
        w_part = veh->part_with_feature(veh_root_part, "WELDRIG");
        craft_part = veh->part_with_feature(veh_root_part, "CRAFTRIG");
        chempart = veh->part_with_feature(veh_root_part, "CHEMLAB");
        cargo_part = veh->part_with_feature(veh_root_part, "CARGO", false);
        ctrl_part = veh->part_with_feature(veh_root_part, "CONTROLS");
        from_vehicle = veh && cargo_part >= 0 && !veh->parts[cargo_part].items.empty();

        menu_items.push_back(_("Examine vehicle"));
        options_message.push_back(uimenu_entry(_("Examine vehicle"), 'e'));
        if (ctrl_part >= 0) {
            menu_items.push_back(_("Control vehicle"));
            options_message.push_back(uimenu_entry(_("Control vehicle"), 'v'));
        }

        if( from_vehicle ) {
            menu_items.push_back(_("Get items"));
            options_message.push_back(uimenu_entry(_("Get items"), 'g'));
        }

        if(!here_ground.empty()) {
            menu_items.push_back(_("Get items on the ground"));
            options_message.push_back(uimenu_entry(_("Get items on the ground"), 'i'));
        }

        if((k_part >= 0 || chempart >= 0) && veh->fuel_left("battery") > 0) {
            menu_items.push_back(_("Use the hotplate"));
            options_message.push_back(uimenu_entry(_("Use the hotplate"), 'h'));
        }
        if((k_part >= 0 || wtr_part >= 0) && veh->fuel_left("water") > 0) {
            menu_items.push_back(_("Fill a container with water"));
            options_message.push_back(uimenu_entry(_("Fill a container with water"), 'c'));

            menu_items.push_back(_("Have a drink"));
            options_message.push_back(uimenu_entry(_("Have a drink"), 'd'));
        }
        if(w_part >= 0 && veh->fuel_left("battery") > 0) {
            menu_items.push_back(_("Use the welding rig?"));
            options_message.push_back(uimenu_entry(_("Use the welding rig?"), 'w'));
        }
        if(craft_part >= 0 && veh->fuel_left("battery") > 0) {
            menu_items.push_back(_("Use the water purifier?"));
            options_message.push_back(uimenu_entry(_("Use the water purifier?"), 'p'));
        }

        int choice;
        if( menu_items.size() == 1 ) {
            choice = 0;
        } else {
            uimenu selectmenu;
            selectmenu.return_invalid = true;
            selectmenu.text = _("Select an action");
            selectmenu.entries = options_message;
            selectmenu.selected = 0;
            selectmenu.query();
            choice = selectmenu.ret;
        }

        if(choice < 0) {
            return -2;
        }
        if(menu_items[choice] == _("Use the hotplate")) {
            //Will be -1 if no battery at all
            item tmp_hotplate( "hotplate", 0 );
            // Drain a ton of power
            tmp_hotplate.charges = veh->drain( "battery", 100 );
            if( tmp_hotplate.is_tool() ) {
                it_tool *tmptool = dynamic_cast<it_tool *>((&tmp_hotplate)->type);
                if ( tmp_hotplate.charges >= tmptool->charges_per_use ) {
                    tmptool->invoke(&g->u, &tmp_hotplate, false);
                    tmp_hotplate.charges -= tmptool->charges_per_use;
                    veh->refill( "battery", tmp_hotplate.charges );
                }
            }
            return -2;
        }

        if(menu_items[choice] == _("Fill a container with water")) {
            int amt = veh->drain("water", veh->fuel_left("water"));
            item fill_water( default_ammo("water"), calendar::turn );
            fill_water.charges = amt;
            int back = g->move_liquid(fill_water);
            if (back >= 0) {
                veh->refill("water", back);
            } else {
                veh->refill("water", amt);
            }
            return -2;
        }

        if(menu_items[choice] == _("Have a drink")) {
            veh->drain("water", 1);
            item water( "water_clean", 0 );
            g->u.eat(&water, dynamic_cast<it_comest *>(water.type));
            g->u.moves -= 250;
            return -2;
        }

        if(menu_items[choice] == _("Use the welding rig?")) {
            //Will be -1 if no battery at all
            item tmp_welder( "welder", 0 );
            // Drain a ton of power
            tmp_welder.charges = veh->drain( "battery", 1000 );
            if( tmp_welder.is_tool() ) {
                it_tool *tmptool = dynamic_cast<it_tool *>((&tmp_welder)->type);
                if ( tmp_welder.charges >= tmptool->charges_per_use ) {
                    tmptool->invoke( &g->u, &tmp_welder, false );
                    tmp_welder.charges -= tmptool->charges_per_use;
                    veh->refill( "battery", tmp_welder.charges );
                }
            }
            return -2;
        }

        if(menu_items[choice] == _("Use the water purifier?")) {
            //Will be -1 if no battery at all
            item tmp_purifier( "water_purifier", 0 );
            // Drain a ton of power
            tmp_purifier.charges = veh->drain( "battery", 100 );
            if( tmp_purifier.is_tool() ) {
                it_tool *tmptool = dynamic_cast<it_tool *>((&tmp_purifier)->type);
                if ( tmp_purifier.charges >= tmptool->charges_per_use ) {
                    tmptool->invoke( &g->u, &tmp_purifier, false );
                    tmp_purifier.charges -= tmptool->charges_per_use;
                    veh->refill( "battery", tmp_purifier.charges );
                }
            }
            return -2;
        }

        if(menu_items[choice] == _("Control vehicle")) {
            veh->use_controls();
            return -2;
        }

        if(menu_items[choice] == _("Examine vehicle")) {
            g->exam_vehicle(*veh, posx, posy);
            return -2;
        }

        if(menu_items[choice] == _("Get items on the ground")) {
            from_vehicle = false;
        }
    }
    return from_vehicle ? cargo_part : -1;
}
Exemple #15
0
void game::dump_stats( const std::string& what, dump_mode mode )
{
    load_core_data();
    DynamicDataLoader::get_instance().finalize_loaded_data();

    std::vector<std::string> header;
    std::vector<std::vector<std::string>> rows;

    if( what == "AMMO" ) {
        header = {
            "Name", "Ammo", "Volume", "Weight", "Stack",
            "Range", "Dispersion", "Recoil", "Damage", "Pierce"
        };
        auto dump = [&rows]( const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( false ) );
            r.push_back( obj.type->ammo->type );
            r.push_back( std::to_string( obj.volume() ) );
            r.push_back( std::to_string( obj.weight() ) );
            r.push_back( std::to_string( obj.type->stack_size ) );
            r.push_back( std::to_string( obj.type->ammo->range ) );
            r.push_back( std::to_string( obj.type->ammo->dispersion ) );
            r.push_back( std::to_string( obj.type->ammo->recoil ) );
            r.push_back( std::to_string( obj.type->ammo->damage ) );
            r.push_back( std::to_string( obj.type->ammo->pierce ) );
            rows.push_back( r );
        };
        for( auto& e : item_controller->get_all_itypes() ) {
            if( e.second->ammo ) {
                dump( item( e.first, calendar::turn, item::solitary_tag {} ) );
            }
        }

    } else if( what == "EDIBLE" ) {
        header = {
            "Name", "Volume", "Weight", "Stack", "Calories", "Quench", "Healthy"
        };
        for( const auto& v : vitamin::all() ) {
             header.push_back( v.second.name() );
        }
        auto dump = [&rows]( const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( false ) );
            r.push_back( std::to_string( obj.volume() ) );
            r.push_back( std::to_string( obj.weight() ) );
            r.push_back( std::to_string( obj.type->stack_size ) );
            r.push_back( std::to_string( obj.type->comestible->get_calories() ) );
            r.push_back( std::to_string( obj.type->comestible->quench ) );
            r.push_back( std::to_string( obj.type->comestible->healthy ) );
            auto vits = g->u.vitamins_from( obj );
            for( const auto& v : vitamin::all() ) {
                 r.push_back( std::to_string( vits[ v.first ] ) );
            }
            rows.push_back( r );
        };
        for( auto& e : item_controller->get_all_itypes() ) {
            if( e.second->comestible &&
                ( e.second->comestible->comesttype == "FOOD" ||
                  e.second->comestible->comesttype == "DRINK" ) ) {

                item food( e.first, calendar::turn, item::solitary_tag {} );
                if( g->u.can_eat( food, false, true ) == EDIBLE ) {
                    dump( food );
                }
            }
        }

    } else if( what == "GUN" ) {
        header = {
            "Name", "Ammo", "Volume", "Weight", "Capacity",
            "Range", "Dispersion", "Recoil", "Damage", "Pierce"
        };
        std::set<std::string> locations;
        for( const auto& e : item_controller->get_all_itypes() ) {
            if( e.second->gun ) {
                std::transform( e.second->gun->valid_mod_locations.begin(),
                                e.second->gun->valid_mod_locations.end(),
                                std::inserter( locations, locations.begin() ),
                                []( const std::pair<std::string, int>& e ) { return e.first; } );
            }
        }
        for( const auto &e : locations ) {
            header.push_back( e );
        }

        auto dump = [&rows,&locations]( const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( false ) );
            r.push_back( obj.ammo_type() != "NULL" ? obj.ammo_type() : "" );
            r.push_back( std::to_string( obj.volume() ) );
            r.push_back( std::to_string( obj.weight() ) );
            r.push_back( std::to_string( obj.ammo_capacity() ) );
            r.push_back( std::to_string( obj.gun_range() ) );
            r.push_back( std::to_string( obj.gun_dispersion() ) );
            r.push_back( std::to_string( obj.gun_recoil() ) );
            r.push_back( std::to_string( obj.gun_damage() ) );
            r.push_back( std::to_string( obj.gun_pierce() ) );
            for( const auto &e : locations ) {
                r.push_back( std::to_string( obj.type->gun->valid_mod_locations[ e ] ) );
            }
            rows.push_back( r );
        };
        for( const auto& e : item_controller->get_all_itypes() ) {
            if( e.second->gun ) {
                item gun( e.first );
                if( gun.is_reloadable() ) {
                    gun.ammo_set( default_ammo( gun.ammo_type() ), gun.ammo_capacity() );
                }
                dump( gun );

                if( gun.type->gun->barrel_length > 0 ) {
                    gun.emplace_back( "barrel_small" );
                    dump( gun );
                }
            }
        }

    } else if( what == "VEHICLE" ) {
        header = {
            "Name", "Weight (empty)", "Weight (fueled)"
        };
        auto dump = [&rows]( const vproto_id& obj ) {
            auto veh_empty = vehicle( obj, 0, 0 );
            auto veh_fueled = vehicle( obj, 100, 0 );

            std::vector<std::string> r;
            r.push_back( veh_empty.name );
            r.push_back( std::to_string( veh_empty.total_mass() ) );
            r.push_back( std::to_string( veh_fueled.total_mass() ) );
            rows.push_back( r );
        };
        for( auto& e : vehicle_prototype::get_all() ) {
            dump( e );
        }

    } else if( what == "VPART" ) {
        header = {
            "Name", "Location", "Weight", "Size"
        };
        auto dump = [&rows]( const vpart_info *obj ) {
            std::vector<std::string> r;
            r.push_back( obj->name() );
            r.push_back( obj->location );
            r.push_back( std::to_string( int( ceil( item( obj->item ).weight() / 1000.0 ) ) ) );
            r.push_back( std::to_string( obj->size ) );
            rows.push_back( r );
        };
        for( const auto e : vpart_info::get_all() ) {
            dump( e );
        }
    }

    rows.erase( std::remove_if( rows.begin(), rows.end(), []( const std::vector<std::string>& e ) {
        return e.empty();
    } ), rows.end() );

    std::sort( rows.begin(), rows.end(), []( const std::vector<std::string>& lhs, const std::vector<std::string>& rhs ) {
        return lhs[ 0 ] < rhs[ 0 ];
    } );

    rows.erase( std::unique( rows.begin(), rows.end() ), rows.end() );

    switch( mode ) {
        case dump_mode::TSV:
            rows.insert( rows.begin(), header );
            for( const auto& r : rows ) {
                std::copy( r.begin(), r.end() - 1, std::ostream_iterator<std::string>( std::cout, "\t" ) );
                std::cout << r.back() << "\n";
            }
            break;

        case dump_mode::HTML:
            std::cout << "<table>";

            std::cout << "<thead>";
            std::cout << "<tr>";
            for( const auto& col : header ) {
                std::cout << "<th>" << col << "</th>";
            }
            std::cout << "</tr>";
            std::cout << "</thead>";

            std::cout << "<tdata>";
            for( const auto& r : rows ) {
                std::cout << "<tr>";
                for( const auto& col : r ) {
                    std::cout << "<td>" << col << "</td>";
                }
                std::cout << "</tr>";
            }
            std::cout << "</tdata>";

            std::cout << "</table>";
            break;
    }
}