Petr Mrázek 2012-08-12 01:10:37 +02:00
commit 7cc100b26e
16 changed files with 380 additions and 94 deletions

6
.gitignore vendored

@ -50,12 +50,6 @@ dfhack/python/PyDFHack.egg-info
dfhack/python/build dfhack/python/build
dfhack/python/dist dfhack/python/dist
# Ruby binding binaries
plugins/ruby/libruby*
plugins/ruby/msvcrtruby*.tar.gz
plugins/ruby/ruby-autogen.rb
plugins/ruby/ruby-autogen.rb.rule
# CPack stuff # CPack stuff
build/CPack*Config.cmake build/CPack*Config.cmake

@ -1401,18 +1401,30 @@ 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.
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. May not work set to 0, which means immediate death at the next game tick. For creatures
on vampires and other weird creatures. such as vampires, also set animal.vanish_countdown to 2.
An alternate mode is selected by adding a 2nd argument to the command,
``magma``. In this case, a column of 7/7 magma is generated on top of the
targets until they die (Warning: do not call on magma-safe creatures. Also,
using this mode for birds is not recommanded.)
Will target any unit on a revealed tile of the map, including ambushers.
Targets any unit on a revealed tile of the map, including ambushers. Ex: Ex:
:: ::
slayrace gob slayrace gob
To kill a single creature in the same way, you can use the following line, To kill a single creature, select the unit with the 'v' cursor and:
after selecting the unit with the 'v' cursor: ::
slayrace him
To purify all elves on the map with fire (may have side-effects):
:: ::
rb_eval df.unit_find.body.blood_count = 0 slayrace elve magma
magmasource magmasource

@ -62,7 +62,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// George Vulov for MacOSX // George Vulov for MacOSX
#ifndef __LINUX__ #ifndef __LINUX__
#define TEMP_FAILURE_RETRY(expr) \ #define TMP_FAILURE_RETRY(expr) \
({ long int _res; \ ({ long int _res; \
do _res = (long int) (expr); \ do _res = (long int) (expr); \
while (_res == -1L && errno == EINTR); \ while (_res == -1L && errno == EINTR); \
@ -155,7 +155,7 @@ namespace DFHack
FD_ZERO(&descriptor_set); FD_ZERO(&descriptor_set);
FD_SET(STDIN_FILENO, &descriptor_set); FD_SET(STDIN_FILENO, &descriptor_set);
FD_SET(exit_pipe[0], &descriptor_set); FD_SET(exit_pipe[0], &descriptor_set);
int ret = TEMP_FAILURE_RETRY( int ret = TMP_FAILURE_RETRY(
select (FD_SETSIZE,&descriptor_set, NULL, NULL, NULL) select (FD_SETSIZE,&descriptor_set, NULL, NULL, NULL)
); );
if(ret == -1) if(ret == -1)
@ -165,7 +165,7 @@ namespace DFHack
if (FD_ISSET(STDIN_FILENO, &descriptor_set)) if (FD_ISSET(STDIN_FILENO, &descriptor_set))
{ {
// read byte from stdin // read byte from stdin
ret = TEMP_FAILURE_RETRY( ret = TMP_FAILURE_RETRY(
read(STDIN_FILENO, &out, 1) read(STDIN_FILENO, &out, 1)
); );
if(ret == -1) if(ret == -1)
@ -245,7 +245,8 @@ namespace DFHack
if(rawmode) if(rawmode)
{ {
const char * clr = "\033c\033[3J\033[H"; const char * clr = "\033c\033[3J\033[H";
::write(STDIN_FILENO,clr,strlen(clr)); if (::write(STDIN_FILENO,clr,strlen(clr)) == -1)
;
} }
else else
{ {
@ -269,7 +270,8 @@ namespace DFHack
{ {
const char * colstr = getANSIColor(index); const char * colstr = getANSIColor(index);
int lstr = strlen(colstr); int lstr = strlen(colstr);
::write(STDIN_FILENO,colstr,lstr); if (::write(STDIN_FILENO,colstr,lstr) == -1)
;
} }
} }
/// Reset color to default /// Reset color to default
@ -656,7 +658,8 @@ bool Console::init(bool sharing)
inited = false; inited = false;
return false; return false;
} }
freopen("stdout.log", "w", stdout); if (!freopen("stdout.log", "w", stdout))
;
d = new Private(); d = new Private();
// make our own weird streams so our IO isn't redirected // make our own weird streams so our IO isn't redirected
d->dfout_C = fopen("/dev/tty", "w"); d->dfout_C = fopen("/dev/tty", "w");
@ -664,7 +667,8 @@ bool Console::init(bool sharing)
clear(); clear();
d->supported_terminal = !isUnsupportedTerm() && isatty(STDIN_FILENO); d->supported_terminal = !isUnsupportedTerm() && isatty(STDIN_FILENO);
// init the exit mechanism // init the exit mechanism
pipe(d->exit_pipe); if (pipe(d->exit_pipe) == -1)
;
FD_ZERO(&d->descriptor_set); FD_ZERO(&d->descriptor_set);
FD_SET(STDIN_FILENO, &d->descriptor_set); FD_SET(STDIN_FILENO, &d->descriptor_set);
FD_SET(d->exit_pipe[0], &d->descriptor_set); FD_SET(d->exit_pipe[0], &d->descriptor_set);

@ -1,29 +1,29 @@
OPTION(DL_RUBY "download libruby from the internet" ON) OPTION(DL_RUBY "download libruby from the internet" ON)
IF (DL_RUBY AND NOT APPLE) IF (DL_RUBY AND NOT APPLE)
IF (UNIX) IF (UNIX)
FILE(DOWNLOAD http://cloud.github.com/downloads/jjyg/dfhack/libruby187.tar.gz ${CMAKE_CURRENT_SOURCE_DIR}/libruby187.tar.gz FILE(DOWNLOAD http://cloud.github.com/downloads/jjyg/dfhack/libruby187.tar.gz ${CMAKE_CURRENT_BINARY_DIR}/libruby187.tar.gz
EXPECTED_MD5 eb2adea59911f68e6066966c1352f291) EXPECTED_MD5 eb2adea59911f68e6066966c1352f291)
EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E tar xzf libruby187.tar.gz EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E tar xzf libruby187.tar.gz
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
FILE(RENAME libruby1.8.so.1.8.7 libruby.so) FILE(RENAME ${CMAKE_CURRENT_BINARY_DIR}/libruby1.8.so.1.8.7 ${CMAKE_CURRENT_BINARY_DIR}/libruby.so)
SET(RUBYLIB libruby.so) SET(RUBYLIB ${CMAKE_CURRENT_BINARY_DIR}/libruby.so)
ELSE (UNIX) ELSE (UNIX)
FILE(DOWNLOAD http://cloud.github.com/downloads/jjyg/dfhack/msvcrtruby187.tar.gz ${CMAKE_CURRENT_SOURCE_DIR}/msvcrtruby187.tar.gz FILE(DOWNLOAD http://cloud.github.com/downloads/jjyg/dfhack/msvcrtruby187.tar.gz ${CMAKE_CURRENT_BINARY_DIR}/msvcrtruby187.tar.gz
EXPECTED_MD5 9f4a1659ac3a5308f32d3a1937bbeeae) EXPECTED_MD5 9f4a1659ac3a5308f32d3a1937bbeeae)
EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E tar xzf msvcrtruby187.tar.gz EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E tar xzf msvcrtruby187.tar.gz
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
FILE(RENAME msvcrt-ruby18.dll libruby.dll) FILE(RENAME ${CMAKE_CURRENT_BINARY_DIR}/msvcrt-ruby18.dll ${CMAKE_CURRENT_BINARY_DIR}/libruby.dll)
SET(RUBYLIB libruby.dll) SET(RUBYLIB ${CMAKE_CURRENT_BINARY_DIR}/libruby.dll)
ENDIF(UNIX) ENDIF(UNIX)
ENDIF(DL_RUBY AND NOT APPLE) ENDIF(DL_RUBY AND NOT APPLE)
ADD_CUSTOM_COMMAND( ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/ruby-autogen.rb OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/ruby-autogen.rb
COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/codegen.pl ${dfhack_SOURCE_DIR}/library/include/df/codegen.out.xml ${CMAKE_CURRENT_SOURCE_DIR}/ruby-autogen.rb COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/codegen.pl ${dfhack_SOURCE_DIR}/library/include/df/codegen.out.xml ${CMAKE_CURRENT_BINARY_DIR}/ruby-autogen.rb
DEPENDS ${dfhack_SOURCE_DIR}/library/include/df/codegen.out.xml ${CMAKE_CURRENT_SOURCE_DIR}/codegen.pl DEPENDS ${dfhack_SOURCE_DIR}/library/include/df/codegen.out.xml ${CMAKE_CURRENT_SOURCE_DIR}/codegen.pl
COMMENT ruby-autogen.rb COMMENT ruby-autogen.rb
) )
ADD_CUSTOM_TARGET(ruby-autogen-rb DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ruby-autogen.rb) ADD_CUSTOM_TARGET(ruby-autogen-rb DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ruby-autogen.rb)
INCLUDE_DIRECTORIES("${dfhack_SOURCE_DIR}/depends/tthread") INCLUDE_DIRECTORIES("${dfhack_SOURCE_DIR}/depends/tthread")
@ -32,6 +32,8 @@ ADD_DEPENDENCIES(ruby ruby-autogen-rb)
INSTALL(FILES ${RUBYLIB} DESTINATION ${DFHACK_LIBRARY_DESTINATION}) INSTALL(FILES ${RUBYLIB} DESTINATION ${DFHACK_LIBRARY_DESTINATION})
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/ruby-autogen.rb DESTINATION hack/ruby)
INSTALL(DIRECTORY . INSTALL(DIRECTORY .
DESTINATION hack/ruby DESTINATION hack/ruby
FILES_MATCHING PATTERN "*.rb") FILES_MATCHING PATTERN "*.rb")

