From 0aa2dc149f902341b9f675b4077c1966e40e90dd Mon Sep 17 00:00:00 2001 From: expwnent Date: Mon, 30 Jun 2014 02:21:58 -0400 Subject: [PATCH] Converted outsideOnly plugin to Lua script. --- plugins/CMakeLists.txt | 2 +- plugins/outsideOnly.cpp | 202 --------------------------------------- scripts/outside-only.lua | 113 ++++++++++++++++++++++ 3 files changed, 114 insertions(+), 203 deletions(-) delete mode 100644 plugins/outsideOnly.cpp create mode 100644 scripts/outside-only.lua diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 4a67ed6c3..8553f5755 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -152,7 +152,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(infiniteSky infiniteSky.cpp) DFHACK_PLUGIN(digFlood digFlood.cpp) DFHACK_PLUGIN(createitem createitem.cpp) - DFHACK_PLUGIN(outsideOnly outsideOnly.cpp) + #DFHACK_PLUGIN(outsideOnly outsideOnly.cpp) DFHACK_PLUGIN(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) DFHACK_PLUGIN(buildingplan buildingplan.cpp) DFHACK_PLUGIN(resume resume.cpp) diff --git a/plugins/outsideOnly.cpp b/plugins/outsideOnly.cpp deleted file mode 100644 index 95aec686f..000000000 --- a/plugins/outsideOnly.cpp +++ /dev/null @@ -1,202 +0,0 @@ - -#include "Console.h" -#include "Core.h" -#include "DataDefs.h" -#include "Export.h" -#include "PluginManager.h" - -#include "modules/Buildings.h" -#include "modules/EventManager.h" -#include "modules/Maps.h" -#include "modules/Once.h" - -#include "df/coord.h" -#include "df/building.h" -#include "df/building_def.h" -#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; -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) -{ - 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 checkEvery [n]\n" - " checks for buildings that were previously in appropriate inside/outsideness but are not anymore every [n] ticks. If [n] is negative, disables checking.\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; -} - -DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) -{ - switch (event) { - case SC_WORLD_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; - EventManager::unregisterAll(plugin_self); - if ( enabled ) { - EventManager::EventHandler handler(buildingCreated,1); - EventManager::registerListener(EventManager::EventType::BUILDING, handler, plugin_self); - checkBuildings(out, 0); - } - return CR_OK; -} - -void destroy(df::building* building) { - if ( Buildings::deconstruct(building) ) - return; - building->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) { - 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; -} - -void buildingCreated(color_ostream& out, void* data) { - int32_t id = (int32_t)data; - df::building* building = df::building::find(id); - if ( building == NULL ) - return; - - if ( building->getCustomType() < 0 ) - return; - //check if it was created inside or outside - 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 ) - 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); - } - } -} - diff --git a/scripts/outside-only.lua b/scripts/outside-only.lua new file mode 100644 index 000000000..ec8d1554a --- /dev/null +++ b/scripts/outside-only.lua @@ -0,0 +1,113 @@ +--outsideOnly.lua +--author expwnent +--enables outside only and inside only buildings + +local eventful = require 'plugins.eventful' +local utils = require 'utils' + +buildingType = buildingType or utils.invert({'EITHER','OUTSIDE_ONLY','INSIDE_ONLY'}) +registeredBuildings = registeredBuildings or {} +checkEvery = checkEvery or 100 +timeoutId = timeoutId or nil + +eventful.enableEvent(eventful.eventType.UNLOAD,1) +eventful.onUnload.outsideOnly = function() + registeredBuildings = {} + checkEvery = 100 +end + +local function destroy(building) + if #building.jobs > 0 and building.jobs[0] and building.jobs[0].job_type == df.job_type.DestroyBuilding then + return + end + local b = dfhack.buildings.deconstruct(building) + if b then + --TODO: print an error message to the user so they know + return + end +-- building.flags.almost_deleted = 1 +end + +local function checkBuildings() + local toDestroy = {} + local function forEach(building) + if building:getCustomType() < 0 then + --TODO: support builtin building types if someone wants + return + end + local pos = df.coord:new() + pos.x = building.centerx + pos.y = building.centery + pos.z = building.z + local outside = dfhack.maps.getTileBlock(pos).designation[pos.x%16][pos.y%16].outside + local def = df.global.world.raws.buildings.all[building:getCustomType()] + local btype = registeredBuildings[def.code] + if btype then +-- print('outside: ' .. outside==true .. ', type: ' .. btype) + end + + if not btype or btype == buildingType.EITHER then + registeredBuildings[def.code] = nil + return + elseif btype == buildingType.OUTSIDE_ONLY then + if outside then + return + end + else + if not outside then + return + end + end + table.insert(toDestroy,building) + end + for _,building in ipairs(df.global.world.buildings.all) do + forEach(building) + end + for _,building in ipairs(toDestroy) do + destroy(building) + end + if timeoutId then + dfhack.timeout_active(timeoutId,nil) + timeoutId = nil + end + timeoutId = dfhack.timeout(checkEvery, 'ticks', checkBuildings) +end + +eventful.enableEvent(eventful.eventType.BUILDING, 100) +eventful.onBuildingCreatedDestroyed.outsideOnly = function(buildingId) + checkBuildings() +end + +local args = utils.processArgs(...) +if args.help then + --print help message +end + +if args.clear then + registeredBuildings = {} +end + +if args.checkEvery then + if not tonumber(args.checkEvery) then + error('Invalid checkEvery.') + end + checkEvery = tonumber(args.checkEvery) +end + +if not args.building then + return +end + +if not args['type'] then + print 'outside-only: please specify type' + return +end + +if not buildingType[args['type']] then + error('Invalid building type: ' .. args['type']) +end + +registeredBuildings[args.building] = buildingType[args['type']] + +checkBuildings() +