|
| 1 | + |
| 2 | +-- From workorder.lua |
| 3 | +---------------------------8<----------------------------- |
| 4 | + |
| 5 | +-- local start = dfhack.getTickCount() |
| 6 | + |
| 7 | +local utils = require 'utils' |
| 8 | + |
| 9 | +local world = df.global.world |
| 10 | +local uu = dfhack.units |
| 11 | + |
| 12 | +local function isValidAnimal(u) |
| 13 | + -- this should also check for the absence of misc trait 55 (as of 50.09), but we don't |
| 14 | + -- currently have an enum definition for that value yet |
| 15 | + return uu.isOwnCiv(u) |
| 16 | + and uu.isAlive(u) |
| 17 | + and uu.isAdult(u) |
| 18 | + and uu.isActive(u) |
| 19 | + and uu.isFortControlled(u) |
| 20 | + and uu.isTame(u) |
| 21 | + and not uu.isMarkedForSlaughter(u) |
| 22 | + and not uu.getMiscTrait(u, df.misc_trait_type.Migrant, false) |
| 23 | +end |
| 24 | + |
| 25 | +-- true/false or nil if no shearable_tissue_layer with length > 0. |
| 26 | +local function canShearCreature(u) |
| 27 | + local stls = world.raws.creatures |
| 28 | + .all[u.race] |
| 29 | + .caste[u.caste] |
| 30 | + .shearable_tissue_layer |
| 31 | + |
| 32 | + local any |
| 33 | + for _, stl in ipairs(stls) do |
| 34 | + if stl.length > 0 then |
| 35 | + for _, bpi in ipairs(stl.bp_modifiers_idx) do |
| 36 | + any = { u.appearance.bp_modifiers[bpi], stl.length } |
| 37 | + if u.appearance.bp_modifiers[bpi] >= stl.length then |
| 38 | + return true, any |
| 39 | + end |
| 40 | + end |
| 41 | + end |
| 42 | + end |
| 43 | + |
| 44 | + if any then return false, any end |
| 45 | + -- otherwise: nil |
| 46 | +end |
| 47 | + |
| 48 | +---------------------------8<----------------------------- |
| 49 | + |
| 50 | +local function canMilkCreature(u) |
| 51 | + if uu.isMilkable(u) and not uu.isPet(u) then |
| 52 | + local mt_milk = uu.getMiscTrait(u, df.misc_trait_type.MilkCounter, false) |
| 53 | + if not mt_milk then return true else return false end |
| 54 | + else |
| 55 | + return nil |
| 56 | + end |
| 57 | +end |
| 58 | + |
| 59 | +function hasJobType(workshop, jobtype) |
| 60 | + for _, job in ipairs(workshop.jobs) do |
| 61 | + if job.job_type == jobtype then return true end |
| 62 | + end |
| 63 | + return false |
| 64 | +end |
| 65 | + |
| 66 | + |
| 67 | +function addWorkshopJob(workshop, job_type, rep, priority) |
| 68 | + local ref = df.general_ref_building_holderst:new() |
| 69 | + ref.building_id = workshop.id |
| 70 | + |
| 71 | + local job = df.job:new() |
| 72 | + job.job_type = job_type |
| 73 | + job.pos = { |
| 74 | + x = workshop.centerx, |
| 75 | + y = workshop.centery, |
| 76 | + z = workshop.z |
| 77 | + } |
| 78 | + job.flags['repeat'] = rep |
| 79 | + job.flags.do_now = priority |
| 80 | + job.general_refs:insert("#", ref) |
| 81 | + workshop.jobs:insert("#", job) |
| 82 | + |
| 83 | + dfhack.job.linkIntoWorld(job, true) |
| 84 | + dfhack.job.checkBuildingsNow() |
| 85 | +end |
| 86 | + |
| 87 | +-- squared distance is enough for ordering by distance |
| 88 | +local function distance2 (x1,y1,x2,y2) |
| 89 | + return (math.abs(x1-x2)^2 + math.abs(y1-y2)^2) |
| 90 | +end |
| 91 | + |
| 92 | +-- local start2 = dfhack.getTickCount() |
| 93 | + |
| 94 | +-- organize workshops by z-level |
| 95 | +local workshops_by_z = {} |
| 96 | +for _, workshop in ipairs(df.global.world.buildings.other.WORKSHOP_FARMER) do |
| 97 | + table.insert(ensure_key(workshops_by_z, workshop.z), workshop) |
| 98 | +end |
| 99 | + |
| 100 | +for _, unit in ipairs(world.units.active) do |
| 101 | + if not isValidAnimal(unit) then goto skip end |
| 102 | + |
| 103 | + local shear = canShearCreature(unit) |
| 104 | + local milk = canMilkCreature(unit) |
| 105 | + |
| 106 | + if not shear and not milk then goto skip end |
| 107 | + |
| 108 | + -- print(dfhack.units.getReadableName(unit),'shear:', shear, 'milk:', milk) |
| 109 | + |
| 110 | + -- locate closest farmers workshop (on same z level) |
| 111 | + local closest = nil |
| 112 | + local distance = nil |
| 113 | + for _, workshop in pairs(workshops_by_z[unit.pos.z] or {}) do |
| 114 | + local d = distance2(unit.pos.x, unit.pos.y, workshop.centerx, workshop.centery) |
| 115 | + if not closest or d < distance then |
| 116 | + closest = workshop |
| 117 | + distance = d |
| 118 | + end |
| 119 | + end |
| 120 | + |
| 121 | + -- enure that closest workshop has the appropriate jobs |
| 122 | + if closest and #closest.jobs < 5 then |
| 123 | + if milk and not hasJobType(closest, df.job_type.MilkCreature) then |
| 124 | + addWorkshopJob(closest, df.job_type.MilkCreature, false, false) |
| 125 | + end |
| 126 | + if shear and not hasJobType(closest, df.job_type.ShearCreature) then |
| 127 | + addWorkshopJob(closest, df.job_type.ShearCreature, false, false) |
| 128 | + end |
| 129 | + end |
| 130 | + |
| 131 | + ::skip:: |
| 132 | +end |
| 133 | + |
| 134 | +-- local end_ = dfhack.getTickCount() |
| 135 | +-- print ('Ticks:', start2 - start, end_ - start) |
0 commit comments