=begin autofarm ======== Automatically handle crop selection in farm plots based on current plant stocks. Selects a crop for planting if current stock is below a threshold. Selected crops are dispatched on all farmplots. Usage:: autofarm start autofarm default 30 autofarm threshold 150 helmet_plump tail_pig =end class AutoFarm def initialize @thresholds = Hash.new(50) @lastcounts = Hash.new(0) end def setthreshold(id, v) list = df.world.raws.plants.all.find_all { |plt| plt.flags[:SEED] }.map { |plt| plt.id } if tok = df.match_rawname(id, list) @thresholds[tok] = v.to_i else puts "No plant with id #{id}, try one of " + list.map { |w| w =~ /[^\w]/ ? w.inspect : w }.sort.join(' ') end end def setdefault(v) @thresholds.default = v.to_i end def is_plantable(plant) has_seed = plant.flags[:SEED] season = df.cur_season harvest = df.cur_season_tick + plant.growdur * 10 will_finish = harvest < 10080 can_plant = has_seed && plant.flags[season] can_plant = can_plant && (will_finish || plant.flags[(season+1)%4]) can_plant end def find_plantable_plants plantable = {} counts = Hash.new(0) df.world.items.other[:SEEDS].each { |i| if (!i.flags.dump && !i.flags.forbid && !i.flags.garbage_collect && !i.flags.hostile && !i.flags.on_fire && !i.flags.rotten && !i.flags.trader && !i.flags.in_building && !i.flags.construction && !i.flags.artifact) counts[i.mat_index] += i.stack_size end } counts.keys.each { |i| if df.ui.tasks.discovered_plants[i] plant = df.world.raws.plants.all[i] if is_plantable(plant) plantable[i] = :Surface if (plant.underground_depth_min == 0 || plant.underground_depth_max == 0) plantable[i] = :Underground if (plant.underground_depth_min > 0 || plant.underground_depth_max > 0) end end } return plantable end def set_farms(plants, farms) return if farms.length == 0 if plants.length == 0 plants = [-1] end season = df.cur_season farms.each_with_index { |f, idx| f.plant_id[season] = plants[idx % plants.length] } end def process plantable = find_plantable_plants @lastcounts = Hash.new(0) df.world.items.other[:PLANT].each { |i| if (!i.flags.dump && !i.flags.forbid && !i.flags.garbage_collect && !i.flags.hostile && !i.flags.on_fire && !i.flags.rotten && !i.flags.trader && !i.flags.in_building && !i.flags.construction && !i.flags.artifact && plantable.has_key?(i.mat_index)) id = df.world.raws.plants.all[i.mat_index].id @lastcounts[id] += i.stack_size end } return unless @running plants_s = [] plants_u = [] plantable.each_key { |k| plant = df.world.raws.plants.all[k] if (@lastcounts[plant.id] < @thresholds[plant.id]) plants_s.push(k) if plantable[k] == :Surface plants_u.push(k) if plantable[k] == :Underground end } farms_s = [] farms_u = [] df.world.buildings.other[:FARM_PLOT].each { |f| if (f.flags.exists) underground = df.map_designation_at(f.centerx,f.centery,f.z).subterranean farms_s.push(f) unless underground farms_u.push(f) if underground end } set_farms(plants_s, farms_s) set_farms(plants_u, farms_u) end def start return if @running @onupdate = df.onupdate_register('autofarm', 1200) { process } @running = true end def stop df.onupdate_unregister(@onupdate) @running = false end def status stat = @running ? "Running." : "Stopped." @lastcounts.each { |k,v| stat << "\n#{k} limit #{@thresholds.fetch(k, 'default')} current #{v}" } @thresholds.each { |k,v| stat << "\n#{k} limit #{v} current 0" unless @lastcounts.has_key?(k) } stat << "\nDefault: #{@thresholds.default}" stat end end $AutoFarm ||= AutoFarm.new case $script_args[0] when 'start', 'enable' $AutoFarm.start puts $AutoFarm.status when 'end', 'stop', 'disable' $AutoFarm.stop puts 'Stopped.' when 'default' $AutoFarm.setdefault($script_args[1]) when 'threshold' t = $script_args[1] $script_args[2..-1].each {|i| $AutoFarm.setthreshold(i, t) } when 'delete' $AutoFarm.stop $AutoFarm = nil when 'help', '?' puts <