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

Display all (unknown) recipes option in crafting GUI #279

Merged
merged 1 commit into from Apr 22, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions data/raw/keybindings.json
Expand Up @@ -551,6 +551,13 @@
"name": "Batch crafting",
"bindings": [ { "input_method": "keyboard", "key": [ "b" ] } ]
},
{
"type": "keybinding",
"id": "TOGGLE_UNAVAILABLE",
"category": "CRAFTING",
"name": "Hide/show unavailable",
"bindings": [ { "input_method": "keyboard", "key": "u" } ]
},
{
"type": "keybinding",
"id": "SCROLL_UP",
Expand Down
30 changes: 30 additions & 0 deletions src/crafting.cpp
Expand Up @@ -2334,3 +2334,33 @@ bench_location find_best_bench( const player &p, const item &craft )

return bench_location{best_type, best_loc};
}

namespace crafting
{

std::set<itype_id> get_books_for_recipe( const Character &c, const inventory &crafting_inv,
const recipe *r )
{
std::set<itype_id> book_ids;
const int skill_level = c.get_skill_level( r->skill_used );
for( auto &book_lvl : r->booksets ) {
itype_id book_id = book_lvl.first;
int required_skill_level = book_lvl.second;
if( skill_level >= required_skill_level && crafting_inv.amount_of( book_id ) > 0 ) {
book_ids.insert( book_id );
}
}
return book_ids;
}

std::set<itype_id> get_books_for_recipe( const recipe *r )
{
std::set<itype_id> book_ids;
std::transform( r->booksets.begin(), r->booksets.end(), std::inserter( book_ids, book_ids.end() ),
[]( const std::pair<itype_id, int> &pr ) {
return pr.first;
} );
return book_ids;
}

} // namespace crafting
25 changes: 25 additions & 0 deletions src/crafting.h
Expand Up @@ -3,12 +3,17 @@
#define CATA_SRC_CRAFTING_H

#include <list>
#include <set>
#include "point.h"

class Character;
class inventory;
class item;
class player;
class recipe;

using itype_id = std::string;

enum class craft_flags : int {
none = 0,
start_only = 1, // Only require 5% (plus remainder) of tool charges
Expand Down Expand Up @@ -47,4 +52,24 @@ float crafting_speed_multiplier( const player &p, const recipe &rec, bool in_pro
float crafting_speed_multiplier( const player &p, const item &craft, const bench_location &bench );
void complete_craft( player &p, item &craft, const bench_location &bench );

namespace crafting
{

/**
* Returns the set of book types in crafting_inv that provide the
* given recipe.
* @param c Character whose skills are used to limit the available recipes
* @param crafting_inv Current available items that may contain readable books
* @param r Recipe to search for in the available books
*/
std::set<itype_id> get_books_for_recipe( const Character &c, const inventory &crafting_inv,
const recipe *r );

/**
* Returns the set of book types that provide the given recipe.
*/
std::set<itype_id> get_books_for_recipe( const recipe *r );

} // namespace crafting

#endif // CATA_SRC_CRAFTING_H
124 changes: 82 additions & 42 deletions src/crafting_gui.cpp

Large diffs are not rendered by default.

19 changes: 2 additions & 17 deletions src/player.cpp
Expand Up @@ -3799,21 +3799,6 @@ recipe_subset player::get_recipes_from_books( const inventory &crafting_inv ) co
return res;
}

std::set<itype_id> player::get_books_for_recipe( const inventory &crafting_inv,
const recipe *r ) const
{
std::set<itype_id> book_ids;
const int skill_level = get_skill_level( r->skill_used );
for( auto &book_lvl : r->booksets ) {
itype_id book_id = book_lvl.first;
int required_skill_level = book_lvl.second;
if( skill_level >= required_skill_level && crafting_inv.amount_of( book_id ) > 0 ) {
book_ids.insert( book_id );
}
}
return book_ids;
}

recipe_subset player::get_available_recipes( const inventory &crafting_inv,
const std::vector<npc *> *helpers ) const
{
Expand Down Expand Up @@ -4190,7 +4175,7 @@ bool player::can_decomp_learn( const recipe &rec ) const

bool player::knows_recipe( const recipe *rec ) const
{
return get_learned_recipes().contains( rec );
return get_learned_recipes().contains( *rec );
}

int player::has_recipe( const recipe *r, const inventory &crafting_inv,
Expand All @@ -4205,7 +4190,7 @@ int player::has_recipe( const recipe *r, const inventory &crafting_inv,
}

const auto available = get_available_recipes( crafting_inv, &helpers );
return available.contains( r ) ? available.get_custom_difficulty( r ) : -1;
return available.contains( *r ) ? available.get_custom_difficulty( r ) : -1;
}

void player::learn_recipe( const recipe *const rec )
Expand Down
8 changes: 0 additions & 8 deletions src/player.h
Expand Up @@ -565,14 +565,6 @@ class player : public Character
*/
recipe_subset get_available_recipes( const inventory &crafting_inv,
const std::vector<npc *> *helpers = nullptr ) const;
/**
* Returns the set of book types in crafting_inv that provide the
* given recipe.
* @param crafting_inv Current available items that may contain readable books
* @param r Recipe to search for in the available books
*/
std::set<itype_id> get_books_for_recipe( const inventory &crafting_inv,
const recipe *r ) const;

// crafting.cpp
float morale_crafting_speed_multiplier( const recipe &rec ) const;
Expand Down
1 change: 1 addition & 0 deletions src/recipe_dictionary.cpp
Expand Up @@ -513,6 +513,7 @@ void recipe_subset::include( const recipe *r, int custom_difficulty )
}
// insert the recipe
recipes.insert( r );
ids.insert( r->ident() );
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/recipe_dictionary.h
Expand Up @@ -101,10 +101,8 @@ class recipe_subset
}

