From e4978a1da7c369cbfdf919472361c3ae336c9fcf Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Fri, 25 Oct 2013 12:51:06 +0400 Subject: [PATCH 01/10] Relax 3dveins preconditions to account for soil quirks and volcanoes. --- plugins/3dveins.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/plugins/3dveins.cpp b/plugins/3dveins.cpp index e010ed3d3..432d93cf6 100644 --- a/plugins/3dveins.cpp +++ b/plugins/3dveins.cpp @@ -377,6 +377,7 @@ struct GeoLayer int16_t material; bool is_soil; + bool is_soil_layer; // World-global origin coordinates in blocks 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; material = info->mat_index; 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); @@ -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 &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; if (max_level[idx] < 0) { // Do not start the layer stack in open air. // Those tiles can be very weird. - if (bottom < 0 && isOpenTerrain(b->baseTiletypeAt(tile))) + if (bottom < 0 && (isOpenTerrain(ttype) || obsidian)) continue; max_level[idx] = min_level[idx] = z; @@ -777,9 +782,14 @@ bool VeinGenerator::adjust_layer_depth(df::coord2d column) if (max_defined < 0) continue; + int last_top = min_defined; + // Verify assumptions 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) max_level[i+1] = min_level[i+1] = min_level[i]; @@ -815,6 +825,22 @@ bool VeinGenerator::adjust_layer_depth(df::coord2d column) 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( "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], From 54b45349c57ccf6fc1df2f72d12aedd9963c129b Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Fri, 25 Oct 2013 14:37:37 +0400 Subject: [PATCH 02/10] Improve pre-embark prospect using new knowledge about soil depth. --- plugins/prospector.cpp | 101 +++++++++++++++++++++++++++++++---------- 1 file changed, 76 insertions(+), 25 deletions(-) diff --git a/plugins/prospector.cpp b/plugins/prospector.cpp index efd457dfd..cec6c3bcb 100644 --- a/plugins/prospector.cpp +++ b/plugins/prospector.cpp @@ -234,11 +234,18 @@ static coord2d biome_delta[] = { struct EmbarkTileLayout { coord2d biome_off, biome_pos; df::region_map_entry *biome; + df::world_geo_biome *geo_biome; int elevation, max_soil_depth; int min_z, base_z; std::map 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) { // 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 = &data->region_map[bx][by]; + tile.geo_biome = df::world_geo_biome::find(tile.biome->geo_index); + // Compute surface elevation - tile.elevation = ( - details->elevation[x][y] + details->elevation[x][y+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.elevation = details->elevation[x][y]; + tile.max_soil_depth = std::max((154-tile.elevation)/5,1); 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]; // 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) { - out.printerr("Could not find magma sea.\n"); - return false; + out.printerr("Could not find magma sea; depth may be incorrect.\n"); + tile.min_z = tile.base_z; } // 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; - 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) { @@ -350,35 +379,58 @@ bool estimate_materials(color_ostream &out, EmbarkTileLayout &tile, MatMap &laye } // soil depth increases by 1 every 5 levels below 150 - int top_z_level = tile.elevation - tile.max_soil_depth; + unsigned nlayers = std::min(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]; - switch (layer->type) + layer_shift[i] = cur_shift; + + if (layer->type == SOIL || layer->type == SOIL_SAND) { - case SOIL: - case SOIL_OCEAN: - case SOIL_SAND: - top_z_level += layer->top_height - layer->bottom_height + 1; - break; - default:; + int size = layer->top_height - layer->bottom_height + 1; + + // This is to replicate the behavior of a probable bug in the + // map generation code: if a layer is partially eroded, the + // removed levels are in fact transferred to the layer below, + // 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]; - int top_z = std::min(layer->top_height + top_z_level, tile.elevation-1); - int bottom_z = std::max(layer->bottom_height + top_z_level, tile.min_z); - if (i+1 == geo_biome->layers.size()) // stretch layer if needed + int top_z = last_bottom-1; + int bottom_z = std::max(layer->bottom_height + layer_shift[i], tile.min_z); + if (i+1 == nlayers) // stretch layer if needed bottom_z = tile.min_z; if (top_z < bottom_z) continue; + last_bottom = bottom_z; + float layer_size = 48*48; 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; coord2d cur_region = screen->region_pos; - int d_idx = linear_index(data->region_details, &df::world_region_details::pos, cur_region); - auto cur_details = vector_get(data->region_details, d_idx); + auto cur_details = get_details(data, cur_region); if (!cur_details) { From 15c2d99a3e54a6ca1a0b5f3c5dfc80f38dded428 Mon Sep 17 00:00:00 2001 From: expwnent Date: Fri, 25 Oct 2013 14:23:55 -0400 Subject: [PATCH 03/10] Update xml. --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index e62d498e6..d6bcaa991 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e62d498e68e3a87929b144220d03e691016f7aae +Subproject commit d6bcaa991cfe9ab5a8031b1721d548a73258d7ed From b97a13fa6309f7415d3c00b842d585e78d65ca06 Mon Sep 17 00:00:00 2001 From: Quietust Date: Wed, 30 Oct 2013 14:19:52 -0500 Subject: [PATCH 04/10] Update "plants" plugin * Add "createplant" command, creates a shrub or sapling at the cursor. * Put help text in command definitions so CR_WRONG_USAGE works properly --- plugins/plants.cpp | 165 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 127 insertions(+), 38 deletions(-) diff --git a/plugins/plants.cpp b/plugins/plants.cpp index 89a3257fa..9b845edc6 100644 --- a/plugins/plants.cpp +++ b/plugins/plants.cpp @@ -22,25 +22,8 @@ using df::global::world; const uint32_t sapling_to_tree_threshold = 120 * 28 * 12 * 3; // 3 years -command_result df_grow (color_ostream &out, vector & parameters); -command_result df_immolate (color_ostream &out, vector & parameters); -command_result df_extirpate (color_ostream &out, vector & parameters); - DFHACK_PLUGIN("plants"); -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &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 { do_immolate, @@ -84,19 +67,8 @@ static bool getoptions( vector & parameters, bool & shrubs, bool & tree */ 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) - { - 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; - } + return CR_WRONG_USAGE; CoreSuspender suspend; if (!Maps::IsValid()) { @@ -165,26 +137,26 @@ command_result df_immolate (color_ostream &out, vector & parameters) bool shrubs = false, trees = false, help = false; if(getoptions(parameters,shrubs,trees,help)) { - return immolations(out,do_immolate,shrubs,trees, help); + return immolations(out,do_immolate,shrubs,trees,help); } else { out.printerr("Invalid parameter!\n"); - return CR_FAILURE; + return CR_WRONG_USAGE; } } command_result df_extirpate (color_ostream &out, vector & parameters) { 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 { out.printerr("Invalid parameter!\n"); - return CR_FAILURE; + return CR_WRONG_USAGE; } } @@ -193,10 +165,7 @@ command_result df_grow (color_ostream &out, vector & parameters) for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") - { - out.print("This command turns all living saplings into full-grown trees.\n"); - return CR_OK; - } + return CR_WRONG_USAGE; } CoreSuspender suspend; @@ -245,3 +214,123 @@ command_result df_grow (color_ostream &out, vector & parameters) return CR_OK; } +command_result df_createplant (color_ostream &out, vector & 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 = new 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 &commands) +{ + commands.push_back(PluginCommand("grow", "Grows saplings into trees (with active cursor, only the targetted one).", df_grow, + "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, + "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, + "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, + "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; +} \ No newline at end of file From ff939e36bbb8e46d6a1f7405908bbd0ae00754d3 Mon Sep 17 00:00:00 2001 From: Quietust Date: Wed, 30 Oct 2013 14:25:35 -0500 Subject: [PATCH 05/10] Missed parameter in plugin command init --- plugins/plants.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/plants.cpp b/plugins/plants.cpp index 9b845edc6..9be4c193a 100644 --- a/plugins/plants.cpp +++ b/plugins/plants.cpp @@ -310,21 +310,21 @@ command_result df_createplant (color_ostream &out, vector & parameters) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand("grow", "Grows saplings into trees (with active cursor, only the targetted one).", df_grow, + 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, + 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, + 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, + 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; From 463bb8d498259ad0c0ec5d81378892f2c9b96779 Mon Sep 17 00:00:00 2001 From: Quietust Date: Wed, 30 Oct 2013 15:58:14 -0500 Subject: [PATCH 06/10] Update plugins to use CR_WRONG_USAGE where appropriate --- plugins/autotrade.cpp | 2 +- plugins/buildingplan.cpp | 2 +- plugins/createitem.cpp | 19 +++++++--------- plugins/lair.cpp | 3 ++- plugins/liquids.cpp | 25 ++++++++------------ plugins/probe.cpp | 12 +++++++--- plugins/regrass.cpp | 3 ++- plugins/reveal.cpp | 49 +++++++++++++++++----------------------- plugins/seedwatch.cpp | 11 ++++++--- plugins/showmood.cpp | 3 ++- plugins/stocks.cpp | 2 +- plugins/tubefill.cpp | 11 ++++----- 12 files changed, 68 insertions(+), 74 deletions(-) diff --git a/plugins/autotrade.cpp b/plugins/autotrade.cpp index 2d3cf0ed2..0d11af9f0 100644 --- a/plugins/autotrade.cpp +++ b/plugins/autotrade.cpp @@ -626,7 +626,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector & parameters); DFhackCExport command_result plugin_init (color_ostream &out, std::vector &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 [count]\n" + " - Item token for what you wish to create, as specified in custom\n" + " reactions. If the item has no subtype, omit the :NONE.\n" + " - 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; } @@ -91,17 +98,7 @@ command_result df_createitem (color_ostream &out, vector & parameters) int count = 1; if ((parameters.size() < 2) || (parameters.size() > 3)) - { - out.print("Syntax: createitem [count]\n" - " - Item token for what you wish to create, as specified in custom\n" - " reactions. If the item has no subtype, omit the :NONE.\n" - " - 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; - } item_str = parameters[0]; material_str = parameters[1]; diff --git a/plugins/lair.cpp b/plugins/lair.cpp index 0c2912761..cafbbcc33 100644 --- a/plugins/lair.cpp +++ b/plugins/lair.cpp @@ -58,6 +58,7 @@ command_result lair(color_ostream &out, std::vector & params) DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &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; } diff --git a/plugins/liquids.cpp b/plugins/liquids.cpp index 15ae84c9b..712955b86 100644 --- a/plugins/liquids.cpp +++ b/plugins/liquids.cpp @@ -59,12 +59,16 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector & parameters) for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") - { - 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; - } + return CR_WRONG_USAGE; } if (!Maps::IsValid()) @@ -375,11 +372,7 @@ command_result df_liquids_here (color_ostream &out, vector & parameters for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") - { - 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; - } + return CR_WRONG_USAGE; } out.print("Run liquids-here with these parameters: "); diff --git a/plugins/probe.cpp b/plugins/probe.cpp index 353caea0f..28b62c24e 100644 --- a/plugins/probe.cpp +++ b/plugins/probe.cpp @@ -46,13 +46,19 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector & parameters); DFhackCExport command_result plugin_init (color_ostream &out, std::vector &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; } diff --git a/plugins/reveal.cpp b/plugins/reveal.cpp index 2c51295a8..91ab75686 100644 --- a/plugins/reveal.cpp +++ b/plugins/reveal.cpp @@ -76,12 +76,23 @@ DFHACK_PLUGIN("reveal"); DFhackCExport command_result plugin_init ( color_ostream &out, vector &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("unreveal","Revert the map to its previous state.",unreveal)); - commands.push_back(PluginCommand("revtoggle","Reveal/unreveal depending on state.",revtoggle)); - commands.push_back(PluginCommand("revflood","Hide all, reveal all tiles reachable from cursor position.",revflood)); - commands.push_back(PluginCommand("revforget", "Forget the current reveal data, allowing to use reveal again.",revforget)); - commands.push_back(PluginCommand("nopause","Disable pausing (doesn't affect pause forced by reveal).",nopause)); + commands.push_back(PluginCommand("reveal","Reveal the map. 'reveal hell' will also reveal hell. 'reveal demon' won't pause.",reveal,false, + "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")); + 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; } @@ -160,14 +171,7 @@ command_result reveal(color_ostream &out, vector & params) if(params[i]=="hell") no_hell = false; else if(params[i] == "help" || params[i] == "?") - { - 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; - } + return CR_WRONG_USAGE; } if(params.size() && params[0] == "hell") { @@ -254,10 +258,7 @@ command_result unreveal(color_ostream &out, vector & params) for(size_t i = 0; i < params.size();i++) { if(params[i] == "help" || params[i] == "?") - { - out.print("Reverts the previous reveal operation, hiding the map again.\n"); - return CR_OK; - } + return CR_WRONG_USAGE; } if(!revealed) { @@ -330,12 +331,7 @@ command_result revflood(color_ostream &out, vector & params) for(size_t i = 0; i < params.size();i++) { if(params[i] == "help" || params[i] == "?") - { - 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; - } + return CR_WRONG_USAGE; } CoreSuspender suspend; uint32_t x_max,y_max,z_max; @@ -482,10 +478,7 @@ command_result revforget(color_ostream &out, vector & params) for(size_t i = 0; i < params.size();i++) { if(params[i] == "help" || params[i] == "?") - { - out.print("Forget the current reveal data, allowing to use reveal again.\n"); - return CR_OK; - } + return CR_WRONG_USAGE; } if(!revealed) { diff --git a/plugins/seedwatch.cpp b/plugins/seedwatch.cpp index 19fa9b154..e0c2daeae 100755 --- a/plugins/seedwatch.cpp +++ b/plugins/seedwatch.cpp @@ -130,11 +130,15 @@ command_result df_seedwatch(color_ostream &out, vector& parameters) { case 0: printHelp(out); - break; + return CR_WRONG_USAGE; + case 1: par = parameters[0]; - if(par == "help") printHelp(out); - else if(par == "?") printHelp(out); + if ((par == "help") || (par == "?")) + { + printHelp(out); + return CR_WRONG_USAGE; + } else if(par == "start") { running = true; @@ -239,6 +243,7 @@ command_result df_seedwatch(color_ostream &out, vector& parameters) break; default: printHelp(out); + return CR_WRONG_USAGE; break; } diff --git a/plugins/showmood.cpp b/plugins/showmood.cpp index 7a3662f82..ba6df034a 100644 --- a/plugins/showmood.cpp +++ b/plugins/showmood.cpp @@ -292,7 +292,8 @@ DFHACK_PLUGIN("showmood"); DFhackCExport command_result plugin_init (color_ostream &out, std::vector &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; } diff --git a/plugins/stocks.cpp b/plugins/stocks.cpp index 10594fe9e..7873595ff 100644 --- a/plugins/stocks.cpp +++ b/plugins/stocks.cpp @@ -1002,7 +1002,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &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; } @@ -39,12 +41,7 @@ command_result tubefill(color_ostream &out, std::vector & params) for(size_t i = 0; i < params.size();i++) { if(params[i] == "help" || params[i] == "?") - { - out.print("Replenishes mined out adamantine and hollow adamantine tubes.\n" - "May cause !!FUN!!\n" - ); - return CR_OK; - } + return CR_WRONG_USAGE; } CoreSuspender suspend; From 4d2e5b80bf4c48403fb5491929d45e46652aeca1 Mon Sep 17 00:00:00 2001 From: Quietust Date: Mon, 4 Nov 2013 14:55:31 -0600 Subject: [PATCH 07/10] Use df::allocate here for proper compatibility with 40d and earlier --- plugins/plants.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/plants.cpp b/plugins/plants.cpp index 9be4c193a..c0cd427a9 100644 --- a/plugins/plants.cpp +++ b/plugins/plants.cpp @@ -269,7 +269,7 @@ command_result df_createplant (color_ostream &out, vector & parameters) return CR_FAILURE; } - df::plant *plant = new df::plant; + df::plant *plant = df::allocate(); if (plant_raw->flags.is_set(plant_raw_flags::TREE)) plant->hitpoints = 400000; else From b2819ea8693c479f6d578579a98579e73ef47aec Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 7 Nov 2013 11:40:26 +0400 Subject: [PATCH 08/10] Fix wrong argument iteration bounds in dfhack.matinfo.find(). --- library/LuaApi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 3f93e912d..bdc0c39e5 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -565,7 +565,7 @@ static int dfhack_matinfo_find(lua_State *state) { std::vector tokens; - for (int i = 1; i < argc; i++) + for (int i = 1; i <= argc; i++) tokens.push_back(luaL_checkstring(state, i)); info.find(tokens); From 7ce5831257c241eee4c3e87873f6e9aa37a271a6 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 7 Nov 2013 11:58:11 +0400 Subject: [PATCH 09/10] Get rid of the std exception. --- plugins/eventful.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/eventful.cpp b/plugins/eventful.cpp index f93c15edc..97527c0ed 100644 --- a/plugins/eventful.cpp +++ b/plugins/eventful.cpp @@ -1,4 +1,5 @@ #include "Core.h" +#include "Error.h" #include #include #include @@ -228,8 +229,8 @@ static void enableEvent(int evType,int freq) { if (freq < 0) return; - if (evType < 0 || evType >= EventManager::EventType::EVENT_MAX || evType == EventManager::EventType::TICK) - throw std::runtime_error("invalid event type to enable"); + CHECK_INVALID_ARGUMENT(evType >= 0 && evType < EventManager::EventType::EVENT_MAX && + evType != EventManager::EventType::TICK); EventManager::EventHandler::callback_t fun_ptr = eventHandlers[evType]; EventManager::EventType::EventType typeToEnable=static_cast(evType); From 53bd1125153f5625249aebca85f37632a3688da7 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 7 Nov 2013 12:27:53 +0400 Subject: [PATCH 10/10] Hide fake historical figures from legends xml export. --- library/modules/World.cpp | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/library/modules/World.cpp b/library/modules/World.cpp index 9ae4266b2..0f54e68eb 100644 --- a/library/modules/World.cpp +++ b/library/modules/World.cpp @@ -42,11 +42,14 @@ using namespace std; #include "MiscUtils.h" +#include "VTableInterpose.h" + #include "DataDefs.h" #include "df/world.h" #include "df/historical_figure.h" #include "df/map_block.h" #include "df/block_square_event_world_constructionst.h" +#include "df/viewscreen_legendsst.h" using namespace DFHack; 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); } +// 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 *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 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() { next_persistent_id = 0; persistent_index.clear(); + + INTERPOSE_HOOK(hide_fake_histfigs_hook, feed).apply(Core::getInstance().isWorldLoaded()); } static bool BuildPersistentCache() { + if (in_export_xml) + return false; if (next_persistent_id) return true; if (!Core::getInstance().isWorldLoaded())