I'd like to add that I've encountered this same kind of problem, coming from a different source.
I repurposed an old script in order to civilize wild animal people and the same happens: for all the game purposes they are citizens, but Dwarf Therapist, specifically, won't recognize them as such. The script also forges historical links and changes their civ alignment even in the most obscure of places (such as in current_soul.personality). All the other functions work normally: you can alter their labors in the native interface, retiring the fort and talking to them in advmode works as expected, they can be militia commander (and other nobles) and command squads, etc.
So every single aspect of the game itself is fine in relation to them. The problem arises from DT not recognizing them properly.
It might be that DT is correct in that they are not full citizens: in that case my script failed to change something important and I didn't notice, and some bug happened involving your adventurers that marked them as not citizens despite having all the right links (known to us, at least).
The most likely scenario, IMO, is that it's a flaw from DT itself. Which sucks, because the Therapist is a must for me to play the game: I simply can't stand using the current UI and labormanager gives the player almost no control at all over the dorfs. So no civilizing the furry savages for now.
Script for anyone interested. It's kind of lacking, though.
-- For converting passing animal people to your civilization
-- Ideally, you'd find a way to name the unit first.
-- just loo'k' at the unit and type the name of the script in the console
local utils = require 'gui'
function addcitizen()
local unit
local hf
unit=dfhack.gui.getSelectedUnit()
if unit==nil then
qerror("No unit selected")
return
end
if unit.hist_figure_id ~= -1 then
qerror(dfhack.TranslateName(dfhack.units.getVisibleName(unit)).." isn't interested.")
return
end
-- create histfig
hf=df.historical_figure:new()
hf.id=df.global.hist_figure_next_id
df.global.hist_figure_next_id=df.global.hist_figure_next_id+1
hf.race=unit.race
hf.caste=unit.caste
hf.profession = unit.profession
hf.sex = unit.sex
hf.orientation_flags:assign(unit.status.current_soul.orientation_flags)
hf.appeared_year = df.global.cur_year
hf.born_year = unit.birth_year
hf.born_seconds = unit.birth_time
hf.curse_year = unit.curse_year
hf.curse_seconds = unit.curse_time
hf.birth_year_bias = unit.birth_year_bias
hf.birth_time_bias = unit.birth_time_bias
hf.old_year = unit.old_year
hf.old_seconds = unit.old_time
hf.died_year = -1
hf.died_seconds = -1
hf.name:assign(unit.name) -- Probably no name, though
hf.civ_id = df.global.ui.civ_id
hf.population_id = hf.civ_id
hf.breed_id = -1
hf.cultural_identity = -1
hf.family_head_id = hf.id
hf.flags[16]=true
hf.unit_id = unit.id
hf.nemesis_id = unit.id
-- These will need to be adjusted as DFhack gets updated
hf.unk4 = 0
hf.unk_v47_3 = 0
hf.unk_v47_4 = 0
hf.unk_v4019_1 = -1
hf.anon_1 = -1
-- make the links to your civilization
hf.entity_links:insert("#",{new=df.histfig_entity_link_memberst,entity_id=df.global.ui.civ_id,link_strength=100})
hf.entity_links:insert("#",{new=df.histfig_entity_link_memberst,entity_id=df.global.ui.group_id,link_strength=100})
-- explicitly state in the hf info that it settled in your site
hf.info = df.historical_figure_info:new()
hf.info.whereabouts = df.historical_figure_info.T_whereabouts:new()
hf.info.whereabouts.whereabouts_type = 1 -- (1) settler
hf.info.whereabouts.site = df.global.ui.site_id
hf.info.whereabouts.region_id = -1
hf.info.whereabouts.underground_region_id = -1
hf.info.whereabouts.army_id = -1
hf.info.whereabouts.death_condition = 0
hf.info.whereabouts.death_condition_parameter_1 = -1
hf.info.whereabouts.death_condition_parameter_1 = -1
hf.info.whereabouts.year = df.global.cur_year
hf.info.whereabouts.year_tick = df.global.cur_year_tick
-- let's forge some historical events, just for completion sake
local hf_event_id = df.global.hist_event_next_id
df.global.hist_event_next_id=df.global.hist_event_next_id+1
-- Became a member of your civilization
df.global.world.history.events:insert("#",{new=df.history_event_add_hf_entity_linkst,
year=df.global.cur_year,
seconds=df.global.cur_year_tick,
id=hf_event_id,
civ=df.global.ui.civ_id,
histfig=hf.id,
link_type=0})
hf_event_id = df.global.hist_event_next_id
df.global.hist_event_next_id=df.global.hist_event_next_id+1
-- Settled in your site
df.global.world.history.events:insert("#",{new=df.history_event_change_hf_statest,
year=df.global.cur_year,
seconds=df.global.cur_year_tick, -- Are these 'seconds' the same as yearticks? Comparing natural values form random events were inconclusive.
id=hf_event_id,
hfid=hf.id,
state = 1,
reason = -1,
site = df.global.ui.site_id,
region = -1,
layer = -1})
-- TODO: generate a (random?) name for the unit. Also apply it on the soul and the histfig
-- TODO: check for the existence of RAW tags that allow the unit to join civilizations. As it is, you can use this script to civilize regular animals, with some weirdness involved.
-- insert the histfig
df.global.world.history.figures:insert("#",hf)
-- unit: set the appropriate flags (some are left over from the original script)
unit.flags1.important_historical_figure = true
unit.flags2.important_historical_figure = true
unit.hist_figure_id = hf.id
unit.hist_figure_id2 = hf.id
unit.civ_id = df.global.ui.civ_id
unit.population_id = df.global.ui.civ_id
unit.status.current_soul.personality.civ_id = df.global.ui.civ_id
unit.status.current_soul.name:assign(unit.name) -- For completeness sake only. Name of the soul doesn't seem to matter.
unit.flags1.merchant=false
unit.flags1.forest=false
unit.flags1.diplomat=false
unit.flags2.visitor=false
unit.flags2.roaming_wilderness_population_source = false
unit.flags2.roaming_wilderness_population_source_not_a_map_feature = false
unit.flags3.unk31=false
unit.following = nil
unit.follow_distance = -1
local color=_G["COLOR_YELLOW"]
dfhack.gui.showAnnouncement(dfhack.TranslateName(dfhack.units.getVisibleName(unit)).."has joined our fortress!", color)
end
addcitizen()