2017-05-27 15:47:18 -06:00
# include "Console.h"
# include "Core.h"
# include "DataDefs.h"
# include "Export.h"
# include "PluginManager.h"
# include "modules/Filesystem.h"
# include "modules/Materials.h"
2018-06-14 11:22:40 -06:00
# include "json/json.h"
2017-05-27 15:47:18 -06:00
# include "df/building.h"
# include "df/historical_figure.h"
# include "df/itemdef_ammost.h"
# include "df/itemdef_armorst.h"
# include "df/itemdef_foodst.h"
# include "df/itemdef_glovesst.h"
# include "df/itemdef_helmst.h"
# include "df/itemdef_instrumentst.h"
# include "df/itemdef_pantsst.h"
# include "df/itemdef_shieldst.h"
# include "df/itemdef_shoesst.h"
# include "df/itemdef_siegeammost.h"
# include "df/itemdef_toolst.h"
# include "df/itemdef_toyst.h"
# include "df/itemdef_trapcompst.h"
# include "df/itemdef_weaponst.h"
# include "df/job_item.h"
# include "df/manager_order.h"
# include "df/manager_order_condition_item.h"
# include "df/manager_order_condition_order.h"
2021-07-18 23:55:57 -06:00
# include "df/reaction.h"
# include "df/reaction_reagent.h"
2017-05-27 15:47:18 -06:00
# include "df/world.h"
using namespace DFHack ;
using namespace df : : enums ;
DFHACK_PLUGIN ( " orders " ) ;
REQUIRE_GLOBAL ( world ) ;
2021-09-07 23:05:47 -06:00
static const std : : string ORDERS_DIR = " dfhack-config/orders " ;
2022-07-06 08:03:29 -06:00
static const std : : string ORDERS_LIBRARY_DIR = " dfhack-config/orders/library " ;
2021-09-07 23:05:47 -06:00
2017-05-27 15:47:18 -06:00
static command_result orders_command ( color_ostream & out , std : : vector < std : : string > & parameters ) ;
DFhackCExport command_result plugin_init ( color_ostream & out , std : : vector < PluginCommand > & commands )
{
commands . push_back ( PluginCommand (
" orders " ,
" Manipulate manager orders. " ,
orders_command ,
false ,
" orders - Manipulate manager orders \n "
2021-09-07 23:05:47 -06:00
" orders list \n "
2022-07-06 08:03:29 -06:00
" Shows the list of previously exported orders. \n "
2017-05-27 15:47:18 -06:00
" orders export [name] \n "
" Exports the current list of manager orders to a file named dfhack-config/orders/[name].json. \n "
" orders import [name] \n "
" Imports manager orders from a file named dfhack-config/orders/[name].json. \n "
2017-07-02 15:00:45 -06:00
" orders clear \n "
" Deletes all manager orders in the current embark. \n "
2021-09-01 14:04:23 -06:00
" orders sort \n "
" Sorts current manager orders by repeat frequency so they don't conflict. \n "
2017-05-27 15:47:18 -06:00
) ) ;
return CR_OK ;
}
DFhackCExport command_result plugin_shutdown ( color_ostream & out )
{
return CR_OK ;
}
2021-09-07 23:05:47 -06:00
static command_result orders_list_command ( color_ostream & out ) ;
2017-05-27 15:47:18 -06:00
static command_result orders_export_command ( color_ostream & out , const std : : string & name ) ;
static command_result orders_import_command ( color_ostream & out , const std : : string & name ) ;
2017-07-02 15:00:45 -06:00
static command_result orders_clear_command ( color_ostream & out ) ;
2021-09-01 14:04:23 -06:00
static command_result orders_sort_command ( color_ostream & out ) ;
2017-05-27 15:47:18 -06:00
static command_result orders_command ( color_ostream & out , std : : vector < std : : string > & parameters )
{
class color_ostream_resetter
{
color_ostream & out ;
public :
color_ostream_resetter ( color_ostream & out ) : out ( out ) { }
~ color_ostream_resetter ( ) { out . reset_color ( ) ; }
} resetter ( out ) ;
if ( parameters . empty ( ) )
{
return CR_WRONG_USAGE ;
}
2021-09-07 23:05:47 -06:00
if ( parameters [ 0 ] = = " list " )
{
return orders_list_command ( out ) ;
}
2017-05-27 15:47:18 -06:00
if ( parameters [ 0 ] = = " export " & & parameters . size ( ) = = 2 )
{
return orders_export_command ( out , parameters [ 1 ] ) ;
}
if ( parameters [ 0 ] = = " import " & & parameters . size ( ) = = 2 )
{
return orders_import_command ( out , parameters [ 1 ] ) ;
}
2017-07-02 15:00:45 -06:00
if ( parameters [ 0 ] = = " clear " & & parameters . size ( ) = = 1 )
{
return orders_clear_command ( out ) ;
}
2021-09-01 14:04:23 -06:00
if ( parameters [ 0 ] = = " sort " & & parameters . size ( ) = = 1 )
{
return orders_sort_command ( out ) ;
}
2017-05-27 15:47:18 -06:00
return CR_WRONG_USAGE ;
}
2022-07-06 08:03:29 -06:00
static void list_library ( color_ostream & out ) {
std : : map < std : : string , bool > files ;
if ( 0 < Filesystem : : listdir_recursive ( ORDERS_LIBRARY_DIR , files , 0 , false ) ) {
// if the library directory doesn't exist, just skip it
return ;
}
if ( files . empty ( ) ) {
// if no files in the library directory, just skip it
return ;
}
for ( auto it : files )
{
if ( it . second )
continue ; // skip directories
std : : string name = it . first ;
if ( name . length ( ) < = 5 | | name . rfind ( " .json " ) ! = name . length ( ) - 5 )
continue ; // skip non-.json files
name . resize ( name . length ( ) - 5 ) ;
out < < " library/ " < < name < < std : : endl ;
}
}
2021-09-07 23:05:47 -06:00
static command_result orders_list_command ( color_ostream & out )
{
// use listdir_recursive instead of listdir even though orders doesn't
// support subdirs so we can identify and ignore subdirs with ".json" names.
// also listdir_recursive will alphabetize the list for us.
std : : map < std : : string , bool > files ;
if ( 0 < Filesystem : : listdir_recursive ( ORDERS_DIR , files , 0 , false ) )
{
out < < COLOR_LIGHTRED < < " Unable to list files in directory: " < < ORDERS_DIR < < std : : endl ;
return CR_FAILURE ;
}
if ( files . empty ( ) )
{
out < < COLOR_YELLOW < < " No exported orders yet. Create manager orders and export them with 'orders export <name>', or copy pre-made orders .json files into " < < ORDERS_DIR < < " . " < < std : : endl ;
return CR_OK ;
}
for ( auto it : files )
{
if ( it . second )
continue ; // skip directories
std : : string name = it . first ;
if ( name . length ( ) < = 5 | | name . rfind ( " .json " ) ! = name . length ( ) - 5 )
continue ; // skip non-.json files
name . resize ( name . length ( ) - 5 ) ;
out < < name < < std : : endl ;
}
2022-07-06 08:03:29 -06:00
list_library ( out ) ;
2021-09-07 23:05:47 -06:00
return CR_OK ;
}
2017-05-27 15:47:18 -06:00
static bool is_safe_filename ( color_ostream & out , const std : : string & name )
{
if ( name . empty ( ) )
{
out < < COLOR_LIGHTRED < < " Missing filename! " < < std : : endl ;
return false ;
}
2017-07-02 15:00:45 -06:00
for ( auto it : name )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
if ( isalnum ( it ) )
2017-05-27 15:47:18 -06:00
{
continue ;
}
2017-07-02 15:00:45 -06:00
if ( it ! = ' ' & & it ! = ' . ' & & it ! = ' - ' & & it ! = ' _ ' )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
out < < COLOR_LIGHTRED < < " Invalid symbol in name: " < < it < < std : : endl ;
2017-05-27 15:47:18 -06:00
return false ;
}
}
return true ;
}
template < typename B >
static void bitfield_to_json_array ( Json : : Value & out , B bits )
{
std : : vector < std : : string > names ;
bitfield_to_string ( & names , bits ) ;
2017-07-02 15:00:45 -06:00
for ( auto & it : names )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
out . append ( it ) ;
2017-05-27 15:47:18 -06:00
}
}
template < typename B >
static void json_array_to_bitfield ( B & bits , Json : : Value & arr )
{
if ( arr . size ( ) = = 0 )
{
return ;
}
2017-10-16 13:01:23 -06:00
for ( Json : : ArrayIndex i = arr . size ( ) ; i ! = 0 ; i - - )
2017-05-27 15:47:18 -06:00
{
2017-10-16 13:01:23 -06:00
if ( ! arr [ i - 1 ] . isString ( ) )
{
continue ;
}
std : : string str ( arr [ i - 1 ] . asString ( ) ) ;
2017-05-27 15:47:18 -06:00
int current ;
2017-10-16 13:01:23 -06:00
if ( get_bitfield_field ( & current , bits , str ) )
2017-05-27 15:47:18 -06:00
{
2017-10-16 13:01:23 -06:00
if ( ! current & & set_bitfield_field ( & bits , str , 1 ) )
2017-05-27 15:47:18 -06:00
{
Json : : Value removed ;
2017-10-16 13:01:23 -06:00
arr . removeIndex ( i - 1 , & removed ) ;
2017-05-27 15:47:18 -06:00
}
}
}
}
template < typename D >
static df : : itemdef * get_itemdef ( int16_t subtype )
{
return D : : find ( subtype ) ;
}
template < typename D >
static df : : itemdef * get_itemdef ( const std : : string & subtype )
{
2017-07-02 15:00:45 -06:00
for ( auto it : D : : get_vector ( ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
if ( it - > id = = subtype )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
return it ;
2017-05-27 15:47:18 -06:00
}
}
return nullptr ;
}
template < typename ST >
static df : : itemdef * get_itemdef ( color_ostream & out , df : : item_type type , ST subtype )
{
switch ( type )
{
case item_type : : AMMO :
return get_itemdef < df : : itemdef_ammost > ( subtype ) ;
case item_type : : ARMOR :
return get_itemdef < df : : itemdef_armorst > ( subtype ) ;
case item_type : : FOOD :
return get_itemdef < df : : itemdef_foodst > ( subtype ) ;
case item_type : : GLOVES :
return get_itemdef < df : : itemdef_glovesst > ( subtype ) ;
case item_type : : HELM :
return get_itemdef < df : : itemdef_helmst > ( subtype ) ;
case item_type : : INSTRUMENT :
return get_itemdef < df : : itemdef_instrumentst > ( subtype ) ;
case item_type : : PANTS :
return get_itemdef < df : : itemdef_pantsst > ( subtype ) ;
case item_type : : SHIELD :
return get_itemdef < df : : itemdef_shieldst > ( subtype ) ;
case item_type : : SHOES :
return get_itemdef < df : : itemdef_shoesst > ( subtype ) ;
case item_type : : SIEGEAMMO :
return get_itemdef < df : : itemdef_siegeammost > ( subtype ) ;
case item_type : : TOOL :
return get_itemdef < df : : itemdef_toolst > ( subtype ) ;
case item_type : : TOY :
return get_itemdef < df : : itemdef_toyst > ( subtype ) ;
case item_type : : TRAPCOMP :
return get_itemdef < df : : itemdef_trapcompst > ( subtype ) ;
case item_type : : WEAPON :
return get_itemdef < df : : itemdef_weaponst > ( subtype ) ;
default :
out < < COLOR_YELLOW < < " Unhandled raw item type in manager order: " < < enum_item_key ( type ) < < " ! Please report this bug to DFHack. " < < std : : endl ;
return nullptr ;
}
}
static command_result orders_export_command ( color_ostream & out , const std : : string & name )
{
if ( ! is_safe_filename ( out , name ) )
{
return CR_WRONG_USAGE ;
}
Json : : Value orders ( Json : : arrayValue ) ;
{
CoreSuspender suspend ;
2017-07-02 15:00:45 -06:00
for ( auto it : world - > manager_orders )
2017-05-27 15:47:18 -06:00
{
Json : : Value order ( Json : : objectValue ) ;
2017-07-02 15:00:45 -06:00
order [ " id " ] = it - > id ;
order [ " job " ] = enum_item_key ( it - > job_type ) ;
if ( ! it - > reaction_name . empty ( ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
order [ " reaction " ] = it - > reaction_name ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it - > item_type ! = item_type : : NONE )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
order [ " item_type " ] = enum_item_key ( it - > item_type ) ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it - > item_subtype ! = - 1 )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
df : : itemdef * def = get_itemdef ( out , it - > item_type = = item_type : : NONE ? ENUM_ATTR ( job_type , item , it - > job_type ) : it - > item_type , it - > item_subtype ) ;
2017-05-27 15:47:18 -06:00
if ( def )
{
order [ " item_subtype " ] = def - > id ;
}
}
2017-07-02 15:00:45 -06:00
if ( it - > job_type = = job_type : : PrepareMeal )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
order [ " meal_ingredients " ] = it - > mat_type ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
else if ( it - > mat_type ! = - 1 | | it - > mat_index ! = - 1 )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
order [ " material " ] = MaterialInfo ( it ) . getToken ( ) ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it - > item_category . whole ! = 0 )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
bitfield_to_json_array ( order [ " item_category " ] , it - > item_category ) ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it - > hist_figure_id ! = - 1 )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
order [ " hist_figure " ] = it - > hist_figure_id ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it - > material_category . whole ! = 0 )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
bitfield_to_json_array ( order [ " material_category " ] , it - > material_category ) ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it - > art_spec . type ! = df : : job_art_specification : : None )
2017-05-27 15:47:18 -06:00
{
Json : : Value art ( Json : : objectValue ) ;
2017-07-02 15:00:45 -06:00
art [ " type " ] = enum_item_key ( it - > art_spec . type ) ;
art [ " id " ] = it - > art_spec . id ;
if ( it - > art_spec . subid ! = - 1 )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
art [ " subid " ] = it - > art_spec . subid ;
2017-05-27 15:47:18 -06:00
}
order [ " art " ] = art ;
}
2017-07-02 15:00:45 -06:00
order [ " amount_left " ] = it - > amount_left ;
order [ " amount_total " ] = it - > amount_total ;
order [ " is_validated " ] = bool ( it - > status . bits . validated ) ;
order [ " is_active " ] = bool ( it - > status . bits . active ) ;
2017-05-27 15:47:18 -06:00
2017-07-02 15:00:45 -06:00
order [ " frequency " ] = enum_item_key ( it - > frequency ) ;
2017-05-27 15:47:18 -06:00
// TODO: finished_year, finished_year_tick
2017-07-02 15:00:45 -06:00
if ( it - > workshop_id ! = - 1 )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
order [ " workshop_id " ] = it - > workshop_id ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it - > max_workshops ! = 0 )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
order [ " max_workshops " ] = it - > max_workshops ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( ! it - > item_conditions . empty ( ) )
2017-05-27 15:47:18 -06:00
{
Json : : Value conditions ( Json : : arrayValue ) ;
2017-07-02 15:00:45 -06:00
for ( auto it2 : it - > item_conditions )
2017-05-27 15:47:18 -06:00
{
Json : : Value condition ( Json : : objectValue ) ;
2017-07-02 15:00:45 -06:00
condition [ " condition " ] = enum_item_key ( it2 - > compare_type ) ;
condition [ " value " ] = it2 - > compare_val ;
2017-05-27 15:47:18 -06:00
2017-07-02 15:00:45 -06:00
if ( it2 - > flags1 . whole ! = 0 | | it2 - > flags2 . whole ! = 0 | | it2 - > flags3 . whole ! = 0 )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
bitfield_to_json_array ( condition [ " flags " ] , it2 - > flags1 ) ;
bitfield_to_json_array ( condition [ " flags " ] , it2 - > flags2 ) ;
bitfield_to_json_array ( condition [ " flags " ] , it2 - > flags3 ) ;
2017-05-27 15:47:18 -06:00
// TODO: flags4, flags5
}
2017-07-02 15:00:45 -06:00
if ( it2 - > item_type ! = item_type : : NONE )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
condition [ " item_type " ] = enum_item_key ( it2 - > item_type ) ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it2 - > item_subtype ! = - 1 )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
df : : itemdef * def = get_itemdef ( out , it2 - > item_type , it2 - > item_subtype ) ;
2017-05-27 15:47:18 -06:00
if ( def )
{
condition [ " item_subtype " ] = def - > id ;
}
}
2017-07-02 15:00:45 -06:00
if ( it2 - > mat_type ! = - 1 | | it2 - > mat_index ! = - 1 )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
condition [ " material " ] = MaterialInfo ( it2 ) . getToken ( ) ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it2 - > inorganic_bearing ! = - 1 )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
condition [ " bearing " ] = df : : inorganic_raw : : find ( it2 - > inorganic_bearing ) - > id ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( ! it2 - > reaction_class . empty ( ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
condition [ " reaction_class " ] = it2 - > reaction_class ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( ! it2 - > has_material_reaction_product . empty ( ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
condition [ " reaction_product " ] = it2 - > has_material_reaction_product ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it2 - > has_tool_use ! = tool_uses : : NONE )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
condition [ " tool " ] = enum_item_key ( it2 - > has_tool_use ) ;
2017-05-27 15:47:18 -06:00
}
2021-07-18 23:55:57 -06:00
if ( it2 - > min_dimension ! = - 1 )
{
condition [ " min_dimension " ] = it2 - > min_dimension ;
}
if ( it2 - > reaction_id ! = - 1 )
{
df : : reaction * reaction = world - > raws . reactions . reactions [ it2 - > reaction_id ] ;
condition [ " reaction_id " ] = reaction - > code ;
if ( ! it2 - > contains . empty ( ) )
{
Json : : Value contains ( Json : : arrayValue ) ;
for ( int32_t contains_val : it2 - > contains )
{
contains . append ( reaction - > reagents [ contains_val ] - > code ) ;
}
condition [ " contains " ] = contains ;
}
}
2017-05-27 15:47:18 -06:00
conditions . append ( condition ) ;
}
order [ " item_conditions " ] = conditions ;
}
2017-07-02 15:00:45 -06:00
if ( ! it - > order_conditions . empty ( ) )
2017-05-27 15:47:18 -06:00
{
Json : : Value conditions ( Json : : arrayValue ) ;
2017-07-02 15:00:45 -06:00
for ( auto it2 : it - > order_conditions )
2017-05-27 15:47:18 -06:00
{
Json : : Value condition ( Json : : objectValue ) ;
2017-07-02 15:00:45 -06:00
condition [ " order " ] = it2 - > order_id ;
condition [ " condition " ] = enum_item_key ( it2 - > condition ) ;
2017-05-27 15:47:18 -06:00
2022-06-29 08:27:37 -06:00
// TODO: unk_1
2017-05-27 15:47:18 -06:00
conditions . append ( condition ) ;
}
order [ " order_conditions " ] = conditions ;
}
2022-06-29 08:27:37 -06:00
// TODO: items
2017-05-27 15:47:18 -06:00
orders . append ( order ) ;
}
}
2021-09-07 23:05:47 -06:00
Filesystem : : mkdir ( ORDERS_DIR ) ;
2017-05-27 15:47:18 -06:00
2021-09-07 23:05:47 -06:00
std : : ofstream file ( ORDERS_DIR + " / " + name + " .json " ) ;
2017-05-27 15:47:18 -06:00
file < < orders < < std : : endl ;
return file . good ( ) ? CR_OK : CR_FAILURE ;
}
2021-06-30 15:58:01 -06:00
static command_result orders_import ( color_ostream & out , Json : : Value & orders )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
std : : map < int32_t , int32_t > id_mapping ;
for ( auto it : orders )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
id_mapping [ it [ " id " ] . asInt ( ) ] = world - > manager_order_next_id ;
world - > manager_order_next_id + + ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
for ( auto & it : orders )
2017-05-27 15:47:18 -06:00
{
df : : manager_order * order = new df : : manager_order ( ) ;
2017-07-02 15:00:45 -06:00
order - > id = id_mapping . at ( it [ " id " ] . asInt ( ) ) ;
2017-05-27 15:47:18 -06:00
2017-07-02 15:00:45 -06:00
if ( ! find_enum_item ( & order - > job_type , it [ " job " ] . asString ( ) ) )
2017-05-27 15:47:18 -06:00
{
delete order ;
2017-07-02 15:00:45 -06:00
out < < COLOR_LIGHTRED < < " Invalid job type for imported manager order: " < < it [ " job " ] . asString ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
return CR_FAILURE ;
}
2017-07-02 15:00:45 -06:00
if ( it . isMember ( " reaction " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
order - > reaction_name = it [ " reaction " ] . asString ( ) ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it . isMember ( " item_type " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
if ( ! find_enum_item ( & order - > item_type , it [ " item_type " ] . asString ( ) ) | | order - > item_type = = item_type : : NONE )
2017-05-27 15:47:18 -06:00
{
delete order ;
2017-07-02 15:00:45 -06:00
out < < COLOR_LIGHTRED < < " Invalid item type for imported manager order: " < < it [ " item_type " ] . asString ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
return CR_FAILURE ;
}
}
2017-07-02 15:00:45 -06:00
if ( it . isMember ( " item_subtype " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
df : : itemdef * def = get_itemdef ( out , order - > item_type = = item_type : : NONE ? ENUM_ATTR ( job_type , item , order - > job_type ) : order - > item_type , it [ " item_subtype " ] . asString ( ) ) ;
2017-05-27 15:47:18 -06:00
if ( def )
{
order - > item_subtype = def - > subtype ;
}
else
{
2017-07-02 15:00:45 -06:00
out < < COLOR_LIGHTRED < < " Invalid item subtype for imported manager order: " < < enum_item_key ( order - > item_type ) < < " : " < < it [ " item_subtype " ] . asString ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
2022-06-23 06:49:05 -06:00
delete order ;
2017-05-27 15:47:18 -06:00
return CR_FAILURE ;
}
}
2017-07-02 15:00:45 -06:00
if ( it . isMember ( " meal_ingredients " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
order - > mat_type = it [ " meal_ingredients " ] . asInt ( ) ;
2017-05-27 15:47:18 -06:00
order - > mat_index = - 1 ;
}
2017-07-02 15:00:45 -06:00
else if ( it . isMember ( " material " ) )
2017-05-27 15:47:18 -06:00
{
MaterialInfo mat ;
2017-07-02 15:00:45 -06:00
if ( ! mat . find ( it [ " material " ] . asString ( ) ) )
2017-05-27 15:47:18 -06:00
{
delete order ;
2017-07-02 15:00:45 -06:00
out < < COLOR_LIGHTRED < < " Invalid material for imported manager order: " < < it [ " material " ] . asString ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
return CR_FAILURE ;
}
order - > mat_type = mat . type ;
order - > mat_index = mat . index ;
}
2017-07-02 15:00:45 -06:00
if ( it . isMember ( " item_category " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
json_array_to_bitfield ( order - > item_category , it [ " item_category " ] ) ;
if ( ! it [ " item_category " ] . empty ( ) )
2017-05-27 15:47:18 -06:00
{
delete order ;
2017-07-02 15:00:45 -06:00
out < < COLOR_LIGHTRED < < " Invalid item_category value for imported manager order: " < < it [ " item_category " ] < < std : : endl ;
2017-05-27 15:47:18 -06:00
return CR_FAILURE ;
}
}
2017-07-02 15:00:45 -06:00
if ( it . isMember ( " hist_figure " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
if ( ! df : : historical_figure : : find ( it [ " hist_figure " ] . asInt ( ) ) )
2017-05-27 15:47:18 -06:00
{
delete order ;
2017-07-02 15:00:45 -06:00
out < < COLOR_YELLOW < < " Missing historical figure for imported manager order: " < < it [ " hist_figure " ] . asInt ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
continue ;
}
2017-07-02 15:00:45 -06:00
order - > hist_figure_id = it [ " hist_figure " ] . asInt ( ) ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it . isMember ( " material_category " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
json_array_to_bitfield ( order - > material_category , it [ " material_category " ] ) ;
if ( ! it [ " material_category " ] . empty ( ) )
2017-05-27 15:47:18 -06:00
{
delete order ;
2017-07-02 15:00:45 -06:00
out < < COLOR_LIGHTRED < < " Invalid material_category value for imported manager order: " < < it [ " material_category " ] < < std : : endl ;
2017-05-27 15:47:18 -06:00
return CR_FAILURE ;
}
}
2017-07-02 15:00:45 -06:00
if ( it . isMember ( " art " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
if ( ! find_enum_item ( & order - > art_spec . type , it [ " art " ] [ " type " ] . asString ( ) ) )
2017-05-27 15:47:18 -06:00
{
delete order ;
2017-07-02 15:00:45 -06:00
out < < COLOR_LIGHTRED < < " Invalid art type value for imported manager order: " < < it [ " art " ] [ " type " ] . asString ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
return CR_FAILURE ;
}
2017-07-02 15:00:45 -06:00
order - > art_spec . id = it [ " art " ] [ " id " ] . asInt ( ) ;
if ( it [ " art " ] . isMember ( " subid " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
order - > art_spec . subid = it [ " art " ] [ " subid " ] . asInt ( ) ;
2017-05-27 15:47:18 -06:00
}
}
2017-07-02 15:00:45 -06:00
order - > amount_left = it [ " amount_left " ] . asInt ( ) ;
order - > amount_total = it [ " amount_total " ] . asInt ( ) ;
order - > status . bits . validated = it [ " is_validated " ] . asBool ( ) ;
order - > status . bits . active = it [ " is_active " ] . asBool ( ) ;
2017-05-27 15:47:18 -06:00
2017-07-02 15:00:45 -06:00
if ( ! find_enum_item ( & order - > frequency , it [ " frequency " ] . asString ( ) ) )
2017-05-27 15:47:18 -06:00
{
delete order ;
2017-07-02 15:00:45 -06:00
out < < COLOR_LIGHTRED < < " Invalid frequency value for imported manager order: " < < it [ " frequency " ] . asString ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
return CR_FAILURE ;
}
// TODO: finished_year, finished_year_tick
2017-07-02 15:00:45 -06:00
if ( it . isMember ( " workshop_id " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
if ( ! df : : building : : find ( it [ " workshop_id " ] . asInt ( ) ) )
2017-05-27 15:47:18 -06:00
{
delete order ;
2017-07-02 15:00:45 -06:00
out < < COLOR_YELLOW < < " Missing workshop for imported manager order: " < < it [ " workshop_id " ] . asInt ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
continue ;
}
2017-07-02 15:00:45 -06:00
order - > workshop_id = it [ " workshop_id " ] . asInt ( ) ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it . isMember ( " max_workshops " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
order - > max_workshops = it [ " max_workshops " ] . asInt ( ) ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it . isMember ( " item_conditions " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
for ( auto & it2 : it [ " item_conditions " ] )
2017-05-27 15:47:18 -06:00
{
df : : manager_order_condition_item * condition = new df : : manager_order_condition_item ( ) ;
2017-07-02 15:00:45 -06:00
if ( ! find_enum_item ( & condition - > compare_type , it2 [ " condition " ] . asString ( ) ) )
2017-05-27 15:47:18 -06:00
{
delete condition ;
2017-07-02 15:00:45 -06:00
out < < COLOR_YELLOW < < " Invalid item condition condition for imported manager order: " < < it2 [ " condition " ] . asString ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
continue ;
}
2017-07-02 15:00:45 -06:00
condition - > compare_val = it2 [ " value " ] . asInt ( ) ;
2017-05-27 15:47:18 -06:00
2017-07-02 15:00:45 -06:00
if ( it2 . isMember ( " flags " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
json_array_to_bitfield ( condition - > flags1 , it2 [ " flags " ] ) ;
json_array_to_bitfield ( condition - > flags2 , it2 [ " flags " ] ) ;
json_array_to_bitfield ( condition - > flags3 , it2 [ " flags " ] ) ;
2017-05-27 15:47:18 -06:00
// TODO: flags4, flags5
2017-07-02 15:00:45 -06:00
if ( ! it2 [ " flags " ] . empty ( ) )
2017-05-27 15:47:18 -06:00
{
delete condition ;
2017-07-02 15:00:45 -06:00
out < < COLOR_YELLOW < < " Invalid item condition flags for imported manager order: " < < it2 [ " flags " ] < < std : : endl ;
2017-05-27 15:47:18 -06:00
continue ;
}
}
2017-07-02 15:00:45 -06:00
if ( it2 . isMember ( " item_type " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
if ( ! find_enum_item ( & condition - > item_type , it2 [ " item_type " ] . asString ( ) ) | | condition - > item_type = = item_type : : NONE )
2017-05-27 15:47:18 -06:00
{
delete condition ;
2017-07-02 15:00:45 -06:00
out < < COLOR_YELLOW < < " Invalid item condition item type for imported manager order: " < < it2 [ " item_type " ] . asString ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
continue ;
}
}
2017-07-02 15:00:45 -06:00
if ( it2 . isMember ( " item_subtype " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
df : : itemdef * def = get_itemdef ( out , condition - > item_type , it2 [ " item_subtype " ] . asString ( ) ) ;
2017-05-27 15:47:18 -06:00
if ( def )
{
condition - > item_subtype = def - > subtype ;
}
else
{
2017-07-02 15:00:45 -06:00
out < < COLOR_YELLOW < < " Invalid item condition item subtype for imported manager order: " < < enum_item_key ( condition - > item_type ) < < " : " < < it2 [ " item_subtype " ] . asString ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
2022-06-23 06:49:05 -06:00
delete condition ;
2017-05-27 15:47:18 -06:00
continue ;
}
}
2017-07-02 15:00:45 -06:00
if ( it2 . isMember ( " material " ) )
2017-05-27 15:47:18 -06:00
{
MaterialInfo mat ;
2017-07-02 15:00:45 -06:00
if ( ! mat . find ( it2 [ " material " ] . asString ( ) ) )
2017-05-27 15:47:18 -06:00
{
delete condition ;
2017-07-02 15:00:45 -06:00
out < < COLOR_YELLOW < < " Invalid item condition material for imported manager order: " < < it2 [ " material " ] . asString ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
continue ;
}
condition - > mat_type = mat . type ;
condition - > mat_index = mat . index ;
}
2017-07-02 15:00:45 -06:00
if ( it2 . isMember ( " bearing " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
std : : string bearing ( it2 [ " bearing " ] . asString ( ) ) ;
2017-05-27 15:47:18 -06:00
auto found = std : : find_if ( world - > raws . inorganics . begin ( ) , world - > raws . inorganics . end ( ) , [ bearing ] ( df : : inorganic_raw * raw ) - > bool { return raw - > id = = bearing ; } ) ;
if ( found = = world - > raws . inorganics . end ( ) )
{
delete condition ;
2017-07-02 15:00:45 -06:00
out < < COLOR_YELLOW < < " Invalid item condition inorganic bearing type for imported manager order: " < < it2 [ " bearing " ] . asString ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
continue ;
}
condition - > inorganic_bearing = found - world - > raws . inorganics . begin ( ) ;
}
2017-07-02 15:00:45 -06:00
if ( it2 . isMember ( " reaction_class " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
condition - > reaction_class = it2 [ " reaction_class " ] . asString ( ) ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it2 . isMember ( " reaction_product " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
condition - > has_material_reaction_product = it2 [ " reaction_product " ] . asString ( ) ;
2017-05-27 15:47:18 -06:00
}
2017-07-02 15:00:45 -06:00
if ( it2 . isMember ( " tool " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
if ( ! find_enum_item ( & condition - > has_tool_use , it2 [ " tool " ] . asString ( ) ) | | condition - > has_tool_use = = tool_uses : : NONE )
2017-05-27 15:47:18 -06:00
{
delete condition ;
2017-07-02 15:00:45 -06:00
out < < COLOR_YELLOW < < " Invalid item condition tool use for imported manager order: " < < it2 [ " tool " ] . asString ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
continue ;
}
}
2021-07-18 23:55:57 -06:00
if ( it2 . isMember ( " min_dimension " ) )
{
condition - > min_dimension = it2 [ " min_dimension " ] . asInt ( ) ;
}
if ( it2 . isMember ( " reaction_id " ) )
{
std : : string reaction_code = it2 [ " reaction_id " ] . asString ( ) ;
df : : reaction * reaction = NULL ;
int32_t reaction_id = - 1 ;
size_t num_reactions = world - > raws . reactions . reactions . size ( ) ;
for ( size_t idx = 0 ; idx < num_reactions ; + + idx )
{
reaction = world - > raws . reactions . reactions [ idx ] ;
if ( reaction - > code = = reaction_code )
{
reaction_id = idx ;
break ;
}
}
if ( reaction_id < 0 )
{
delete condition ;
out < < COLOR_YELLOW < < " Reaction code not found for imported manager order: " < < reaction_code < < std : : endl ;
continue ;
}
condition - > reaction_id = reaction_id ;
if ( it2 . isMember ( " contains " ) )
{
size_t num_reagents = reaction - > reagents . size ( ) ;
std : : string bad_reagent_code ;
for ( Json : : Value & contains_val : it2 [ " contains " ] )
{
std : : string reagent_code = contains_val . asString ( ) ;
bool reagent_found = false ;
for ( size_t idx = 0 ; idx < num_reagents ; + + idx )
{
df : : reaction_reagent * reagent = reaction - > reagents [ idx ] ;
if ( reagent - > code = = reagent_code )
{
condition - > contains . push_back ( idx ) ;
reagent_found = true ;
break ;
}
}
if ( ! reagent_found )
{
bad_reagent_code = reagent_code ;
break ;
}
}
if ( ! bad_reagent_code . empty ( ) )
{
delete condition ;
out < < COLOR_YELLOW < < " Invalid reagent code for imported manager order: " < < bad_reagent_code < < std : : endl ;
continue ;
}
}
}
2017-05-27 15:47:18 -06:00
order - > item_conditions . push_back ( condition ) ;
}
}
2017-07-02 15:00:45 -06:00
if ( it . isMember ( " order_conditions " ) )
2017-05-27 15:47:18 -06:00
{
2017-07-02 15:00:45 -06:00
for ( auto & it2 : it [ " order_conditions " ] )
2017-05-27 15:47:18 -06:00
{
df : : manager_order_condition_order * condition = new df : : manager_order_condition_order ( ) ;
2017-07-02 15:00:45 -06:00
int32_t id = it2 [ " order " ] . asInt ( ) ;
if ( id = = it [ " id " ] . asInt ( ) | | ! id_mapping . count ( id ) )
2017-05-27 15:47:18 -06:00
{
delete condition ;
2017-07-02 15:00:45 -06:00
out < < COLOR_YELLOW < < " Missing order condition target for imported manager order: " < < it2 [ " order " ] . asInt ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
continue ;
}
2017-07-02 15:00:45 -06:00
condition - > order_id = id_mapping . at ( id ) ;
2017-05-27 15:47:18 -06:00
2017-07-02 15:00:45 -06:00
if ( ! find_enum_item ( & condition - > condition , it2 [ " condition " ] . asString ( ) ) )
2017-05-27 15:47:18 -06:00
{
delete condition ;
2017-07-02 15:00:45 -06:00
out < < COLOR_YELLOW < < " Invalid order condition type for imported manager order: " < < it2 [ " condition " ] . asString ( ) < < std : : endl ;
2017-05-27 15:47:18 -06:00
continue ;
}
2022-06-29 08:27:37 -06:00
// TODO: unk_1
2017-05-27 15:47:18 -06:00
order - > order_conditions . push_back ( condition ) ;
}
}
2022-06-29 08:27:37 -06:00
// TODO: items
2017-05-27 15:47:18 -06:00
world - > manager_orders . push_back ( order ) ;
}
return CR_OK ;
}
2017-07-02 15:00:45 -06:00
2021-06-30 15:58:01 -06:00
static command_result orders_import_command ( color_ostream & out , const std : : string & name )
{
2022-07-06 08:03:29 -06:00
std : : string fname = name ;
bool is_library = false ;
if ( 0 = = name . find ( " library/ " ) ) {
is_library = true ;
fname = name . substr ( 8 ) ;
}
if ( ! is_safe_filename ( out , fname ) )
2021-06-30 15:58:01 -06:00
{
return CR_WRONG_USAGE ;
}
2022-07-06 08:03:29 -06:00
const std : : string filename ( ( is_library ? ORDERS_LIBRARY_DIR : ORDERS_DIR ) +
" / " + fname + " .json " ) ;
2021-06-30 15:58:01 -06:00
Json : : Value orders ;
{
std : : ifstream file ( filename ) ;
if ( ! file . good ( ) )
{
out < < COLOR_LIGHTRED < < " Cannot find orders file: " < < filename < < std : : endl ;
return CR_FAILURE ;
}
try
{
file > > orders ;
}
catch ( const std : : exception & e )
{
out < < COLOR_LIGHTRED < < " Error reading orders file: " < < filename < < " : " < < e . what ( ) < < std : : endl ;
return CR_FAILURE ;
}
if ( ! file . good ( ) )
{
out < < COLOR_LIGHTRED < < " Error reading orders file: " < < filename < < std : : endl ;
return CR_FAILURE ;
}
}
if ( orders . type ( ) ! = Json : : arrayValue )
{
out < < COLOR_LIGHTRED < < " Invalid orders file: " < < filename < < " : expected array " < < std : : endl ;
return CR_FAILURE ;
}
CoreSuspender suspend ;
try
{
return orders_import ( out , orders ) ;
}
catch ( const std : : exception & e )
{
out < < COLOR_LIGHTRED < < " Error reading orders file: " < < filename < < " : " < < e . what ( ) < < std : : endl ;
return CR_FAILURE ;
}
}
2017-07-02 15:00:45 -06:00
static command_result orders_clear_command ( color_ostream & out )
{
CoreSuspender suspend ;
for ( auto order : world - > manager_orders )
{
for ( auto condition : order - > item_conditions )
{
delete condition ;
}
for ( auto condition : order - > order_conditions )
{
delete condition ;
}
2020-04-15 19:05:15 -06:00
if ( order - > items )
2017-07-02 15:00:45 -06:00
{
2020-04-15 19:05:15 -06:00
for ( auto item : * order - > items )
2017-07-02 15:00:45 -06:00
{
2020-04-15 19:05:15 -06:00
delete item ;
2017-07-02 15:00:45 -06:00
}
2020-04-15 19:05:15 -06:00
delete order - > items ;
2017-07-02 15:00:45 -06:00
}
delete order ;
}
out < < " Deleted " < < world - > manager_orders . size ( ) < < " manager orders. " < < std : : endl ;
world - > manager_orders . clear ( ) ;
return CR_OK ;
}
2021-09-01 14:04:23 -06:00
static bool compare_freq ( df : : manager_order * a , df : : manager_order * b )
{
if ( a - > frequency = = df : : manager_order : : T_frequency : : OneTime
| | b - > frequency = = df : : manager_order : : T_frequency : : OneTime )
return a - > frequency < b - > frequency ;
return a - > frequency > b - > frequency ;
}
static command_result orders_sort_command ( color_ostream & out )
{
CoreSuspender suspend ;
2021-09-01 17:52:11 -06:00
if ( ! std : : is_sorted ( world - > manager_orders . begin ( ) ,
world - > manager_orders . end ( ) ,
compare_freq ) )
{
std : : stable_sort ( world - > manager_orders . begin ( ) ,
world - > manager_orders . end ( ) ,
compare_freq ) ;
out < < " Fixed priority of manager orders. " < < std : : endl ;
}
2021-09-01 14:04:23 -06:00
return CR_OK ;
}