Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
6634 lines (5673 sloc) 230 KB
// Kloker ~ A Unitlist Reiki Practitioner
// Spawn of Dwarf Manipulator
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <MiscUtils.h>
#include <VTableInterpose.h>
#include <modules/Screen.h>
#include <modules/Gui.h>
#include <modules/Translation.h>
#include <modules/Units.h>
#include <modules/Filesystem.h>
#include <modules/Job.h>
#include <array>
#include <algorithm>
#include <chrono>
#include <vector>
#include <string>
#include <set>
#include <tuple>
#include <math.h>
#include "listcolumn.h"
#include "uicommon.h"
#include "df/ui.h"
#include "df/enabler.h"
#include "df/graphic.h"
#include "df/interface_key.h"
#include "df/viewscreen_unitlistst.h"
#include "df/viewscreen_dwarfmodest.h"
#include "df/caste_raw.h"
#include "df/creature_raw.h"
#include "df/creature_graphics_role.h"
#include "df/entity_raw.h"
#include "df/world.h"
#include "df/world_site.h"
#include "df/nemesis_record.h"
#include "df/historical_entity.h"
#include "df/historical_figure.h"
#include "df/historical_figure_info.h"
#include "df/histfig_hf_link.h"
#include "df/histfig_hf_link_type.h"
#include "df/activity_event.h"
#include "df/unit.h"
#include "df/unit_soul.h"
#include "df/unit_skill.h"
#include "df/unit_syndrome.h"
#include "df/unit_health_info.h"
#include "df/unit_health_flags.h"
#include "df/unit_wound.h"
#include "df/unit_preference.h"
#include "df/unit_relationship_type.h"
#include "df/unit_misc_trait.h"
#include "df/misc_trait_type.h"
#include "df/item_type.h"
#include "df/itemdef_weaponst.h"
#include "df/itemdef_trapcompst.h"
#include "df/itemdef_toyst.h"
#include "df/itemdef_toolst.h"
#include "df/itemdef_instrumentst.h"
#include "df/itemdef_armorst.h"
#include "df/itemdef_ammost.h"
#include "df/itemdef_siegeammost.h"
#include "df/itemdef_glovesst.h"
#include "df/itemdef_shoesst.h"
#include "df/itemdef_shieldst.h"
#include "df/itemdef_helmst.h"
#include "df/itemdef_pantsst.h"
#include "df/itemdef_foodst.h"
using std::stringstream;
using std::set;
using std::vector;
using std::string;
using namespace DFHack;
using namespace df::enums;
DFHACK_PLUGIN("manipulator");
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
REQUIRE_GLOBAL(world);
REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(gps);
REQUIRE_GLOBAL(enabler);
#define CONFIG_DIR "kloker"
struct SkillLevel
{
const char *name;
int points;
char abbrev;
};
#define NUM_SKILL_LEVELS (sizeof(skill_levels) / sizeof(SkillLevel))
// The various skill rankings.
const SkillLevel skill_levels[] = {
{"Dabbling", 500, '0'},
{"Novice", 600, '1'},
{"Adequate", 700, '2'},
{"Competent", 800, '3'},
{"Skilled", 900, '4'},
{"Proficient", 1000, '5'},
{"Talented", 1100, '6'},
{"Adept", 1200, '7'},
{"Expert", 1300, '8'},
{"Professional",1400, '9'},
{"Accomplished",1500, 'A'},
{"Great", 1600, 'B'},
{"Master", 1700, 'C'},
{"High Master", 1800, 'D'},
{"Grand Master",1900, 'E'},
{"Legendary", 2000, 'U'},
{"Legendary+1", 2100, 'V'},
{"Legendary+2", 2200, 'W'},
{"Legendary+3", 2300, 'X'},
{"Legendary+4", 2400, 'Y'},
{"Legendary+5", 0, 'Z'}
};
struct SkillColumn
{
int group; // for navigation and mass toggling
int8_t color; // for column headers
df::profession profession; // to display graphical tiles
df::unit_labor labor; // toggled when pressing Enter
df::job_skill skill; // displayed rating
char label[3]; // column header
bool special; // specified labor is mutually exclusive with all other special labors
};
#define NUM_COLUMNS (sizeof(columns) / sizeof(SkillColumn))
const SkillColumn columns[] = {
// Mining
{0, 7, profession::MINER, unit_labor::MINE, job_skill::MINING, "Mi", true},
// Woodworking
{1, 14, profession::CARPENTER, unit_labor::CARPENTER, job_skill::CARPENTRY, "Ca"},
{1, 14, profession::BOWYER, unit_labor::BOWYER, job_skill::BOWYER, "Bw"},
{1, 14, profession::WOODCUTTER, unit_labor::CUTWOOD, job_skill::WOODCUTTING, "WC", true},
// Stoneworking
{2, 15, profession::MASON, unit_labor::MASON, job_skill::MASONRY, "Ma"},
{2, 15, profession::ENGRAVER, unit_labor::DETAIL, job_skill::DETAILSTONE, "En"},
// Hunting/Related
{3, 2, profession::ANIMAL_TRAINER, unit_labor::ANIMALTRAIN, job_skill::ANIMALTRAIN, "Tn"},
{3, 2, profession::ANIMAL_CARETAKER, unit_labor::ANIMALCARE, job_skill::ANIMALCARE, "Ca"},
{3, 2, profession::HUNTER, unit_labor::HUNT, job_skill::SNEAK, "Hu", true},
{3, 2, profession::TRAPPER, unit_labor::TRAPPER, job_skill::TRAPPING, "Tr"},
{3, 2, profession::ANIMAL_DISSECTOR, unit_labor::DISSECT_VERMIN, job_skill::DISSECT_VERMIN, "Di"},
// Healthcare
{4, 5, profession::DIAGNOSER, unit_labor::DIAGNOSE, job_skill::DIAGNOSE, "Di"},
{4, 5, profession::SURGEON, unit_labor::SURGERY, job_skill::SURGERY, "Su"},
{4, 5, profession::BONE_SETTER, unit_labor::BONE_SETTING, job_skill::SET_BONE, "Bo"},
{4, 5, profession::SUTURER, unit_labor::SUTURING, job_skill::SUTURE, "St"},
{4, 5, profession::DOCTOR, unit_labor::DRESSING_WOUNDS, job_skill::DRESS_WOUNDS, "Dr"},
{4, 5, profession::NONE, unit_labor::FEED_WATER_CIVILIANS, job_skill::NONE, "Fd"},
{4, 5, profession::NONE, unit_labor::RECOVER_WOUNDED, job_skill::NONE, "Re"},
// Farming Related
{5, 6, profession::BUTCHER, unit_labor::BUTCHER, job_skill::BUTCHER, "Bu"},
{5, 6, profession::TANNER, unit_labor::TANNER, job_skill::TANNER, "Ta"},
{5, 6, profession::COOK, unit_labor::COOK, job_skill::COOK, "Co"},
{5, 6, profession::BREWER, unit_labor::BREWER, job_skill::BREWING, "Br"},
{5, 6, profession::GELDER, unit_labor::GELD, job_skill::GELD, "Ge"},
{5, 6, profession::PLANTER, unit_labor::PLANT, job_skill::PLANT, "Gr"},
{5, 6, profession::HERBALIST, unit_labor::HERBALIST, job_skill::HERBALISM, "He"},
{5, 6, profession::BEEKEEPER, unit_labor::BEEKEEPING, job_skill::BEEKEEPING, "Be"},
{5, 6, profession::PRESSER, unit_labor::PRESSING, job_skill::PRESSING, "Pr"},
{5, 6, profession::MILLER, unit_labor::MILLER, job_skill::MILLING, "Ml"},
{5, 6, profession::THRESHER, unit_labor::PROCESS_PLANT, job_skill::PROCESSPLANTS, "Th"},
{5, 6, profession::CHEESE_MAKER, unit_labor::MAKE_CHEESE, job_skill::CHEESEMAKING, "Ch"},
{5, 6, profession::MILKER, unit_labor::MILK, job_skill::MILK, "Mk"},
{5, 6, profession::SHEARER, unit_labor::SHEARER, job_skill::SHEARING, "Sh"},
{5, 6, profession::SPINNER, unit_labor::SPINNER, job_skill::SPINNING, "Sp"},
{5, 6, profession::DYER, unit_labor::DYER, job_skill::DYER, "Dy"},
{5, 6, profession::SOAP_MAKER, unit_labor::SOAP_MAKER, job_skill::SOAP_MAKING, "So"},
{5, 6, profession::LYE_MAKER, unit_labor::LYE_MAKING, job_skill::LYE_MAKING, "Ly"},
{5, 6, profession::POTASH_MAKER, unit_labor::POTASH_MAKING, job_skill::POTASH_MAKING, "Po"},
{5, 6, profession::WOOD_BURNER, unit_labor::BURN_WOOD, job_skill::WOOD_BURNING, "WB"},
// Fishing/Related
{6, 1, profession::FISHERMAN, unit_labor::FISH, job_skill::FISH, "Fi"},
{6, 1, profession::FISH_CLEANER, unit_labor::CLEAN_FISH, job_skill::PROCESSFISH, "Cl"},
{6, 1, profession::FISH_DISSECTOR, unit_labor::DISSECT_FISH, job_skill::DISSECT_FISH, "Di"},
// Metalsmithing
{7, 8, profession::FURNACE_OPERATOR, unit_labor::SMELT, job_skill::SMELT, "Fu"},
{7, 8, profession::BLACKSMITH, unit_labor::FORGE_FURNITURE, job_skill::FORGE_FURNITURE, "Bl"},
{7, 8, profession::WEAPONSMITH, unit_labor::FORGE_WEAPON, job_skill::FORGE_WEAPON, "We"},
{7, 8, profession::ARMORER, unit_labor::FORGE_ARMOR, job_skill::FORGE_ARMOR, "Ar"},
{7, 8, profession::METALCRAFTER, unit_labor::METAL_CRAFT, job_skill::METALCRAFT, "Cr"},
// Crafts
{8, 9, profession::LEATHERWORKER, unit_labor::LEATHER, job_skill::LEATHERWORK, "Le"},
{8, 9, profession::WOODCRAFTER, unit_labor::WOOD_CRAFT, job_skill::WOODCRAFT, "Wo"},
{8, 9, profession::STONECRAFTER, unit_labor::STONE_CRAFT, job_skill::STONECRAFT, "St"},
{8, 9, profession::BONE_CARVER, unit_labor::BONE_CARVE, job_skill::BONECARVE, "Bo"},
{8, 9, profession::CLOTHIER, unit_labor::CLOTHESMAKER, job_skill::CLOTHESMAKING, "Cl"},
{8, 9, profession::WEAVER, unit_labor::WEAVER, job_skill::WEAVING, "We"},
{8, 9, profession::GLASSMAKER, unit_labor::GLASSMAKER, job_skill::GLASSMAKER, "Gl"},
{8, 9, profession::POTTER, unit_labor::POTTERY, job_skill::POTTERY, "Po"},
{8, 9, profession::GLAZER, unit_labor::GLAZING, job_skill::GLAZING, "Gl"},
{8, 9, profession::WAX_WORKER, unit_labor::WAX_WORKING, job_skill::WAX_WORKING, "Wx"},
{8, 9, profession::PAPERMAKER, unit_labor::PAPERMAKING, job_skill::PAPERMAKING, "Pa"},
{8, 9, profession::BOOKBINDER, unit_labor::BOOKBINDING, job_skill::BOOKBINDING, "Bk"},
{8, 9, profession::STRAND_EXTRACTOR, unit_labor::EXTRACT_STRAND, job_skill::EXTRACT_STRAND, "Ad"},
// Jewelry
{9, 10, profession::GEM_CUTTER, unit_labor::CUT_GEM, job_skill::CUTGEM, "Cu"},
{9, 10, profession::GEM_SETTER, unit_labor::ENCRUST_GEM, job_skill::ENCRUSTGEM, "Se"},
// Engineering
{10, 12, profession::SIEGE_ENGINEER, unit_labor::SIEGECRAFT, job_skill::SIEGECRAFT, "En"},
{10, 12, profession::SIEGE_OPERATOR, unit_labor::SIEGEOPERATE, job_skill::SIEGEOPERATE, "Op"},
{10, 12, profession::MECHANIC, unit_labor::MECHANIC, job_skill::MECHANICS, "Me"},
{10, 12, profession::PUMP_OPERATOR, unit_labor::OPERATE_PUMP, job_skill::OPERATE_PUMP, "Pu"},
// Hauling
{11, 3, profession::NONE, unit_labor::HAUL_STONE, job_skill::NONE, "St"},
{11, 3, profession::NONE, unit_labor::HAUL_WOOD, job_skill::NONE, "Wo"},
{11, 3, profession::NONE, unit_labor::HAUL_ITEM, job_skill::NONE, "It"},
{11, 3, profession::NONE, unit_labor::HAUL_BODY, job_skill::NONE, "Bu"},
{11, 3, profession::NONE, unit_labor::HAUL_FOOD, job_skill::NONE, "Fo"},
{11, 3, profession::NONE, unit_labor::HAUL_REFUSE, job_skill::NONE, "Re"},
{11, 3, profession::NONE, unit_labor::HAUL_FURNITURE, job_skill::NONE, "Fu"},
{11, 3, profession::NONE, unit_labor::HAUL_ANIMALS, job_skill::NONE, "An"},
{11, 3, profession::NONE, unit_labor::HANDLE_VEHICLES, job_skill::NONE, "Ve"},
{11, 3, profession::NONE, unit_labor::HAUL_TRADE, job_skill::NONE, "Tr"},
{11, 3, profession::NONE, unit_labor::HAUL_WATER, job_skill::NONE, "Wa"},
// Other Jobs
{12, 4, profession::ARCHITECT, unit_labor::ARCHITECT, job_skill::DESIGNBUILDING, "Ar"},
{12, 4, profession::ALCHEMIST, unit_labor::ALCHEMIST, job_skill::ALCHEMY, "Al"},
{12, 4, profession::NONE, unit_labor::CLEAN, job_skill::NONE, "Cl"},
{12, 4, profession::NONE, unit_labor::PULL_LEVER, job_skill::NONE, "Lv"},
{12, 4, profession::NONE, unit_labor::BUILD_ROAD, job_skill::NONE, "Ro"},
{12, 4, profession::NONE, unit_labor::BUILD_CONSTRUCTION, job_skill::NONE, "Co"},
{12, 4, profession::NONE, unit_labor::REMOVE_CONSTRUCTION, job_skill::NONE, "CR"},
// Military - Weapons
{13, 7, profession::WRESTLER, unit_labor::NONE, job_skill::WRESTLING, "Wr"},
{13, 7, profession::AXEMAN, unit_labor::NONE, job_skill::AXE, "Ax"},
{13, 7, profession::SWORDSMAN, unit_labor::NONE, job_skill::SWORD, "Sw"},
{13, 7, profession::MACEMAN, unit_labor::NONE, job_skill::MACE, "Mc"},
{13, 7, profession::HAMMERMAN, unit_labor::NONE, job_skill::HAMMER, "Ha"},
{13, 7, profession::SPEARMAN, unit_labor::NONE, job_skill::SPEAR, "Sp"},
{13, 7, profession::CROSSBOWMAN, unit_labor::NONE, job_skill::CROSSBOW, "Cb"},
{13, 7, profession::THIEF, unit_labor::NONE, job_skill::DAGGER, "Kn"},
{13, 7, profession::BOWMAN, unit_labor::NONE, job_skill::BOW, "Bo"},
{13, 7, profession::BLOWGUNMAN, unit_labor::NONE, job_skill::BLOWGUN, "Bl"},
{13, 7, profession::PIKEMAN, unit_labor::NONE, job_skill::PIKE, "Pk"},
{13, 7, profession::LASHER, unit_labor::NONE, job_skill::WHIP, "La"},
// Military - Other Combat
{14, 15, profession::NONE, unit_labor::NONE, job_skill::BITE, "Bi"},
{14, 15, profession::NONE, unit_labor::NONE, job_skill::GRASP_STRIKE, "St"},
{14, 15, profession::NONE, unit_labor::NONE, job_skill::STANCE_STRIKE, "Ki"},
{14, 15, profession::NONE, unit_labor::NONE, job_skill::MISC_WEAPON, "Mi"},
{14, 15, profession::NONE, unit_labor::NONE, job_skill::MELEE_COMBAT, "Fg"},
{14, 15, profession::NONE, unit_labor::NONE, job_skill::RANGED_COMBAT, "Ac"},
{14, 15, profession::NONE, unit_labor::NONE, job_skill::ARMOR, "Ar"},
{14, 15, profession::NONE, unit_labor::NONE, job_skill::SHIELD, "Sh"},
{14, 15, profession::NONE, unit_labor::NONE, job_skill::DODGING, "Do"},
// Military - Misc
{15, 8, profession::NONE, unit_labor::NONE, job_skill::SWIMMING, "Sw"},
{15, 8, profession::NONE, unit_labor::NONE, job_skill::COORDINATION, "Cr"},
{15, 8, profession::NONE, unit_labor::NONE, job_skill::BALANCE, "Ba"},
{15, 8, profession::NONE, unit_labor::NONE, job_skill::CLIMBING, "Cl"},
{15, 8, profession::NONE, unit_labor::NONE, job_skill::SITUATIONAL_AWARENESS, "Ob"},
{15, 8, profession::NONE, unit_labor::NONE, job_skill::KNOWLEDGE_ACQUISITION, "St"},
{15, 8, profession::NONE, unit_labor::NONE, job_skill::TEACHING, "Te"},
{15, 8, profession::NONE, unit_labor::NONE, job_skill::CONCENTRATION, "Co"},
{15, 8, profession::NONE, unit_labor::NONE, job_skill::DISCIPLINE, "Di"},
{15, 8, profession::NONE, unit_labor::NONE, job_skill::LEADERSHIP, "Ld"},
// Noble
{16, 5, profession::ADMINISTRATOR, unit_labor::NONE, job_skill::ORGANIZATION, "Or"},
{16, 5, profession::TRADER, unit_labor::NONE, job_skill::APPRAISAL, "Ap"},
{16, 5, profession::CLERK, unit_labor::NONE, job_skill::RECORD_KEEPING, "RK"},
// Social
{17, 3, profession::NONE, unit_labor::NONE, job_skill::PERSUASION, "Pe"},
{17, 3, profession::NONE, unit_labor::NONE, job_skill::NEGOTIATION, "Ne"},
{17, 3, profession::NONE, unit_labor::NONE, job_skill::JUDGING_INTENT, "Ju"},
{17, 3, profession::NONE, unit_labor::NONE, job_skill::LYING, "Li"},
{17, 3, profession::NONE, unit_labor::NONE, job_skill::INTIMIDATION, "In"},
{17, 3, profession::NONE, unit_labor::NONE, job_skill::CONVERSATION, "Cn"},
{17, 3, profession::NONE, unit_labor::NONE, job_skill::COMEDY, "Cm"},
{17, 3, profession::NONE, unit_labor::NONE, job_skill::FLATTERY, "Fl"},
{17, 3, profession::NONE, unit_labor::NONE, job_skill::CONSOLE, "Cs"},
{17, 3, profession::NONE, unit_labor::NONE, job_skill::PACIFY, "Pc"},
// Miscellaneous
{18, 3, profession::NONE, unit_labor::NONE, job_skill::THROW, "Th"},
{18, 3, profession::NONE, unit_labor::NONE, job_skill::CRUTCH_WALK, "CW"},
{18, 3, profession::NONE, unit_labor::NONE, job_skill::KNAPPING, "Kn"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::WRITING, "Wr"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::PROSE, "Pr"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::POETRY, "Po"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::READING, "Rd"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::SPEAKING, "Sp"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::DANCE, "Dn"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::MAKE_MUSIC, "MM"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::SING_MUSIC, "SM"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::PLAY_KEYBOARD_INSTRUMENT, "PK"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::PLAY_STRINGED_INSTRUMENT, "PS"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::PLAY_WIND_INSTRUMENT, "PW"},
{19, 6, profession::NONE, unit_labor::NONE, job_skill::PLAY_PERCUSSION_INSTRUMENT, "PP"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::CRITICAL_THINKING, "CT"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::LOGIC, "Lo"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::MATHEMATICS, "Ma"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::ASTRONOMY, "As"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::CHEMISTRY, "Ch"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::GEOGRAPHY, "Ge"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::OPTICS_ENGINEER, "OE"},
{20, 4, profession::NONE, unit_labor::NONE, job_skill::FLUID_ENGINEER, "FE"},
{21, 5, profession::NONE, unit_labor::NONE, job_skill::MILITARY_TACTICS, "MT"},
{21, 5, profession::NONE, unit_labor::NONE, job_skill::TRACKING, "Tr"},
{21, 5, profession::NONE, unit_labor::NONE, job_skill::MAGIC_NATURE, "Dr"},
};
struct UnitInfo
{
df::unit *unit;
bool allowEdit;
string name;
string transname;
string lastname;
string profession;
string squad_info;
string squad_effective_name;
string job_desc;
string likesline;
string dream;
string tagline;
string godline;
string traits;
string regards;
enum { IDLE, SOCIAL, JOB, MILITARY } job_mode;
bool selected;
struct {
// Used for custom professions, 1-indexed
int list_id; // Position in list
int list_id_group; // Position in list by group (e.g. craftsdwarf)
int list_id_prof; // Position in list by profession (e.g. woodcrafter)
void init() {
list_id = 0;
list_id_group = 0;
list_id_prof = 0;
}
} ids;
string notices;
int8_t color;
int age;
int arrival_group;
int active_index;
int work_aptitude = 0;
int skill_aptitude = 0;
int notice_score;
int demand = 0;
int scholar = 0;
int performer = 0;
int martial = 0;
int medic = 0;
int focus = 0;
int civil = 0;
uint8_t column_aptitudes[NUM_COLUMNS];
int8_t column_hints[NUM_COLUMNS];
bool sort_grouping_hint;
};
int work_aptitude_avg = 0;
int skill_aptitude_avg = 0;
enum detail_cols {
DETAIL_MODE_PROFESSION,
DETAIL_MODE_SQUAD,
DETAIL_MODE_JOB,
DETAIL_MODE_NOTICE,
DETAIL_MODE_ATTRIBUTE,
DETAIL_MODE_MAX
};
const char * const detailmode_shortnames[] = {
"Profession, ",
"Squads, ",
"Actions, ",
"Notices, ",
"Attributes, ",
"n/a"
};
const char * const detailmode_legend[] = {
"Profession", "Squad", "Action", "Notice", "", "n/a"
};
enum wide_sorts {
WIDESORT_UNDER = -1,
WIDESORT_NONE = 0,
WIDESORT_SELECTED,
WIDESORT_PROFESSION,
WIDESORT_SQUAD,
WIDESORT_JOB,
WIDESORT_ARRIVAL,
WIDESORT_OVER
};
const char * const widesort_names[] = {
" All, ",
" Selection ",
" Profession",
" Squads ",
" Actions ",
" Arrivals ",
"n/a",
};
enum fine_sorts {
FINESORT_UNDER = -1,
FINESORT_UNFOCUSED = 0,
FINESORT_STRESS,
FINESORT_SURNAME,
FINESORT_NAME,
FINESORT_TOPSKILLED,
FINESORT_MEDIC,
FINESORT_MARTIAL,
FINESORT_PERFORMER,
FINESORT_SCHOLAR,
FINESORT_COLUMN,
FINESORT_DEMAND,
FINESORT_AGE,
FINESORT_NOTICES,
FINESORT_OVER
};
const char * const finesort_names[] = {
"Unfocus",
"Unkept",
"Surname",
"Name",
"Civil",
"Medic",
"Martial",
"Perform",
"Scholar",
"Column",
"Availed",
"Age",
"Notices",
"n/a"
};
const char * const happy_names[] = {
"Braw","Keen","Flux","Myth","Boon",
"Grit","Okay","Fine","Mojo","Rune",
"Perk","Tale"," ","Hppy","Glad",
"Keep","Soda","Smug","Ease","Zeal",
"Well","Epic","Odes"
};
static int happy_shuffle[] = {
0, 14, 21, 8, 17, 4, 20, 12, 18, 5, 10, 16, 1, 6, 13, 3, 11, 2, 15, 9, 22, 7, 19
};
static string cur_world;
int happy_label_seed = 0;
int detail_mode = 0; //mode settings
int color_mode = 2;
int hint_power = 2;
int show_curse = 0;
int notices_countdown = 0;
bool show_sprites = false;
int show_details = 3;
int tran_names = 1;
int theme_color = 0;
int cheat_level = 0; //cheatmode
int spare_skill = 0;
int sel_attrib = 0;
int maxnamesz = 5; //for screen layout
int row_space = 0;
int dimex = 80, dimey = 30;
int xmargin = 0, xfooter = 0;
int xpanend = 0, xpanover = 0;
static int first_row = 0; //focus position
static int display_rows_b = 0;
static int first_column = 0;
static int sel_column = 0;
static int sel_column_b = 0;
static int sel_row = 0;
static int sel_row_b = 0;
static int sel_unitid = -1;
static wide_sorts widesort_mode = WIDESORT_NONE;
static fine_sorts finesort_mode = FINESORT_NAME;
fine_sorts finesort_mode_b = FINESORT_UNDER;
static wide_sorts widesort_mode_b = WIDESORT_NONE;
static int column_sort_column = -1;
int column_sort_last = 0;
bool cancel_sort = false;
static int const MAX_ALABOR = 128;
static std::map <int, std::vector<bool>> labor_stash;
static map<int, bool> selection_stash;
static bool batchlabor_ran = false;
static bool selection_changed = false;
static int tool_tip = 0;
static int tool_tip_timer = 0;
const char * const tip_settings[] = {
" [ Color Pallete 1/3 ] ",
" [ Color Pallete 2/3 ] ",
" [ Color Pallete 3/3 ] ",
" [ No Aptitude Highlights ] ",
" [ 20% Aptitude Highlights ] ",
" [ 40% Aptitude Highlights ] ",
" [ 60% Aptitude Highlights ] ",
" [ 75% Aptitude Highlights ] ",
" [ Revise Embark Skills ] ",
" [ Edit Skills and Stats ] ",
" [ Left Cheatmode ] ",
" [ No Descriptions ] ",
" [ 1/5 Description Setting ] ",
" [ 2/5 Description Setting ] ",
" [ 3/5 Description Setting ] ",
" [ 4/5 Description Setting ] ",
" [ 5/5 Description Setting ] ",
" [ Curses Hidden From Notes ] ",
" [ Curses Are Revealed ] ",
" [ 1/4 Naming Setting ] ",
" [ 2/4 Naming Setting ] ",
" [ 4/4 Naming Setting ] ",
" [ 3/4 Naming Setting ] ",
" [ All Details Hidden ] ",
" [ Made A Batch Profession ] ",
" [ Made A Profession +Mask+ ] ",
" [ Un-made This Profession ! ] ",
" [ No Profession to un-make ] "
};
void stashSelection(UnitInfo* cur) {
selection_stash[cur->unit->id] = cur->selected; //sel;
}
void stashSelection(vector<UnitInfo *> &units) {
for (size_t i = 0; i < units.size(); i++) {
selection_stash[units[i]->unit->id] = units[i]->selected;
}
}
void unstashSelection(vector<UnitInfo *> &units) {
for (size_t i = 0; i < units.size(); i++) {
if (selection_stash[units[i]->unit->id] == true)
units[i]->selected = true;
else
units[i]->selected = false;
}
}
int unitSkillRating(const UnitInfo *cur, df::job_skill skill)
{
if (!cur->unit->status.current_soul){ return 0; }
df::unit_skill *s = binsearch_in_vector<df::unit_skill, df::job_skill>(cur->unit->status.current_soul->skills, &df::unit_skill::id, skill);
if (s != NULL){ return s->rating; } else { return 0; }
}
int unitSkillExperience(const UnitInfo *cur, df::job_skill skill)
{
if (!cur->unit->status.current_soul){ return 0; }
df::unit_skill *s = binsearch_in_vector<df::unit_skill, df::job_skill>(cur->unit->status.current_soul->skills, &df::unit_skill::id, skill);
if (s != NULL){ return s->experience; } else { return 0; }
}
//widesorts (which form groups)
bool sortBySelected(const UnitInfo *d1, const UnitInfo *d2)
{
return d1->selected > d2->selected;
}
bool sortByProfession (const UnitInfo *d1, const UnitInfo *d2)
{
return (d1->profession < d2->profession);
}
bool sortBySquad (const UnitInfo *d1, const UnitInfo *d2)
{
if (d1->unit->military.squad_id == d2->unit->military.squad_id)
return false;
if (d1->unit->military.squad_id == -1 && d2->unit->military.squad_id != -1)
return false;
if (d2->unit->military.squad_id == -1 && d1->unit->military.squad_id != -1)
return true;
return d1->unit->military.squad_id < d2->unit->military.squad_id ;
}
bool sortByArrival(const UnitInfo *d1, const UnitInfo *d2)
{
return d1->arrival_group < d2->arrival_group;
}
bool sortByEnabled(const UnitInfo *d1, const UnitInfo *d2)
{
if (Units::isBaby(d2->unit) && !Units::isBaby(d1->unit))
return true;
if (Units::isChild(d2->unit) && !(Units::isChild(d1->unit) || Units::isBaby(d1->unit)))
return true;
if ((!d2->allowEdit) && (d1->allowEdit && !(Units::isChild(d1->unit) || Units::isBaby(d1->unit))))
return true;
return false;
}
bool sortByJob(const UnitInfo *d1, const UnitInfo *d2)
{
if (d1->job_mode == UnitInfo::MILITARY && d2->job_mode != UnitInfo::MILITARY)
return true;
if (d2->job_mode == UnitInfo::MILITARY)
return false;
if (d1->job_mode == UnitInfo::IDLE && d2->job_mode != UnitInfo::IDLE)
return true;
if (d2->job_mode == UnitInfo::IDLE)
return false;
if (d1->job_mode == UnitInfo::SOCIAL && d2->job_mode != UnitInfo::SOCIAL)
return true;
if (d1->job_mode != UnitInfo::SOCIAL && d2->job_mode == UnitInfo::SOCIAL)
return false;
if (d1->job_mode == UnitInfo::SOCIAL && d2->job_mode == UnitInfo::SOCIAL)
return d1->job_desc > d2->job_desc;
if (d1->job_mode != d2->job_mode)
return d1->job_mode < d2->job_mode;
return d1->job_desc < d2->job_desc;
}
//finesorts (do before widesorts)
bool sortByScholar(const UnitInfo *d1, const UnitInfo *d2) {
return (d1->scholar > d2->scholar);
}
bool sortByMedic(const UnitInfo *d1, const UnitInfo *d2) {
return (d1->medic > d2->medic);
}
bool sortByNotices(const UnitInfo *d1, const UnitInfo *d2) {
return (d1->notice_score > d2->notice_score);
}
bool sortByMartial(const UnitInfo *d1, const UnitInfo *d2) {
return (d1->martial > d2->martial);
}
bool sortByPerformer(const UnitInfo *d1, const UnitInfo *d2) {
return (d1->performer > d2->performer);
}
bool sortByTopskilled(const UnitInfo *d1, const UnitInfo *d2) {
return (d1->civil > d2->civil);
}
bool sortByDemand(const UnitInfo *d1, const UnitInfo *d2) {
return (d1->demand > d2->demand);
}
bool sortByAge(const UnitInfo *d1, const UnitInfo *d2) {
return (d1->age > d2->age);
}
bool sortByName(const UnitInfo *d1, const UnitInfo *d2) {
return (d1->name < d2->name);
}
bool sortByTransName(const UnitInfo *d1, const UnitInfo *d2) {
return (d1->transname < d2->transname);
}
bool sortBySurName(const UnitInfo *d1, const UnitInfo *d2)
{
return (d1->lastname < d2->lastname) || (d1->lastname == d2->lastname && d1->name < d2->name);
}
bool sortByUnfocused(const UnitInfo *d1, const UnitInfo *d2) {
return (d1->focus < d2->focus);
}
bool sortByStress (const UnitInfo *d1, const UnitInfo *d2)
{
if (!d1->unit->status.current_soul)
return true;
if (!d2->unit->status.current_soul)
return false;
return (d1->unit->status.current_soul->personality.stress_level > d2->unit->status.current_soul->personality.stress_level);
}
bool sortByColumn(const UnitInfo *d1, const UnitInfo *d2)
{
if (!d1->unit->status.current_soul)
return false;
if (!d2->unit->status.current_soul)
return true;
df::job_skill sort_skill = columns[column_sort_column].skill;
df::unit_labor sort_labor = columns[column_sort_column].labor;
int l1 = 0;
int l2 = 0;
if (sort_skill != job_skill::NONE)
{
l1 = unitSkillRating(d1, sort_skill) * 50;
l1 += 25 + unitSkillExperience(d1, sort_skill) * 40 / (skill_levels[l1 / 50].points + 1);
//eg skill 1 = 50, 5 = 250, 10 = 500
l1 *= d1->column_aptitudes[column_sort_column] + 200;
l2 = unitSkillRating(d2, sort_skill) * 50;
l2 += 25 + unitSkillExperience(d2, sort_skill) * 45 / (skill_levels[l2 / 50].points + 1);
l2 *= d2->column_aptitudes[column_sort_column] + 200;
}
if (sort_labor != unit_labor::NONE) {
if (d1->unit->status.labors[sort_labor])
l1 += 10 + l1 / 10;
if (d2->unit->status.labors[sort_labor])
l2 += 10 + l2 / 10;
}
return l1 > l2;
}
bool sortByUnitId(const UnitInfo *d1, const UnitInfo *d2) {
return (d1->unit->id > d2->unit->id);
}//used to find arrival_groups
bool sortByActiveIndex(const UnitInfo *d1, const UnitInfo *d2) {
return (d1->active_index > d2->active_index);
}//used to find arrival_groups
string itos(int n)
{
stringstream ss;
ss << n;
return ss.str();
}
int8_t cltheme_a[] = { //values for alpha background rendering mode
//noskill hint 0 hint 1 hint 2
//BG not set
COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK,
//FG not set
COLOR_DARKGREY, COLOR_YELLOW, COLOR_GREY, COLOR_LIGHTCYAN,
//BG not set and cursor
COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE,
//FG not set and cursor
COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK,
//BG set
COLOR_DARKGREY, COLOR_YELLOW, COLOR_GREY, COLOR_LIGHTCYAN,
//FG set
COLOR_GREY, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE,
//BG set and cursor
COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE,
//FG set and cursor
COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE,
//32 BG mili 33 FG other 34 row hint
COLOR_LIGHTMAGENTA, COLOR_LIGHTMAGENTA, COLOR_BLUE
};
int8_t cltheme_b[] = {
/*noskill hint 0 hint 1 hint 2 */
//BG not set
COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK,
//FG not set
COLOR_DARKGREY, COLOR_YELLOW, COLOR_GREY, COLOR_LIGHTCYAN,
//BG not set and cursor
COLOR_GREY, COLOR_GREY, COLOR_GREY, COLOR_GREY,
//FG not set and cursor
COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK,
//BG set
COLOR_DARKGREY, COLOR_BROWN, COLOR_DARKGREY, COLOR_CYAN,
//FG set
COLOR_GREY, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE,
//BG set and cursor
COLOR_GREY, COLOR_YELLOW, COLOR_GREY, COLOR_LIGHTCYAN,
//FG set and cursor
COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE,
//32 BG mili 33 FG other 34 row hint
COLOR_MAGENTA, COLOR_LIGHTMAGENTA, COLOR_BLUE
};
int8_t cltheme_c[] = {
/*noskill hint 0 hint 1 hint 2 */
//BG not set
COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK,
//FG not set
COLOR_DARKGREY, COLOR_LIGHTRED, COLOR_GREY, COLOR_LIGHTGREEN,
//BG not set and cursor
COLOR_GREY, COLOR_GREY, COLOR_GREY, COLOR_GREY,
//FG not set and cursor
COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, COLOR_BLACK,
//BG set
COLOR_DARKGREY, COLOR_RED, COLOR_DARKGREY, COLOR_GREEN,
//FG set
COLOR_GREY, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE,
//BG set and cursor
COLOR_GREY, COLOR_LIGHTRED, COLOR_GREY, COLOR_LIGHTGREEN,
//FG set and cursor
COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE,
//32 BG mili 33 FG other 34 row hint
COLOR_MAGENTA, COLOR_LIGHTMAGENTA, COLOR_BLUE
};
int8_t *cltheme = cltheme_a;
PersistentDataItem config_kloker;
void save_kloker_config()
{
config_kloker = World::GetPersistentData("kloker/config");
if (!config_kloker.isValid()) {
config_kloker = World::AddPersistentData("kloker/config");
if (!config_kloker.isValid())
return;
}
config_kloker.ival(0) = color_mode + 1;
config_kloker.ival(1) = hint_power;
config_kloker.ival(2) = spare_skill;
config_kloker.ival(3) = show_details + 1;
config_kloker.ival(4) = tran_names;
config_kloker.ival(5) = theme_color;
config_kloker.ival(6) = show_curse;
config_kloker.ival(7) = happy_label_seed;
}
void read_kloker_config()
{
config_kloker = World::GetPersistentData("kloker/config");
if (!config_kloker.isValid()) {
save_kloker_config();
return;
}
color_mode = config_kloker.ival(0) - 1;
if (color_mode == -1) { color_mode = 1; hint_power = 1; }
hint_power = config_kloker.ival(1);
spare_skill = config_kloker.ival(2);
show_details = config_kloker.ival(3) - 1;
if (show_details == -1){ show_details = 1; }
tran_names = config_kloker.ival(4);
theme_color = config_kloker.ival(5);
show_curse = config_kloker.ival(6);
happy_label_seed = config_kloker.ival(7);
if (theme_color == 0){ cltheme = cltheme_a; }
if (theme_color == 1){ cltheme = cltheme_b; }
if (theme_color == 2){ cltheme = cltheme_c; }
}
template<typename T>
class StringFormatter {
public:
typedef string(*T_callback)(T);
typedef std::tuple<string, string, T_callback> T_opt;
typedef vector<T_opt> T_optlist;
static bool compare_opts(const string &first, const string &second)
{
return first.size() > second.size();
}
StringFormatter() {}
void add_option(string spec, string help, string (*callback)(T))
{
opt_list.push_back(std::make_tuple(spec, help, callback));
}
T_optlist *get_options() { return &opt_list; }
void clear_options()
{
opt_list.clear();
}
string grab_opt (string s, size_t start)
{
vector<string> candidates;
for (auto it = opt_list.begin(); it != opt_list.end(); ++it)
{
string opt = std::get<0>(*it);
string slice = s.substr(start, opt.size());
if (slice == opt)
candidates.push_back(slice);
}
if (!candidates.size())
return "";
// Select the longest candidate
std::sort(candidates.begin(), candidates.end(), StringFormatter<T>::compare_opts);
return candidates[0];
}
T_callback get_callback (string s)
{
for (auto it = opt_list.begin(); it != opt_list.end(); ++it)
{
if (std::get<0>(*it) == s)
return std::get<2>(*it);
}
return NULL;
}
string format (T obj, string fmt)
{
string dest = "";
bool in_opt = false;
size_t i = 0;
while (i < fmt.size())
{
if (in_opt)
{
if (fmt[i] == '%')
{
// escape: %% -> %
in_opt = false;
dest.push_back('%');
i++;
}
else
{
string opt = grab_opt(fmt, i);
if (opt.size())
{
T_callback func = get_callback(opt);
if (func != NULL)
dest += func(obj);
i += opt.size();
in_opt = false;
if (i < fmt.size() && fmt[i] == '$')
// Allow $ to terminate format options
i++;
}
else
{
// Unrecognized format option; replace with original text
dest.push_back('%');
in_opt = false;
}
}
}
else
{
if (fmt[i] == '%')
in_opt = true;
else
dest.push_back(fmt[i]);
i++;
}
}
return dest;
}
protected:
T_optlist opt_list;
};
static bool labor_skill_map_made = false;
namespace unit_info_ops {
//these are copied from managelabor.cpp ( skill_attr_weight )
struct skill_attrib_weight {
int8_t phys_attr_weights [6];
int8_t mental_attr_weights [13];
};
const skill_attrib_weight skills_attribs[] =
{ // weights can be 0 to 7, bit3 set (8) means attr is not excercised
// but might possibly affect skills work (like musical_feel > musician)
// S A T E R D A F W C I P M L S M K E S
// t g o n e i n o i r n a e i p u i m o
{ { 1, 0, 1, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MINING */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WOODCUTTING */,
{ { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CARPENTRY */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DETAILSTONE */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MASONRY */,
{ { 0, 1, 1, 1, 0, 0 }, { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 } } /* ANIMALTRAIN */,
{ { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 } } /* ANIMALCARE */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DISSECT_FISH */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DISSECT_VERMIN */,
{ { 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PROCESSFISH */,
{ { 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BUTCHER */,
{ { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* TRAPPING */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* TANNER */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WEAVING */,
{ { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BREWING */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* ALCHEMY */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* CLOTHESMAKING */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MILLING */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PROCESSPLANTS */,
{ { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CHEESEMAKING */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MILK */,
{ { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* COOK */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PLANT */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } /* HERBALISM */,
{ { 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } } /* FISH */,
{ { 1, 0, 1, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SMELT */,
{ { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* EXTRACT_STRAND */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FORGE_WEAPON */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FORGE_ARMOR */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* FORGE_FURNITURE */,
{ { 0, 1, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CUTGEM */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* ENCRUSTGEM */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WOODCRAFT */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* STONECRAFT */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* METALCRAFT */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* GLASSMAKER */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* LEATHERWORK */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BONECARVE */,
{ { 1, 1, 1, 0, 9, 9 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 9 } } /* AXE */,
{ { 1, 1, 1, 0, 9, 9 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 9 } } /* SWORD */,
{ { 1, 1, 1, 0, 9, 9 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 9 } } /* DAGGER */,
{ { 1, 1, 1, 0, 9, 9 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 9 } } /* MACE */,
{ { 1, 1, 1, 0, 9, 9 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 9 } } /* HAMMER */,
{ { 1, 1, 1, 0, 9, 9 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 9 } } /* SPEAR */,
{ { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* CROSSBOW */,
{ { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SHIELD */,
{ { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* ARMOR */,
{ { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SIEGECRAFT */,
{ { 1, 0, 1, 1, 0, 0 }, { 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SIEGEOPERATE */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BOWYER */,
{ { 1, 1, 1, 0, 9, 9 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 9 } } /* PIKE */,
{ { 1, 1, 1, 0, 9, 9 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 9 } } /* WHIP */,
{ { 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BOW */,
{ { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BLOWGUN */,
{ { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* THROW */,
{ { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* MECHANICS */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 9, 9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 9 } } /* MAGIC_NATURE */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SNEAK */,
{ { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* DESIGNBUILDING */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0 } } /* DRESS_WOUNDS */,
{ { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 } } /* DIAGNOSE */,
{ { 0, 1, 0, 0, 0, 9 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SURGERY */,
{ { 1, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SET_BONE */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SUTURE */,
{ { 0, 1, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* CRUTCH_WALK */,
{ { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* WOOD_BURNING */,
{ { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* LYE_MAKING */,
{ { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SOAP_MAKING */,
{ { 1, 0, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* POTASH_MAKING */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DYER */,
{ { 1, 0, 1, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* OPERATE_PUMP */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SWIMMING */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* PERSUASION */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* NEGOTIATION */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1 } } /* JUDGING_INTENT */,
{ { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 } } /* APPRAISAL */,
{ { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 } } /* ORGANIZATION */,
{ { 0, 0, 0, 0, 0, 0 }, { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 9 } } /* RECORD_KEEPING */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1 } } /* LYING */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 } } /* INTIMIDATION */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* CONVERSATION */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 } } /* COMEDY */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* FLATTERY */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 9 } } /* CONSOLE */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* PACIFY */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 9, 0 } } /* TRACKING */,
{ { 0, 1, 0, 0, 0, 9 }, { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } /* KNOWLEDGE_ACQUISITION*/,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } } /* CONCENTRATION */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* DISCIPLINE */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 9 } } /* SITUATIONAL_AWARENESS*/,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 9, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0 } } /* WRITING */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 9, 0, 0, 9, 0, 0, 0, 0, 0 } } /* PROSE */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 9, 0 } } /* POETRY */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0 } } /* READING */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 9, 0, 0, 9, 0, 0, 0, 0, 9 } } /* SPEAKING */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* COORDINATION */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BALANCE */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* LEADERSHIP */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1 } } /* TEACHING */,
{ { 1, 1, 1, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MELEE_COMBAT */,
{ { 1, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* RANGED_COMBAT */,
{ { 1, 1, 1, 0, 0, 9 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WRESTLING */,
{ { 1, 0, 1, 1, 0, 9 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* BITE */,
{ { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* GRASP_STRIKE */,
{ { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* STANCE_STRIKE */,
{ { 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* DODGING */,
{ { 1, 1, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* MISC_WEAPON */,
{ { 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* KNAPPING */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 9, 9, 0, 0, 0, 0, 9, 0, 0, 0, 0 } } /* MILITARY_TACTICS */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* SHEARING */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* SPINNING */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* POTTERY */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* GLAZING */,
{ { 1, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PRESSING */,
{ { 1, 1, 0, 1, 0, 0 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BEEKEEPING */,
{ { 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 } } /* WAX_WORKING */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CLIMBING */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* GELD */,
{ { 0, 9, 0, 9, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0 } } /* DANCE */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 9, 0, 0, 0, 0, 0, 9, 0, 0, 0 } } /* MAKE_MUSIC */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 9, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0 } } /* SING_MUSIC */,
{ { 0, 9, 0, 0, 0, 0 }, { 0, 9, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0 } } /* PLAY_KEYBOARD_INST*/,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 9, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0 } } /* PLAY_STRINGED_INST*/,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 9, 0, 0, 9, 0, 0, 0, 0, 9, 0, 0, 0 } } /* PLAY_WIND_INSTRUMENT*/,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 9, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0 } } /* PLAY_PERCUSSION_INS*/,
{ { 0, 0, 9, 0, 0, 0 }, { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* CRITICAL_THINKING */,
{ { 0, 0, 0, 0, 0, 0 }, { 9, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0 } } /* LOGIC */,
{ { 0, 0, 0, 0, 0, 0 }, { 9, 0, 0, 9, 0, 0, 9, 9, 9, 0, 0, 0, 0 } } /* MATHEMATICS */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 9, 0, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0 } } /* ASTRONOMY */,
{ { 0, 0, 0, 0, 0, 9 }, { 9, 0, 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, 0 } } /* CHEMISTRY */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 9, 0, 0, 0, 9, 0, 9, 0, 0, 0, 9 } } /* GEOGRAPHY */,
{ { 0, 0, 0, 0, 0, 0 }, { 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 0 } } /* OPTICS_ENGINEER */,
{ { 0, 0, 0, 0, 0, 0 }, { 9, 0, 0, 9, 0, 0, 0, 0, 9, 0, 0, 0, 0 } } /* FLUID_ENGINEER */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* PAPERMAKING */,
{ { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } /* BOOKBINDING */
};//S A T E R D A F W C I P M L S M K E S
df::job_skill labor_skill_map[ENUM_LAST_ITEM(unit_labor) + 1];
//similar to labormanager.cpp : generate_labor_to_skill_map()
void make_labor_skill_map()
{
int e = ENUM_LAST_ITEM(unit_labor);
for (int i = 0; i <= e; i++){
labor_skill_map[i] = df::job_skill::NONE;
}
FOR_ENUM_ITEMS(job_skill, skill)
{
int labor = ENUM_ATTR(job_skill, labor, skill);
if (labor > -1 && labor <= e)
labor_skill_map[labor] = skill;
}
}
int aptitude_for_role(UnitInfo *d, df::unit_labor labor, df::job_skill skill)
{
if (!labor_skill_map_made) {
make_labor_skill_map();
labor_skill_map_made = false;
}
int attr_weight = 0;
if (!d->unit->status.current_soul) return 0;
if (labor != unit_labor::NONE && skill == job_skill::NONE)
skill = labor_skill_map[labor];
if (skill == job_skill::NONE) return 0;
int weights = 0, wg = 0, bitmask = 7;
for (int pa = 0; pa < 6; pa++)
{
wg = bitmask & skills_attribs[skill].phys_attr_weights[pa];
if (wg != 0)
{
weights += wg;
attr_weight += wg * (d->unit->body.physical_attrs[pa].value);
}
}
for (int ma = 0; ma < 13; ma++)
{
wg = bitmask & skills_attribs[skill].mental_attr_weights[ma];
if (wg != 0)
{
weights += wg;
attr_weight += wg * (d->unit->status.current_soul->mental_attrs[ma].value);
}
}
if (weights > 1) {
attr_weight /= weights;
}
if (attr_weight < 13 && attr_weight > 0) {
attr_weight = 1;
} else {
attr_weight = ((attr_weight + 12) / 25);
}
if (attr_weight > 200) {
attr_weight = 200;
}
return attr_weight;
}
void allotHintColors(UnitInfo* cur, int column_unit_apt[], int a_col, int e_col, int avg_apt, int unit_apt)
{
int cn = e_col - a_col;
double rank = static_cast<int>(1000 * log2(static_cast<double>(unit_apt + avg_apt) / static_cast<double>(avg_apt + 2)));
rank = (rank * 115) / 100 - 150;
if (rank > 1800) rank = 1800;
if (rank < 0) rank = 0;
const int pwrs[] = {30000, 13500, 7500, 4500}; //display few,,,many hints
int highs = (cn * rank) / pwrs[hint_power] + 1;
int lows = (cn * (1800 - rank)) / pwrs[hint_power] + 1;
for (int j = a_col; j < e_col; j++) {
cur->column_hints[j] = 1;
}
while (highs > 0) {
highs--;
int bval = -100000; // b)efore value
int bpos = 0; // b)efore position
for (int j = a_col; j < e_col; j++)
{
if (cur->column_hints[j] == 1
&& column_unit_apt[j] >= bval)
{
bpos = j;
bval = column_unit_apt[j];
}
}
cur->column_hints[bpos] = 2;
}
while (lows > 0) {
lows--;
int bval = 100000;
int bpos = 0;
for (int j = a_col; j < e_col; j++)
{
if (cur->column_hints[j] == 1
&& column_unit_apt[j] <= bval
&& column_unit_apt[j] > -111111)
{
bpos = j;
bval = column_unit_apt[j];
}
}
cur->column_hints[bpos] = 0;
}
}
const int traitscore[] ={
// mil civ pfm aca med
//hi ln lw
-1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 // LOVE_PROPENSITY
,-2,-1,-2, -1,-1, 0, 0,-2, 0, 0,-2, 0, -2,-2, 0 // HATE_PROPENSITY
,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0 // ENVY_PROPENSITY
, 0, 1,-1, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 1, 0 // CHEER_PROPENSITY
,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // DEPRESSION_PROPENSITY
,-1, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0 // ANGER_PROPENSITY
,-1,-2, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, -1, 0, 0 // ANXIETY_PROPENSITY
, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 // LUST_PROPENSITY
, 0,-2, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0 // STRESS_VULNERABILITY
,-1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 // GREED
, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, -1, 0,-1 // IMMODERATION
,-2, 2,-2, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1,-1, 1 // VIOLENT
, 0, 2,-1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1,-1 // PERSEVERENCE
, 0, 0, 0, 0,-1, 0, 0, 1, 0, 0, 1, 0, -1, 0,-1 // WASTEFULNESS
, 0, 0,-1, 0, 1, 0, 0, 1, 0, 0, 1, 0, -1, 1, 0 // DISCORD
, 0, 1, 0, 0,-1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 // FRIENDLINESS
,-1, 0,-1, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 1,-1 // POLITENESS
,-1, 0,-1, 0, 0, 0, 0,-1, 0, 0,-1, 0, 0, 0, 0 // DISDAIN_ADVICE
,-1, 3,-1, 0,-1, 0, 0, 0, 0, 0,-1, 0, 1, 0, 0 // BRAVERY
, 0, 2,-1, 0,-1, 0, 0, 1, 0, 0, 0, 0, 0, 1,-1 // CONFIDENCE
, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 // VANITY
,-1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0 // AMBITION
,-1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0 // GRATITUDE
,-1,-1, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // IMMODESTY
, 0, 1, 0, 0, 1, 0, 1, 1,-1, 0, 0, 0, 0, 1, 0 // HUMOR
,-3,-1, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, -1,-1, 0 // VENGEFUL
, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // PRIDE
,-3,-2,-1, 0,-1, 0, 0,-2, 1, -1,-1, 0, -5,-2, 2 // CRUELTY
, 0, 0,-2, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1, 1,-1 // SINGLEMINDED
, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 // HOPEFUL
, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 2,-1, 0, 0, 0 // CURIOUS
,-1, 0,-1, 0, 1, 0, -1,-1, 1, 0, 1, 0, -1, 1, 0 // BASHFUL
, 0,-1, 0, 0, 1, 0, 0,-2, 1, 0, 1, 0, 0, 0, 0 // PRIVACY
, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0,-2 // PERFECTIONIST
, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0,-1, 0, 0, 0, 0 // CLOSEMINDED
, 0, 2,-1, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 2,-1 // TOLERANT
,-1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0 // EMOTION OBSESSIVE
,-2, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, -2, 0, 0 // SWAYED_BY_EMOTION
,-1, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2,-1 // ALTRUISM
, 1, 2,-2, 0, 1, 0, 0,-1, 0, 0,-1, 0, 0, 0, 0 // DUTIFULNESS
,-1, 0,-1, 1, 0, 1, 0, 0, 0, 0, 0, 0, -1, 0, 0 // THOUGHTLESSNESS
,-1, 1, 0, 0, 2,-1, 0,-1, 0, 0, 1, 0, 0, 1, 0 // ORDERLINESS
,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // TRUST
, 0, 1, 0, 0,-2, 1, 0, 3,-1, -1, 1, 1, 0, 1,-1 // GREGARIOUSNESS
, 1, 1, 0, 0,-1, 1, 0, 0, 0, 0, 0, 1, -1, 1, 0 // ASSERTIVENESS
, 0, 2, 0, 2, 3,-1, 0, 0, 0, 0, 0, 0, 0, 1,-1 // ACTIVITY_LEVEL
, 1, 1, 0, -1,-3, 2, 0, 0, 0, -1,-1, 0, 0, 0, 0 // EXCITEMENT_S
,-1, 0, 1, 0, 0, 0, 0, 4, 0, 2, 2,-1, -1, 0, 0 // IMAGINATION
, 0,-1, 0, -1,-1, 0, 0, 1, 0, 2, 2,-1, -1, 0, 0 // ABSTRACT_INCLINED
,-1, 0, 1, 1, 1, 0, 1, 1,-1, 0, 1, 0, 0, 0, 0 // ART_INCLINED
};
const int regardscore[] ={
//mil civ pfm aca med
2 ,-1 ,-1 , 0 , 0 //"Law"
, 2 , 0 , 1 , 0 , 0 //"Loyal"
,-1 , 1 , 1 , 0 , 0 //"Family"
, 1 , 0 , 0 , 1 , 1 //"Friendship"
, 0 , 0 , 0 , 1 , 0 //"Power"
, 0 , 0 , 0 , 1 , 0 //"Truth"
, 0 , 0 , 0 , 0 , 0 //"Cunning"
, 0 , 0 , 1 , 1 , 0 //"Eloquence"
, 1 , 0 , 1 , 0 , 1 //"Equity"
, 0 , 0 , 0 , 0 , 1 //"Decorum"
, 0 , 0 , 0 , 0 , 0 //"Tradition"
, 0 , 1 , 0 , 1 , 0 //"Art"
, 1 , 0 , 1 , 0 , 0 //"Accord"
,-2 , 1 , 1 , 2 , 0 //"Freedom"
, 1 , 0 ,-1 , 0 , 0 //"Stoicism"
,-1 , 0 , 1 , 2 , 0 //"SelfExam"
, 1 , 0 , 1 , 0 , 1 //"SelfCtrl"
,-2 , 1 ,-1 , 2 , 0 //"Quiet"
, 1 , 0 , 1 , 0 , 1 //"Harmony"
, 1 , 0 , 1 , 0 , 0 //"Mirth"
,-1 , 3 ,-2 ,-1 ,-1 //"Craftwork"
, 3 ,-2 ,-2 , 0 ,-1 //"Combat"
, 2 , 1 , 0 ,-1 , 0 //"Skill"
, 1 , 3 ,-1 ,-1 , 1 //"Labour"
, 2 , 0 , 0 ,-1 , 1 //"Sacrifice"
, 2 , 0 , 0 , 0 ,-1 //"Rivalry"
, 2 , 0 , 0 , 0 , 1 //"Grit"
,-1 ,-2 , 1 , 0 ,-1 //"Leisure"
, 0 , 1 , 1 , 1 , 0 //"Commerce"
, 0 , 1 , 1 , 1 , 0 //"Romance"
,-1 , 1 , 0 , 1 , 1 //"Nature"
,-1 , 1 , 1 , 0 , 1 //"Peace"
,-1 ,-1 ,-1 , 4 , 1 //"Lore"
};
const int dreamscore[] ={
//mil civ pfm aca med
10 ,10 ,10 ,10 ,10 // "Surviving"
,10 ,10 ,11 ,11 ,10 // "Status"
, 9 ,10 ,10 ,10 ,10 // "Family"
,11 ,10 ,11 ,11 ,10 // "Power"
, 9 ,12 ,10 ,10 ,10 // "Artwork"
, 9 ,12 , 8 , 9 , 9 // "Craftwork"
,10 ,10 ,10 ,11 ,10 // "Peace"
,12 ,10 , 9 , 9 ,10 // "Combat"
,11 ,11 ,10 , 9 ,11 // "Skill"
,10 ,11 ,11 ,10 ,10 // "Romance"
,12 ,10 ,10 ,11 ,10 // "Voyages"
, 7 , 8 , 8 , 9 , 8 // "Immortality"
};
static int adjustscores[] = { 0, 0, 0, 0, 0 }; //mil civ pfm aca med
void assess_traits(UnitInfo *cur) {
int sn = 5; //nb of scores
int pc = 0, x = 0;
adjustscores[0] = adjustscores[1] = adjustscores[2] =
adjustscores[3] = adjustscores[4] = 10;
if (!(cur->unit->status.current_soul)) return;
df::unit_soul *soul = cur->unit->status.current_soul;
if (true) {
auto traits = soul->personality.traits;
for (int c = 0; c < 50; c++)
{
pc = ((int)traits[c]) - 50;
for (int q = 0; q < sn; q++)
{
if (pc > 13) { //high adjust
adjustscores[q] += (traitscore[x] * (pc - 13) * 3) / 2;
} else if (pc < -13) { //low adjust
adjustscores[q] -= (traitscore[x + 2] * (pc + 13) * 3) / 2;
}
//linear adjust
adjustscores[q] += traitscore[x + 1] * pc;
x += 3;
}
}
//cerr << "traits adjust " << 0 << ":sco:" << adjustscores[0]<<"\n";
//cerr << "traits adjust " << 1 << ":sco:" << adjustscores[1]<<"\n";
//cerr << "traits adjust " << 2 << ":sco:" << adjustscores[2]<<"\n";
//cerr << "traits adjust " << 3 << ":sco:" << adjustscores[3]<<"\n";
//cerr << "traits adjust " << 4 << ":sco:" << adjustscores[4]<<"\n";
}
if (&soul->personality.values) {
auto &regards = soul->personality.values;
int vn = regards.size();
for (int c = 0; c < vn; c++)
{
int rc = ((int)regards[c]->type);
int pc = ((int)regards[c]->strength);
pc = (pc > 25) ? 25 : (pc < -25) ? -25 : pc;
for (int q = 0; q < sn; q++)
{
adjustscores[q] += regardscore[rc * sn + q] * pc * 2;
}
}
//cerr << "+values adjust " << 0 << ":sco:" << adjustscores[0]<<"\n";
}
if (&soul->personality.dreams) {
int cn = soul->personality.dreams.size() - 1;
if (cn > -1) {
int dr = soul->personality.dreams[cn]->type;
if (dr > -1) {
for (int q = 0; q < sn; q++)
{
int adj = dreamscore[dr * sn + q];
adjustscores[q] = (adjustscores[q] * adj) / 10 + (adj - 10) * 25;
}
}
}
//cerr << "+dreams adjust " << 0 << ":sco:" << adjustscores[0]<<"\n";
}
}
void calcAptScores(vector<UnitInfo*> &units)
{
int unit_workapt_sum = 0;
int unit_skillapt_sum = 0;
int alls_workapt_sum = 0;
int alls_skillapt_sum = 0;
int unit_work_count = 0;
int unit_skill_count = 0;
int all_work_count = 0;
int all_skill_count = 0;
int uinfo_avg_work_aptitude = 0;
int uinfo_avg_skill_aptitude = 0;
int column_total_apt[NUM_COLUMNS] = {};
int column_total_skill[NUM_COLUMNS] = {};
int unit_count = units.size();
int col_end = NUM_COLUMNS - 1;
for (size_t i = 0; i < unit_count; i++)
{
UnitInfo *cur = units[i];
for (size_t j = 0; j <= col_end; j++)
{
df::unit_labor cur_labor = columns[j].labor;
df::job_skill cur_skill = columns[j].skill;
int sco = unit_info_ops::aptitude_for_role(cur, cur_labor, cur_skill);
cur->column_aptitudes[j] = (uint8_t)sco;
if (cur_labor != unit_labor::NONE || columns[j].profession != profession::NONE)
{
if (sco) unit_work_count++;
unit_workapt_sum += sco;
}
else //skill onlys
{
if (sco) unit_skill_count++;
unit_skillapt_sum += sco;
}
int wskill = unitSkillRating(cur, cur_skill);
column_total_apt[j] += sco;
column_total_skill[j] += wskill;
if (j == col_end) //last col. next unit...
{
cur->work_aptitude = (unit_work_count == 0) ? 0
: unit_workapt_sum / unit_work_count;
cur->skill_aptitude = (unit_skill_count == 0) ? 0
: unit_skillapt_sum / unit_skill_count;
alls_workapt_sum += unit_workapt_sum;
alls_skillapt_sum += unit_skillapt_sum;
all_work_count += unit_work_count;
all_skill_count += unit_skill_count;
unit_workapt_sum = unit_work_count = 0;
unit_skillapt_sum = unit_skill_count = 0;
}
}
}
uinfo_avg_work_aptitude = (alls_workapt_sum + 1) / (all_work_count + 1);
uinfo_avg_skill_aptitude = (alls_skillapt_sum + 1) / (all_skill_count + 1);
int uinfo_avg_aptitude =
(alls_workapt_sum + alls_skillapt_sum + 1)
/ (all_skill_count + all_work_count + 1);
int column_unit_apt[NUM_COLUMNS] = {};
int dither = 123;
//sweep again to set hints
for (size_t i = 0; i < unit_count; i++)
{
UnitInfo *cur = units[i];
//make normalised apt vals
for (size_t j = 0; j <= col_end; j++)
{
int col_avg = column_total_apt[j] / unit_count;
//make adjusted apts
if (column_total_apt[j]) {
column_unit_apt[j] = 5 * (cur->column_aptitudes[j] - (col_avg * 2) / 3);
column_unit_apt[j] += (j * j * j ^ dither++) % 5; //psuedofundom
} else {
column_unit_apt[j] = -111111; //out of hint range for noskill roles
}
}
int skill_col = 75; //this division doesnt need to be totaly precise
allotHintColors(cur, column_unit_apt, 0, skill_col, uinfo_avg_work_aptitude, cur->work_aptitude);
allotHintColors(cur, column_unit_apt, skill_col, NUM_COLUMNS, uinfo_avg_skill_aptitude, cur->skill_aptitude);
}//units
//sweep again to set skill class scores
for (size_t i = 0; i < unit_count; i++)
{
UnitInfo *cur = units[i];
cur->scholar = 0;
cur->performer = 0;
cur->martial = 0;
cur->civil = 0;
for (size_t j = 0; j <= col_end; j++)
{
int avg_skill = column_total_skill[j] / unit_count;
df::unit_labor col_labor = columns[j].labor;
df::job_skill col_skill = columns[j].skill;
int group = columns[j].group;
int mskill = 1 + unitSkillRating(cur, col_skill);
int wskill = unitSkillRating(cur, col_skill); //0 to 20
wskill = wskill * 4 + ((wskill + 2) * cur->column_aptitudes[j]) / 11 ;
wskill = static_cast<int>(std::sqrt(static_cast<double>(wskill)));
//approx 5 to 20
if (group < 11) {
if (col_skill == df::job_skill::WOODCUTTING
|| col_skill == df::job_skill::DISSECT_VERMIN
|| col_skill == df::job_skill::GELD
|| col_skill == df::job_skill::MILK
|| col_skill == df::job_skill::SHEARING
|| col_skill == df::job_skill::WOOD_BURNING)
{
cur->civil += static_cast<int>(wskill * std::sqrt(static_cast<double>(mskill) / static_cast<double>(10 + avg_skill * 2)));
} else {
cur->civil += static_cast<int>(wskill * std::sqrt(static_cast<double>(mskill) / static_cast<double>(5 + avg_skill)));
}
}
//martial
if ((group > 12 && group < 16)
|| col_skill == df::job_skill::MILITARY_TACTICS
|| col_skill == job_skill::PACIFY)
{
if (col_skill == df::job_skill::TEACHING) {
cur->martial += wskill / 4 + (cur->martial * wskill) / (300);
} else {
cur->martial += mskill;
}
if (group == 13) {
cur->martial += wskill / 4;
}
}
if (col_skill == df::job_skill::DISCIPLINE) cur->martial += wskill;
if (col_skill == df::job_skill::KNOWLEDGE_ACQUISITION
|| col_skill == df::job_skill::DODGING)
{
cur->martial += wskill / 4;
}
if (group == 17
|| col_skill == df::job_skill::LEADERSHIP
|| col_skill == df::job_skill::ORGANIZATION)
{
cur->martial += wskill / 9;
}
//scholar
if (col_skill == df::job_skill::TEACHING
|| col_skill == df::job_skill::CONCENTRATION
|| col_skill == df::job_skill::WRITING
|| col_skill == df::job_skill::READING
|| col_skill == df::job_skill::KNOWLEDGE_ACQUISITION
|| col_skill == df::job_skill::CONVERSATION
|| group == 21)
{
cur->scholar += wskill;
}
//performer
if (group == 19 && col_skill != df::job_skill::WRITING
|| col_skill == job_skill::COMEDY
|| col_skill == job_skill::FLATTERY
|| col_skill == job_skill::CONSOLE
|| col_skill == job_skill::PACIFY)
{
if (group == 19) {
cur->performer += wskill;
} else {
cur->performer += wskill / 2;
}
}
//medic
if (col_skill == job_skill::DRESS_WOUNDS
|| col_skill == job_skill::SUTURE
|| col_skill == job_skill::SET_BONE
|| col_skill == job_skill::SURGERY
|| col_skill == job_skill::DIAGNOSE)
{
cur->medic += wskill;
}
}
cur->martial += cur->unit->body.physical_attrs[4].value / 180; //recoupe
cur->martial += cur->unit->body.physical_attrs[5].value / 320; //disease
assess_traits(cur);
//mil civ pfm aca med
//cerr << "martial " << cur->martial <<"\n";
//cerr << "civil " << cur->civil<<"\n";
//cerr << "perform " << cur->performer<<"\n";
//cerr << "scholar " << cur->scholar<<"\n";
//cerr << "medic " << cur->medic<<"\n";
cur->martial = cur->martial * 3 + adjustscores[0];
cur->civil = cur->civil * 4 + adjustscores[1];
cur->performer = cur->performer * 4 + adjustscores[2];
cur->scholar = cur->scholar * 4 + adjustscores[3];
cur->medic = cur->medic * 5 + adjustscores[4];
}
work_aptitude_avg = uinfo_avg_work_aptitude ;
skill_aptitude_avg = uinfo_avg_skill_aptitude;
}//end of scoring.. next comes notice string gen
//from cursecheck.cpp
string determineCurse(df::unit * unit)
{
string cursetype = "";
if (unit->curse_year == -1) return cursetype;
cursetype = "Shade "; //an unresting soul ghost was this
if (!unit->curse.add_tags1.bits.NOT_LIVING
&& unit->curse.add_tags2.bits.NO_AGING)
cursetype = "Imortal ";
if (unit->flags3.bits.ghostly)
cursetype = "Ghost ";
if ((unit->curse.add_tags1.bits.OPPOSED_TO_LIFE || unit->curse.add_tags1.bits.NOT_LIVING)
&& !unit->curse.add_tags1.bits.BLOODSUCKER)
cursetype = "Zmbie ";
if (!unit->curse.add_tags1.bits.NOT_LIVING
&& unit->curse.add_tags1.bits.NO_EAT
&& unit->curse.add_tags1.bits.NO_DRINK
&& unit->curse.add_tags2.bits.NO_AGING)
cursetype = "Ncrmncr ";
if (!unit->curse.add_tags1.bits.NOT_LIVING
&& !unit->curse.add_tags1.bits.NO_EAT
&& !unit->curse.add_tags1.bits.NO_DRINK
&& unit->curse.add_tags2.bits.NO_AGING)
cursetype = "Werebst ";
if (unit->curse.add_tags1.bits.BLOODSUCKER)
cursetype = "Vampr ";
return cursetype;
}
void calcNotices(vector<UnitInfo *> &units)
{
for (size_t i = 0; i < units.size(); i++)
{
units[i]->notices = "";
units[i]->notice_score = 0;
df::unit *curu = units[i]->unit;
if (!(curu->status.current_soul)) {
units[i]->notices = "Husk";
units[i]->notice_score = 0;
continue;
}
string lks = "";
string iss = "";
int iscore = 0;
int newwnd = 0;
int oldwnd = 0;
//if(curu->body)
for (size_t a = 0; a < curu->body.wounds.size(); a++)
{
df::unit_wound* wound = curu->body.wounds[a];
if (wound->age != 0 && wound->age < 111) {
newwnd++;
} else if (wound->age >= 500) {
//oldwnd++;
}
}
if (show_curse) {
iss += determineCurse(units[i]->unit);
}
if (curu->flags2.bits.underworld && show_curse) {
iss += "Undrwld "; iscore += 2000;
}
if (curu->flags2.bits.killed) {
iss += "Dead "; iscore += 1330;
}
if (curu->flags3.bits.available_for_adoption) {
iss += "Orphan "; iscore += 600;
}
if (curu->flags1.bits.marauder) {
iss += "Maraudr "; iscore += 900;
}
if (curu->flags1.bits.active_invader) {
iss += "Invadr "; iscore += 900;
}
else if (curu->flags2.bits.visitor_uninvited && show_curse) {
iss += "Intrudr "; iscore += 900;
}
//~ if(!curu->flags1.bits.important_historical_figure){ iss+="Fauna "; iscore+=1;}
if (curu->pregnancy_timer > 0) {
iss += "Pregnt "; iscore += 700;
}
if (curu->flags1.bits.has_mood) {
iss += "Mood "; iscore += 305;
}
if (curu->flags1.bits.drowning) {
iss += "Drowning "; iscore += 2000;
}
if (curu->flags1.bits.projectile) {
iss += "Falling "; iscore += 945;
}
if (curu->flags3.bits.dangerous_terrain) {
iss += "DngrTrrn "; iscore += 600;
}
if (curu->flags3.bits.floundering) {
iss += "Flundrg "; iscore += 600;
}
if (curu->counters.suffocation) {
iss += "Suffcatn "; iscore += 2000;
}
if (curu->counters.pain > 10) {
iss += "Agony "; iscore += 700;
}
if (curu->health) {
if (curu->health->flags.bits.needs_recovery) {
iss += "RqRescue "; iscore += 1600;
} else if (curu->health->flags.bits.rq_diagnosis) {
iss += "RqDoctor "; iscore += 1200;
} else if (curu->health->flags.bits.rq_immobilize
|| curu->health->flags.bits.rq_surgery
|| curu->health->flags.bits.rq_traction
|| curu->health->flags.bits.rq_immobilize)
{
iss += "NdSurgry "; iscore += 1300;
} else if (curu->health->flags.bits.rq_dressing
|| curu->health->flags.bits.rq_cleaning
|| curu->health->flags.bits.rq_suture
|| curu->health->flags.bits.rq_setting
|| curu->health->flags.bits.rq_crutch)
{
iss += "NdNurse "; iscore += 700;
} else if (newwnd && iscore < 1308) {
iss += "Ruffdup "; iscore += 403;
}
}
if (curu->flags1.bits.chained) {
iss += "Chaind "; iscore += 500;
} else if (curu->flags1.bits.caged) {
iss += "Trappd "; iscore += 500;
}
int exh = curu->counters2.exhaustion;
if (exh > 5000) {
iss += "Xhaustd "; iscore += 601;
}
if (curu->flags2.bits.vision_damaged) {
iss += "VisnDmg "; iscore += 809;
}
if (curu->flags2.bits.breathing_problem) {
iss += "LungDmg "; iscore += 608;
}
//name=SYndrometype->syn_name ?
int unknowns = 0;
string addlater;
//if(curu->syndromes)
for (size_t b = 0; b < curu->syndromes.active.size(); b++)
{
int q = curu->syndromes.active[b]->type;
if (q == 63 || q == 60) {
addlater = "Drunk "; iscore += 103;
} else {
unknowns++; iscore += 303;
}
}
if (unknowns > 0) {
if (unknowns > 1) iss += "Sick ";
else iss += "Intxctd ";
}
if (curu->counters2.stored_fat < 3000 && curu->counters2.hunger_timer > 3000) {
iss += "XStarvtn "; iscore += 2000;
} else if (curu->counters2.stored_fat < 9000) {
iss += "Emaciatd "; iscore += 905;
}
if (curu->flags3.bits.injury_thought) {
iss += "Pained "; iscore += 402;
}
if (curu->status2.limbs_grasp_max == 2) {
if (curu->status2.limbs_grasp_count == 1) {
iss += "OneHndd "; iscore += 107;
} else if (curu->status2.limbs_grasp_count == 0) {
iss += "NoGrasp "; iscore += 308;
}
}
if (curu->status2.limbs_stand_max == 2) {
if (curu->status2.limbs_stand_count == 1) {
iss += "OneLegd "; iscore += 103;
} else if (curu->status2.limbs_stand_count == 0) {
iss += "BadLegs "; iscore += 303;
}
}
if (curu->flags3.bits.emotionally_overloaded) {
iss += "Despair "; iscore += 1013;
}
//if(curu->counters.unconscious){ iss += "Unconsc. "; iscore += 800;}
if (curu->counters2.numbness) {
iss += "Numb "; iscore += 1055;
}
if (curu->counters.stunned) {
iss += "Stund "; iscore += 633;
}
if (curu->counters.nausea > 1000) {
iss += "Naus "; iscore += 210;
}
if (curu->counters.dizziness > 1000) {
iss += "Dzzy "; iscore += 500;
}
if (curu->counters2.paralysis) {
iss += "Parlysd "; iscore += 3005;
}
if (curu->counters2.fever > 10) {
iss += "Fever "; iscore += 1002;
}
if (curu->counters2.thirst_timer > 30000) {
iss += "Dehydt "; iscore += 1005;
}
if (curu->counters2.sleepiness_timer > 55000) {
iss += "vSleepy "; iscore += 609;
}
if (exh <= 5000 && exh > 2500) {
iss += "Tired "; iscore += 202;
}
//if(curu->status)
for (int r = 0; r < curu->status.misc_traits.size(); r++)
{
auto tr = curu->status.misc_traits[r];
//up to 403200 ?
if (tr->id == df::misc_trait_type::WantsDrink) {
if (tr->value > 200000) { iss += "NdBooz "; }
else if (tr->value > 100000) { iss += "vDry "; }
else if (tr->value > 40000) { iss += "Dry ";}
if (tr->value > 2000) iscore += tr->value / 666;
}
if (tr->id == df::misc_trait_type::NoPantsAnger) {
if (tr->value > 20) {
iss += "nPants ";
iscore += tr->value / 100;
}
}
if (tr->id == df::misc_trait_type::NoShirtAnger) {
if (tr->value > 20) {
iss += "nShirt ";
iscore += tr->value / 100;
}
}
if (tr->id == df::misc_trait_type::NoShoesAnger) {
if (tr->value > 20) {
iss += "nShoes ";
iscore += tr->value / 100;
}
}
}
iss += addlater;
//units[i]->likes = "na"; //not done yet
units[i]->notices = iss;
units[i]->notice_score = iscore;
}
}
//pinched from dwarfmonitor
df::world_raws::T_itemdefs &defs = world->raws.itemdefs;
// COIN ROCK SLAB PET GEM CABINET BIN BOX TABLE BARREL CHAIN CHAIR BED DOOR ROUGH
string getItemLabel(int &item_type, int &subtype)
{
string label;
if (subtype != -1) {
switch (item_type)
{
case (df::item_type::WEAPON):
if (defs.weapons.size() > subtype && defs.weapons[subtype])
label = defs.weapons[subtype]->name_plural;
break;
case (df::item_type::TRAPCOMP):
if (defs.trapcomps.size() > subtype && defs.trapcomps[subtype])
label = defs.trapcomps[subtype]->name_plural;
break;
case (df::item_type::PET):
label = "pet";
break;
case (df::item_type::TOOL):
if (defs.tools.size() > subtype && defs.tools[subtype])
label = defs.tools[subtype]->name_plural;
break;
//~ case (df::item_type::INSTRUMENT):
//~ if(defs.instruments[subtype])
//~ label = defs.instruments[subtype]->name_plural;
//~ break;
case (df::item_type::ARMOR):
if (defs.armor.size() > subtype && defs.armor[subtype])
label = defs.armor[subtype]->name_plural;
break;
case (df::item_type::AMMO):
if (defs.ammo.size() > subtype && defs.ammo[subtype])
label = defs.ammo[subtype]->name_plural;
break;
//~ case (df::item_type::SIEGEAMMO):
//~ if(defs.siege_ammo[subtype])
//~ label = defs.siege_ammo[subtype]->name_plural;
//~ break;
case (df::item_type::GLOVES):
if (defs.gloves.size() > subtype && defs.gloves[subtype])
label = defs.gloves[subtype]->name_plural;
break;
case (df::item_type::SHOES):
if (defs.shoes.size() > subtype && defs.shoes[subtype])
label = defs.shoes[subtype]->name_plural;
break;
case (df::item_type::SHIELD):
if (defs.shields.size() > subtype && defs.shields[subtype])
label = defs.shields[subtype]->name_plural;
break;
case (df::item_type::HELM):
if (defs.helms.size() > subtype && defs.helms[subtype])
label = defs.helms[subtype]->name_plural;
break;
case (df::item_type::PANTS):
if (defs.pants.size() > subtype && defs.pants[subtype])
label = defs.pants[subtype]->name_plural;
break;
default:
break;
}
} else {
switch (item_type)
{
case (df::item_type::DOOR):
label = "doors";
break;
case (df::item_type::CHAIR):
label = "thrones";
break;
case (df::item_type::TABLE):
label = "tables";
break;
case (df::item_type::BED):
label = "beds";
break;
case (df::item_type::CHAIN):
label = "chains";
break;
case (df::item_type::WINDOW):
label = "windows";
break;
case (df::item_type::CAGE):
label = "cages";
break;
case (df::item_type::BARREL):
label = "barrels";
break;
case (df::item_type::BUCKET):
label = "buckets";
break;
case (df::item_type::COFFIN):
label = "coffins";
break;
case (df::item_type::STATUE):
label = "statues";
break;
case (df::item_type::ARMORSTAND):
label = "armor stands";
break;
case (df::item_type::WEAPONRACK):
label = "weapon racks";
break;
case (df::item_type::COIN):
label = "coins";
break;
case (df::item_type::SLAB):
label = "slabs";
break;
case (df::item_type::BOOK):
label = "book";
break;
case (df::item_type::CABINET):
label = "cabinets";
break;
case (df::item_type::BIN):
label = "bins";
break;
case (df::item_type::ANVIL):
label = "anvils";
break;
case (df::item_type::TRAPPARTS):
label = "mechanisms";
break;
case (df::item_type::ROUGH):
label = "gems";
break;
case (df::item_type::SMALLGEM):
label = "small gems";
break;
case (df::item_type::GEM):
label = "large gems";
break;
case (df::item_type::CROWN):
label = "crowns";
break;
case (df::item_type::RING):
label = "rings";
break;
case (df::item_type::EARRING):
label = "earrings";
break;
case (df::item_type::BRACELET):
label = "bracelets";
break;
case (df::item_type::PET):
label = "pets";
break;
default:
break;
}
}
return label;
}
const char * const adverb[] = {
"Incredibly ", "Extremely ", "Really ", "Rather ", "A bit "
};
const char * const Regardnom[] = {
"Law"
, "Loyal"
, "Family"
, "Friendship"
, "Power"
, "Truth"
, "Cunning"
, "Eloquence"
, "Equity"
, "Decorum"
, "Tradition"
, "Art"
, "Accord"
, "Freedom"
, "Stoicism"
, "SelfExam"
, "SelfCtrl"
, "Quiet"
, "Harmony"
, "Mirth"
, "Craftwork"
, "Combat"
, "Skill"
, "Labour"
, "Sacrifice"
, "Rivalry"
, "Grit"
, "Leisure"
, "Commerce"
, "Romance"
, "Nature"
, "Peace"
, "Lore"
};
const char * const dreamnom[] = {
"Surviving"
, "Status"
, "Family"
, "Power"
, "Artwork"
, "Craftwork"
, "Peace"
, "Combat"
, "Skill"
, "Romance"
, "Voyages"
, "Immortality"
};
const char * const traitnom[] = {
"adoring" ,"aloof" //LOVE_PROPENSITY
,"hostile" ,"cool" //HATE_PROPENSITY
,"envious" ,"unenvious" //ENVY_PROPENSITY
,"cheerful" ,"grumpy" //CHEER_PROPENSIT
,"depressive","resilient" //DEPRESSION_PROP
,"irritable" ,"calm" //ANGER_PROPENSIT
,"anxious" ,"assured" //ANXIETY_PROPENS
,"salacious" ,"chaste" //LUST_PROPENSITY
,"brittle" ,"robust" //STRESS_VULNERAB
,"greedy" ,"generous" //GREED
,"impetuous" ,"measured" //IMMODERATION
,"fierce" ,"peaceful" //VIOLENT
,"resolute" ,"yielding" //PERSEVERENCE
,"wasteful" ,"frugal" //WASTEFULNESS
,"boisterous","cordial" //DISCORD
,"friendly" ,"quarrelsome"//FRIENDLINESS
,"polite" ,"rude" //POLITENESS
,"obstinate" ,"receptive" //DISDAIN_ADVICE
,"brave" ,"cowardly" //BRAVERY
,"confident" ,"unsure" //CONFIDENCE
,"vain" ,"humble" //VANITY
,"driven" ,"recumbent" //AMBITION
,"grateful" ,"ungrateful" //GRATITUDE
,"pompous" ,"austere" //IMMODESTY
,"funny" ,"dour" //HUMOR
,"vengeful" ,"forgiving" //VENGEFUL
,"proud" ,"modest" //PRIDE
,"cruel" ,"kind" //CRUELTY
,"adamant" ,"inattentive"//SINGLEMINDED
,"optimistic","pessimistic"//HOPEFUL
,"inquisitive","incurious" //CURIOUS
,"bashful" ,"brazen" //BASHFUL
,"indiscreet","secretive" //PRIVACY
,"fastidious","sloppy" //PERFECTIONIST
,"stubborn" ,"fickle" //CLOSEMINDED
,"inclusive" ,"insular" //TOLERANT
,"doting" ,"independent"//EMOTIONALLY_OBS
,"impulsive" ,"impassive" //SWAYED_BY_EMOTI
,"helpful" ,"selfish" //ALTRUISM
,"dutiful" ,"unruly" //DUTIFULNESS
,"rash" ,"tentative" //THOUGHTLESSNESS
,"tidy" ,"messy" //ORDERLINESS
,"trusting" ,"cynical" //TRUST
,"gregarious","solitary" //GREGARIOUSNESS
,"assertive" ,"passive" //ASSERTIVENESS
,"active" ,"leisurely" //ACTIVITY_LEVEL
,"intrepid" ,"reticent" //EXCITEMENT_SEEK
,"fanciful" ,"serious" //IMAGINATION
,"contemplative","practical"//ABSTRACT_INCLIN
,"artistic" ,"inartistic" //ART_INCLINED
};
string get_name_string(df::language_name &name) {
string ret = Translation::capitalize(name.first_name) + " ";
for (int i = 0; i < 2; i++)
{
if (name.words[i] >= 0)
ret += *world->raws.language.translations[name.language]->words[name.words[i]];
}
return Translation::capitalize(ret);
}
void setDescriptions(UnitInfo * uin)
{
uin->dream = "";
uin->traits = "";
uin->likesline = "";
uin->regards = "";
uin->tagline = " ";
uin->godline = "";
auto unit = uin->unit;
if (!(unit->status.current_soul)) { return; }
int uid = uin->unit->id;
int figid = unit->hist_figure_id;
int mother = 0, father = 0, spouse = 0, sibling = 0, child = 0, lover = 0, prisoner = 0, inprison = 0, master = 0, apprentice = 0, pets = 0
, companion = 0, fmaster = 0, fapp = 0, petown = 0, heros = 0, stars = 0, friends = 0, aquaints = 0, comrades = 0, lsoldiers = 0, grudges = 0, bullies = 0, foes = 0;
string gods;
int kids = 0, rels = 0, kin = 0;
int momfid = 0, dadfid = 0;
int momuid = -2, daduid = -2;
string kills, books, momname;
if (figid != -1) {
df::historical_figure *figure;
if (Units::getNemesis(unit)) figure = Units::getNemesis(unit)->figure;
//if(figure->info->kills.size()) kills =" kll"+to_string(figure->info->kills);
//if(figure->info->books) books =" bks"+to_string(figure->info->books);
//these are histfig relation enum now.. rewrite later..
enum class rattitude {
aqua = 1
, frie = 2
, star = 4
, loya = 8
, comr = 16
, hero = 32
, grud = 64
, bull = 128
, foe = 256
};
rels = (figure->info->relationships->list).size();
if (figure->info->relationships)
for (int nk = 0; nk < (figure->info->relationships->list).size(); nk++)
{
int relatq = 0;
if ((figure->info->relationships->list[nk]->attitude).size() == 0)
relatq |= (int)rattitude::aqua;
for (int x = 0; x < (figure->info->relationships->list[nk]->attitude).size(); x++)
{ //(attitude was anon_3)
switch (figure->info->relationships->list[nk]->attitude[x])
{
case 0: relatq |= (int)rattitude::hero; break;
case 1: relatq |= (int)rattitude::frie; break;
case 2: relatq |= (int)rattitude::grud; break;
//case 3:relatq |= (int)rattitude::hero; break;//god?
case 4: relatq |= (int)rattitude::grud; break;
case 5: relatq |= (int)rattitude::foe; break;
case 6: relatq |= (int)rattitude::frie; break;
case 7: relatq |= (int)rattitude::aqua; break;
case 8: relatq |= (int)rattitude::grud; break;
case 9: relatq |= (int)rattitude::foe; break;
case 10: relatq |= (int)rattitude::comr; break;
case 14: relatq |= (int)rattitude::aqua; break;
case 15: relatq |= (int)rattitude::bull; break;
case 16: relatq |= (int)rattitude::foe; break;
case 17: relatq |= (int)rattitude::loya; break;
case 18: relatq |= (int)rattitude::foe; break;
case 19: relatq |= (int)rattitude::star; break;
case 20: relatq |= (int)rattitude::star; break;
case 21: relatq |= (int)rattitude::star; break;
case 22: relatq |= (int)rattitude::star; break;
case 23: relatq |= (int)rattitude::hero; break;
default: break;
}
}
//mil0:7 (sub:com) gru0:0 (grudge bully) sup0:0 (fan:hero)
if (relatq & 4 && relatq < 128) { stars++; }
if (relatq & 256) { foes++;}
else if (relatq & 128){ bullies++; }
else if (relatq & 64) { grudges++; }
else if (relatq & 32) { heros++; }
else if (relatq & 16) { comrades++; }
else if (relatq & 8) { lsoldiers++;}
else if (relatq & 2) { friends++; }
else if (relatq & 1) { aquaints++; }
}
for (int k = 0; k < figure->histfig_links.size(); k++) {
auto &nk = figure->histfig_links[k];
switch (nk->getType())
{
case df::histfig_hf_link_type::MOTHER:
momfid = nk->target_hf; break ;
case df::histfig_hf_link_type::FATHER:
dadfid = nk->target_hf; break ;
case df::histfig_hf_link_type::SPOUSE: spouse++; break ;
case df::histfig_hf_link_type::CHILD: child++; break ;
case df::histfig_hf_link_type::DEITY:
{
auto deity = df::historical_figure::find(nk->target_hf);
if (gods.size()) gods += ",";
gods += deity->name.first_name;
if (nk->link_strength > 5000) gods += "+"; //tuned okish
if (nk->link_strength > 10000) gods += "+";
if (nk->link_strength > 20000) gods += "+";
}
break;
case df::histfig_hf_link_type::LOVER: lover++; break ;
case df::histfig_hf_link_type::PRISONER: prisoner++; break ;
case df::histfig_hf_link_type::IMPRISONER: inprison++; break ;
case df::histfig_hf_link_type::MASTER: master++; break ;
case df::histfig_hf_link_type::APPRENTICE: apprentice++; break ;
case df::histfig_hf_link_type::COMPANION: companion++; break ;
case df::histfig_hf_link_type::FORMER_MASTER: fmaster++; break ;
case df::histfig_hf_link_type::FORMER_APPRENTICE: fapp++; break ;
case df::histfig_hf_link_type::PET_OWNER: petown = nk->target_hf; break ;
}//switch
}//for it had relations
df::historical_figure *momfigure = df::historical_figure::find(momfid);
if (momfigure) {
for (int k = 0; k < momfigure->histfig_links.size(); k++)
{
auto &nk = momfigure->histfig_links[k];
switch (nk->getType())
{
case df::histfig_hf_link_type::CHILD: kin++; break ;
}
}
} else {
kin = -1; //unit is motherless !
}
}///if had figure id
// count minor children, lover and sibling
momuid = unit->relationship_ids[df::unit_relationship_type::Mother];
daduid = unit->relationship_ids[df::unit_relationship_type::Father];
if (momuid < 1) momuid = -2;
if (daduid < 1) daduid = -2;
for (auto cu = world->units.all.begin(); cu != world->units.all.end(); cu++)
{
if (Units::isKilled(*cu)) continue;
//this unit is mom or dad of world unit
if (uid == (*cu)->relationship_ids[df::unit_relationship_type::Pet]) pets++;
if (uid == (*cu)->relationship_ids[df::unit_relationship_type::Mother]
|| uid == (*cu)->relationship_ids[df::unit_relationship_type::Father])
{
if ((*cu)->profession == df::profession::CHILD
|| (*cu)->profession == df::profession::BABY)
{
kids++;
}
}
}
//for (auto hf = world->history.figures.begin(); hf != world->history.figures.end(); hf++){}
if (kin > 99) kin = 99;
string hard, cave, outdoors;
if (!(uin->unit->status.current_soul)) {
if (&uin->unit->status.misc_traits)
{
for (int r = 0; r < unit->status.misc_traits.size(); r++)
{
auto *tr = unit->status.misc_traits[r];
if (tr->id == misc_trait_type::anon_2) //Hardened
{
if (tr->value > 200000) { hard = " Hrd++"; }
else if (tr->value > 125000) { hard = " Hrd+"; }
else if (tr->value > 75000) { hard = " Hrd"; }
}
else if (tr->id == df::misc_trait_type::CaveAdapt)
{
if (tr->value > 750000) { cave = " Cav++"; }
else if (tr->value > 500000) { cave = " Cav+"; }
else if (tr->value > 250000) { cave = " Cav"; }
}
}
}
}
int outy = 0;
if (uin->unit->status.current_soul)
//outy = uin->unit->status.current_soul->personality.unk_v4019_1;
outy =uin->unit->status.current_soul->personality.likes_outdoors;
if (outy == 1) { outdoors = " Rgh"; }
else if (outy == 2) { outdoors = " Rgh+"; }
//Fam 0:0 Frn 0:0 Foe Fan wif lvr pet cav++ hrd++ kil1 loy1 boo1 mas1 app1 gru1 pri-1
string cstr = "";
int dds = 0; //a rough score of string length to help abbreviation
if (spouse) dds++;
if (companion) dds++;
if (pets) dds++;
if (grudges + bullies + foes) dds += 2;
if (heros + stars) dds += 2;
if (master + apprentice) dds += 2;
if (unit->military.squad_id > -1) dds += 8;
if (hard.size()) dds += 1;
if (cave.size()) dds += 1;
if (outdoors.size()) dds += 1;
if (petown) {
dds += 6;
auto pto = df::historical_figure::find(petown);
if (pto) cstr += "Pet of " + get_name_string(pto->name) + " ";
}
string siblings = to_string(kin);
if (kin < 0) { siblings = "-"; }
if (dds > 5) {
cstr += "Fam" + to_string(kids) + ":" + siblings
+ ",Frd" + to_string(friends) + ":" + to_string(aquaints);
} else {
cstr += "Family" + to_string(kids) + ":" + to_string(kin)
+ ",Friends" + to_string(friends) + ":" + to_string(aquaints); dds += 6;
}
if (spouse) {
if (uin->unit && uin->unit->sex) { cstr += ",wif"; }
else { cstr += ",hus"; }
}
if (companion) cstr += ",cmp";
if (lover) cstr += ",lvr";
if (pets) cstr += ",pet";
cstr += cave;
cstr += outdoors;
cstr += hard;
if (unit->military.squad_id > -1)
{
string sqd = uin->squad_effective_name;
int mxln = 30 - dds; if (mxln < 6) mxln = 6;
if (sqd.length() > mxln) sqd.resize(mxln);
cstr += " " + sqd + ":";
if (unit->military.squad_position == 0) {
cstr += "cpt";
} else {
cstr += to_string(unit->military.squad_position);
}
if ((lsoldiers + comrades) > 0) {
cstr += ":s" + to_string(lsoldiers) + ":c" + to_string(comrades);
}
cstr += " ";
}
//cstr+=kills;
if (grudges + bullies + foes) {
cstr += " Foe" + to_string(bullies)
+ ":" + to_string(foes)
+ ":" + to_string(grudges);
}
if (heros + stars) {
cstr += " Fan" + to_string(heros)
+ ":" + to_string(stars);
}
if (master + apprentice) {
cstr += " Civ" + to_string(master)
+ ":" + to_string(apprentice);
}
cstr += books + " ";
int max_len = dimex - 4;
if (max_len > 86) {
max_len = (85 + max_len) / 2 - 1;
}
uin->tagline = cstr;
uin->godline = gods;
cstr = "";
if (!(&unit->status)) return;
if (!(&unit->status.current_soul)) return;
if (!(&unit->status.current_soul->personality)) return;
if (!(&unit->status.current_soul->personality.dreams)) return;
auto *personality = &uin->unit->status.current_soul->personality;
cstr = "";
if (&personality->dreams) {
int cn = personality->dreams.size() - 1;
int dr = -1;
if (cn > -1) dr = personality->dreams[cn]->type;
if (dr > -1 && dr < 11) {
cstr += dreamnom[dr];
} else {
cstr += "a mystery";
}
} else {
cstr += "a mystery";
}
uin->dream = cstr;
cstr = "";
string dstr = "";
string estr = "";
int pw, e, c, n;
bool firstgo = true;
if (&unit->status.current_soul->preferences)
{
auto prefs = uin->unit->status.current_soul->preferences;
n = prefs.size();
for (c = 0; c < n; c++)
{
if (!(prefs[c]->active)) continue;
int t = prefs[c]->type;
int it = prefs[c]->item_type;
int sit = prefs[c]->item_subtype;
int mit = prefs[c]->mattype;
int mix = prefs[c]->matindex;
if (t == 1 && it == 170) {
dstr = "dogs";
} else if ((t == 4 || t == 8) && it > -1) {
if (t == 8) {
dstr = "gem";
if (it == 33 || it == 18 || it == 22){ dstr += "s"; }
} else { dstr = getItemLabel(it, sit); //subtype is optional
}
} else if (t == 0 && mit == 0 && it == -1 && sit == -1) {
//is a raw mat like metal or rock
MaterialInfo mi(mit, mix);
string ds = mi.toString();
if (ds == "platinum" || ds == "gold" || ds == "silver" || ds == "steel"
|| ds == "billon" || ds == "electrum" || ds == "bronze"
|| ds == "iron" || ds == "copper" || ds == "aluminum" || ds == "pig iron"
|| ds == "brass" || ds == "tin" || ds == "rose gold"
|| ds == "zinc" || ds == "nickel" || ds == "lead"
|| ds == "obsidian" || ds == "adamantine"
|| ds == "limestone" || ds == "bismuth bronze"
|| ds == "dolomite" || ds == "bone"
|| ds == "chalk" || ds == "marble" || ds == "wood"
|| ds == "leather" || ds == "gems")
{
dstr = ds;
} else {
if (estr.size() + ds.size() < 15) estr += ds + ",";
}
}
if (dstr.size()) { cstr += dstr + ","; dstr = "";}
}
if (cstr.size() + estr.size() < 20) cstr += estr;
if (cstr.size() > 1) cstr.resize(cstr.size() - 1);
uin->likesline = cstr + ".";
}///preferences
int regard_len = 75; //20+max_len/2 ;
int traits_len = 110; //- 9-gods.size(); //
if (traits_len > 85) traits_len = 85 + ((traits_len - 85) * 2) / 3;
cstr = "";
//Regarded stuff..
if (&unit->status.current_soul->personality.values) {
std::array<uint8_t, 250> cachptr;
std::array<int, 250> cachval;
auto &values = personality->values;
n = values.size();
for (c = 0; c < n; c++) {
cachptr[c] = c;
cachval[c] = (int)(values[c]->strength);
}
std::sort(cachptr.begin(), cachptr.begin() + n, [&cachval](int a, int b) {
return abs(cachval[a]) > abs(cachval[b]);
});
for (e = 0; e < n; e++) if (abs(cachval[cachptr[e]]) < 16) break;
const char * const psve[] = {"++++ ", "+++ ", "++ ", "+ "};
const char * const ngve[] = {"---- ", "--- ", "-- ", "- "};
for (c = 0; c < n; c++)
{
int x = cachptr[c];
pw = abs(cachval[x]);
if (pw < 14) break;
// ++++ +++ ++ +
pw = pw > 46 ? 0 : pw > 35 ? 1 : pw > 24 ? 2 : 3;
dstr = Regardnom[values[x]->type];
if (cachval[x] > 0) {
dstr += psve[pw];
} else {
dstr += ngve[pw];
}
if (cstr.size() + dstr.size() < regard_len) {
cstr += dstr;
} else {
if (c < e) cstr += ".. ";
}
if (cstr.size() + 6 > regard_len) {
break;
}
}
uin->regards = cstr;
}///rwgards
cstr = "";
dstr = "";
if (&unit->status.current_soul->personality.traits) {
//Traits..
std::array<uint8_t, 50> cachptr;
std::array<int, 50> cachval;
for (c = 0; c < 50; c++) {
cachval[c] = (int)personality->traits[c];
cachptr[c] = c;
}
std::sort(cachptr.begin(), cachptr.end(), [&cachval](int a, int b) {
return abs(cachval[a] - 50) > abs(cachval[b] - 50);
});
//find end of must note
for (e = 0; e < 50; e++) if (abs(cachval[cachptr[e]] - 50) < 6) break;
bool punc = false;
bool tinu = true;
int adv = -1;
int firstgo = true;
c = 0; cstr = ""; dstr = "";
int abit = 0;
int wrds = 0;
while (tinu) {
dstr = "";
int tx = cachptr[c++];
pw = abs(cachval[tx] - 50);
int lowest = 12;
if (pw <= lowest) break; //crash without this
//incredibly extremely really rather : a bit
pw = pw > 45 ? 0 : pw > 36 ? 1 : pw > 24 ? 2 : pw > 18 ? 3 : 4;
//pw=pw>lowest?4:pw; //a bit
//game cat is
//most 41 - 50
//much 24 - 40
//often 10 - 24
if (pw == 4) {
if (abit++ == 0) adv = 3;
if (abit > 1 && (wrds > 4 || abs(cachval[tx] - 50) < 8)) break;
}
if (pw > adv) {
if (punc) dstr = ". ";
adv = pw;
dstr += adverb[adv];
//if(firstgo&&pw==2) dstr+="Quite ";
punc = false;
firstgo = false;
}
if (punc) dstr += ",";
punc = true;
dstr += traitnom[ tx * 2 + ((cachval[tx] > 50) ? 0 : 1) ];
if (pw == 4 && wrds > 3 && dstr.size() > 13) { //cancel a bit "bigword"
abit--; //get small final word.
dstr = "";
}
if (cstr.size() + dstr.size() < traits_len) {
cstr += dstr; wrds++;
}
if ((pw > 2 && cstr.size() > (traits_len * 2 + 76) / 3) || cstr.size() > traits_len) { //wont fit another in
//if(c<e) cstr+="..";
tinu = false;
}
if (c >= e)tinu = false;
}
uin->traits = cstr + ". ";
}/// Extremely gregarious...
}
void setDistraction(UnitInfo * uin) {
if (!(uin->unit->status.current_soul)) {
uin->focus = 8;
return;
}
int fo = uin->unit->status.current_soul->personality.current_focus - uin->unit->status.current_soul->personality.undistracted_focus;
int pol = fo < 0 ? -1 : 1;
fo = static_cast<int>(std::sqrt((double)(fo * pol * 25)) / 4 + 0.5);
fo = fo > 9 ? 9 : fo;
uin->focus = fo * pol;
}
}//namespace unit_info_ops
static bool theme_reload = true;
bool loadPallete()
{
theme_reload = false;
/*cerr << "Attempt to load kloker pallete" << file << endl; */
std::ifstream infile(Filesystem::getcwd() + "/" + CONFIG_DIR + "/kloker_pallete.txt");
if (infile.bad()) {
return false;
}
show_sprites = false;
string line;
int clr = 0;
int k = 0;
while (std::getline(infile, line)) {
if (strcmp(line.substr(0, 7).c_str(), "RELOADS") == 0)
theme_reload = true;
if (strcmp(line.substr(0, 7).c_str(), "SHOWSPR") == 0)
show_sprites = true;
if (strcmp(line.substr(0, 1).c_str(), "/") == 0)
continue;
size_t pos = line.find(',');
while (pos != string::npos) {
clr = std::stoi(line.substr(pos + 1, 2).c_str());
pos = line.find(',', pos + 1);
if (k < 35)
cltheme[k++] = clr;//&15;
}
}
return true;
}
/*
// File for custom kloker highlights
// save in [df_root]/kloker/kloker_pallete.txt
// numbers for colors:
// BLACK = 0 BLUE = 1 GREEN = 2 CYAN = 3
// RED = 4 MAGENTA = 5 BROWN = 6 GREY = 7
// DKGREY = 8 LTBLUE = 9 LTGREEN =10 LTCYAN =11
// LTRED =12 LTMAGENTA =13 YELLOW =14 WHITE =15
// following colors prefixed with commas are read in order
// noskill low med hai
BG for not set: ,0 ,0 ,0 ,0
FG for not set: ,8 ,14 ,7 ,11
cursor BG not set ,15 ,15 ,15 ,15
cursor FG not set ,0 ,0 ,0 ,0
BG set ,8 ,14 ,7 ,11
FG set ,7 ,15 ,15 ,15
cursor BG set ,15 ,15 ,15 ,15
cursor FG set ,15 ,15 ,15 ,15
BG military ,13
FG other ,13
BG posflash ,1
//RELOADS - uncomment this line to
//have theme reload on every relist
//SHOWSPRITES - uncomment to clutter X axis with sprites
*/
namespace unit_ops {
string get_real_name(UnitInfo *u)
{ return Translation::TranslateName(&u->unit->name, false); }
string get_nickname(UnitInfo *u)
{ return Translation::TranslateName(Units::getVisibleName(u->unit), false); }
string get_real_name_eng(UnitInfo *u)
{ return Translation::TranslateName(&u->unit->name, true); }
string get_nickname_eng(UnitInfo *u)
{ return Translation::TranslateName(Units::getVisibleName(u->unit), true); }
string get_first_nickname(UnitInfo *u)
{
return Translation::capitalize(u->unit->name.nickname.size() ?
u->unit->name.nickname : u->unit->name.first_name);
}
string get_first_name(UnitInfo *u)
{ return Translation::capitalize(u->unit->name.first_name); }
string get_last_name(UnitInfo *u)
{
df::language_name name = u->unit->name;
string ret = "";
for (int i = 0; i < 2; i++)
{
if (name.words[i] >= 0)
ret += *world->raws.language.translations[name.language]->words[name.words[i]];
}
return Translation::capitalize(ret);
}
string get_last_name_eng(UnitInfo *u)
{
df::language_name name = u->unit->name;
string ret = "";
for (int i = 0; i < 2; i++)
{
if (name.words[i] >= 0)
ret += world->raws.language.words[name.words[i]]->forms[name.parts_of_speech[i].value];
}
return Translation::capitalize(ret);
}
string get_profname(UnitInfo *u)
{ return Units::getProfessionName(u->unit); }
string get_real_profname(UnitInfo *u)
{
string tmp = u->unit->custom_profession;
u->unit->custom_profession = "";
string ret = get_profname(u);
u->unit->custom_profession = tmp;
return ret;
}
string get_base_profname(UnitInfo *u)
{
return ENUM_ATTR_STR(profession, caption, u->unit->profession);
}
string get_short_profname(UnitInfo *u)
{
for (size_t i = 0; i < NUM_COLUMNS; i++)
{
if (columns[i].profession == u->unit->profession)
return string(columns[i].label);
}
return "??";
}
#define id_getter(id) \
string get_##id(UnitInfo *u) \
{ return itos(u->ids.id); }
id_getter(list_id);
id_getter(list_id_prof);
id_getter(list_id_group);
#undef id_getter
string get_unit_id(UnitInfo *u)
{ return itos(u->unit->id); }
string get_unit_ax(UnitInfo *u)
{ return itos(u->active_index); }
string get_unit_xx(UnitInfo *u)
{ return to_string(u->medic) + ","
+ to_string(u->civil) + ","
+ to_string(u->scholar) + ","
+ to_string(u->performer) + ","
+ to_string(u->martial) + ",";
}
string get_age(UnitInfo *u)
{ return itos((int)Units::getAge(u->unit)); }
string get_arrival(UnitInfo *u)
{ return itos(u->arrival_group); }
void set_nickname(UnitInfo *u, std::string nick)
{
Units::setNickname(u->unit, nick);
u->name = get_nickname(u);
u->transname = get_nickname_eng(u);
}
void set_profname(UnitInfo *u, std::string prof)
{
u->unit->custom_profession = prof;
u->profession = get_profname(u);
}
}
struct ProfessionTemplate
{
std::string name;
bool mask;
std::vector<df::unit_labor> labors;
bool load(string directory, string file)
{
cerr << "Attempt to load " << file << endl;
std::ifstream infile(directory + "/" + file);
if (infile.bad()) {
return false;
}
std::string line;
name = file; // If no name is given we default to the filename
mask = false;
while (std::getline(infile, line)) {
if (strcmp(line.substr(0,5).c_str(),"NAME ")==0)
{
auto nextInd = line.find(' ');
name = line.substr(nextInd + 1);
continue;
}
if (line == "MASK")
{
mask = true;
continue;
}
for (size_t i = 0; i < NUM_COLUMNS; i++)
{
if (line == ENUM_KEY_STR(unit_labor, columns[i].labor))
{
labors.push_back(columns[i].labor);
}
}
}
return true;
}
bool save(string directory, bool ismask = false)
{
std::ofstream outfile(directory + "/" + name);
if (outfile.bad())
return false;
outfile << "NAME " << name << std::endl;
if (ismask)
outfile << "MASK" << std::endl;
for (size_t i = 0; i < NUM_COLUMNS; i++)
{
if (hasLabor(columns[i].labor))
{
outfile << ENUM_KEY_STR(unit_labor, columns[i].labor) << std::endl;
}
}
outfile.flush();
outfile.close();
return true;
}
void apply(UnitInfo* u)
{
if (!mask && name.size() > 0)
unit_ops::set_profname(u, name);
for (size_t i = 0; i < NUM_COLUMNS; i++)
{
df::unit_labor labor = columns[i].labor;
bool status = hasLabor(labor);
if (!mask || status) {
u->unit->status.labors[labor] = status;
}
}
}
void fromUnit(UnitInfo* u)
{
for (size_t i = 0; i < NUM_COLUMNS; i++)
{
if (u->unit->status.labors[columns[i].labor])
labors.push_back(columns[i].labor);
}
}
bool hasLabor (df::unit_labor labor)
{
return std::find(labors.begin(), labors.end(), labor) != labors.end();
}
};
static std::string professions_folder = Filesystem::getcwd() + "/professions";
class ProfessionTemplateManager
{
public:
std::vector<ProfessionTemplate> templates;
void reload() {
unload();
load();
}
void unload() {
templates.clear();
}
void load()
{
vector <string> files;
cerr << "Attempting to load professions: " << professions_folder.c_str() << endl;
if (!Filesystem::isdir(professions_folder) && !Filesystem::mkdir(professions_folder))
{
cerr << professions_folder << ": Does not exist and cannot be created" << endl;
return;
}
Filesystem::listdir(professions_folder, files);
std::sort(files.begin(), files.end());
for(size_t i = 0; i < files.size(); i++)
{
if (files[i] == "." || files[i] == "..")
continue;
ProfessionTemplate t;
if (t.load(professions_folder, files[i]))
{
templates.push_back(t);
}
}
}
void save_from_unit(UnitInfo *unit, bool ismask = false)
{
ProfessionTemplate t = {
unit_ops::get_profname(unit)
};
t.fromUnit(unit);
t.save(professions_folder,ismask);
reload();
}
bool delete_if_exist(UnitInfo *unit)
{
string filep = professions_folder + "/" + unit_ops::get_profname(unit);
if (Filesystem::isfile ( filep )) {
std::remove( filep.c_str() );
return true;
}
return false;
}
};
static ProfessionTemplateManager profmanager;
class viewscreen_helppagest : public dfhack_viewscreen {
public:
viewscreen_helppagest() { }
std::string getFocusString() { return "unitkloker/helpscreen"; }
void feed(set<df::interface_key> *events)
{
if (events->count(interface_key::LEAVESCREEN))
{
Screen::dismiss(this);
return;
}
}
void render()
{
dfhack_viewscreen::render();
Screen::clear();
int x = 2, y = 2;
x = 2; y = 2;
const int Qa[] = {1, 4, 1, 4, 3, 2, 4, 1, 1, 4, 2, 0, 1, 1, 0, 1, 0, 3, 4};
const int Qc[] = {COLOR_LIGHTRED, COLOR_YELLOW, COLOR_GREEN, COLOR_LIGHTBLUE, COLOR_WHITE};
string Wa = "SaterdAfwcipmlsmkes";
string Wb = "tgoneinoirnaeipuimo";
string Wc = "riuecsaclettmnasnpc";
string Wd = "elgroelulauiogtieai";
string We = "nihguaysptieruicsta";
string Wf = "gtnypss oitnyiaathl";
string Wg = "tye eei wvic sllhyA";
string Wh = " s rRs eioe tS e w";
string Wi = " s ae rtn ie t a";
string Wj = " ts y cn i r";
string Wk = " ii s c e";
string Wl = " os e ";
string Wm = " mt ";
string Wn = " ";
int len = 19;
OutputString(COLOR_WHITE, x, y, Screen::getKeyDisplay(interface_key::ZOOM_IN));
OutputString(COLOR_WHITE, x, y, Screen::getKeyDisplay(interface_key::ZOOM_OUT));
OutputString(COLOR_LIGHTGREEN, x, y, ":zoom text");
OutputString(COLOR_LIGHTMAGENTA, x, y, " Cave Kloker Help ");
OutputString(COLOR_WHITE, x, y, Screen::getKeyDisplay(interface_key::LEAVESCREEN));
OutputString(COLOR_LIGHTGREEN, x, y, ":return"); x = 2; y += 2;
OutputString(COLOR_YELLOW, x, y, "Attributes Legend ");
OutputString(COLOR_GREY, x, y, " Most Labors employ and improve certain Attributes."); x = 2; y++;
OutputString(COLOR_YELLOW, x, y, " ");
OutputString(COLOR_GREY, x, y, " Attribute mode prints them in a grid."); x = 2; y++;
for (int c = 0; c < len; c++) { OutputString(Qc[Qa[c]], x, y, Wa.substr(c, 1)); };
OutputString(COLOR_RED, x, y, " <-");
OutputString(COLOR_GREY, x, y, "First two letters make the grids header."); x = 2; y++;
for (int c = 0; c < len; c++) { OutputString(Qc[Qa[c]], x, y, Wb.substr(c, 1)); }; x += 2;
OutputString(COLOR_LIGHTRED, x, y, " Units weak attributes are highlighted Red."); x = 2; y++;
for (int c = 0; c < len; c++) { OutputString(Qc[Qa[c]], x, y, Wc.substr(c, 1)); }; x += 2;
OutputString(COLOR_LIGHTBLUE, x, y, " Units strong attributes are highlighted Blue."); x = 2; y++;
for (int c = 0; c < len; c++) { OutputString(Qc[Qa[c]], x, y, Wd.substr(c, 1)); }; x += 2;
OutputString(COLOR_WHITE, x, y, " White attribs are exercised by the labor."); x = 2; y++;
for (int c = 0; c < len; c++) { OutputString(Qc[Qa[c]], x, y, We.substr(c, 1)); }; x += 2;
OutputString(COLOR_LIGHTGREEN, x, y, " Green attribs may contribute to the labor.");