@@ -64,12 +64,15 @@ distribution.
6464#include " df/interaction_profilest.h"
6565#include " df/item.h"
6666#include " df/job.h"
67+ #include " df/need_type.h"
6768#include " df/nemesis_record.h"
6869#include " df/personality_goalst.h"
70+ #include " df/personality_needst.h"
6971#include " df/plotinfost.h"
7072#include " df/proj_unitst.h"
7173#include " df/reputation_profilest.h"
7274#include " df/syndrome.h"
75+ #include " df/squad.h"
7376#include " df/tile_occupancy.h"
7477#include " df/training_assignment.h"
7578#include " df/unit.h"
@@ -89,6 +92,7 @@ distribution.
8992#include " df/world_site.h"
9093
9194#include < algorithm>
95+ #include < bitset>
9296#include < cstring>
9397#include < functional>
9498#include < map>
@@ -2017,6 +2021,92 @@ df::activity_event *Units::getMainSocialEvent(df::unit *unit) {
20172021 return entry->events [entry->events .size () - 1 ];
20182022}
20192023
2024+ int32_t Units::getFocusPenalty (df::unit* unit, need_types_set need_types) {
2025+ CHECK_NULL_POINTER (unit);
2026+
2027+ int max_penalty = INT_MAX;
2028+ auto & needs = unit->status .current_soul ->personality .needs ;
2029+ for (auto const need : needs) {
2030+ if (need_types.test (need->id )) {
2031+ max_penalty = min (max_penalty, need->focus_level );
2032+ }
2033+ }
2034+ return max_penalty;
2035+ }
2036+
2037+ int32_t Units::getFocusPenalty (df::unit* unit, df::need_type need_type) {
2038+ auto need_types = need_types_set ().set (need_type);
2039+ return getFocusPenalty (unit, need_types);
2040+ }
2041+
2042+ // reverse engineered from unitst::have_unbailable_sp_activities (partial implementation)
2043+ bool Units::unbailableSocialActivity (df::unit *unit)
2044+ {
2045+ // these can become constexpr with C++23
2046+ static const need_types_set pray_needs = need_types_set ()
2047+ .set (df::need_type::PrayOrMeditate);
2048+
2049+ static const need_types_set socialize_needs = need_types_set ()
2050+ .set (df::need_type::Socialize)
2051+ .set (df::need_type::BeCreative)
2052+ .set (df::need_type::Excitement)
2053+ .set (df::need_type::AdmireArt);
2054+
2055+ static const need_types_set read_needs = need_types_set ()
2056+ .set (df::need_type::ThinkAbstractly)
2057+ .set (df::need_type::LearnSomething);
2058+
2059+ CHECK_NULL_POINTER (unit);
2060+
2061+ if (unit->social_activities .empty ()) {
2062+ return false ;
2063+ } else if (unit->social_activities .size () > 1 ) {
2064+ return true ; // is this even possible?
2065+ }
2066+
2067+ auto activity = df::activity_entry::find (unit->social_activities [0 ]);
2068+ if (activity) {
2069+ using df::activity_entry_type;
2070+ switch (activity->type ) {
2071+ case activity_entry_type::Socialize:
2072+ return getFocusPenalty (unit, socialize_needs) <= -10000 ;
2073+ case activity_entry_type::Prayer:
2074+ return getFocusPenalty (unit, pray_needs) <= -10000 ;
2075+ case activity_entry_type::Read:
2076+ return getFocusPenalty (unit, read_needs) <= -10000 ;
2077+ default :
2078+ // consider unhandled activities as uninterruptible
2079+ return true ;
2080+ }
2081+ }
2082+ // this should never happen
2083+ return false ;
2084+ }
2085+
2086+ bool Units::isJobAvailable (df::unit *unit, bool preserve_social = false ){
2087+ if (unit->job .current_job )
2088+ return false ;
2089+ if (unit->flags1 .bits .caged || unit->flags1 .bits .chained )
2090+ return false ;
2091+ if (unit->individual_drills .size () > 0 ) {
2092+ if (unit->individual_drills .size () > 1 )
2093+ return false ; // this is even possible
2094+ auto activity = df::activity_entry::find (unit->individual_drills [0 ]);
2095+ if (activity && (activity->type == df::activity_entry_type::FillServiceOrder))
2096+ return false ;
2097+ }
2098+ if (unbailableSocialActivity (unit))
2099+ return false ;
2100+ if (preserve_social && unit->social_activities .size () > 0 )
2101+ return false ;
2102+ if (unit->military .squad_id != -1 ) {
2103+ auto squad = df::squad::find (unit->military .squad_id );
2104+ if (squad)
2105+ return squad->orders .size () == 0 && squad->activity == -1 ;
2106+ }
2107+ return true ;
2108+ }
2109+
20202110// 50000 and up is level 0, 25000 and up is level 1, etc.
20212111const vector<int32_t > Units::stress_cutoffs {50000 , 25000 , 10000 , -10000 , -25000 , -50000 , -100000 };
20222112
0 commit comments