Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rebalance item handling costs #14977

Merged
merged 17 commits into from
Jan 28, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions data/json/items/armor.json
Original file line number Diff line number Diff line change
Expand Up @@ -10617,6 +10617,35 @@
"coverage" : 20,
"material_thickness" : 2
},
{
"type" : "ARMOR",
"id" : "legpouch",
"name" : "drop leg ammo pouch",
"name_plural" : "drop leg ammo pouches",
"weight" : 100,
"color" : "dark_gray",
"covers" : ["LEG_EITHER"],
"storage" : 0,
"symbol" : "[",
"description" : "A small fabric ammo pouch that can be strapped to your leg and capable of holding a single magazine close at hand.",
"price" : 2000,
"material" : ["cotton", "null"],
"volume" : 1,
"warmth" : 0,
"phase" : "solid",
"encumbrance" : 3,
"flags" : ["VARSIZE", "WATER_FRIENDLY", "BELTED"],
"coverage" : 15,
"material_thickness" : 2,
"use_action" : {
"type": "holster",
"holster_prompt": "Stash ammo",
"holster_msg": "You stash your %s",
"max_volume": 2,
"draw_cost": 5,
"flags": [ "COMPACT_MAG" ]
}
},
{
"type" : "ARMOR",
"id" : "leather_cat_ears",
Expand Down
5 changes: 4 additions & 1 deletion data/json/items/magazines.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"ammo_type" : "223",
"capacity" : 30,
"reliability" : 10,
"reload_time" : 30
"reload_time" : 30,
"flags": [ "COMPACT_MAG" ]
},
{ "type" : "MAGAZINE",
"id" : "belt223",
Expand Down Expand Up @@ -49,6 +50,7 @@
"capacity" : 15,
"reliability" : 10,
"reload_time" : 40,
"flags": [ "COMPACT_MAG" ],
"alternatives" : [
[ "45", [ "usp45mag" ] ]
]
Expand All @@ -68,6 +70,7 @@
"capacity" : 12,
"reliability" : 10,
"reload_time" : 35,
"flags": [ "COMPACT_MAG" ],
"alternatives" : [
[ "9mm", [ "glockmag" ] ]
]
Expand Down
2 changes: 2 additions & 0 deletions doc/JSON_FLAGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,8 @@ Some armor flags, such as `WATCH` and `ALARMCLOCK` are compatible with other ite
- ```QUIVER_n``` Item can hold n arrows (will parse number as integer)
- ```ALWAYS_TWOHAND``` Item is always wielded with two hands. Without this, the items volume and weight are used to calculate this.
- ```BAYONET``` If the item is attached to a gun (as gunmod), the gun will use the cutting damage from the mod instead of its own.
- ```COMPACT_MAG``` Item can be stashed in an appropriate ammo pouch (intended for compact magazines)
- ```BULKY_MAG``` Item can be stashed in an appropriate ammo pouch (intended for bulky or awkwardly shaped magazines)

## Guns

Expand Down
54 changes: 37 additions & 17 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ bool Character::has_active_bionic(const std::string & b) const
return false;
}