@ -23,7 +23,7 @@ All ruby code runs while the main DF process and other plugins are suspended.
DFHack console DFHack console
-------------- --------------
The ruby plugin defines 1 dfhack console command: The ruby plugin defines one new dfhack console command:
rb_eval <ruby expression> ; evaluate a ruby expression and show the result in rb_eval <ruby expression> ; evaluate a ruby expression and show the result in
the console. Ex: rb_eval df.unit_find().name.first_name the console. Ex: rb_eval df.unit_find().name.first_name
You can use single-quotes for strings ; avoid double-quotes that are parsed You can use single-quotes for strings ; avoid double-quotes that are parsed
@ -50,7 +50,7 @@ The script can access the console command arguments through the global variable
'$script_args', which is an array of ruby Strings. '$script_args', which is an array of ruby Strings.
The help string displayed in dfhack 'ls' command is the first line of the The help string displayed in dfhack 'ls' command is the first line of the
script, if it is a comment (starts with '# '). script, if it is a comment (ie starts with '# ').
Ruby helper functions Ruby helper functions
@ -67,7 +67,9 @@ obj1 and 2 should respond to #pos and #x #y #z.
Returns the MapBlock for the coordinates or nil. Returns the MapBlock for the coordinates or nil.
df.map_tile_at(pos) df.map_tile_at(pos)
Returns a MapTile, holds all information relative to the map tile. Returns a MapTile, holding all informations wrt the map tile (read&write).
This class is a ruby specific extention, to facilitate interaction with the
DF map data. Check out hack/ruby/map.rb.
df.each_map_block { |b| } df.each_map_block { |b| }
df.each_map_block_z(zlevel) { |b| } df.each_map_block_z(zlevel) { |b| }
@ -142,9 +144,16 @@ The ruby classes defined in ruby-autogen.rb are accessors to the underlying
df C++ objects in-memory. To allocate a new C++ object for use in DF, use the df C++ objects in-memory. To allocate a new C++ object for use in DF, use the
RubyClass.cpp_new method (see buildings.rb for exemples), works for Compounds RubyClass.cpp_new method (see buildings.rb for exemples), works for Compounds
only. only.
A special Compound DFHack::StlString is available for allocating a single c++
stl::string, so that you can call vmethods that take a string pointer argument
(eg getName).
ex: s = DFHack::StlString.cpp_new ; df.building_find.getName(s) ; p s.str
Deallocation is not supported. You may manually call df.free if you know Deallocation may work, using the compound method _cpp_delete. Use with caution,
what you are doing (maps directly to the native malloc/free) may crash your DF session. It may be simpler to just leak the memory.
_cpp_delete will try to free all memory directly used by the compound, eg
strings and vectors. It will *not* call the class destructor, and will not free
stuff behind pointers.
C++ std::string fields may be directly re-allocated using standard ruby strings, C++ std::string fields may be directly re-allocated using standard ruby strings,
e.g. some_unit.name.nickname = 'moo' e.g. some_unit.name.nickname = 'moo'
@ -160,11 +169,13 @@ To delete an element, vector.delete_at(index)
You can binary search an element in a vector for a given numeric field value: You can binary search an element in a vector for a given numeric field value:
df.world.unit.all.binsearch(42, :id) df.world.unit.all.binsearch(42, :id)
will find the element whose 'id' field is 42 (needs the vector to be initially will find the entry whose 'id' field is 42 (needs the vector to be initially
sorted by this field). The binsearch 2nd argument defaults to :id. sorted by this field). The binsearch 2nd argument defaults to :id.
Any numeric field defined as being an enum value will be converted to a ruby Any numeric field defined as being an enum value will be converted to a ruby
Symbol. This works for array indexes too. Symbol. This works for array indexes too.
ex: df.unit_find(:selected).status.labors[:HAUL_FOOD] = true
df.map_tile_at(df.cursor).designation.liquid_type = :Water
Virtual method calls are supported for C++ objects, with a maximum of 4 Virtual method calls are supported for C++ objects, with a maximum of 4
arguments. Arguments / return value are interpreted as Compound/Enums as arguments. Arguments / return value are interpreted as Compound/Enums as
@ -194,7 +205,7 @@ Change current unit profession
Center the screen on unit ID '123' Center the screen on unit ID '123'
df.center_viewscreen(df.unit_find(123)) df.center_viewscreen(df.unit_find(123))
Find an item at a given position, show its C++ classname Find an item under the game cursor and show its C++ classname
p df.item_find(df.cursor)._rtti_classname p df.item_find(df.cursor)._rtti_classname
Find the raws name of the plant under cursor Find the raws name of the plant under cursor
@ -205,15 +216,29 @@ Dig a channel under the cursor
df.map_designation_at(df.cursor).dig = :Channel df.map_designation_at(df.cursor).dig = :Channel
df.map_block_at(df.cursor).flags.designated = true df.map_block_at(df.cursor).flags.designated = true
Spawn 2/7 magma on the tile of the dwarf nicknamed 'hotfeet'
hot = df.unit_citizens.find { |u| u.name.nickname == 'hotfeet' }
df.map_tile_at(hot).spawn_magma(2)
Plugin compilation Plugin compilation
------------------ ------------------
The plugin consists of the *.rb file including user comfort functions and The plugin consists of the main ruby.cpp native plugin and the *.rb files.
describing basic classes used by the autogenerated code, and ruby-autogen.rb,
the auto-generated code. The native plugin handles only low-level ruby-to-df interaction (eg raw memory
read/write, and dfhack integration), and the .rb files hold end-user helper
functions.
On dfhack start, the native plugin will initialize the ruby interpreter, and
load hack/ruby/ruby.rb. This one then loads all other .rb files.
autogen is output by codegen.pl from dfhack/library/include/df/codegen.out.xml The DF internal structures are described in ruby-autogen.rb .
It is output by ruby/codegen.pl, from dfhack/library/include/df/codegen.out.xml
It contains architecture-specific data (eg DF internal structures field offsets,
which differ between Windows and Linux. Linux and Macosx are the same, as they
both use gcc).
It is stored inside the build directory (eg build/plugins/ruby/ruby-autogen.rb)
For exemple, For exemple,
<ld:global-type ld:meta="struct-type" type-name="unit"> <ld:global-type ld:meta="struct-type" type-name="unit">
@ -230,6 +255,7 @@ Will generate
The syntax for the 'field' method in ruby-autogen.rb is: The syntax for the 'field' method in ruby-autogen.rb is:
1st argument = name of the method 1st argument = name of the method
2nd argument = offset of this field from the beginning of the current struct. 2nd argument = offset of this field from the beginning of the current struct.
This field depends on the compiler used by Toady to generate DF.
The block argument describes the type of the field: uint32, ptr to global... The block argument describes the type of the field: uint32, ptr to global...
Primitive type access is done through native methods from ruby.cpp (vector length, Primitive type access is done through native methods from ruby.cpp (vector length,

@ -286,14 +286,23 @@ 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
i.itemrefs.empty? and building_isitemfree(i)
!i.flags.in_job
} }
raise 'no free bed, build more !' if not item raise 'no free bed, build more !' if not item

