Skip to content

Commit

Permalink
Merge pull request #77715 from RenechCDDA/npc_crafting_with_blackjack…
Browse files Browse the repository at this point in the history
…_and_hookers_and_especially_liquids

Camp crafting uses the normal crafting GUI
  • Loading branch information
Maleclypse authored Nov 13, 2024
2 parents 7b05cec + aeefddb commit c7c024a
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 81 deletions.
10 changes: 10 additions & 0 deletions data/json/effects.json
Original file line number Diff line number Diff line change
Expand Up @@ -5152,5 +5152,15 @@
"id": "a_winner_is_u",
"name": [ "Winning!" ],
"//": "Used to display the winning screen upon winning like a winner."
},
{
"type": "effect_type",
"//": "Horrible hack to apply vision flag. Set in C++ basecamp::start_crafting()",
"id": "HACK_camp_vision_for_npc",
"name": [ "" ],
"desc": [ "" ],
"rating": "good",
"flags": [ "EFFECT_LIMB_SCORE_MOD", "CRAFT_IN_DARKNESS", "READ_IN_DARKNESS" ],
"limb_score_mods": [ { "limb_score": "night_vis", "modifier": 10 } ]
}
]
24 changes: 24 additions & 0 deletions src/basecamp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,10 +409,34 @@ std::vector<basecamp_upgrade> basecamp::available_upgrades( const point &dir )
return ret_data;
}

std::unordered_set<recipe_id> basecamp::recipe_deck_all() const
{
std::unordered_set<recipe_id> known_recipes;
for( const npc_ptr &guy : assigned_npcs ) {
if( guy.get() ) {
for( const recipe *rec : guy->get_learned_recipes() ) {
known_recipes.insert( rec->ident() );
}
}
}

for( const auto &exp_data_pair : expansions ) {
for( const auto &provides : exp_data_pair.second.provides ) {
const auto &test_s = recipe_group::get_recipes_by_id( provides.first );
for( const std::pair<const recipe_id, translation> &rec_list : test_s ) {
known_recipes.insert( rec_list.first );
}
}
}

return known_recipes;
}

