Skip to content

Commit

Permalink
Merge pull request #120 from wapcaplet/fix-batmod
Browse files Browse the repository at this point in the history
Fix battery mod installation
  • Loading branch information
KorGgenT authored Jul 7, 2020
2 parents c026a48 + 829d89a commit 5fc0fe4
Show file tree
Hide file tree
Showing 5 changed files with 520 additions and 23 deletions.
24 changes: 11 additions & 13 deletions src/activity_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2041,35 +2041,32 @@ void activity_handlers::reload_finish( player_activity *act, player *p )
}

item &reloadable = *act->targets[ 0 ];
item &ammo = *act->targets[1];
item &ammo = *act->targets[ 1 ];
std::string reloadable_name = reloadable.tname();
std::string ammo_name = ammo.tname();
const int qty = act->index;
const bool is_speedloader = ammo.has_flag( flag_SPEEDLOADER );
const bool ammo_is_filthy = ammo.is_filthy();

if( !reloadable.reload( *p, std::move( act->targets[ 1 ] ), qty ) ) {
add_msg( m_info, _( "Can't reload the %s." ), reloadable.tname() );
add_msg( m_info, _( "Can't reload the %s." ), reloadable_name );
return;
}

std::string msg = _( "You reload the %s." );

if( ammo_is_filthy ) {
if( ammo.is_filthy() ) {
reloadable.set_flag( "FILTHY" );
}

if( reloadable.get_var( "dirt", 0 ) > 7800 ) {
msg =
_( "You manage to loosen some debris and make your %s somewhat operational." );
add_msg( m_neutral, _( "You manage to loosen some debris and make your %s somewhat operational." ),
reloadable_name );
reloadable.set_var( "dirt", ( reloadable.get_var( "dirt", 0 ) - rng( 790, 2750 ) ) );
}

if( reloadable.is_gun() ) {
p->recoil = MAX_RECOIL;

if( reloadable.has_flag( flag_RELOAD_ONE ) && !is_speedloader ) {
if( reloadable.has_flag( flag_RELOAD_ONE ) && !ammo.has_flag( flag_SPEEDLOADER ) ) {
for( int i = 0; i != qty; ++i ) {
msg = _( "You insert one %2$s into the %1$s." );
add_msg( m_neutral, _( "You insert one %2$s into the %1$s." ), reloadable_name, ammo_name );
}
}
if( reloadable.type->gun->reload_noise_volume > 0 ) {
Expand All @@ -2079,9 +2076,10 @@ void activity_handlers::reload_finish( player_activity *act, player *p )
sounds::sound_t::activity, reloadable.type->gun->reload_noise );
}
} else if( reloadable.is_watertight_container() ) {
msg = _( "You refill the %s." );
add_msg( m_neutral, _( "You refill the %s." ), reloadable_name );
} else {
add_msg( m_neutral, _( "You reload the %1$s with %2$s." ), reloadable_name, ammo_name );
}
add_msg( m_neutral, msg, reloadable.tname(), ammo_name );
}

void activity_handlers::start_fire_finish( player_activity *act, player *p )
Expand Down
14 changes: 6 additions & 8 deletions src/item.h
Original file line number Diff line number Diff line change
Expand Up @@ -1764,19 +1764,17 @@ class item : public visitable<item>
const itype *ammo_data() const;
/** Specific ammo type, returns "null" if item is neither ammo nor loaded with any */
itype_id ammo_current() const;
/** Set of ammo types (@ref ammunition_type) used by item
* @param conversion whether to include the effect of any flags or mods which convert the type
* @return empty set if item does not use a specific ammo type (and is consequently not reloadable) */
std::set<ammotype> ammo_types( bool conversion = true ) const;

/** Ammo type of an ammo item
* @return ammotype of ammo item or a null id if the item is not ammo */
ammotype ammo_type() const;

/** Get default ammo used by item or a null id if item does not have a default ammo type
/** Ammo types (@ref ammunition_type) the item magazine pocket can contain.
* @param conversion whether to include the effect of any flags or mods which convert the type
* @return empty set if item does not have a magazine for a specific ammo type */
std::set<ammotype> ammo_types( bool conversion = true ) const;
/** Default ammo for the the item magazine pocket, if item has ammo_types().
* @param conversion whether to include the effect of any flags or mods which convert the type
* @return itype_id::NULL_ID() if item does not use a specific ammo type
* (and is consequently not reloadable) */
* @return itype_id::NULL_ID() if item does have a magazine for a specific ammo type */
itype_id ammo_default( bool conversion = true ) const;

