void DFHack::Lua::InvokeEvent(color_ostream &out, lua_State *state, void *key, int num_args) { AssertCoreSuspend(state); int base = lua_gettop(state) - num_args; if (!lua_checkstack(state, num_args+4)) { out.printerr("Stack overflow in Lua::InvokeEvent"); lua_settop(state, base); return; } lua_rawgetp(state, LUA_REGISTRYINDEX, key); if (!lua_istable(state, -1)) { if (!lua_isnil(state, -1)) out.printerr("Invalid event object in Lua::InvokeEvent"); lua_settop(state, base); return; } lua_insert(state, base+1); color_ostream *cur_out = Lua::GetOutput(state); set_dfhack_output(state, &out); dfhack_event_invoke(state, base, true); set_dfhack_output(state, cur_out); }
command_result outsideOnly(color_ostream& out, vector<string>& parameters) { int32_t status = 2; for ( size_t a = 0; a < parameters.size(); a++ ) { if ( parameters[a] == "clear" ) { registeredBuildings.clear(); } else if ( parameters[a] == "outside" ) { status = OUTSIDE_ONLY; } else if ( parameters[a] == "inside" ) { status = INSIDE_ONLY; } else if ( parameters[a] == "either" ) { status = EITHER; } else if ( parameters[a] == "checkEvery" ) { if (a+1 >= parameters.size()) { out.printerr("You must specify how often to check.\n"); return CR_WRONG_USAGE; } checkEvery = atoi(parameters[a].c_str()); } else { if ( status == 2 ) { out.printerr("Error: you need to tell outsideOnly whether the building is inside only, outside-only or either.\n"); return CR_WRONG_USAGE; } registeredBuildings[parameters[a]] = status; } } out.print("outsideOnly is %s\n", enabled ? "enabled" : "disabled"); if ( enabled ) { } return CR_OK; }
command_result spotclean (color_ostream &out, vector <string> & parameters) { // HOTKEY COMMAND: CORE ALREADY SUSPENDED if (cursor->x == -30000) { out.printerr("The cursor is not active.\n"); return CR_WRONG_USAGE; } if (!Maps::IsValid()) { out.printerr("Map is not available.\n"); return CR_FAILURE; } df::map_block *block = Maps::getTileBlock(cursor->x, cursor->y, cursor->z); if (block == NULL) { out.printerr("Invalid map block selected!\n"); return CR_FAILURE; } for (size_t i = 0; i < block->block_events.size(); i++) { df::block_square_event *evt = block->block_events[i]; if (evt->getType() != block_square_event_type::material_spatter) continue; // type verified - recast to subclass df::block_square_event_material_spatterst *spatter = (df::block_square_event_material_spatterst *)evt; spatter->amount[cursor->x % 16][cursor->y % 16] = 0; } return CR_OK; }
bool Plugin::unload(color_ostream &con) { // get the mutex access->lock(); // if we are actually loaded if(state == PS_LOADED) { EventManager::unregisterAll(this); // notify the plugin about an attempt to shutdown if (plugin_onstatechange && plugin_onstatechange(con, SC_BEGIN_UNLOAD) != CR_OK) { con.printerr("Plugin %s has refused to be unloaded.\n", name.c_str()); access->unlock(); return false; } // wait for all calls to finish access->wait(); state = PS_UNLOADING; access->unlock(); // enter suspend CoreSuspender suspend; access->lock(); // notify plugin about shutdown, if it has a shutdown function command_result cr = CR_OK; if(plugin_shutdown) cr = plugin_shutdown(con); // cleanup... plugin_is_enabled = 0; plugin_onupdate = 0; reset_lua(); parent->unregisterCommands(this); commands.clear(); if(cr == CR_OK) { ClosePlugin(plugin_lib); state = PS_UNLOADED; access->unlock(); return true; } else { con.printerr("Plugin %s has failed to shutdown!\n",name.c_str()); state = PS_BROKEN; access->unlock(); return false; } } else if(state == PS_UNLOADED) { access->unlock(); return true; } access->unlock(); return false; }
static command_result rename(color_ostream &out, vector <string> ¶meters) { CoreSuspender suspend; string cmd; if (!parameters.empty()) cmd = parameters[0]; if (cmd == "hotkey") { if (parameters.size() != 3) return CR_WRONG_USAGE; int id = atoi(parameters[1].c_str()); if (id < 1 || id > 16) { out.printerr("Invalid hotkey index\n"); return CR_WRONG_USAGE; } ui->main.hotkeys[id-1].name = parameters[2]; } else if (cmd == "unit") { if (parameters.size() != 2) return CR_WRONG_USAGE; df::unit *unit = Gui::getSelectedUnit(out, true); if (!unit) return CR_WRONG_USAGE; Units::setNickname(unit, parameters[1]); } else if (cmd == "unit-profession") { if (parameters.size() != 2) return CR_WRONG_USAGE; df::unit *unit = Gui::getSelectedUnit(out, true); if (!unit) return CR_WRONG_USAGE; unit->custom_profession = parameters[1]; } else { if (!parameters.empty() && cmd != "?") out.printerr("Invalid command: %s\n", cmd.c_str()); return CR_WRONG_USAGE; } return CR_OK; }
static bool recover_job(color_ostream &out, ProtectedJob *pj) { if (pj->isLive()) return true; // Check that the building exists pj->holder = df::building::find(pj->building_id); if (!pj->holder) { out.printerr("Forgetting job %d (%s): holder building lost.\n", pj->id, ENUM_KEY_STR(job_type, pj->job_copy->job_type).c_str()); forget_job(out, pj); return true; } // Check its state and postpone or cancel if invalid if (pj->holder->jobs.size() >= 10) { out.printerr("Forgetting job %d (%s): holder building has too many jobs.\n", pj->id, ENUM_KEY_STR(job_type, pj->job_copy->job_type).c_str()); forget_job(out, pj); return true; } if (!pj->holder->jobs.empty()) { df::job_type ftype = pj->holder->jobs[0]->job_type; if (ftype == job_type::DestroyBuilding) return false; if (ENUM_ATTR(job_type,type,ftype) == job_type_class::StrangeMood) return false; } // Create and link in the actual job structure df::job *recovered = Job::cloneJobStruct(pj->job_copy); if (!Job::linkIntoWorld(recovered, false)) // reuse same id { Job::deleteJobStruct(recovered); out.printerr("Inconsistency: job %d (%s) already in list.\n", pj->id, ENUM_KEY_STR(job_type, pj->job_copy->job_type).c_str()); return true; } pj->holder->jobs.push_back(recovered); // Done pj->recover(recovered); return true; }
command_result cmd_fix_unit_occupancy (color_ostream &out, std::vector <std::string> & parameters) { CoreSuspender suspend; uo_opts opts; bool ok = true; if (parameters.size() >= 1 && (parameters[0] == "-i" || parameters[0].find("interval") != std::string::npos)) { if (parameters.size() >= 2) { int new_interval = atoi(parameters[1].c_str()); if (new_interval < 100) { out.printerr("Invalid interval - minimum is 100 ticks\n"); return CR_WRONG_USAGE; } run_interval = new_interval; if (!is_enabled) out << "note: Plugin not enabled (use `enable fix-unit-occupancy` to enable)" << endl; return CR_OK; } else return CR_WRONG_USAGE; } for (auto opt = parameters.begin(); opt != parameters.end(); ++opt) { if (*opt == "-n" || opt->find("dry") != std::string::npos) opts.dry_run = true; else if (*opt == "-h" || opt->find("cursor") != std::string::npos || opt->find("here") != std::string::npos) opts.use_cursor = true; else if (opt->find("enable") != std::string::npos) plugin_enable(out, true); else if (opt->find("disable") != std::string::npos) plugin_enable(out, false); else { out.printerr("Unknown parameter: %s\n", opt->c_str()); ok = false; } } if (!ok) return CR_WRONG_USAGE; unsigned count = fix_unit_occupancy(out, opts); if (!count) out << "No occupancy issues found." << endl; return CR_OK; }
command_result cmd_3dveins(color_ostream &con, std::vector<std::string> & parameters) { bool verbose = false; for (size_t i = 0; i < parameters.size(); i++) { if (parameters[i] == "verbose") verbose = true; else return CR_WRONG_USAGE; } CoreSuspender suspend; if (!Maps::IsValid()) { con.printerr("Map is not available!\n"); return CR_FAILURE; } if (*gametype != game_type::DWARF_MAIN && *gametype != game_type::DWARF_RECLAIM) { con.printerr("Must be used in fortress mode!\n"); return CR_FAILURE; } VeinGenerator generator(con); con.print("Collecting statistics...\n"); if (!generator.init_biomes()) return CR_FAILURE; if (!generator.scan_tiles()) return CR_FAILURE; con.print("Generating veins...\n"); if (!generator.form_veins()) return CR_FAILURE; if (!generator.place_veins(verbose)) return CR_FAILURE; con.print("Writing tiles...\n"); generator.write_tiles(); 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; }
command_result df_grow (color_ostream &out, vector <string> & parameters) { for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") { out << "Usage:\n" "This command turns all living saplings on the map into full-grown trees.\n" "With active cursor, work on the targetted one only.\n"; return CR_OK; } } CoreSuspender suspend; if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } MapExtras::MapCache map; int32_t x,y,z; if(Gui::getCursorCoords(x,y,z)) { auto block = Maps::getTileBlock(x,y,z); stl::vector<df::plant *> *alltrees = &world->plants.all; if(alltrees) { for(size_t i = 0 ; i < alltrees->size(); i++) { df::plant * tree = alltrees->at(i); if(tree->pos.x == x && tree->pos.y == y && tree->pos.z == z) { if(tileShape(map.tiletypeAt(DFCoord(x,y,z))) == tiletype_shape::SAPLING && tileSpecial(map.tiletypeAt(DFCoord(x,y,z))) != tiletype_special::DEAD) { tree->grow_counter = sapling_to_tree_threshold; } break; } } } } else { int grown = 0; for(size_t i = 0 ; i < world->plants.all.size(); i++) { df::plant *p = world->plants.all[i]; df::tiletype ttype = map.tiletypeAt(df::coord(p->pos.x,p->pos.y,p->pos.z)); bool is_shrub = p->flags >= plant_flags::shrub_forest; if(!is_shrub && tileShape(ttype) == tiletype_shape::SAPLING && tileSpecial(ttype) != tiletype_special::DEAD) { p->grow_counter = sapling_to_tree_threshold; } } } return CR_OK; }
command_result lair(color_ostream &out, std::vector<std::string> & params) { state do_what = LAIR_SET; for(auto iter = params.begin(); iter != params.end(); iter++) { if(*iter == "reset") do_what = LAIR_RESET; } CoreSuspender lock; if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } uint32_t x_max,y_max,z_max; Maps::getSize(x_max,y_max,z_max); for (size_t i = 0; i < world->map.map_blocks.size(); i++) { df::map_block *block = world->map.map_blocks[i]; DFHack::occupancies40d & occupancies = block->occupancy; // for each tile in block for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++) { // set to revealed occupancies[x][y].bits.monster_lair = (do_what == LAIR_SET); } } if(do_what == LAIR_SET) out.print("Map marked as lair.\n"); else out.print("Map no longer marked as lair.\n"); return CR_OK; }
command_result df_immolate (color_ostream &out, vector <string> & parameters, do_what what) { bool shrubs = false, trees = false, help = false; if (getoptions(parameters, shrubs, trees, help) && !help) { return immolations(out, what, shrubs, trees); } string mode; if (what == do_immolate) mode = "Set plants on fire"; else mode = "Kill plants"; if (!help) out.printerr("Invalid parameter!\n"); out << "Usage:\n" << mode << " (under cursor, 'shrubs', 'trees' or 'all').\n" "Without any options, this command acts on the plant under the cursor.\n" "Options:\n" "shrubs - affect all shrubs\n" "trees - affect all trees\n" "all - affect all plants\n"; return CR_OK; }
command_result wagonshot (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 murder.\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) { if (parameters.size() == 1 && (parameters[0] == "--kill" || parameters[0] == "-k")) { unit->flags3.bits.scuttle = 1; //out.print("Boom! Wagonshot!\n"); continue; } else { out.print("'wagonshot --kill' short and sweet\n(or 'wagonshot -k' even shorter). No condiments needed. That's what the wagon provides.\nNow show me where we drop the wagon.\n"); break; } } } } return CR_OK; }
static void init_state(color_ostream &out) { auto pworld = Core::getInstance().getWorld(); config = pworld->GetPersistentData("workflow/config"); if (config.isValid() && config.ival(0) == -1) config.ival(0) = 0; enabled = isOptionEnabled(CF_ENABLED); // Parse constraints std::vector<PersistentDataItem> items; pworld->GetPersistentData(&items, "workflow/constraints"); for (int i = items.size()-1; i >= 0; i--) { if (get_constraint(out, items[i].val(), &items[i])) continue; out.printerr("Lost constraint %s\n", items[i].val().c_str()); pworld->DeletePersistentData(items[i]); } last_tick_frame_count = world->frame_counter; last_frame_count = world->frame_counter; if (!enabled) return; start_protect(out); }
bool read_order(color_ostream &out, lua_State *L, std::vector<unsigned> *order, size_t size) { std::vector<char> found; Lua::StackUnwinder frame(L, 1); if (!lua_istable(L, -1)) { out.printerr("Not a table returned as ordering.\n"); return false; } if (lua_rawlen(L, -1) != size) { out.printerr("Invalid ordering size: expected %d, actual %d\n", size, lua_rawlen(L, -1)); return false; } order->clear(); order->resize(size); found.resize(size); for (size_t i = 1; i <= size; i++) { lua_rawgeti(L, frame[1], i); int v = lua_tointeger(L, -1); lua_pop(L, 1); if (v < 1 || size_t(v) > size) { out.printerr("Order value out of range: %d\n", v); return false; } if (found[v-1]) { out.printerr("Duplicate order value: %d\n", v); return false; } found[v-1] = 1; (*order)[i-1] = v-1; } return true; }
command_result misery(color_ostream &out, vector<string>& parameters) { if ( !world || !world->map.block_index ) { out.printerr("misery can only be enabled in fortress mode with a fully-loaded game.\n"); return CR_FAILURE; } if ( parameters.size() < 1 || parameters.size() > 2 ) { return CR_WRONG_USAGE; } if ( parameters[0] == "disable" ) { if ( parameters.size() > 1 ) { return CR_WRONG_USAGE; } factor = 1; is_enabled = false; return CR_OK; } else if ( parameters[0] == "enable" ) { is_enabled = true; factor = 2; if ( parameters.size() == 2 ) { int a = atoi(parameters[1].c_str()); if ( a <= 1 ) { out.printerr("Second argument must be a positive integer.\n"); return CR_WRONG_USAGE; } factor = a; } } else if ( parameters[0] == "clear" ) { for ( size_t a = 0; a < fakeThoughts.size(); a++ ) { int dorfIndex = fakeThoughts[a].first; int thoughtIndex = fakeThoughts[a].second; world->units.all[dorfIndex]->status.recent_events[thoughtIndex]->age = 1000000; } fakeThoughts.clear(); } else { int a = atoi(parameters[0].c_str()); if ( a < 1 ) { return CR_WRONG_USAGE; } factor = a; is_enabled = factor > 1; } return CR_OK; }
command_result reveal(color_ostream &out, vector<string> & params) { bool pause = true; for(size_t i = 0; i < params.size();i++) { if(params[i] == "help" || params[i] == "?") return CR_WRONG_USAGE; } auto & con = out; if(revealed != NOT_REVEALED) { con.printerr("Map is already revealed or this is a different map.\n"); return CR_FAILURE; } CoreSuspender suspend; if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } t_gamemodes gm; World::ReadGameMode(gm); if(gm.g_mode == game_mode::ADVENTURE) { revealAdventure(out); return CR_OK; } if(gm.g_mode != game_mode::DWARF) { con.printerr("Only in fortress mode.\n"); return CR_FAILURE; } Maps::getSize(x_max,y_max,z_max); hidesaved.reserve(x_max * y_max * z_max); for (size_t i = 0; i < world->map.map_blocks.size(); i++) { df::map_block *block = world->map.map_blocks[i]; hideblock hb; hb.c = block->map_pos; 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++) { // save hidden state of tile hb.hiddens[x][y] = designations[x][y].bits.hidden; // set to revealed designations[x][y].bits.hidden = 0; } hidesaved.push_back(hb); } revealed = REVEALED; con.print("Map revealed.\n"); con.print("Run 'unreveal' to revert to previous state.\n"); return CR_OK; }
/** * Initialize the plugin */ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) { // This seems to verify that the default labor list and the current labor // list are the same size if(ARRAY_COUNT(default_labor_infos) != ENUM_LAST_ITEM(unit_labor) + 1) { out.printerr("autohauler: labor size mismatch\n"); return CR_FAILURE; } // Essentially an introduction dumped to the console commands.push_back(PluginCommand( "autohauler", "Automatically manage hauling labors.", autohauler, false, /* true means that the command can't be used from non-interactive user interface */ // Extended help string. Used by CR_WRONG_USAGE and the help command: " autohauler enable\n" " autohauler disable\n" " Enables or disables the plugin.\n" " autohauler <labor> haulers\n" " Set a labor to be handled by hauler dwarves.\n" " autohauler <labor> allow\n" " Allow hauling if a specific labor is enabled.\n" " autohauler <labor> forbid\n" " Forbid hauling if a specific labor is enabled.\n" " autohauler <labor> reset\n" " Return a labor to the default handling.\n" " autohauler reset-all\n" " Return all labors to the default handling.\n" " autohauler frameskip <int>\n" " Set the number of frames between runs of autohauler.\n" " autohauler list\n" " List current status of all labors.\n" " autohauler status\n" " Show basic status information.\n" " autohauler debug\n" " In the next cycle, will output the state of every dwarf.\n" "Function:\n" " When enabled, autohauler periodically checks your dwarves and assigns\n" " hauling jobs to idle dwarves while removing them from busy dwarves.\n" " This plugin, in contrast to autolabor, is explicitly designed to be\n" " used alongside Dwarf Therapist.\n" " Warning: autohauler will override any manual changes you make to\n" " hauling labors while it is enabled...but why would you make them?\n" "Examples:\n" " autohauler HAUL_STONE haulers\n" " Set stone hauling as a hauling labor.\n" " autohauler BOWYER allow\n" " Allow hauling when the bowyer labor is enabled.\n" " autohauler MINE forbid\n" " Forbid hauling while the mining labor is disabled." )); // Initialize plugin labor lists init_state(); return CR_OK; }
command_result unreveal(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("Reverts the previous reveal operation, hiding the map again.\n"); return CR_OK; } } if(!revealed) { con.printerr("There's nothing to revert!\n"); return CR_FAILURE; } CoreSuspender suspend; World *World = Core::getInstance().getWorld(); if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } t_gamemodes gm; World->ReadGameMode(gm); if(gm.g_mode != GAMEMODE_DWARF) { con.printerr("Only in fortress mode.\n"); return CR_FAILURE; } // Sanity check: map size uint32_t x_max_b, y_max_b, z_max_b; Maps::getSize(x_max_b,y_max_b,z_max_b); if(x_max != x_max_b || y_max != y_max_b || z_max != z_max_b) { con.printerr("The map is not of the same size...\n"); return CR_FAILURE; } for(size_t i = 0; i < hidesaved.size();i++) { hideblock & hb = hidesaved[i]; df::map_block * b = Maps::getBlockAbs(hb.c.x,hb.c.y,hb.c.z); for (uint32_t x = 0; x < 16;x++) for (uint32_t y = 0; y < 16;y++) { b->designation[x][y].bits.hidden = hb.hiddens[x][y]; } } // give back memory. hidesaved.clear(); revealed = NOT_REVEALED; con.print("Map hidden!\n"); return CR_OK; }
static bool ParseSpec(color_ostream &out, lua_State *L, const char *type, vector<string> ¶ms) { if (!parse_ordering_spec(out, L, type, params)) { out.printerr("Invalid ordering specification for %s.\n", type); return false; } return true; }
void DFHack::Lua::Core::Reset(color_ostream &out, const char *where) { int top = lua_gettop(State); if (top != 0) { out.printerr("Common lua context stack top left at %d after %s.\n", top, where); lua_settop(State, 0); } }
command_result df_grow (color_ostream &out, vector <string> & 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; } } CoreSuspender suspend; if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } MapExtras::MapCache map; int32_t x,y,z; if(Gui::getCursorCoords(x,y,z)) { vector<df::plant *> * alltrees; if(Maps::ReadVegetation(x/16,y/16,z,alltrees)) { for(size_t i = 0 ; i < alltrees->size(); i++) { df::plant * tree = alltrees->at(i); if(tree->pos.x == x && tree->pos.y == y && tree->pos.z == z) { if(tileShape(map.tiletypeAt(DFCoord(x,y,z))) == tiletype_shape::SAPLING && tileSpecial(map.tiletypeAt(DFCoord(x,y,z))) != tiletype_special::DEAD) { tree->grow_counter = Vegetation::sapling_to_tree_threshold; } break; } } } } else { int grown = 0; for(size_t i = 0 ; i < world->plants.all.size(); i++) { df::plant *p = world->plants.all[i]; df::tiletype ttype = map.tiletypeAt(df::coord(p->pos.x,p->pos.y,p->pos.z)); if(!p->flags.bits.is_shrub && tileShape(ttype) == tiletype_shape::SAPLING && tileSpecial(ttype) != tiletype_special::DEAD) { p->grow_counter = Vegetation::sapling_to_tree_threshold; } } } return CR_OK; }
static void enable_plugin(color_ostream &out) { auto entry = World::GetPersistentData("fix-armory/enabled", NULL); if (!entry.isValid()) { out.printerr("Could not save the status.\n"); return; } enable_hooks(out, true); }
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands) { if (!gps || !INTERPOSE_HOOK(hotkeys_hook, feed).apply() || !INTERPOSE_HOOK(hotkeys_hook, render).apply()) out.printerr("Could not insert hotkeys hooks!\n"); commands.push_back( PluginCommand( "hotkeys", "List all keybindings active in current mode", hotkeys_cmd, false, "")); return CR_OK; }
command_result unreveal(color_ostream &out, vector<string> & params) { auto & con = out; for(size_t i = 0; i < params.size();i++) { if(params[i] == "help" || params[i] == "?") return CR_WRONG_USAGE; } if(!revealed) { con.printerr("There's nothing to revert!\n"); return CR_FAILURE; } CoreSuspender suspend; if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } t_gamemodes gm; World::ReadGameMode(gm); if(gm.g_mode != game_mode::DWARF) { con.printerr("Only in fortress mode.\n"); return CR_FAILURE; } // Sanity check: map size uint32_t x_max_b, y_max_b, z_max_b; Maps::getSize(x_max_b,y_max_b,z_max_b); if(x_max != x_max_b || y_max != y_max_b || z_max != z_max_b) { con.printerr("The map is not of the same size...\n"); return CR_FAILURE; } for(size_t i = 0; i < hidesaved.size();i++) { hideblock & hb = hidesaved[i]; df::map_block * b = Maps::getTileBlock(hb.c.x,hb.c.y,hb.c.z); for (uint32_t x = 0; x < 16;x++) for (uint32_t y = 0; y < 16;y++) { b->designation[x][y].bits.hidden = hb.hiddens[x][y]; } } // give back memory. hidesaved.clear(); revealed = NOT_REVEALED; is_active = nopause_state || (revealed == REVEALED); con.print("Map hidden!\n"); return CR_OK; }
bool bodySwap(color_ostream &out, df::unit *player) { if (!player) { out.printerr("Unit to swap is NULL\n"); return false; } auto &vec = world->units.active; int idx = linear_index(vec, player); if (idx < 0) { out.printerr("Unit to swap not found: %d\n", player->id); return false; } if (idx != 0) std::swap(vec[0], vec[idx]); return true; }
command_result df_changevein (color_ostream &out, vector <string> & parameters) { if (parameters.size() != 1) return CR_WRONG_USAGE; CoreSuspender suspend; if (!Maps::IsValid()) { out.printerr("Map is not available!\n"); return CR_FAILURE; } if (!cursor || cursor->x == -30000) { out.printerr("No cursor detected - please place the cursor over a mineral vein.\n"); return CR_FAILURE; } MaterialInfo mi; if (!mi.findInorganic(parameters[0])) { out.printerr("No such material!\n"); return CR_FAILURE; } if (mi.inorganic->material.flags.is_set(material_flags::IS_METAL) || mi.inorganic->material.flags.is_set(material_flags::NO_STONE_STOCKPILE) || mi.inorganic->flags.is_set(inorganic_flags::SOIL_ANY)) { out.printerr("Invalid material - you must select a type of stone or gem\n"); return CR_FAILURE; } df::map_block *block = Maps::getBlockAbs(cursor->x, cursor->y, cursor->z); if (!block) { out.printerr("Invalid tile selected.\n"); return CR_FAILURE; } df::block_square_event_mineralst *mineral = NULL; int tx = cursor->x % 16, ty = cursor->y % 16; for (size_t j = 0; j < block->block_events.size(); j++) { df::block_square_event *evt = block->block_events[j]; if (evt->getType() != block_square_event_type::mineral) continue; mineral = (df::block_square_event_mineralst *)evt; if (mineral->getassignment(tx, ty)) break; mineral = NULL; } if (!mineral) { out.printerr("Selected tile does not contain a mineral vein.\n"); return CR_FAILURE; } mineral->inorganic_mat = mi.index; return CR_OK; }
command_result df_extirpate (color_ostream &out, vector <string> & parameters) { bool shrubs = false, trees = false, help = false; if(getoptions(parameters,shrubs,trees, help)) { return immolations(out,do_extirpate,shrubs,trees, help); } else { out.printerr("Invalid parameter!\n"); return CR_FAILURE; } }
DFhackCExport command_result plugin_onupdate(color_ostream &out) { if (running) { // reduce processing rate static int counter = 0; if (++counter < 500) return CR_OK; counter = 0; 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)) { // stop running. running = false; out.printerr("seedwatch deactivated due to game mode switch\n"); return CR_OK; } // this is dwarf mode, continue map<t_materialSubtype, unsigned int> seedCount; // the number of seeds // count all seeds and plants by RAW material for(size_t i = 0; i < world->items.other[items_other_id::ANY_GOOD_FOOD].size(); ++i) { df::item * item = world->items.other[items_other_id::ANY_GOOD_FOOD][i]; if (item->getType() != item_type::SEEDS) continue; t_materialSubtype plant = item->getMatgloss(); if(!ignoreSeeds(item->flags)) ++seedCount[plant]; } map<t_materialSubtype, unsigned int> watchMap; Kitchen::fillWatchMap(watchMap); for(auto i = watchMap.begin(); i != watchMap.end(); ++i) { if(seedCount[i->first] <= i->second) { Kitchen::denyPlantSeedCookery(i->first); } else if(i->second + buffer < seedCount[i->first]) { Kitchen::allowPlantSeedCookery(i->first); } } } return CR_OK; }
DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { if (!Core::getInstance().isWorldLoaded()) { out.printerr("World is not loaded: please load a game first.\n"); return CR_FAILURE; } if (enable) enable_plugin(out); else disable_plugin(out); return CR_OK; }