// recipes and craft support functions
std::map<recipe_id, translation> basecamp::recipe_deck( const point &dir ) const
{
std::map<recipe_id, translation> recipes;

const auto &e = expansions.find( dir );
if( e == expansions.end() ) {
return recipes;
Expand Down
12 changes: 8 additions & 4 deletions src/basecamp.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,8 @@ class basecamp
std::map<recipe_id, translation> recipe_deck( const point &dir ) const;
// from a building
std::map<recipe_id, translation> recipe_deck( const std::string &bldg ) const;
// All recipes known by NPCs stationed here + all recipes provided by all expansions
std::unordered_set<recipe_id> recipe_deck_all() const;
int recipe_batch_max( const recipe &making ) const;
void form_crafting_inventory();
void form_crafting_inventory( map &target_map );
Expand Down Expand Up @@ -331,8 +333,7 @@ class basecamp
void place_results( const item &result );

// mission description functions
void add_available_recipes( mission_data &mission_key, mission_kind kind, const point &dir,
const std::map<recipe_id, translation> &craft_recipes );
void add_available_recipes( mission_data &mission_key, mission_kind kind, const point &dir );

std::string recruit_description( int npc_count ) const;
/// Provides a "guess" for some of the things your gatherers will return with
Expand Down Expand Up @@ -365,7 +366,8 @@ class basecamp
npc_ptr start_mission( const mission_id &miss_id, time_duration duration,
bool must_feed, const std::string &desc, bool group,
const std::vector<item *> &equipment, float exertion_level,
const std::map<skill_id, int> &required_skills = {} );
const std::map<skill_id, int> &required_skills = {},
const npc_ptr &preselected_choice = nullptr );
comp_list start_multi_mission( const mission_id &miss_id,
bool must_feed, const std::string &desc,
// const std::vector<item*>& equipment, // No support for extracting equipment from recipes currently..
Expand All @@ -380,7 +382,9 @@ class basecamp
void start_menial_labor();
void worker_assignment_ui();
void job_assignment_ui();
void start_crafting( const std::string &type, const mission_id &miss_id );
// Assembles a dummy NPC with all available recipes and uses player input on the regular crafting GUI to
// determine what to make, batch size, who to assign to making it, etc.
void start_crafting( const mission_id &miss_id );

/// Called when a companion is sent to cut logs
void start_cut_logs( const mission_id &miss_id, float exertion_level );
Expand Down
23 changes: 15 additions & 8 deletions src/crafting_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,12 @@ static bool cannot_gain_skill_or_prof( const Character &crafter, const recipe &r
namespace
{
struct availability {
explicit availability( Character &_crafter, const recipe *r, int batch_size = 1 ) :
explicit availability( Character &_crafter, const recipe *r, int batch_size = 1,
bool camp_crafting = false, inventory *inventory_override = nullptr ) :
crafter( _crafter ) {
rec = r;
const inventory &inv = crafter.crafting_inventory();
inv_override = inventory_override;
const inventory &inv = camp_crafting ? *inv_override : crafter.crafting_inventory();
auto all_items_filter = r->get_component_filter( recipe_filter_flags::none );
auto no_rotten_filter = r->get_component_filter( recipe_filter_flags::no_rotten );
auto no_favorite_filter = r->get_component_filter( recipe_filter_flags::no_favorite );
Expand All @@ -229,7 +231,7 @@ struct availability {
>= static_cast<int>( rec->get_difficulty( crafter ) * 0.8f );
has_proficiencies = r->character_has_required_proficiencies( crafter );
std::string reason;
if( crafter.is_npc() && !r->npc_can_craft( reason ) ) {
if( crafter.is_npc() && !r->npc_can_craft( reason ) && !camp_crafting ) {
can_craft = false;
} else if( r->is_nested() ) {
can_craft = check_can_craft_nested( _crafter, *r );
Expand Down Expand Up @@ -264,6 +266,7 @@ struct availability {
bool has_proficiencies;
bool has_all_skills;
bool is_nested_category;
inventory *inv_override;
private:
const recipe *rec;
mutable float proficiency_time_maluses = -1.0f;
Expand Down Expand Up @@ -457,7 +460,7 @@ static std::vector<std::string> recipe_info(
recp.has_flag( flag_BLIND_HARD ) ? _( "Hard" ) :
_( "Impossible" ) );

const inventory &crafting_inv = guy.crafting_inventory();
const inventory &crafting_inv = avail.inv_override ? *avail.inv_override : guy.crafting_inventory();
if( recp.result() ) {
const int nearby_amount = crafting_inv.count_item( recp.result() );
std::string nearby_string;
Expand Down Expand Up @@ -1207,7 +1210,8 @@ static bool selection_ok( const std::vector<const recipe *> &list, const int cur
}

std::pair<Character *, const recipe *> select_crafter_and_crafting_recipe( int &batch_size_out,
const recipe_id &goto_recipe, Character *crafter, std::string filterstring )
const recipe_id &goto_recipe, Character *crafter, std::string filterstring, bool camp_crafting,
inventory *inventory_override )
{
if( crafter == nullptr ) {
return {nullptr, nullptr};
Expand Down Expand Up @@ -1344,7 +1348,10 @@ std::pair<Character *, const recipe *> select_crafter_and_crafting_recipe( int &
crafter ) - crafting_group.begin();

// Get everyone's recipes
const recipe_subset &available_recipes = crafter->get_group_available_recipes();
// WTF? If called with dummy npc, we have to do this. Why? Why doesn't Character::get_group_available_recipes()
// already include get_learned_recipes()?
const recipe_subset &available_recipes = camp_crafting ? crafter->get_learned_recipes() :
crafter->get_group_available_recipes();
std::map<character_id, std::map<const recipe *, availability>> guy_availability_cache;
// next line also inserts empty cache for crafter->getID()
std::map<const recipe *, availability> *availability_cache =
Expand Down Expand Up @@ -1582,7 +1589,7 @@ std::pair<Character *, const recipe *> select_crafter_and_crafting_recipe( int &
current.clear();
for( int i = 1; i <= 50; i++ ) {
current.push_back( chosen );
available.emplace_back( *crafter, chosen, i );
available.emplace_back( *crafter, chosen, i, camp_crafting, inventory_override );
}
indent.assign( current.size(), 0 );
} else {
Expand Down Expand Up @@ -1636,7 +1643,7 @@ std::pair<Character *, const recipe *> select_crafter_and_crafting_recipe( int &
// cache recipe availability on first display
for( const recipe *e : current ) {
if( !availability_cache->count( e ) ) {
availability_cache->emplace( e, availability( *crafter, e ) );
availability_cache->emplace( e, availability( *crafter, e, 1, camp_crafting, inventory_override ) );
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/crafting_gui.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "type_id.h"

class Character;
class inventory;
class JsonObject;
class recipe;

Expand All @@ -21,7 +22,8 @@ class recipe;
* Return: if recipe * is not nullptr, then Character * is not nullptr either.
*/
std::pair<Character *, const recipe *> select_crafter_and_crafting_recipe( int &batch_size_out,
const recipe_id &goto_recipe, Character *crafter, std::string filterstring = "" );
const recipe_id &goto_recipe, Character *crafter, std::string filterstring = "",
bool camp_crafting = false, inventory *inventory_override = nullptr );

void load_recipe_category( const JsonObject &jsobj, const std::string &src );
void reset_recipe_categories();
Expand Down
Loading

0 comments on commit c7c024a

Please sign in to comment.