-
Notifications
You must be signed in to change notification settings - Fork 207
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
realSquidCoder
wants to merge
57
commits into
DFHack:master
Choose a base branch
from
SquidCoderIndustries:sci-gym-script
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
57 commits
Select commit
Hold shift + click to select a range
9da6925
New Feature: `gym`
realSquidCoder 81127f2
Fix whitespace
realSquidCoder 5c08fb6
missed some
realSquidCoder edb3e83
MORE whitespace (and some other cleanup)
realSquidCoder 0c4f5b5
Update gym.lua
realSquidCoder 50d6a96
Create gym.rst
realSquidCoder deca155
Fix EOF
realSquidCoder 74784f8
Update gym.rst
realSquidCoder f4cf0a0
fix key error
realSquidCoder 39f2c9c
more key errors
realSquidCoder a5d6c0a
Update the documentation
realSquidCoder 105b0cc
Merge remote-tracking branch 'upstream/master' into sci-gym-script
realSquidCoder 6c53215
Use the enable/disable stuff not args to start or stop
realSquidCoder f701f9f
Merge branch 'master' into sci-gym-script
realSquidCoder f149d5c
Merge remote-tracking branch 'upstream/master' into sci-gym-script
realSquidCoder 4492f3e
Merge remote-tracking branch 'upstream/master' into sci-gym-script
realSquidCoder a6761bd
Do the documentation in one place
realSquidCoder 0acd601
Various fixes
realSquidCoder 9463d79
More cleanup
realSquidCoder 7dba7e4
rename the script itself
realSquidCoder 86967d7
fix docs
realSquidCoder eaa1d86
Add credit where credit is due
realSquidCoder 1892f62
add to control panel
realSquidCoder e69aba5
Check the squad's entity_id to make sure we get *our* Gym
realSquidCoder 0d0ef1e
Update autotraining.lua
realSquidCoder c7c73ad
Fix the ignore count never being reset
realSquidCoder bceb905
Fix units that need training but are already doing so being reported …
realSquidCoder 8803e82
fix the ignore count (it should be global)
realSquidCoder 82d3acd
Apply suggestions from code review
realSquidCoder 00e883f
fix typo
realSquidCoder 6634120
fix to actually check the unit's squad
realSquidCoder ed76a08
Update for gui usage
realSquidCoder 92076ba
clean up
realSquidCoder fc832a3
initial gui and update from code review
realSquidCoder 55ddbfe
show alias in gui too
realSquidCoder f1edec2
clean up
realSquidCoder 3906eb0
Create gui docs
realSquidCoder 59d53f5
update the docs
realSquidCoder 612936b
remove non-existant name args in docs
realSquidCoder f59f6de
fix typo in message
realSquidCoder 1c427c6
fix trainees being labeled as queued
realSquidCoder 648ae90
add ignore nobles
realSquidCoder 3612593
Remove more debug code
realSquidCoder a9bf6e6
Gui cleanup
realSquidCoder 218a41f
Merge remote-tracking branch 'upstream/master' into sci-gym-script
realSquidCoder 3b151be
Merge remote-tracking branch 'upstream/master' into sci-gym-script
realSquidCoder f44a37a
Update to use the Military Module
realSquidCoder 7c186d3
use the squad position
realSquidCoder f670df7
Remove all training dwarves when you disable
realSquidCoder 996a5f8
Merge branch 'master' into sci-gym-script
realSquidCoder 595a760
disable autotraining on map unload
realSquidCoder 067d182
Merge remote-tracking branch 'upstream/master' into sci-gym-script
realSquidCoder cf1431e
Apply suggestions from code review
realSquidCoder 7d0ded1
fix erroneous training numbers
realSquidCoder 191a5c3
Update autotraining.rst
realSquidCoder 807f350
remove outdated debug logging
realSquidCoder 7b77466
remove outdated comment
realSquidCoder File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,297 @@ | ||
-- Based on the original code by RNGStrategist (who also got some help from Uncle Danny) | ||
--@ enable = true | ||
--@ module = true | ||
|
||
local repeatUtil = require('repeat-util') | ||
local utils=require('utils') | ||
|
||
validArgs = utils.invert({ | ||
't' | ||
}) | ||
|
||
local args = utils.processArgs({...}, validArgs) | ||
local GLOBAL_KEY = "autotraining" | ||
local need_id = df.need_type['MartialTraining'] | ||
local ignore_count = 0 | ||
|
||
local function get_default_state() | ||
return { | ||
enabled=false, | ||
threshold=-5000, | ||
ignored={}, | ||
ignored_nobles={}, | ||
training_squads = {}, | ||
} | ||
end | ||
|
||
state = state or get_default_state() | ||
|
||
function isEnabled() | ||
return state.enabled | ||
end | ||
|
||
-- persisting a table with numeric keys results in a json array with a huge number of null entries | ||
-- therefore, we convert the keys to strings for persistence | ||
local function to_persist(persistable) | ||
local persistable_ignored = {} | ||
for k, v in pairs(persistable) do | ||
persistable_ignored[tostring(k)] = v | ||
end | ||
return persistable_ignored | ||
end | ||
|
||
-- loads both from the older array format and the new string table format | ||
local function from_persist(persistable) | ||
if not persistable then | ||
return | ||
end | ||
local ret = {} | ||
for k, v in pairs(persistable) do | ||
ret[tonumber(k)] = v | ||
end | ||
return ret | ||
end | ||
|
||
function persist_state() | ||
dfhack.persistent.saveSiteData(GLOBAL_KEY, { | ||
enabled=state.enabled, | ||
threshold=state.threshold, | ||
ignored=to_persist(state.ignored), | ||
ignored_nobles=state.ignored_nobles, | ||
training_squads=to_persist(state.training_squads) | ||
}) | ||
end | ||
|
||
--- Load the saved state of the script | ||
local function load_state() | ||
-- load persistent data | ||
local persisted_data = dfhack.persistent.getSiteData(GLOBAL_KEY, {}) | ||
state.enabled = persisted_data.enabled or state.enabled | ||
state.threshold = persisted_data.threshold or state.threshold | ||
state.ignored = from_persist(persisted_data.ignored) or state.ignored | ||
state.ignored_nobles = persisted_data.ignored_nobles or state.ignored_nobles | ||
state.training_squads = from_persist(persisted_data.training_squads) or state.training_squads | ||
return state | ||
end | ||
|
||
dfhack.onStateChange[GLOBAL_KEY] = function(sc) | ||
if sc == SC_MAP_UNLOADED then | ||
state.enabled = false | ||
return | ||
end | ||
-- the state changed, is a map loaded and is that map in fort mode? | ||
if sc ~= SC_MAP_LOADED or df.global.gamemode ~= df.game_mode.DWARF then | ||
-- no its isnt, so bail | ||
return | ||
end | ||
-- yes it was, so: | ||
|
||
-- retrieve state saved in game. merge with default state so config | ||
-- saved from previous versions can pick up newer defaults. | ||
load_state() | ||
if ( state.enabled ) then | ||
start() | ||
else | ||
stop() | ||
end | ||
persist_state() | ||
end | ||
|
||
|
||
--###### | ||
--Functions | ||
--###### | ||
function getTrainingCandidates() | ||
local ret = {} | ||
local citizen = dfhack.units.getCitizens(true) | ||
ignore_count = 0 | ||
for _, unit in ipairs(citizen) do | ||
if dfhack.units.isAdult(unit) then | ||
local noblePos = dfhack.units.getNoblePositions(unit) | ||
local isIgnNoble = false | ||
if ( not state.ignored[unit.id] ) then | ||
if noblePos ~=nil then | ||
for _, position in ipairs(noblePos) do | ||
if state.ignored_nobles[position.position.code] then | ||
isIgnNoble = true | ||
break | ||
end | ||
end | ||
end | ||
if not isIgnNoble then | ||
table.insert(ret, unit) | ||
else | ||
removeTraining(unit) | ||
ignore_count = ignore_count +1 | ||
end | ||
else | ||
removeTraining(unit) | ||
ignore_count = ignore_count +1 | ||
end | ||
end | ||
end | ||
return ret | ||
end | ||
|
||
function getTrainingSquads() | ||
local squads = {} | ||
for squad_id, _ in pairs(state.training_squads) do | ||
local squad = df.squad.find(squad_id) | ||
if squad then | ||
table.insert(squads, squad) | ||
else | ||
-- setting to nil during iteration is permitted by lua | ||
state.training_squads[squad_id] = nil | ||
end | ||
end | ||
return squads | ||
end | ||
|
||
function findNeed(unit) | ||
local needs = unit.status.current_soul.personality.needs | ||
for _, need in ipairs(needs) do | ||
if need.id == need_id then | ||
return need | ||
end | ||
end | ||
return nil | ||
end | ||
|
||
--###### | ||
--Main | ||
--###### | ||
|
||
function getByID(id) | ||
for _, unit in ipairs(getTrainingCandidates()) 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 = {} | ||
for _, squad in ipairs(getTrainingSquads()) do | ||
if squad.entity_id == df.global.plotinfo.group_id then | ||
local leader = squad.positions[0].occupant | ||
if ( leader ~= -1) then | ||
table.insert(squads,squad) | ||
end | ||
end | ||
end | ||
|
||
if (#squads == 0) then | ||
return nil | ||
end | ||
|
||
return squads | ||
end | ||
|
||
function addTraining(unit) | ||
if (unit.military.squad_id ~= -1) then | ||
for _, squad in ipairs(getTrainingSquads()) do | ||
if unit.military.squad_id == squad.id then | ||
return true | ||
end | ||
end | ||
return false | ||
end | ||
for _, squad in ipairs(getTrainingSquads()) do | ||
for i=1,9,1 do | ||
if ( squad.positions[i].occupant == -1 ) then | ||
return dfhack.military.addToSquad(unit.id,squad.id,i) | ||
end | ||
end | ||
end | ||
|
||
return false | ||
end | ||
|
||
function removeTraining(unit) | ||
for _, squad in ipairs(getTrainingSquads()) do | ||
for i=1,9,1 do | ||
if ( unit.hist_figure_id == squad.positions[i].occupant ) then | ||
return dfhack.military.removeFromSquad(unit.id) | ||
end | ||
end | ||
end | ||
return false | ||
end | ||
|
||
function removeAll() | ||
if ( state.training_squads == nil) then return end | ||
for _, squad in ipairs(getTrainingSquads()) do | ||
for i=1,9,1 do | ||
local dwarf = getByID(squad.positions[i].occupant) | ||
if (dwarf ~= nil) then | ||
removeTraining(dwarf) | ||
end | ||
end | ||
end | ||
end | ||
|
||
|
||
function check() | ||
local squads = checkSquads() | ||
local intraining_count = 0 | ||
local inque_count = 0 | ||
if ( squads == nil) then return end | ||
for _, unit in ipairs(getTrainingCandidates()) do | ||
local need = findNeed(unit) | ||
if ( need ~= nil ) then | ||
if ( need.focus_level < state.threshold ) then | ||
local bol = addTraining(unit) | ||
if ( bol ) then | ||
intraining_count = intraining_count +1 | ||
else | ||
inque_count = inque_count +1 | ||
end | ||
else | ||
removeTraining(unit) | ||
end | ||
end | ||
end | ||
|
||
dfhack.println(GLOBAL_KEY .. " | IGN: " .. ignore_count .. " TRAIN: " .. intraining_count .. " QUE: " ..inque_count ) | ||
end | ||
|
||
function start() | ||
dfhack.println(GLOBAL_KEY .. " | START") | ||
|
||
if (args.t) then | ||
state.threshold = 0-tonumber(args.t) | ||
end | ||
repeatUtil.scheduleEvery(GLOBAL_KEY, 1, 'days', check) | ||
end | ||
|
||
function stop() | ||
removeAll() | ||
repeatUtil.cancel(GLOBAL_KEY) | ||
dfhack.println(GLOBAL_KEY .. " | STOP") | ||
end | ||
|
||
if dfhack_flags.enable then | ||
if dfhack_flags.enable_state then | ||
state.enabled = true | ||
else | ||
state.enabled = false | ||
end | ||
persist_state() | ||
end | ||
|
||
if dfhack_flags.module then | ||
return | ||
end | ||
|
||
if ( state.enabled ) then | ||
start() | ||
dfhack.println(GLOBAL_KEY .." | Enabled") | ||
else | ||
stop() | ||
dfhack.println(GLOBAL_KEY .." | Disabled") | ||
end | ||
persist_state() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
autotraining | ||
============ | ||
|
||
.. dfhack-tool:: | ||
:summary: Assigns citizens to a military squad until they have fulfilled their need for Martial Training | ||
:tags: fort auto bugfix units | ||
|
||
This script automatically assigns citizens with the need for military training to designated training squads. | ||
|
||
You need to have at least one squad that is set up for training. The squad should be set to "Constant Training" in the military screen. The squad doesn't need months off. The members leave the squad once they have satisfied their need for military training. | ||
|
||
The configured uniform determines the skills that are acquired by the training dwarves. Providing "No Uniform" is a perfectly valid choice and will make your militarily inclined civilians become wrestlers over time. However, you can also provide weapons and armor to pre-train civilians for future drafts. | ||
|
||
Once you have made squads for training use `gui/autotraining` to select the squads and ignored units, as well as the needs threshhold. | ||
|
||
Usage | ||
----- | ||
|
||
``autotraining [<options>]`` | ||
|
||
Examples | ||
-------- | ||
|
||
``autotraining`` | ||
Current status of script | ||
|
||
``enable autotraining`` | ||
Checks to see if you have fullfilled the creation of a training squad. | ||
If there is no squad marked for training use, a clickable notification will appear letting you know to set one up/ | ||
Searches your fort for dwarves with a need for military training, and begins assigning them to a training squad. | ||
Once they have fulfilled their need they will be removed from their squad to be replaced by the next dwarf in the list. | ||
|
||
``disable autotraining`` | ||
Stops adding new units to the squad. | ||
|
||
Options | ||
------- | ||
``-t`` | ||
Use integer values. (Default 5000) | ||
The negative need threshhold to trigger for each citizen | ||
The greater the number the longer before a dwarf is added to the waiting list. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
gui/autotraining | ||
================ | ||
|
||
.. dfhack-tool:: | ||
:summary: GUI interface for ``autotraining`` | ||
:tags: fort auto interface | ||
|
||
This is an in-game configuration interface for `autotraining`. You can pick squads for training, select ignored units, and set the needs threshold. | ||
|
||
Usage | ||
----- | ||
|
||
:: | ||
|
||
gui/autotraining |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.