Merge remote-tracking branch 'kmartin/master'

develop
Alexander Gavrilov 2012-10-12 16:02:42 +04:00
commit adfb307942
11 changed files with 116 additions and 53 deletions

@ -8,6 +8,7 @@ DFHack future
Misc improvements: Misc improvements:
- fastdwarf: new mode using debug flags, and some internal consistency fixes. - fastdwarf: new mode using debug flags, and some internal consistency fixes.
- added a small stand-alone utility for applying and removing binary patches. - added a small stand-alone utility for applying and removing binary patches.
- removebadthoughts: add --dry-run option
DFHack v0.34.11-r2 DFHack v0.34.11-r2

@ -1662,16 +1662,18 @@ removebadthoughts
This script remove negative thoughts from your dwarves. Very useful against This script remove negative thoughts from your dwarves. Very useful against
tantrum spirals. tantrum spirals.
With a selected unit in 'v' mode, will clear this unit's mind, otherwise The script can target a single creature, when used with the ``him`` argument,
clear all your fort's units minds. or the whole fort population, with ``all``.
To show every bad thought present without actually removing them, run the
script with the ``-n`` or ``--dry-run`` argument. This can give a quick
hint on what bothers your dwarves the most.
Individual dwarf happiness may not increase right after this command is run, Individual dwarf happiness may not increase right after this command is run,
but in the short term your dwarves will get much more joyful. but in the short term your dwarves will get much more joyful.
The thoughts are set to be very old, and the game will remove them soon when
you unpause.
With the optional ``-v`` parameter, the script will dump the negative thoughts Internals: the thoughts are set to be very old, so that the game remove them
it removed. quickly after you unpause.
slayrace slayrace
@ -1680,7 +1682,7 @@ Kills any unit of a given race.
With no argument, lists the available races. With no argument, lists the available races.
With the special argument 'him', targets only the selected creature. With the special argument ``him``, targets only the selected creature.
Any non-dead non-caged unit of the specified race gets its ``blood_count`` Any non-dead non-caged unit of the specified race gets its ``blood_count``
set to 0, which means immediate death at the next game tick. For creatures set to 0, which means immediate death at the next game tick. For creatures

@ -352,23 +352,13 @@ module DFHack
job job
end end
# check item flags to see if it is suitable for use as a building material
def building_isitemfree(i)
!i.flags.in_job and
!i.flags.in_inventory and
!i.flags.removed and
!i.flags.in_building and
!i.flags.owned and
!i.flags.forbid
end
# exemple usage # exemple usage
def buildbed(pos=cursor) def buildbed(pos=cursor)
raise 'where to ?' if pos.x < 0 raise 'where to ?' if pos.x < 0
item = world.items.all.find { |i| item = world.items.all.find { |i|
i.kind_of?(ItemBedst) and i.kind_of?(ItemBedst) and
building_isitemfree(i) item_isfree(i)
} }
raise 'no free bed, build more !' if not item raise 'no free bed, build more !' if not item

@ -6,8 +6,12 @@ module DFHack
if what == :selected if what == :selected
case curview._rtti_classname case curview._rtti_classname
when :viewscreen_itemst when :viewscreen_itemst
ref = curview.entry_ref[curview.cursor_pos] if ref = curview.entry_ref[curview.cursor_pos]
ref.item_tg if ref.kind_of?(GeneralRefItem) ref.item_tg if ref.kind_of?(GeneralRefItem)
else
# not a container
curview.item
end
when :viewscreen_storesst # z/stocks when :viewscreen_storesst # z/stocks
if curview.in_group_mode == 0 and curview.in_right_list == 1 if curview.in_group_mode == 0 and curview.in_right_list == 1
curview.items[curview.item_cursor] curview.items[curview.item_cursor]
@ -47,5 +51,17 @@ module DFHack
raise "what what?" raise "what what?"
end end
end end
# check item flags to see if it is suitable for use as a job input material
def item_isfree(i)
!i.flags.trader and
!i.flags.in_job and
!i.flags.in_inventory and
!i.flags.removed and
!i.flags.in_building and
!i.flags.owned and
!i.flags.forbid
end
end end
end end

