Merge branch 'master' of github.com/quietust/dfhack

develop
jj 2013-12-24 14:07:08 +01:00
commit ce33973f0f
19 changed files with 344 additions and 143 deletions

@ -565,7 +565,7 @@ static int dfhack_matinfo_find(lua_State *state)
{ {
std::vector<std::string> tokens; std::vector<std::string> tokens;
for (int i = 1; i < argc; i++) for (int i = 1; i <= argc; i++)
tokens.push_back(luaL_checkstring(state, i)); tokens.push_back(luaL_checkstring(state, i));
info.find(tokens); info.find(tokens);

@ -42,11 +42,14 @@ using namespace std;
#include "MiscUtils.h" #include "MiscUtils.h"
#include "VTableInterpose.h"
#include "DataDefs.h" #include "DataDefs.h"
#include "df/world.h" #include "df/world.h"
#include "df/historical_figure.h" #include "df/historical_figure.h"
#include "df/map_block.h" #include "df/map_block.h"
#include "df/block_square_event_world_constructionst.h" #include "df/block_square_event_world_constructionst.h"
#include "df/viewscreen_legendsst.h"
using namespace DFHack; using namespace DFHack;
using namespace df::enums; using namespace df::enums;
@ -154,14 +157,51 @@ static PersistentDataItem dataFromHFig(df::historical_figure *hfig)
return PersistentDataItem(hfig->id, hfig->name.first_name, &hfig->name.nickname, hfig->name.words); return PersistentDataItem(hfig->id, hfig->name.first_name, &hfig->name.nickname, hfig->name.words);
} }
// Hide fake histfigs from legends xml export
static bool in_export_xml = false;
struct hide_fake_histfigs_hook : df::viewscreen_legendsst {
typedef df::viewscreen_legendsst interpose_base;
DEFINE_VMETHOD_INTERPOSE(void, feed, (set<df::interface_key> *input))
{
if (input->count(interface_key::LEGENDS_EXPORT_XML))
{
auto &figs = df::historical_figure::get_vector();
auto it = figs.begin();
while (it != figs.end() && (*it)->id <= -100)
++it;
// Move our histfigs to a temporary vector
std::vector<df::historical_figure*> fakes(figs.begin(), it);
figs.erase(figs.begin(), it);
in_export_xml = true;
INTERPOSE_NEXT(feed)(input);
in_export_xml = false;
figs.insert(figs.begin(), fakes.begin(), fakes.end());
}
else
INTERPOSE_NEXT(feed)(input);
}
};
IMPLEMENT_VMETHOD_INTERPOSE_PRIO(hide_fake_histfigs_hook, feed, -10000);
void World::ClearPersistentCache() void World::ClearPersistentCache()
{ {
next_persistent_id = 0; next_persistent_id = 0;
persistent_index.clear(); persistent_index.clear();
INTERPOSE_HOOK(hide_fake_histfigs_hook, feed).apply(Core::getInstance().isWorldLoaded());
} }
static bool BuildPersistentCache() static bool BuildPersistentCache()
{ {
if (in_export_xml)
return false;
if (next_persistent_id) if (next_persistent_id)
return true; return true;
if (!Core::getInstance().isWorldLoaded()) if (!Core::getInstance().isWorldLoaded())

@ -1 +1 @@
Subproject commit e62d498e68e3a87929b144220d03e691016f7aae Subproject commit d6bcaa991cfe9ab5a8031b1721d548a73258d7ed

@ -377,6 +377,7 @@ struct GeoLayer
int16_t material; int16_t material;
bool is_soil; bool is_soil;
bool is_soil_layer;
// World-global origin coordinates in blocks // World-global origin coordinates in blocks
df::coord world_pos; df::coord world_pos;
@ -489,6 +490,7 @@ GeoLayer::GeoLayer(GeoBiome *parent, int index, df::world_geo_layer *info)
tiles = unmined_tiles = mineral_tiles = 0; tiles = unmined_tiles = mineral_tiles = 0;
material = info->mat_index; material = info->mat_index;
is_soil = isSoilInorganic(material); is_soil = isSoilInorganic(material);
is_soil_layer = (info->type == geo_layer_type::SOIL || info->type == geo_layer_type::SOIL_SAND);
} }
const unsigned NUM_INCLUSIONS = 1+(int)ENUM_LAST_ITEM(inclusion_type); const unsigned NUM_INCLUSIONS = 1+(int)ENUM_LAST_ITEM(inclusion_type);
@ -721,14 +723,17 @@ bool VeinGenerator::scan_layer_depth(Block *b, df::coord2d column, int z)
auto &top_solid = col_info.top_solid_z[x][y]; auto &top_solid = col_info.top_solid_z[x][y];
auto &bottom = col_info.bottom_layer[x][y]; auto &bottom = col_info.bottom_layer[x][y];
if (top_solid < 0 && isWallTerrain(b->baseTiletypeAt(tile))) auto ttype = b->baseTiletypeAt(tile);
bool obsidian = (tileMaterial(ttype) == tiletype_material::LAVA_STONE);
if (top_solid < 0 && !obsidian && isWallTerrain(ttype))
top_solid = z; top_solid = z;
if (max_level[idx] < 0) if (max_level[idx] < 0)
{ {
// Do not start the layer stack in open air. // Do not start the layer stack in open air.
// Those tiles can be very weird. // Those tiles can be very weird.
if (bottom < 0 && isOpenTerrain(b->baseTiletypeAt(tile))) if (bottom < 0 && (isOpenTerrain(ttype) || obsidian))
continue; continue;
max_level[idx] = min_level[idx] = z; max_level[idx] = min_level[idx] = z;
@ -777,9 +782,14 @@ bool VeinGenerator::adjust_layer_depth(df::coord2d column)
if (max_defined < 0) if (max_defined < 0)
continue; continue;
int last_top = min_defined;
// Verify assumptions // Verify assumptions
for (int i = min_defined; i < max_defined; i++) for (int i = min_defined; i < max_defined; i++)
{ {
if (max_level[i] >= top_solid)
last_top = i;
if (max_level[i+1] < 0 && min_level[i] > top_solid) if (max_level[i+1] < 0 && min_level[i] > top_solid)
max_level[i+1] = min_level[i+1] = min_level[i]; max_level[i+1] = min_level[i+1] = min_level[i];
@ -815,6 +825,22 @@ bool VeinGenerator::adjust_layer_depth(df::coord2d column)
continue; continue;
} }
// If below a thick soil layer, allow thickness to pass from prev to current.
// This accounts for a probable bug in worldgen soil placement code.
if (i > min_defined && i-1 <= last_top)
{
auto prev = biome->layers[i-1];
if (size > layer->thickness &&
prev->is_soil_layer && prev->thickness > 1 &&
size <= layer->thickness+prev->thickness-1)
{
max_level[i] += layer->thickness - size;
layer->setZBias(size - layer->thickness);
continue;
}
}
out.printerr( out.printerr(
"Layer height change in layer %d at (%d,%d,%d): %d instead of %d.\n", "Layer height change in layer %d at (%d,%d,%d): %d instead of %d.\n",
i, x+column.x*16, y+column.y*16, max_level[i], i, x+column.x*16, y+column.y*16, max_level[i],

@ -626,7 +626,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
commands.push_back( commands.push_back(
PluginCommand( PluginCommand(
"autotrade", "Automatically send items in marked stockpiles to trade depot, when trading is possible.", "autotrade", "Automatically send items in marked stockpiles to trade depot, when trading is possible.",
autotrade_cmd, false, "")); autotrade_cmd, false, "Run 'autotrade version' to query the plugin version."));
return CR_OK; return CR_OK;
} }

@ -1183,7 +1183,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
commands.push_back( commands.push_back(
PluginCommand( PluginCommand(
"buildingplan", "Place furniture before it's built", "buildingplan", "Place furniture before it's built",
buildingplan_cmd, false, "")); buildingplan_cmd, false, "Run 'buildingplan debug [on|off]' to toggle debugging, or 'buildingplan version' to query the plugin version."));
planner.initialize(); planner.initialize();
return CR_OK; return CR_OK;

@ -37,7 +37,14 @@ command_result df_createitem (color_ostream &out, vector <string> & parameters);
DFhackCExport command_result plugin_init (color_ostream &out, std::vector<PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector<PluginCommand> &commands)
{ {
commands.push_back(PluginCommand("createitem", "Create arbitrary item at the selected unit's feet.", df_createitem)); commands.push_back(PluginCommand("createitem", "Create arbitrary item at the selected unit's feet.", df_createitem, false,
"Syntax: createitem <item> <material> [count]\n"
" <item> - Item token for what you wish to create, as specified in custom\n"
" reactions. If the item has no subtype, omit the :NONE.\n"
" <material> - The material you want the item to be made of, as specified\n"
" in custom reactions. For REMAINS, FISH, FISH_RAW, VERMIN,\n"
" PET, and EGG, replace this with a creature ID and caste.\n"
" [count] - How many of the item you wish to create.\n"));
return CR_OK; return CR_OK;
} }
@ -91,17 +98,7 @@ command_result df_createitem (color_ostream &out, vector <string> & parameters)
int count = 1; int count = 1;
if ((parameters.size() < 2) || (parameters.size() > 3)) if ((parameters.size() < 2) || (parameters.size() > 3))
{
out.print("Syntax: createitem <item> <material> [count]\n"
" <item> - Item token for what you wish to create, as specified in custom\n"
" reactions. If the item has no subtype, omit the :NONE.\n"
" <material> - The material you want the item to be made of, as specified\n"
" in custom reactions. For REMAINS, FISH, FISH_RAW, VERMIN,\n"
" PET, and EGG, replace this with a creature ID and caste.\n"
" [count] - How many of the item you wish to create.\n"
);
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
}
item_str = parameters[0]; item_str = parameters[0];
material_str = parameters[1]; material_str = parameters[1];

@ -1,4 +1,5 @@
#include "Core.h" #include "Core.h"
#include "Error.h"
#include <Console.h> #include <Console.h>
#include <Export.h> #include <Export.h>
#include <PluginManager.h> #include <PluginManager.h>
@ -228,8 +229,8 @@ static void enableEvent(int evType,int freq)
{ {
if (freq < 0) if (freq < 0)
return; return;
if (evType < 0 || evType >= EventManager::EventType::EVENT_MAX || evType == EventManager::EventType::TICK) CHECK_INVALID_ARGUMENT(evType >= 0 && evType < EventManager::EventType::EVENT_MAX &&
throw std::runtime_error("invalid event type to enable"); evType != EventManager::EventType::TICK);
EventManager::EventHandler::callback_t fun_ptr = eventHandlers[evType]; EventManager::EventHandler::callback_t fun_ptr = eventHandlers[evType];
EventManager::EventType::EventType typeToEnable=static_cast<EventManager::EventType::EventType>(evType); EventManager::EventType::EventType typeToEnable=static_cast<EventManager::EventType::EventType>(evType);

@ -58,6 +58,7 @@ command_result lair(color_ostream &out, std::vector<std::string> & params)
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.push_back(PluginCommand("lair","Mark the map as a monster lair, preventing item scatter ('lair reset' reverts that).",lair)); commands.push_back(PluginCommand("lair","Mark the map as a monster lair, preventing item scatter.",lair, false,
"Usage: 'lair' to mark entire map as monster lair, 'lair reset' to undo the operation.\n"));
return CR_OK; return CR_OK;
} }

@ -59,12 +59,16 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
liquids_hist.load("liquids.history"); liquids_hist.load("liquids.history");
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"liquids", "Place magma, water or obsidian.", "liquids", "Place magma, water or obsidian.",
df_liquids, true)); // interactive, needs console for prompt df_liquids, true,
"This tool allows placing magma, water and other similar things.\n"
"It is interactive and further help is available when you run it.\n"
"The settings will be remembered until dfhack is closed and you can call\n"
"'liquids-here' (mapped to a hotkey) to paint liquids at the cursor position\n"
"without the need to go back to the dfhack console.\n")); // interactive, needs console for prompt
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
"liquids-here", "Use settings from liquids at cursor position.", "liquids-here", "Use settings from liquids at cursor position.",
df_liquids_here, Gui::cursor_hotkey, // non-interactive, needs ingame cursor df_liquids_here, Gui::cursor_hotkey, // non-interactive, needs ingame cursor
" Identical to pressing enter in liquids, intended for use as keybinding.\n" " This command is intended to be mapped to a hotkey and is identical to pressing Enter in liquids with the current parameters.\n"));
" Can (but doesn't need to) be called while liquids is running in the console."));
return CR_OK; return CR_OK;
} }
@ -157,14 +161,7 @@ command_result df_liquids (color_ostream &out_, vector <string> & parameters)
for(size_t i = 0; i < parameters.size();i++) for(size_t i = 0; i < parameters.size();i++)
{ {
if(parameters[i] == "help" || parameters[i] == "?") if(parameters[i] == "help" || parameters[i] == "?")
{ return CR_WRONG_USAGE;
out.print( "This tool allows placing magma, water and other similar things.\n"
"It is interactive and further help is available when you run it.\n"
"The settings will be remembered until dfhack is closed and you can call\n"
"'liquids-here' (mapped to a hotkey) to paint liquids at the cursor position\n"
"without the need to go back to the dfhack console.\n");
return CR_OK;
}
} }
if (!Maps::IsValid()) if (!Maps::IsValid())
@ -375,11 +372,7 @@ command_result df_liquids_here (color_ostream &out, vector <string> & parameters
for(size_t i = 0; i < parameters.size();i++) for(size_t i = 0; i < parameters.size();i++)
{ {
if(parameters[i] == "help" || parameters[i] == "?") if(parameters[i] == "help" || parameters[i] == "?")
{ return CR_WRONG_USAGE;
out << "This command is supposed to be mapped to a hotkey." << endl;
out << "It will use the current/last parameters set in liquids." << endl;
return CR_OK;
}
} }
out.print("Run liquids-here with these parameters: "); out.print("Run liquids-here with these parameters: ");

@ -22,25 +22,8 @@ using df::global::world;
const uint32_t sapling_to_tree_threshold = 120 * 28 * 12 * 3; // 3 years const uint32_t sapling_to_tree_threshold = 120 * 28 * 12 * 3; // 3 years
command_result df_grow (color_ostream &out, vector <string> & parameters);
command_result df_immolate (color_ostream &out, vector <string> & parameters);
command_result df_extirpate (color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("plants"); DFHACK_PLUGIN("plants");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand("grow", "Grows saplings into trees (with active cursor, only the targetted one).", df_grow));
commands.push_back(PluginCommand("immolate", "Set plants on fire (under cursor, 'shrubs', 'trees' or 'all').", df_immolate));
commands.push_back(PluginCommand("extirpate", "Kill plants (same mechanics as immolate).", df_extirpate));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
return CR_OK;
}
enum do_what enum do_what
{ {
do_immolate, do_immolate,
@ -84,19 +67,8 @@ static bool getoptions( vector <string> & parameters, bool & shrubs, bool & tree
*/ */
static command_result immolations (color_ostream &out, do_what what, bool shrubs, bool trees, bool help) static command_result immolations (color_ostream &out, do_what what, bool shrubs, bool trees, bool help)
{ {
static const char * what1 = "destroys";
static const char * what2 = "burns";
if(help) if(help)
{ return CR_WRONG_USAGE;
out.print("Without any options, this command %s a plant under the cursor.\n"
"Options:\n"
"shrubs - affect all shrubs\n"
"trees - affect all trees\n"
"all - affect all plants\n",
what == do_immolate? what2 : what1
);
return CR_OK;
}
CoreSuspender suspend; CoreSuspender suspend;
if (!Maps::IsValid()) if (!Maps::IsValid())
{ {
@ -165,26 +137,26 @@ command_result df_immolate (color_ostream &out, vector <string> & parameters)
bool shrubs = false, trees = false, help = false; bool shrubs = false, trees = false, help = false;
if(getoptions(parameters,shrubs,trees,help)) if(getoptions(parameters,shrubs,trees,help))
{ {
return immolations(out,do_immolate,shrubs,trees, help); return immolations(out,do_immolate,shrubs,trees,help);
} }
else else
{ {
out.printerr("Invalid parameter!\n"); out.printerr("Invalid parameter!\n");
return CR_FAILURE; return CR_WRONG_USAGE;
} }
} }
command_result df_extirpate (color_ostream &out, vector <string> & parameters) command_result df_extirpate (color_ostream &out, vector <string> & parameters)
{ {
bool shrubs = false, trees = false, help = false; bool shrubs = false, trees = false, help = false;
if(getoptions(parameters,shrubs,trees, help)) if(getoptions(parameters,shrubs,trees,help))
{ {
return immolations(out,do_extirpate,shrubs,trees, help); return immolations(out,do_extirpate,shrubs,trees,help);
} }
else else
{ {
out.printerr("Invalid parameter!\n"); out.printerr("Invalid parameter!\n");
return CR_FAILURE; return CR_WRONG_USAGE;
} }
} }
@ -193,10 +165,7 @@ command_result df_grow (color_ostream &out, vector <string> & parameters)
for(size_t i = 0; i < parameters.size();i++) for(size_t i = 0; i < parameters.size();i++)
{ {
if(parameters[i] == "help" || parameters[i] == "?") if(parameters[i] == "help" || parameters[i] == "?")
{ return CR_WRONG_USAGE;
out.print("This command turns all living saplings into full-grown trees.\n");
return CR_OK;
}
} }
CoreSuspender suspend; CoreSuspender suspend;
@ -245,3 +214,123 @@ command_result df_grow (color_ostream &out, vector <string> & parameters)
return CR_OK; return CR_OK;
} }
command_result df_createplant (color_ostream &out, vector <string> & parameters)
{
if ((parameters.size() != 1) || (parameters[0] == "help" || parameters[0] == "?"))
return CR_WRONG_USAGE;
CoreSuspender suspend;
if (!Maps::IsValid())
{
out.printerr("Map is not available!\n");
return CR_FAILURE;
}
int32_t x,y,z;
if(!Gui::getCursorCoords(x,y,z))
{
out.printerr("No cursor detected - please place the cursor over the location in which you wish to create a new plant.\n");
return CR_FAILURE;
}
df::map_block *map = Maps::getTileBlock(x, y, z);
if (!map)
{
out.printerr("Invalid location selected!\n");
return CR_FAILURE;
}
int tx = x & 15, ty = y & 15;
int mat = tileMaterial(map->tiletype[tx][ty]);
if ((tileShape(map->tiletype[tx][ty]) != tiletype_shape::FLOOR) || ((mat != tiletype_material::SOIL) && (mat != tiletype_material::GRASS_DARK) && (mat != tiletype_material::GRASS_LIGHT)))
{
out.printerr("Plants can only be placed on dirt or grass floors!\n");
return CR_FAILURE;
}
int plant_id = -1;
df::plant_raw *plant_raw = NULL;
for (size_t i = 0; i < world->raws.plants.all.size(); i++)
{
plant_raw = world->raws.plants.all[i];
if (plant_raw->id == parameters[0])
{
plant_id = i;
break;
}
}
if (plant_id == -1)
{
out.printerr("Invalid plant ID specified!\n");
return CR_FAILURE;
}
if (plant_raw->flags.is_set(plant_raw_flags::GRASS))
{
out.printerr("You cannot plant grass using this command.\n");
return CR_FAILURE;
}
df::plant *plant = df::allocate<df::plant>();
if (plant_raw->flags.is_set(plant_raw_flags::TREE))
plant->hitpoints = 400000;
else
{
plant->hitpoints = 100000;
plant->flags.bits.is_shrub = 1;
}
// for now, always set "watery" for WET-permitted plants, even if they're spawned away from water
// the proper method would be to actually look for nearby water features, but it's not clear exactly how that works
if (plant_raw->flags.is_set(plant_raw_flags::WET))
plant->flags.bits.watery = 1;
plant->material = plant_id;
plant->pos.x = x;
plant->pos.y = y;
plant->pos.z = z;
plant->update_order = rand() % 10;
plant->temperature_tile_tick = -1;
plant->temperature_tile = 60001;
plant->min_safe_temp = 9900;
plant->max_safe_temp = 60001;
world->plants.all.push_back(plant);
switch (plant->flags.whole & 3)
{
case 0: world->plants.tree_dry.push_back(plant); break;
case 1: world->plants.tree_wet.push_back(plant); break;
case 2: world->plants.shrub_dry.push_back(plant); break;
case 3: world->plants.shrub_wet.push_back(plant); break;
}
map->plants.push_back(plant);
if (plant->flags.bits.is_shrub)
map->tiletype[tx][ty] = tiletype::Shrub;
else
map->tiletype[tx][ty] = tiletype::Sapling;
return CR_OK;
}
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand("grow", "Grows saplings into trees (with active cursor, only the targetted one).", df_grow, false,
"This command turns all living saplings on the map into full-grown trees.\n"));
commands.push_back(PluginCommand("immolate", "Set plants on fire (under cursor, 'shrubs', 'trees' or 'all').", df_immolate, false,
"Without any options, this command burns a plant under the cursor.\n"
"Options:\n"
"shrubs - affect all shrubs\n"
"trees - affect all trees\n"
"all - affect all plants\n"));
commands.push_back(PluginCommand("extirpate", "Kill plants (same mechanics as immolate).", df_extirpate, false,
"Without any options, this command destroys a plant under the cursor.\n"
"Options:\n"
"shrubs - affect all shrubs\n"
"trees - affect all trees\n"
"all - affect all plants\n"));
commands.push_back(PluginCommand("createplant", "Create a new plant at the cursor.", df_createplant, false,
"Specify the type of plant to create by its raw ID (e.g. TOWER_CAP or MUSHROOM_HELMET_PLUMP).\n"
"Only shrubs and saplings can be placed, and they must be located on a dirt or grass floor.\n"));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
return CR_OK;
}

@ -46,13 +46,19 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
{ {
commands.push_back(PluginCommand("probe", commands.push_back(PluginCommand("probe",
"A tile probe", "A tile probe",
df_probe)); df_probe,
false,
"Hover the cursor over a tile to view its properties.\n"));
commands.push_back(PluginCommand("cprobe", commands.push_back(PluginCommand("cprobe",
"A creature probe", "A creature probe",
df_cprobe)); df_cprobe,
false,
"Select a creature to view its properties.\n"));
commands.push_back(PluginCommand("bprobe", commands.push_back(PluginCommand("bprobe",
"A simple building probe", "A simple building probe",
df_bprobe)); df_bprobe,
false,
"Select a building to view its properties.\n"));
return CR_OK; return CR_OK;
} }

@ -234,11 +234,18 @@ static coord2d biome_delta[] = {
struct EmbarkTileLayout { struct EmbarkTileLayout {
coord2d biome_off, biome_pos; coord2d biome_off, biome_pos;
df::region_map_entry *biome; df::region_map_entry *biome;
df::world_geo_biome *geo_biome;
int elevation, max_soil_depth; int elevation, max_soil_depth;
int min_z, base_z; int min_z, base_z;
std::map<int, float> penalty; std::map<int, float> penalty;
}; };
static df::world_region_details *get_details(df::world_data *data, df::coord2d pos)
{
int d_idx = linear_index(data->region_details, &df::world_region_details::pos, pos);
return vector_get(data->region_details, d_idx);
}
bool estimate_underground(color_ostream &out, EmbarkTileLayout &tile, df::world_region_details *details, int x, int y) bool estimate_underground(color_ostream &out, EmbarkTileLayout &tile, df::world_region_details *details, int x, int y)
{ {
// Find actual biome // Find actual biome
@ -251,15 +258,37 @@ bool estimate_underground(color_ostream &out, EmbarkTileLayout &tile, df::world_
tile.biome_pos = coord2d(bx, by); tile.biome_pos = coord2d(bx, by);
tile.biome = &data->region_map[bx][by]; tile.biome = &data->region_map[bx][by];
tile.geo_biome = df::world_geo_biome::find(tile.biome->geo_index);
// Compute surface elevation // Compute surface elevation
tile.elevation = ( tile.elevation = details->elevation[x][y];
details->elevation[x][y] + details->elevation[x][y+1] + tile.max_soil_depth = std::max((154-tile.elevation)/5,1);
details->elevation[x+1][y] + details->elevation[x+1][y+1]
) / 4;
tile.max_soil_depth = std::max((154-tile.biome->elevation)/5,0);
tile.base_z = tile.elevation;
tile.penalty.clear(); tile.penalty.clear();
// Special biome adjustments
if (!tile.biome->flags.is_set(region_map_entry_flags::is_lake))
{
// Mountain biome
if (tile.biome->elevation >= 150)
tile.max_soil_depth = 0;
// Ocean biome
else if (tile.biome->elevation < 100)
{
if (tile.elevation == 99)
tile.elevation = 98;
if (tile.geo_biome && (tile.geo_biome->unk1 == 4 || tile.geo_biome->unk1 == 5))
{
auto b_details = get_details(data, tile.biome_pos);
if (b_details && b_details->unk12e8 < 500)
tile.max_soil_depth = 0;
}
}
}
tile.base_z = tile.elevation-1;
auto &features = details->features[x][y]; auto &features = details->features[x][y];
// Collect global feature layer depths and apply penalties // Collect global feature layer depths and apply penalties
@ -301,8 +330,8 @@ bool estimate_underground(color_ostream &out, EmbarkTileLayout &tile, df::world_
if (!sea_found) if (!sea_found)
{ {
out.printerr("Could not find magma sea.\n"); out.printerr("Could not find magma sea; depth may be incorrect.\n");
return false; tile.min_z = tile.base_z;
} }
// Scan for big local features and apply their penalties // Scan for big local features and apply their penalties
@ -340,7 +369,7 @@ bool estimate_materials(color_ostream &out, EmbarkTileLayout &tile, MatMap &laye
{ {
using namespace geo_layer_type; using namespace geo_layer_type;
df::world_geo_biome *geo_biome = df::world_geo_biome::find(tile.biome->geo_index); df::world_geo_biome *geo_biome = tile.geo_biome;
if (!geo_biome) if (!geo_biome)
{ {
@ -350,35 +379,58 @@ bool estimate_materials(color_ostream &out, EmbarkTileLayout &tile, MatMap &laye
} }
// soil depth increases by 1 every 5 levels below 150 // soil depth increases by 1 every 5 levels below 150
int top_z_level = tile.elevation - tile.max_soil_depth; unsigned nlayers = std::min<unsigned>(16, geo_biome->layers.size());
int soil_size = 0;
for (unsigned i = 0; i < nlayers; i++)
{
auto layer = geo_biome->layers[i];
if (layer->type == SOIL || layer->type == SOIL_SAND)
soil_size += layer->top_height - layer->bottom_height + 1;
}
for (unsigned i = 0; i < geo_biome->layers.size(); i++) // Compute shifts for layers in the stack
int soil_erosion = soil_size - std::min(soil_size,tile.max_soil_depth);
int layer_shift[16];
int cur_shift = tile.elevation+soil_erosion-1;
for (unsigned i = 0; i < nlayers; i++)
{ {
auto layer = geo_biome->layers[i]; auto layer = geo_biome->layers[i];
switch (layer->type) layer_shift[i] = cur_shift;
if (layer->type == SOIL || layer->type == SOIL_SAND)
{ {
case SOIL: int size = layer->top_height - layer->bottom_height + 1;
case SOIL_OCEAN:
case SOIL_SAND: // This is to replicate the behavior of a probable bug in the
top_z_level += layer->top_height - layer->bottom_height + 1; // map generation code: if a layer is partially eroded, the
break; // removed levels are in fact transferred to the layer below,
default:; // because unlike the case of removing the whole layer, the code
// does not execute a loop to shift the lower part of the stack up.
if (size > soil_erosion)
cur_shift -= soil_erosion;
soil_erosion -= std::min(soil_erosion, size);
} }
} }
top_z_level = std::max(top_z_level, tile.elevation)-1; // Estimate amounts
int last_bottom = tile.elevation;
for (unsigned i = 0; i < geo_biome->layers.size(); i++) for (unsigned i = 0; i < nlayers; i++)
{ {
auto layer = geo_biome->layers[i]; auto layer = geo_biome->layers[i];
int top_z = std::min(layer->top_height + top_z_level, tile.elevation-1); int top_z = last_bottom-1;
int bottom_z = std::max(layer->bottom_height + top_z_level, tile.min_z); int bottom_z = std::max(layer->bottom_height + layer_shift[i], tile.min_z);
if (i+1 == geo_biome->layers.size()) // stretch layer if needed if (i+1 == nlayers) // stretch layer if needed
bottom_z = tile.min_z; bottom_z = tile.min_z;
if (top_z < bottom_z) if (top_z < bottom_z)
continue; continue;
last_bottom = bottom_z;
float layer_size = 48*48; float layer_size = 48*48;
int sums[ENUM_LAST_ITEM(inclusion_type)+1] = { 0 }; int sums[ENUM_LAST_ITEM(inclusion_type)+1] = { 0 };
@ -438,8 +490,7 @@ static command_result embark_prospector(color_ostream &out, df::viewscreen_choos
df::world_data *data = world->world_data; df::world_data *data = world->world_data;
coord2d cur_region = screen->region_pos; coord2d cur_region = screen->region_pos;
int d_idx = linear_index(data->region_details, &df::world_region_details::pos, cur_region); auto cur_details = get_details(data, cur_region);
auto cur_details = vector_get(data->region_details, d_idx);
if (!cur_details) if (!cur_details)
{ {

@ -30,7 +30,8 @@ command_result df_regrass (color_ostream &out, vector <string> & parameters);
DFhackCExport command_result plugin_init (color_ostream &out, std::vector<PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector<PluginCommand> &commands)
{ {
commands.push_back(PluginCommand("regrass", "Regrows surface grass.", df_regrass)); commands.push_back(PluginCommand("regrass", "Regrows surface grass.", df_regrass, false,
"Specify parameter 'max' to set all grass types to full density, otherwise only one type of grass will be restored per tile.\n"));
return CR_OK; return CR_OK;
} }

@ -76,12 +76,23 @@ DFHACK_PLUGIN("reveal");
DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands)
{ {
commands.push_back(PluginCommand("reveal","Reveal the map. 'reveal hell' will also reveal hell. 'reveal demon' won't pause.",reveal)); commands.push_back(PluginCommand("reveal","Reveal the map. 'reveal hell' will also reveal hell. 'reveal demon' won't pause.",reveal,false,
commands.push_back(PluginCommand("unreveal","Revert the map to its previous state.",unreveal)); "Reveals the map, by default ignoring hell.\n"
commands.push_back(PluginCommand("revtoggle","Reveal/unreveal depending on state.",revtoggle)); "Options:\n"
commands.push_back(PluginCommand("revflood","Hide all, reveal all tiles reachable from cursor position.",revflood)); "hell - also reveal hell, while forcing the game to pause.\n"
commands.push_back(PluginCommand("revforget", "Forget the current reveal data, allowing to use reveal again.",revforget)); "demon - reveal hell, do not pause.\n"));
commands.push_back(PluginCommand("nopause","Disable pausing (doesn't affect pause forced by reveal).",nopause)); commands.push_back(PluginCommand("unreveal","Revert the map to its previous state.",unreveal,false,
"Reverts the previous reveal operation, hiding the map again.\n"));
commands.push_back(PluginCommand("revtoggle","Reveal/unreveal depending on state.",revtoggle,false,
"Toggles between reveal and unreveal.\n"));
commands.push_back(PluginCommand("revflood","Hide all, reveal all tiles reachable from cursor position.",revflood,false,
"This command hides the whole map. Then, starting from the cursor,\n"
"reveals all accessible tiles. Allows repairing parma-revealed maps.\n"));
commands.push_back(PluginCommand("revforget", "Forget the current reveal data, allowing to use reveal again.",revforget,false,
"Forget the current reveal data, allowing to use reveal again.\n"));
commands.push_back(PluginCommand("nopause","Disable pausing (doesn't affect pause forced by reveal).",nopause,false,
"Disable pausing (doesn't affect pause forced by reveal).\n"
"Activate with 'nopause 1', deactivate with 'nopause 0'.\n"));
return CR_OK; return CR_OK;
} }
@ -160,14 +171,7 @@ command_result reveal(color_ostream &out, vector<string> & params)
if(params[i]=="hell") if(params[i]=="hell")
no_hell = false; no_hell = false;
else if(params[i] == "help" || params[i] == "?") else if(params[i] == "help" || params[i] == "?")
{ return CR_WRONG_USAGE;
out.print("Reveals the map, by default ignoring hell.\n"
"Options:\n"
"hell - also reveal hell, while forcing the game to pause.\n"
"demon - reveal hell, do not pause.\n"
);
return CR_OK;
}
} }
if(params.size() && params[0] == "hell") if(params.size() && params[0] == "hell")
{ {
@ -254,10 +258,7 @@ command_result unreveal(color_ostream &out, vector<string> & params)
for(size_t i = 0; i < params.size();i++) for(size_t i = 0; i < params.size();i++)
{ {
if(params[i] == "help" || params[i] == "?") if(params[i] == "help" || params[i] == "?")
{ return CR_WRONG_USAGE;
out.print("Reverts the previous reveal operation, hiding the map again.\n");
return CR_OK;
}
} }
if(!revealed) if(!revealed)
{ {
@ -330,12 +331,7 @@ command_result revflood(color_ostream &out, vector<string> & params)
for(size_t i = 0; i < params.size();i++) for(size_t i = 0; i < params.size();i++)
{ {
if(params[i] == "help" || params[i] == "?") if(params[i] == "help" || params[i] == "?")
{ return CR_WRONG_USAGE;
out.print("This command hides the whole map. Then, starting from the cursor,\n"
"reveals all accessible tiles. Allows repairing parma-revealed maps.\n"
);
return CR_OK;
}
} }
CoreSuspender suspend; CoreSuspender suspend;
uint32_t x_max,y_max,z_max; uint32_t x_max,y_max,z_max;
@ -482,10 +478,7 @@ command_result revforget(color_ostream &out, vector<string> & params)
for(size_t i = 0; i < params.size();i++) for(size_t i = 0; i < params.size();i++)
{ {
if(params[i] == "help" || params[i] == "?") if(params[i] == "help" || params[i] == "?")
{ return CR_WRONG_USAGE;
out.print("Forget the current reveal data, allowing to use reveal again.\n");
return CR_OK;
}
} }
if(!revealed) if(!revealed)
{ {

@ -130,11 +130,15 @@ command_result df_seedwatch(color_ostream &out, vector<string>& parameters)
{ {
case 0: case 0:
printHelp(out); printHelp(out);
break; return CR_WRONG_USAGE;
case 1: case 1:
par = parameters[0]; par = parameters[0];
if(par == "help") printHelp(out); if ((par == "help") || (par == "?"))
else if(par == "?") printHelp(out); {
printHelp(out);
return CR_WRONG_USAGE;
}
else if(par == "start") else if(par == "start")
{ {
running = true; running = true;
@ -239,6 +243,7 @@ command_result df_seedwatch(color_ostream &out, vector<string>& parameters)
break; break;
default: default:
printHelp(out); printHelp(out);
return CR_WRONG_USAGE;
break; break;
} }

@ -292,7 +292,8 @@ DFHACK_PLUGIN("showmood");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector<PluginCommand> &commands) DFhackCExport command_result plugin_init (color_ostream &out, std::vector<PluginCommand> &commands)
{ {
commands.push_back(PluginCommand("showmood", "Shows items needed for current strange mood.", df_showmood)); commands.push_back(PluginCommand("showmood", "Shows items needed for current strange mood.", df_showmood, false,
"Run this command without any parameters to display information on the currently active Strange Mood."));
return CR_OK; return CR_OK;
} }

@ -1002,7 +1002,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
commands.push_back( commands.push_back(
PluginCommand( PluginCommand(
"stocks", "An improved stocks display screen", "stocks", "An improved stocks display screen",
stocks_cmd, false, "")); stocks_cmd, false, "Run 'stocks show' open the stocks display screen, or 'stocks version' to query the plugin version."));
ViewscreenStocks::reset(); ViewscreenStocks::reset();

@ -23,7 +23,9 @@ DFHACK_PLUGIN("tubefill");
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{ {
commands.push_back(PluginCommand("tubefill","Fill in all the adamantine tubes again.",tubefill)); commands.push_back(PluginCommand("tubefill","Fill in all the adamantine tubes again.",tubefill, false,
"Replenishes mined out adamantine and hollow adamantine tubes.\n"
"May cause !!FUN!!\n"));
return CR_OK; return CR_OK;
} }
@ -39,12 +41,7 @@ command_result tubefill(color_ostream &out, std::vector<std::string> & params)
for(size_t i = 0; i < params.size();i++) for(size_t i = 0; i < params.size();i++)
{ {
if(params[i] == "help" || params[i] == "?") if(params[i] == "help" || params[i] == "?")
{ return CR_WRONG_USAGE;
out.print("Replenishes mined out adamantine and hollow adamantine tubes.\n"
"May cause !!FUN!!\n"
);
return CR_OK;
}
} }
CoreSuspender suspend; CoreSuspender suspend;