@ -23,6 +23,15 @@
# include <df/building.h>
# include <df/building.h>
# include <df/workshop_type.h>
# include <df/workshop_type.h>
# include <df/unit_misc_trait.h>
# include <df/unit_misc_trait.h>
# include <df/entity_position_responsibility.h>
# include <df/historical_figure.h>
# include <df/historical_entity.h>
# include <df/histfig_entity_link.h>
# include <df/histfig_entity_link_positionst.h>
# include <df/entity_position_assignment.h>
# include <df/entity_position.h>
# include <MiscUtils.h>
using std : : string ;
using std : : string ;
using std : : endl ;
using std : : endl ;
@ -446,21 +455,44 @@ static const struct labor_default default_labor_infos[] = {
/* WAX_WORKING */ { AUTOMATIC , false , 1 , 200 , 0 } ,
/* WAX_WORKING */ { AUTOMATIC , false , 1 , 200 , 0 } ,
} ;
} ;
static const df : : job_skill noble_skills [ ] = {
static const int responsibility_penalties [ ] = {
df : : enums : : job_skill : : APPRAISAL ,
0 , /* LAW_MAKING */
df : : enums : : job_skill : : ORGANIZATION ,
0 , /* LAW_ENFORCEMENT */
df : : enums : : job_skill : : RECORD_KEEPING ,
3000 , /* RECEIVE_DIPLOMATS */
0 , /* MEET_WORKERS */
1000 , /* MANAGE_PRODUCTION */
3000 , /* TRADE */
1000 , /* ACCOUNTING */
0 , /* ESTABLISH_COLONY_TRADE_AGREEMENTS */
0 , /* MAKE_INTRODUCTIONS */
0 , /* MAKE_PEACE_AGREEMENTS */
0 , /* MAKE_TOPIC_AGREEMENTS */
0 , /* COLLECT_TAXES */
0 , /* ESCORT_TAX_COLLECTOR */
0 , /* EXECUTIONS */
0 , /* TAME_EXOTICS */
0 , /* RELIGION */
0 , /* ATTACK_ENEMIES */
0 , /* PATROL_TERRITORY */
0 , /* MILITARY_GOALS */
0 , /* MILITARY_STRATEGY */
0 , /* UPGRADE_SQUAD_EQUIPMENT */
0 , /* EQUIPMENT_MANIFESTS */
0 , /* SORT_AMMUNITION */
0 , /* BUILD_MORALE */
5000 /* HEALTH_MANAGEMENT */
} ;
} ;
struct dwarf_info_t
struct dwarf_info_t
{
{
int highest_skill ;
int highest_skill ;
int total_skill ;
int total_skill ;
bool is_best_noble ;
int mastery_penalty ;
int mastery_penalty ;
int assigned_jobs ;
int assigned_jobs ;
dwarf_state state ;
dwarf_state state ;
bool has_exclusive_labor ;
bool has_exclusive_labor ;
int noble_penalty ; // penalty for assignment due to noble status
bool medical ; // this dwarf has medical responsibility
} ;
} ;
static bool isOptionEnabled ( unsigned flag )
static bool isOptionEnabled ( unsigned flag )
@ -714,15 +746,45 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
std : : vector < dwarf_info_t > dwarf_info ( n_dwarfs ) ;
std : : vector < dwarf_info_t > dwarf_info ( n_dwarfs ) ;
std : : vector < int > best_noble ( ARRAY_COUNT ( noble_skills ) ) ;
std : : vector < int > highest_noble_skill ( ARRAY_COUNT ( noble_skills ) ) ;
std : : vector < int > highest_noble_experience ( ARRAY_COUNT ( noble_skills ) ) ;
// Find total skill and highest skill for each dwarf. More skilled dwarves shouldn't be used for minor tasks.
// Find total skill and highest skill for each dwarf. More skilled dwarves shouldn't be used for minor tasks.
for ( int dwarf = 0 ; dwarf < n_dwarfs ; dwarf + + )
for ( int dwarf = 0 ; dwarf < n_dwarfs ; dwarf + + )
{
{
assert ( dwarfs [ dwarf ] - > status . souls . size ( ) > 0 ) ;
// assert(dwarfs[dwarf]->status.souls.size() > 0);
// assert fails can cause DF to crash, so don't do that
if ( dwarfs [ dwarf ] - > status . souls . size ( ) < = 0 )
continue ;
// compute noble penalty
int noble_penalty = 0 ;
df : : historical_figure * hf = df : : historical_figure : : find ( dwarfs [ dwarf ] - > hist_figure_id ) ;
for ( int i = 0 ; i < hf - > entity_links . size ( ) ; i + + ) {
df : : histfig_entity_link * hfelink = hf - > entity_links . at ( i ) ;
if ( hfelink - > getType ( ) = = df : : histfig_entity_link_type : : POSITION ) {
df : : histfig_entity_link_positionst * epos =
( df : : histfig_entity_link_positionst * ) hfelink ;
df : : historical_entity * entity = df : : historical_entity : : find ( epos - > entity_id ) ;
if ( ! entity )
continue ;
df : : entity_position_assignment * assignment = binsearch_in_vector ( entity - > positions . assignments , epos - > assignment_id ) ;
if ( ! assignment )
continue ;
df : : entity_position * position = binsearch_in_vector ( entity - > positions . own , assignment - > position_id ) ;
if ( ! position )
continue ;
for ( int n = 0 ; n < 25 ; n + + )
if ( position - > responsibilities [ n ] )
noble_penalty + = responsibility_penalties [ n ] ;
if ( position - > responsibilities [ df : : entity_position_responsibility : : HEALTH_MANAGEMENT ] )
dwarf_info [ dwarf ] . medical = true ;
}
}
for ( auto s = dwarfs [ dwarf ] - > status . souls [ 0 ] - > skills . begin ( ) ; s ! = dwarfs [ dwarf ] - > status . souls [ 0 ] - > skills . end ( ) ; s + + )
for ( auto s = dwarfs [ dwarf ] - > status . souls [ 0 ] - > skills . begin ( ) ; s ! = dwarfs [ dwarf ] - > status . souls [ 0 ] - > skills . end ( ) ; s + + )
{
{
@ -733,30 +795,6 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
int skill_level = ( * s ) - > rating ;
int skill_level = ( * s ) - > rating ;
int skill_experience = ( * s ) - > experience ;
int skill_experience = ( * s ) - > experience ;
// Track the dwarfs with the best Appraisal, Organization, and Record Keeping skills.
// They are likely to have appointed noble positions, so should be kept free where possible.
int noble_skill_id = - 1 ;
for ( int i = 0 ; i < ARRAY_COUNT ( noble_skills ) ; i + + )
{
if ( skill = = noble_skills [ i ] )
noble_skill_id = i ;
}
if ( noble_skill_id > = 0 )
{
assert ( noble_skill_id < ARRAY_COUNT ( noble_skills ) ) ;
if ( highest_noble_skill [ noble_skill_id ] < skill_level | |
( highest_noble_skill [ noble_skill_id ] = = skill_level & &
highest_noble_experience [ noble_skill_id ] < skill_experience ) )
{
highest_noble_skill [ noble_skill_id ] = skill_level ;
highest_noble_experience [ noble_skill_id ] = skill_experience ;
best_noble [ noble_skill_id ] = dwarf ;
}
}
// Track total & highest skill among normal/medical skills. (We don't care about personal or social skills.)
// Track total & highest skill among normal/medical skills. (We don't care about personal or social skills.)
if ( skill_class ! = df : : enums : : job_skill_class : : Normal & & skill_class ! = df : : enums : : job_skill_class : : Medical )
if ( skill_class ! = df : : enums : : job_skill_class : : Normal & & skill_class ! = df : : enums : : job_skill_class : : Medical )
@ -768,24 +806,13 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
}
}
}
}
// Mark the best nobles, so we try to keep them non-busy. (It would be better to find the actual assigned nobles.)
for ( int i = 0 ; i < ARRAY_COUNT ( noble_skills ) ; i + + )
{
assert ( best_noble [ i ] > = 0 ) ;
assert ( best_noble [ i ] < n_dwarfs ) ;
dwarf_info [ best_noble [ i ] ] . is_best_noble = true ;
}
// Calculate a base penalty for using each dwarf for a task he isn't good at.
// Calculate a base penalty for using each dwarf for a task he isn't good at.
for ( int dwarf = 0 ; dwarf < n_dwarfs ; dwarf + + )
for ( int dwarf = 0 ; dwarf < n_dwarfs ; dwarf + + )
{
{
dwarf_info [ dwarf ] . mastery_penalty - = 40 * dwarf_info [ dwarf ] . highest_skill ;
dwarf_info [ dwarf ] . mastery_penalty - = 40 * dwarf_info [ dwarf ] . highest_skill ;
dwarf_info [ dwarf ] . mastery_penalty - = 10 * dwarf_info [ dwarf ] . total_skill ;
dwarf_info [ dwarf ] . mastery_penalty - = 10 * dwarf_info [ dwarf ] . total_skill ;
if ( dwarf_info [ dwarf ] . is_best_noble )
dwarf_info [ dwarf ] . mastery_penalty - = dwarf_info [ dwarf ] . noble_penalty ;
dwarf_info [ dwarf ] . mastery_penalty - = 250 ;
for ( int labor = ENUM_FIRST_ITEM ( unit_labor ) ; labor < = ENUM_LAST_ITEM ( unit_labor ) ; labor + + )
for ( int labor = ENUM_FIRST_ITEM ( unit_labor ) ; labor < = ENUM_LAST_ITEM ( unit_labor ) ; labor + + )
{
{
@ -1032,6 +1059,7 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
* Note that only idle and busy dwarfs count towards the number of dwarfs . " Other " dwarfs
* Note that only idle and busy dwarfs count towards the number of dwarfs . " Other " dwarfs
* ( sleeping , eating , on break , etc . ) will have labors assigned , but will not be counted .
* ( sleeping , eating , on break , etc . ) will have labors assigned , but will not be counted .
* Military and children / nobles will not have labors assigned .
* Military and children / nobles will not have labors assigned .
* Dwarfs with the " health management " responsibility are always assigned DIAGNOSIS .
*/
*/
for ( int i = 0 ; i < candidates . size ( ) & & labor_infos [ labor ] . active_dwarfs < max_dwarfs ; i + + )
for ( int i = 0 ; i < candidates . size ( ) & & labor_infos [ labor ] . active_dwarfs < max_dwarfs ; i + + )
{
{
@ -1040,6 +1068,8 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
assert ( dwarf > = 0 ) ;
assert ( dwarf > = 0 ) ;
assert ( dwarf < n_dwarfs ) ;
assert ( dwarf < n_dwarfs ) ;
bool preferred_dwarf = false ;
bool preferred_dwarf = false ;
if ( want_idle_dwarf & & dwarf_info [ dwarf ] . state = = IDLE )
if ( want_idle_dwarf & & dwarf_info [ dwarf ] . state = = IDLE )
preferred_dwarf = true ;
preferred_dwarf = true ;
@ -1047,6 +1077,8 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
preferred_dwarf = true ;
preferred_dwarf = true ;
if ( previously_enabled [ dwarf ] & & labor_infos [ labor ] . is_exclusive )
if ( previously_enabled [ dwarf ] & & labor_infos [ labor ] . is_exclusive )
preferred_dwarf = true ;
preferred_dwarf = true ;
if ( dwarf_info [ dwarf ] . medical & & labor = = df : : unit_labor : : DIAGNOSE )
preferred_dwarf = true ;
if ( labor_infos [ labor ] . active_dwarfs > = min_dwarfs & & ! preferred_dwarf )
if ( labor_infos [ labor ] . active_dwarfs > = min_dwarfs & & ! preferred_dwarf )
continue ;
continue ;