From 31dcaecc1e6d249ce857fe9c7ca380eb1a95d070 Mon Sep 17 00:00:00 2001 From: Kevin Granade Date: Wed, 22 Apr 2020 01:11:37 +0000 Subject: [PATCH] Extract character oracle to its own module --- src/behavior_oracle.cpp | 119 ++------------------------------------- src/behavior_oracle.h | 23 -------- src/character_oracle.cpp | 116 ++++++++++++++++++++++++++++++++++++++ src/character_oracle.h | 34 +++++++++++ 4 files changed, 155 insertions(+), 137 deletions(-) create mode 100644 src/character_oracle.cpp create mode 100644 src/character_oracle.h diff --git a/src/behavior_oracle.cpp b/src/behavior_oracle.cpp index cd37a837a55b9..a2f49f82e643e 100644 --- a/src/behavior_oracle.cpp +++ b/src/behavior_oracle.cpp @@ -1,22 +1,12 @@ #include "behavior_oracle.h" -#include #include -#include -#include +#include +#include #include "behavior.h" -#include "bodypart.h" -#include "character.h" -#include "inventory.h" -#include "item.h" -#include "itype.h" -#include "player.h" -#include "ret_val.h" -#include "value_ptr.h" -#include "weather.h" - -static const std::string flag_FIRESTARTER( "FIRESTARTER" ); +#include "character_oracle.h" +#include "monster_oracle.h" namespace behavior { @@ -26,106 +16,6 @@ status_t return_running( const oracle_t * ) return running; } -// To avoid a local minima when the character has access to warmth in a shelter but gets cold -// when they go outside, this method needs to only alert when travel time to known shelter -// approaches time to freeze. -status_t character_oracle_t::needs_warmth_badly() const -{ - const player *p = dynamic_cast( subject ); - // Use player::temp_conv to predict whether the Character is "in trouble". - for( const body_part bp : all_body_parts ) { - if( p->temp_conv[ bp ] <= BODYTEMP_VERY_COLD ) { - return running; - } - } - return success; -} - -status_t character_oracle_t::needs_water_badly() const -{ - // Check thirst threshold. - if( subject->get_thirst() > 520 ) { - return running; - } - return success; -} - -status_t character_oracle_t::needs_food_badly() const -{ - // Check hunger threshold. - if( subject->get_hunger() >= 300 && subject->get_starvation() > 2500 ) { - return running; - } - return success; -} - -status_t character_oracle_t::can_wear_warmer_clothes() const -{ - const player *p = dynamic_cast( subject ); - // Check inventory for wearable warmer clothes, greedily. - // Don't consider swapping clothes yet, just evaluate adding clothes. - for( const auto &i : subject->inv.const_slice() ) { - const item &candidate = i->front(); - if( candidate.get_warmth() > 0 || p->can_wear( candidate ).success() ) { - return running; - } - } - return failure; -} - -status_t character_oracle_t::can_make_fire() const -{ - // Check inventory for firemaking tools and fuel - bool tool = false; - bool fuel = false; - for( const auto &i : subject->inv.const_slice() ) { - const item &candidate = i->front(); - if( candidate.has_flag( flag_FIRESTARTER ) ) { - tool = true; - if( fuel ) { - return running; - } - } else if( candidate.flammable() ) { - fuel = true; - if( tool ) { - return running; - } - } - } - return success; -} - -status_t character_oracle_t::can_take_shelter() const -{ - // See if we know about some shelter - // Don't know how yet. - return failure; -} - -status_t character_oracle_t::has_water() const -{ - // Check if we know about water somewhere - bool found_water = subject->inv.has_item_with( []( const item & cand ) { - return cand.is_food() && cand.get_comestible()->quench > 0; - } ); - return found_water ? running : failure; -} - -status_t character_oracle_t::has_food() const -{ - // Check if we know about food somewhere - bool found_food = subject->inv.has_item_with( []( const item & cand ) { - return cand.is_food() && cand.get_comestible()->has_calories(); - } ); - return found_food ? running : failure; -} - -// predicate_map doesn't have to live here, but for the time being it's pretty pointless -// to break it out into it's own module. -// In principle this can be populated with any function that has a matching signature. -// In practice each element is a pointer-to-function to one of the above methods so that -// They can have provlidged access to the subject's internals. - // Just a little helper to make populating predicate_map slightly less gross. static std::function < status_t( const oracle_t * ) > make_function( status_t ( character_oracle_t::* fun )() const ) @@ -144,4 +34,5 @@ std::unordered_map> pre { "npc_has_food", make_function( &character_oracle_t::has_food ) } } }; + } // namespace behavior diff --git a/src/behavior_oracle.h b/src/behavior_oracle.h index 8f35266a64fef..79171642bb53a 100644 --- a/src/behavior_oracle.h +++ b/src/behavior_oracle.h @@ -6,8 +6,6 @@ #include #include -class Character; - namespace behavior { enum status_t : char; @@ -25,27 +23,6 @@ class oracle_t status_t return_running( const oracle_t * ); -class character_oracle_t : public oracle_t -{ - public: - character_oracle_t( const Character *subject ) { - this->subject = subject; - } - /** - * Predicates used by AI to determine goals. - */ - status_t needs_warmth_badly() const; - status_t needs_water_badly() const; - status_t needs_food_badly() const; - status_t can_wear_warmer_clothes() const; - status_t can_make_fire() const; - status_t can_take_shelter() const; - status_t has_water() const; - status_t has_food() const; - private: - const Character *subject; -}; - extern std::unordered_map> predicate_map; } // namespace behavior diff --git a/src/character_oracle.cpp b/src/character_oracle.cpp new file mode 100644 index 0000000000000..aece481d2d430 --- /dev/null +++ b/src/character_oracle.cpp @@ -0,0 +1,116 @@ +#include +#include +#include + +#include "behavior.h" +#include "character_oracle.h" +#include "bodypart.h" +#include "character.h" +#include "inventory.h" +#include "item.h" +#include "itype.h" +#include "player.h" +#include "ret_val.h" +#include "value_ptr.h" +#include "weather.h" + +static const std::string flag_FIRESTARTER( "FIRESTARTER" ); + +namespace behavior +{ + +// To avoid a local minima when the character has access to warmth in a shelter but gets cold +// when they go outside, this method needs to only alert when travel time to known shelter +// approaches time to freeze. +status_t character_oracle_t::needs_warmth_badly() const +{ + const player *p = dynamic_cast( subject ); + // Use player::temp_conv to predict whether the Character is "in trouble". + for( const body_part bp : all_body_parts ) { + if( p->temp_conv[ bp ] <= BODYTEMP_VERY_COLD ) { + return running; + } + } + return success; +} + +status_t character_oracle_t::needs_water_badly() const +{ + // Check thirst threshold. + if( subject->get_thirst() > 520 ) { + return running; + } + return success; +} + +status_t character_oracle_t::needs_food_badly() const +{ + // Check hunger threshold. + if( subject->get_hunger() >= 300 && subject->get_starvation() > 2500 ) { + return running; + } + return success; +} + +status_t character_oracle_t::can_wear_warmer_clothes() const +{ + const player *p = dynamic_cast( subject ); + // Check inventory for wearable warmer clothes, greedily. + // Don't consider swapping clothes yet, just evaluate adding clothes. + for( const auto &i : subject->inv.const_slice() ) { + const item &candidate = i->front(); + if( candidate.get_warmth() > 0 || p->can_wear( candidate ).success() ) { + return running; + } + } + return failure; +} + +status_t character_oracle_t::can_make_fire() const +{ + // Check inventory for firemaking tools and fuel + bool tool = false; + bool fuel = false; + for( const auto &i : subject->inv.const_slice() ) { + const item &candidate = i->front(); + if( candidate.has_flag( flag_FIRESTARTER ) ) { + tool = true; + if( fuel ) { + return running; + } + } else if( candidate.flammable() ) { + fuel = true; + if( tool ) { + return running; + } + } + } + return success; +} + +status_t character_oracle_t::can_take_shelter() const +{ + // See if we know about some shelter + // Don't know how yet. + return failure; +} + +status_t character_oracle_t::has_water() const +{ + // Check if we know about water somewhere + bool found_water = subject->inv.has_item_with( []( const item & cand ) { + return cand.is_food() && cand.get_comestible()->quench > 0; + } ); + return found_water ? running : failure; +} + +status_t character_oracle_t::has_food() const +{ + // Check if we know about food somewhere + bool found_food = subject->inv.has_item_with( []( const item & cand ) { + return cand.is_food() && cand.get_comestible()->has_calories(); + } ); + return found_food ? running : failure; +} + +} // namespace behavior diff --git a/src/character_oracle.h b/src/character_oracle.h new file mode 100644 index 0000000000000..01781694f20a7 --- /dev/null +++ b/src/character_oracle.h @@ -0,0 +1,34 @@ +#pragma once +#ifndef CATA_SRC_CHARACTER_ORACLE_H +#define CATA_SRC_CHARACTER_ORACLE_H + +#include "behavior_oracle.h" + +class Character; + +namespace behavior +{ + +class character_oracle_t : public oracle_t +{ + public: + character_oracle_t( const Character *subject ) { + this->subject = subject; + } + /** + * Predicates used by AI to determine goals. + */ + status_t needs_warmth_badly() const; + status_t needs_water_badly() const; + status_t needs_food_badly() const; + status_t can_wear_warmer_clothes() const; + status_t can_make_fire() const; + status_t can_take_shelter() const; + status_t has_water() const; + status_t has_food() const; + private: + const Character *subject; +}; + +} //namespace behavior +#endif // CATA_SRC_CHARACTER_ORACLE_H