Skip to content

New Feature: autotraining #1411

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 68 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
9da6925
New Feature: `gym`
realSquidCoder Mar 1, 2025
81127f2
Fix whitespace
realSquidCoder Mar 1, 2025
5c08fb6
missed some
realSquidCoder Mar 1, 2025
edb3e83
MORE whitespace (and some other cleanup)
realSquidCoder Mar 1, 2025
0c4f5b5
Update gym.lua
realSquidCoder Mar 1, 2025
50d6a96
Create gym.rst
realSquidCoder Mar 2, 2025
deca155
Fix EOF
realSquidCoder Mar 2, 2025
74784f8
Update gym.rst
realSquidCoder Mar 2, 2025
f4cf0a0
fix key error
realSquidCoder Mar 2, 2025
39f2c9c
more key errors
realSquidCoder Mar 2, 2025
a5d6c0a
Update the documentation
realSquidCoder Mar 3, 2025
105b0cc
Merge remote-tracking branch 'upstream/master' into sci-gym-script
realSquidCoder Mar 5, 2025
6c53215
Use the enable/disable stuff not args to start or stop
realSquidCoder Mar 6, 2025
f701f9f
Merge branch 'master' into sci-gym-script
realSquidCoder Mar 6, 2025
f149d5c
Merge remote-tracking branch 'upstream/master' into sci-gym-script
realSquidCoder Mar 8, 2025
4492f3e
Merge remote-tracking branch 'upstream/master' into sci-gym-script
realSquidCoder Mar 12, 2025
a6761bd
Do the documentation in one place
realSquidCoder Mar 12, 2025
0acd601
Various fixes
realSquidCoder Mar 12, 2025
9463d79
More cleanup
realSquidCoder Mar 12, 2025
7dba7e4
rename the script itself
realSquidCoder Mar 12, 2025
86967d7
fix docs
realSquidCoder Mar 12, 2025
eaa1d86
Add credit where credit is due
realSquidCoder Mar 12, 2025
1892f62
add to control panel
realSquidCoder Mar 12, 2025
e69aba5
Check the squad's entity_id to make sure we get *our* Gym
realSquidCoder Mar 13, 2025
0d0ef1e
Update autotraining.lua
realSquidCoder Mar 13, 2025
c7c73ad
Fix the ignore count never being reset
realSquidCoder Mar 14, 2025
bceb905
Fix units that need training but are already doing so being reported …
realSquidCoder Mar 14, 2025
8803e82
fix the ignore count (it should be global)
realSquidCoder Mar 14, 2025
82d3acd
Apply suggestions from code review
realSquidCoder Mar 15, 2025
00e883f
fix typo
realSquidCoder Mar 16, 2025
6634120
fix to actually check the unit's squad
realSquidCoder Mar 16, 2025
ed76a08
Update for gui usage
realSquidCoder Mar 16, 2025
92076ba
clean up
realSquidCoder Mar 16, 2025
fc832a3
initial gui and update from code review
realSquidCoder Mar 16, 2025
55ddbfe
show alias in gui too
realSquidCoder Mar 16, 2025
f1edec2
clean up
realSquidCoder Mar 16, 2025
3906eb0
Create gui docs
realSquidCoder Mar 19, 2025
59d53f5
update the docs
realSquidCoder Mar 19, 2025
612936b
remove non-existant name args in docs
realSquidCoder Mar 19, 2025
f59f6de
fix typo in message
realSquidCoder Mar 19, 2025
1c427c6
fix trainees being labeled as queued
realSquidCoder Mar 19, 2025
648ae90
add ignore nobles
realSquidCoder Mar 21, 2025
3612593
Remove more debug code
realSquidCoder Mar 21, 2025
a9bf6e6
Gui cleanup
realSquidCoder Mar 21, 2025
218a41f
Merge remote-tracking branch 'upstream/master' into sci-gym-script
realSquidCoder Mar 23, 2025
3b151be
Merge remote-tracking branch 'upstream/master' into sci-gym-script
realSquidCoder Mar 23, 2025
f44a37a
Update to use the Military Module
realSquidCoder Apr 4, 2025
7c186d3
use the squad position
realSquidCoder Apr 4, 2025
f670df7
Remove all training dwarves when you disable
realSquidCoder Apr 6, 2025
996a5f8
Merge branch 'master' into sci-gym-script
realSquidCoder Apr 6, 2025
595a760
disable autotraining on map unload
realSquidCoder Apr 10, 2025
067d182
Merge remote-tracking branch 'upstream/master' into sci-gym-script
realSquidCoder Apr 26, 2025
cf1431e
Apply suggestions from code review
realSquidCoder May 10, 2025
7d0ded1
fix erroneous training numbers
realSquidCoder May 10, 2025
191a5c3
Update autotraining.rst
realSquidCoder May 10, 2025
807f350
remove outdated debug logging
realSquidCoder May 10, 2025
7b77466
remove outdated comment
realSquidCoder May 10, 2025
98e12c7
fix up silly code in `removeTraining`
realSquidCoder Jul 3, 2025
097755e
Update autotraining.lua
realSquidCoder Jul 3, 2025
e274598
Update autotraining.lua
realSquidCoder Jul 3, 2025
2250848
clean and de-nest training candidates
realSquidCoder Jul 3, 2025
c325bd3
remove units who don't need training
realSquidCoder Jul 3, 2025
bc3d60f
use our precomputed good squads list
realSquidCoder Jul 3, 2025
9800e73
Merge branch 'master' into sci-gym-script
realSquidCoder Jul 3, 2025
3f639ec
forgot a nil check
realSquidCoder Jul 3, 2025
04e34be
only count as ignored if they are ignored
realSquidCoder Jul 3, 2025
5c18bba
Apply suggestions from code review
realSquidCoder Jul 4, 2025
8cee911
code review changes
realSquidCoder Jul 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions docs/gym.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
gym
===