/** Get default ammo for the first ammotype common to an item and its current magazine or "NULL" if none exists
Expand Down
4 changes: 2 additions & 2 deletions src/item_contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,14 +400,14 @@ ret_val<bool> item_contents::insert_item( const item &it, item_pocket::pocket_ty

ret_val<item_pocket *> pocket = find_pocket_for( it, pk_type );
if( pocket.value() == nullptr ) {
return ret_val<bool>::make_failure( "No pocket found: " + pocket.str() );
return ret_val<bool>::make_failure( "Found no suitable pocket for item" );
}

ret_val<item_pocket::contain_code> pocket_contain_code = pocket.value()->insert_item( it );
if( pocket_contain_code.success() ) {
return ret_val<bool>::make_success();
}
return ret_val<bool>::make_failure( "No success" );
return ret_val<bool>::make_failure( "Failed to insert into pocket" );
}

void item_contents::force_insert_item( const item &it, item_pocket::pocket_type pk_type )
Expand Down
188 changes: 188 additions & 0 deletions tests/ammo_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#include "item.h"
#include "itype.h"

#include "catch/catch.hpp"

// Functions:
// - item::ammo_types
//
// TODO:
// - ammo_type
// - common_ammo_default
// - ammo_sort_name

// item::ammo_types returns the ammo types an item may *contain*, which is distinct from the ammo
// types an item may *use*.
//
// Only magazines have ammo_types().
//
// Tools, tool mods, and (all other item types?) have empty ammo_types()


// Return true if the given item has non-empty ammo_types
static bool has_ammo_types( const item &it )
{
return !it.ammo_types().empty();
}

TEST_CASE( "ammo types", "[ammo][ammo_types]" )
{
// Only a few kinds of item have ammo_types:
// - Items with type=MAGAZINE (including batteries as well as gun magazines)
// - Tools/weapons with magazine_integral (pocket_data has a MAGAZINE rather than MAGAZINE_WELL)

SECTION( "items with MAGAZINE pockets have ammo_types" ) {
// Batteries are magazines
REQUIRE( item( "light_battery_cell" ).is_magazine() );
REQUIRE( item( "battery_car" ).is_magazine() );

// Tool batteries
CHECK( has_ammo_types( item( "light_battery_cell" ) ) );
CHECK( has_ammo_types( item( "medium_battery_cell" ) ) );
CHECK( has_ammo_types( item( "heavy_battery_cell" ) ) );
CHECK( has_ammo_types( item( "light_disposable_cell" ) ) );
CHECK( has_ammo_types( item( "medium_disposable_cell" ) ) );
CHECK( has_ammo_types( item( "heavy_disposable_cell" ) ) );
// Vehicle batteries
CHECK( has_ammo_types( item( "battery_car" ) ) );
CHECK( has_ammo_types( item( "battery_motorbike" ) ) );
CHECK( has_ammo_types( item( "large_storage_battery" ) ) );

SECTION( "battery magazines include 'battery' ammo type" ) {
CHECK( item( "light_battery_cell" ).ammo_types().count( ammotype( "battery" ) ) == 1 );
CHECK( item( "battery_car" ).ammo_types().count( ammotype( "battery" ) ) == 1 );
}

// Gun magazines
REQUIRE( item( "belt40mm" ).is_magazine() );
REQUIRE( item( "akmag10" ).is_magazine() );

CHECK( has_ammo_types( item( "belt40mm" ) ) );
CHECK( has_ammo_types( item( "belt308" ) ) );
CHECK( has_ammo_types( item( "akmag10" ) ) );
CHECK( has_ammo_types( item( "akdrum75" ) ) );
CHECK( has_ammo_types( item( "glockmag" ) ) );

SECTION( "gun magazines include ammo type for that magazine" ) {
CHECK( item( "glockmag" ).ammo_types().count( ammotype( "9mm" ) ) == 1 );
CHECK( item( "akmag10" ).ammo_types().count( ammotype( "762" ) ) == 1 );
}
}

SECTION( "GUN items with integral MAGAZINE pockets have ammo_types" ) {
REQUIRE( item( "nailgun" ).magazine_integral() );
REQUIRE( item( "colt_army" ).magazine_integral() );

CHECK( has_ammo_types( item( "nailgun" ) ) );
CHECK( has_ammo_types( item( "colt_army" ) ) );
CHECK( has_ammo_types( item( "hand_crossbow" ) ) );
CHECK( has_ammo_types( item( "compositebow" ) ) );
CHECK( has_ammo_types( item( "sling" ) ) );
CHECK( has_ammo_types( item( "slingshot" ) ) );
}

SECTION( "TOOL items with integral MAGAZINE pockets have ammo_types" ) {
REQUIRE( item( "sewing_kit" ).magazine_integral() );

CHECK( has_ammo_types( item( "needle_bone" ) ) );
CHECK( has_ammo_types( item( "needle_wood" ) ) );
CHECK( has_ammo_types( item( "sewing_kit" ) ) );
CHECK( has_ammo_types( item( "tailors_kit" ) ) );
}

SECTION( "TOOL items with NO pockets have ammo_types" ) {
// NOTE: Fish trap is a TOOL with "ammo", but no "pocket_data", so an implicit MAGAZINE
// pocket is added by Item_factory::check_and_create_magazine_pockets on JSON load.
// This item would be considered needing data migration to an explicit MAGAZINE pocket.
REQUIRE( item( "fish_trap" ).magazine_integral() );

CHECK( has_ammo_types( item( "fish_trap" ) ) );
}

// These items have NO ammo_types:

SECTION( "GUN items with MAGAZINE_WELL pockets do NOT have ammo_types" ) {
REQUIRE_FALSE( item( "m1911" ).magazine_integral() );

CHECK_FALSE( has_ammo_types( item( "m1911" ) ) );
CHECK_FALSE( has_ammo_types( item( "usp_9mm" ) ) );
CHECK_FALSE( has_ammo_types( item( "tommygun" ) ) );
CHECK_FALSE( has_ammo_types( item( "ak74" ) ) );
CHECK_FALSE( has_ammo_types( item( "ak47" ) ) );
}

SECTION( "TOOL items with MAGAZINE_WELL pockets do NOT have ammo_types" ) {
REQUIRE( item( "flashlight" ).is_tool() );

CHECK_FALSE( has_ammo_types( item( "flashlight" ) ) );
CHECK_FALSE( has_ammo_types( item( "hotplate" ) ) );
CHECK_FALSE( has_ammo_types( item( "vac_sealer" ) ) );
CHECK_FALSE( has_ammo_types( item( "forge" ) ) );
CHECK_FALSE( has_ammo_types( item( "cordless_drill" ) ) );
}

SECTION( "AMMO items themselves do NOT have ammo_types" ) {
REQUIRE( item( "38_special" ).is_ammo() );
REQUIRE( item( "sinew" ).is_ammo() );

// Ammo for guns
CHECK_FALSE( has_ammo_types( item( "38_special" ) ) );
CHECK_FALSE( has_ammo_types( item( "reloaded_308" ) ) );
CHECK_FALSE( has_ammo_types( item( "bp_9mm" ) ) );
CHECK_FALSE( has_ammo_types( item( "44magnum" ) ) );
// Not for guns but classified as ammo
CHECK_FALSE( has_ammo_types( item( "sinew" ) ) );
CHECK_FALSE( has_ammo_types( item( "nail" ) ) );
CHECK_FALSE( has_ammo_types( item( "rock" ) ) );
CHECK_FALSE( has_ammo_types( item( "solder_wire" ) ) );
}

SECTION( "TOOLMOD items do NOT have ammo_types" ) {
item med_mod( "magazine_battery_medium_mod" );
REQUIRE( med_mod.is_toolmod() );

CHECK_FALSE( has_ammo_types( med_mod ) );
}
}

// The same items with no ammo_types, also have no ammo_default.
TEST_CASE( "ammo default", "[ammo][ammo_default]" )
{
// TOOLMOD type, and TOOL/GUN type items with MAGAZINE_WELL pockets have no ammo_default
SECTION( "items without ammo_default" ) {
item flashlight( "flashlight" );
item med_mod( "magazine_battery_medium_mod" );
item tommygun( "tommygun" );

CHECK( flashlight.ammo_default().is_null() );
CHECK( med_mod.ammo_default().is_null() );
CHECK( tommygun.ammo_default().is_null() );
}

// MAGAZINE type, and TOOL/GUN items with integral MAGAZINE pockets do have ammo_default
SECTION( "items with ammo_default" ) {
// MAGAZINE type items
item battery( "light_battery_cell" );
item glockmag( "glockmag" );
CHECK( battery.ammo_default() == itype_id( "battery" ) );
CHECK( glockmag.ammo_default() == itype_id( "9mm" ) );

// TOOL type items with integral magazines
item sewing_kit( "sewing_kit" );
item needle( "needle_bone" );
item fishtrap( "fish_trap" );
CHECK( sewing_kit.ammo_default() == itype_id( "thread" ) );
CHECK( needle.ammo_default() == itype_id( "thread" ) );
CHECK( fishtrap.ammo_default() == itype_id( "fish_bait" ) );

// GUN type items with integral magazine
item slingshot( "slingshot" );
item colt( "colt_army" );
item lemat( "lemat_revolver" );
CHECK( slingshot.ammo_default() == itype_id( "pebble" ) );
// Revolver ammo is "44paper" but default ammunition type is "44army"
CHECK( colt.ammo_default() == itype_id( "44army" ) );
CHECK( lemat.ammo_default() == itype_id( "44army" ) );
}
}

Loading

0 comments on commit 5fc0fe4

Please sign in to comment.