@ -240,5 +240,35 @@ module DFHack
def spawn_magma(quantity=7) def spawn_magma(quantity=7)
spawn_liquid(quantity, true) spawn_liquid(quantity, true)
end end
# yield a serie of tiles until the block returns true, returns the matching tile
# the yielded tiles form a (squared) spiral centered here in the current zlevel
# eg for radius 4, yields (-4, -4), (-4, -3), .., (-4, 3),
# (-4, 4), (-3, 4), .., (4, 4), .., (4, -4), .., (-3, -4)
# then move on to radius 5
def spiral_search(maxradius=100, minradius=0, step=1)
if minradius == 0
return self if yield self
minradius += step
end
sides = [[0, 1], [1, 0], [0, -1], [-1, 0]]
(minradius..maxradius).step(step) { |r|
sides.length.times { |s|
dxr, dyr = sides[(s-1) % sides.length]
dx, dy = sides[s]
(-r...r).step(step) { |v|
t = offset(dxr*r + dx*v, dyr*r + dy*v)
return t if t and yield t
}
}
}
nil
end
# returns dx^2+dy^2+dz^2
def distance_to(ot)
(x-ot.x)**2 + (y-ot.y)**2 + (z-ot.z)**2
end
end end
end end

@ -189,6 +189,10 @@ module DFHack
end end
def to_s ; token ; end def to_s ; token ; end
def ===(other)
other.mat_index == mat_index and other.mat_type == mat_type
end
end end
class << self class << self

@ -785,6 +785,7 @@ module DFHack
def isset(key) def isset(key)
raise unless @_memaddr raise unless @_memaddr
key = @_enum.int(key) if _enum key = @_enum.int(key) if _enum
raise "unknown key #{key.inspect}" if key.kind_of?(::Symbol)
DFHack.memory_stlset_isset(@_memaddr, key) DFHack.memory_stlset_isset(@_memaddr, key)
end end
alias is_set? isset alias is_set? isset
@ -792,12 +793,14 @@ module DFHack
def set(key) def set(key)
raise unless @_memaddr raise unless @_memaddr
key = @_enum.int(key) if _enum key = @_enum.int(key) if _enum
raise "unknown key #{key.inspect}" if key.kind_of?(::Symbol)
DFHack.memory_stlset_set(@_memaddr, key) DFHack.memory_stlset_set(@_memaddr, key)
end end
def delete(key) def delete(key)
raise unless @_memaddr raise unless @_memaddr
key = @_enum.int(key) if _enum key = @_enum.int(key) if _enum
raise "unknown key #{key.inspect}" if key.kind_of?(::Symbol)
DFHack.memory_stlset_deletekey(@_memaddr, key) DFHack.memory_stlset_deletekey(@_memaddr, key)
end end