@ -175,10 +175,10 @@ sub render_bitfield_fields {
if ($name) if ($name)
{ {
if ($count == 1) { if ($enum) {
push @lines_rb, "field(:$name, 0) { bit $shift }";
} elsif ($enum) {
push @lines_rb, "field(:$name, 0) { bits $shift, $count, $enum }"; push @lines_rb, "field(:$name, 0) { bits $shift, $count, $enum }";
} elsif ($count == 1) {
push @lines_rb, "field(:$name, 0) { bit $shift }";
} else { } else {
push @lines_rb, "field(:$name, 0) { bits $shift, $count }"; push @lines_rb, "field(:$name, 0) { bits $shift, $count }";
} }

@ -107,6 +107,31 @@ module DFHack
Tiletype::Direction[tiletype] Tiletype::Direction[tiletype]
end end
def shape_caption
TiletypeShape::Caption[shape]
end
def shape_basic
TiletypeShape::BasicShape[shape]
end
def shape_passablelow
TiletypeShape::PassableLow[shape]
end
def shape_passablehigh
TiletypeShape::PassableHigh[shape]
end
def shape_passableflow
TiletypeShape::PassableFlow[shape]
end
def shape_walkable
TiletypeShape::Walkable[shape]
end
# return all veins for current mapblock # return all veins for current mapblock
def all_veins def all_veins
mapblock.block_events.grep(BlockSquareEventMineralst) mapblock.block_events.grep(BlockSquareEventMineralst)
@ -162,5 +187,28 @@ module DFHack
def inspect def inspect
"#<MapTile pos=[#@x, #@y, #@z] shape=#{shape} tilemat=#{tilemat} material=#{mat_info.token}>" "#<MapTile pos=[#@x, #@y, #@z] shape=#{shape} tilemat=#{tilemat} material=#{mat_info.token}>"
end end
def spawn_liquid(quantity, is_magma=false, flowing=true)
designation.flow_size = quantity
designation.liquid_type = (is_magma ? :Magma : :Water)
designation.flow_forbid = true if is_magma or quantity >= 4
if flowing
mapblock.flags.update_liquid = true
mapblock.flags.update_liquid_twice = true
zf = df.world.map.z_level_flags[z]
zf.update = true
zf.update_twice = true
end
end
def spawn_water(quantity=7)
spawn_liquid(quantity)
end
def spawn_magma(quantity=7)
spawn_liquid(quantity, true)
end
end end
end end

@ -7,6 +7,7 @@ module DFHack
def _at(addr) ; d = dup ; d._memaddr = addr ; d ; end def _at(addr) ; d = dup ; d._memaddr = addr ; d ; end
def _get ; self ; end def _get ; self ; end
def _cpp_init ; end def _cpp_init ; end
def _cpp_delete ; end
end end
class Compound < MemStruct class Compound < MemStruct
@ -34,8 +35,8 @@ module DFHack
def float def float
Float.new Float.new
end end
def bit(shift) def bit(shift, enum=nil)
BitField.new(shift, 1) BitField.new(shift, 1, enum)
end end
def bits(shift, len, enum=nil) def bits(shift, len, enum=nil)
BitField.new(shift, len, enum) BitField.new(shift, len, enum)
@ -114,6 +115,11 @@ module DFHack
def _cpp_init def _cpp_init
_fields_ancestors.each { |n, o, s| s._at(@_memaddr+o)._cpp_init } _fields_ancestors.each { |n, o, s| s._at(@_memaddr+o)._cpp_init }
end end
def _cpp_delete
_fields_ancestors.each { |n, o, s| s._at(@_memaddr+o)._cpp_delete }
DFHack.free(@_memaddr)
@_memaddr = nil # turn future segfaults in harmless ruby exceptions
end
def _set(h) def _set(h)
case h case h
when Hash; h.each { |k, v| send("#{k}=", v) } when Hash; h.each { |k, v| send("#{k}=", v) }
@ -147,7 +153,7 @@ module DFHack
out << '>' out << '>'
end end
def inspect_field(n, o, s) def inspect_field(n, o, s)
if s.kind_of?(BitField) and s._len == 1 if s.kind_of?(BitField) and s._len == 1 and not s._enum
send(n) ? n.to_s : '' send(n) ? n.to_s : ''
elsif s.kind_of?(Pointer) elsif s.kind_of?(Pointer)
"#{n}=#{s._at(@_memaddr+o).inspect}" "#{n}=#{s._at(@_memaddr+o).inspect}"
@ -242,7 +248,7 @@ module DFHack
def _get def _get
v = DFHack.memory_read_int32(@_memaddr) >> @_shift v = DFHack.memory_read_int32(@_memaddr) >> @_shift
if @_len == 1 if @_len == 1 and not @_enum
((v & 1) == 0) ? false : true ((v & 1) == 0) ? false : true
else else
v &= _mask v &= _mask
@ -252,7 +258,7 @@ module DFHack
end end
def _set(v) def _set(v)
if @_len == 1 if @_len == 1 and (not @_enum or v == false or v == true)
# allow 'bit = 0' # allow 'bit = 0'
v = (v && v != 0 ? 1 : 0) v = (v && v != 0 ? 1 : 0)
end end
@ -355,6 +361,7 @@ module DFHack
def empty? ; length == 0 ; end def empty? ; length == 0 ; end
def flatten ; map { |e| e.respond_to?(:flatten) ? e.flatten : e }.flatten ; end def flatten ; map { |e| e.respond_to?(:flatten) ? e.flatten : e }.flatten ; end
def index(e=nil, &b) ; (0...length).find { |i| b ? b[self[i]] : self[i] == e } ; end def index(e=nil, &b) ; (0...length).find { |i| b ? b[self[i]] : self[i] == e } ; end
def map! ; (0...length).each { |i| self[i] = yield(self[i]) } ; end
def first ; self[0] ; end def first ; self[0] ; end
def last ; self[length-1] ; end def last ; self[length-1] ; end
end end
@ -372,6 +379,9 @@ module DFHack
def _cpp_init def _cpp_init
_length.times { |i| _tgat(i)._cpp_init } _length.times { |i| _tgat(i)._cpp_init }
end end
def _cpp_delete
_length.times { |i| _tgat(i)._cpp_delete }
end
alias length _length alias length _length
alias size _length alias size _length
def _tgat(i) def _tgat(i)
@ -423,10 +433,10 @@ module DFHack
DFHack.memory_vector32_ptrat(@_memaddr, idx) DFHack.memory_vector32_ptrat(@_memaddr, idx)
end end
def insert_at(idx, val) def insert_at(idx, val)
DFHack.memory_vector32_insert(@_memaddr, idx, val) DFHack.memory_vector32_insertat(@_memaddr, idx, val)
end end
def delete_at(idx) def delete_at(idx)
DFHack.memory_vector32_delete(@_memaddr, idx) DFHack.memory_vector32_deleteat(@_memaddr, idx)
end end
def _set(v) def _set(v)
@ -434,6 +444,12 @@ module DFHack
v.each_with_index { |e, i| self[i] = e } # patch entries v.each_with_index { |e, i| self[i] = e } # patch entries
end end
def self._cpp_new
new._at DFHack.memory_vector_new
end
def _cpp_delete
DFHack.memory_vector_delete(@_memaddr)
end
def _cpp_init def _cpp_init
DFHack.memory_vector_init(@_memaddr) DFHack.memory_vector_init(@_memaddr)
end end
@ -496,10 +512,10 @@ module DFHack
DFHack.memory_vector16_ptrat(@_memaddr, idx) DFHack.memory_vector16_ptrat(@_memaddr, idx)
end end
def insert_at(idx, val) def insert_at(idx, val)
DFHack.memory_vector16_insert(@_memaddr, idx, val) DFHack.memory_vector16_insertat(@_memaddr, idx, val)
end end
def delete_at(idx) def delete_at(idx)
DFHack.memory_vector16_delete(@_memaddr, idx) DFHack.memory_vector16_deleteat(@_memaddr, idx)
end end
end end
class StlVector8 < StlVector32 class StlVector8 < StlVector32
@ -510,10 +526,10 @@ module DFHack
DFHack.memory_vector8_ptrat(@_memaddr, idx) DFHack.memory_vector8_ptrat(@_memaddr, idx)
end end
def insert_at(idx, val) def insert_at(idx, val)
DFHack.memory_vector8_insert(@_memaddr, idx, val) DFHack.memory_vector8_insertat(@_memaddr, idx, val)
end end
def delete_at(idx) def delete_at(idx)
DFHack.memory_vector8_delete(@_memaddr, idx) DFHack.memory_vector8_deleteat(@_memaddr, idx)
end end
end end
class StlBitVector < StlVector32 class StlBitVector < StlVector32
@ -522,10 +538,10 @@ module DFHack
DFHack.memory_vectorbool_length(@_memaddr) DFHack.memory_vectorbool_length(@_memaddr)
end end
def insert_at(idx, val) def insert_at(idx, val)
DFHack.memory_vectorbool_insert(@_memaddr, idx, val) DFHack.memory_vectorbool_insertat(@_memaddr, idx, val)
end end
def delete_at(idx) def delete_at(idx)
DFHack.memory_vectorbool_delete(@_memaddr, idx) DFHack.memory_vectorbool_deleteat(@_memaddr, idx)
end end
def [](idx) def [](idx)
idx += length if idx < 0 idx += length if idx < 0
@ -541,6 +557,12 @@ module DFHack
DFHack.memory_vectorbool_setat(@_memaddr, idx, v) DFHack.memory_vectorbool_setat(@_memaddr, idx, v)
end end
end end
def self._cpp_new
new._at DFHack.memory_vectorbool_new
end
def _cpp_delete
DFHack.memory_vectorbool_delete(@_memaddr)
end
end end
class StlString < MemStruct class StlString < MemStruct
def _get def _get
@ -551,6 +573,12 @@ module DFHack
DFHack.memory_write_stlstring(@_memaddr, v) DFHack.memory_write_stlstring(@_memaddr, v)
end end
def self._cpp_new
new._at DFHack.memory_stlstring_new
end
def _cpp_delete
DFHack.memory_stlstring_delete(@_memaddr)
end
def _cpp_init def _cpp_init
DFHack.memory_stlstring_init(@_memaddr) DFHack.memory_stlstring_init(@_memaddr)
end end
@ -574,7 +602,7 @@ module DFHack
def length def length
DFHack.memory_bitarray_length(@_memaddr) DFHack.memory_bitarray_length(@_memaddr)
end end
# TODO _cpp_init # TODO _cpp_init, _cpp_delete
def size ; length ; end def size ; length ; end
def resize(len) def resize(len)
DFHack.memory_bitarray_resize(@_memaddr, len) DFHack.memory_bitarray_resize(@_memaddr, len)
@ -608,7 +636,7 @@ module DFHack
def length ; _length ; end def length ; _length ; end
def size ; _length ; end def size ; _length ; end
# TODO _cpp_init # TODO _cpp_init, _cpp_delete
def _tgat(i) def _tgat(i)
@_tg._at(_ptr + i*@_tglen) if i >= 0 and i < _length @_tg._at(_ptr + i*@_tglen) if i >= 0 and i < _length
end end
@ -702,6 +730,21 @@ module DFHack
def self.sym(v) ; (!v || (v == 0)) ? false : true ; end def self.sym(v) ; (!v || (v == 0)) ? false : true ; end
end end
class StlString < MemHack::Compound
field(:str, 0) { stl_string }
def self.cpp_new(init=nil)
s = MemHack::StlString._cpp_new
s._set(init) if init
new._at(s._memaddr)
end
def _cpp_delete
MemHack::StlString.new._at(@_memaddr+0)._cpp_delete
@_memaddr = nil
end
end
# cpp rtti name -> rb class # cpp rtti name -> rb class
@rtti_n2c = {} @rtti_n2c = {}
@rtti_c2n = {} @rtti_c2n = {}

@ -528,7 +528,7 @@ static VALUE rb_dfmalloc(VALUE self, VALUE len)
if (!ptr) if (!ptr)
return Qnil; return Qnil;
memset(ptr, 0, FIX2INT(len)); memset(ptr, 0, FIX2INT(len));
return rb_uint2inum((long)ptr); return rb_uint2inum((uint32_t)ptr);
} }
static VALUE rb_dffree(VALUE self, VALUE ptr) static VALUE rb_dffree(VALUE self, VALUE ptr)
@ -599,6 +599,18 @@ static VALUE rb_dfmemory_write_float(VALUE self, VALUE addr, VALUE val)
// stl::string // stl::string
static VALUE rb_dfmemory_stlstring_new(VALUE self)
{
std::string *ptr = new std::string;
return rb_uint2inum((uint32_t)ptr);
}
static VALUE rb_dfmemory_stlstring_delete(VALUE self, VALUE addr)
{
std::string *ptr = (std::string*)rb_num2ulong(addr);
if (ptr)
delete ptr;
return Qtrue;
}
static VALUE rb_dfmemory_stlstring_init(VALUE self, VALUE addr) static VALUE rb_dfmemory_stlstring_init(VALUE self, VALUE addr)
{ {
// XXX THIS IS TERRIBLE // XXX THIS IS TERRIBLE
@ -621,6 +633,18 @@ static VALUE rb_dfmemory_write_stlstring(VALUE self, VALUE addr, VALUE val)
// vector access // vector access
static VALUE rb_dfmemory_vec_new(VALUE self)
{
std::vector<uint8_t> *ptr = new std::vector<uint8_t>;
return rb_uint2inum((uint32_t)ptr);
}
static VALUE rb_dfmemory_vec_delete(VALUE self, VALUE addr)
{
std::vector<uint8_t> *ptr = (std::vector<uint8_t>*)rb_num2ulong(addr);
if (ptr)
delete ptr;
return Qtrue;
}
static VALUE rb_dfmemory_vec_init(VALUE self, VALUE addr) static VALUE rb_dfmemory_vec_init(VALUE self, VALUE addr)
{ {
std::vector<uint8_t> *ptr = new std::vector<uint8_t>; std::vector<uint8_t> *ptr = new std::vector<uint8_t>;
@ -638,13 +662,13 @@ static VALUE rb_dfmemory_vec8_ptrat(VALUE self, VALUE addr, VALUE idx)
std::vector<uint8_t> *v = (std::vector<uint8_t>*)rb_num2ulong(addr); std::vector<uint8_t> *v = (std::vector<uint8_t>*)rb_num2ulong(addr);
return rb_uint2inum((uint32_t)&v->at(FIX2INT(idx))); return rb_uint2inum((uint32_t)&v->at(FIX2INT(idx)));
} }
static VALUE rb_dfmemory_vec8_insert(VALUE self, VALUE addr, VALUE idx, VALUE val) static VALUE rb_dfmemory_vec8_insertat(VALUE self, VALUE addr, VALUE idx, VALUE val)
{ {
std::vector<uint8_t> *v = (std::vector<uint8_t>*)rb_num2ulong(addr); std::vector<uint8_t> *v = (std::vector<uint8_t>*)rb_num2ulong(addr);
v->insert(v->begin()+FIX2INT(idx), rb_num2ulong(val)); v->insert(v->begin()+FIX2INT(idx), rb_num2ulong(val));
return Qtrue; return Qtrue;
} }
static VALUE rb_dfmemory_vec8_delete(VALUE self, VALUE addr, VALUE idx) static VALUE rb_dfmemory_vec8_deleteat(VALUE self, VALUE addr, VALUE idx)
{ {
std::vector<uint8_t> *v = (std::vector<uint8_t>*)rb_num2ulong(addr); std::vector<uint8_t> *v = (std::vector<uint8_t>*)rb_num2ulong(addr);
v->erase(v->begin()+FIX2INT(idx)); v->erase(v->begin()+FIX2INT(idx));
@ -662,13 +686,13 @@ static VALUE rb_dfmemory_vec16_ptrat(VALUE self, VALUE addr, VALUE idx)
std::vector<uint16_t> *v = (std::vector<uint16_t>*)rb_num2ulong(addr); std::vector<uint16_t> *v = (std::vector<uint16_t>*)rb_num2ulong(addr);
return rb_uint2inum((uint32_t)&v->at(FIX2INT(idx))); return rb_uint2inum((uint32_t)&v->at(FIX2INT(idx)));
} }
static VALUE rb_dfmemory_vec16_insert(VALUE self, VALUE addr, VALUE idx, VALUE val) static VALUE rb_dfmemory_vec16_insertat(VALUE self, VALUE addr, VALUE idx, VALUE val)
{ {
std::vector<uint16_t> *v = (std::vector<uint16_t>*)rb_num2ulong(addr); std::vector<uint16_t> *v = (std::vector<uint16_t>*)rb_num2ulong(addr);
v->insert(v->begin()+FIX2INT(idx), rb_num2ulong(val)); v->insert(v->begin()+FIX2INT(idx), rb_num2ulong(val));
return Qtrue; return Qtrue;
} }
static VALUE rb_dfmemory_vec16_delete(VALUE self, VALUE addr, VALUE idx) static VALUE rb_dfmemory_vec16_deleteat(VALUE self, VALUE addr, VALUE idx)
{ {
std::vector<uint16_t> *v = (std::vector<uint16_t>*)rb_num2ulong(addr); std::vector<uint16_t> *v = (std::vector<uint16_t>*)rb_num2ulong(addr);
v->erase(v->begin()+FIX2INT(idx)); v->erase(v->begin()+FIX2INT(idx));
@ -686,13 +710,13 @@ static VALUE rb_dfmemory_vec32_ptrat(VALUE self, VALUE addr, VALUE idx)
std::vector<uint32_t> *v = (std::vector<uint32_t>*)rb_num2ulong(addr); std::vector<uint32_t> *v = (std::vector<uint32_t>*)rb_num2ulong(addr);
return rb_uint2inum((uint32_t)&v->at(FIX2INT(idx))); return rb_uint2inum((uint32_t)&v->at(FIX2INT(idx)));
} }
static VALUE rb_dfmemory_vec32_insert(VALUE self, VALUE addr, VALUE idx, VALUE val) static VALUE rb_dfmemory_vec32_insertat(VALUE self, VALUE addr, VALUE idx, VALUE val)
{ {
std::vector<uint32_t> *v = (std::vector<uint32_t>*)rb_num2ulong(addr); std::vector<uint32_t> *v = (std::vector<uint32_t>*)rb_num2ulong(addr);
v->insert(v->begin()+FIX2INT(idx), rb_num2ulong(val)); v->insert(v->begin()+FIX2INT(idx), rb_num2ulong(val));
return Qtrue; return Qtrue;
} }
static VALUE rb_dfmemory_vec32_delete(VALUE self, VALUE addr, VALUE idx) static VALUE rb_dfmemory_vec32_deleteat(VALUE self, VALUE addr, VALUE idx)
{ {
std::vector<uint32_t> *v = (std::vector<uint32_t>*)rb_num2ulong(addr); std::vector<uint32_t> *v = (std::vector<uint32_t>*)rb_num2ulong(addr);
v->erase(v->begin()+FIX2INT(idx)); v->erase(v->begin()+FIX2INT(idx));
@ -700,6 +724,24 @@ static VALUE rb_dfmemory_vec32_delete(VALUE self, VALUE addr, VALUE idx)
} }
// vector<bool> // vector<bool>
static VALUE rb_dfmemory_vecbool_new(VALUE self)
{
std::vector<bool> *ptr = new std::vector<bool>;
return rb_uint2inum((uint32_t)ptr);
}
static VALUE rb_dfmemory_vecbool_delete(VALUE self, VALUE addr)
{
std::vector<bool> *ptr = (std::vector<bool>*)rb_num2ulong(addr);
if (ptr)
delete ptr;
return Qtrue;
}
static VALUE rb_dfmemory_vecbool_init(VALUE self, VALUE addr)
{
std::vector<bool> *ptr = new std::vector<bool>;
memcpy((void*)rb_num2ulong(addr), (void*)ptr, sizeof(*ptr));
return Qtrue;
}
static VALUE rb_dfmemory_vecbool_length(VALUE self, VALUE addr) static VALUE rb_dfmemory_vecbool_length(VALUE self, VALUE addr)
{ {
std::vector<bool> *v = (std::vector<bool>*)rb_num2ulong(addr); std::vector<bool> *v = (std::vector<bool>*)rb_num2ulong(addr);
@ -716,13 +758,13 @@ static VALUE rb_dfmemory_vecbool_setat(VALUE self, VALUE addr, VALUE idx, VALUE
v->at(FIX2INT(idx)) = (BOOL_ISFALSE(val) ? 0 : 1); v->at(FIX2INT(idx)) = (BOOL_ISFALSE(val) ? 0 : 1);
return Qtrue; return Qtrue;
} }
static VALUE rb_dfmemory_vecbool_insert(VALUE self, VALUE addr, VALUE idx, VALUE val) static VALUE rb_dfmemory_vecbool_insertat(VALUE self, VALUE addr, VALUE idx, VALUE val)
{ {
std::vector<bool> *v = (std::vector<bool>*)rb_num2ulong(addr); std::vector<bool> *v = (std::vector<bool>*)rb_num2ulong(addr);
v->insert(v->begin()+FIX2INT(idx), (BOOL_ISFALSE(val) ? 0 : 1)); v->insert(v->begin()+FIX2INT(idx), (BOOL_ISFALSE(val) ? 0 : 1));
return Qtrue; return Qtrue;
} }
static VALUE rb_dfmemory_vecbool_delete(VALUE self, VALUE addr, VALUE idx) static VALUE rb_dfmemory_vecbool_deleteat(VALUE self, VALUE addr, VALUE idx)
{ {
std::vector<bool> *v = (std::vector<bool>*)rb_num2ulong(addr); std::vector<bool> *v = (std::vector<bool>*)rb_num2ulong(addr);
v->erase(v->begin()+FIX2INT(idx)); v->erase(v->begin()+FIX2INT(idx));
@ -834,27 +876,34 @@ static void ruby_bind_dfhack(void) {
rb_define_singleton_method(rb_cDFHack, "memory_write_int32", RUBY_METHOD_FUNC(rb_dfmemory_write_int32), 2); rb_define_singleton_method(rb_cDFHack, "memory_write_int32", RUBY_METHOD_FUNC(rb_dfmemory_write_int32), 2);
rb_define_singleton_method(rb_cDFHack, "memory_write_float", RUBY_METHOD_FUNC(rb_dfmemory_write_float), 2); rb_define_singleton_method(rb_cDFHack, "memory_write_float", RUBY_METHOD_FUNC(rb_dfmemory_write_float), 2);
rb_define_singleton_method(rb_cDFHack, "memory_stlstring_new", RUBY_METHOD_FUNC(rb_dfmemory_stlstring_new), 0);
rb_define_singleton_method(rb_cDFHack, "memory_stlstring_delete", RUBY_METHOD_FUNC(rb_dfmemory_stlstring_delete), 1);
rb_define_singleton_method(rb_cDFHack, "memory_stlstring_init", RUBY_METHOD_FUNC(rb_dfmemory_stlstring_init), 1); rb_define_singleton_method(rb_cDFHack, "memory_stlstring_init", RUBY_METHOD_FUNC(rb_dfmemory_stlstring_init), 1);
rb_define_singleton_method(rb_cDFHack, "memory_read_stlstring", RUBY_METHOD_FUNC(rb_dfmemory_read_stlstring), 1); rb_define_singleton_method(rb_cDFHack, "memory_read_stlstring", RUBY_METHOD_FUNC(rb_dfmemory_read_stlstring), 1);
rb_define_singleton_method(rb_cDFHack, "memory_write_stlstring", RUBY_METHOD_FUNC(rb_dfmemory_write_stlstring), 2); rb_define_singleton_method(rb_cDFHack, "memory_write_stlstring", RUBY_METHOD_FUNC(rb_dfmemory_write_stlstring), 2);
rb_define_singleton_method(rb_cDFHack, "memory_vector_new", RUBY_METHOD_FUNC(rb_dfmemory_vec_new), 0);
rb_define_singleton_method(rb_cDFHack, "memory_vector_delete", RUBY_METHOD_FUNC(rb_dfmemory_vec_delete), 1);
rb_define_singleton_method(rb_cDFHack, "memory_vector_init", RUBY_METHOD_FUNC(rb_dfmemory_vec_init), 1); rb_define_singleton_method(rb_cDFHack, "memory_vector_init", RUBY_METHOD_FUNC(rb_dfmemory_vec_init), 1);
rb_define_singleton_method(rb_cDFHack, "memory_vector8_length", RUBY_METHOD_FUNC(rb_dfmemory_vec8_length), 1); rb_define_singleton_method(rb_cDFHack, "memory_vector8_length", RUBY_METHOD_FUNC(rb_dfmemory_vec8_length), 1);
rb_define_singleton_method(rb_cDFHack, "memory_vector8_ptrat", RUBY_METHOD_FUNC(rb_dfmemory_vec8_ptrat), 2); rb_define_singleton_method(rb_cDFHack, "memory_vector8_ptrat", RUBY_METHOD_FUNC(rb_dfmemory_vec8_ptrat), 2);
rb_define_singleton_method(rb_cDFHack, "memory_vector8_insert", RUBY_METHOD_FUNC(rb_dfmemory_vec8_insert), 3); rb_define_singleton_method(rb_cDFHack, "memory_vector8_insertat", RUBY_METHOD_FUNC(rb_dfmemory_vec8_insertat), 3);
rb_define_singleton_method(rb_cDFHack, "memory_vector8_delete", RUBY_METHOD_FUNC(rb_dfmemory_vec8_delete), 2); rb_define_singleton_method(rb_cDFHack, "memory_vector8_deleteat", RUBY_METHOD_FUNC(rb_dfmemory_vec8_deleteat), 2);
rb_define_singleton_method(rb_cDFHack, "memory_vector16_length", RUBY_METHOD_FUNC(rb_dfmemory_vec16_length), 1); rb_define_singleton_method(rb_cDFHack, "memory_vector16_length", RUBY_METHOD_FUNC(rb_dfmemory_vec16_length), 1);
rb_define_singleton_method(rb_cDFHack, "memory_vector16_ptrat", RUBY_METHOD_FUNC(rb_dfmemory_vec16_ptrat), 2); rb_define_singleton_method(rb_cDFHack, "memory_vector16_ptrat", RUBY_METHOD_FUNC(rb_dfmemory_vec16_ptrat), 2);
rb_define_singleton_method(rb_cDFHack, "memory_vector16_insert", RUBY_METHOD_FUNC(rb_dfmemory_vec16_insert), 3); rb_define_singleton_method(rb_cDFHack, "memory_vector16_insertat", RUBY_METHOD_FUNC(rb_dfmemory_vec16_insertat), 3);
rb_define_singleton_method(rb_cDFHack, "memory_vector16_delete", RUBY_METHOD_FUNC(rb_dfmemory_vec16_delete), 2); rb_define_singleton_method(rb_cDFHack, "memory_vector16_deleteat", RUBY_METHOD_FUNC(rb_dfmemory_vec16_deleteat), 2);
rb_define_singleton_method(rb_cDFHack, "memory_vector32_length", RUBY_METHOD_FUNC(rb_dfmemory_vec32_length), 1); rb_define_singleton_method(rb_cDFHack, "memory_vector32_length", RUBY_METHOD_FUNC(rb_dfmemory_vec32_length), 1);
rb_define_singleton_method(rb_cDFHack, "memory_vector32_ptrat", RUBY_METHOD_FUNC(rb_dfmemory_vec32_ptrat), 2); rb_define_singleton_method(rb_cDFHack, "memory_vector32_ptrat", RUBY_METHOD_FUNC(rb_dfmemory_vec32_ptrat), 2);
rb_define_singleton_method(rb_cDFHack, "memory_vector32_insert", RUBY_METHOD_FUNC(rb_dfmemory_vec32_insert), 3); rb_define_singleton_method(rb_cDFHack, "memory_vector32_insertat", RUBY_METHOD_FUNC(rb_dfmemory_vec32_insertat), 3);
rb_define_singleton_method(rb_cDFHack, "memory_vector32_delete", RUBY_METHOD_FUNC(rb_dfmemory_vec32_delete), 2); rb_define_singleton_method(rb_cDFHack, "memory_vector32_deleteat", RUBY_METHOD_FUNC(rb_dfmemory_vec32_deleteat), 2);
rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_new", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_new), 0);
rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_delete", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_delete), 1);
rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_init", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_init), 1);
rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_length", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_length), 1); rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_length", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_length), 1);
rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_at", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_at), 2); rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_at", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_at), 2);
rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_setat", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_setat), 3); rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_setat", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_setat), 3);
rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_insert", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_insert), 3); rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_insertat", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_insertat), 3);
rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_delete", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_delete), 2); rb_define_singleton_method(rb_cDFHack, "memory_vectorbool_deleteat", RUBY_METHOD_FUNC(rb_dfmemory_vecbool_deleteat), 2);
rb_define_singleton_method(rb_cDFHack, "memory_bitarray_length", RUBY_METHOD_FUNC(rb_dfmemory_bitarray_length), 1); rb_define_singleton_method(rb_cDFHack, "memory_bitarray_length", RUBY_METHOD_FUNC(rb_dfmemory_bitarray_length), 1);
rb_define_singleton_method(rb_cDFHack, "memory_bitarray_resize", RUBY_METHOD_FUNC(rb_dfmemory_bitarray_resize), 2); rb_define_singleton_method(rb_cDFHack, "memory_bitarray_resize", RUBY_METHOD_FUNC(rb_dfmemory_bitarray_resize), 2);
rb_define_singleton_method(rb_cDFHack, "memory_bitarray_isset", RUBY_METHOD_FUNC(rb_dfmemory_bitarray_isset), 2); rb_define_singleton_method(rb_cDFHack, "memory_bitarray_isset", RUBY_METHOD_FUNC(rb_dfmemory_bitarray_isset), 2);

