I’ve made and decided to share on here a simple-ish C++ implementation of proper support for heavy vehicular weapons that prevent firing said weapons from bicycles, shopping carts or similar light vehicles, as was the issue with how Tankmod had tank guns implemented.
The way it is currently done is as such:
Any vehicle-only guns get the JSON flag called “VEHICLE_GUN_ONLY”.
If a gun with this flag is mounted on a vehicle which has total mass lower than the mass defined in “min_veh_mass” JSON field of a gun item, then said gun can’t be fired.
Furthermore, if a gun with this flag is installed on a vehicle tile with has no parts with a new “MOUNTABLE_HEAVY” JSON flag (which usually is a heavy-duty frame), then the gun can’t be fired either.
The code additions are below. Anyone feel free to make a pull request with it, but note that code may or may not need minor updates for the most recent experimental version of DDA. Suggestions are welcome.
- File
avatar_action.cpp
:
Functionavatar_action::fire_turret_manual
: this code defines the logic behind forbidding firing vehicular weapons from an unsuitable vehicle.
if( turret.base()->has_flag( flag_VEHICLE_GUN_ONLY ) ) {
const optional_vpart_position vp = m.veh_at( you.pos() );
vehicle *veh = veh_pointer_or_null( vp );
if( !veh ) {
debugmsg( "Vehicle not found on fired vehicular weapon tile." );
return false;
}
if( !static_cast<bool>( vp.part_with_feature( "MOUNTABLE_HEAVY", true ) ) ) {
add_msg( m_bad, _( "This vehicle's frame is not durable enough to handle the recoil of the %s." ),
turret.name() );
return false;
}
if( veh->total_mass() < turret.base()->get_min_veh_mass() ) {
add_msg( m_bad, _( "This vehicle is too light to safely fire the %s." ), turret.name() );
return false;
}
}
Function avatar_action::fire_wielded_weapon
: show failure text if player tries to fire a vehicle-only weapon while wielding it.
if( weapon->has_flag( flag_VEHICLE_GUN_ONLY ) ) {
add_msg( m_info,
_( "Your %s must be mounted on a vehicle with a sturdy frame and enough mass to fire." ),
weapon->tname() );
return;
}
- File
flag.cpp
: define new flag.
const flag_id flag_VEHICLE_GUN_ONLY( "VEHICLE_GUN_ONLY" );
- File
flag.h
: define new flag.
extern const flag_id flag_VEHICLE_GUN_ONLY;
- File
item.cpp
:
Functionitem::gun_info
: code to display minimum vehicle mass in gun info; insert after the code to display barrel length.
if( mod->get_min_veh_mass().value() > 0 ) {
if( parts->test( iteminfo_parts::GUN_MIN_VEH_MASS ) ) {
info.emplace_back( weight_to_info( "GUN", _( "Minimum Vehicle Mass: " ), get_min_veh_mass() ) );
}
}
info.back().bNewLine = true;
New function to get minimum vehicle mass from item data:
units::mass item::get_min_veh_mass() const
{
return type->min_veh_mass;
}
- File
item.h
: defining the new function above.
units::mass get_min_veh_mass() const;
- File
item_factory.cpp
, functionItem_factory::load_basic_info
: load minimum vehicle mass field from JSON.
assign( jo, "min_veh_mass", def.min_veh_mass, false, 0_gram );
-
File
iteminfo_query.h
,enum class iteminfo_parts
: addGUN_MIN_VEH_MASS
afterGUN_BARRELLENGTH
to get minimum vehicle mass data to display in item description. -
File
turret.cpp
: replacevehicle::find_all_ready_turrets
function with this one:
std::vector<vehicle_part *> vehicle::find_all_ready_turrets( bool manual, bool automatic )
{
std::vector<vehicle_part *> res;
for( vehicle_part *t : turrets() ) {
if( ( t->enabled && automatic ) || ( !t->enabled && manual ) ) {
if( turret_query( *t ).query() == turret_data::status::ready ) {
turret_data turret_here = turret_query( global_part_pos3( *t ) );
if( turret_here.base()->has_flag( flag_VEHICLE_GUN_ONLY ) ) {
if( !has_part( global_part_pos3( *t ), "MOUNTABLE_HEAVY", false ) ||
total_mass() < turret_here.base()->get_min_veh_mass() ) {
continue;
}
}
res.push_back( t );
}
}
}
return res;
}
Also add #include "flag.h"
to the file.
Sample gun JSON data to test this mechanic with:
{
"id": "gau19",
"copy-from": "rifle_auto",
"looks_like": "m2browning",
"type": "GUN",
"name": { "str_sp": "GAU-19/B" },
"description": "An electrically driven, three-barrel rotary heavy machine gun firing a .50 BMG cartridge. If you could find enough ammo for it, it would become a devastating weapon. It must be mounted on a heavy vehicle frame before use.",
"weight": "48 kg",
"volume": "12 L",
"longest_side": "1369 mm",
"barrel_length": "914 mm",
"price": 1800000,
"price_postapoc": 10000,
"to_hit": -4,
"material": [ "qt_steel" ],
"ammo": [ "50" ],
"range": 110,
"dispersion": 250,
"durability": 9,
"blackpowder_tolerance": 96,
"energy_drain": "1 kJ",
"reload": 400,
"modes": [ [ "DEFAULT", "low auto", 6 ], [ "AUTO", "high auto", 50 ] ],
"valid_mod_locations": [ [ "sling", 1 ] ],
"min_veh_mass": "250 kg",
"flags": [ "NEVER_JAMS", "VEHICLE_GUN_ONLY", "USE_UPS" ],
"pocket_data": [ { "pocket_type": "MAGAZINE_WELL", "item_restriction": [ "belt50" ] } ],
"melee_damage": { "bash": 18 }
}