.. dfhack-tool::
:summary: Assigns Dwarves to a military squad until they have fulfilled their need for Martial Training
:tags: fort auto bugfix units

Also passively builds military skills and physical stats.

Critical setup:

- Minimum 1 squad with the name "Gym"
- An assigned squadleader in "Gym"
- An assigned Barracks for the squad "Gym"
- Active Training orders for the squad "Gym"

This should be a new non-military-use squad. The uniform should be set to "No Uniform" and the squad should be set to "Constant Training" in the military screen.
Set the squad's schedule to full time training with at least 8 or 9 training.
The squad doesn't need months off. The members leave the squad once they have gotten their gains.

NOTE: Dwarfs with the labor "Fish Dissection" enabled are ignored. Make a Dwarven labour with only the Fish Dissection enabled, set to "Only selected do this" and assign it to a dwarf to ignore them.

Usage
-----

``gym [<options>]``

Examples
--------

``gym``
Current status of script

``gym -start``
Checks to see if you have fullfilled the creation of a training gym.
Searches your fort for dwarves with a need to go to the gym, and begins assigning them to said gym.
Once they have fulfilled their need they will be removed from the gym squad to be replaced by the next dwarf in the list.

``gym -stop``
Dwarves currently in the Gym squad, with the exception of the squad leader, will be unassigned and no new dwarves will be added to the squad.

Options
-------
``-start``
Starts the script
If there is no squad named ``Gym`` with a squadleader assigned it will not proceed.

``-stop``
Stops the script

``-t``
Use integer values. (Default 3000)
The negative need threshhold to trigger for each citizen
The greater the number the longer before a dwarf is added to the waiting list.
262 changes: 262 additions & 0 deletions gym.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
-- Code for dwarves to hit the gym when they yearn for the gains.
--[====[
Gym
===

Tags: Fort| Needs | BugFix | Units

Assigns Dwarves to a military squad until they have fulfilled their need for Martial Training. Also passively builds military skills and physical stats.

CRITICAL SETUP:

- Minimum 1 squad with the name "Gym"
- An assigned squadleader in "Gym"
- An assigned Barracks for the squad "Gym"
- Active Training orders for the squad "Gym"

This should be a new non-military-use squad. The uniform should be set to "No Uniform" and the squad should be set to "Constant Training" in the military screen.
Set the squad's schedule to full time training with at least 8 or 9 training.
The squad doesn't need months off. The members leave the squad once they have gotten their gains.

NOTE: Dwarfs with the labor "Fish Dissection" enabled are ignored. Make a Dwarven labour with only the Fish Dissection enabled, set to "Only selected do this" and assign it to a dwarf to ignore them.

Usage
-----

gym [<options>]

Examples
--------

gym
Current status of script

enable gym
Checks to see if you have fullfilled the creation of a training gym.
Searches your fort for dwarves with a need to go to the gym, and begins assigning them to said gym.
Once they have fulfilled their need they will be removed from the gym squad to be replaced by the next dwarf in the list.

disable gym
Dwarves currently in the Gym squad, with the exception of the squad leader, will be unassigned and no new dwarves will be added to the squad.

Options
-------

-t
Use integer values. (Default 3000)
The negative need threshhold to trigger for each citizen
The greater the number the longer before a dwarf is added to the waiting list.
]====]
--@ enable = true
--@ module = true

