v50 Steam/Premium information for editors
  • v50 information can now be added to pages in the main namespace. v0.47 information can still be found in the DF2014 namespace. See here for more details on the new versioning policy.
  • Use this page to report any issues related to the migration.
This notice may be cached—the current version can be found here.

Editing Utility:DFHack/Programming

Jump to navigation Jump to search

Warning: You are not logged in.
Your IP address will be recorded in this page's edit history.


The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.

Latest revision Your text
Line 1: Line 1:
 
<pre>v1.1 (see change log at the end)</pre>
 
<pre>v1.1 (see change log at the end)</pre>
 +
  
 
== INTRODUCTION ==
 
== INTRODUCTION ==
  
DFHack is a Dwarf Fortress (DF) memory access library and a set of basic tools that use it (see the documentation at https://docs.dfhack.org/en/stable/ ).
+
DFHack is a Dwarf Fortress (DF) memory access library and a set of basic tools that use it (see the readme at https://github.com/DFHack/dfhack/blob/master/Readme.rst ).
  
 
It is possible for developers to write plugins for DFHack, in order to extend the capabilities of DFHack (and therefore DF's gameplay). The plugins come mainly in two flavours:
 
It is possible for developers to write plugins for DFHack, in order to extend the capabilities of DFHack (and therefore DF's gameplay). The plugins come mainly in two flavours:
* C++ plugins: libraries written in C++ that need to be compiled. They can use DFHack's low level functions very closely, and they will be able to perform complex functions ''very'' quickly.
+
* C++ plugins: libraries written in C++, that need to be compiled. They can use DFHack's low level functions very closely.
* Lua and Ruby scripts: text-based scripts which can be dropped into place and modified on the fly. Certain things can be easier to do, and error handling is better in general, but the downside is that they can be quite ''slow'' - for example, trying to reveal the entire map from Lua may take an entire minute, while the C++ plugin can do it in a tiny fraction of a second. This document is focused entirely on plugins - if you would like to learn more about writing scripts, see https://docs.dfhack.org/en/stable/docs/Lua%20API.html
+
* Lua and Ruby scripts: placed in the right folder, they are loaded at DFHack's startup (outside of this document's scope. see more at https://github.com/DFHack/dfhack/blob/master/Lua%20API.rst )
  
This document explains how to get started at writing C++ plugins with Microsoft Visual C++ 2010, step by step. It is intended for people who are totally new to DFHack.
+
This document explains how to get started at writing C++ plugins with VisualC++ 2010, step by step. It is intended for people who are totally new to DFHack.
  
 
== Getting Dwarf Fortress ==
 
== Getting Dwarf Fortress ==
Line 20: Line 21:
  
 
You must download the sources, and build them.
 
You must download the sources, and build them.
* Follow exactly the steps described in DFHack's documentation: https://docs.dfhack.org/en/stable/docs/Compile.html
+
<blockquote>
 +
* Follow exactly the steps described in DFHack's readme : https://github.com/DFHack/dfhack/blob/master/Compile.rst
 +
</blockquote>
  
 
== Make yourself comfy ==
 
== Make yourself comfy ==
=== Windows ===
+
 
As explained in the compiling guidelines (above), there are several scripts available, that will do different things : some will just build, some will also install the results to your DF's "hack" folder. To save some time, here is how you can set up Visual C++ to do a build+install every time you press <code>F7</code>:
+
As explained in the compiling guidelines (above), there are several scripts available, that will do different things : some will just build, some will also install the results to your DF's DFHack folder. To save some time, here is to run the latter script in your VisualC++ every time you press <code>F7</code> (Generate solution):
* Open <code>dfhack.sln</code> in Visual C++
+
<blockquote>
 +
* Open <code>dfhack.sln</code> in VisualC++
 
* Right-click on the Solution, and select "Properties"
 
* Right-click on the Solution, and select "Properties"
 
* Go to "configuration properties"–&gt;"Configuration"
 
* Go to "configuration properties"–&gt;"Configuration"
 
* In the full list of projects, uncheck <code>ALL_BUILD</code>, and instead check <code>INSTALL</code>
 
* In the full list of projects, uncheck <code>ALL_BUILD</code>, and instead check <code>INSTALL</code>
 +
</blockquote>
 +
This way, it will force-build "INSTALL" every time. And guess what? That runs the install script.
  
 
== Create your very own plugin ==
 
== Create your very own plugin ==
 +
 
; What are the requirements for a plugin?
 
; What are the requirements for a plugin?
* A set of C++ source files (there can be just one if you want!)
+
<blockquote>
* The libraries (<code>.lib</code>) it will use
+
;* Its set of C++ source files (there can be just one if you want!)
* The protobufs it will use (if any!)
+
;* The libraries (<code>.lib</code>) it will use
Protobuf (protocol buffer) is a special serialization standard developed by Google, and its main use in DFHack is for communicating with other processes via TCP/IP (e.g. so you can write a separate application that communicates with DFHack to access/modify the game's memory). As such, it is outside of the scope of this document. Only a handful of plugins use that technology, such as <code>rename</code> and <code>isoworldremote</code>.
+
;* The protobufs it will use (if any!)
 +
</blockquote>
 +
Protobufs are some sort of serialization standard developed by Google. This is outside of the scope of this document. Only a handful of plugins use that technology. The <code>rename</code> and <code>isoworldremote</code> plugins do.
  
The libraries are all the 3rd-party libraries you want to use in your project. The good news is that most libraries normally used in C++ have a high probability to be already used by some other plugin. In most cases, the only special library you're going to use is going to be "lua", and only if your plugin is going to provide special functions that can be invoked from scripts.
+
The libraries are all the 3rd-party libraries you want to use in your project. The good news is that most libraries normally used in C++ have a high probability to be already used by some other plugin.
  
 +
; For example:
 +
<blockquote>
 +
;* <code>workflow</code> links to <code>Lua</code>.
 +
;* <code>dfstream</code> links to <code>dfhack-tinythread</code>.
 +
;* I believe I've seen a plugin using <code>boost</code>.
 +
;* <code>SDL</code> is available in any case.
 +
</blockquote>
 
; The first step is to add your plugin to the list of plugins :
 
; The first step is to add your plugin to the list of plugins :
* Open <code>dfhack/plugins/CMakeLists.txt</code>
+
<blockquote>
* Locate the section listing all the plugins : they start with <code>DFHACK_PLUGIN</code>
+
;* Open <code>dfhack/plugins/CMakeLists.txt</code>
* Add a line with your own plugin: <code>DFHACK_PLUGIN(myplugin myplugin.cpp)</code>, and save the file.
+
;* Locate the section listing all the plugins : they start with <code>DFHACK_PLUGIN</code>
* Create a blank file called <code>myplugin.cpp</code> in <code>dfhack/plugins</code>, alongside all the other plugins
+
;* Add a line with your own plugin: <code>DFHACK_PLUGIN(myplugin myplugin.cpp)</code> , and save the file.
 
+
;* Create a blank file called <code>myplugin.cpp</code> in <code>dfhack/plugins</code> , alongside all the other plugins
 +
</blockquote>
 
Now you need to run DFHack's awesome build scripts, to make them generate all the relevant project files for you:
 
Now you need to run DFHack's awesome build scripts, to make them generate all the relevant project files for you:
 +
<blockquote>
 +
* Close VisualStudio
 
* Observe all the batch files in <code>dfhack/build</code> starting with "generate"  
 
* Observe all the batch files in <code>dfhack/build</code> starting with "generate"  
* Run your favourite one. For example, you can choose <code>generate-MSVC-minimal.bat</code>
+
* Run your favourite one. For example you can choose <code>generate-MSVC-minimal.bat</code>
Once this finishes, Visual C++ will prompt you to reload the project if you have it open, and once you do so you'll notice that your project "myplugin" has magically appeared. However, since the source file is still blank, it's not exactly ready to compile.
+
</blockquote>
 +
Now if you re-open <code>dfhack.sln</code> (in <code>dfhack/build/VC2010/</code>) , you'll notice that your project "myplugin" has magically appeared. But its' not ready to compile yet! (the source file is empty, dummy)
  
 
== Mandatory C++ instructions ==
 
== Mandatory C++ instructions ==
  
Open any simple plugin (e.g. <code>tubefill.cpp</code> ) and observe its structure.
+
Open any simple plugin (e.g. <code>catsplosion.cpp</code> ) and observe its structure.
 +
 
 +
You'll notice all the includes for using standard data structures (lists, vectors, etc.) :
  
At the top will be a block of #include statements to allow you to use DFHack. This block can vary, but in nearly all cases it should contain the following:
+
<pre>#include &lt;iostream&gt;
 +
#include &lt;cstdlib&gt;
 +
#include &lt;assert.h&gt;
 +
#include &lt;climits&gt;
 +
#include &lt;stdlib.h&gt; // for rand()
 +
#include &lt;algorithm&gt; // for std::transform
 +
#include &lt;vector&gt;
 +
#include &lt;list&gt;
 +
#include &lt;iterator&gt;
 +
using namespace std;</pre>
 +
More interestingly, you'll notice all the includes allowing you to use DFHack:
  
<pre>#include "Core.h"
+
<pre>#include &quot;DFHack.h&quot;
#include "Console.h"
+
#include &quot;Core.h&quot;
#include "Export.h"
+
#include &quot;Console.h&quot;
#include "PluginManager.h"
+
#include &quot;Export.h&quot;
#include "DataDefs.h"
+
#include &quot;PluginManager.h&quot;
 +
#include &quot;DataDefs.h&quot;
  
 
using namespace DFHack;</pre>
 
using namespace DFHack;</pre>
 
These 5 headers are required for pretty much ''every'' plugin - depending on what you're doing, you'll want to include some extras as well.
 
 
 
Let's imagine your plugin will be a command called from DFHack's console. Well then, that command will call an actual function. It is that function that you declare here:
 
Let's imagine your plugin will be a command called from DFHack's console. Well then, that command will call an actual function. It is that function that you declare here:
  
<pre>command_result tubefill(color_ostream &amp;out, std::vector&lt;std::string&gt; &amp; params);</pre>
+
<pre>command_result catsplosion (color_ostream &amp;out, std::vector &lt;std::string&gt; &amp; parameters);</pre>
 
+
For now, the function only gets declared, we'll define it later in the source code. You'll need to do the same, by replacing <code>catsplosion</code> with <code>myplugin</code>
For now, the function only gets declared, we'll define it later in the source code. You'll need to do the same, by replacing <code>tubefill</code> with  
 
<code>myplugin</code>
 
  
 
Now, tell DFHack's global plugin engine to be aware of our plugin (so that it can load it, etc.):
 
Now, tell DFHack's global plugin engine to be aware of our plugin (so that it can load it, etc.):
  
<pre>DFHACK_PLUGIN("tubefill");</pre>
+
<pre>DFHACK_PLUGIN(&quot;catsplosion&quot;);</pre>
From now on, every time you see "tubefill", replace it with "myplugin".
+
From now on, every time you see "catsplosion", replace it with "myplugin".
  
 
; Each plugin has two central functions:
 
; Each plugin has two central functions:
* <code>DFhackCExport command_result plugin_init(color_ostream&, std::vector<PluginCommand>&)</code>. This is run when the plugin gets loaded, whether or not its command gets run from the command line.
+
<blockquote>
* <code>DFhackCExport command_result plugin_shutdown(color_ostream)&</code>. This is run when the plugin gets unloaded (i.e. when DFHack shuts down).
+
* <code>plugin_init</code>. This is run when the plugin gets loaded, whether or not its command gets run from the command line.
'''Note the <code>DFhackCExport</code> before the function signatures. This is required so that DFHack can load your plugin.'''
+
* <code>plugin_shutdown</code>. This is run when the plugin gets unloaded (i.e. when DFHack shuts down).
 +
</blockquote>
 +
You'll notice that catsplosion's <code>plugin_shutdown</code> is empty (it just returns the standardized "OK" return code : <code>CR_OK</code>). That's because the plugin is simple and doesn't need to delete objects, or close connections, or do any kind of post-processing.
  
The <code>color_ostream&</code> parameter to these functions is an output stream that prints to the DFHack console. You can use this to output debug messages when your plugin is being loaded/unloaded. (An example of using such an output stream is given in the section [http://dwarffortresswiki.org/index.php/Utility:DFHack/Programming#Simplest_possible_plugin:_Hello_world.21 Simplest possible plugin].)
+
However, catsplosion's <code>plugin_init</code> contains an important instruction, that will tell DFHack to be aware of a new custom command-line instruction:
  
The second parameter to the <code>plugin_init</code> function is important -- it is a reference to the list of available commands. You use this to add your own command which calls the <code>myplugin</code> function you declared earlier.
+
<pre>// Fill the command list with your commands.
 
+
commands.push_back(PluginCommand(
As an example, <code>tubefill</code> uses this code to add the "tubefill" command so it can be run in the console:
+
    &quot;catsplosion&quot;, &quot;Make cats just /multiply/.&quot;,
 
+
    catsplosion, false,
<pre>DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
+
    &quot;  Makes cats abnormally abundant, if you provide some base population ;)\n&quot;
{
+
));</pre>
    commands.push_back(PluginCommand("tubefill","Fill in all the adamantine tubes again.",tubefill, false,
 
        "Replenishes mined out adamantine but does not fill hollow adamantine tubes.\n"
 
        "Specify 'hollow' to fill hollow tubes, but beware glitchy HFS spawns.\n"));
 
    return CR_OK;
 
}</pre>
 
 
Details:
 
Details:
  
* <code>"tubefill"</code> will be the string to which the command line must respond, when entered.  
+
<blockquote>
* <code>tubefill</code> is the function that must be called when the command is typed into the command line.  
+
* <code>&quot;catsplosion&quot;</code> will be the string to which the command line must respond ,when entered.  
* <code>"Fill in all the adamantine tubes again."</code> and <code>"Replenishes mined out adamantine..."</code> are the "manual" that will be displayed in the help or when the command is called with the wrong parameters (see below how to test that).
+
* <code>catsplosion</code> is the function that must be called when the command is typed intot he command line.  
 
+
* <code>&quot;Make cats just multiply&quot;</code> and <code>&quot;Make cats abnormally ...&quot;</code> are the "manual" that will be displayed in the help or when the command is called with the wrong parameters (see below how to test that).
<code>tubefill</code>'s <code>plugin_shutdown</code>, however, is empty (it just returns the standardized "OK" return code : <code>CR_OK</code>). That's because the plugin is simple and doesn't need to delete objects, or close connections, or do any kind of post-processing.
+
</blockquote>
 
 
 
Finally, you'll find the actual function definition:
 
Finally, you'll find the actual function definition:
  
<pre>command_result tubefill(color_ostream &amp;out, std::vector&lt;std::string&gt; &amp; params)
+
<pre>command_result catsplosion (color_ostream &amp;out, std::vector &lt;std::string&gt; &amp; parameters)
 
{
 
{
 
     ...
 
     ...
    return CR_OK;
 
 
}
 
}
</pre>
+
return CR_OK;</pre>
 
 
 
 
 
== Simplest possible plugin: Hello world! ==
 
== Simplest possible plugin: Hello world! ==
  
Line 120: Line 141:
 
<pre>command_result myplugin (color_ostream &amp;out, std::vector &lt;std::string&gt; &amp; parameters)
 
<pre>command_result myplugin (color_ostream &amp;out, std::vector &lt;std::string&gt; &amp; parameters)
 
{
 
{
     out.print("Hello Monsieur Ouxx!\n");
+
     out.print(&quot;Hello Monsieur Ouxx!\n&quot;);
    return CR_OK;
 
 
}
 
}
</pre>
+
return CR_OK;</pre>
 
Please note that you have other outputs available:
 
Please note that you have other outputs available:
  
<pre>out.printerr("Oh my gosh, this is an error.\n");</pre>
+
<pre>out.printerr(&quot;Oh my gosh, this is an error.\n&quot;);</pre>
 
You can now test your plugin : Press F7, then run DF and enter "myplugin" in the DFHack console. You should see the message "Hello Monsieur Ouxx!".
 
You can now test your plugin : Press F7, then run DF and enter "myplugin" in the DFHack console. You should see the message "Hello Monsieur Ouxx!".
  
Line 138: Line 158:
 
     for(size_t i = 0; i &lt; parameters.size();i++)
 
     for(size_t i = 0; i &lt; parameters.size();i++)
 
     {
 
     {
         if(parameters[i] == "param1")
+
         if(parameters[i] == &quot;param1&quot;)
 
             param1_ok = true;
 
             param1_ok = true;
         else if(parameters[i] == "param2")
+
         else if(parameters[i] == &quot;param2&quot;)
 
             param2_ok = true;
 
             param2_ok = true;
 
         else
 
         else
Line 158: Line 178:
 
     if (parameters.size() == 1 &amp;&amp; toLower(parameters[0])[0] == 'v')
 
     if (parameters.size() == 1 &amp;&amp; toLower(parameters[0])[0] == 'v')
 
     {
 
     {
         out &lt;&lt; "Building Plan" &lt;&lt; endl &lt;&lt; "Version: " &lt;&lt; PLUGIN_VERSION &lt;&lt; endl;
+
         out &lt;&lt; &quot;Building Plan&quot; &lt;&lt; endl &lt;&lt; &quot;Version: &quot; &lt;&lt; PLUGIN_VERSION &lt;&lt; endl;
 
     }
 
     }
     else if (parameters.size() == 2 &amp;&amp; toLower(parameters[0]) == "debug")
+
     else if (parameters.size() == 2 &amp;&amp; toLower(parameters[0]) == &quot;debug&quot;)
 
     {
 
     {
         show_debugging = (toLower(parameters[1]) == "on");
+
         show_debugging = (toLower(parameters[1]) == &quot;on&quot;);
         out &lt;&lt; "Debugging " &lt;&lt; ((show_debugging) ? "enabled" : "disabled") &lt;&lt; endl;
+
         out &lt;&lt; &quot;Debugging &quot; &lt;&lt; ((show_debugging) ? &quot;enabled&quot; : &quot;disabled&quot;) &lt;&lt; endl;
 
     }         
 
     }         
 
}</pre>
 
}</pre>
  
== Suspend the core! ==
+
== Suspend the core!!!!!111!!11 ==
  
This might be the MOST IMPORTANT section in this document. Never ever forget to suspend the game's core execution before you manipulate anything in its internal data. It is done by adding the following statement:
+
This might be the MOST IMPORTANT section in this document. Never ever forget to suspend the game's core execution before you manipulate anything in its internal data. It is done by running the following instruction:
  
 
<pre>CoreSuspender suspend;</pre>
 
<pre>CoreSuspender suspend;</pre>
 +
You will observe that most plugins actually start with that instruction. Fortunately, our "Hello world" plugin doesn't manipulate any internal data, so we didn't need that. But that's about to change.
  
There is no need to actually ''do'' anything with this variable - simply declaring it will cause Dwarf Fortress to be suspended, and once the variable goes out of scope (e.g. when the plugin function returns), the game will be unsuspended.
+
== Create your own view screen ==
 
 
You will observe that most plugins actually start with that instruction. Fortunately, our "Hello world" plugin doesn't manipulate any internal data, so we didn't need that. But that's about to change.
 
  
== Create your own viewscreen ==
+
Many plugins consist in adding menus to DF in order to extend capabilities (or, at least, sort out DF's mess ;) ).
  
Many plugins add menus to DF in order to extend capabilities (or, at least, sort out DF's mess). A good example of that is the plugin <code>buildingplan</code>. It displays a menu with lists of materials, and allows to filter the materials. Lists and filters. That's what DF is all about!
+
A good example of that is plugin <code>buildingplan</code>. It displays a menu with lists of materials, and allows to filter the materials. Lists and filters. That's what DF is all about! ;)
  
[[File:DFHack_Plugin-_buildingplan_screenshot.png|300px]]
+
http://imageshack.us/a/img28/4686/materials.png
  
You make them fit into a "viewscreen", that is: an additional screen that will fit into DF. This section is about creating a NEW viewscreen, not replacing one already existing in DF.
+
You make them fit into a "view screen", that is: an additional screen that will fit into DF. This section is about creating a NEW viewscreen, not replacing one already existing in DF.
  
 
Have a look at class <code>ViewscreenChooseMaterial</code> : it extends DFHack-provided class <code>dfhack_viewscreen</code>:
 
Have a look at class <code>ViewscreenChooseMaterial</code> : it extends DFHack-provided class <code>dfhack_viewscreen</code>:
Line 205: Line 224:
 
Notice how <code>render</code> calls the overridden function of its parent class.
 
Notice how <code>render</code> calls the overridden function of its parent class.
  
You will find more examples in the plugin <code>manipulator</code>. Have a look at class <code>viewscreen_unitlaborsst</code>.
+
You will find more examples in plugin <code>manipulator</code>. Have a look at class <code>viewscreen_unitlaborsst</code>
  
 
See also: "Replacing an existing view screen"
 
See also: "Replacing an existing view screen"
Line 211: Line 230:
 
== Manipulate the display ==
 
== Manipulate the display ==
  
Once your viewscreen is up and running with its very own <code>render</code> function, you may do whatever you please with the display:
+
Once your view screen is up and running, with its very own <code>render</code> function, you may do whatever you please with the display:
  
 
<pre>Screen::clear();                                    //delete the screen
 
<pre>Screen::clear();                                    //delete the screen
Screen::drawBorder(" Building Material  ");        //create a new DF-style screen, with a title and a border
+
Screen::drawBorder(&quot; Building Material  &quot;);        //create a new DF-stryle screen, with a title and a border
  
 
masks_column.display(selected_column == 0);        //display our column (read this tutorial further)
 
masks_column.display(selected_column == 0);        //display our column (read this tutorial further)
  
 
int32_t y = gps-&gt;dimy - 3;                          //do some calculation on the window size, to position stuff
 
int32_t y = gps-&gt;dimy - 3;                          //do some calculation on the window size, to position stuff
OutputHotkeyString(2, y, "Toggle", "Enter");        //define some hotkey
+
OutputHotkeyString(2, y, &quot;Toggle&quot;, &quot;Enter&quot;);        //define some hotkey
 
x += 3;
 
x += 3;
OutputHotkeyString(x, y, "Save", "Shift-Enter");</pre>
+
OutputHotkeyString(x, y, &quot;Save&quot;, &quot;Shift-Enter&quot;);</pre>
 +
== List columns ==
  
== List columns ==
+
In class <code>ViewscreenChooseMaterial</code> 's private members, you'll see this:
In class <code>ViewscreenChooseMaterial</code>'s private members, you'll see this:
 
  
 
<pre>ListColumn&lt;df::dfhack_material_category&gt; masks_column;</pre>
 
<pre>ListColumn&lt;df::dfhack_material_category&gt; masks_column;</pre>
 
 
<code>ListColumn</code> is a template provided by DFHack. Just feed it with anything you like.
 
<code>ListColumn</code> is a template provided by DFHack. Just feed it with anything you like.
  
 
== Manipulating DF's data ==
 
== Manipulating DF's data ==
  
Start with observing the class <code>ItemFilter</code>. You'll notice that DF exposes pretty much every possible type of object/item from the game. And what DF doesn't, DFHack does. You'll immediately notice these:
+
Start with observing class <code>ItemFilter</code>. You'll notice that DF exposes pretty much every possible type of object/item from the game. And what DF doesn't, DFHack does. You'll immediately notice these:: df::dfhack_material_category DFHack::MaterialInfo df::enums::item
 
+
<blockquote>etc.
* df::dfhack_material_category
+
</blockquote>
* MaterialInfo
 
* df::item_quality
 
 
 
 
Have a look at <code>vector&lt;string&gt; getMaterialFilterAsVector()</code>. It shows you how to get the description from a material, as a string:
 
Have a look at <code>vector&lt;string&gt; getMaterialFilterAsVector()</code>. It shows you how to get the description from a material, as a string:
  
Line 244: Line 259:
 
if (descriptions.size() == 0)
 
if (descriptions.size() == 0)
 
     bitfield_to_string(&amp;descriptions, mat_mask);</pre>
 
     bitfield_to_string(&amp;descriptions, mat_mask);</pre>
 +
<blockquote>
  
 
== Managing speed ==
 
== Managing speed ==
Line 262: Line 278:
 
}</pre>
 
}</pre>
  
== Modifying an existing viewscreen ==
+
== Replacing an existing view screen ==
Maybe you don't want to add an additional viewscreen, but instead add features to one that already exists in DF. In that case, creating a child to <code>dfhack_viewscreen</code>` (as seen in section "Create your own view screen") and implementing <code>render</code> and <code>feed</code> is not enough. Instead, you need to create a child of DF's actual viewscreen and '''interpose''' those two functions in it.
+
</blockquote>
 +
Maybe you don't want to add an additional view screen, but instead add features to one that already exists in DF. In that case, creating a child to <code>dfhack_viewscreen</code>` (as seen in section "Create your own view screen") and overriding <code>render</code> and <code>feed</code> is not enough. You need to "interpose" those two functions in the global DF system.
  
 
That's the case of class <code>buildingplan_hook</code> in plugin <code>buildingplan</code>.
 
That's the case of class <code>buildingplan_hook</code> in plugin <code>buildingplan</code>.
Line 276: Line 293:
 
{
 
{
 
     ...
 
     ...
}
 
  
 
DEFINE_VMETHOD_INTERPOSE(void, render, ())
 
DEFINE_VMETHOD_INTERPOSE(void, render, ())
Line 286: Line 302:
 
<pre>IMPLEMENT_VMETHOD_INTERPOSE(buildingplan_hook, feed);
 
<pre>IMPLEMENT_VMETHOD_INTERPOSE(buildingplan_hook, feed);
 
IMPLEMENT_VMETHOD_INTERPOSE(buildingplan_hook, render);</pre>
 
IMPLEMENT_VMETHOD_INTERPOSE(buildingplan_hook, render);</pre>
 +
Note: That would need more explanations.
  
Note that this will completely ''replace'' the original viewscreen logic with whatever you provide - in order to call the original code (e.g. for the usual default behavior), you can do "INTERPOSE_NEXT(function_name)(args);". Depending on how the original viewscreen works, you'll have to make sure you do it in the right place.
+
See also: "Create your own view screen"
 
 
See also: "Create your own viewscreen"
 
  
 
== CHANGE LOG ==
 
== CHANGE LOG ==
 +
<blockquote>
 
* v1.0 Redaction
 
* v1.0 Redaction
 
* v1.1
 
* v1.1
 
** moved "return CR_OK;" in one of the code snippets
 
** moved "return CR_OK;" in one of the code snippets
 
** corrected a mistake about the need of using "DEFINE_VMETHOD_INTERPOSE"
 
** corrected a mistake about the need of using "DEFINE_VMETHOD_INTERPOSE"
 +
</blockquote>

Please note that all contributions to Dwarf Fortress Wiki are considered to be released under the GFDL & MIT (see Dwarf Fortress Wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To protect the wiki against automated edit spam, we kindly ask you to solve the following CAPTCHA:

Cancel Editing help (opens in new window)