@ -3498,11 +3498,11 @@ command_result start_autonestbox(color_ostream &out)
{ {
enable_autonestbox = true; enable_autonestbox = true;
if (!config_autobutcher.isValid()) if (!config_autonestbox.isValid())
{ {
config_autonestbox = World::AddPersistentData("autonestbox/config"); config_autonestbox = World::AddPersistentData("autonestbox/config");
if (!config_autobutcher.isValid()) if (!config_autonestbox.isValid())
{ {
out << "Cannot enable autonestbox without a world!" << endl; out << "Cannot enable autonestbox without a world!" << endl;
return CR_OK; return CR_OK;

@ -1,15 +1,13 @@
# show death cause of a creature # show death cause of a creature
def display_event(e) def display_death_event(e)
p e if $DEBUG 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 = "#{e.victim_tg.name} died in year #{e.year}" str << " killed by the #{e.slayer_race_tg.name[0]} #{e.slayer_hf_tg.name}" if e.slayer_hf != -1
str << " of #{e.death_cause}" if false
str << " killed by the #{e.slayer_race_tg.name[0]} #{e.slayer_tg.name}" if e.slayer != -1
str << " using a #{df.world.raws.itemdefs.weapons[e.weapon.item_subtype].name}" if e.weapon.item_type == :WEAPON 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.bow_item_subtype].name}" if e.weapon.bow_item_type == :WEAPON str << ", shot by a #{df.world.raws.itemdefs.weapons[e.weapon.bow_item_subtype].name}" if e.weapon.bow_item_type == :WEAPON
puts str + '.' puts str.chomp(',') + '.'
end end
item = df.item_find(:selected) item = df.item_find(:selected)
@ -21,14 +19,15 @@ end
if !item or !item.kind_of?(DFHack::ItemBodyComponent) if !item or !item.kind_of?(DFHack::ItemBodyComponent)
puts "Please select a corpse in the loo'k' menu" puts "Please select a corpse in the loo'k' menu"
else else
hfig = item.hist_figure_id hf = item.hist_figure_id
if hfig == -1 if hf == -1
puts "Not a historical figure, cannot find info" # TODO try to retrieve info from the unit (u = item.unit_tg)
puts "Not a historical figure, cannot death find info"
else else
events = df.world.history.events events = df.world.history.events
(0...events.length).reverse_each { |i| (0...events.length).reverse_each { |i|
if events[i].kind_of?(DFHack::HistoryEventHistFigureDiedst) and events[i].victim == hfig if events[i].kind_of?(DFHack::HistoryEventHistFigureDiedst) and events[i].victim_hf == hf
display_event(events[i]) display_death_event(events[i])
break break
end end
} }

@ -1,27 +1,43 @@
# remove bad thoughts for the selected unit or the whole fort # remove bad thoughts for the selected unit or the whole fort
# with removebadthoughts -v, dump the bad thoughts types we removed dry_run = $script_args.delete('--dry-run') || $script_args.delete('-n')
verbose = $script_args.delete('-v')
if u = df.unit_find(:selected) $script_args << 'all' if dry_run and $script_args.empty?
targets = [u]
else
targets = df.unit_citizens
end
seenbad = Hash.new(0) seenbad = Hash.new(0)
targets.each { |u| clear_mind = lambda { |u|
u.status.recent_events.each { |e| u.status.recent_events.each { |e|
next if DFHack::UnitThoughtType::Value[e.type].to_s[0, 1] != '-' next if DFHack::UnitThoughtType::Value[e.type].to_s[0, 1] != '-'
seenbad[e.type] += 1 seenbad[e.type] += 1
e.age = 0x1000_0000 e.age = 0x1000_0000 unless dry_run
} }
} }
if verbose summary = lambda {
seenbad.sort_by { |k, v| v }.each { |k, v| puts " #{v} #{k}" } seenbad.sort_by { |thought, cnt| cnt }.each { |thought, cnt|
end puts " #{thought} #{cnt}"
}
count = seenbad.values.inject(0) { |sum, cnt| sum+cnt }
puts "Removed #{count} bad thought#{'s' if count != 1}." if count > 0 and not dry_run
}
count = seenbad.values.inject(0) { |s, v| s+v } case $script_args[0]
puts "removed #{count} bad thought#{'s' if count != 1}" when 'him'
if u = df.unit_find
clear_mind[u]
summary[]
else
puts 'Please select a dwarf ingame'
end
when 'all'
df.unit_citizens.each { |uu|
clear_mind[uu]
}
summary[]
else
puts "Usage: removebadthoughts [--dry-run] <him|all>"
end

@ -33,12 +33,14 @@ slayit = lambda { |u|
end end
} }
all_races = df.world.units.active.map { |u| all_races = Hash.new(0)
u.race_tg.creature_id if checkunit[u]
}.compact.uniq.sort df.world.units.active.map { |u|
all_races[u.race_tg.creature_id] += 1 if checkunit[u]
}
if !race if !race
puts all_races all_races.sort_by { |race, cnt| [cnt, race] }.each{ |race, cnt| puts " #{race} #{cnt}" }
elsif race == 'him' elsif race == 'him'
if him = df.unit_find if him = df.unit_find
slayit[him] slayit[him]
@ -46,7 +48,7 @@ elsif race == 'him'
puts "Choose target" puts "Choose target"
end end
else else
raw_race = df.match_rawname(race, all_races) raw_race = df.match_rawname(race, all_races.keys)
raise 'invalid race' if not raw_race raise 'invalid race' if not raw_race
race_nr = df.world.raws.creatures.all.index { |cr| cr.creature_id == raw_race } race_nr = df.world.raws.creatures.all.index { |cr| cr.creature_id == raw_race }