enabled = enabled or false
function isEnabled()
return enabled
end

local repeatUtil = require 'repeat-util'
local utils=require('utils')

validArgs = utils.invert({
't'
})

local args = utils.processArgs({...}, validArgs)
local scriptname = "Gym"
local ignore_flag = 43 -- Fish Dissection labor id
local ignore_count = 0
local need_id = 14
local squadname ="Gym"


--######
--Functions
--######
function getAllCititzen()
local citizen = {}
local my_civ = df.global.world.world_data.active_site[0].entity_links[0].entity_id
for n, unit in ipairs(df.global.world.units.all) do
if unit.civ_id == my_civ and dfhack.units.isCitizen(unit) then
if unit.profession ~= df.profession.BABY and unit.profession ~= df.profession.CHILD then
if ( not unit.status.labors[ignore_flag] ) then
table.insert(citizen, unit)
else
ignore_count = ignore_count +1
end
end
end
end
return citizen
end

local citizen = getAllCititzen()

function findNeed(unit,need_id)
local needs = unit.status.current_soul.personality.needs
local need_index = -1
for k = #needs-1,0,-1 do
if needs[k].id == need_id then
need_index = k
break
end
end if (need_index ~= -1 ) then
return needs[need_index]
end
return nil
end

--######
--Main
--######

function getByID(id)
for n, unit in ipairs(citizen) do
if (unit.hist_figure_id == id) then
return unit
end
end

return nil
end

-- Find all training squads
-- Abort if no squads found
function checkSquads()
local squads = {}
local count = 0
for n, mil in ipairs(df.global.world.squads.all) do
if (mil.alias == squadname) then
local leader = mil.positions[0].occupant
if ( leader ~= -1) then
table.insert(squads,mil)
count = count +1
end
end
end

if (count == 0) then
dfhack.print(scriptname.." | ")
dfhack.printerr('ERROR: You need a squad with the name ' .. squadname)
dfhack.print(scriptname.." | ")
dfhack.printerr('That has an active Squad Leader')
dfhack.color(-1)
return nil
end

return squads
end

function addTraining(squads,unit)
for n, squad in ipairs(squads) do
for i=1,9,1 do
if (unit.hist_figure_id == squad.positions[i].occupant) then
return true
end

if (unit.military.squad_id ~= -1) then
return false
end

if ( squad.positions[i].occupant == -1 ) then
squad.positions[i].occupant = unit.hist_figure_id
return true
end
end
end

return false
end

function removeTraining(squads,unit)
for n, squad in ipairs(squads) do
for i=1,9,1 do
if ( unit.hist_figure_id == squad.positions[i].occupant ) then
unit.military.squad_id = -1
unit.military.squad_position = -1
squad.positions[i].occupant = -1
return true
end
end
end
return false
end

function removeAll(squads)
if ( squads == nil) then return end
for n, squad in ipairs(squads) do
for i=1,9,1 do
local dwarf = getByID(squad.positions[i].occupant)
if (dwarf ~= nil) then
dwarf.military.squad_id = -1
dwarf.military.squad_position = -1
squad.positions[i].occupant = -1
end
end
end
end


function check()
local squads = checkSquads()
local intraining_count = 0
local inque_count = 0
if ( squads == nil)then return end
for n, unit in ipairs(citizen) do
local need = findNeed(unit,need_id)
if ( need ~= nil ) then
if ( need.focus_level < threshold ) then
local bol = addTraining(squads,unit)
if ( bol ) then
intraining_count = intraining_count +1
else
inque_count = inque_count +1
end
else
removeTraining(squads,unit)
end
end
end

dfhack.println(scriptname .. " | IGN: " .. ignore_count .. " TRAIN: " .. intraining_count .. " QUE: " ..inque_count )
end

function start()
threshold = -5000
dfhack.println(scriptname .. " | START")

if (args.t) then
threshold = 0-tonumber(args.t)
end

running = true
repeatUtil.scheduleEvery(scriptname,1000,'ticks',check)
end

function stop()
repeatUtil.cancel(scriptname)
local squads = checkSquads()
removeAll(squads)
running = false
dfhack.println(scriptname .. " | STOP")
end

if dfhack_flags.enable then
if dfhack_flags.enable_state then
start()
enabled = true
else
stop()
enabled = false
end
end

if dfhack_flags.module then
return
end

if ( running ) then
dfhack.println(scriptname .." | Enabled")
else
dfhack.println(scriptname .." | Disabled")
end