@ -68,5 +68,14 @@ module DFHack
world.status.display_timer = 2000 world.status.display_timer = 2000
end end
end end
# add an announcement to display in a game popup message
# (eg "the megabeast foobar arrived")
def popup_announcement(str, color=nil, bright=nil)
pop = PopupMessage.cpp_new(:text => str)
pop.color = color if color
pop.bright = bright if bright
world.status.popups << pop
end
end end
end end

@ -12,6 +12,7 @@
#include "df/world.h" #include "df/world.h"
#include "df/job.h" #include "df/job.h"
#include "df/job_item.h" #include "df/job_item.h"
#include "df/job_item_ref.h"
#include "df/general_ref.h" #include "df/general_ref.h"
#include "df/builtin_mats.h" #include "df/builtin_mats.h"
#include "df/inorganic_raw.h" #include "df/inorganic_raw.h"
@ -165,7 +166,10 @@ command_result df_showmood (color_ostream &out, vector <string> & parameters)
out.print("not yet claimed a workshop but will want"); out.print("not yet claimed a workshop but will want");
out.print(" the following items:\n"); out.print(" the following items:\n");
int count_got = job->items.size(), got; // total amount of stuff fetched so far
int count_got = 0;
for (size_t i = 0; i < job->items.size(); i++)
count_got += job->items[i]->item->getTotalDimension();
for (size_t i = 0; i < job->job_items.size(); i++) for (size_t i = 0; i < job->job_items.size(); i++)
{ {
@ -269,7 +273,9 @@ command_result df_showmood (color_ostream &out, vector <string> & parameters)
} }
} }
got = count_got; // total amount of stuff fetched for this requirement
// XXX may fail with cloth/thread/bars if need 1 and fetch 2
int got = count_got;
if (got > item->quantity) if (got > item->quantity)
got = item->quantity; got = item->quantity;
out.print(", quantity %i (got %i)\n", item->quantity, got); out.print(", quantity %i (got %i)\n", item->quantity, got);