/** Check if the subset contains a recipe with the specified id. */
bool contains( const recipe *r ) const {
return std::any_of( recipes.begin(), recipes.end(), [r]( const recipe * elem ) {
return elem->ident() == r->ident();
} );
bool contains( const recipe &r ) const {
return ids.count( r.ident() ) != 0;
}

/**
Expand Down Expand Up @@ -166,6 +164,7 @@ class recipe_subset
component.clear();
category.clear();
recipes.clear();
ids.clear();
}

std::set<const recipe *>::const_iterator begin() const {
Expand All @@ -181,6 +180,7 @@ class recipe_subset
std::map<const recipe *, int> difficulties;
std::map<std::string, std::set<const recipe *>> category;
std::map<itype_id, std::set<const recipe *>> component;
std::unordered_set<recipe_id> ids;
};

void serialize( const recipe_subset &value, JsonOut &jsout );
Expand Down
18 changes: 9 additions & 9 deletions tests/crafting_test.cpp
Expand Up @@ -48,7 +48,7 @@ TEST_CASE( "recipe_subset" )

THEN( "it's in the subset" ) {
CHECK( subset.size() == 1 );
CHECK( subset.contains( r ) );
CHECK( subset.contains( *r ) );
}
THEN( "it has its default difficulty" ) {
CHECK( subset.get_custom_difficulty( r ) == r->difficulty );
Expand All @@ -70,7 +70,7 @@ TEST_CASE( "recipe_subset" )

THEN( "it's no longer in the subset" ) {
CHECK( subset.size() == 0 );
CHECK_FALSE( subset.contains( r ) );
CHECK_FALSE( subset.contains( *r ) );
}
}
}
Expand Down Expand Up @@ -179,7 +179,7 @@ TEST_CASE( "available_recipes", "[recipes]" )

AND_WHEN( "he searches for the recipe in the book" ) {
THEN( "he finds it!" ) {
CHECK( dummy.get_recipes_from_books( dummy.inv ).contains( r ) );
CHECK( dummy.get_recipes_from_books( dummy.inv ).contains( *r ) );
}
THEN( "it's easier in the book" ) {
CHECK( dummy.get_recipes_from_books( dummy.inv ).get_custom_difficulty( r ) == 2 );
Expand All @@ -192,7 +192,7 @@ TEST_CASE( "available_recipes", "[recipes]" )
dummy.i_rem( &craftbook );

THEN( "he can't brew the recipe anymore" ) {
CHECK_FALSE( dummy.get_recipes_from_books( dummy.inv ).contains( r ) );
CHECK_FALSE( dummy.get_recipes_from_books( dummy.inv ).contains( *r ) );
}
}
}
Expand All @@ -209,7 +209,7 @@ TEST_CASE( "available_recipes", "[recipes]" )

AND_WHEN( "he searches for the recipe in the tablet" ) {
THEN( "he finds it!" ) {
CHECK( dummy.get_recipes_from_books( dummy.inv ).contains( r2 ) );
CHECK( dummy.get_recipes_from_books( dummy.inv ).contains( *r2 ) );
}
THEN( "he still hasn't the recipe memorized" ) {
CHECK_FALSE( dummy.knows_recipe( r2 ) );
Expand All @@ -219,7 +219,7 @@ TEST_CASE( "available_recipes", "[recipes]" )
dummy.i_rem( &eink );

THEN( "he can't make the recipe anymore" ) {
CHECK_FALSE( dummy.get_recipes_from_books( dummy.inv ).contains( r2 ) );
CHECK_FALSE( dummy.get_recipes_from_books( dummy.inv ).contains( *r2 ) );
}
}
}
Expand Down Expand Up @@ -249,7 +249,7 @@ TEST_CASE( "crafting_with_a_companion", "[.]" )
const auto helpers( dummy.get_crafting_helpers() );

REQUIRE( std::find( helpers.begin(), helpers.end(), &who ) != helpers.end() );
REQUIRE_FALSE( dummy.get_available_recipes( dummy.inv, &helpers ).contains( r ) );
REQUIRE_FALSE( dummy.get_available_recipes( dummy.inv, &helpers ).contains( *r ) );
REQUIRE_FALSE( who.knows_recipe( r ) );

WHEN( "you have the required skill" ) {
Expand All @@ -259,7 +259,7 @@ TEST_CASE( "crafting_with_a_companion", "[.]" )
who.learn_recipe( r );

THEN( "he helps you" ) {
CHECK( dummy.get_available_recipes( dummy.inv, &helpers ).contains( r ) );
CHECK( dummy.get_available_recipes( dummy.inv, &helpers ).contains( *r ) );
}
}
AND_WHEN( "he has the cookbook in his inventory" ) {
Expand All @@ -269,7 +269,7 @@ TEST_CASE( "crafting_with_a_companion", "[.]" )
REQUIRE_FALSE( cookbook.type->book->recipes.empty() );

THEN( "he shows it to you" ) {
CHECK( dummy.get_available_recipes( dummy.inv, &helpers ).contains( r ) );
CHECK( dummy.get_available_recipes( dummy.inv, &helpers ).contains( *r ) );
}
}
}
Expand Down