- 
                Notifications
    
You must be signed in to change notification settings  - Fork 218
 
          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
          
     Merged
      
      
    
  
     Merged
                    Changes from all commits
      Commits
    
    
            Show all changes
          
          
            74 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 98e12c7
              
                fix up silly code in `removeTraining`
              
              
                realSquidCoder 097755e
              
                Update autotraining.lua
              
              
                realSquidCoder e274598
              
                Update autotraining.lua
              
              
                realSquidCoder 2250848
              
                clean and de-nest training candidates
              
              
                realSquidCoder c325bd3
              
                remove units who don't need training
              
              
                realSquidCoder bc3d60f
              
                use our precomputed good squads list
              
              
                realSquidCoder 9800e73
              
                Merge branch 'master' into sci-gym-script
              
              
                realSquidCoder 3f639ec
              
                forgot a nil check
              
              
                realSquidCoder 04e34be
              
                only count as ignored if they are ignored
              
              
                realSquidCoder 5c18bba
              
                Apply suggestions from code review
              
              
                realSquidCoder 8cee911
              
                code review changes
              
              
                realSquidCoder 4e39b7e
              
                Fix up from testing
              
              
                realSquidCoder 0a50575
              
                fix whitespace error
              
              
                realSquidCoder b4503f1
              
                Update and fix changelog
              
              
                realSquidCoder 5836945
              
                only process cli args if we are running in the cli
              
              
                realSquidCoder 2eab602
              
                Merge remote-tracking branch 'upstream/master' into sci-gym-script
              
              
                realSquidCoder 0f445c7
              
                skip units in squads (dont mark as ignored tho)
              
              
                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,296 @@ | ||
| -- 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') | ||
| 
     | 
||
| local GLOBAL_KEY = "autotraining" | ||
| local MartialTraining = 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() | ||
| end | ||
| persist_state() | ||
| end | ||
| 
     | 
||
| 
     | 
||
| --###### | ||
| --Functions | ||
| --###### | ||
| local function isIgnoredNoble(unit) | ||
| local noblePos = dfhack.units.getNoblePositions(unit) | ||
| if noblePos ~= nil then | ||
| for _, position in ipairs(noblePos) do | ||
| if state.ignored_nobles[position.position.code] then | ||
| return true | ||
| end | ||
| end | ||
| end | ||
| return false | ||
| end | ||
| 
     | 
||
| ---@return table<integer, { ['unit']: df.unit, ['need']: integer }> | ||
| function getTrainingCandidates() | ||
| local ret = {} | ||
| ignore_count = 0 | ||
| for _, unit in ipairs(dfhack.units.getCitizens(true)) do | ||
| if not dfhack.units.isAdult(unit) then | ||
| goto next_unit | ||
| end | ||
| local need = getTrainingNeed(unit) | ||
| if not need or need.focus_level >= state.threshold then | ||
| goto next_unit | ||
| end | ||
| -- ignored units are those that would like to train but are forbidden from doing so | ||
| if state.ignored[unit.id] then | ||
| ignore_count = ignore_count + 1 | ||
| goto next_unit | ||
| end | ||
| if isIgnoredNoble(unit) then | ||
| ignore_count = ignore_count + 1 | ||
| goto next_unit | ||
| end | ||
| if unit.military.squad_id ~= -1 then | ||
| goto next_unit | ||
| end | ||
| table.insert(ret, { unit = unit, need = need.focus_level }) | ||
| ::next_unit:: | ||
| end | ||
| table.sort(ret, function (a, b) return a.need < b.need 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 getTrainingNeed(unit) | ||
| if unit == nil then return nil end | ||
| local needs = unit.status.current_soul.personality.needs | ||
| for _, need in ipairs(needs) do | ||
| if need.id == MartialTraining then | ||
| return need | ||
| end | ||
| end | ||
| return nil | ||
| end | ||
| 
     | 
||
| --###### | ||
| --Main | ||
| --###### | ||
| 
     | 
||
| -- 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,good_squads) | ||
| if unit.military.squad_id ~= -1 then | ||
| for _, squad in ipairs(good_squads) do | ||
| if unit.military.squad_id == squad.id then | ||
| return true | ||
| end | ||
| end | ||
| return false | ||
| end | ||
| for _, squad in ipairs(good_squads) 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 removeAll() | ||
| if state.training_squads == nil then return end | ||
| for _, squad in ipairs(getTrainingSquads()) do | ||
| for i=1,9,1 do | ||
| local hf = df.historical_figure.find(squad.positions[i].occupant) | ||
| if hf ~= nil then | ||
| dfhack.military.removeFromSquad(hf.unit_id) | ||
| end | ||
| end | ||
| end | ||
| end | ||
| 
     | 
||
| 
     | 
||
| function check() | ||
| local squads = checkSquads() | ||
                
      
                  realSquidCoder marked this conversation as resolved.
               
          
            Show resolved
            Hide resolved
         | 
||
| local intraining_count = 0 | ||
| local inque_count = 0 | ||
| if squads == nil then return end | ||
| for _,squad in ipairs(squads) do | ||
| for i=1,9,1 do | ||
| if squad.positions[i].occupant ~= -1 then | ||
| local hf = df.historical_figure.find(squad.positions[i].occupant) | ||
| if hf ~= nil then | ||
| local unit = df.unit.find(hf.unit_id) | ||
| local training_need = getTrainingNeed(unit) | ||
| if not training_need or training_need.focus_level >= state.threshold then | ||
| dfhack.military.removeFromSquad(unit.id) | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| for _, p in ipairs(getTrainingCandidates()) do | ||
| local added = addTraining(p.unit, squads) | ||
| if added then | ||
| intraining_count = intraining_count +1 | ||
| else | ||
| inque_count = inque_count +1 | ||
| end | ||
| end | ||
| print(("%s: %d training, %d waiting, and %d excluded units with training needs"): | ||
| format(GLOBAL_KEY, intraining_count, inque_count, ignore_count)) | ||
| end | ||
| 
     | 
||
| function start() | ||
| repeatUtil.scheduleEvery(GLOBAL_KEY, 1, 'days', check) | ||
| end | ||
| 
     | 
||
| function stop() | ||
| repeatUtil.cancel(GLOBAL_KEY) | ||
| end | ||
| 
     | 
||
| function enable() | ||
| state.enabled = true | ||
| persist_state() | ||
| start() | ||
| end | ||
| 
     | 
||
| function disable() | ||
| state.enabled = false | ||
| persist_state() | ||
| stop() | ||
| removeAll() | ||
| end | ||
| 
     | 
||
| if dfhack_flags.module then | ||
| return | ||
| end | ||
| 
     | 
||
| validArgs = utils.invert({ | ||
| 't' | ||
| }) | ||
| 
     | 
||
| local args = utils.processArgs({...}, validArgs) | ||
| 
     | 
||
| if dfhack_flags.enable then | ||
| if dfhack_flags.enable_state then | ||
| enable() | ||
| else | ||
| disable() | ||
| end | ||
| else | ||
| -- called on the command-line | ||
| if args.t then | ||
| state.threshold = 0-tonumber(args.t) | ||
| end | ||
| print(("autotraining is %s"):format(state.enabled and "enabled" or "disabled")) | ||
| end | ||
  
    
      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
    
  
  
    
              
  
    
      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.
        
    
  
      
      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.