diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 2c54aebad..55a7c250a 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -115,6 +115,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(sort sort.cpp LINK_LIBRARIES lua) # not yet. busy with other crud again... #DFHACK_PLUGIN(versionosd versionosd.cpp) + DFHACK_PLUGIN(misery misery.cpp) endif() diff --git a/plugins/fastdwarf.cpp b/plugins/fastdwarf.cpp index 5a2e2f206..400bff23b 100644 --- a/plugins/fastdwarf.cpp +++ b/plugins/fastdwarf.cpp @@ -23,33 +23,89 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out ) return CR_OK; } -static int enable_fastdwarf = false; +static bool enable_fastdwarf = false; +static bool enable_teledwarf = false; DFhackCExport command_result plugin_onupdate ( color_ostream &out ) { // check run conditions - if(!world || !world->map.block_index || !enable_fastdwarf) + if(!world || !world->map.block_index) { - // give up if we shouldn't be running' + enable_fastdwarf = enable_teledwarf = false; return CR_OK; } int32_t race = ui->race_id; int32_t civ = ui->civ_id; - - for (size_t i = 0; i < world->units.all.size(); i++) - { - df::unit *unit = world->units.all[i]; - - if (unit->race == race && unit->civ_id == civ && unit->counters.job_counter > 0) - unit->counters.job_counter = 0; - // could also patch the unit->job.current_job->completion_timer + + if ( enable_fastdwarf ) { + for (size_t i = 0; i < world->units.all.size(); i++) + { + df::unit *unit = world->units.all[i]; + + if (unit->race == race && unit->civ_id == civ && unit->counters.job_counter > 0) + unit->counters.job_counter = 0; + // could also patch the unit->job.current_job->completion_timer + } + } + if ( enable_teledwarf ) { + for (size_t i = 0; i < world->units.all.size(); i++) + { + df::unit *unit = world->units.all[i]; + + if (unit->race != race || unit->civ_id != civ || unit->path.dest.x == -30000) + continue; + if (unit->relations.draggee_id != -1 || unit->relations.dragger_id != -1) + continue; + if (unit->relations.following != 0) + continue; + + //move immediately to destination + unit->pos.x = unit->path.dest.x; + unit->pos.y = unit->path.dest.y; + unit->pos.z = unit->path.dest.z; + } } return CR_OK; } static command_result fastdwarf (color_ostream &out, vector & parameters) { - if (parameters.size() == 1 && (parameters[0] == "0" || parameters[0] == "1")) + if (parameters.size() == 1) { + if ( parameters[0] == "0" ) { + enable_fastdwarf = false; + enable_teledwarf = false; + } else if ( parameters[0] == "1" ) { + enable_fastdwarf = true; + enable_teledwarf = false; + } else { + out.print("Incorrect usage.\n"); + return CR_OK; + } + } else if (parameters.size() == 2) { + if ( parameters[0] == "0" ) { + enable_fastdwarf = false; + } else if ( parameters[0] == "1" ) { + enable_fastdwarf = true; + } else { + out.print("Incorrect usage.\n"); + return CR_OK; + } + if ( parameters[1] == "0" ) { + enable_teledwarf = false; + } else if ( parameters[1] == "1" ) { + enable_teledwarf = true; + } else { + out.print("Incorrect usage.\n"); + return CR_OK; + } + } else if (parameters.size() == 0) { + //print status + out.print("Current state: fast = %d, teleport = %d.\n", enable_fastdwarf, enable_teledwarf); + } else { + out.print("Incorrect usage.\n"); + return CR_OK; + } + /*if (parameters.size() == 1 && (parameters[0] == "0" || parameters[0] == "1")) { if (parameters[0] == "0") enable_fastdwarf = 0; @@ -62,7 +118,7 @@ static command_result fastdwarf (color_ostream &out, vector & parameter out.print("Makes your minions move at ludicrous speeds.\n" "Activate with 'fastdwarf 1', deactivate with 'fastdwarf 0'.\n" "Current state: %d.\n", enable_fastdwarf); - } + }*/ return CR_OK; } @@ -70,8 +126,17 @@ static command_result fastdwarf (color_ostream &out, vector & parameter DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand("fastdwarf", - "enable/disable fastdwarf (parameter=0/1)", - fastdwarf)); - + "enable/disable fastdwarf and teledwarf (parameters=0/1)", + fastdwarf, false, + "fastdwarf: controls speedydwarf and teledwarf. Speedydwarf makes dwarves move quickly and perform tasks quickly. Teledwarf makes dwarves move instantaneously, but do jobs at the same speed.\n" + "Usage:\n" + " fastdwarf 0 0: disable both speedydwarf and teledwarf\n" + " fastdwarf 0 1: disable speedydwarf, enable teledwarf\n" + " fastdwarf 1 0: enable speedydwarf, disable teledwarf\n" + " fastdwarf 1 1: enable speedydwarf, enable teledwarf\n" + " fastdwarf 0: disable speedydwarf, disable teledwarf\n" + " fastdwarf 1: enable speedydwarf, disable teledwarf\n" + )); + return CR_OK; } diff --git a/plugins/misery.cpp b/plugins/misery.cpp new file mode 100644 index 000000000..a0c0a2390 --- /dev/null +++ b/plugins/misery.cpp @@ -0,0 +1,183 @@ +#include "PluginManager.h" +#include "Export.h" + +#include "DataDefs.h" +#include "df/world.h" +#include "df/ui.h" +#include "df/unit.h" +#include "df/unit_thought.h" +#include "df/unit_thought_type.h" + +#include +#include +#include +using namespace std; + +using namespace DFHack; + +static int factor = 1; +static map processedThoughtCountTable; + +//keep track of fake thoughts so you can remove them if requested +static vector > fakeThoughts; +static int count; +const int maxCount = 1000; + +DFHACK_PLUGIN("misery"); + +command_result misery(color_ostream& out, vector& parameters); + +DFhackCExport command_result plugin_shutdown(color_ostream& out) { + factor = 1; + return CR_OK; +} + +DFhackCExport command_result plugin_onupdate(color_ostream& out) { + static bool wasLoaded = false; + if ( factor == 1 || !df::global::world || !df::global::world->map.block_index ) { + if ( wasLoaded ) { + //we just unloaded the game: clear all data + factor = 1; + processedThoughtCountTable.clear(); + fakeThoughts.clear(); + wasLoaded = false; + } + return CR_OK; + } + + if ( !wasLoaded ) { + wasLoaded = true; + } + + if ( count < maxCount ) { + count++; + return CR_OK; + } + count = 0; + + int32_t race_id = df::global::ui->race_id; + int32_t civ_id = df::global::ui->civ_id; + for ( size_t a = 0; a < df::global::world->units.all.size(); a++ ) { + df::unit* unit = df::global::world->units.all[a]; //TODO: consider units.active + //living, native units only + if ( unit->race != race_id || unit->civ_id != civ_id ) + continue; + if ( unit->flags1.bits.dead ) + continue; + + int processedThoughtCount; + map::iterator i = processedThoughtCountTable.find(unit->id); + if ( i == processedThoughtCountTable.end() ) { + processedThoughtCount = unit->status.recent_events.size(); + processedThoughtCountTable[unit->id] = processedThoughtCount; + } else { + processedThoughtCount = (*i).second; + } + + if ( processedThoughtCount == unit->status.recent_events.size() ) { + continue; + } else if ( processedThoughtCount > unit->status.recent_events.size() ) { + processedThoughtCount = unit->status.recent_events.size(); + } + + //don't reprocess any old thoughts + vector newThoughts; + for ( size_t b = processedThoughtCount; b < unit->status.recent_events.size(); b++ ) { + df::unit_thought* oldThought = unit->status.recent_events[b]; + const char* bob = ENUM_ATTR(unit_thought_type, value, oldThought->type); + if ( bob[0] != '-' ) { + //out.print("unit %4d: old thought value = %s\n", unit->id, bob); + continue; + } + /*out.print("unit %4d: Duplicating thought type %d (%s), value %s, age %d, subtype %d, severity %d\n", + unit->id, + oldThought->type.value, + ENUM_ATTR(unit_thought_type, caption, (oldThought->type)), + //df::enum_traits::attr_table[oldThought->type].caption + bob, + oldThought->age, + oldThought->subtype, + oldThought->severity + );*/ + //add duplicate thoughts to the temp list + for ( size_t c = 0; c < factor; c++ ) { + df::unit_thought* thought = new df::unit_thought; + thought->type = unit->status.recent_events[b]->type; + thought->age = unit->status.recent_events[b]->age; + thought->subtype = unit->status.recent_events[b]->subtype; + thought->severity = unit->status.recent_events[b]->severity; + newThoughts.push_back(thought); + } + } + for ( size_t b = 0; b < newThoughts.size(); b++ ) { + fakeThoughts.push_back(std::pair(a, unit->status.recent_events.size())); + unit->status.recent_events.push_back(newThoughts[b]); + } + processedThoughtCountTable[unit->id] = unit->status.recent_events.size(); + } + + return CR_OK; +} + +DFhackCExport command_result plugin_init(color_ostream& out, vector &commands) { + commands.push_back(PluginCommand("misery", "increase the intensity of negative dwarven thoughts", + &misery, false, + "misery: When enabled, every new negative dwarven thought will be multiplied by a factor (2 by default).\n" + "Usage:\n" + " misery enable n\n" + " enable misery with optional magnitude n. If specified, n must be positive.\n" + " misery n\n" + " same as \"misery enable n\"\n" + " misery enable\n" + " same as \"misery enable 2\"\n" + " misery disable\n" + " stop adding new negative thoughts. This will not remove existing duplicated thoughts. Equivalent to \"misery 1\"\n" + " misery clear\n" + " remove fake thoughts added in this session of DF. Saving makes them permanent! Does not change factor.\n\n" + )); + return CR_OK; +} + +command_result misery(color_ostream &out, vector& parameters) { + if ( !df::global::world || !df::global::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; + return CR_OK; + } else if ( parameters[0] == "enable" ) { + factor = 2; + if ( parameters.size() == 2 ) { + factor = atoi(parameters[1].c_str()); + if ( factor < 1 ) { + out.printerr("Second argument must be a positive integer.\n"); + return CR_WRONG_USAGE; + } + } + } else if ( parameters[0] == "clear" ) { + for ( size_t a = 0; a < fakeThoughts.size(); a++ ) { + int dorfIndex = fakeThoughts[a].first; + int thoughtIndex = fakeThoughts[a].second; + df::global::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; + } + + return CR_OK; +} +