Skip to content

Commit

Permalink
Migrate ammotypes of guns, magazines, and mods (CleverRaven#37746)
Browse files Browse the repository at this point in the history
* Migrate ammotypes of guns, magazines, and mods

* Migrate magazine compatibility

* Fix seemingly erroneous json entries
  • Loading branch information
ifreund authored Feb 19, 2020
1 parent 7c4d947 commit f98c67d
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 11 deletions.
2 changes: 1 addition & 1 deletion data/json/items/gun/9mm.json
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@
"material": [ "steel", "plastic" ],
"symbol": "(",
"color": "dark_gray",
"ammo": "9mm",
"ammo": [ "9mm", "460" ],
"range": 1,
"dispersion": 340,
"durability": 9,
Expand Down
3 changes: 2 additions & 1 deletion data/mods/Generic_Guns/firearms/pistol_tiny.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"name": "plinker carbine",
"ammo": "ammo_pistol_tiny",
"description": "With near non-existent recoil and inexpensive ammunition, rifles like this one are popular introductory firearms. It has a built in magazine, capable of holding an impressive amount of its small cartridges. You could take small game with this, but anything bigger might not even notice.",
"clip_size": 19
"clip_size": 19,
"magazines": [ ]
},
{
"id": "pistol_tiny_target",
Expand Down
3 changes: 2 additions & 1 deletion data/mods/Generic_Guns/firearms/rifle.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"name": "pipe rifle",
"ammo": "ammo_rifle",
"description": "A crude longarm chambered in standard rifle ammunition, reinforced near the chamber. It holds a single a round and has a crude assembly to fire it. There's no extractor, so it might be slow to reload, and its construction makes for poor reliability and longevity.",
"clip_size": 1
"clip_size": 1,
"magazines": [ ]
},
{
"id": "rifle_pipe_carbine",
Expand Down
7 changes: 2 additions & 5 deletions data/mods/Generic_Guns/magazines/gg_magazines_migration.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
"hptcf380mag_10rd",
"taurus_spectrum_mag",
"m1911mag_10rd_38super",
"m9mag",
"makarovmag",
"glock40mag",
"sig40mag",
"bhp40mag",
Expand Down Expand Up @@ -57,11 +59,6 @@
"type": "MIGRATION",
"replace": "pistol_magnum_mag"
},
{
"id": [ "m9mag", "makarovmag" ],
"type": "MIGRATION",
"replace": "pistol_medium"
},
{
"id": [
"20x66_40_mag",
Expand Down
129 changes: 126 additions & 3 deletions src/item_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,11 +247,107 @@ void Item_factory::finalize_pre( itype &obj )
obj.ammo->special_cookoff = false;
}
}
// for magazines ensure default_ammo is set
if( obj.magazine && obj.magazine->default_ammo == "NULL" ) {
obj.magazine->default_ammo = ammotype( *obj.magazine->type.begin() )->default_ammotype();

// Helper for ammo migration in following sections
auto migrate_ammo_set = [&]( std::set<ammotype> &ammoset ) {
for( auto ammo_type_it = ammoset.begin(); ammo_type_it != ammoset.end(); ) {
auto maybe_migrated = migrated_ammo.find( ammo_type_it->obj().default_ammotype() );
if( maybe_migrated != migrated_ammo.end() ) {
ammo_type_it = ammoset.erase( ammo_type_it );
ammoset.insert( ammoset.begin(), maybe_migrated->second );
} else {
++ammo_type_it;
}
}
};

if( obj.magazine ) {
// ensure default_ammo is set
if( obj.magazine->default_ammo == "NULL" ) {
obj.magazine->default_ammo = ammotype( *obj.magazine->type.begin() )->default_ammotype();
}

// If the magazine has ammo types for which the default ammo has been migrated, we need to
// replace those ammo types with that of the migrated ammo
migrate_ammo_set( obj.magazine->type );

// ensure default_ammo is migrated if need be
auto maybe_migrated = migrated_ammo.find( obj.magazine->default_ammo );
if( maybe_migrated != migrated_ammo.end() ) {
obj.magazine->default_ammo = maybe_migrated->second.obj().default_ammotype();
}
}

// Migrate compataible magazines
for( auto kv : obj.magazines ) {
for( auto mag_it = kv.second.begin(); mag_it != kv.second.end(); ) {
auto maybe_migrated = migrated_magazines.find( *mag_it );
if( maybe_migrated != migrated_magazines.end() ) {
mag_it = kv.second.erase( mag_it );
kv.second.insert( kv.second.begin(), maybe_migrated->second );
} else {
++mag_it;
}
}
}

// Migrate default magazines
for( auto kv : obj.magazine_default ) {
auto maybe_migrated = migrated_magazines.find( kv.second );
if( maybe_migrated != migrated_magazines.end() ) {
kv.second = maybe_migrated->second;
}
}

if( obj.mod ) {
// Migrate acceptable ammo and ammo modifiers
migrate_ammo_set( obj.mod->acceptable_ammo );
migrate_ammo_set( obj.mod->ammo_modifier );

for( auto kv = obj.mod->magazine_adaptor.begin(); kv != obj.mod->magazine_adaptor.end(); ) {
auto maybe_migrated = migrated_ammo.find( kv->first.obj().default_ammotype() );
if( maybe_migrated != migrated_ammo.end() ) {
for( const itype_id &compatible_mag : kv->second ) {
obj.mod->magazine_adaptor[maybe_migrated->second].insert( compatible_mag );
}
kv = obj.mod->magazine_adaptor.erase( kv );
} else {
++kv;
}
}
}

if( obj.gun ) {
// If the gun has ammo types for which the default ammo has been migrated, we need to
// replace those ammo types with that of the migrated ammo
for( auto ammo_type_it = obj.gun->ammo.begin(); ammo_type_it != obj.gun->ammo.end(); ) {
auto maybe_migrated = migrated_ammo.find( ammo_type_it->obj().default_ammotype() );
if( maybe_migrated != migrated_ammo.end() ) {
const ammotype old_ammo = *ammo_type_it;
// Remove the old ammotype add the migrated version
ammo_type_it = obj.gun->ammo.erase( ammo_type_it );
const ammotype &new_ammo = maybe_migrated->second;
obj.gun->ammo.insert( obj.gun->ammo.begin(), new_ammo );
// Migrate the compatible magazines
auto old_mag_it = obj.magazines.find( old_ammo );
if( old_mag_it != obj.magazines.end() ) {
for( const itype_id &old_mag : old_mag_it->second ) {
obj.magazines[new_ammo].insert( old_mag );
}
obj.magazines.erase( old_ammo );
}
// And the default magazines for each magazine type
auto old_default_mag_it = obj.magazine_default.find( old_ammo );
if( old_default_mag_it != obj.magazine_default.end() ) {
const itype_id &old_default_mag = old_default_mag_it->second;
obj.magazine_default[new_ammo] = old_default_mag;
obj.magazine_default.erase( old_ammo );
}
} else {
++ammo_type_it;
}
}

handle_legacy_ranged( *obj.gun );
// TODO: add explicit action field to gun definitions
const auto defmode_name = [&]() {
Expand Down Expand Up @@ -519,6 +615,33 @@ void Item_factory::finalize_item_blacklist()
recipe_dictionary::delete_if( [&migrate]( const recipe & r ) {
return r.result() == migrate.first;
} );

// If the default ammo of an ammo_type gets migrated, we migrate all guns using that ammo
// type to the ammo type of whatever that default ammo was migrated to.
// To do that we need to store a map of ammo to the migration replacement thereof.
auto maybe_ammo = m_templates.find( migrate.first );
// If the itype_id is valid and the itype has ammo data
if( maybe_ammo != m_templates.end() && maybe_ammo->second.ammo ) {
auto replacement = m_templates.find( migrate.second.replace );
if( replacement->second.ammo ) {
migrated_ammo.emplace( std::make_pair( migrate.first, replacement->second.ammo->type ) );
} else {
debugmsg( "Replacement item %s for migrated ammo %s is not ammo.", migrate.second.replace,
migrate.first );
}
}

// migrate magazines as well
auto maybe_mag = m_templates.find( migrate.first );
if( maybe_mag != m_templates.end() && maybe_mag->second.magazine ) {
auto replacement = m_templates.find( migrate.second.replace );
if( replacement->second.magazine ) {
migrated_magazines.emplace( std::make_pair( migrate.first, migrate.second.replace ) );
} else {
debugmsg( "Replacement item %s for migrated magazine %s is not a magazine.", migrate.second.replace,
migrate.first );
}
}
}
for( vproto_id &vid : vehicle_prototype::get_all() ) {
vehicle_prototype &prototype = const_cast<vehicle_prototype &>( vid.obj() );
Expand Down
3 changes: 3 additions & 0 deletions src/item_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ class Item_factory
using GroupMap = std::map<Group_tag, std::unique_ptr<Item_spawn_data>>;
GroupMap m_template_groups;

std::unordered_map<itype_id, ammotype> migrated_ammo;
std::unordered_map<itype_id, itype_id> migrated_magazines;

/** Checks that ammo is listed in ammunition_type::name().
* At least one instance of this ammo type should be defined.
* If any of checks fails, prints a message to the msg stream.
Expand Down

0 comments on commit f98c67d

Please sign in to comment.