void printHelp(color_ostream &out) // prints help { out.print( "Watches the numbers of seeds available and enables/disables seed and plant cooking.\n" "Each plant type can be assigned a limit. If their number falls below,\n" "the plants and seeds of that type will be excluded from cookery.\n" "If the number rises above the limit + %i, then cooking will be allowed.\n", buffer ); out.printerr( "The plugin needs a fortress to be loaded and will deactivate automatically otherwise.\n" "You have to reactivate with 'seedwatch start' after you load the game.\n" ); out.print( "Options:\n" "seedwatch all - Adds all plants from the abbreviation list to the watch list.\n" "seedwatch start - Start watching.\n" "seedwatch stop - Stop watching.\n" "seedwatch info - Display whether seedwatch is watching, and the watch list.\n" "seedwatch clear - Clears the watch list.\n\n" ); if(!abbreviations.empty()) { out.print("You can use these abbreviations for the plant tokens:\n"); for(map<string, string>::const_iterator i = abbreviations.begin(); i != abbreviations.end(); ++i) { out.print("%s -> %s\n", i->first.c_str(), i->second.c_str()); } } out.print( "Examples:\n" "seedwatch MUSHROOM_HELMET_PLUMP 30\n" " add MUSHROOM_HELMET_PLUMP to the watch list, limit = 30\n" "seedwatch MUSHROOM_HELMET_PLUMP\n" " removes MUSHROOM_HELMET_PLUMP from the watch list.\n" "seedwatch ph 30\n" " is the same as 'seedwatch MUSHROOM_HELMET_PLUMP 30'\n" "seedwatch all 30\n" " adds all plants from the abbreviation list to the watch list, the limit being 30.\n" ); };
command_result df_flows (color_ostream &out, vector <string> & parameters) { CoreSuspender suspend; int flow1 = 0, flow2 = 0, flowboth = 0, water = 0, magma = 0; out.print("Counting flows and liquids ...\n"); for (size_t i = 0; i < world->map.map_blocks.size(); i++) { df::map_block *cur = world->map.map_blocks[i]; if (cur->flags.bits.update_liquid) flow1++; if (cur->flags.bits.update_liquid_twice) flow2++; if (cur->flags.bits.update_liquid && cur->flags.bits.update_liquid_twice) flowboth++; for (int x = 0; x < 16; x++) { for (int y = 0; y < 16; y++) { // only count tiles with actual liquid in them if (cur->designation[x][y].bits.flow_size == 0) continue; if (cur->designation[x][y].bits.liquid_type == tile_liquid::Magma) magma++; if (cur->designation[x][y].bits.liquid_type == tile_liquid::Water) water++; } } } out.print("Blocks with liquid_1=true: %d\n", flow1); out.print("Blocks with liquid_2=true: %d\n", flow2); out.print("Blocks with both: %d\n", flowboth); out.print("Water tiles: %d\n", water); out.print("Magma tiles: %d\n", magma); return CR_OK; }
static void world_specific_hooks(color_ostream &out,bool enable) { if(enable && find_reactions(out)) { out.print("Detected reaction hooks - enabling plugin.\n"); INTERPOSE_HOOK(product_hook, produce).apply(true); } else { INTERPOSE_HOOK(product_hook, produce).apply(false); reactions.clear(); products.clear(); } }
static command_result df_rubyload(color_ostream &out, std::vector <std::string> & parameters) { if (parameters.size() == 1 && (parameters[0] == "help" || parameters[0] == "?")) { out.print("This command loads the ruby script whose path is given as parameter, and run it.\n"); return CR_OK; } std::string cmd = "load '"; cmd += parameters[0]; // TODO escape singlequotes cmd += "'"; return plugin_eval_rb(cmd); }
command_result df_liquids_here (color_ostream &out, vector <string> & parameters) { for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") return CR_WRONG_USAGE; } out.print("Run liquids-here with these parameters: "); print_prompt(out, cur_mode); out << endl; return df_liquids_execute(out); }
static void setJobResumed(color_ostream &out, ProtectedJob *pj, bool goal) { bool current = pj->isResumed(); pj->set_resumed(goal); if (goal != current) { out.print("%s %s%s\n", (goal ? "Resuming" : "Suspending"), shortJobDescription(pj->actual_job).c_str(), (!goal || pj->isActuallyResumed() ? "" : " (delayed)")); } }
// dump some cage info void cageInfo(color_ostream & out, df::building* building, bool verbose = false) { if(!isCage(building)) return; string name; building->getName(&name); out.print("Building %i - \"%s\" - type %s (%i)", building->id, name.c_str(), ENUM_KEY_STR(building_type, building->getType()).c_str(), building->getType()); out.print("\n"); out << "x:" << building->x1 << " y:" << building->y1 << " z:" << building->z << endl; df::building_cagest * cage = (df::building_cagest*) building; int32_t creaturecount = cage->assigned_creature.size(); out << "Creatures in this cage: " << creaturecount << endl; for(size_t c = 0; c < creaturecount; c++) { int32_t cindex = cage->assigned_creature.at(c); // print list of all units assigned to that cage for(size_t i = 0; i < world->units.all.size(); i++) { df::unit * creature = world->units.all[i]; if(creature->id != cindex) continue; unitInfo(out, creature, verbose); } } }
void doInfiniteSky(color_ostream& out, int32_t howMany) { CoreSuspender suspend; int32_t x_count_block = world->map.x_count_block; int32_t y_count_block = world->map.y_count_block; for ( int32_t count = 0; count < howMany; count++ ) { //change the size of the pointer stuff int32_t z_count_block = world->map.z_count_block; df::map_block**** block_index = world->map.block_index; for ( int32_t a = 0; a < x_count_block; a++ ) { for ( int32_t b = 0; b < y_count_block; b++ ) { df::map_block** blockColumn = new df::map_block*[z_count_block+1]; memcpy(blockColumn, block_index[a][b], z_count_block*sizeof(df::map_block*)); blockColumn[z_count_block] = NULL; delete[] block_index[a][b]; block_index[a][b] = blockColumn; //deal with map_block_column stuff even though it'd probably be fine df::map_block_column* column = world->map.column_index[a][b]; if ( !column ) { out.print("%s, line %d: column is null (%d, %d).\n", __FILE__, __LINE__, a, b); continue; } df::map_block_column::T_unmined_glyphs* glyphs = new df::map_block_column::T_unmined_glyphs; glyphs->x[0] = 0; glyphs->x[1] = 1; glyphs->x[2] = 2; glyphs->x[3] = 3; glyphs->y[0] = 0; glyphs->y[1] = 0; glyphs->y[2] = 0; glyphs->y[3] = 0; glyphs->tile[0] = 'e'; glyphs->tile[1] = 'x'; glyphs->tile[2] = 'p'; glyphs->tile[3] = '^'; column->unmined_glyphs.push_back(glyphs); } } df::z_level_flags* flags = new df::z_level_flags[z_count_block+1]; memcpy(flags, world->map_extras.z_level_flags, z_count_block*sizeof(df::z_level_flags)); flags[z_count_block].whole = 0; flags[z_count_block].bits.update = 1; world->map.z_count_block++; world->map.z_count++; delete[] world->map_extras.z_level_flags; world->map_extras.z_level_flags = flags; } }
DFhackCExport command_result workNow(color_ostream& out, vector<string>& parameters) { if ( parameters.size() == 0 ) { out.print("workNow status = %d\n", mode); return CR_OK; } if ( parameters.size() > 1 ) { return CR_WRONG_USAGE; } int32_t a = atoi(parameters[0].c_str()); if (a < 0 || a > 2) return CR_WRONG_USAGE; if ( a == 2 && mode != 2 ) { EventManager::registerListener(EventManager::EventType::JOB_COMPLETED, handler, plugin_self); } else if ( mode == 2 && a != 2 ) { EventManager::unregister(EventManager::EventType::JOB_COMPLETED, handler, plugin_self); } mode = a; out.print("workNow status = %d\n", mode); return CR_OK; }
command_result follow (color_ostream &out, std::vector <std::string> & parameters) { // HOTKEY COMMAND: CORE ALREADY SUSPENDED if (!parameters.empty()) return CR_WRONG_USAGE; if (followedUnit) { out.print("No longer following previously selected unit.\n"); followedUnit = 0; } followedUnit = Gui::getSelectedUnit(out); if (followedUnit) { std::ostringstream ss; ss << "Unpause to begin following " << df::global::world->raws.creatures.all[followedUnit->race]->name[0]; if (followedUnit->name.has_name) ss << " " << followedUnit->name.first_name; ss << ". Simply manually move the view to break the following.\n"; out.print(ss.str().c_str()); } else followedUnit = 0; return CR_OK; }
command_result df_cleanconst(color_ostream &out, vector <string> & parameters) { CoreSuspender suspend; if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } size_t numItems = world->items.all.size(); int cleaned_total = 0; // proceed with the cleanup operation for (size_t i = 0; i < numItems; i++) { df::item *item = world->items.all[i]; // only process items marked as "in construction" if (!item->flags.bits.construction) continue; df::coord pos(item->pos.x, item->pos.y, item->pos.z); df::construction *cons = df::construction::find(pos); if (!cons) { out.printerr("Item at %i,%i,%i marked as construction but no construction is present!\n", pos.x, pos.y, pos.z); continue; } // if the construction is already labeled as "no build item", then leave it alone if (cons->flags.bits.no_build_item) continue; // only destroy the item if the construction claims to be made of the exact same thing if (item->getType() != cons->item_type || item->getSubtype() != cons->item_subtype || item->getMaterial() != cons->mat_type || item->getMaterialIndex() != cons->mat_index) continue; item->flags.bits.garbage_collect = 1; cons->flags.bits.no_build_item = 1; cleaned_total++; } out.print("Done. %d construction items cleaned up.\n", cleaned_total); return CR_OK; }
void revealAdventure(color_ostream &out) { for (size_t i = 0; i < world->map.map_blocks.size(); i++) { df::map_block *block = world->map.map_blocks[i]; designations40d & designations = block->designation; // for each tile in block for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++) { // set to revealed designations[x][y].bits.hidden = 0; // and visible designations[x][y].bits.pile = 1; } } out.print("Local map revealed.\n"); }
void describeTile(color_ostream &out, df::tiletype tiletype) { out.print("%d", tiletype); if(tileName(tiletype)) out.print(" = %s",tileName(tiletype)); out.print("\n"); df::tiletype_shape shape = tileShape(tiletype); df::tiletype_material material = tileMaterial(tiletype); df::tiletype_special special = tileSpecial(tiletype); df::tiletype_variant variant = tileVariant(tiletype); out.print("%-10s: %4d %s\n","Class" ,shape, ENUM_KEY_STR(tiletype_shape, shape).c_str()); out.print("%-10s: %4d %s\n","Material" , material, ENUM_KEY_STR(tiletype_material, material).c_str()); out.print("%-10s: %4d %s\n","Special" , special, ENUM_KEY_STR(tiletype_special, special).c_str()); out.print("%-10s: %4d %s\n" ,"Variant" , variant, ENUM_KEY_STR(tiletype_variant, variant).c_str()); out.print("%-10s: %s\n" ,"Direction", tileDirection(tiletype).getStr()); out.print("\n"); }
command_result ktimer (color_ostream &out, vector <string> & parameters) { if(timering) { timering = false; return CR_OK; } uint64_t timestart = GetTimeMs64(); { CoreSuspender suspend; } uint64_t timeend = GetTimeMs64(); out.print("Time to suspend = %d ms\n",timeend - timestart); // harmless potential data race here... timeLast = timeend; timering = true; return CR_OK; }
command_result revtoggle (color_ostream &out, vector<string> & params) { for(size_t i = 0; i < params.size();i++) { if(params[i] == "help" || params[i] == "?") { out.print("Toggles between reveal and unreveal.\nCurrently it: "); break; } } if(revealed) { return unreveal(out,params); } else { return reveal(out,params); } }
static command_result df_rubyeval(color_ostream &out, std::vector <std::string> & parameters) { if (parameters.size() == 1 && (parameters[0] == "help" || parameters[0] == "?")) { out.print("This command executes an arbitrary ruby statement.\n"); return CR_OK; } // reconstruct the text from dfhack console line std::string full = ""; for (unsigned i=0 ; i<parameters.size() ; ++i) { full += parameters[i]; if (i != parameters.size()-1) full += " "; } return plugin_eval_ruby(out, full.c_str()); }
command_result df_cprobe (color_ostream &out, vector <string> & parameters) { CoreSuspender suspend; int32_t cursorX, cursorY, cursorZ; Gui::getCursorCoords(cursorX,cursorY,cursorZ); if(cursorX == -30000) { out.printerr("No cursor; place cursor over creature to probe.\n"); } else { for(size_t i = 0; i < world->units.all.size(); i++) { df::unit * unit = world->units.all[i]; if(unit->pos.x == cursorX && unit->pos.y == cursorY && unit->pos.z == cursorZ) { out.print("Creature %d, race %d (%x), civ %d (%x)\n", unit->id, unit->race, unit->race, unit->civ_id, unit->civ_id); for(size_t j=0; j<unit->inventory.size(); j++) { df::unit_inventory_item* inv_item = unit->inventory[j]; df::item* item = inv_item->item; if(inv_item->mode == df::unit_inventory_item::T_mode::Worn) { out << " wears item: #" << item->id; if(item->flags.bits.owned) out << " (owned)"; else out << " (not owned)"; if(item->getEffectiveArmorLevel() != 0) out << ", armor"; out << endl; } } // don't leave loop, there may be more than 1 creature at the cursor position //break; } } } return CR_OK; }
command_result df_liquids_here (color_ostream &out, vector <string> & 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; } } out.print("Run liquids-here with these parameters: "); out << "[" << mode << ":" << brushname; if (brushname == "range") out << "(w" << width << ":h" << height << ":z" << z_levels << ")"; out << ":" << amount << ":" << flowmode << ":" << setmode << "]\n"; return df_liquids_execute(out); }
command_result cleanunits (color_ostream &out) { // Invoked from clean(), already suspended int cleaned_units = 0, cleaned_total = 0; for (size_t i = 0; i < world->units.all.size(); i++) { df::unit *unit = world->units.all[i]; if (unit->body.spatters.size()) { for (size_t j = 0; j < unit->body.spatters.size(); j++) delete unit->body.spatters[j]; cleaned_units++; cleaned_total += unit->body.spatters.size(); unit->body.spatters.clear(); } } if (cleaned_total) out.print("Removed %d contaminants from %d creatures.\n", cleaned_total, cleaned_units); return CR_OK; }
// A command! It sits around and looks pretty. And it's nice and friendly. command_result skeleton (color_ostream &out, std::vector <std::string> & parameters) { // It's nice to print a help message you get invalid options // from the user instead of just acting strange. // This can be achieved by adding the extended help string to the // PluginCommand registration as show above, and then returning // CR_WRONG_USAGE from the function. The same string will also // be used by 'help your-command'. if (!parameters.empty()) return CR_WRONG_USAGE; // Commands are called from threads other than the DF one. // Suspend this thread until DF has time for us. If you // use CoreSuspender, it'll automatically resume DF when // execution leaves the current scope. CoreSuspender suspend; // Actually do something here. Yay. out.print("Hello! I do nothing, remember?\n"); // Give control back to DF. return CR_OK; }
void revealAdventure(color_ostream &out) { for (size_t i = 0; i < world->map.map_blocks.size(); i++) { df::map_block *block = world->map.map_blocks[i]; // in 'no-hell'/'safe' mode, don't reveal blocks with hell and adamantine if (!isSafe(block->map_pos)) continue; designations40d & designations = block->designation; // for each tile in block for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++) { // set to revealed designations[x][y].bits.hidden = 0; // and visible designations[x][y].bits.pile = 1; } } out.print("Local map revealed.\n"); }
static command_result df_rubyeval(color_ostream &out, std::vector <std::string> & parameters) { command_result ret; if (parameters.size() == 1 && (parameters[0] == "help" || parameters[0] == "?")) { out.print("This command executes an arbitrary ruby statement.\n"); return CR_OK; } std::string full = ""; for (unsigned i=0 ; i<parameters.size() ; ++i) { full += parameters[i]; if (i != parameters.size()-1) full += " "; } return plugin_eval_rb(full); }
command_result cleanplants (color_ostream &out) { // Invoked from clean(), already suspended int cleaned_plants = 0, cleaned_total = 0; for (size_t i = 0; i < world->plants.all.size(); i++) { df::plant *plant = world->plants.all[i]; if (plant->contaminants.size()) { for (size_t j = 0; j < plant->contaminants.size(); j++) delete plant->contaminants[j]; cleaned_plants++; cleaned_total += plant->contaminants.size(); plant->contaminants.clear(); } } if (cleaned_total) out.print("Removed %d contaminants from %d plants.\n", cleaned_total, cleaned_plants); return CR_OK; }
void checkBuildings(color_ostream& out, void* data) { if ( !enabled ) return; std::vector<df::building*>& buildings = df::global::world->buildings.all; for ( size_t a = 0; a < buildings.size(); a++ ) { df::building* building = buildings[a]; if ( building == NULL ) continue; if ( building->getCustomType() < 0 ) continue; df::coord pos(building->centerx,building->centery,building->z); df::tile_designation* des = Maps::getTileDesignation(pos); bool outside = des->bits.outside; df::building_def* def = df::global::world->raws.buildings.all[building->getCustomType()]; int32_t type = registeredBuildings[def->code]; if ( type == EITHER ) { registeredBuildings.erase(def->code); } else if ( type == OUTSIDE_ONLY ) { if ( outside ) continue; destroy(building); } else if ( type == INSIDE_ONLY ) { if ( !outside ) continue; destroy(building); } else { if ( DFHack::Once::doOnce("outsideOnly invalid setting") ) { out.print("Error: outsideOnly: building has invalid setting: %s %d\n", def->code.c_str(), type); } } } if ( checkEvery < 0 ) return; EventManager::EventHandler timeHandler(checkBuildings,-1); EventManager::registerTick(timeHandler, checkEvery, plugin_self); }
command_result revforget(color_ostream &out, vector<string> & params) { auto & con = out; 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; } } if(!revealed) { con.printerr("There's nothing to forget!\n"); return CR_FAILURE; } // give back memory. hidesaved.clear(); revealed = NOT_REVEALED; con.print("Reveal data forgotten!\n"); return CR_OK; }
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) { switch (event) { case SC_WORLD_LOADED: if (find_reactions(out)) { out.print("Detected spatter add reactions - enabling plugin.\n"); enable_hooks(true); } else enable_hooks(false); break; case SC_WORLD_UNLOADED: enable_hooks(false); reactions.clear(); products.clear(); break; default: break; } return CR_OK; }
command_result trackmenu (color_ostream &out, vector <string> & parameters) { if(trackmenu_flg) { trackmenu_flg = false; return CR_OK; } else { if(df::global::ui) { trackmenu_flg = true; last_menu = df::global::ui->main.mode; out.print("Menu: %d\n",last_menu); return CR_OK; } else { out.printerr("Can't read menu state\n"); return CR_FAILURE; } } }
command_result df_createitem (color_ostream &out, vector <string> & parameters) { string item_str, material_str; df::item_type item_type = item_type::NONE; int16_t item_subtype = -1; int16_t mat_type = -1; int32_t mat_index = -1; int count = 1; bool move_to_cursor = false; if (parameters.size() == 1) { if (parameters[0] == "floor") { dest_container = -1; dest_building = -1; out.print("Items created will be placed on the floor.\n"); return CR_OK; } else if (parameters[0] == "item") { dest_building = -1; df::item *item = Gui::getSelectedItem(out); if (!item) { out.printerr("You must select a container!\n"); return CR_FAILURE; } switch (item->getType()) { case item_type::FLASK: case item_type::BARREL: case item_type::BUCKET: case item_type::ANIMALTRAP: case item_type::BOX: case item_type::BIN: case item_type::BACKPACK: case item_type::QUIVER: break; case item_type::TOOL: if (item->hasToolUse(tool_uses::LIQUID_CONTAINER)) break; if (item->hasToolUse(tool_uses::FOOD_STORAGE)) break; if (item->hasToolUse(tool_uses::SMALL_OBJECT_STORAGE)) break; if (item->hasToolUse(tool_uses::TRACK_CART)) break; default: out.printerr("The selected item cannot be used for item storage!\n"); return CR_FAILURE; } dest_container = item->id; string name; item->getItemDescription(&name, 0); out.print("Items created will be placed inside %s.\n", name.c_str()); return CR_OK; } else if (parameters[0] == "building") { dest_container = -1; df::building *building = Gui::getSelectedBuilding(out); if (!building) { out.printerr("You must select a building!\n"); return CR_FAILURE; } switch (building->getType()) { case building_type::Coffin: case building_type::Furnace: case building_type::TradeDepot: case building_type::Shop: case building_type::Box: case building_type::Weaponrack: case building_type::Armorstand: case building_type::Workshop: case building_type::Cabinet: case building_type::SiegeEngine: case building_type::Trap: case building_type::AnimalTrap: case building_type::Cage: case building_type::Wagon: case building_type::NestBox: case building_type::Hive: break; default: out.printerr("The selected building cannot be used for item storage!\n"); return CR_FAILURE; } if (building->getBuildStage() != building->getMaxBuildStage()) { out.printerr("The selected building has not yet been fully constructed!\n"); return CR_FAILURE; } dest_building = building->id; string name; building->getName(&name); out.print("Items created will be placed inside %s.\n", name.c_str()); return CR_OK; } else return CR_WRONG_USAGE; } if ((parameters.size() < 2) || (parameters.size() > 3)) return CR_WRONG_USAGE; item_str = parameters[0]; material_str = parameters[1]; if (parameters.size() == 3) { stringstream ss(parameters[2]); ss >> count; if (count < 1) { out.printerr("You cannot produce less than one item!\n"); return CR_FAILURE; } }
command_result changelayer (color_ostream &out, std::vector <std::string> & parameters) { CoreSuspender suspend; string material; bool force = false; bool all_biomes = false; bool all_layers = false; bool verbose = false; warned = false; for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") { out.print(changelayer_help.c_str()); return CR_OK; } if(parameters[i] == "trouble") { out.print(changelayer_trouble.c_str()); return CR_OK; } if(parameters[i] == "force") force = true; if(parameters[i] == "all_biomes") all_biomes = true; if(parameters[i] == "all_layers") all_layers = true; if(parameters[i] == "verbose") verbose = true; } if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } if (parameters.empty()) { out.printerr("You need to specify a material!\n"); return CR_WRONG_USAGE; } material = parameters[0]; MaterialInfo mat_new; if (!mat_new.findInorganic(material)) { out.printerr("No such material!\n"); return CR_FAILURE; } // check if specified material is stone or gem or soil if (mat_new.inorganic->material.flags.is_set(material_flags::IS_METAL) || mat_new.inorganic->material.flags.is_set(material_flags::NO_STONE_STOCKPILE)) { out.printerr("Invalid material - you must select a type of stone or gem or soil.\n"); return CR_FAILURE; } MapExtras::MapCache mc; int32_t regionX, regionY, regionZ; Maps::getPosition(regionX,regionY,regionZ); int32_t cursorX, cursorY, cursorZ; Gui::getCursorCoords(cursorX,cursorY,cursorZ); if(cursorX == -30000) { out.printerr("No cursor; place cursor over tile.\n"); return CR_FAILURE; } DFCoord cursor (cursorX,cursorY,cursorZ); uint32_t blockX = cursorX / 16; uint32_t tileX = cursorX % 16; uint32_t blockY = cursorY / 16; uint32_t tileY = cursorY % 16; MapExtras::Block * b = mc.BlockAt(cursor/16); if(!b || !b->is_valid()) { out.printerr("No data.\n"); return CR_OK; } df::tile_designation des = b->DesignationAt(cursor%16); // get biome and geolayer at cursor position uint32_t biome = des.bits.biome; uint32_t layer = des.bits.geolayer_index; if(verbose) { out << "biome: " << biome << endl << "geolayer: " << layer << endl; } // there is no Maps::WriteGeology or whatever, and I didn't want to mess with the library and add it // so I copied the stuff which reads the geology information and modified it to be able to change it // // a more elegant solution would probably look like this: // 1) modify Maps::ReadGeology to accept and fill one more optional vector // where the geolayer ids of the 9 biomes are stored // 2) call ReadGeology here, modify the data in the vectors without having to do all that map stuff // 3) write Maps::WriteGeology, pass the vectors, let it do it's work // Step 1) is optional, but it would make implementing 3) easier. // Otherwise that "check which geo_index is used by biome X" loop would need to be done again. // no need to touch the same geology more than once // though it wouldn't matter much since there is not much data to be processed vector<uint16_t> v_geoprocessed; v_geoprocessed.clear(); // iterate over 8 surrounding regions + local region for (int i = eNorthWest; i < eBiomeCount; i++) { if(verbose) out << "---Biome: " << i; if(!all_biomes && i!=biome) { if(verbose) out << "-skipping" << endl; continue; } else { if(verbose) out << "-checking" << endl; } // check against worldmap boundaries, fix if needed // regionX is in embark squares // regionX/16 is in 16x16 embark square regions // i provides -1 .. +1 offset from the current region int bioRX = world->map.region_x / 16 + ((i % 3) - 1); if (bioRX < 0) bioRX = 0; if (bioRX >= world->world_data->world_width) bioRX = world->world_data->world_width - 1; int bioRY = world->map.region_y / 16 + ((i / 3) - 1); if (bioRY < 0) bioRY = 0; if (bioRY >= world->world_data->world_height) bioRY = world->world_data->world_height - 1; // get index into geoblock vector uint16_t geoindex = world->world_data->region_map[bioRX][bioRY].geo_index; if(verbose) out << "geoindex: " << geoindex << endl; bool skip = false; for(int g=0; g<v_geoprocessed.size(); g++) { if(v_geoprocessed.at(g)==geoindex) { if(verbose) out << "already processed" << endl; skip = true; break; } } if(skip) continue; v_geoprocessed.push_back(geoindex); /// geology blocks have a vector of layer descriptors // get the vector with pointer to layers df::world_geo_biome *geo_biome = df::world_geo_biome::find(geoindex); if (!geo_biome) { if(verbose) out << "no geology found here." << endl; continue; } vector <df::world_geo_layer*> &geolayers = geo_biome->layers; // complain if layer is out of range // geology has up to 16 layers currently, but can have less! if(layer >= geolayers.size() || layer < 0) { if(verbose) out << "layer out of range!"; continue; } // now let's actually write the new mat id to the layer(s) if(all_layers) { for (size_t j = 0; j < geolayers.size(); j++) { MaterialInfo mat_old; mat_old.decode(0, geolayers[j]->mat_index); if(conversionAllowed(out, mat_new, mat_old, force)) { if(verbose) out << "changing geolayer " << j << " from " << mat_old.getToken() << " to " << mat_new.getToken() << endl; geolayers[j]->mat_index = mat_new.index; } } } else { MaterialInfo mat_old; mat_old.decode(0, geolayers[layer]->mat_index); if(conversionAllowed(out, mat_new, mat_old, force)) { if(verbose) out << "changing geolayer " << layer << " from " << mat_old.getToken() << " to " << mat_new.getToken() << endl; geolayers[layer]->mat_index = mat_new.index; } } } out.print("Done.\n"); // Give control back to DF. return CR_OK; }
command_result df_seedwatch(color_ostream &out, vector<string>& parameters) { CoreSuspender suspend; map<string, t_materialIndex> materialsReverser; for(size_t i = 0; i < world->raws.plants.all.size(); ++i) { materialsReverser[world->raws.plants.all[i]->id] = i; } t_gamemodes gm; World::ReadGameMode(gm);// FIXME: check return value // if game mode isn't fortress mode if(gm.g_mode != game_mode::DWARF || !(gm.g_type == game_type::DWARF_MAIN || gm.g_type == game_type::DWARF_RECLAIM)) { // just print the help printHelp(out); return CR_OK; } string par; int limit; switch(parameters.size()) { case 0: printHelp(out); break; case 1: par = parameters[0]; if(par == "help") printHelp(out); else if(par == "?") printHelp(out); else if(par == "start") { running = true; out.print("seedwatch supervision started.\n"); } else if(par == "stop") { running = false; out.print("seedwatch supervision stopped.\n"); } else if(par == "clear") { Kitchen::clearLimits(); out.print("seedwatch watchlist cleared\n"); } else if(par == "info") { out.print("seedwatch Info:\n"); if(running) { out.print("seedwatch is supervising. Use 'seedwatch stop' to stop supervision.\n"); } else { out.print("seedwatch is not supervising. Use 'seedwatch start' to start supervision.\n"); } map<t_materialIndex, unsigned int> watchMap; Kitchen::fillWatchMap(watchMap); if(watchMap.empty()) { out.print("The watch list is empty.\n"); } else { out.print("The watch list is:\n"); for(map<t_materialIndex, unsigned int>::const_iterator i = watchMap.begin(); i != watchMap.end(); ++i) { out.print("%s : %u\n", world->raws.plants.all[i->first]->id.c_str(), i->second); } } } else if(par == "debug") { map<t_materialIndex, unsigned int> watchMap; Kitchen::fillWatchMap(watchMap); Kitchen::debug_print(out); } /* else if(par == "dumpmaps") { out.print("Plants:\n"); for(auto i = plantMaterialTypes.begin(); i != plantMaterialTypes.end(); i++) { auto t = materialsModule.df_organic->at(i->first); out.print("%s : %u %u\n", organics[i->first].id.c_str(), i->second, t->material_basic_mat); } out.print("Seeds:\n"); for(auto i = seedMaterialTypes.begin(); i != seedMaterialTypes.end(); i++) { auto t = materialsModule.df_organic->at(i->first); out.print("%s : %u %u\n", organics[i->first].id.c_str(), i->second, t->material_seed); } } */ else { string token = searchAbbreviations(par); if(materialsReverser.count(token) > 0) { Kitchen::removeLimit(materialsReverser[token]); out.print("%s is not being watched\n", token.c_str()); } else { out.print("%s has not been found as a material.\n", token.c_str()); } } break; case 2: limit = atoi(parameters[1].c_str()); if(limit < 0) limit = 0; if(parameters[0] == "all") { for(map<string, string>::const_iterator i = abbreviations.begin(); i != abbreviations.end(); ++i) { if(materialsReverser.count(i->second) > 0) Kitchen::setLimit(materialsReverser[i->second], limit); } } else { string token = searchAbbreviations(parameters[0]); if(materialsReverser.count(token) > 0) { Kitchen::setLimit(materialsReverser[token], limit); out.print("%s is being watched.\n", token.c_str()); } else { out.print("%s has not been found as a material.\n", token.c_str()); } } break; default: printHelp(out); break; } return CR_OK; }