From c0e6e62ceacb059d1c53377f67de19afd32c0c03 Mon Sep 17 00:00:00 2001 From: expwnent Date: Fri, 20 Jun 2014 18:49:11 -0400 Subject: [PATCH 1/5] outsideOnly: registration of buildings is now required, and you can also register buildings as inside-only. --- NEWS | 8 ++- Readme.rst | 2 +- plugins/outsideOnly.cpp | 108 ++++++++++++++++++++++++++++++++++------ 3 files changed, 101 insertions(+), 17 deletions(-) diff --git a/NEWS b/NEWS index 03332493d..0c32baa51 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,12 @@ DFHack future -The future has not yet happened. Stay tuned! + Internals: + New scripts: + New commands: + New tweaks: + New plugins: + Misc improvements: + - outsideOnly: now buildings have to be registered as inside or outside only DFHack v0.34.11-r5 diff --git a/Readme.rst b/Readme.rst index fde2b5c04..40cbeaf8f 100644 --- a/Readme.rst +++ b/Readme.rst @@ -954,7 +954,7 @@ Again, note that plugins AND scripts can be executed this way, and arguments wil outsideOnly ----------- -This plugin makes it so that buildings whose names begin with ``OUTSIDE_ONLY`` cannot be built inside. If the player attempts to do so, the building will automatically be deconstructed. +This plugin makes custom buildings either inside-only or outside-only. If you attempt to build one in an inappropriate location, the building plan will immediately deconstruct. Try `help outsideOnly` for details. syndromeTrigger --------------- diff --git a/plugins/outsideOnly.cpp b/plugins/outsideOnly.cpp index 7707053ca..f7a301cb7 100644 --- a/plugins/outsideOnly.cpp +++ b/plugins/outsideOnly.cpp @@ -8,6 +8,7 @@ #include "modules/Buildings.h" #include "modules/EventManager.h" #include "modules/Maps.h" +#include "modules/Once.h" #include "df/coord.h" #include "df/building.h" @@ -15,25 +16,94 @@ #include "df/map_block.h" #include "df/tile_designation.h" +#include #include +//TODO: check if building becomes inside/outside later using namespace DFHack; using namespace std; +DFHACK_PLUGIN_IS_ENABLED(enabled); DFHACK_PLUGIN("outsideOnly"); +static map registeredBuildings; +const int32_t OUTSIDE_ONLY = 1; +const int32_t EITHER = 0; +const int32_t INSIDE_ONLY = -1; + void buildingCreated(color_ostream& out, void* data); +command_result outsideOnly(color_ostream& out, vector& parameters); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - EventManager::EventHandler handler(buildingCreated,1); - EventManager::registerListener(EventManager::EventType::BUILDING, handler, plugin_self); + commands.push_back(PluginCommand("outsideOnly", "Register buildings as inside/outside only. If the player attempts to construct them in an inapproprate place, the building plan automatically deconstructs.\n", &outsideOnly, false, + "outsideOnly:\n" + " outsideOnly outside [custom building name]\n" + " registers [custom building name] as outside-only\n" + " outsideOnly inside [custom building name]\n" + " registers [custom building name] as inside-only\n" + " outsideOnly either [custom building name]\n" + " unregisters [custom building name]\n" + " outsideOnly clear\n" + " unregisters all custom buildings\n" + " enable outsideOnly\n" + " enables the plugin. Plugin must be enabled to function!\n" + " disable outsideOnly\n" + " disables the plugin\n" + " outsideOnly clear outside BUILDING_1 BUILDING_2 inside BUILDING_3\n" + " equivalent to:\n" + " outsideOnly clear\n" + " outsideOnly outside BUILDING_1\n" + " outsideOnly outside BUILDING_2\n" + " outsideOnly inside BUILDING_3\n" + )); return CR_OK; } -// This is called right before the plugin library is removed from memory. -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) +DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) { + switch (event) { + case SC_GAME_UNLOADED: + registeredBuildings.clear(); + break; + default: + break; + } + return CR_OK; +} + +DFhackCExport command_result plugin_enable(color_ostream& out, bool enable) { + if ( enabled == enable ) + return CR_OK; + enabled = enable; + if ( enabled ) { + EventManager::EventHandler handler(buildingCreated,1); + EventManager::registerListener(EventManager::EventType::BUILDING, handler, plugin_self); + } else { + EventManager::unregisterAll(plugin_self); + } +} + +command_result outsideOnly(color_ostream& out, vector& 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 ( status == 2 ) { + out.print("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"); return CR_OK; } @@ -45,19 +115,27 @@ void buildingCreated(color_ostream& out, void* data) { if ( building->getCustomType() < 0 ) return; - string prefix("OUTSIDE_ONLY"); - df::building_def* def = df::global::world->raws.buildings.all[building->getCustomType()]; - if (def->code.compare(0, prefix.size(), prefix)) { - return; - } - - //now, just check if it was created inside, and if so, scuttle it + //check if it was created inside or outside df::coord pos(building->centerx,building->centery,building->z); - df::tile_designation* des = Maps::getTileDesignation(pos); - if ( des->bits.outside ) - return; + bool outside = des->bits.outside; - Buildings::deconstruct(building); + 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 ) + return; + Buildings::deconstruct(building); + } else if ( type == INSIDE_ONLY ) { + if ( !outside ) + return; + Buildings::deconstruct(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); + } + } } From f94fc5846d9273f2bed813cc94f9ca6eeac4b4a8 Mon Sep 17 00:00:00 2001 From: expwnent Date: Fri, 20 Jun 2014 19:48:56 -0400 Subject: [PATCH 2/5] outsideOnly: allow checking periodically in case a building was made outside and then became inside. --- plugins/outsideOnly.cpp | 71 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/plugins/outsideOnly.cpp b/plugins/outsideOnly.cpp index f7a301cb7..95aec686f 100644 --- a/plugins/outsideOnly.cpp +++ b/plugins/outsideOnly.cpp @@ -30,8 +30,10 @@ static map registeredBuildings; const int32_t OUTSIDE_ONLY = 1; const int32_t EITHER = 0; const int32_t INSIDE_ONLY = -1; +int32_t checkEvery = -1; void buildingCreated(color_ostream& out, void* data); +void checkBuildings(color_ostream& out, void* data); command_result outsideOnly(color_ostream& out, vector& parameters); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) @@ -44,6 +46,8 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector flags.bits.almost_deleted = 1; +} + +void checkBuildings(color_ostream& out, void* data) { + if ( !enabled ) + return; + + std::vector& 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 outsideOnly(color_ostream& out, vector& parameters) { @@ -95,15 +146,25 @@ command_result outsideOnly(color_ostream& out, vector& parameters) { status = INSIDE_ONLY; } else if ( parameters[a] == "either" ) { status = EITHER; - } else { + } 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.print("Error: you need to tell outsideOnly whether the building is inside only, outside-only or either.\n"); + 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; } From 634dd0aa1ecd261a4e99ed5c5a5c3688d24d6ae3 Mon Sep 17 00:00:00 2001 From: expwnent Date: Fri, 20 Jun 2014 19:52:12 -0400 Subject: [PATCH 3/5] Update NEWS. --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 0c32baa51..d0d714acc 100644 --- a/NEWS +++ b/NEWS @@ -6,7 +6,7 @@ DFHack future New tweaks: New plugins: Misc improvements: - - outsideOnly: now buildings have to be registered as inside or outside only + - outsideOnly: now buildings have to be registered as inside or outside only, and it checks periodically to see when buildings change outsideness DFHack v0.34.11-r5 From 247bd212f3cdd4674579188502a7db0a71aec5ec Mon Sep 17 00:00:00 2001 From: expwnent Date: Sat, 21 Jun 2014 13:28:59 -0400 Subject: [PATCH 4/5] Update stonesense. --- plugins/stonesense | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stonesense b/plugins/stonesense index 0d41614ff..c0a2a9a2a 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 0d41614ff3dae9245e786ad667b0e463fe0dea3e +Subproject commit c0a2a9a2a6909cc79f9a564c8039caf8103010a8 From d7e3352b8c7ad729ec3d054e4cd545ed75510613 Mon Sep 17 00:00:00 2001 From: expwnent Date: Sat, 21 Jun 2014 17:45:19 -0400 Subject: [PATCH 5/5] Remove exit line from package-release.bat so that you can see console output after calling it. --- build/package-release.bat | 1 - 1 file changed, 1 deletion(-) diff --git a/build/package-release.bat b/build/package-release.bat index 99e94b0e5..510aaa6df 100644 --- a/build/package-release.bat +++ b/build/package-release.bat @@ -3,4 +3,3 @@ call "%VS100COMNTOOLS%vsvars32.bat" cd VC2010 msbuild /m /p:Platform=Win32 /p:Configuration=Release PACKAGE.vcxproj cd .. -exit %ERRORLEVEL% \ No newline at end of file