@ -0,0 +1,64 @@
# 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.unknown8.enemy_status_slot != -1
i = unit.unknown8.enemy_status_slot
unit.unknown8.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

@ -12,26 +12,16 @@ when 'here'
end end
$magma_sources.each { |x, y, z| $magma_sources.each { |x, y, z|
if tile = df.map_tile_at(x, y, z) and DFHack::TiletypeShape::PassableFlow[tile.shape] if tile = df.map_tile_at(x, y, z) and tile.shape_passableflow
des = tile.designation des = tile.designation
des.flow_size += 1 if des.flow_size < 7 tile.spawn_magma(des.flow_size + 1) if des.flow_size < 7
des.liquid_type = 1
des.flow_forbid = true
mf = tile.mapblock.flags
mf.update_liquid = true
mf.update_liquid_twice = true
zf = df.world.map.z_level_flags[z]
zf.update = true
zf.update_twice = true
end end
} }
} }
if df.cursor.x != -30000 if df.cursor.x != -30000
if tile = df.map_tile_at(df.cursor) if tile = df.map_tile_at(df.cursor)
if DFHack::TiletypeShape::PassableFlow[tile.shape] if tile.shape_passableflow
$magma_sources << [df.cursor.x, df.cursor.y, df.cursor.z] $magma_sources << [df.cursor.x, df.cursor.y, df.cursor.z]
else else
puts "Impassable tile: I'm afraid I can't do that, Dave" puts "Impassable tile: I'm afraid I can't do that, Dave"