VisitResponse Character::visit_items( const std::function<VisitResponse( item& )>& func )
VisitResponse Character::visit_items( const std::function<VisitResponse( item *, item * )>& func )
{
if( !weapon.is_null() && weapon.visit_items( func ) == VisitResponse::ABORT ) {
return VisitResponse::ABORT;
Expand All @@ -484,26 +484,46 @@ VisitResponse Character::visit_items( const std::function<VisitResponse( item& )
return inv.visit_items( func );
}

VisitResponse Character::visit_items( const std::function<VisitResponse( const item& )>& func ) const
VisitResponse Character::visit_items( const std::function<VisitResponse( const item *, const item * )>& func ) const
{
return const_cast<Character *>( this )->visit_items( static_cast<const std::function<VisitResponse(item&)>&>( func ) );
return const_cast<Character *>( this )->visit_items( static_cast<const std::function<VisitResponse(item *, item *)>&>( func ) );
}

item * Character::find_parent( item& it )
{
item *res = nullptr;
if( visit_items( [&]( item *node, item *parent ){
if( node == &it ) {
res = parent;
return VisitResponse::ABORT;
}
return VisitResponse::NEXT;
} ) != VisitResponse::ABORT ) {
debugmsg( "Tried to find item parent using character who doesn't have the item" );
}
return res;
}

const item * Character::find_parent( const item& it ) const
{
return const_cast<Character *>( this )->find_parent( const_cast<item&>( it ) );
}

std::vector<item *> Character::items_with( const std::function<bool(const item&)>& filter )
{
auto res = inv.items_with( filter );

weapon.visit_items( [&res, &filter]( item& it ) {
if( filter( it ) ) {
res.emplace_back( &it );
weapon.visit_items( [&res, &filter]( item *node, item * ) {
if( filter( *node ) ) {
res.emplace_back( node );
}
return VisitResponse::NEXT;
});

for( auto &e : worn ) {
e.visit_items( [&res, &filter]( item& it ) {
if( filter( it ) ) {
res.emplace_back( &it );
e.visit_items( [&res, &filter]( item *node, item * ) {
if( filter( *node ) ) {
res.emplace_back( node );
}
return VisitResponse::NEXT;
});
Expand All @@ -516,17 +536,17 @@ std::vector<const item *> Character::items_with( const std::function<bool(const
{
auto res = inv.items_with( filter );

weapon.visit_items( [&res, &filter]( const item& it ) {
if( filter( it ) ) {
res.emplace_back( &it );
weapon.visit_items( [&res, &filter]( const item *node, const item * ) {
if( filter( *node ) ) {
res.emplace_back( node );
}
return VisitResponse::NEXT;
});

for( const auto &e : worn ) {
e.visit_items( [&res, &filter]( const item& it ) {
if( filter( it ) ) {
res.emplace_back( &it );
e.visit_items( [&res, &filter]( const item *node, const item * ) {
if( filter( *node ) ) {
res.emplace_back( node );
}
return VisitResponse::NEXT;
});
Expand All @@ -537,8 +557,8 @@ std::vector<const item *> Character::items_with( const std::function<bool(const

bool Character::has_item_with( const std::function<bool(const item&)>& filter ) const
{
return visit_items( [&filter]( const item& it ) {
return filter( it ) ? VisitResponse::ABORT : VisitResponse::NEXT;
return visit_items( [&filter]( const item *node, const item * ) {
return filter( *node ) ? VisitResponse::ABORT : VisitResponse::NEXT;
}) == VisitResponse::ABORT;
}

Expand Down
17 changes: 13 additions & 4 deletions src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,20 @@ class Character : public Creature
}

/** Traverses wielded, worn and inventory items and using a visitor function
* @return Similar to item::visit returns only VisitResponse::Next or VisitResponse::Abort
* @see item::visit
* @return Similar to item::visit_items returns only VisitResponse::Next or VisitResponse::Abort
* @see item::visit_items
**/
VisitResponse visit_items( const std::function<VisitResponse(item&)>& func );
VisitResponse visit_items( const std::function<VisitResponse(const item&)>& func ) const;
VisitResponse visit_items( const std::function<VisitResponse(item *, item *)>& func );
VisitResponse visit_items( const std::function<VisitResponse(const item *, const item *)>& func ) const;

/**
* Determine the parent container (if any) for an item.
* Wielded and worn items are checked first as these are typically the most frequently requested
* @param it item to search for which must be in the characters possession
* @return parent container or nullptr if the item is not within a container
*/
item * find_parent( item& it );
const item * find_parent( const item& it ) const;

/**
* Test whether an item in the playerts possession matches a certain filter.
Expand Down
15 changes: 3 additions & 12 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11482,21 +11482,12 @@ void game::reload( int pos )
break;
}

// pick ammo
auto loc = it->pick_reload_ammo( u, true );
auto ammo = loc.get_item();
if( ammo ) {
// move ammo to inventory if necessary
int am_pos = u.get_item_position( ammo );
if( am_pos == INT_MIN ) {
am_pos = u.get_item_position( &u.i_add( *ammo ) );
loc.remove_item();
}

// do the actual reloading
if( loc.get_item() ) {
std::stringstream ss;
ss << pos;
u.assign_activity( ACT_RELOAD, it->reload_time( u ), -1, am_pos, ss.str() );
u.assign_activity( ACT_RELOAD, it->reload_time( u ), -1, loc.obtain( u ), ss.str() );
u.inv.restack( &u );
}

refresh_all();
Expand Down
10 changes: 8 additions & 2 deletions src/game_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,17 @@
#define OVERMAP_LAYERS (1 + OVERMAP_DEPTH + OVERMAP_HEIGHT)

/** Base move cost (before modifiers) per unit volume when handling items */
#define VOLUME_MOVE_COST 10
#define VOLUME_MOVE_COST 20
/** Minimum move cost when handling an item */
#define MIN_HANDLING_COST 40
#define MIN_HANDLING_COST 30
/** Maximum move cost when handling an item */
#define MAX_HANDLING_COST 800
/** Factor for item handling costs when item found in inventory */
#define INVENTORY_HANDLING_FACTOR 3
/** Factor for item handling costs when item found on map tile */
#define MAP_HANDLING_FACTOR 5
/** Factor for item handling costs when item found in vehicle */
#define VEHICLE_HANDLING_FACTOR 4

/** Minimum amount of damage to an item (state of maximum repair) */
#define MIN_ITEM_DAMAGE -1
Expand Down
42 changes: 31 additions & 11 deletions src/inventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1182,7 +1182,7 @@ std::set<char> inventory::allocated_invlets() const
return invlets;
}

VisitResponse inventory::visit_items( const std::function<VisitResponse(item&)>& func ) {
VisitResponse inventory::visit_items( const std::function<VisitResponse(item *, item *)>& func ) {
for( auto &stack : items ) {
for( auto &it : stack ) {
if( it.visit_items( func ) == VisitResponse::ABORT ) {
Expand All @@ -1193,15 +1193,35 @@ VisitResponse inventory::visit_items( const std::function<VisitResponse(item&)>&
return VisitResponse::NEXT;
}

VisitResponse inventory::visit_items( const std::function<VisitResponse(const item&)>& func ) const {
return const_cast<inventory *>( this )->visit_items( static_cast<const std::function<VisitResponse(item&)>&>( func ) );
VisitResponse inventory::visit_items( const std::function<VisitResponse(const item *, const item *)>& func ) const {
return const_cast<inventory *>( this )->visit_items( static_cast<const std::function<VisitResponse(item *, item *)>&>( func ) );
}

item * inventory::find_parent( item& it )
{
item *res = nullptr;
if( visit_items( [&]( item *node, item *parent ){
if( node == &it ) {
res = parent;
return VisitResponse::ABORT;
}
return VisitResponse::NEXT;
} ) != VisitResponse::ABORT ) {
debugmsg( "Tried to find item parent using inventory which doesn't contain it" );
}
return res;
}

const item * inventory::find_parent( const item& it ) const
{
return const_cast<inventory *>( this )->find_parent( const_cast<item&>( it ) );
}

std::vector<item *> inventory::items_with( const std::function<bool(const item&)>& filter ) {
std::vector<item *> res;
visit_items( [&res, &filter]( item& it ) {
if( filter( it ) ) {
res.emplace_back( &it );
visit_items( [&res, &filter]( item *node, item * ) {
if( filter( *node ) ) {
res.emplace_back( node );
}
return VisitResponse::NEXT;
});
Expand All @@ -1210,17 +1230,17 @@ std::vector<item *> inventory::items_with( const std::function<bool(const item&)

std::vector<const item *> inventory::items_with( const std::function<bool(const item&)>& filter ) const {
std::vector<const item *> res;
visit_items( [&res, &filter]( const item& it ) {
if( filter( it ) ) {
res.emplace_back( &it );
visit_items( [&res, &filter]( const item *node, const item * ) {
if( filter( *node ) ) {
res.emplace_back( node );
}
return VisitResponse::NEXT;
});
return res;
}

bool inventory::has_item_with( const std::function<bool(const item&)>& filter ) const {
return visit_items( [&filter]( const item& it ) {
return filter( it ) ? VisitResponse::ABORT : VisitResponse::NEXT;
return visit_items( [&filter]( const item *node, const item * ) {
return filter( *node ) ? VisitResponse::ABORT : VisitResponse::NEXT;
} ) == VisitResponse::ABORT;
}
16 changes: 12 additions & 4 deletions src/inventory.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,19 @@ class inventory
}

/** Traverses each item in the inventory using a visitor function
* @return Similar to item::visit returns only VisitResponse::Next or VisitResponse::Abort
* @see item::visit
* @return Similar to item::visit_items returns only VisitResponse::Next or VisitResponse::Abort
* @see item::visit_items
**/
VisitResponse visit_items( const std::function<VisitResponse(item&)>& func );
VisitResponse visit_items( const std::function<VisitResponse(const item&)>& func ) const;
VisitResponse visit_items( const std::function<VisitResponse(item *, item *)>& func );
VisitResponse visit_items( const std::function<VisitResponse(const item *, const item *)>& func ) const;

/**
* Determine the parent container (if any) for an item.
* @param it item to search for which must be contained in the inventory
* @return parent container or nullptr if the item is not within a container
*/
item * find_parent( item& it );
const item * find_parent( const item& it ) const;

/** Returns true if any item (including those within a container) matches the filter */
bool has_item_with( const std::function<bool(const item&)>& filter ) const;
Expand Down
Loading