Skip to content

Commit

Permalink
Fix shotgun speedloader (#73043)
Browse files Browse the repository at this point in the history
* Use pocket_mods instead of magazine_adaptor.

* ammo_uses_speedloader_clip

* Fix the "unloaded" check of is_gunmod_compatible.

* Add "loaded" check to gunmod_remove.

* Speedloader chute modification

* chute needs modification before attaching

* speedloader chute

* Apply suggestions from code review

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Certain shotgun needs specific chute.

* speedloader chute

* remington_870 and mossberg_500 speedloader chutes

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
osuphobia and github-actions[bot] authored Apr 18, 2024
1 parent 3577b05 commit 041f8fa
Show file tree
Hide file tree
Showing 5 changed files with 291 additions and 16 deletions.
99 changes: 97 additions & 2 deletions data/json/items/gunmod/loading_port.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"id": "arredondo_chute",
"type": "GUNMOD",
"name": { "str": "speedloader chute" },
"description": "A metal ramp that is installed near a shotgun's feeding port to index speedloader tubes.",
"description": "A metal ramp that can be installed near a shotgun's feeding port to index speedloader tubes. Need modification before attaching.",
"weight": "135 g",
"volume": "149 ml",
"integral_volume": "149 ml",
Expand All @@ -16,7 +16,102 @@
"location": "loading port",
"mod_targets": [ "pistol", "shotgun" ],
"acceptable_ammo": [ "shot" ],
"magazine_adaptor": [ [ "shot", [ "shot_speedloader6", "shot_speedloader8" ] ] ],
"min_skills": [ [ "weapon", 2 ], [ "mechanics", 1 ] ]
},
{
"id": "arredondo_chute_benelli_sa",
"type": "GUNMOD",
"name": { "str": "speedloader chute, 4-round waterfowl shotgun" },
"description": "A metal ramp that is installed near a shotgun's feeding port to index speedloader tubes. This one is for 4-round waterfowl shotgun.",
"copy-from": "arredondo_chute",
"mod_targets": [ "benelli_sa" ],
"pocket_mods": [
{
"pocket_type": "MAGAZINE",
"rigid": true,
"ammo_restriction": { "shot": 4 },
"allowed_speedloaders": [ "shot_speedloader6", "shot_speedloader8" ]
}
]
},
{
"id": "arredondo_chute_remington_870_breacher",
"type": "GUNMOD",
"name": { "str": "speedloader chute, 4-round breaching shotgun" },
"description": "A metal ramp that is installed near a shotgun's feeding port to index speedloader tubes. This one is for 4-round breaching shotgun.",
"copy-from": "arredondo_chute",
"mod_targets": [ "remington_870_breacher" ],
"pocket_mods": [
{
"pocket_type": "MAGAZINE",
"rigid": true,
"ammo_restriction": { "shot": 4 },
"allowed_speedloaders": [ "shot_speedloader6", "shot_speedloader8" ]
}
]
},
{
"id": "arredondo_chute_remington_870",
"type": "GUNMOD",
"name": { "str": "speedloader chute, 5-round hunting shotgun" },
"description": "A metal ramp that is installed near a shotgun's feeding port to index speedloader tubes. This one is for 5-round hunting shotgun.",
"copy-from": "arredondo_chute",
"mod_targets": [ "remington_870" ],
"pocket_mods": [
{
"pocket_type": "MAGAZINE",
"rigid": true,
"ammo_restriction": { "shot": 5 },
"allowed_speedloaders": [ "shot_speedloader6", "shot_speedloader8" ]
}
]
},
{
"id": "arredondo_chute_mossberg_500",
"type": "GUNMOD",
"name": { "str": "speedloader chute, 6-round combat shotgun" },
"description": "A metal ramp that is installed near a shotgun's feeding port to index speedloader tubes. This one is for 6-round combat shotgun.",
"copy-from": "arredondo_chute",
"mod_targets": [ "mossberg_500" ],
"pocket_mods": [
{
"pocket_type": "MAGAZINE",
"rigid": true,
"ammo_restriction": { "shot": 6 },
"allowed_speedloaders": [ "shot_speedloader6", "shot_speedloader8" ]
}
]
},
{
"id": "arredondo_chute_mossberg_930",
"type": "GUNMOD",
"name": { "str": "speedloader chute, 8-round auto-loading shotgun" },
"description": "A metal ramp that is installed near a shotgun's feeding port to index speedloader tubes. This one is for 8-round auto-loading shotgun.",
"copy-from": "arredondo_chute",
"mod_targets": [ "mossberg_930" ],
"pocket_mods": [
{
"pocket_type": "MAGAZINE",
"rigid": true,
"ammo_restriction": { "shot": 8 },
"allowed_speedloaders": [ "shot_speedloader6", "shot_speedloader8" ]
}
]
},
{
"id": "arredondo_chute_mossberg_590",
"type": "GUNMOD",
"name": { "str": "speedloader chute, 9-round combat shotgun" },
"description": "A metal ramp that is installed near a shotgun's feeding port to index speedloader tubes. This one is for 9-round combat shotgun.",
"copy-from": "arredondo_chute",
"mod_targets": [ "mossberg_590" ],
"pocket_mods": [
{
"pocket_type": "MAGAZINE",
"rigid": true,
"ammo_restriction": { "shot": 9 },
"allowed_speedloaders": [ "shot_speedloader6", "shot_speedloader8" ]
}
]
}
]
162 changes: 161 additions & 1 deletion data/json/recipes/weapon/mods.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[
{
"result": "arredondo_chute",
"result": "arredondo_chute_benelli_sa",
"type": "recipe",
"activity_level": "LIGHT_EXERCISE",
"category": "CC_WEAPON",
Expand All @@ -14,6 +14,166 @@
"qualities": [ { "id": "HAMMER_FINE", "level": 1 }, { "id": "DRILL", "level": 1 }, { "id": "SAW_M_FINE", "level": 1 } ],
"components": [ [ [ "scrap", 4 ] ], [ [ "sheet_metal_small", 4 ] ] ]
},
{
"result": "arredondo_chute_remington_870_breacher",
"type": "recipe",
"activity_level": "LIGHT_EXERCISE",
"category": "CC_WEAPON",
"subcategory": "CSC_WEAPON_MODS",
"skill_used": "fabrication",
"difficulty": 1,
"skills_required": [ [ "gun", 2 ] ],
"time": "30 m",
"book_learn": [ [ "mag_guns", 4 ], [ "mag_pistol", 4 ], [ "mag_shotgun", 4 ], [ "mag_rifle", 4 ] ],
"using": [ [ "soldering_standard", 15 ] ],
"qualities": [ { "id": "HAMMER_FINE", "level": 1 }, { "id": "DRILL", "level": 1 }, { "id": "SAW_M_FINE", "level": 1 } ],
"components": [ [ [ "scrap", 4 ] ], [ [ "sheet_metal_small", 4 ] ] ]
},
{
"result": "arredondo_chute_remington_870",
"type": "recipe",
"activity_level": "LIGHT_EXERCISE",
"category": "CC_WEAPON",
"subcategory": "CSC_WEAPON_MODS",
"skill_used": "fabrication",
"difficulty": 1,
"skills_required": [ [ "gun", 2 ] ],
"time": "30 m",
"book_learn": [ [ "mag_guns", 4 ], [ "mag_pistol", 4 ], [ "mag_shotgun", 4 ], [ "mag_rifle", 4 ] ],
"using": [ [ "soldering_standard", 15 ] ],
"qualities": [ { "id": "HAMMER_FINE", "level": 1 }, { "id": "DRILL", "level": 1 }, { "id": "SAW_M_FINE", "level": 1 } ],
"components": [ [ [ "scrap", 4 ] ], [ [ "sheet_metal_small", 4 ] ] ]
},
{
"result": "arredondo_chute_mossberg_500",
"type": "recipe",
"activity_level": "LIGHT_EXERCISE",
"category": "CC_WEAPON",
"subcategory": "CSC_WEAPON_MODS",
"skill_used": "fabrication",
"difficulty": 1,
"skills_required": [ [ "gun", 2 ] ],
"time": "30 m",
"book_learn": [ [ "mag_guns", 4 ], [ "mag_pistol", 4 ], [ "mag_shotgun", 4 ], [ "mag_rifle", 4 ] ],
"using": [ [ "soldering_standard", 15 ] ],
"qualities": [ { "id": "HAMMER_FINE", "level": 1 }, { "id": "DRILL", "level": 1 }, { "id": "SAW_M_FINE", "level": 1 } ],
"components": [ [ [ "scrap", 4 ] ], [ [ "sheet_metal_small", 4 ] ] ]
},
{
"result": "arredondo_chute_mossberg_930",
"type": "recipe",
"activity_level": "LIGHT_EXERCISE",
"category": "CC_WEAPON",
"subcategory": "CSC_WEAPON_MODS",
"skill_used": "fabrication",
"difficulty": 1,
"skills_required": [ [ "gun", 2 ] ],
"time": "30 m",
"book_learn": [ [ "mag_guns", 4 ], [ "mag_pistol", 4 ], [ "mag_shotgun", 4 ], [ "mag_rifle", 4 ] ],
"using": [ [ "soldering_standard", 15 ] ],
"qualities": [ { "id": "HAMMER_FINE", "level": 1 }, { "id": "DRILL", "level": 1 }, { "id": "SAW_M_FINE", "level": 1 } ],
"components": [ [ [ "scrap", 4 ] ], [ [ "sheet_metal_small", 4 ] ] ]
},
{
"result": "arredondo_chute_mossberg_590",
"type": "recipe",
"activity_level": "LIGHT_EXERCISE",
"category": "CC_WEAPON",
"subcategory": "CSC_WEAPON_MODS",
"skill_used": "fabrication",
"difficulty": 1,
"skills_required": [ [ "gun", 2 ] ],
"time": "30 m",
"book_learn": [ [ "mag_guns", 4 ], [ "mag_pistol", 4 ], [ "mag_shotgun", 4 ], [ "mag_rifle", 4 ] ],
"using": [ [ "soldering_standard", 15 ] ],
"qualities": [ { "id": "HAMMER_FINE", "level": 1 }, { "id": "DRILL", "level": 1 }, { "id": "SAW_M_FINE", "level": 1 } ],
"components": [ [ [ "scrap", 4 ] ], [ [ "sheet_metal_small", 4 ] ] ]
},
{
"result": "arredondo_chute_benelli_sa",
"type": "recipe",
"//": "Remove these four simple recipes when obselete arredondo_chute.",
"id_suffix": "simple",
"activity_level": "LIGHT_EXERCISE",
"category": "CC_WEAPON",
"subcategory": "CSC_WEAPON_MODS",
"skill_used": "fabrication",
"difficulty": 1,
"skills_required": [ [ "gun", 2 ] ],
"time": "1 m",
"autolearn": true,
"components": [ [ [ "arredondo_chute", 1 ] ] ]
},
{
"result": "arredondo_chute_remington_870_breacher",
"type": "recipe",
"id_suffix": "simple",
"activity_level": "LIGHT_EXERCISE",
"category": "CC_WEAPON",
"subcategory": "CSC_WEAPON_MODS",
"skill_used": "fabrication",
"difficulty": 1,
"skills_required": [ [ "gun", 2 ] ],
"time": "1 m",
"autolearn": true,
"components": [ [ [ "arredondo_chute", 1 ] ] ]
},
{
"result": "arredondo_chute_remington_870",
"type": "recipe",
"id_suffix": "simple",
"activity_level": "LIGHT_EXERCISE",
"category": "CC_WEAPON",
"subcategory": "CSC_WEAPON_MODS",
"skill_used": "fabrication",
"difficulty": 1,
"skills_required": [ [ "gun", 2 ] ],
"time": "1 m",
"autolearn": true,
"components": [ [ [ "arredondo_chute", 1 ] ] ]
},
{
"result": "arredondo_chute_mossberg_500",
"type": "recipe",
"id_suffix": "simple",
"activity_level": "LIGHT_EXERCISE",
"category": "CC_WEAPON",
"subcategory": "CSC_WEAPON_MODS",
"skill_used": "fabrication",
"difficulty": 1,
"skills_required": [ [ "gun", 2 ] ],
"time": "1 m",
"autolearn": true,
"components": [ [ [ "arredondo_chute", 1 ] ] ]
},
{
"result": "arredondo_chute_mossberg_930",
"type": "recipe",
"id_suffix": "simple",
"activity_level": "LIGHT_EXERCISE",
"category": "CC_WEAPON",
"subcategory": "CSC_WEAPON_MODS",
"skill_used": "fabrication",
"difficulty": 1,
"skills_required": [ [ "gun", 2 ] ],
"time": "1 m",
"autolearn": true,
"components": [ [ [ "arredondo_chute", 1 ] ] ]
},
{
"result": "arredondo_chute_mossberg_590",
"type": "recipe",
"id_suffix": "simple",
"activity_level": "LIGHT_EXERCISE",
"category": "CC_WEAPON",
"subcategory": "CSC_WEAPON_MODS",
"skill_used": "fabrication",
"difficulty": 1,
"skills_required": [ [ "gun", 2 ] ],
"time": "1 m",
"autolearn": true,
"components": [ [ [ "arredondo_chute", 1 ] ] ]
},
{
"result": "bipod_mod",
"type": "recipe",
Expand Down
4 changes: 3 additions & 1 deletion src/activity_actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4789,6 +4789,7 @@ void reload_activity_actor::finish( player_activity &act, Character &who )
const std::string ammo_name = ammo.tname();
const bool ammo_is_filthy = ammo.is_filthy();
const bool ammo_uses_speedloader = ammo.has_flag( flag_SPEEDLOADER );
const bool ammo_uses_speedloader_clip = ammo.has_flag( flag_SPEEDLOADER_CLIP );

if( !reloadable.reload( who, std::move( ammo_loc ), quantity ) ) {
add_msg( m_info, _( "Can't reload the %s." ), reloadable_name );
Expand All @@ -4806,7 +4807,8 @@ void reload_activity_actor::finish( player_activity &act, Character &who )
}

if( reloadable.is_gun() ) {
if( reloadable.has_flag( flag_RELOAD_ONE ) && !ammo_uses_speedloader ) {
if( reloadable.has_flag( flag_RELOAD_ONE ) && !ammo_uses_speedloader &&
!ammo_uses_speedloader_clip ) {
add_msg( m_neutral, _( "You insert %dx %s into the %s." ), quantity, ammo_name, reloadable_name );
}
make_reload_sound( who, reloadable );
Expand Down
9 changes: 9 additions & 0 deletions src/game_inventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1276,6 +1276,15 @@ class gunmod_remove_inventory_preset : public inventory_selector_preset
// a sight mod location, both are removable. Ideally one should not be removable, to
// represent the mod that has the other mod attached to its added sight mod location.
std::string get_denial( const item_location &loc ) const override {
item mod = *loc.get_item();
if( ( mod.type->gunmod->location.name() == "magazine" ||
mod.type->gunmod->location.name() == "mechanism" ||
mod.type->gunmod->location.name() == "loading port" ||
mod.type->gunmod->location.name() == "bore" ) &&
( gun.ammo_remaining() > 0 || gun.magazine_current() ) ) {
return _( "must be unloaded before removing this mod" );
}

if( !loc->type->gunmod->add_mod.empty() ) {
std::map<gunmod_location, int> mod_locations_added = loc->type->gunmod->add_mod;

Expand Down
33 changes: 21 additions & 12 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ static const item_category_id item_category_spare_parts( "spare_parts" );
static const item_category_id item_category_tools( "tools" );
static const item_category_id item_category_weapons( "weapons" );

static const itype_id itype_arredondo_chute( "arredondo_chute" );
static const itype_id itype_barrel_small( "barrel_small" );
static const itype_id itype_battery( "battery" );
static const itype_id itype_blood( "blood" );
Expand Down Expand Up @@ -11253,17 +11254,6 @@ ret_val<void> item::is_gunmod_compatible( const item &mod ) const
!mod.has_flag( flag_PUMP_RAIL_COMPATIBLE ) && has_flag( flag_PUMP_ACTION ) ) {
return ret_val<void>::make_failure( _( "can only accept small mods on that slot" ) );

} else if( !mod.type->mod->acceptable_ammo.empty() ) {
bool compat_ammo = false;
for( const ammotype &at : mod.type->mod->acceptable_ammo ) {
if( ammo_types( false ).count( at ) ) {
compat_ammo = true;
}
}
if( !compat_ammo ) {
return ret_val<void>::make_failure(
_( "%1$s cannot be used on item with no compatible ammo types" ), mod.tname( 1 ) );
}
} else if( mod.typeId() == itype_waterproof_gunmod && has_flag( flag_WATERPROOF_GUN ) ) {
return ret_val<void>::make_failure( _( "is already waterproof" ) );

Expand All @@ -11274,13 +11264,32 @@ ret_val<void> item::is_gunmod_compatible( const item &mod ) const
return ret_val<void>::make_failure( _( "cannot have a brass catcher" ) );

} else if( ( mod.type->gunmod->location.name() == "magazine" ||
mod.type->gunmod->location.name() == "mechanism" ) &&
mod.type->gunmod->location.name() == "mechanism" ||
mod.type->gunmod->location.name() == "loading port" ||
mod.type->gunmod->location.name() == "bore" ) &&
( ammo_remaining() > 0 || magazine_current() ) ) {
return ret_val<void>::make_failure( _( "must be unloaded before installing this mod" ) );

} else if( gunmod_find( itype_stock_none ) &&
mod.type->gunmod->location.name() == "stock accessory" ) {
return ret_val<void>::make_failure( _( "doesn't have a stock to attach this mod" ) );

} else if( mod.typeId() == itype_arredondo_chute ) {
return ret_val<void>::make_failure( _( "chute needs modification before attaching" ) );

// Acceptable_ammo check is kinda weird now, if it is passed, checks after it will be ignored.
// Moved it here as a workaround.
} else if( !mod.type->mod->acceptable_ammo.empty() ) {
bool compat_ammo = false;
for( const ammotype &at : mod.type->mod->acceptable_ammo ) {
if( ammo_types( false ).count( at ) ) {
compat_ammo = true;
}
}
if( !compat_ammo ) {
return ret_val<void>::make_failure(
_( "%1$s cannot be used on item with no compatible ammo types" ), mod.tname( 1 ) );
}
}

for( const gunmod_location &slot : mod.type->gunmod->blacklist_slot ) {
Expand Down

0 comments on commit 041f8fa

Please sign in to comment.