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

[READY] Sort out my loot, please! #24488

Merged
merged 27 commits into from
Aug 24, 2018
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
6 changes: 6 additions & 0 deletions data/json/flags.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@
"info": "This piece of clothing is <info>fancy</info>.",
"conflicts": [ "SUPER_FANCY" ]
},
{
"id": "FIREWOOD",
"type": "json_flag",
"context": [ "GENERIC" ],
"info": "This item can serve as a firewood."
},
{
"id": "FIX_FARSIGHT",
"type": "json_flag",
Expand Down
7 changes: 4 additions & 3 deletions data/json/items/generic.json
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,8 @@
"weight": 9071,
"volume": 40,
"bashing": 10,
"to_hit": -10
"to_hit": -10,
"flags": [ "FIREWOOD" ]
},
{
"type": "GENERIC",
Expand All @@ -560,7 +561,7 @@
"bashing": 4,
"to_hit": 1,
"qualities": [ [ "COOK", 1 ] ],
"flags": [ "NO_SALVAGE", "TRADER_AVOID" ]
"flags": [ "NO_SALVAGE", "TRADER_AVOID", "FIREWOOD" ]
},
{
"type": "GENERIC",
Expand Down Expand Up @@ -1701,7 +1702,7 @@
"weight": 220,
"volume": 2,
"to_hit": -2,
"flags": [ "TRADER_AVOID" ]
"flags": [ "TRADER_AVOID", "FIREWOOD" ]
},
{
"type": "GENERIC",
Expand Down
7 changes: 4 additions & 3 deletions data/json/items/melee.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"description": "A sturdy, heavy stick. Makes a decent melee weapon, and can be cut into two by fours for crafting.",
"material": "wood",
"techniques": [ "WBLOCK_1" ],
"flags": "TRADER_AVOID",
"flags": [ "TRADER_AVOID", "FIREWOOD" ],
"weight": 1700,
"volume": 5,
"bashing": 14,
Expand All @@ -39,7 +39,7 @@
"description": "A long stick. Makes a decent melee weapon, and can be broken into heavy sticks for crafting.",
"material": "wood",
"techniques": [ "WBLOCK_1" ],
"flags": "TRADER_AVOID",
"flags": [ "TRADER_AVOID", "FIREWOOD" ],
"weight": 3400,
"volume": 10,
"bashing": 18,
Expand Down Expand Up @@ -521,7 +521,8 @@
"volume": 6,
"bashing": 10,
"price": 1000,
"price_postapoc": 0
"price_postapoc": 0,
"flags": [ "FIREWOOD" ]
},
{
"type": "GENERIC",
Expand Down
8 changes: 8 additions & 0 deletions data/json/player_activities.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,14 @@
"based_on": "neither",
"no_resume": true
},
{
"id": "ACT_MOVE_LOOT",
"type": "activity_type",
"stop_phrase": "Stop sorting out the loot?",
"suspendable": false,
"based_on": "neither",
"no_resume": true
},
{
"id": "ACT_ADV_INVENTORY",
"type": "activity_type",
Expand Down
1 change: 1 addition & 0 deletions data/raw/keybindings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2170,6 +2170,7 @@
{ "type":"keybinding", "name": "Advanced Inventory management", "category":"DEFAULTMODE", "id":"advinv", "bindings":[ { "input_method":"keyboard", "key":"/" } ] },
{ "type":"keybinding", "name": "Pick up Item(s)", "category":"DEFAULTMODE", "id":"pickup", "bindings":[ { "input_method":"keyboard", "key":"," }, { "input_method":"keyboard", "key":"g" } ] },
{ "type":"keybinding", "name": "Grab something nearby", "category":"DEFAULTMODE", "id":"grab", "bindings":[ { "input_method":"keyboard", "key":"G" } ] },
{ "type":"keybinding", "name": "Sort out loot", "category":"DEFAULTMODE", "id":"loot", "bindings":[ { "input_method":"keyboard", "key":"O" } ] },
{ "type":"keybinding", "name": "Butcher", "category":"DEFAULTMODE", "id":"butcher", "bindings":[ { "input_method":"keyboard", "key":"B" } ] },
{ "type":"keybinding", "name": "Chat with NPC", "category":"DEFAULTMODE", "id":"chat", "bindings":[ { "input_method":"keyboard", "key":"C" } ] },
{ "type":"keybinding", "name": "Look Around", "category":"DEFAULTMODE", "id":"look", "bindings":[ { "input_method":"keyboard", "key":";" }, { "input_method":"keyboard", "key":"x" } ] },
Expand Down
1 change: 1 addition & 0 deletions doc/JSON_FLAGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,7 @@ Those flags are added by the game code to specific items (that specific welder,
- ```ANESTHESIA``` ... Item is considered anesthesia for the purpose of installing or uninstalling bionics.
- ```DURABLE_MELEE``` ... Item is made to hit stuff and it does it well, so it's considered to be a lot tougher than other weapons made of the same materials.
- ```FAKE_SMOKE``` ... Item is a fake item generating smoke, recognizable by @ref item::process_fake_smoke, where conditions for its removal are set.
- ```FIREWOOD``` ... This item can serve as a firewood. Items with this flag are sorted out to "Loot: Wood" zone
- ```FRAGILE_MELEE``` ... Fragile items that fall apart easily when used as a weapon due to poor construction quality and will break into components when broken.
- ```GAS_DISCOUNT``` ... Discount cards for the automated gas stations.
- ```LEAK_ALWAYS``` ... Leaks (may be combined with "RADIOACTIVE").
Expand Down
3 changes: 3 additions & 0 deletions src/action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ std::string action_ident( action_id act )
return "listitems";
case ACTION_ZONES:
return "zones";
case ACTION_LOOT:
return "loot";
case ACTION_INVENTORY:
return "inventory";
case ACTION_COMPARE:
Expand Down Expand Up @@ -728,6 +730,7 @@ action_id handle_action_menu()
REGISTER_ACTION( ACTION_PICKUP );
REGISTER_ACTION( ACTION_GRAB );
REGISTER_ACTION( ACTION_BUTCHER );
REGISTER_ACTION( ACTION_LOOT );
} else if( category == _( "Combat" ) ) {
REGISTER_ACTION( ACTION_TOGGLE_MOVE );
REGISTER_ACTION( ACTION_FIRE );
Expand Down
2 changes: 2 additions & 0 deletions src/action.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ enum action_id : int {
ACTION_LIST_ITEMS,
/** Open the zone manager */
ACTION_ZONES,
/** Sort out the loot */
ACTION_LOOT,
/**@}*/

// Inventory Interaction (including quasi-inventories like bionics)
Expand Down
12 changes: 12 additions & 0 deletions src/activity_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const std::map< activity_id, std::function<void( player_activity *, player *)> >
{ activity_id( "ACT_AIM" ), aim_do_turn },
{ activity_id( "ACT_PICKUP" ), pickup_do_turn },
{ activity_id( "ACT_MOVE_ITEMS" ), move_items_do_turn },
{ activity_id( "ACT_MOVE_LOOT" ), move_loot_do_turn },
{ activity_id( "ACT_ADV_INVENTORY" ), adv_inventory_do_turn },
{ activity_id( "ACT_ARMOR_LAYERS" ), armor_layers_do_turn },
{ activity_id( "ACT_ATM" ), atm_do_turn },
Expand Down Expand Up @@ -127,6 +128,7 @@ const std::map< activity_id, std::function<void( player_activity *, player *)> >
{ activity_id( "ACT_BUILD" ), build_finish },
{ activity_id( "ACT_VIBE" ), vibe_finish },
{ activity_id( "ACT_MOVE_ITEMS" ), move_items_finish },
{ activity_id( "ACT_MOVE_LOOT" ), move_loot_finish },
{ activity_id( "ACT_ATM" ), atm_finish },
{ activity_id( "ACT_AIM" ), aim_finish },
{ activity_id( "ACT_WASH" ), washing_finish },
Expand Down Expand Up @@ -1368,6 +1370,11 @@ void activity_handlers::move_items_finish( player_activity *act, player *p )
pickup_finish( act, p );
}

void activity_handlers::move_loot_finish( player_activity *act, player *p )
{
pickup_finish( act, p );
}

void activity_handlers::firstaid_finish( player_activity *act, player *p )
{
static const std::string iuse_name_string( "heal" );
Expand Down Expand Up @@ -2420,6 +2427,11 @@ void activity_handlers::move_items_do_turn( player_activity *, player * )
activity_on_turn_move_items();
}

void activity_handlers::move_loot_do_turn( player_activity *act, player *p )
{
activity_on_turn_move_loot( *act, *p );
}

void activity_handlers::adv_inventory_do_turn( player_activity *, player *p )
{
p->cancel_activity();
Expand Down
3 changes: 3 additions & 0 deletions src/activity_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class player;
// activity_item_handling.cpp
void activity_on_turn_drop();
void activity_on_turn_move_items();
void activity_on_turn_move_loot( player_activity &act, player &p );
void activity_on_turn_pickup();
void activity_on_turn_stash();
void try_refuel_fire( player &p );
Expand Down Expand Up @@ -40,6 +41,7 @@ void oxytorch_do_turn( player_activity *act, player *p );
void aim_do_turn( player_activity *act, player *p );
void pickup_do_turn( player_activity *act, player *p );
void move_items_do_turn( player_activity *act, player *p );
void move_loot_do_turn( player_activity *act, player *p );
void adv_inventory_do_turn( player_activity *act, player *p );
void armor_layers_do_turn( player_activity *act, player *p );
void atm_do_turn( player_activity *act, player *p );
Expand Down Expand Up @@ -91,6 +93,7 @@ void disassemble_finish( player_activity *act, player *p );
void build_finish( player_activity *act, player *p );
void vibe_finish( player_activity *act, player *p );
void move_items_finish( player_activity *act, player *p );
void move_loot_finish( player_activity *act, player *p );
void atm_finish( player_activity *act, player *p );
void aim_finish( player_activity *act, player *p );
void washing_finish( player_activity *act, player *p );
Expand Down
181 changes: 181 additions & 0 deletions src/activity_item_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "debug.h"
#include "pickup.h"
#include "requirements.h"
#include "clzones.h"

#include <list>
#include <vector>
Expand Down Expand Up @@ -643,6 +644,186 @@ void activity_on_turn_move_items()
}
}

static double get_capacity_fraction( int capacity, int volume )
{
// fration of capacity the item would occupy
// fr = 1 is for capacity smaller than is size of item
// in such case, let's assume player does the trip for full cost with item in hands
double fr = 1;

if( capacity > volume ) {
fr = ( double )volume / capacity;
}

return fr;
}

static int move_cost_inv( const item &it, const tripoint &src, const tripoint &dest )
{
// to prevent potentially ridiculous number
const int MAX_COST = 500;

// it seems that pickup cost is flat 100
// in function pick_one_up, varible moves_taken has initial value of 100
// and never changes until it is finally used in function
// remove_from_map_or_vehicle
const int pickup_cost = 100;

// drop cost for non-tumbling items (from inventory overload) is also flat 100
// according to convert_to_items (it does contain todo to use calculated costs)
const int drop_cost = 100;

// typical flat ground move cost
const int mc_per_tile = 100;

// only free inventory capacity
const int inventory_capacity = units::to_milliliter( g->u.volume_capacity() -
g->u.volume_carried() );

const int item_volume = units::to_milliliter( it.volume() );

const double fr = get_capacity_fraction( inventory_capacity, item_volume );

// approximation of movement cost between source and destination
const int move_cost = mc_per_tile * rl_dist( src, dest ) * fr;

return std::min( pickup_cost + drop_cost + move_cost, MAX_COST );
}

static int move_cost_cart( const item &it, const tripoint &src, const tripoint &dest,
const units::volume &capacity )
{
// to prevent potentially ridiculous number
const int MAX_COST = 500;

// cost to move item into the cart
const int pickup_cost = Pickup::cost_to_move_item( g->u, it );

// cost to move item out of the cart
const int drop_cost = pickup_cost;

// typical flat ground move cost
const int mc_per_tile = 100;

// only free cart capacity
const int cart_capacity = units::to_milliliter( capacity );

const int item_volume = units::to_milliliter( it.volume() );

const double fr = get_capacity_fraction( cart_capacity, item_volume );

// approximation of movement cost between source and destination
const int move_cost = mc_per_tile * rl_dist( src, dest ) * fr;

return std::min( pickup_cost + drop_cost + move_cost, MAX_COST );
}

static int move_cost( const item &it, const tripoint &src, const tripoint &dest )
{
if( g->u.grab_type == OBJECT_VEHICLE ) {
tripoint cart_position = g->u.pos() + g->u.grab_point;

if( const cata::optional<vpart_reference> vp = g->m.veh_at(
cart_position ).part_with_feature( "CARGO", false ) ) {
auto veh = vp->vehicle();
auto vstor = vp->part_index();
auto capacity = veh.free_volume( vstor );

return move_cost_cart( it, src, dest, capacity );
}
}

return move_cost_inv( it, src, dest );
}

static void move_item( item &it, int quantity, const tripoint &src, const tripoint &dest )
{
item leftovers = it;

if( quantity != 0 && it.count_by_charges() ) {
// Reinserting leftovers happens after item removal to avoid stacking issues.
leftovers.charges = it.charges - quantity;
if( leftovers.charges > 0 ) {
it.charges = quantity;
}
} else {
leftovers.charges = 0;
}

// Check that we can pick it up.
if( !it.made_of( LIQUID ) ) {
g->u.mod_moves( -move_cost( it, src, dest ) );
drop_on_map( g->u, { it }, dest );
// Remove from map.
g->m.i_rem( src, &it );
}

// If we didn't pick up a whole stack, put the remainder back where it came from.
if( leftovers.charges > 0 ) {
g->m.add_item_or_charges( src, leftovers );
}
}

void activity_on_turn_move_loot( player_activity &, player &p )
{
const auto &mgr = zone_manager::get_manager();
const auto abspos = g->m.getabs( p.pos() );
const auto &src_set = mgr.get_near( zone_type_id( "LOOT_UNSORTED" ), abspos );

// Nuke the current activity, leaving the backlog alone.
p.activity = player_activity();

for( auto &src : src_set ) {
const auto &src_loc = g->m.getlocal( src );

// skip tiles in IGNORE zone and tiles on fire (to prevent taking out wood off the lit brazier)
// and inaccessible furniture, like filled charcoal kiln
if( mgr.has( zone_type_id( "LOOT_IGNORE" ), src ) ||
g->m.get_field( src_loc, fd_fire ) != nullptr ||
!g->m.can_put_items_ter_furn( src_loc ) ) {
continue;
}

auto items = std::vector<item *>();
for( auto &it : g->m.i_at( src_loc ) ) {
items.push_back( &it );
}

for( auto it : items ) {
const auto id = mgr.get_near_zone_type_for_item( *it, abspos );

// checks whether the item is already on correct loot zone or not
// if it is, we can skip such item, if not we move the item to correct pile
// think empty bag on food pile, after you ate the content
if( !mgr.has( id, src ) ) {
const auto &dest_set = mgr.get_near( id, abspos );

for( auto &dest : dest_set ) {
const auto &dest_loc = g->m.getlocal( dest );

// skip tiles with inaccessible furniture, like filled charcoal kiln
if( !g->m.can_put_items_ter_furn( dest_loc ) ) {
continue;
}

if( g->m.free_volume( dest_loc ) > it->volume() ) {
move_item( *it, it->count_by_charges() ? it->charges : 1, src_loc, dest_loc );
break;
}
}

if( p.moves <= 0 ) {
// Restart activity and break from cycle.
p.assign_activity( activity_id( "ACT_MOVE_LOOT" ) );
return;
}
}
}
}

// If we got here without restarting the activity, it means we're done
}

cata::optional<tripoint> find_best_fire( const std::vector<tripoint> &from, const tripoint &center )
{
cata::optional<tripoint> best_fire;
Expand Down
Loading