diff --git a/add-thought.lua b/add-thought.lua index 3739f85c76..3136474451 100644 --- a/add-thought.lua +++ b/add-thought.lua @@ -70,14 +70,14 @@ if args.gui then end) else local thought = args.thought or 180 - + local emotion = args.emotion or -1 - + local severity = args.severity or 0 - + local subthought = args.subthought or 0 - + local strength = args.strength or 0 - + addEmotionToUnit(unit,thought,emotion,severity,strength,subthought) end diff --git a/autofarm.rb b/autofarm.rb index 52e0245bec..cc2f29dff8 100644 --- a/autofarm.rb +++ b/autofarm.rb @@ -1,176 +1,176 @@ -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 < 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 < 0 - puts "Unsuspended #{count} job(s)." - df.process_jobs = true - end - end - - def start - @running = true - @onupdate = df.onupdate_register('autounsuspend', 5) { process if @running } - end - - def stop - @running = false - df.onupdate_unregister(@onupdate) - end -end - -case $script_args[0] -when 'start' - $AutoUnsuspend ||= AutoUnsuspend.new - $AutoUnsuspend.start - -when 'end', 'stop' - $AutoUnsuspend.stop - -else - puts $AutoUnsuspend && $AutoUnsuspend.running ? 'Running.' : 'Stopped.' -end +class AutoUnsuspend + attr_accessor :running + + def process + count = 0 + df.world.job_list.each { |job| + if job.job_type == :ConstructBuilding and job.flags.suspend and df.map_tile_at(job).designation.flow_size <= 1 + job.flags.suspend = false + count += 1 + end + } + if count > 0 + puts "Unsuspended #{count} job(s)." + df.process_jobs = true + end + end + + def start + @running = true + @onupdate = df.onupdate_register('autounsuspend', 5) { process if @running } + end + + def stop + @running = false + df.onupdate_unregister(@onupdate) + end +end + +case $script_args[0] +when 'start' + $AutoUnsuspend ||= AutoUnsuspend.new + $AutoUnsuspend.start + +when 'end', 'stop' + $AutoUnsuspend.stop + +else + puts $AutoUnsuspend && $AutoUnsuspend.running ? 'Running.' : 'Stopped.' +end diff --git a/create-items.rb b/create-items.rb index fb1b2d8c72..ea739f4e0a 100644 --- a/create-items.rb +++ b/create-items.rb @@ -1,177 +1,177 @@ -# create first necessity items under cursor - -category = $script_args[0] || 'help' -mat_raw = $script_args[1] || 'list' -count = $script_args[2] - - -category = df.match_rawname(category, ['help', 'bars', 'boulders', 'plants', 'logs', 'webs', 'anvils']) || 'help' - -if category == 'help' - puts < 5 - df.curview.feed_keys(:CURSOR_DOWN_Z) - df.curview.feed_keys(:CURSOR_UP_Z) -else - df.curview.feed_keys(:CURSOR_UP_Z) - df.curview.feed_keys(:CURSOR_DOWN_Z) -end +# create first necessity items under cursor + +category = $script_args[0] || 'help' +mat_raw = $script_args[1] || 'list' +count = $script_args[2] + + +category = df.match_rawname(category, ['help', 'bars', 'boulders', 'plants', 'logs', 'webs', 'anvils']) || 'help' + +if category == 'help' + puts < 5 + df.curview.feed_keys(:CURSOR_DOWN_Z) + df.curview.feed_keys(:CURSOR_UP_Z) +else + df.curview.feed_keys(:CURSOR_UP_Z) + df.curview.feed_keys(:CURSOR_DOWN_Z) +end diff --git a/deathcause.rb b/deathcause.rb index 45e87daff1..4ba3d2388d 100644 --- a/deathcause.rb +++ b/deathcause.rb @@ -1,67 +1,67 @@ -# show death cause of a creature - -def display_death_event(e) - str = "The #{e.victim_hf_tg.race_tg.name[0]} #{e.victim_hf_tg.name} died in year #{e.year}" - str << " (cause: #{e.death_cause.to_s.downcase})," - str << " killed by the #{e.slayer_race_tg.name[0]} #{e.slayer_hf_tg.name}" if e.slayer_hf != -1 - str << " using a #{df.world.raws.itemdefs.weapons[e.weapon.item_subtype].name}" if e.weapon.item_type == :WEAPON - str << ", shot by a #{df.world.raws.itemdefs.weapons[e.weapon.shooter_item_subtype].name}" if e.weapon.shooter_item_type == :WEAPON - - puts str.chomp(',') + '.' -end - -def display_death_unit(u) - death_info = u.counters.death_tg - killer = death_info.killer_tg if death_info - - str = "The #{u.race_tg.name[0]}" - str << " #{u.name}" if u.name.has_name - str << " died" - str << " in year #{death_info.event_year}" if death_info - str << " (cause: #{u.counters.death_cause.to_s.downcase})," if u.counters.death_cause != -1 - str << " killed by the #{killer.race_tg.name[0]} #{killer.name}" if killer - - puts str.chomp(',') + '.' -end - -item = df.item_find(:selected) -unit = df.unit_find(:selected) - -if !item or !item.kind_of?(DFHack::ItemBodyComponent) - item = df.world.items.other[:ANY_CORPSE].find { |i| df.at_cursor?(i) } -end - -if item and item.kind_of?(DFHack::ItemBodyComponent) - hf = item.hist_figure_id -elsif unit - hf = unit.hist_figure_id -end - -if not hf - puts "Please select a corpse in the loo'k' menu, or an unit in the 'u'nitlist screen" - -elsif hf == -1 - if unit ||= item.unit_tg - display_death_unit(unit) - else - puts "Not a historical figure, cannot death find info" - end - -else - histfig = df.world.history.figures.binsearch(hf) - unit = histfig ? df.unit_find(histfig.unit_id) : nil - if unit and not unit.flags1.dead and not unit.flags3.ghostly - puts "#{unit.name} is not dead yet !" - - else - events = df.world.history.events - (0...events.length).reverse_each { |i| - e = events[i] - if e.kind_of?(DFHack::HistoryEventHistFigureDiedst) and e.victim_hf == hf - display_death_event(e) - break - end - } - end -end - +# show death cause of a creature + +def display_death_event(e) + str = "The #{e.victim_hf_tg.race_tg.name[0]} #{e.victim_hf_tg.name} died in year #{e.year}" + str << " (cause: #{e.death_cause.to_s.downcase})," + str << " killed by the #{e.slayer_race_tg.name[0]} #{e.slayer_hf_tg.name}" if e.slayer_hf != -1 + str << " using a #{df.world.raws.itemdefs.weapons[e.weapon.item_subtype].name}" if e.weapon.item_type == :WEAPON + str << ", shot by a #{df.world.raws.itemdefs.weapons[e.weapon.shooter_item_subtype].name}" if e.weapon.shooter_item_type == :WEAPON + + puts str.chomp(',') + '.' +end + +def display_death_unit(u) + death_info = u.counters.death_tg + killer = death_info.killer_tg if death_info + + str = "The #{u.race_tg.name[0]}" + str << " #{u.name}" if u.name.has_name + str << " died" + str << " in year #{death_info.event_year}" if death_info + str << " (cause: #{u.counters.death_cause.to_s.downcase})," if u.counters.death_cause != -1 + str << " killed by the #{killer.race_tg.name[0]} #{killer.name}" if killer + + puts str.chomp(',') + '.' +end + +item = df.item_find(:selected) +unit = df.unit_find(:selected) + +if !item or !item.kind_of?(DFHack::ItemBodyComponent) + item = df.world.items.other[:ANY_CORPSE].find { |i| df.at_cursor?(i) } +end + +if item and item.kind_of?(DFHack::ItemBodyComponent) + hf = item.hist_figure_id +elsif unit + hf = unit.hist_figure_id +end + +if not hf + puts "Please select a corpse in the loo'k' menu, or an unit in the 'u'nitlist screen" + +elsif hf == -1 + if unit ||= item.unit_tg + display_death_unit(unit) + else + puts "Not a historical figure, cannot death find info" + end + +else + histfig = df.world.history.figures.binsearch(hf) + unit = histfig ? df.unit_find(histfig.unit_id) : nil + if unit and not unit.flags1.dead and not unit.flags3.ghostly + puts "#{unit.name} is not dead yet !" + + else + events = df.world.history.events + (0...events.length).reverse_each { |i| + e = events[i] + if e.kind_of?(DFHack::HistoryEventHistFigureDiedst) and e.victim_hf == hf + display_death_event(e) + break + end + } + end +end + diff --git a/devel/light.lua b/devel/light.lua index 48324d7973..111d12b46b 100644 --- a/devel/light.lua +++ b/devel/light.lua @@ -9,367 +9,367 @@ local tile_attrs = df.tiletype.attrs local args={...} function setCell(x,y,cell) - cell=cell or {} - cell.fm=cell.fm or {r=1,g=1,b=1} - cell.bm=cell.bm or {r=1,g=1,b=1} - cell.fo=cell.fo or {r=0,g=0,b=0} - cell.bo=cell.bo or {r=0,g=0,b=0} - render.setCell(x,y,cell) + cell=cell or {} + cell.fm=cell.fm or {r=1,g=1,b=1} + cell.bm=cell.bm or {r=1,g=1,b=1} + cell.fo=cell.fo or {r=0,g=0,b=0} + cell.bo=cell.bo or {r=0,g=0,b=0} + render.setCell(x,y,cell) end function getCursorPos() - local g_cursor=df.global.cursor + local g_cursor=df.global.cursor if g_cursor.x ~= -30000 then return copyall(g_cursor) end end function falloff(color,sqDist,maxdist) - local v1=1/(sqDist/maxdist+1) - local v2=v1-1/(1+maxdist*maxdist) - local v=v2/(1-1/(1+maxdist*maxdist)) - return {r=v*color.r,g=v*color.g,b=v*color.b} + local v1=1/(sqDist/maxdist+1) + local v2=v1-1/(1+maxdist*maxdist) + local v=v2/(1-1/(1+maxdist*maxdist)) + return {r=v*color.r,g=v*color.g,b=v*color.b} end function blend(c1,c2) return {r=math.max(c1.r,c2.r), - g=math.max(c1.g,c2.g), - b=math.max(c1.b,c2.b)} + g=math.max(c1.g,c2.g), + b=math.max(c1.b,c2.b)} end LightOverlay=defclass(LightOverlay,guidm.DwarfOverlay) LightOverlay.ATTRS { lightMap={}, - dynamic=true, - dirty=false, + dynamic=true, + dirty=false, } function LightOverlay:init(args) - - self.tick=df.global.cur_year_tick_advmode + + self.tick=df.global.cur_year_tick_advmode end function lightPassable(shape) - if shape==df.tiletype_shape.WALL or - shape==df.tiletype_shape.BROOK_BED or - shape==df.tiletype_shape.TREE then - return false - else - return true - end + if shape==df.tiletype_shape.WALL or + shape==df.tiletype_shape.BROOK_BED or + shape==df.tiletype_shape.TREE then + return false + else + return true + end end function circle(xm, ym,r,plot) local x = -r local y = 0 - local err = 2-2*r -- /* II. Quadrant */ - repeat + local err = 2-2*r -- /* II. Quadrant */ + repeat plot(xm-x, ym+y);--/* I. Quadrant */ plot(xm-y, ym-x);--/* II. Quadrant */ plot(xm+x, ym-y);--/* III. Quadrant */ plot(xm+y, ym+x);--/* IV. Quadrant */ r = err; if (r <= y) then - y=y+1 - err =err+y*2+1; --/* e_xy+e_y < 0 */ - end + y=y+1 + err =err+y*2+1; --/* e_xy+e_y < 0 */ + end if (r > x or err > y) then - x=x+1 - err =err+x*2+1; --/* e_xy+e_x > 0 or no 2nd y-step */ - end + x=x+1 + err =err+x*2+1; --/* e_xy+e_x > 0 or no 2nd y-step */ + end until (x >= 0); end function line(x0, y0, x1, y1,plot) - local dx = math.abs(x1-x0) - local dy = math.abs(y1-y0) - local sx,sy - if x0 < x1 then sx = 1 else sx = -1 end - if y0 < y1 then sy = 1 else sy = -1 end - local err = dx-dy + local dx = math.abs(x1-x0) + local dy = math.abs(y1-y0) + local sx,sy + if x0 < x1 then sx = 1 else sx = -1 end + if y0 < y1 then sy = 1 else sy = -1 end + local err = dx-dy - while true do - if not plot(x0,y0) then - return - end - if x0 == x1 and y0 == y1 then - break - end - local e2 = 2*err - if e2 > -dy then - err = err - dy - x0 = x0 + sx - end - if x0 == x1 and y0 == y1 then - if not plot(x0,y0) then - return - end - break - end - if e2 < dx then - err = err + dx - y0 = y0 + sy - end - end + while true do + if not plot(x0,y0) then + return + end + if x0 == x1 and y0 == y1 then + break + end + local e2 = 2*err + if e2 > -dy then + err = err - dy + x0 = x0 + sx + end + if x0 == x1 and y0 == y1 then + if not plot(x0,y0) then + return + end + break + end + if e2 < dx then + err = err + dx + y0 = y0 + sy + end + end end function LightOverlay:calculateFovs() - self.fovs=self.fovs or {} - self.precalc=self.precalc or {} - for k,v in ipairs(self.fovs) do - self:calculateFov(v.pos,v.radius,v.color) - end + self.fovs=self.fovs or {} + self.precalc=self.precalc or {} + for k,v in ipairs(self.fovs) do + self:calculateFov(v.pos,v.radius,v.color) + end end function LightOverlay:calculateFov(pos,radius,color) - local vp=self:getViewport() - local map = self.df_layout.map - local ray=function(tx,ty) - local power=copyall(color) - local lx=pos.x - local ly=pos.y - local setTile=function(x,y) - if x>0 and y>0 and x<=map.width and y<=map.height then - local dtsq=(lx-x)*(lx-x)+(ly-y)*(ly-y) - local dt=math.sqrt(dtsq) - local tile=x+y*map.width - if self.precalc[tile] then - local tcol=blend(self.precalc[tile],power) - if tcol.r==self.precalc[tile].r and tcol.g==self.precalc[tile].g and self.precalc[tile].b==self.precalc[tile].b - and dtsq>0 then - return false - end - end - local ocol=self.lightMap[tile] or {r=0,g=0,b=0} - local ncol=blend(power,ocol) - - self.lightMap[tile]=ncol - local v=self.ocupancy[tile] - if dtsq>0 then - power.r=power.r*(v.r^dt) - power.g=power.g*(v.g^dt) - power.b=power.b*(v.b^dt) - end - lx=x - ly=y - local pwsq=power.r*power.r+power.g*power.g+power.b*power.b - return pwsq>levelDim*levelDim - end - return false - end - line(pos.x,pos.y,tx,ty,setTile) - end - circle(pos.x,pos.y,radius,ray) + local vp=self:getViewport() + local map = self.df_layout.map + local ray=function(tx,ty) + local power=copyall(color) + local lx=pos.x + local ly=pos.y + local setTile=function(x,y) + if x>0 and y>0 and x<=map.width and y<=map.height then + local dtsq=(lx-x)*(lx-x)+(ly-y)*(ly-y) + local dt=math.sqrt(dtsq) + local tile=x+y*map.width + if self.precalc[tile] then + local tcol=blend(self.precalc[tile],power) + if tcol.r==self.precalc[tile].r and tcol.g==self.precalc[tile].g and self.precalc[tile].b==self.precalc[tile].b + and dtsq>0 then + return false + end + end + local ocol=self.lightMap[tile] or {r=0,g=0,b=0} + local ncol=blend(power,ocol) + + self.lightMap[tile]=ncol + local v=self.ocupancy[tile] + if dtsq>0 then + power.r=power.r*(v.r^dt) + power.g=power.g*(v.g^dt) + power.b=power.b*(v.b^dt) + end + lx=x + ly=y + local pwsq=power.r*power.r+power.g*power.g+power.b*power.b + return pwsq>levelDim*levelDim + end + return false + end + line(pos.x,pos.y,tx,ty,setTile) + end + circle(pos.x,pos.y,radius,ray) end function LightOverlay:placeLightFov(pos,radius,color) - local map = self.df_layout.map - local tile=pos.x+pos.y*map.width - local ocol=self.precalc[tile] or {r=0,g=0,b=0} - local ncol=blend(color,ocol) - self.precalc[tile]=ncol - local ocol=self.lightMap[tile] or {r=0,g=0,b=0} - local ncol=blend(color,ocol) - self.lightMap[tile]=ncol - table.insert(self.fovs,{pos=pos,radius=radius,color=color}) + local map = self.df_layout.map + local tile=pos.x+pos.y*map.width + local ocol=self.precalc[tile] or {r=0,g=0,b=0} + local ncol=blend(color,ocol) + self.precalc[tile]=ncol + local ocol=self.lightMap[tile] or {r=0,g=0,b=0} + local ncol=blend(color,ocol) + self.lightMap[tile]=ncol + table.insert(self.fovs,{pos=pos,radius=radius,color=color}) end function LightOverlay:placeLightFov2(pos,radius,color,f,rays) - f=f or falloff - local raycount=rays or 25 - local vp=self:getViewport() - local map = self.df_layout.map - local off=math.random(0,math.pi) - local done={} - for d=0,math.pi*2,math.pi*2/raycount do - local dx,dy - dx=math.cos(d+off) - dy=math.sin(d+off) - local cx=0 - local cy=0 - - for dt=0,radius,0.01 do - if math.abs(math.floor(dt*dx)-cx)>0 or math.abs(math.floor(dt*dy)-cy)> 0then - local x=cx+pos.x - local y=cy+pos.y - - if x>0 and y>0 and x<=map.width and y<=map.height and not done[tile] then - local tile=x+y*map.width - done[tile]=true - local ncol=f(color,dt*dt,radius) - local ocol=self.lightMap[tile] or {r=0,g=0,b=0} - ncol=blend(ncol,ocol) - self.lightMap[tile]=ncol - - - if --(ncol.r==ocol.r and ncol.g==ocol.g and ncol.b==ocol.b) or - not self.ocupancy[tile] then - break - end - end - cx=math.floor(dt*dx) - cy=math.floor(dt*dy) - end - end - end + f=f or falloff + local raycount=rays or 25 + local vp=self:getViewport() + local map = self.df_layout.map + local off=math.random(0,math.pi) + local done={} + for d=0,math.pi*2,math.pi*2/raycount do + local dx,dy + dx=math.cos(d+off) + dy=math.sin(d+off) + local cx=0 + local cy=0 + + for dt=0,radius,0.01 do + if math.abs(math.floor(dt*dx)-cx)>0 or math.abs(math.floor(dt*dy)-cy)> 0then + local x=cx+pos.x + local y=cy+pos.y + + if x>0 and y>0 and x<=map.width and y<=map.height and not done[tile] then + local tile=x+y*map.width + done[tile]=true + local ncol=f(color,dt*dt,radius) + local ocol=self.lightMap[tile] or {r=0,g=0,b=0} + ncol=blend(ncol,ocol) + self.lightMap[tile]=ncol + + + if --(ncol.r==ocol.r and ncol.g==ocol.g and ncol.b==ocol.b) or + not self.ocupancy[tile] then + break + end + end + cx=math.floor(dt*dx) + cy=math.floor(dt*dy) + end + end + end end function LightOverlay:placeLight(pos,radius,color,f) - f=f or falloff - local vp=self:getViewport() - local map = self.df_layout.map + f=f or falloff + local vp=self:getViewport() + local map = self.df_layout.map - for i=-radius,radius do - for j=-radius,radius do - local x=pos.x+i+1 - local y=pos.y+j+1 - if x>0 and y>0 and x<=map.width and y<=map.height then - local tile=x+y*map.width - local ncol=f(color,(i*i+j*j),radius) - local ocol=self.lightMap[tile] or {r=0,g=0,b=0} - self.lightMap[tile]=blend(ncol,ocol) - end - end - end + for i=-radius,radius do + for j=-radius,radius do + local x=pos.x+i+1 + local y=pos.y+j+1 + if x>0 and y>0 and x<=map.width and y<=map.height then + local tile=x+y*map.width + local ncol=f(color,(i*i+j*j),radius) + local ocol=self.lightMap[tile] or {r=0,g=0,b=0} + self.lightMap[tile]=blend(ncol,ocol) + end + end + end end function LightOverlay:calculateLightLava() - local vp=self:getViewport() - local map = self.df_layout.map - for i=map.x1,map.x2 do - for j=map.y1,map.y2 do - local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z} - local pos2={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z-1} - local t1=dfhack.maps.getTileFlags(pos) - local tt=dfhack.maps.getTileType(pos) - if tt then - local shape=tile_attrs[tt].shape - local t2=dfhack.maps.getTileFlags(pos2) - if (t1 and t1.liquid_type and t1.flow_size>0) or - (shape==df.tiletype_shape.EMPTY and t2 and t2.liquid_type and t2.flow_size>0) then - --self:placeLight({x=i,y=j},5,{r=0.8,g=0.2,b=0.2}) - self:placeLightFov({x=i,y=j},5,{r=0.8,g=0.2,b=0.2},nil) - end - end - end - end + local vp=self:getViewport() + local map = self.df_layout.map + for i=map.x1,map.x2 do + for j=map.y1,map.y2 do + local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z} + local pos2={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z-1} + local t1=dfhack.maps.getTileFlags(pos) + local tt=dfhack.maps.getTileType(pos) + if tt then + local shape=tile_attrs[tt].shape + local t2=dfhack.maps.getTileFlags(pos2) + if (t1 and t1.liquid_type and t1.flow_size>0) or + (shape==df.tiletype_shape.EMPTY and t2 and t2.liquid_type and t2.flow_size>0) then + --self:placeLight({x=i,y=j},5,{r=0.8,g=0.2,b=0.2}) + self:placeLightFov({x=i,y=j},5,{r=0.8,g=0.2,b=0.2},nil) + end + end + end + end end function LightOverlay:calculateLightSun() - local vp=self:getViewport() - local map = self.df_layout.map - for i=map.x1,map.x2+1 do - for j=map.y1,map.y2+1 do - local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z} - - local t1=dfhack.maps.getTileFlags(pos) - - if (t1 and t1.outside ) then - - self:placeLightFov({x=i,y=j},15,{r=1,g=1,b=1},nil) - end - end - end + local vp=self:getViewport() + local map = self.df_layout.map + for i=map.x1,map.x2+1 do + for j=map.y1,map.y2+1 do + local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z} + + local t1=dfhack.maps.getTileFlags(pos) + + if (t1 and t1.outside ) then + + self:placeLightFov({x=i,y=j},15,{r=1,g=1,b=1},nil) + end + end + end end function LightOverlay:calculateLightCursor() - local c=getCursorPos() - - if c then - - local vp=self:getViewport() - local pos=vp:tileToScreen(c) - --self:placeLight(pos,11,{r=0.96,g=0.84,b=0.03}) - self:placeLightFov({x=pos.x+1,y=pos.y+1},11,{r=0.96,g=0.84,b=0.03}) - - end + local c=getCursorPos() + + if c then + + local vp=self:getViewport() + local pos=vp:tileToScreen(c) + --self:placeLight(pos,11,{r=0.96,g=0.84,b=0.03}) + self:placeLightFov({x=pos.x+1,y=pos.y+1},11,{r=0.96,g=0.84,b=0.03}) + + end end function LightOverlay:buildOcupancy() - self.ocupancy={} - local vp=self:getViewport() - local map = self.df_layout.map - for i=map.x1,map.x2+1 do - for j=map.y1,map.y2+1 do - local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z} - local tile=i+j*map.width - local tt=dfhack.maps.getTileType(pos) - local t1=dfhack.maps.getTileFlags(pos) - if tt then - local shape=tile_attrs[tt].shape - if not lightPassable(shape) then - self.ocupancy[tile]={r=0,g=0,b=0} - else - if t1 and not t1.liquid_type and t1.flow_size>2 then - self.ocupancy[tile]={r=0.5,g=0.5,b=0.7} - else - self.ocupancy[tile]={r=0.8,g=0.8,b=0.8} - end - end - end - end - end + self.ocupancy={} + local vp=self:getViewport() + local map = self.df_layout.map + for i=map.x1,map.x2+1 do + for j=map.y1,map.y2+1 do + local pos={x=i+vp.x1-1,y=j+vp.y1-1,z=vp.z} + local tile=i+j*map.width + local tt=dfhack.maps.getTileType(pos) + local t1=dfhack.maps.getTileFlags(pos) + if tt then + local shape=tile_attrs[tt].shape + if not lightPassable(shape) then + self.ocupancy[tile]={r=0,g=0,b=0} + else + if t1 and not t1.liquid_type and t1.flow_size>2 then + self.ocupancy[tile]={r=0.5,g=0.5,b=0.7} + else + self.ocupancy[tile]={r=0.8,g=0.8,b=0.8} + end + end + end + end + end end function LightOverlay:changed() - if self.dirty or self.tick~=df.global.cur_year_tick_advmode then - self.dirty=false - self.tick=df.global.cur_year_tick_advmode - return true - end - return false + if self.dirty or self.tick~=df.global.cur_year_tick_advmode then + self.dirty=false + self.tick=df.global.cur_year_tick_advmode + return true + end + return false end function LightOverlay:makeLightMap() - if not self:changed() then - return - end - self.fovs={} - self.precalc={} - self.lightMap={} - - self:buildOcupancy() - self:calculateLightCursor() - self:calculateLightLava() - self:calculateLightSun() - - self:calculateFovs() + if not self:changed() then + return + end + self.fovs={} + self.precalc={} + self.lightMap={} + + self:buildOcupancy() + self:calculateLightCursor() + self:calculateLightLava() + self:calculateLightSun() + + self:calculateFovs() end function LightOverlay:onIdle() - self._native.parent:logic() + self._native.parent:logic() end function LightOverlay:render(dc) - if self.dynamic then - self:makeLightMap() - end - self:renderParent() - local vp=self:getViewport() - local map = self.df_layout.map - - self.lightMap=self.lightMap or {} - render.lockGrids() - render.invalidate({x=map.x1,y=map.y1,w=map.width,h=map.height}) - render.resetGrids() - for i=map.x1,map.x2 do - for j=map.y1,map.y2 do - local v=self.lightMap[i+j*map.width] - if v then - setCell(i,j,{fm=v,bm=v}) - else - local dimRgb={r=levelDim,g=levelDim,b=levelDim} - setCell(i,j,{fm=dimRgb,bm=dimRgb}) - end - end - end - render.unlockGrids() - + if self.dynamic then + self:makeLightMap() + end + self:renderParent() + local vp=self:getViewport() + local map = self.df_layout.map + + self.lightMap=self.lightMap or {} + render.lockGrids() + render.invalidate({x=map.x1,y=map.y1,w=map.width,h=map.height}) + render.resetGrids() + for i=map.x1,map.x2 do + for j=map.y1,map.y2 do + local v=self.lightMap[i+j*map.width] + if v then + setCell(i,j,{fm=v,bm=v}) + else + local dimRgb={r=levelDim,g=levelDim,b=levelDim} + setCell(i,j,{fm=dimRgb,bm=dimRgb}) + end + end + end + render.unlockGrids() + end function LightOverlay:onDismiss() - render.lockGrids() - render.resetGrids() - render.invalidate() - render.unlockGrids() - + render.lockGrids() + render.resetGrids() + render.invalidate() + render.unlockGrids() + end function LightOverlay:onInput(keys) - if keys.STRING_A096 then - self:dismiss() - else - self:sendInputToParent(keys) - - if keys.CHANGETAB then - self:updateLayout() - end - if keys.STRING_A126 and not self.dynamic then - self:makeLightMap() - end - self.dirty=true - end + if keys.STRING_A096 then + self:dismiss() + else + self:sendInputToParent(keys) + + if keys.CHANGETAB then + self:updateLayout() + end + if keys.STRING_A126 and not self.dynamic then + self:makeLightMap() + end + self.dirty=true + end end if not render.isEnabled() then - qerror("Lua rendermode not enabled!") + qerror("Lua rendermode not enabled!") end local dyn=true if #args>0 and args[1]=="static" then dyn=false end diff --git a/devel/scanitemother.rb b/devel/scanitemother.rb index e026f926b3..00b093a28c 100644 --- a/devel/scanitemother.rb +++ b/devel/scanitemother.rb @@ -6,5 +6,5 @@ o = df.world.items.other # discard ANY/BAD o._indexenum::ENUM.sort.transpose[1][1..-2].each { |k| - puts k if o[k].find { |i| i == tg } + puts k if o[k].find { |i| i == tg } } diff --git a/devel/spawn-unit-helper.rb b/devel/spawn-unit-helper.rb index 999fe7e456..a7d4f610d1 100644 --- a/devel/spawn-unit-helper.rb +++ b/devel/spawn-unit-helper.rb @@ -4,10 +4,10 @@ df.world.arena_spawn.caste.clear df.world.raws.creatures.all.length.times { |r_idx| - df.world.raws.creatures.all[r_idx].caste.length.times { |c_idx| - df.world.arena_spawn.race << r_idx - df.world.arena_spawn.caste << c_idx - } + df.world.raws.creatures.all[r_idx].caste.length.times { |c_idx| + df.world.arena_spawn.race << r_idx + df.world.arena_spawn.caste << c_idx + } } df.world.arena_spawn.creature_cnt[df.world.arena_spawn.race.length-1] = 0 diff --git a/digfort.rb b/digfort.rb index 0d41649b31..c129575009 100644 --- a/digfort.rb +++ b/digfort.rb @@ -1,65 +1,65 @@ -# designate an area for digging according to a plan in csv format - -fname = $script_args[0].to_s - -if not $script_args[0] then - puts " Usage: digfort " - throw :script_finished -end -if not fname[-4..-1] == ".csv" then - puts " The plan file must be in .csv format." - throw :script_finished -end -if not File.file?(fname) then - puts " The specified file does not exist." - throw :script_finished -end - -planfile = File.read(fname) - -if df.cursor.x == -30000 - puts "place the game cursor to the top-left corner of the design and retry" - throw :script_finished -end - -offset = [0, 0] -tiles = [] -planfile.each_line { |l| - if l =~ /#.*start\s*\(\s*(-?\d+)\s*[,;]\s*(-?\d+)/ - raise "Error: multiple start() comments" if offset != [0, 0] - offset = [$1.to_i, $2.to_i] - end - - l = l.chomp.sub(/#.*/, '') - next if l == '' - tiles << l.split(/[;,]/).map { |t| - t = t.strip - (t[0] == ?") ? t[1..-2] : t - } -} - -x = df.cursor.x - offset[0] -y = df.cursor.y - offset[1] -z = df.cursor.z - -tiles.each { |line| - next if line.empty? or line == [''] - line.each { |tile| - t = df.map_tile_at(x, y, z) - s = t.shape_basic - case tile - when 'd'; t.dig(:Default) if s == :Wall - when 'u'; t.dig(:UpStair) if s == :Wall - when 'j'; t.dig(:DownStair) if s == :Wall or s == :Floor - when 'i'; t.dig(:UpDownStair) if s == :Wall - when 'h'; t.dig(:Channel) if s == :Wall or s == :Floor - when 'r'; t.dig(:Ramp) if s == :Wall - when 'x'; t.dig(:No) - end - x += 1 - } - x = df.cursor.x - offset[0] - y += 1 -} - -puts ' done' +# designate an area for digging according to a plan in csv format + +fname = $script_args[0].to_s + +if not $script_args[0] then + puts " Usage: digfort " + throw :script_finished +end +if not fname[-4..-1] == ".csv" then + puts " The plan file must be in .csv format." + throw :script_finished +end +if not File.file?(fname) then + puts " The specified file does not exist." + throw :script_finished +end + +planfile = File.read(fname) + +if df.cursor.x == -30000 + puts "place the game cursor to the top-left corner of the design and retry" + throw :script_finished +end + +offset = [0, 0] +tiles = [] +planfile.each_line { |l| + if l =~ /#.*start\s*\(\s*(-?\d+)\s*[,;]\s*(-?\d+)/ + raise "Error: multiple start() comments" if offset != [0, 0] + offset = [$1.to_i, $2.to_i] + end + + l = l.chomp.sub(/#.*/, '') + next if l == '' + tiles << l.split(/[;,]/).map { |t| + t = t.strip + (t[0] == ?") ? t[1..-2] : t + } +} + +x = df.cursor.x - offset[0] +y = df.cursor.y - offset[1] +z = df.cursor.z + +tiles.each { |line| + next if line.empty? or line == [''] + line.each { |tile| + t = df.map_tile_at(x, y, z) + s = t.shape_basic + case tile + when 'd'; t.dig(:Default) if s == :Wall + when 'u'; t.dig(:UpStair) if s == :Wall + when 'j'; t.dig(:DownStair) if s == :Wall or s == :Floor + when 'i'; t.dig(:UpDownStair) if s == :Wall + when 'h'; t.dig(:Channel) if s == :Wall or s == :Floor + when 'r'; t.dig(:Ramp) if s == :Wall + when 'x'; t.dig(:No) + end + x += 1 + } + x = df.cursor.x - offset[0] + y += 1 +} + +puts ' done' diff --git a/drain-aquifer.lua b/drain-aquifer.lua index 0c153acaf7..4f7fd1616d 100644 --- a/drain-aquifer.lua +++ b/drain-aquifer.lua @@ -9,7 +9,7 @@ local function drain() if block.flags.has_aquifer then block.flags.has_aquifer = false block.flags.check_aquifer = false - + for x, row in ipairs(block.designation) do for y, tile in ipairs(row) do if tile.water_table then @@ -18,7 +18,7 @@ local function drain() end end end - + if not layers[block.map_pos.z] then layers[block.map_pos.z] = true layer_count = layer_count + 1 diff --git a/exterminate.rb b/exterminate.rb index 5dfc36a967..b2625428f9 100644 --- a/exterminate.rb +++ b/exterminate.rb @@ -1,151 +1,151 @@ -# exterminate creatures - -# race = name of the race to eradicate, use 'him' to target only the selected creature -# use 'undead' to target all undeads -race = $script_args[0] - -# if the 2nd parameter is 'magma', magma rain for the targets instead of instant death -# if it is 'butcher' mark all units for butchering (wont work with hostiles) -kill_by = $script_args[1] - -case kill_by -when 'magma' - slain = 'burning' -when 'slaughter', 'butcher' - slain = 'marked for butcher' -when nil - slain = 'slain' -else - race = 'help' -end - -checkunit = lambda { |u| - (u.body.blood_count != 0 or u.body.blood_max == 0) and - not u.flags1.dead and - not u.flags1.caged and not u.flags1.chained and - #not u.flags1.hidden_in_ambush and - not df.map_designation_at(u).hidden -} - -slayit = lambda { |u| - case kill_by - when 'magma' - # it's getting hot around here - # !!WARNING!! do not call on a magma-safe creature - ouh = df.onupdate_register("exterminate ensure #{u.id}", 1) { - if u.flags1.dead - df.onupdate_unregister(ouh) - else - x, y, z = u.pos.x, u.pos.y, u.pos.z - z += 1 while tile = df.map_tile_at(x, y, z+1) and - tile.shape_passableflow and tile.shape_passablelow - df.map_tile_at(x, y, z).spawn_magma(7) - end - } - when 'butcher', 'slaughter' - # mark for slaughter at butcher's shop - u.flags2.slaughter = true - else - # just make them drop dead - u.body.blood_count = 0 - # some races dont mind having no blood, ensure they are still taken care of. - u.animal.vanish_countdown = 2 - end -} - -all_races = Hash.new(0) - -df.world.units.active.map { |u| - if checkunit[u] - if (u.enemy.undead or - (u.curse.add_tags1.OPPOSED_TO_LIFE and not - u.curse.rem_tags1.OPPOSED_TO_LIFE)) - all_races['Undead'] += 1 - else - all_races[u.race_tg.creature_id] += 1 - end - end -} - -case race -when nil - all_races.sort_by { |race, cnt| [cnt, race] }.each{ |race, cnt| puts " #{race} #{cnt}" } - -when 'help', '?' - puts < i2 - links.delete_at i2 - links.delete_at i1 - links << DFHack::HistfigEntityLinkMemberst.cpp_new(:entity_id => df.ui.civ_id, :link_strength => 100) - df.add_announcement "fixloyalty: #{unit.name} is now a member of #{df.ui.civ_tg.name} again" - end - - # check if the unit is a group renegade - if i1 = links.index { |l| - l.kind_of?(DFHack::HistfigEntityLinkFormerMemberst) and - l.entity_id == df.ui.group_id - } and i2 = links.index { |l| - l.kind_of?(DFHack::HistfigEntityLinkEnemyst) and - l.entity_id == df.ui.group_id - } - fixed = true - i1, i2 = i2, i1 if i1 > i2 - links.delete_at i2 - links.delete_at i1 - links << DFHack::HistfigEntityLinkMemberst.cpp_new(:entity_id => df.ui.group_id, :link_strength => 100) - df.add_announcement "fixloyalty: #{unit.name} is now a member of #{df.ui.group_tg.name} again" - end - - # fix the 'is an enemy' cache matrix (mark to be recalculated by the game when needed) - if fixed and unit.enemy.enemy_status_slot != -1 - i = unit.enemy.enemy_status_slot - unit.enemy.enemy_status_slot = -1 - cache = df.world.enemy_status_cache - cache.slot_used[i] = false - cache.rel_map[i].map! { -1 } - cache.rel_map.each { |a| a[i] = -1 } - cache.next_slot = i if cache.next_slot > i - end - - # return true if we actually fixed the unit - fixed -end - -count = 0 -df.unit_citizens.each { |u| - count += 1 if fixunit(u) -} - -if count > 0 - puts "loyalty cascade fixed (#{count} dwarves)" -else - puts "no loyalty cascade found" -end +# script to fix loyalty cascade, when you order your militia to kill friendly units + +def fixunit(unit) + return if unit.race != df.ui.race_id or unit.civ_id != df.ui.civ_id + links = unit.hist_figure_tg.entity_links + fixed = false + + # check if the unit is a civ renegade + if i1 = links.index { |l| + l.kind_of?(DFHack::HistfigEntityLinkFormerMemberst) and + l.entity_id == df.ui.civ_id + } and i2 = links.index { |l| + l.kind_of?(DFHack::HistfigEntityLinkEnemyst) and + l.entity_id == df.ui.civ_id + } + fixed = true + i1, i2 = i2, i1 if i1 > i2 + links.delete_at i2 + links.delete_at i1 + links << DFHack::HistfigEntityLinkMemberst.cpp_new(:entity_id => df.ui.civ_id, :link_strength => 100) + df.add_announcement "fixloyalty: #{unit.name} is now a member of #{df.ui.civ_tg.name} again" + end + + # check if the unit is a group renegade + if i1 = links.index { |l| + l.kind_of?(DFHack::HistfigEntityLinkFormerMemberst) and + l.entity_id == df.ui.group_id + } and i2 = links.index { |l| + l.kind_of?(DFHack::HistfigEntityLinkEnemyst) and + l.entity_id == df.ui.group_id + } + fixed = true + i1, i2 = i2, i1 if i1 > i2 + links.delete_at i2 + links.delete_at i1 + links << DFHack::HistfigEntityLinkMemberst.cpp_new(:entity_id => df.ui.group_id, :link_strength => 100) + df.add_announcement "fixloyalty: #{unit.name} is now a member of #{df.ui.group_tg.name} again" + end + + # fix the 'is an enemy' cache matrix (mark to be recalculated by the game when needed) + if fixed and unit.enemy.enemy_status_slot != -1 + i = unit.enemy.enemy_status_slot + unit.enemy.enemy_status_slot = -1 + cache = df.world.enemy_status_cache + cache.slot_used[i] = false + cache.rel_map[i].map! { -1 } + cache.rel_map.each { |a| a[i] = -1 } + cache.next_slot = i if cache.next_slot > i + end + + # return true if we actually fixed the unit + fixed +end + +count = 0 +df.unit_citizens.each { |u| + count += 1 if fixunit(u) +} + +if count > 0 + puts "loyalty cascade fixed (#{count} dwarves)" +else + puts "no loyalty cascade found" +end diff --git a/fix/stuckdoors.rb b/fix/stuckdoors.rb index 5c4adada18..249ed58102 100644 --- a/fix/stuckdoors.rb +++ b/fix/stuckdoors.rb @@ -1,25 +1,25 @@ -# fix doors that are frozen in 'open' state - -# this may happen after people mess with the game by (incorrectly) teleporting units or items -# a door may stick open if the map occupancy flags are wrong - -count = 0 -df.world.buildings.all.each { |bld| - # for all doors - next if bld._rtti_classname != :building_doorst - # check if it is open - next if bld.close_timer == 0 - # check if occupancy is set - occ = df.map_occupancy_at(bld.x1, bld.y1, bld.z) - if (occ.unit or occ.unit_grounded) and not - # check if an unit is present - df.world.units.active.find { |u| u.pos.x == bld.x1 and u.pos.y == bld.y1 and u.pos.z == bld.z } - count += 1 - occ.unit = occ.unit_grounded = false - end - if occ.item and not df.world.items.all.find { |i| i.pos.x == bld.x1 and i.pos.y == bld.y1 and i.pos.z == bld.z } - count += 1 - occ.item = false - end -} -puts "unstuck #{count} doors" +# fix doors that are frozen in 'open' state + +# this may happen after people mess with the game by (incorrectly) teleporting units or items +# a door may stick open if the map occupancy flags are wrong + +count = 0 +df.world.buildings.all.each { |bld| + # for all doors + next if bld._rtti_classname != :building_doorst + # check if it is open + next if bld.close_timer == 0 + # check if occupancy is set + occ = df.map_occupancy_at(bld.x1, bld.y1, bld.z) + if (occ.unit or occ.unit_grounded) and not + # check if an unit is present + df.world.units.active.find { |u| u.pos.x == bld.x1 and u.pos.y == bld.y1 and u.pos.z == bld.z } + count += 1 + occ.unit = occ.unit_grounded = false + end + if occ.item and not df.world.items.all.find { |i| i.pos.x == bld.x1 and i.pos.y == bld.y1 and i.pos.z == bld.z } + count += 1 + occ.item = false + end +} +puts "unstuck #{count} doors" diff --git a/forum-dwarves.lua b/forum-dwarves.lua index 805d8586a7..eb12b3baed 100644 --- a/forum-dwarves.lua +++ b/forum-dwarves.lua @@ -8,35 +8,35 @@ local args = {...} if args[1] == 'help' then print([[ description: - This script will attempt to read the current df-screen, and if it is a - text-viewscreen (such as the dwarf 'thoughts' screen or an item - 'description') then append a marked-up version of this text to the - target file. Previous entries in the file are not overwritten, so you - may use the 'forumdwarves' command multiple times to create a single - document containing the text from multiple screens (eg: text screens - from several dwarves, or text screens from multiple artifacts/items, + This script will attempt to read the current df-screen, and if it is a + text-viewscreen (such as the dwarf 'thoughts' screen or an item + 'description') then append a marked-up version of this text to the + target file. Previous entries in the file are not overwritten, so you + may use the 'forumdwarves' command multiple times to create a single + document containing the text from multiple screens (eg: text screens + from several dwarves, or text screens from multiple artifacts/items, or some combination). known screens: - The screens which have been tested and known to function properly with + The screens which have been tested and known to function properly with this script are: 1: dwarf/unit 'thoughts' screen 2: item/art 'description' screen 3: individual 'historical item/figure' screens - There may be other screens to which the script applies. It should be - safe to attempt running the script with any screen active, with an + There may be other screens to which the script applies. It should be + safe to attempt running the script with any screen active, with an error message to inform you when the selected screen is not appropriate for this script. target file: The target file's name is 'forumdwarves.txt'. A remider to this effect will be displayed if the script is successful. character encoding: - The text will likely be using system-default encoding, and as such - will likely NOT display special characters (eg:È,ı,Ã) correctly. To - fix this, you need to modify the character set that you are reading - the document with. 'Notepad++' is a freely available program which + The text will likely be using system-default encoding, and as such + will likely NOT display special characters (eg:È,ı,Ã) correctly. To + fix this, you need to modify the character set that you are reading + the document with. 'Notepad++' is a freely available program which can do this using the following steps: 1: open the document in Notepad++ - 2: in the menu-bar, select + 2: in the menu-bar, select Encoding->Character Sets->Western European->OEM-US 3: copy the text normally to wherever you want to use it ]]) @@ -69,32 +69,32 @@ local flerb = dfhack.gui.getFocusString(scrn) local function format_for_forum(strin) local strout = strin - + local newline_idx = string.find(strout, '[P]', 1, true) while newline_idx ~= nil do strout = string.sub(strout,1, newline_idx-1)..'\n'..string.sub(strout,newline_idx+3) newline_idx = string.find(strout, '[P]', 1, true) end - + newline_idx = string.find(strout, '[B]', 1, true) while newline_idx ~= nil do strout = string.sub(strout,1, newline_idx-1)..'\n'..string.sub(strout,newline_idx+3) newline_idx = string.find(strout, '[B]', 1, true) end - + newline_idx = string.find(strout, '[R]', 1, true) while newline_idx ~= nil do strout = string.sub(strout,1, newline_idx-1)..'\n'..string.sub(strout,newline_idx+3) newline_idx = string.find(strout, '[R]', 1, true) end - + local color_idx = string.find(strout, '[C:', 1, true) while color_idx ~= nil do local colormatch = (string.byte(strout, color_idx+3)-48)+((string.byte(strout, color_idx+7)-48)*8) strout = string.sub(strout,1, color_idx-1)..'[/color][color='..colors_css[colormatch]..']'..string.sub(strout,color_idx+9) color_idx = string.find(strout, '[C:', 1, true) end - + return strout end @@ -103,7 +103,7 @@ if flerb == 'textviewer' then printall(scrn) local lines = scrn.src_text local line = "" - + if lines ~= nil then local log = io.open('forumdwarves.txt', 'a') log:write("[color=silver]") diff --git a/full-heal.lua b/full-heal.lua index 8de3f9eda0..d7267118ce 100644 --- a/full-heal.lua +++ b/full-heal.lua @@ -30,9 +30,9 @@ if args.help then end if(args.unit) then - unit = df.unit.find(args.unit) + unit = df.unit.find(args.unit) else - unit = dfhack.gui.getSelectedUnit() + unit = dfhack.gui.getSelectedUnit() end if not unit then @@ -51,7 +51,7 @@ if unit then unit.flags3.ghostly = false --unit.unk_100 = 3 end - + --print("Erasing wounds...") while #unit.body.wounds > 0 do unit.body.wounds:erase(#unit.body.wounds-1) @@ -96,7 +96,7 @@ if unit then unit.counters2.thirst_timer=0 unit.counters2.sleepiness_timer=0 unit.counters2.vomit_timeout=0 - + --print("Resetting body part status...") local v=unit.body.components for i=0,#v.nonsolid_remaining - 1,1 do @@ -111,7 +111,7 @@ if unit then v.layer_dent_fraction[i] = 0 -- 100*surface percentage of dents on the body part layer (Urist Da Vinci) v.layer_effect_fraction[i] = 0 -- 100*surface percentage of "effects" on the body part layer (Urist Da Vinci) end - + v=unit.body.components.body_part_status for i=0,#v-1,1 do v[i].on_fire = false @@ -126,7 +126,7 @@ if unit then v[i].motor_nerve_severed = false v[i].sensory_nerve_severed = false end - + if unit.job.current_job and unit.job.current_job.job_type == df.job_type.Rest then --print("Wake from rest -> clean self...") unit.job.current_job = df.job_type.CleanSelf diff --git a/gaydar.lua b/gaydar.lua index f4eb7d67f2..1aca8cdbed 100644 --- a/gaydar.lua +++ b/gaydar.lua @@ -1,5 +1,5 @@ local utils = require('utils') - + validArgs = utils.invert({ 'all', 'citizens', @@ -12,7 +12,7 @@ validArgs = utils.invert({ 'help' }) - + local args = utils.processArgs({...}, validArgs) if args.help then @@ -40,7 +40,7 @@ orientation filters: shows only creatures who are strictly straight. -asexualOnly shows only creatures who are strictly asexual. - + No argument will show the orientation of the unit under the cursor. ]]) diff --git a/growcrops.rb b/growcrops.rb index ed370030e9..c5ad717cc1 100644 --- a/growcrops.rb +++ b/growcrops.rb @@ -1,49 +1,49 @@ -# grow crops in farm plots. ex: growcrops helmet_plump 20 - -material = $script_args[0] -count_max = $script_args[1].to_i -count_max = 100 if count_max == 0 - -# cache information from the raws -@raws_plant_name ||= {} -@raws_plant_growdur ||= {} -if @raws_plant_name.empty? - df.world.raws.plants.all.each_with_index { |p, idx| - @raws_plant_name[idx] = p.id - @raws_plant_growdur[idx] = p.growdur - } -end - -inventory = Hash.new(0) -df.world.items.other[:SEEDS].each { |seed| - next if not seed.flags.in_building - next if not seed.general_refs.find { |ref| ref._rtti_classname == :general_ref_building_holderst } - next if seed.grow_counter >= @raws_plant_growdur[seed.mat_index] - inventory[seed.mat_index] += 1 -} - -if !material or material == 'help' or material == 'list' - # show a list of available crop types - inventory.sort_by { |mat, c| c }.each { |mat, c| - name = df.world.raws.plants.all[mat].id - puts " #{name} #{c}" - } - -else - - mat = df.match_rawname(material, inventory.keys.map { |k| @raws_plant_name[k] }) - unless wantmat = @raws_plant_name.index(mat) - raise "invalid plant material #{material}" - end - - count = 0 - df.world.items.other[:SEEDS].each { |seed| - next if seed.mat_index != wantmat - next if not seed.flags.in_building - next if not seed.general_refs.find { |ref| ref._rtti_classname == :general_ref_building_holderst } - next if seed.grow_counter >= @raws_plant_growdur[seed.mat_index] - seed.grow_counter = @raws_plant_growdur[seed.mat_index] - count += 1 - } - puts "Grown #{count} #{mat}" -end +# grow crops in farm plots. ex: growcrops helmet_plump 20 + +material = $script_args[0] +count_max = $script_args[1].to_i +count_max = 100 if count_max == 0 + +# cache information from the raws +@raws_plant_name ||= {} +@raws_plant_growdur ||= {} +if @raws_plant_name.empty? + df.world.raws.plants.all.each_with_index { |p, idx| + @raws_plant_name[idx] = p.id + @raws_plant_growdur[idx] = p.growdur + } +end + +inventory = Hash.new(0) +df.world.items.other[:SEEDS].each { |seed| + next if not seed.flags.in_building + next if not seed.general_refs.find { |ref| ref._rtti_classname == :general_ref_building_holderst } + next if seed.grow_counter >= @raws_plant_growdur[seed.mat_index] + inventory[seed.mat_index] += 1 +} + +if !material or material == 'help' or material == 'list' + # show a list of available crop types + inventory.sort_by { |mat, c| c }.each { |mat, c| + name = df.world.raws.plants.all[mat].id + puts " #{name} #{c}" + } + +else + + mat = df.match_rawname(material, inventory.keys.map { |k| @raws_plant_name[k] }) + unless wantmat = @raws_plant_name.index(mat) + raise "invalid plant material #{material}" + end + + count = 0 + df.world.items.other[:SEEDS].each { |seed| + next if seed.mat_index != wantmat + next if not seed.flags.in_building + next if not seed.general_refs.find { |ref| ref._rtti_classname == :general_ref_building_holderst } + next if seed.grow_counter >= @raws_plant_growdur[seed.mat_index] + seed.grow_counter = @raws_plant_growdur[seed.mat_index] + count += 1 + } + puts "Grown #{count} #{mat}" +end diff --git a/gui/advfort.lua b/gui/advfort.lua index 17aef6a42b..1c8713d021 100644 --- a/gui/advfort.lua +++ b/gui/advfort.lua @@ -30,13 +30,13 @@ prevJob={key="CUSTOM_SHIFT_R",desc="Previous job in the list"}, continue={key="A_WAIT",desc="Continue job if available"}, down_alt1={key="CUSTOM_CTRL_D",desc="Use job down"}, down_alt2={key="CURSOR_DOWN_Z_AUX",desc="Use job down"}, -up_alt1={key="CUSTOM_CTRL_E",desc="Use job up"}, +up_alt1={key="CUSTOM_CTRL_E",desc="Use job up"}, up_alt2={key="CURSOR_UP_Z_AUX",desc="Use job up"}, use_same={key="A_MOVE_SAME_SQUARE",desc="Use job at the tile you are standing"}, workshop={key="CHANGETAB",desc="Show building menu"}, } -- building filters -build_filter={ +build_filter={ forbid_all=false, --this forbits all except the "allow" allow={"MetalSmithsForge"}, --ignored if forbit_all=false forbid={} --ignored if forbit_all==true @@ -84,7 +84,7 @@ function deon_filter(name,type_id,subtype_id,custom_id, parent) else return not hasValue(race_filter.forbid,name) end - else + else if build_filter.forbid_all then return hasValue(build_filter.allow,name) else @@ -104,7 +104,7 @@ for k,v in ipairs({...}) do --setting parsing settings.df_assign=false else mode_name=v - + end end @@ -154,7 +154,7 @@ end function inSite() local tx,ty=advGlobalPos() --print(tx,ty) - + for k,v in pairs(df.global.world.world_data.sites) do local tp={v.pos.x,v.pos.y} if tx>=tp[1]*16+v.rgn_min_x and tx<=tp[1]*16+v.rgn_max_x and @@ -465,19 +465,19 @@ function chooseBuildingWidthHeightDir(args) --TODO nicer selection dialog if myneeds==nil then return end if args.width==nil and myneeds.w then --args.width=3 - dialog.showInputPrompt("Building size:", "Input building width:", nil, "1", + dialog.showInputPrompt("Building size:", "Input building width:", nil, "1", function(txt) args.width=tonumber(txt);BuildingChosen(args) end) return true end if args.height==nil and myneeds.h then --args.height=4 - dialog.showInputPrompt("Building size:", "Input building height:", nil, "1", + dialog.showInputPrompt("Building size:", "Input building height:", nil, "1", function(txt) args.height=tonumber(txt);BuildingChosen(args) end) return true end if args.direction==nil and myneeds.d then --args.direction=0--? - dialog.showInputPrompt("Building size:", "Input building direction:", nil, "0", + dialog.showInputPrompt("Building size:", "Input building direction:", nil, "0", function(txt) args.direction=tonumber(txt);BuildingChosen(args) end) return true end @@ -487,7 +487,7 @@ end CheckAndFinishBuilding=nil function BuildingChosen(inp_args,type_id,subtype_id,custom_id) local args=inp_args or {} - + args.type=type_id or args.type args.subtype=subtype_id or args.subtype args.custom=custom_id or args.custom_id @@ -497,9 +497,9 @@ function BuildingChosen(inp_args,type_id,subtype_id,custom_id) last_building.type=args.type last_building.subtype=args.subtype last_building.custom=args.custom - + if chooseBuildingWidthHeightDir(args) then - + return end --if settings.build_by_items then @@ -530,7 +530,7 @@ function isSuitableItem(job_item,item) --todo butcher test if job_item.item_type~=-1 then if item:getType()~= job_item.item_type then - + return false, "type" elseif job_item.item_subtype~=-1 then if item:getSubtype()~=job_item.item_subtype then @@ -538,7 +538,7 @@ function isSuitableItem(job_item,item) end end end - + if job_item.mat_type~=-1 then if item:getActualMaterial()~= job_item.mat_type then --unless we would want to make hist-fig specific reactions return false, "material" @@ -580,7 +580,7 @@ function isSuitableItem(job_item,item) print(v) end --]] - + return false,"matinfo" end -- some bonus checks: @@ -748,10 +748,10 @@ function AssignJobItems(args) local used_item_id={} for job_id, trg_job_item in ipairs(job.job_items) do item_suitability[job_id]={} - - for _,cur_item in pairs(its) do + + for _,cur_item in pairs(its) do if not used_item_id[cur_item.id] then - + local item_suitable,msg=isSuitableItem(trg_job_item,cur_item) if item_suitable or settings.build_by_items then table.insert(item_suitability[job_id],cur_item) @@ -787,7 +787,7 @@ function AssignJobItems(args) else print("Failed job, i'm confused...") end - + --end) return false,"Selecting items" else @@ -803,7 +803,7 @@ function AssignJobItems(args) return true end - + end @@ -815,7 +815,7 @@ CheckAndFinishBuilding=function (args,bld) break end end - + if args.job~=nil then args.pre_actions={AssignJobItems} else @@ -849,9 +849,9 @@ function BuildLast(args) return true end function CancelJob(unit) - local c_job=unit.job.current_job + local c_job=unit.job.current_job if c_job then - unit.job.current_job =nil --todo add real cancelation + unit.job.current_job =nil --todo add real cancelation for k,v in pairs(c_job.general_refs) do if df.general_ref_unit_workerst:is_instance(v) then v:delete() @@ -862,7 +862,7 @@ function CancelJob(unit) end end function ContinueJob(unit) - local c_job=unit.job.current_job + local c_job=unit.job.current_job --no job to continue if not c_job then return end --reset suspends... @@ -883,7 +883,7 @@ actions={ {"DetailWall" ,df.job_type.DetailWall,{IsWall,IsHardMaterial}}, {"DetailFloor" ,df.job_type.DetailFloor,{IsFloor,IsHardMaterial,SameSquare}}, {"CarveTrack" ,df.job_type.CarveTrack,{IsFloor,IsHardMaterial} - ,{SetCarveDir}}, + ,{SetCarveDir}}, {"Dig" ,df.job_type.Dig,{MakePredicateWieldsItem(df.job_skill.MINING),IsWall}}, {"CarveUpwardStaircase" ,df.job_type.CarveUpwardStaircase,{MakePredicateWieldsItem(df.job_skill.MINING),IsWall}}, {"CarveDownwardStaircase",df.job_type.CarveDownwardStaircase,{MakePredicateWieldsItem(df.job_skill.MINING)}}, @@ -894,7 +894,7 @@ actions={ {"Fish" ,df.job_type.Fish,{IsWater}}, --{"Diagnose Patient" ,df.job_type.DiagnosePatient,{IsUnit},{SetPatientRef}}, --{"Surgery" ,df.job_type.Surgery,{IsUnit},{SetPatientRef}}, - {"TameAnimal" ,df.job_type.TameAnimal,{IsUnit},{SetCreatureRef}}, + {"TameAnimal" ,df.job_type.TameAnimal,{IsUnit},{SetCreatureRef}}, {"GatherPlants" ,df.job_type.GatherPlants,{IsPlant,SameSquare}}, {"RemoveConstruction" ,df.job_type.RemoveConstruction,{IsConstruct}}, {"RemoveBuilding" ,RemoveBuilding,{IsBuilding}}, @@ -904,7 +904,7 @@ actions={ {"BuildLast" ,BuildLast,{NoConstructedBuilding}}, {"Clean" ,df.job_type.Clean,{}}, {"GatherWebs" ,df.job_type.CollectWebs,{--[[HasWeb]]},{SetWebRef}}, - + } for id,action in pairs(actions) do @@ -922,7 +922,7 @@ function usetool:getModeName() else return actions[(mode or 0)+1][1] or " " end - + end function usetool:init(args) @@ -933,7 +933,7 @@ function usetool:init(args) text={{key=keybinds.prevJob.key},{gap=1,text=self:callback("getModeName")},{gap=1,key=keybinds.nextJob.key}, } }, - + wid.Label{ view_id="shopLabel", @@ -942,7 +942,7 @@ function usetool:init(args) text={ {id="text1",gap=1,key=keybinds.workshop.key,key_sep="()", text="Workshop menu",pen=dfhack.pen.parse{fg=COLOR_YELLOW,bg=0}}} }, - + wid.Label{ view_id="siteLabel", frame = {t=1,xalign=-1,yalign=0}, @@ -1051,7 +1051,7 @@ function putItemToBuilding(building,item) end end function usetool:openPutWindow(building) - + local adv=df.global.world.units.active[0] local items=EnumItems{pos=adv.pos,unit=adv, inv={[df.unit_inventory_item.T_mode.Hauled]=true,--[df.unit_inventory_item.T_mode.Worn]=true, @@ -1106,7 +1106,7 @@ function usetool:openShopWindowButtoned(building,no_reset) --]] end building:fillSidebarMenu() - + local list={} for id,choice in pairs(wui.choices_visible) do table.insert(list,{text=utils.call_with_string(choice,"getLabel"),button=choice}) @@ -1122,7 +1122,7 @@ function usetool:openShopWindowButtoned(building,no_reset) end function usetool:openShopWindow(building) local adv=df.global.world.units.active[0] - + local filter_pile=workshopJobs.getJobs(building:getType(),building:getSubtype(),building:getCustomType()) if filter_pile then local state={unit=adv,from_pos={x=adv.pos.x,y=adv.pos.y, z=adv.pos.z},building=building @@ -1153,7 +1153,7 @@ function usetool:armCleanTrap(building) LoadStoneTrap, LoadWeaponTrap, ]] - if building.trap_type==df.trap_type.Lever then + if building.trap_type==df.trap_type.Lever then --link return end @@ -1190,7 +1190,7 @@ function usetool:hiveActions(building) --CollectHiveProducts, end function usetool:operatePump(building) - + local adv=df.global.world.units.active[0] makeJob{unit=adv,post_actions={AssignBuildingRef},pos=adv.pos,from_pos=adv.pos,job_type=df.job_type.OperatePump,screen=self} end @@ -1205,7 +1205,7 @@ function usetool:farmPlot(building) end end --check if there tile is without plantseeds,add job - + local args={unit=adv,pos=adv.pos,from_pos=adv.pos,screen=self} if do_harvest then args.job_type=df.job_type.HarvestPlants @@ -1294,7 +1294,7 @@ MODES={ input=usetool.chairActions, }, } -function usetool:shopMode(enable,mode,building) +function usetool:shopMode(enable,mode,building) self.subviews.shopLabel.visible=enable if mode then self.subviews.shopLabel:itemById("text1").text=mode.name @@ -1349,7 +1349,7 @@ function usetool:fieldInput(keys) break end end - + for _,p in pairs(cur_mode[3] or {}) do local ok,msg=p(state) if ok==false then @@ -1357,7 +1357,7 @@ function usetool:fieldInput(keys) failed=true end end - + if not failed then local ok,msg if type(cur_mode[2])=="function" then @@ -1365,9 +1365,9 @@ function usetool:fieldInput(keys) else makeJob(state) --(adv,moddedpos(adv.pos,MOVEMENT_KEYS[code]),cur_mode[2],adv.pos,cur_mode[4]) - + end - + if code=="SELECT" then self:sendInputToParent("LEAVESCREEN") end @@ -1381,11 +1381,11 @@ function usetool:fieldInput(keys) end end end - + end function usetool:onInput(keys) local adv=df.global.world.units.active[0] - + if keys.LEAVESCREEN then if df.global.cursor.x~=-30000 then self:sendInputToParent("LEAVESCREEN") @@ -1412,13 +1412,13 @@ function usetool:onInput(keys) if keys[keybinds.workshop.key] then self.mode.input(self,self.building) end - self:fieldInput(keys) + self:fieldInput(keys) else self:fieldInput(keys) end end local site=inSite() - + if site then self.subviews.siteLabel.visible=true self.subviews.siteLabel:itemById("site").text=dfhack.TranslateName(site.name) diff --git a/gui/advfort_items.lua b/gui/advfort_items.lua index e44e3857af..39a10367cf 100644 --- a/gui/advfort_items.lua +++ b/gui/advfort_items.lua @@ -23,7 +23,7 @@ function update_slot_text(slot) items=items.."," end end - + slot.text=string.format("%02d. Filled(%d/%d):%s",slot.id+1,slot.filled_amount,slot.job_item.quantity,items) end --items-> table => key-> id of job.job_items, value-> table => key (num), value => item(ref) @@ -31,7 +31,7 @@ function jobitemEditor:init(args) --self.job=args.job if self.job==nil then qerror("This screen must have job target") end if self.items==nil then qerror("This screen must have item list") end - + self:addviews{ wid.Label{ view_id = 'label', diff --git a/gui/companion-order.lua b/gui/companion-order.lua index 68bc7ab396..bef1e0968a 100644 --- a/gui/companion-order.lua +++ b/gui/companion-order.lua @@ -31,10 +31,10 @@ function CheckCursor(p) return true end function getxyz() -- this will return pointers x,y and z coordinates. - local x=df.global.cursor.x - local y=df.global.cursor.y - local z=df.global.cursor.z - return x,y,z -- return the coords + local x=df.global.cursor.x + local y=df.global.cursor.y + local z=df.global.cursor.z + return x,y,z -- return the coords end function GetCaste(race_id,caste_id) @@ -59,7 +59,7 @@ function ReadCurrentEquiped(body_equip,unit) local sb=v.item.subtype.props local trg=body_equip[bpid] local trg_layer=trg.layers[sb.layer] - + if trg_layer.permit==0 then trg_layer.permit=sb.layer_permit else @@ -94,7 +94,7 @@ function AddLayering(body_part,item) end function AddIfFits(body_equip,unit,item) --TODO shaped items - + local need_flag for k,v in pairs(permited_equips) do if k:is_instance(item) then @@ -106,7 +106,7 @@ function AddIfFits(body_equip,unit,item) return false end - + for k,bp in pairs(body_equip) do local handedness_ok=true if df.item_glovesst:is_instance(item) then @@ -153,7 +153,7 @@ end function GetBackpack(unit) for k,v in pairs(unit.inventory) do - + if df.item_backpackst:is_instance(v.item) then return v.item end @@ -223,7 +223,7 @@ end}, --todo make a table join function or sth... submit it to the lua list! AddBackpackItems(GetBackpack(unit),items) items=FilterByEquipable(items) - FilterBySize(items,unit.race) + FilterBySize(items,unit.race) local body_parts=EnumBodyEquipable(unit.race,unit.caste) ReadCurrentEquiped(body_parts,unit) for it_num,item in pairs(items) do @@ -239,7 +239,7 @@ end}, -- TODO sort with weapon/shield on top of list! --add to grasps, then add to backpack (sanely? i.e. weapons/shields into hands then stuff) --or add to backpack if have, only then check grasps (faster equiping) - while #grasps >0 and #items>0 do + while #grasps >0 and #items>0 do if(dfhack.items.moveToInventory(items[#items],v,1,grasps[#grasps])) then table.remove(grasps) end @@ -265,7 +265,7 @@ end}, return true end}, {name="unwield",f=function (unit_list) - + for k,v in pairs(unit_list) do local wep_count=0 for _,it in pairs(v.inventory) do @@ -279,7 +279,7 @@ end}, dfhack.items.moveToGround(it.item,v.pos) break end - end + end end end return true @@ -314,7 +314,7 @@ end}, local adv=df.global.world.units.active[0] local t_nem=dfhack.units.getNemesis(adv) for k,v in pairs(unit_list) do - + v.relations.group_leader_id=-1 local u_nem=dfhack.units.getNemesis(v) if u_nem then @@ -336,14 +336,14 @@ end}, local cheats={ {name="Patch up",f=function (unit_list) local dft=require("plugins.dfusion.tools") - for k,v in pairs(unit_list) do + for k,v in pairs(unit_list) do dft.healunit(v) - end - return true + end + return true end}, {name="Power up",f=function (unit_list) local dft=require("plugins.dfusion.tools") - for k,d in pairs(unit_list) do + for k,d in pairs(unit_list) do dft.powerup(d) end return true @@ -352,16 +352,16 @@ end}, if not CheckCursor(pos) then return false end - adv=df.global.world.units.active[0] - item=getItemsAtPos(getxyz())[1] - print(item.id) + adv=df.global.world.units.active[0] + item=getItemsAtPos(getxyz())[1] + print(item.id) for k,v in pairs(unit_list) do v.riding_item_id=item.id local ref=df.general_ref_unit_riderst:new() ref.unit_id=v.id item.general_refs:insert("#",ref) - end - return true + end + return true end}, } --[[ todo: add cheats...]]-- @@ -404,7 +404,7 @@ function CompanionUi:GetSelectedUnits() end function CompanionUi:onInput(keys) - + if keys.LEAVESCREEN then self:dismiss() elseif keys._STRING then @@ -412,13 +412,13 @@ function CompanionUi:onInput(keys) if s==string.byte('*') then local v=self.selected[1] or false for i=0,26 do - + self.selected[i]=not v end end if s>=string.byte('a') and s<=string.byte('z') then local idx=s-string.byte('a')+1 - if self.selected[idx] then + if self.selected[idx] then self.selected[idx]=false else self.selected[idx]=true diff --git a/gui/dfstatus.lua b/gui/dfstatus.lua index 0ebaa141d8..f7dc4988c3 100644 --- a/gui/dfstatus.lua +++ b/gui/dfstatus.lua @@ -30,19 +30,19 @@ function screen2:onRenderBody(dc) --local raw_fish = 0 --local plants = 0 local prepared_meals = 0 - + local fuel = 0 local pigiron = 0 local iron = 0 local steel = 0 - + local silver = 0 local copper = 0 local gold = 0 - + local tannedhides = 0 local cloth = 0 - + --print("------------------------------") for _,item in ipairs(df.global.world.items.all) do if(not item.flags.rotten and not item.flags.dump and not item.flags.forbid) then @@ -52,18 +52,18 @@ function screen2:onRenderBody(dc) if(item:getType() == df.item_type.DRINK)then --print(item:getType() .. ":" .. dfhack.items.getDescription(item,0)) end - + if (item:getType() == df.item_type.WOOD) then wood = wood + item:getStackSize() elseif (item:getType() == df.item_type.DRINK) then drink = drink + item:getStackSize() elseif (item:getType() == df.item_type.SKIN_TANNED) then tannedhides = tannedhides + item:getStackSize() elseif (item:getType() == df.item_type.CLOTH) then cloth = cloth + item:getStackSize() - --elseif (item:getType() == df.item_type.MEAT) then meat = meat + item:getStackSize() - --elseif (item:getType() == df.item_type.FISH_RAW) then raw_fish = raw_fish + item:getStackSize() - --elseif (item:getType() == df.item_type.PLANT) then plants = plants + item:getStackSize() - elseif (item:getType() == df.item_type.FOOD) then prepared_meals = prepared_meals + item:getStackSize() + --elseif (item:getType() == df.item_type.MEAT) then meat = meat + item:getStackSize() + --elseif (item:getType() == df.item_type.FISH_RAW) then raw_fish = raw_fish + item:getStackSize() + --elseif (item:getType() == df.item_type.PLANT) then plants = plants + item:getStackSize() + elseif (item:getType() == df.item_type.FOOD) then prepared_meals = prepared_meals + item:getStackSize() elseif (item:getType() == df.item_type.BAR) then for token in string.gmatch(dfhack.items.getDescription(item,0),"[^%s]+") do - if (token == "silver") then silver = silver + item:getStackSize() + if (token == "silver") then silver = silver + item:getStackSize() elseif (token == "charcoal" or token == "coke") then fuel = fuel + item:getStackSize() elseif (token == "iron") then iron = iron + item:getStackSize() elseif (token == "pig") then pigiron = pigiron + item:getStackSize() diff --git a/gui/gm-editor.lua b/gui/gm-editor.lua index 11fbdca99f..4f74051217 100644 --- a/gui/gm-editor.lua +++ b/gui/gm-editor.lua @@ -46,7 +46,7 @@ GmEditorUi = defclass(GmEditorUi, gui.FramedScreen) GmEditorUi.ATTRS={ frame_style = gui.GREY_LINE_FRAME, frame_title = "GameMaster's editor", - } + } function GmEditorUi:onHelp() self.subviews.pages:setSelected(2) end @@ -76,7 +76,7 @@ function GmEditorUi:init(args) end table.insert(helptext,NEWLINE) Disclaimer(helptext) - + local helpPage=widgets.Panel{ subviews={widgets.Label{text=helptext,frame = {l=1,t=1,yalign=0}}}} local mainList=widgets.List{view_id="list_main",choices={},frame = {l=1,t=3,yalign=0},on_submit=self:callback("editSelected"), @@ -90,7 +90,7 @@ function GmEditorUi:init(args) --widgets.Label{text="BLAH2"} } ,view_id='page_main'} - + local pages=widgets.Pages{subviews={mainPage,helpPage},view_id="pages"} self:addviews{ pages @@ -104,20 +104,20 @@ function GmEditorUi:enable_input(enable) self.subviews.filter_input.active=enable end function GmEditorUi:find(test) - local trg=self:currentTarget() - + local trg=self:currentTarget() + if test== nil then dialog.showInputPrompt("Test function","Input function that tests(k,v as argument):",COLOR_WHITE,"",dfhack.curry(self.find,self)) return end - + local e,what=load("return function(k,v) return "..test.." end") if e==nil then dialog.showMessage("Error!","function failed to compile\n"..what,COLOR_RED) end - + if trg.target and trg.target._kind and trg.target._kind=="container" then - + for k,v in pairs(trg.target) do if e()(k,v)==true then self:pushTarget(v) @@ -146,13 +146,13 @@ function GmEditorUi:insertNew(typename) dialog.showMessage("Error!","Type '"..tp.." not found",COLOR_RED) return end - - local trg=self:currentTarget() + + local trg=self:currentTarget() if trg.target and trg.target._kind and trg.target._kind=="container" then local thing=ntype:new() dfhack.call_with_finalizer(1,false,df.delete,thing,function (tscreen,target,to_insert) target:insert("#",to_insert); tscreen:updateTarget(true,true);end,self,trg.target,thing) - + end end function GmEditorUi:deleteSelected(key) @@ -186,7 +186,7 @@ function GmEditorUi:editSelectedEnum(index,choice) self:updateTarget(true) end end) - + else qerror("not an enum") end @@ -211,7 +211,7 @@ function GmEditorUi:editSelected(index,choice) if trg_type=='number' or trg_type=='string' then --ugly TODO: add metatable get selected dialog.showInputPrompt(tostring(trg_key),"Enter new value:",COLOR_WHITE, tostring(trg.target[trg_key]),self:callback("commitEdit",trg_key)) - + elseif trg_type=='boolean' then trg.target[trg_key]= not trg.target[trg_key] self:updateTarget(true) @@ -235,8 +235,8 @@ function GmEditorUi:commitEdit(key,value) end function GmEditorUi:set(key,input) - local trg=self:currentTarget() - + local trg=self:currentTarget() + if input== nil then dialog.showInputPrompt("Set to what?","Lua code to set to (v cur target):",COLOR_WHITE,"",self:callback("set",key)) return @@ -281,7 +281,7 @@ function GmEditorUi:onInput(keys) self:insertNew() elseif keys[keybindings.delete.key] then --delete self:deleteSelected(self:getSelectedKey()) - elseif keys[keybindings.reinterpret.key] then + elseif keys[keybindings.reinterpret.key] then self:openReinterpret(self:getSelectedKey()) elseif keys[keybindings.start_filter.key] then self:enable_input(true) @@ -292,7 +292,7 @@ function GmEditorUi:onInput(keys) end function getStringValue(trg,field) local obj=trg.target - + local text=tostring(obj[field]) pcall(function() if obj._field ~= nil then @@ -326,7 +326,7 @@ function GmEditorUi:updateTarget(preserve_pos,reindex) self.subviews.lbl_current_item:itemById('name').text=tostring(trg.target) local t={} for k,v in pairs(trg.keys) do - table.insert(t,{text={{text=string.format("%-25s",tostring(v))},{gap=1,text=getStringValue(trg,v)}}}) + table.insert(t,{text={{text=string.format("%-25s",tostring(v))},{gap=1,text=getStringValue(trg,v)}}}) end local last_pos if preserve_pos then diff --git a/gui/hack-wish.lua b/gui/hack-wish.lua index 19e59bb525..e3c1f374c0 100644 --- a/gui/hack-wish.lua +++ b/gui/hack-wish.lua @@ -3,7 +3,7 @@ -- author Putnam -- edited by expwnent - + function getGenderString(gender) local genderStr if gender==0 then @@ -15,7 +15,7 @@ function getGenderString(gender) end return string.char(40)..genderStr..string.char(41) end - + function getCreatureList() local crList={} for k,cr in ipairs(df.global.world.raws.creatures.alphabetic) do @@ -27,7 +27,7 @@ function getCreatureList() end return crList end - + function getMatFilter(itemtype) local itemTypes={ SEEDS=function(mat,parent,typ,idx) @@ -69,7 +69,7 @@ function getMatFilter(itemtype) } return itemTypes[df.item_type[itemtype]] or getRestrictiveMatFilter(itemtype) end - + function getRestrictiveMatFilter(itemType) if not args.restrictive then return nil end local itemTypes={ @@ -95,7 +95,7 @@ function getRestrictiveMatFilter(itemType) BAR=function(mat,parent,typ,idx) return (mat.flags.IS_METAL or mat.flags.SOAP or mat.id==COAL) end - + } for k,v in ipairs({'GOBLET','FLASK','TOY','RING','CROWN','SCEPTER','FIGURINE','TOOL'}) do itemTypes[v]=itemTypes.INSTRUMENT @@ -109,14 +109,14 @@ function getRestrictiveMatFilter(itemType) itemTypes.BOULDER=itemTypes.ROCK return itemTypes[df.item_type[itemType]] end - + function createItem(mat,itemType,quality,creator,description) - dfhack.items.createItem(itemType[1], itemType[2], mat[1], mat[2], creator) + dfhack.items.createItem(itemType[1], itemType[2], mat[1], mat[2], creator) if df.item_type[itemType[1]]=='SLAB' then item.description=description end end - + function qualityTable() return {{'None'}, {'-Well-crafted-'}, @@ -126,9 +126,9 @@ function qualityTable() {string.char(15)..'Masterwork'..string.char(15)} } end - + local script=require('gui.script') - + function showItemPrompt(text,item_filter,hide_none) require('gui.materials').ItemTypeDialog{ prompt=text, @@ -138,10 +138,10 @@ function showItemPrompt(text,item_filter,hide_none) on_cancel=script.mkresume(false), on_close=script.qresume(nil) }:show() - + return script.wait() end - + function showMaterialPrompt(title, prompt, filter, inorganic, creature, plant) --the one included with DFHack doesn't have a filter or the inorganic, creature, plant things available require('gui.materials').MaterialDialog{ frame_title = title, @@ -154,19 +154,19 @@ function showMaterialPrompt(title, prompt, filter, inorganic, creature, plant) - on_cancel = script.mkresume(false), on_close = script.qresume(nil) }:show() - + return script.wait() end - + function usesCreature(itemtype) typesThatUseCreatures={REMAINS=true,FISH=true,FISH_RAW=true,VERMIN=true,PET=true,EGG=true,CORPSE=true,CORPSEPIECE=true} return typesThatUseCreatures[df.item_type[itemtype]] end - + function getCreatureRaceAndCaste(caste) return df.global.world.raws.creatures.list_creature[caste.index],df.global.world.raws.creatures.list_caste[caste.index] end - + function hackWish(unit) script.start(function() local amountok, amount @@ -202,11 +202,11 @@ function hackWish(unit) else if mattype and itemtype then createItem({mattype,matindex},{itemtype,itemsubtype},quality,unit,description) - end + end end end) end - + scriptArgs={...} utils=require('utils') @@ -220,10 +220,10 @@ validArgs = validArgs or utils.invert({ }) args = utils.processArgs({...}, validArgs) - + eventful=require('plugins.eventful') -if not args.startup then +if not args.startup then local unit=args.unit and df.unit.find(args.unit) or dfhack.gui.getSelectedUnit(true) if unit then hackWish(unit) diff --git a/gui/mod-manager.lua b/gui/mod-manager.lua index a4f5038684..2f2aa92ba7 100644 --- a/gui/mod-manager.lua +++ b/gui/mod-manager.lua @@ -25,13 +25,13 @@ local mod_dir=dfhack.getDFPath().."/hack/mods" ]] function fileExists(filename) - local file=io.open(filename,"rb") - if file==nil then - return - else - file:close() - return true - end + local file=io.open(filename,"rb") + if file==nil then + return + else + file:close() + return true + end end if not fileExists(init_file) then local initFile=io.open(init_file,"a") @@ -47,10 +47,10 @@ function copyFile(from,to) --oh so primitive fileto:close() end function patchInit(initFileName,patch_guard,code) - local initFile=io.open(initFileName,"a") - initFile:write(string.format("\n%s\n%s\n%s",patch_guard[1], - code,patch_guard[2])) - initFile:close() + local initFile=io.open(initFileName,"a") + initFile:write(string.format("\n%s\n%s\n%s",patch_guard[1], + code,patch_guard[2])) + initFile:close() end function patchDofile( luaFileName,patch_guard,dofile_list,mod_path ) local luaFile=io.open(luaFileName,"a") @@ -64,10 +64,10 @@ function patchDofile( luaFileName,patch_guard,dofile_list,mod_path ) end function patchFile(file_name,patch_guard,after_string,code) local input_lines=patch_guard[1].."\n"..code.."\n"..patch_guard[2] - + local badchars="[%:%[%]]" local find_string=after_string:gsub(badchars,"%%%1") --escape some bad chars - + local entityFile=io.open(file_name,"r") local buf=entityFile:read("*all") entityFile:close() @@ -77,98 +77,98 @@ function patchFile(file_name,patch_guard,after_string,code) entityFile:close() end function findGuards(str,start,patch_guard) - local pStart=string.find(str,patch_guard[1],start) - if pStart==nil then return nil end - local pEnd=string.find(str,patch_guard[2],pStart) - if pEnd==nil then error("Start guard token found, but end was not found") end - return pStart-1,pEnd+#patch_guard[2]+1 + local pStart=string.find(str,patch_guard[1],start) + if pStart==nil then return nil end + local pEnd=string.find(str,patch_guard[2],pStart) + if pEnd==nil then error("Start guard token found, but end was not found") end + return pStart-1,pEnd+#patch_guard[2]+1 end function findGuardsFile(filename,patch_guard) - local file=io.open(filename,"r") - local buf=file:read("*all") - return findGuards(buf,1,patch_guard) + local file=io.open(filename,"r") + local buf=file:read("*all") + return findGuards(buf,1,patch_guard) end function unPatchFile(filename,patch_guard) - local file=io.open(filename,"r") - local buf=file:read("*all") - file:close() - - local newBuf="" - local pos=1 - local lastPos=1 - repeat - local endPos - pos,endPos=findGuards(buf,lastPos,patch_guard) - newBuf=newBuf..string.sub(buf,lastPos,pos) - if endPos~=nil then - lastPos=endPos - end - until pos==nil - - local file=io.open(filename,"w+") - file:write(newBuf) + local file=io.open(filename,"r") + local buf=file:read("*all") + file:close() + + local newBuf="" + local pos=1 + local lastPos=1 + repeat + local endPos + pos,endPos=findGuards(buf,lastPos,patch_guard) + newBuf=newBuf..string.sub(buf,lastPos,pos) + if endPos~=nil then + lastPos=endPos + end + until pos==nil + + local file=io.open(filename,"w+") + file:write(newBuf) file:close() end function checkInstalled(dfMod) --try to figure out if installed - if dfMod.checkInstalled then - return dfMod.checkInstalled() - else - if dfMod.raws_list then - for k,v in pairs(dfMod.raws_list) do - if fileExists(dfhack.getDFPath().."/raw/objects/"..v) then - return true,v - end - end - end - if dfMod.patch_entity then - if findGuardsFile(entity_file,dfMod.guard)~=nil then - return true,"entity_default.txt" - end - end + if dfMod.checkInstalled then + return dfMod.checkInstalled() + else + if dfMod.raws_list then + for k,v in pairs(dfMod.raws_list) do + if fileExists(dfhack.getDFPath().."/raw/objects/"..v) then + return true,v + end + end + end + if dfMod.patch_entity then + if findGuardsFile(entity_file,dfMod.guard)~=nil then + return true,"entity_default.txt" + end + end if dfMod.patch_files then for k,v in pairs(dfMod.patch_files) do if findGuardsFile(dfhack.getDFPath().."/raw/objects/"..v.filename,dfMod.guard)~=nil then return true,"v.filename" end end - end - if dfMod.patch_init then - if findGuardsFile(init_file,dfMod.guard_init)~=nil then - return true,"init.lua" - end - end - end + end + if dfMod.patch_init then + if findGuardsFile(init_file,dfMod.guard_init)~=nil then + return true,"init.lua" + end + end + end end manager=defclass(manager,gui.FramedScreen) function manager:init(args) self.mods={} local mods=self.mods - local mlist=dfhack.internal.getDir(mod_dir) + local mlist=dfhack.internal.getDir(mod_dir) if #mlist==0 then qerror("Mod directory not found! Are you sure it is in:"..mod_dir) end - for k,v in ipairs(mlist) do - if v~="." and v~=".." then - local f,modData=pcall(dofile,mod_dir.."/".. v .. "/init.lua") + for k,v in ipairs(mlist) do + if v~="." and v~=".." then + local f,modData=pcall(dofile,mod_dir.."/".. v .. "/init.lua") if f then mods[modData.name]=modData modData.guard=modData.guard or {">>"..modData.name.." patch","< 10 then hitCeiling = true end - if stairs == 1 and x == pos.x and y == pos.y then + if stairs == 1 and x == pos.x and y == pos.y then if block.tiletype[x%16][y%16] == 32 then - if z == pos.z then + if z == pos.z then block.tiletype[x%16][y%16] = 56 - else - block.tiletype[x%16][y%16] = 55 + else + block.tiletype[x%16][y%16] = 55 end - else - block.tiletype[x%16][y%16] = 57 + else + block.tiletype[x%16][y%16] = 57 end end end @@ -68,7 +68,7 @@ for x=pos.x-size,pos.x+size,1 do elseif x == pos.x+size and y == pos.y-size then if needsWall == true then block.tiletype[x%16][y%16]=323 end elseif x == pos.x-size or x == pos.x+size then if needsWall == true then block.tiletype[x%16][y%16]=324 end elseif y == pos.y-size or y == pos.y+size then if needsWall == true then block.tiletype[x%16][y%16]=325 end - elseif stairs == 1 and x == pos.x and y == pos.y then + elseif stairs == 1 and x == pos.x and y == pos.y then if z == pos.z then block.tiletype[x%16][y%16]=56 else block.tiletype[x%16][y%16]=55 end else block.tiletype[x%16][y%16]=32 diff --git a/lever.rb b/lever.rb index 4e2d399e5f..18e4484cde 100644 --- a/lever.rb +++ b/lever.rb @@ -1,124 +1,124 @@ -# control your levers from the dfhack console - -def lever_pull_job(bld) - ref = DFHack::GeneralRefBuildingHolderst.cpp_new - ref.building_id = bld.id - - job = DFHack::Job.cpp_new - job.job_type = :PullLever - job.pos = [bld.centerx, bld.centery, bld.z] - job.general_refs << ref - bld.jobs << job - df.job_link job - - puts lever_descr(bld) -end - -def lever_pull_cheat(bld) - bld.linked_mechanisms.each { |i| - i.general_refs.grep(DFHack::GeneralRefBuildingHolderst).each { |r| - r.building_tg.setTriggerState(bld.state) - } - } - - bld.state = (bld.state == 0 ? 1 : 0) - - puts lever_descr(bld) -end - -def lever_descr(bld, idx=nil) - ret = [] - - # lever description - descr = '' - descr << "#{idx}: " if idx - descr << "lever ##{bld.id} @[#{bld.centerx}, #{bld.centery}, #{bld.z}] #{bld.state == 0 ? '\\' : '/'}" - bld.jobs.each { |j| - if j.job_type == :PullLever - flags = '' - flags << ', repeat' if j.flags.repeat - flags << ', suspended' if j.flags.suspend - descr << " (pull order#{flags})" - end - } - - bld.linked_mechanisms.map { |i| - i.general_refs.grep(DFHack::GeneralRefBuildingHolderst) - }.flatten.each { |r| - # linked building description - tg = r.building_tg - state = '' - if tg.respond_to?(:gate_flags) - state << (tg.gate_flags.closed ? 'closed' : 'opened') - state << ", closing (#{tg.timer})" if tg.gate_flags.closing - state << ", opening (#{tg.timer})" if tg.gate_flags.opening - end - - ret << (descr + " linked to #{tg._rtti_classname} ##{tg.id} @[#{tg.centerx}, #{tg.centery}, #{tg.z}] #{state}") - - # indent other links - descr = descr.gsub(/./, ' ') - } - - ret << descr if ret.empty? - - ret -end - -def lever_list - @lever_list = [] - df.world.buildings.other[:TRAP].find_all { |bld| - bld.trap_type == :Lever - }.sort_by { |bld| bld.id }.each { |bld| - puts lever_descr(bld, @lever_list.length) - @lever_list << bld.id - } -end - - -@lever_list ||= [] - -case $script_args[0] -when 'pull' - cheat = $script_args.delete('--cheat') || $script_args.delete('--now') - - id = $script_args[1].to_i - id = @lever_list[id] || id - bld = df.building_find(id) - raise 'invalid lever id' if not bld - - if cheat - lever_pull_cheat(bld) - else - lever_pull_job(bld) - end - -when 'list' - lever_list - -when /^\d+$/ - id = $script_args[0].to_i - id = @lever_list[id] || id - bld = df.building_find(id) - raise 'invalid lever id' if not bld - - puts lever_descr(bld) - -else - - puts < 0 and bx+dx < df.world.map.x_count-1 and by+dy > 0 and by+dy < df.world.map.y_count-1 - pos = [bx+dx, by+dy, bz] - end - } - } - } - } - df.center_viewscreen(*pos) - df.map_tile_at(*pos).dig - puts "Here is some #{df.world.raws.inorganics[found_mat].id}" - else - puts "Cannot find unmined #{mats.map { |mat| df.world.raws.inorganics[mat].id }.join(', ')}" - end - -else - puts "Available ores:", $ore_veins.sort_by { |mat, pos| pos.length }.map { |mat, pos| - ore = df.world.raws.inorganics[mat] - metals = ore.metal_ore.mat_index.map { |m| df.world.raws.inorganics[m] } - ' ' + ore.id.downcase + ' (' + metals.map { |m| m.id.downcase }.join(', ') + ')' - } - -end +# scan the map for ore veins + +target_ore = $script_args[0] + +def find_all_ore_veins + puts 'scanning map...' + $ore_veins = {} + seen_mat = {} + df.each_map_block { |block| + block.block_events.grep(DFHack::BlockSquareEventMineralst).each { |vein| + mat_index = vein.inorganic_mat + if not seen_mat[mat_index] or $ore_veins[mat_index] + seen_mat[mat_index] = true + if df.world.raws.inorganics[mat_index].flags[:METAL_ORE] + $ore_veins[mat_index] ||= [] + $ore_veins[mat_index] << [block.map_pos.x, block.map_pos.y, block.map_pos.z] + end + end + } + } + + df.onstatechange_register_once { |st| + if st == :MAP_LOADED + $ore_veins = nil # invalidate veins cache + true + end + } + + $ore_veins +end + +$ore_veins ||= find_all_ore_veins + +if not target_ore or target_ore == 'help' + puts < 0 and bx+dx < df.world.map.x_count-1 and by+dy > 0 and by+dy < df.world.map.y_count-1 + pos = [bx+dx, by+dy, bz] + end + } + } + } + } + df.center_viewscreen(*pos) + df.map_tile_at(*pos).dig + puts "Here is some #{df.world.raws.inorganics[found_mat].id}" + else + puts "Cannot find unmined #{mats.map { |mat| df.world.raws.inorganics[mat].id }.join(', ')}" + end + +else + puts "Available ores:", $ore_veins.sort_by { |mat, pos| pos.length }.map { |mat, pos| + ore = df.world.raws.inorganics[mat] + metals = ore.metal_ore.mat_index.map { |m| df.world.raws.inorganics[m] } + ' ' + ore.id.downcase + ' (' + metals.map { |m| m.id.downcase }.join(', ') + ')' + } + +end diff --git a/log-region.lua b/log-region.lua index 2da2da7739..31cdaf7824 100644 --- a/log-region.lua +++ b/log-region.lua @@ -29,7 +29,7 @@ else --site.name --fort_ent.name --civ_ent.name - + write_gamelog('Loaded '..world.cur_savegame.save_dir..', '..fullname(world.world_data).. ' at coordinates ('..site.pos.x..','..site.pos.y..')'..NEWLINE.. 'Loaded the fortress '..fullname(site).. diff --git a/make-monarch.lua b/make-monarch.lua index 2531796806..967225589e 100644 --- a/make-monarch.lua +++ b/make-monarch.lua @@ -17,7 +17,7 @@ for pos_id,v in pairs(my_entity.positions.assignments) do old_id=v.histfig v.histfig=newfig.id local oldfig=df.historical_figure.find(old_id) - + for k,v in pairs(oldfig.entity_links) do if df.histfig_entity_link_positionst:is_instance(v) and v.assignment_id==pos_id and v.entity_id==df.global.ui.civ_id then oldfig.entity_links:erase(k) diff --git a/markdown.lua b/markdown.lua index 957f18c101..7fb1dbee96 100644 --- a/markdown.lua +++ b/markdown.lua @@ -4,54 +4,54 @@ local args = {...} -if args[1] == 'help' then +if args[1] == 'help' then print([[ description: - This script will attempt to read the current df-screen, and if it is a + This script will attempt to read the current df-screen, and if it is a text-viewscreen (such as the dwarf 'thoughts' screen or an item / creature - 'description') or an announcement list screen (such as announcements and - combat reports) then append a marked-down version of this text to the + 'description') or an announcement list screen (such as announcements and + combat reports) then append a marked-down version of this text to the target file (for easy pasting on reddit for example). - Previous entries in the file are not overwritten, so you - may use the 'markdown' command multiple times to create a single - document containing the text from multiple screens (eg: text screens - from several dwarves, or text screens from multiple artifacts/items, - or some combination). - + Previous entries in the file are not overwritten, so you + may use the 'markdown' command multiple times to create a single + document containing the text from multiple screens (eg: text screens + from several dwarves, or text screens from multiple artifacts/items, + or some combination). + usage: markdown [/n] [filename] - + /n - overwrites contents of output file filename - if provided, the data will be saved in md_filename.md instead - of default md_export.md - + of default md_export.md + known screens: - The screens which have been tested and known to function properly with + The screens which have been tested and known to function properly with this script are: 1: dwarf/unit 'thoughts' screen 2: item/art 'description' screen 3: individual 'historical item/figure' screens - 4: manual + 4: manual 4: announements screen 5: combat reports screen 6: latest news (when meeting with liaison) - There may be other screens to which the script applies. It should be - safe to attempt running the script with any screen active, with an + There may be other screens to which the script applies. It should be + safe to attempt running the script with any screen active, with an error message to inform you when the selected screen is not appropriate for this script. - + target file: The default target file's name is 'md_export.md'. A remider to this effect - will be displayed if the script is successful. - + will be displayed if the script is successful. + character encoding: - The text will likely be using system-default encoding, and as such - will likely NOT display special characters (eg:é,õ,ç) correctly. To - fix this, you need to modify the character set that you are reading - the document with. 'Notepad++' is a freely available program which + The text will likely be using system-default encoding, and as such + will likely NOT display special characters (eg:é,õ,ç) correctly. To + fix this, you need to modify the character set that you are reading + the document with. 'Notepad++' is a freely available program which can do this using the following steps: 1: open the document in Notepad++ - 2: in the menu-bar, select + 2: in the menu-bar, select Encoding->Character Sets->Western European->OEM-US 3: copy the text normally to wherever you want to use it ]]) @@ -60,7 +60,7 @@ end local writemode = 'a' --- check if we want to append to an existing file (default) or overwrite previous contents +-- check if we want to append to an existing file (default) or overwrite previous contents if args[1] == '/n' then writemode = 'w' table.remove(args, 1) @@ -70,7 +70,7 @@ local filename if args[1] ~= nil then filename = 'md_' .. table.remove(args, 1) .. '.md' -else +else filename = 'md_export.md' end @@ -103,7 +103,7 @@ local function getFileHandle() return io.open(filename, writemode) end -local function closeFileHandle(handle) +local function closeFileHandle(handle) handle:write('\n***\n\n') handle:close() print ('Data exported to "' .. filename .. '"') @@ -111,35 +111,35 @@ end local function reformat(strin) local strout = strin - + -- [P] tags seem to indicate a new paragraph local newline_idx = string.find(strout, '[P]', 1, true) while newline_idx ~= nil do strout = string.sub(strout, 1, newline_idx - 1) .. '\n***\n\n' .. string.sub(strout, newline_idx + 3) newline_idx = string.find(strout, '[P]', 1, true) end - + -- [R] tags seem to indicate a new 'section'. Let's mark it with a horizontal line. newline_idx = string.find(strout, '[R]', 1, true) while newline_idx ~= nil do strout = string.sub(strout, 1, newline_idx - 1) .. '\n***\n\n' .. string.sub(strout,newline_idx + 3) newline_idx = string.find(strout, '[R]', 1, true) end - + -- No idea what [B] tags might indicate. Just removing them seems to work fine newline_idx = string.find(strout, '[B]', 1, true) while newline_idx ~= nil do strout = string.sub(strout, 1, newline_idx - 1) .. string.sub(strout,newline_idx + 3) newline_idx = string.find(strout, '[B]', 1, true) end - + -- Reddit doesn't support custom colors in markdown. We need to remove all color information :( local color_idx = string.find(strout, '[C:', 1, true) - while color_idx ~= nil do + while color_idx ~= nil do strout = string.sub(strout, 1, color_idx - 1) .. string.sub(strout, color_idx + 9) color_idx = string.find(strout, '[C:', 1, true) end - + return strout end @@ -147,18 +147,18 @@ local function formattime(year, ticks) -- Dwarf Mode month is 33600 ticks long local month = math.floor(ticks / 33600) local dayRemainder = ticks - month * 33600 - + -- Dwarf Mode day is 1200 ticks long local day = math.floor(dayRemainder / 1200) local timeRemainder = dayRemainder - day * 1200 - + -- Assuming a 24h day each Dwarf Mode tick corresponds to 72 seconds local seconds = timeRemainder * 72 - + local H = string.format("%02.f", math.floor(seconds / 3600)); local m = string.format("%02.f", math.floor(seconds / 60 - (H * 60))); local i = string.format("%02.f", math.floor(seconds - H * 3600 - m * 60)); - + day = day + 1 if (day == 1 or day == 21) then day = day .. 'st' @@ -167,37 +167,37 @@ local function formattime(year, ticks) else day = day .. 'th' end - + return (day .. " " .. months[month + 1] .. " " .. year .. " " .. H .. ":" .. m..":" .. i) end if flerb == 'textviewer' then - + local lines = scrn.src_text - + if lines ~= nil then - + local log = getFileHandle() log:write('### ' .. scrn.title .. '\n') print('Exporting ' .. scrn.title .. '\n') - + for n,x in ipairs(lines) do log:write(reformat(x.value).." ") --- debug output --- print(x.value) +-- debug output +-- print(x.value) end closeFileHandle(log) - end - + end + elseif flerb == 'announcelist' then local lines = scrn.reports - + if lines ~= nil then local log = getFileHandle() local lastTime = "" - + for n,x in ipairs(lines) do local currentTime = formattime(x.year, x.time) if (currentTime ~= lastTime) then @@ -205,22 +205,22 @@ elseif flerb == 'announcelist' then log:write('\n***\n\n') log:write('## ' .. currentTime .. '\n') end --- debug output +-- debug output -- print(x.text) log:write(x.text .. '\n') end closeFileHandle(log) end - - + + elseif flerb == 'topicmeeting' then local lines = scrn.text - + if lines ~= nil then local log = getFileHandle() - - for n,x in ipairs(lines) do --- debug output + + for n,x in ipairs(lines) do +-- debug output -- print(x.value) log:write(x.value .. '\n') end diff --git a/masspit.rb b/masspit.rb index b38f69d429..e391509fb8 100644 --- a/masspit.rb +++ b/masspit.rb @@ -1,40 +1,40 @@ -# pit all caged creatures in a zone - -case $script_args[0] -when '?', 'help' - puts <= df.cursor.x and zone.y1 <= df.cursor.y and zone.y2 >= df.cursor.y - } - -end - -if not bld - puts "Please select a pit/pond zone" - throw :script_finished -end - -found = 0 -df.world.items.other[:CAGE].each { |cg| - next if not cg.flags.on_ground - next if cg.pos.z != bld.z or cg.pos.x < bld.x1 or cg.pos.x > bld.x2 or cg.pos.y < bld.y1 or cg.pos.y > bld.y2 - next if not uref = cg.general_refs.grep(DFHack::GeneralRefContainsUnitst).first - found += 1 - u = uref.unit_tg - puts "Pitting #{u.race_tg.name[0]} #{u.id} #{u.name}" - u.general_refs << DFHack::GeneralRefBuildingCivzoneAssignedst.cpp_new(:building_id => bld.id) - bld.assigned_units << u.id -} -puts "No creature available for pitting" if found == 0 +# pit all caged creatures in a zone + +case $script_args[0] +when '?', 'help' + puts <= df.cursor.x and zone.y1 <= df.cursor.y and zone.y2 >= df.cursor.y + } + +end + +if not bld + puts "Please select a pit/pond zone" + throw :script_finished +end + +found = 0 +df.world.items.other[:CAGE].each { |cg| + next if not cg.flags.on_ground + next if cg.pos.z != bld.z or cg.pos.x < bld.x1 or cg.pos.x > bld.x2 or cg.pos.y < bld.y1 or cg.pos.y > bld.y2 + next if not uref = cg.general_refs.grep(DFHack::GeneralRefContainsUnitst).first + found += 1 + u = uref.unit_tg + puts "Pitting #{u.race_tg.name[0]} #{u.id} #{u.name}" + u.general_refs << DFHack::GeneralRefBuildingCivzoneAssignedst.cpp_new(:building_id => bld.id) + bld.assigned_units << u.id +} +puts "No creature available for pitting" if found == 0 diff --git a/modtools/force.lua b/modtools/force.lua index 615b6b969f..2930d29302 100644 --- a/modtools/force.lua +++ b/modtools/force.lua @@ -8,7 +8,7 @@ local utils = require 'utils' local function findCiv(arg) local entities = df.global.world.entities.all if tonumber(arg) then return arg end - if arg then + if arg then for eid,entity in ipairs(entities) do if entity.entity_raw.code == arg then return entity end end diff --git a/modtools/interaction-trigger.lua b/modtools/interaction-trigger.lua index 94e476b8fb..10eca5d4ea 100644 --- a/modtools/interaction-trigger.lua +++ b/modtools/interaction-trigger.lua @@ -69,7 +69,7 @@ eventful.onInteraction.interactionTrigger = function(attackVerb, defendVerb, att processTrigger(command) utils.unfillTable(command,extras) end - + local eraseReport = function(unit,report) for i,v in ipairs(unit.reports.log.Combat) do if v == report then diff --git a/modtools/item-trigger.lua b/modtools/item-trigger.lua index 4ad30315c7..c7f9c6d18e 100644 --- a/modtools/item-trigger.lua +++ b/modtools/item-trigger.lua @@ -62,7 +62,7 @@ function handler(table) local itemType = dfhack.items.getSubtypeDef(table.item:getType(),table.item:getSubtype()).id table.itemMat = itemMat table.itemType = itemType - + for _,command in ipairs(itemTriggers[itemType] or {}) do if command[table.mode] then utils.fillTable(command,table) @@ -78,7 +78,7 @@ function handler(table) utils.unfillTable(command,table) end end - + for _,contaminant in ipairs(table.item.contaminants or {}) do local contaminantMat = dfhack.matinfo.decode(contaminant.mat_type, contaminant.mat_index) local contaminantStr = contaminantMat:getToken() @@ -106,7 +106,7 @@ eventful.onInventoryChange.equipmentTrigger = function(unit, item, item_old, ite if item_old and item_new then return end - + local isEquip = item_new and not item_old equipHandler(unit,item,isEquip) end @@ -114,11 +114,11 @@ end eventful.onUnitAttack.attackTrigger = function(attacker,defender,wound) attacker = df.unit.find(attacker) defender = df.unit.find(defender) - + if not attacker then return end - + local attackerWeapon for _,item in ipairs(attacker.inventory) do if item.mode == df.unit_inventory_item.T_mode.Weapon then @@ -126,7 +126,7 @@ eventful.onUnitAttack.attackTrigger = function(attacker,defender,wound) break end end - + if not attackerWeapon then return end @@ -161,7 +161,7 @@ arguments: print this help message -clear clear all registered triggers - -checkAttackEvery n + -checkAttackEvery n check the attack event at least every n ticks -checkInventoryEvery n check inventory event at least every n ticks diff --git a/modtools/random-trigger.lua b/modtools/random-trigger.lua index 50d32b930a..4ad6813c19 100644 --- a/modtools/random-trigger.lua +++ b/modtools/random-trigger.lua @@ -58,7 +58,7 @@ If you want multiple independent random events, call the script multiple times. 99% of the time, you won't need to worry about this, but just in case, you can specify a name of a list of outcomes to prevent interference from other scripts that call this one. That also permits situations where you don't know until runtime what outcomes you want. For example, you could make a reaction-trigger that registers the worker as a mayor candidate, then run this script to choose a random mayor from the list of units that did the mayor reaction. - + arguments: -help print this help message diff --git a/modtools/reaction-trigger.lua b/modtools/reaction-trigger.lua index 2e428c1d49..9d14ae6082 100644 --- a/modtools/reaction-trigger.lua +++ b/modtools/reaction-trigger.lua @@ -76,12 +76,12 @@ eventful.onJobCompleted.reactionTrigger = function(job) if job.completion_timer > 0 then return end - + -- if job.job_type ~= df.job_type.CustomReaction then -- --TODO: support builtin reaction triggers if someone asks -- return -- end - + if not job.reaction_name or job.reaction_name == '' then return end @@ -89,7 +89,7 @@ eventful.onJobCompleted.reactionTrigger = function(job) if not job.reaction_name or not reactionHooks[job.reaction_name] then return end - + local worker,building = getWorkerAndBuilding(job) worker = df.unit.find(worker) building = df.building.find(building) @@ -98,7 +98,7 @@ eventful.onJobCompleted.reactionTrigger = function(job) --TODO: consider printing a warning once return end - + local function doAction(action) local didSomething if action.command then diff --git a/multicmd.rb b/multicmd.rb index d92e25cde3..593b0fa727 100644 --- a/multicmd.rb +++ b/multicmd.rb @@ -1,4 +1,4 @@ -# run many dfhack commands separated by ; -# ex: multicmd locate-ore IRON ; digv ; digcircle 16 - -$script_args.join(' ').split(/\s*;\s*/).each { |cmd| df.dfhack_run cmd } +# run many dfhack commands separated by ; +# ex: multicmd locate-ore IRON ; digv ; digcircle 16 + +$script_args.join(' ').split(/\s*;\s*/).each { |cmd| df.dfhack_run cmd } diff --git a/position.lua b/position.lua index 8c3dbe72a8..ea824e15f4 100644 --- a/position.lua +++ b/position.lua @@ -1,7 +1,7 @@ --prints current time and position local months = { - 'Granite, in early Spring.', + 'Granite, in early Spring.', 'Slate, in mid Spring.', 'Felsite, in late Spring.', 'Hematite, in early Summer.', @@ -38,6 +38,6 @@ print('Place:') print(' The z-level is z='..df.global.window_z) print(' The cursor is at x='..df.global.cursor.x..', y='..df.global.cursor.y) print(' The window is '..df.global.gps.dimx..' tiles wide and '..df.global.gps.dimy..' tiles high') -if df.global.gps.mouse_x == -1 then print(' The mouse is not in the DF window') else +if df.global.gps.mouse_x == -1 then print(' The mouse is not in the DF window') else print(' The mouse is at x='..df.global.gps.mouse_x..', y='..df.global.gps.mouse_y..' within the window') end --TODO: print(' The fortress is at '..x, y..' on the world map ('..worldsize..' square)') diff --git a/show-unit-syndromes.rb b/show-unit-syndromes.rb index 54860b48c9..f79a79e839 100644 --- a/show-unit-syndromes.rb +++ b/show-unit-syndromes.rb @@ -179,7 +179,7 @@ def get_effect_target(target) if(target.mode[i].to_s() != "") items = "" - + #case target.mode[i].to_s() #when "BY_TYPE" # item = "type(" @@ -188,12 +188,12 @@ def get_effect_target(target) #when "BY_CATEGORY" # item = "category(" #end - + if(target.key[i].to_s()!="") item = "#{item}#{target.key[i].to_s().capitalize()}" end - if target.tissue[i].to_s() != "ALL" + if target.tissue[i].to_s() != "ALL" if(target.key[i].to_s()!="" and target.tissue[i].to_s()!="") item = "#{item}:" end @@ -211,7 +211,7 @@ def get_effect_target(target) end if values.length == 0 or (values.length == 1 and values[0] == "All") - return "" + return "" else return ", target=" + values.join(", ") end @@ -272,7 +272,7 @@ def get_display_name(name, verb) if verb.length > 100 verb = verb.slice(0, 100).capitalize() end - + pos = verb.index(".") if pos == nil return verb.slice(0, verb.rindex(" ")).capitalize() @@ -563,28 +563,28 @@ def find_creature_name(id, casteid) end creature_name = creature.name[0].capitalize() - + if casteid == "DEFAULT" return creature_name, "" end - + caste = creature.caste.find{ |c| c.caste_id == casteid } - + if caste == nil return creature_name, casteid elsif creature.name[0].downcase() == caste.caste_name[0].downcase() return creature_name, "" else castename = caste.caste_name[0].downcase().chomp(creature.name[0].downcase()).strip() - + if castename.start_with?(creature.name[0]) castename = castename.slice(creature.name[0].length, castename.length - creature.name[0].length).strip() end if castename.start_with?("of the") castename = castename.slice("of the".length, castename.length - "of the".length).strip() - end - + end + return creature_name, castename.downcase() end end @@ -765,13 +765,13 @@ def get_effect(logger, ce, ticks, showdisplayeffects) end creature_name = find_creature_name(ce.race_str, ce.caste_str) - + if creature_name[1] == "" - desc = "#{creature_name[0]}#{chance}" + desc = "#{creature_name[0]}#{chance}" else - desc = "#{creature_name[0]}(#{creature_name[1]})#{chance}" + desc = "#{creature_name[0]}(#{creature_name[1]})#{chance}" end - + color = Output::BLUE when "PHYS_ATT_CHANGE" name = "Physical" @@ -793,7 +793,7 @@ def get_effect(logger, ce, ticks, showdisplayeffects) else color = Output::DEFAULT end - + if ce.mat_index >=0 mat = df.decode_mat(ce.mat_type, ce.mat_index ) elsif ce.mat_type >= 0 @@ -801,16 +801,16 @@ def get_effect(logger, ce, ticks, showdisplayeffects) else mat = nil end - + if mat!= nil token = mat.token if token.start_with?("INORGANIC:") token = token.slice("INORGANIC:".length, token.length - "INORGANIC:".length) end - + desc = "#{desc} vs #{token.capitalize()}" - end - + end + when "BODY_MAT_INTERACTION" # interactionId, SundromeTriggerType name = "Body material interaction" diff --git a/source.rb b/source.rb index 204afc70cc..176cfbf2ba 100644 --- a/source.rb +++ b/source.rb @@ -1,83 +1,83 @@ -# create an infinite magma/water source/drain at the cursor - -$sources ||= [] - -cur_source = { - :liquid => 'water', - :amount => 7, - :pos => [df.cursor.x, df.cursor.y, df.cursor.z] -} -cmd = 'help' - -$script_args.each { |a| - case a.downcase - when 'water', 'magma' - cur_source[:liquid] = a.downcase - when /^\d+$/ - cur_source[:amount] = a.to_i - when 'add', 'del', 'delete', 'clear', 'help', 'list' - cmd = a.downcase - else - puts "source: unhandled argument #{a}" - end -} - -case cmd -when 'add' - $sources_onupdate ||= df.onupdate_register('sources', 12) { - # called every 12 game ticks (100x a dwarf day) - $sources.each { |s| - if tile = df.map_tile_at(*s[:pos]) and tile.shape_passableflow - # XXX does not check current liquid_type - des = tile.designation - cur = des.flow_size - if cur != s[:amount] - tile.spawn_liquid((cur > s[:amount] ? cur-1 : cur+1), s[:liquid] == 'magma') - end - end - } - if $sources.empty? - df.onupdate_unregister($sources_onupdate) - $sources_onupdate = nil - end - } - - if cur_source[:pos][0] >= 0 - if tile = df.map_tile_at(*cur_source[:pos]) - if tile.shape_passableflow - $sources << cur_source - else - puts "Impassable tile: I'm afraid I can't do that, Dave" - end - else - puts "Unallocated map block - build something here first" - end - else - puts "Please put the game cursor where you want a source" - end - -when 'del', 'delete' - $sources.delete_if { |s| s[:pos] == cur_source[:pos] } - -when 'clear' - $sources.clear - -when 'list' - puts "Source list:", $sources.map { |s| - " #{s[:pos].inspect} #{s[:liquid]} #{s[:amount]}" - } - puts "Current cursor pos: #{[df.cursor.x, df.cursor.y, df.cursor.z].inspect}" if df.cursor.x >= 0 - -else - puts < 'water', + :amount => 7, + :pos => [df.cursor.x, df.cursor.y, df.cursor.z] +} +cmd = 'help' + +$script_args.each { |a| + case a.downcase + when 'water', 'magma' + cur_source[:liquid] = a.downcase + when /^\d+$/ + cur_source[:amount] = a.to_i + when 'add', 'del', 'delete', 'clear', 'help', 'list' + cmd = a.downcase + else + puts "source: unhandled argument #{a}" + end +} + +case cmd +when 'add' + $sources_onupdate ||= df.onupdate_register('sources', 12) { + # called every 12 game ticks (100x a dwarf day) + $sources.each { |s| + if tile = df.map_tile_at(*s[:pos]) and tile.shape_passableflow + # XXX does not check current liquid_type + des = tile.designation + cur = des.flow_size + if cur != s[:amount] + tile.spawn_liquid((cur > s[:amount] ? cur-1 : cur+1), s[:liquid] == 'magma') + end + end + } + if $sources.empty? + df.onupdate_unregister($sources_onupdate) + $sources_onupdate = nil + end + } + + if cur_source[:pos][0] >= 0 + if tile = df.map_tile_at(*cur_source[:pos]) + if tile.shape_passableflow + $sources << cur_source + else + puts "Impassable tile: I'm afraid I can't do that, Dave" + end + else + puts "Unallocated map block - build something here first" + end + else + puts "Please put the game cursor where you want a source" + end + +when 'del', 'delete' + $sources.delete_if { |s| s[:pos] == cur_source[:pos] } + +when 'clear' + $sources.clear + +when 'list' + puts "Source list:", $sources.map { |s| + " #{s[:pos].inspect} #{s[:liquid]} #{s[:amount]}" + } + puts "Current cursor pos: #{[df.cursor.x, df.cursor.y, df.cursor.z].inspect}" if df.cursor.x >= 0 + +else + puts < 1}" -end - -def cage_dump_items(list) - count = 0 - count_cage = 0 - list.each { |cage| - pre_count = count - cage.general_refs.each { |ref| - next unless ref.kind_of?(DFHack::GeneralRefContainsItemst) - next if ref.item_tg.flags.dump - count += 1 - ref.item_tg.flags.dump = true - } - count_cage += 1 if pre_count != count - } - - puts "Dumped #{plural(count, 'item')} in #{plural(count_cage, 'cage')}" -end - -def cage_dump_armor(list) - count = 0 - count_cage = 0 - list.each { |cage| - pre_count = count - cage.general_refs.each { |ref| - next unless ref.kind_of?(DFHack::GeneralRefContainsUnitst) - ref.unit_tg.inventory.each { |it| - next if it.mode != :Worn - next if it.item.flags.dump - count += 1 - it.item.flags.dump = true - } - } - count_cage += 1 if pre_count != count - } - - puts "Dumped #{plural(count, 'armor piece')} in #{plural(count_cage, 'cage')}" -end - -def cage_dump_weapons(list) - count = 0 - count_cage = 0 - list.each { |cage| - pre_count = count - cage.general_refs.each { |ref| - next unless ref.kind_of?(DFHack::GeneralRefContainsUnitst) - ref.unit_tg.inventory.each { |it| - next if it.mode != :Weapon - next if it.item.flags.dump - count += 1 - it.item.flags.dump = true - } - } - count_cage += 1 if pre_count != count - } - - puts "Dumped #{plural(count, 'weapon')} in #{plural(count_cage, 'cage')}" -end - -def cage_dump_all(list) - count = 0 - count_cage = 0 - list.each { |cage| - pre_count = count - cage.general_refs.each { |ref| - case ref - when DFHack::GeneralRefContainsItemst - next if ref.item_tg.flags.dump - count += 1 - ref.item_tg.flags.dump = true - when DFHack::GeneralRefContainsUnitst - ref.unit_tg.inventory.each { |it| - next if it.item.flags.dump - count += 1 - it.item.flags.dump = true - } - end - } - count_cage += 1 if pre_count != count - } - - puts "Dumped #{plural(count, 'item')} in #{plural(count_cage, 'cage')}" -end - - -def cage_dump_list(list) - count_total = Hash.new(0) - empty_cages = 0 - list.each { |cage| - count = Hash.new(0) - - cage.general_refs.each { |ref| - case ref - when DFHack::GeneralRefContainsItemst - count[ref.item_tg._rtti_classname] += 1 - when DFHack::GeneralRefContainsUnitst - ref.unit_tg.inventory.each { |it| - count[it.item._rtti_classname] += 1 - } - # TODO vermin ? - else - puts "unhandled ref #{ref.inspect}" if $DEBUG - end - } - - type = case cage - when DFHack::ItemCagest; 'Cage' - when DFHack::ItemAnimaltrapst; 'Animal trap' - else cage._rtti_classname - end - - if count.empty? - empty_cages += 1 - else - puts "#{type} ##{cage.id}: ", count.sort_by { |k, v| v }.map { |k, v| " #{v} #{k}" } - end - - count.each { |k, v| count_total[k] += v } - } - - if list.length > 2 - puts '', "Total: ", count_total.sort_by { |k, v| v }.map { |k, v| " #{v} #{k}" } - puts "with #{plural(empty_cages, 'empty cage')}" - end -end - - -# handle magic script arguments -here_only = $script_args.delete 'here' -if here_only - it = df.item_find - list = [it] - if not it.kind_of?(DFHack::ItemCagest) and not it.kind_of?(DFHack::ItemAnimaltrapst) - list = df.world.items.other[:ANY_CAGE_OR_TRAP].find_all { |i| df.at_cursor?(i) } - end - if list.empty? - puts 'Please select a cage' - throw :script_finished - end - -elsif ids = $script_args.find_all { |arg| arg =~ /^\d+$/ } and ids.first - list = [] - ids.each { |id| - $script_args.delete id - if not it = df.item_find(id.to_i) - puts "Invalid item id #{id}" - elsif not it.kind_of?(DFHack::ItemCagest) and not it.kind_of?(DFHack::ItemAnimaltrapst) - puts "Item ##{id} is not a cage" - list << it - else - list << it - end - } - if list.empty? - puts 'Please use a valid cage id' - throw :script_finished - end - -else - list = df.world.items.other[:ANY_CAGE_OR_TRAP] -end - - -# act -case $script_args[0] -when /^it/i - cage_dump_items(list) -when /^arm/i - cage_dump_armor(list) -when /^wea/i - cage_dump_weapons(list) -when 'all' - cage_dump_all(list) -when 'list' - cage_dump_list(list) -else - puts < 1}" +end + +def cage_dump_items(list) + count = 0 + count_cage = 0 + list.each { |cage| + pre_count = count + cage.general_refs.each { |ref| + next unless ref.kind_of?(DFHack::GeneralRefContainsItemst) + next if ref.item_tg.flags.dump + count += 1 + ref.item_tg.flags.dump = true + } + count_cage += 1 if pre_count != count + } + + puts "Dumped #{plural(count, 'item')} in #{plural(count_cage, 'cage')}" +end + +def cage_dump_armor(list) + count = 0 + count_cage = 0 + list.each { |cage| + pre_count = count + cage.general_refs.each { |ref| + next unless ref.kind_of?(DFHack::GeneralRefContainsUnitst) + ref.unit_tg.inventory.each { |it| + next if it.mode != :Worn + next if it.item.flags.dump + count += 1 + it.item.flags.dump = true + } + } + count_cage += 1 if pre_count != count + } + + puts "Dumped #{plural(count, 'armor piece')} in #{plural(count_cage, 'cage')}" +end + +def cage_dump_weapons(list) + count = 0 + count_cage = 0 + list.each { |cage| + pre_count = count + cage.general_refs.each { |ref| + next unless ref.kind_of?(DFHack::GeneralRefContainsUnitst) + ref.unit_tg.inventory.each { |it| + next if it.mode != :Weapon + next if it.item.flags.dump + count += 1 + it.item.flags.dump = true + } + } + count_cage += 1 if pre_count != count + } + + puts "Dumped #{plural(count, 'weapon')} in #{plural(count_cage, 'cage')}" +end + +def cage_dump_all(list) + count = 0 + count_cage = 0 + list.each { |cage| + pre_count = count + cage.general_refs.each { |ref| + case ref + when DFHack::GeneralRefContainsItemst + next if ref.item_tg.flags.dump + count += 1 + ref.item_tg.flags.dump = true + when DFHack::GeneralRefContainsUnitst + ref.unit_tg.inventory.each { |it| + next if it.item.flags.dump + count += 1 + it.item.flags.dump = true + } + end + } + count_cage += 1 if pre_count != count + } + + puts "Dumped #{plural(count, 'item')} in #{plural(count_cage, 'cage')}" +end + + +def cage_dump_list(list) + count_total = Hash.new(0) + empty_cages = 0 + list.each { |cage| + count = Hash.new(0) + + cage.general_refs.each { |ref| + case ref + when DFHack::GeneralRefContainsItemst + count[ref.item_tg._rtti_classname] += 1 + when DFHack::GeneralRefContainsUnitst + ref.unit_tg.inventory.each { |it| + count[it.item._rtti_classname] += 1 + } + # TODO vermin ? + else + puts "unhandled ref #{ref.inspect}" if $DEBUG + end + } + + type = case cage + when DFHack::ItemCagest; 'Cage' + when DFHack::ItemAnimaltrapst; 'Animal trap' + else cage._rtti_classname + end + + if count.empty? + empty_cages += 1 + else + puts "#{type} ##{cage.id}: ", count.sort_by { |k, v| v }.map { |k, v| " #{v} #{k}" } + end + + count.each { |k, v| count_total[k] += v } + } + + if list.length > 2 + puts '', "Total: ", count_total.sort_by { |k, v| v }.map { |k, v| " #{v} #{k}" } + puts "with #{plural(empty_cages, 'empty cage')}" + end +end + + +# handle magic script arguments +here_only = $script_args.delete 'here' +if here_only + it = df.item_find + list = [it] + if not it.kind_of?(DFHack::ItemCagest) and not it.kind_of?(DFHack::ItemAnimaltrapst) + list = df.world.items.other[:ANY_CAGE_OR_TRAP].find_all { |i| df.at_cursor?(i) } + end + if list.empty? + puts 'Please select a cage' + throw :script_finished + end + +elsif ids = $script_args.find_all { |arg| arg =~ /^\d+$/ } and ids.first + list = [] + ids.each { |id| + $script_args.delete id + if not it = df.item_find(id.to_i) + puts "Invalid item id #{id}" + elsif not it.kind_of?(DFHack::ItemCagest) and not it.kind_of?(DFHack::ItemAnimaltrapst) + puts "Item ##{id} is not a cage" + list << it + else + list << it + end + } + if list.empty? + puts 'Please use a valid cage id' + throw :script_finished + end + +else + list = df.world.items.other[:ANY_CAGE_OR_TRAP] +end + + +# act +case $script_args[0] +when /^it/i + cage_dump_items(list) +when /^arm/i + cage_dump_armor(list) +when /^wea/i + cage_dump_weapons(list) +when 'all' + cage_dump_all(list) +when 'list' + cage_dump_list(list) +else + puts < 10000 - u.counters2.sleepiness_timer = 1 - end - - # no break - if b = u.status.misc_traits.find { |t| t.id == :OnBreak } - b.value = 500_000 - end - else - $superdwarf_ids.delete id - end - } - end - } - else - puts "Select a creature using 'v'" - end - -when 'del' - if u = df.unit_find - $superdwarf_ids.delete u.id - else - puts "Select a creature using 'v'" - end - -when 'clear' - $superdwarf_ids.clear - -when 'list' - puts "current superdwarves:", $superdwarf_ids.map { |id| df.unit_find(id).name } - -else - puts "Usage:", - " - superdwarf add: give superspeed to currently selected creature", - " - superdwarf del: remove superspeed to current creature", - " - superdwarf clear: remove all superpowers", - " - superdwarf list: list super-dwarves" -end +# give super-dwarven speed to an unit + +$superdwarf_onupdate ||= nil +$superdwarf_ids ||= [] + +case $script_args[0] +when 'add' + if u = df.unit_find + $superdwarf_ids |= [u.id] + + $superdwarf_onupdate ||= df.onupdate_register('superdwarf', 1) { + if $superdwarf_ids.empty? + df.onupdate_unregister($superdwarf_onupdate) + $superdwarf_onupdate = nil + else + $superdwarf_ids.each { |id| + if u = df.unit_find(id) and not u.flags1.dead + u.actions.each { |a| + case a.type + when :Move + a.data.move.timer = 1 + when :Climb + a.data.climb.timer = 1 + when :Job + a.data.job.timer = 1 + when :Job2 + a.data.job2.timer = 1 + when :Attack + # Attack execution timer; fires when reaches zero. + a.data.attack.timer1 = 1 + # Attack completion timer: finishes action at zero. + # An action must complete before target re-seleciton + # occurs. + a.data.attack.timer2 = 0 + end + } + + # no sleep + if u.counters2.sleepiness_timer > 10000 + u.counters2.sleepiness_timer = 1 + end + + # no break + if b = u.status.misc_traits.find { |t| t.id == :OnBreak } + b.value = 500_000 + end + else + $superdwarf_ids.delete id + end + } + end + } + else + puts "Select a creature using 'v'" + end + +when 'del' + if u = df.unit_find + $superdwarf_ids.delete u.id + else + puts "Select a creature using 'v'" + end + +when 'clear' + $superdwarf_ids.clear + +when 'list' + puts "current superdwarves:", $superdwarf_ids.map { |id| df.unit_find(id).name } + +else + puts "Usage:", + " - superdwarf add: give superspeed to currently selected creature", + " - superdwarf del: remove superspeed to current creature", + " - superdwarf clear: remove all superpowers", + " - superdwarf list: list super-dwarves" +end diff --git a/undump-buildings.lua b/undump-buildings.lua index fc15113437..77e7fce5f6 100644 --- a/undump-buildings.lua +++ b/undump-buildings.lua @@ -17,7 +17,7 @@ function undump_buildings() end end end - + if undumped > 0 then local s = "s" if undumped == 1 then s = "" end diff --git a/unsuspend.rb b/unsuspend.rb index 0d5a10be4e..690ce6f038 100644 --- a/unsuspend.rb +++ b/unsuspend.rb @@ -1,17 +1,17 @@ -joblist = df.world.job_list.next -count = 0 - -while joblist - job = joblist.item - joblist = joblist.next - - if job.job_type == :ConstructBuilding - if (job.flags.suspend && job.items && job.items[0]) - item = job.items[0].item - job.flags.suspend = false - count += 1 - end - end -end - -puts "Unsuspended #{count} job(s)." +joblist = df.world.job_list.next +count = 0 + +while joblist + job = joblist.item + joblist = joblist.next + + if job.job_type == :ConstructBuilding + if (job.flags.suspend && job.items && job.items[0]) + item = job.items[0].item + job.flags.suspend = false + count += 1 + end + end +end + +puts "Unsuspended #{count} job(s)."