Hey all. I'm working on a python script that goes through the Steam version of Dwarf Fortress and checks each Dwarf in your fort and looks at their innate abilities and makes suggestions of jobs that they should be doing.
I started out using pytesseract and pyautogui to try to click buttons to cycle through the Dwarves' dossiers and grab screengrabs of their names, their current title, and their innate ability (on the overview page) to mixed results. I usually don't have problems putting their innate abilities into a list but the Dwarf names are sometimes jacked up from special characters.
Someone had made a suggestion to use Cheat Engine to find memory addresses for the Dwarves but when I tried to look up a Dwarf name (with no special characters) it gave me an address that appeared to be dynamically changing or something. It appeared to be the right character length but it didn't really give me a value.
Here is when I am in the Creatures/Citizens panel. I can search for 'Lolor Gusiltherleth', who is my fifth listed dwarf.
I then click on the magnifying glass associated with 'Lolor Gusiltheleth' to pull up her Dossier page (Overview). I then try using Cheat Engine to search for 'lolor gusiltherleth' and I get this result which seems to be scrolling through different details about them.
I'd like to be able to find the memory address that is storing the name of the character when I click through the dossier pages to snatch their innate abilities but i'm open to different suggestions on how to accomplish this.
I've gone though Cheat Engine and it just seems like the memory address for their name keeps changing. This is so frustrating!
Here is an example of how my original pytesseract script was getting results
CSRSCREASESSASSSee
['Disdains sacrifice', 'Not wasteful', 'Developed empathy', 'Flights of fancy', 'Not vengeful', 'Cruel']
eSteeoo
['Patient', 'Low willpover', 'Poor memory', 'Bad with words', 'Perfectionist', 'Gracious']
UVutokZonsarekBSSsyoresa
['Values knowledge', 'Disdains self', 'control', 'Good spatial sense', 'Good focus', 'Thrill', 'seeker', 'Overhearing']
MebzuthGemeshast Miner
['Good with language', 'Patient', 'Disdains harmony', 'Poor intuition', 'Low willpover', 'Not lustful']
LolorGusiltherleth
Miner
['Disdains perseverance', 'High kinesthetic sense', 'Poor social avareness', 'Low stamina', 'Recovers slouly', 'Obst inate']
AthelDuthalavuz Miner
['Disdains tranquility', 'Good memory', 'Not creative', 'Low stamina', 'High kinesthetic sense', 'Low willpower']
EdmOttansarvesh Miner
['Values independence', 'Zany', 'High social awareness', 'Emotional obsessive', 'Disdains artwork', 'Overshares']
Hit or miss as you can see.
Anyway, suggestions welcome
Edit: pytesseract code snippet:
pyautogui.mouseDown(citizen_info)
time.sleep(0.05)
pyautogui.mouseUp()
pyautogui.mouseDown(magni_glass_list[dwarf_number])
time.sleep(0.05)
ImageGrab.grab(dwarf_name_title).save('dwarf_name_title.png')
image = Image.open('dwarf_name_title.png')
dwarf_name_title_string = pytesseract.image_to_string('dwarf_name_title.png',lang='eng')
#name function. I am converting the string to a list so that I can iterate through the characters and remove bad characters from the pytesseract interpretation which sometimes happens.
name_spell = []
job_spell = []
name_status = False
for letter in dwarf_name_title_string:
if letter != "," and name_status == False:
name_spell.append(letter)
elif letter == "," and name_status == False:
name_status = True
elif letter != "," and name_status == True:
job_spell.append(letter)
else:
print("There was an Error")
print(letter)
#clean up weird characters
for letter in name_spell:
if letter not in alphabet:
name_spell.remove(letter)
for letter in job_spell:
if letter not in alphabet:
job_spell.remove(letter)
#convert list to string
name = ''.join(name_spell)
job = ''.join(job_spell)
#Grabbing the Dwarve's innate attributes
time.sleep(0.05)
ImageGrab.grab(attributes).save('attributes.png')
image = Image.open('attributes.png')
attributes_string = pytesseract.image_to_string('attributes.png',lang='eng')
attributes_list = []
attributes_spell = []
for letter in attributes_string:
if letter in alphabet or letter == " ":
attributes_spell.append(letter)
else:
if len(attributes_spell) > 1:
attributes_list.append(''.join(attributes_spell))
attributes_spell.clear()
Edit: Just ran it and the script as it is right now takes about 24 minutes to run for 149 Dwarves (since it is using Pytesseract image interpretation and pyautogui is clicking through the menus). A lot of the time is lost from scrolling to the next Dwarf so, yeah, if we can figure out a way to get the Dwarves data from memory with consistent results, as well as where their innate abilities are located, that would speed up this process significantly but would probably take significant effort. Another way I think this can be sped up is if you exile the dwarves as you get their information and then quit without saving but then we would need to code in logic about what to do if there are nobels that can't be exiled. But even still, doing it with pytesseract is going to require a lot of different x and y coordinates due to different screen sizes, monitor amounts, etc so being able to access data directly is the best way. I dunno I'm a novice lol.