@ -1,6 +1,9 @@
# slay all creatures of a given race # slay all creatures of a given race
# race = name of the race to eradicate, use 'him' to target only the selected creature
race = $script_args[0] race = $script_args[0]
# if the 2nd parameter is 'magma', magma rain for the targets instead of instant death
magma = ($script_args[1] == 'magma')
checkunit = lambda { |u| checkunit = lambda { |u|
u.body.blood_count != 0 and u.body.blood_count != 0 and
@ -9,12 +12,39 @@ checkunit = lambda { |u|
not df.map_designation_at(u).hidden not df.map_designation_at(u).hidden
} }
slayit = lambda { |u|
if not magma
# 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
else
# it's getting hot around here
# !!WARNING!! do not call on a magma-safe creature
ouh = df.onupdate_register(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
df.map_tile_at(x, y, z).spawn_magma(7)
end
}
end
}
all_races = df.world.units.active.map { |u| all_races = df.world.units.active.map { |u|
u.race_tg.creature_id if checkunit[u] u.race_tg.creature_id if checkunit[u]
}.compact.uniq.sort }.compact.uniq.sort
if !race if !race
puts all_races puts all_races
elsif race == 'him'
if him = df.unit_find
slayit[him]
else
puts "Choose target"
end
else else
raw_race = df.match_rawname(race, all_races) raw_race = df.match_rawname(race, all_races)
raise 'invalid race' if not raw_race raise 'invalid race' if not raw_race
@ -24,7 +54,7 @@ else
count = 0 count = 0
df.world.units.active.each { |u| df.world.units.active.each { |u|
if u.race == race_nr and checkunit[u] if u.race == race_nr and checkunit[u]
u.body.blood_count = 0 slayit[u]
count += 1 count += 1
end end
} }