parent
edfaf5f9f2
commit
cb338e4257
@ -1,23 +0,0 @@
|
|||||||
resume
|
|
||||||
======
|
|
||||||
|
|
||||||
.. dfhack-tool::
|
|
||||||
:summary: Color planned buildings based on their suspend status.
|
|
||||||
:tags: fort productivity interface jobs
|
|
||||||
:no-command:
|
|
||||||
|
|
||||||
.. dfhack-command:: resume
|
|
||||||
:summary: Resume all suspended building jobs.
|
|
||||||
|
|
||||||
When enabled, this plugin will display a colored 'X' over suspended buildings.
|
|
||||||
When run as a command, it can resume all suspended building jobs, allowing you
|
|
||||||
to quickly recover if a bunch of jobs were suspended due to the workers getting
|
|
||||||
scared off by wildlife or items temporarily blocking building sites.
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-----
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
enable resume
|
|
||||||
resume all
|
|
@ -1,325 +0,0 @@
|
|||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "Core.h"
|
|
||||||
#include <Console.h>
|
|
||||||
#include <Export.h>
|
|
||||||
#include <PluginManager.h>
|
|
||||||
#include <VTableInterpose.h>
|
|
||||||
|
|
||||||
|
|
||||||
// DF data structure definition headers
|
|
||||||
#include "DataDefs.h"
|
|
||||||
#include "LuaTools.h"
|
|
||||||
#include "MiscUtils.h"
|
|
||||||
#include "Types.h"
|
|
||||||
#include "df/viewscreen_dwarfmodest.h"
|
|
||||||
#include "df/world.h"
|
|
||||||
#include "df/building_constructionst.h"
|
|
||||||
#include "df/building.h"
|
|
||||||
#include "df/job.h"
|
|
||||||
#include "df/job_item.h"
|
|
||||||
|
|
||||||
#include "modules/Gui.h"
|
|
||||||
#include "modules/Screen.h"
|
|
||||||
#include "modules/Buildings.h"
|
|
||||||
#include "modules/Maps.h"
|
|
||||||
|
|
||||||
#include "modules/World.h"
|
|
||||||
|
|
||||||
#include "uicommon.h"
|
|
||||||
|
|
||||||
using std::map;
|
|
||||||
using std::string;
|
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
using namespace DFHack;
|
|
||||||
using namespace df::enums;
|
|
||||||
|
|
||||||
DFHACK_PLUGIN("resume");
|
|
||||||
#define PLUGIN_VERSION 0.2
|
|
||||||
|
|
||||||
REQUIRE_GLOBAL(gps);
|
|
||||||
REQUIRE_GLOBAL(process_jobs);
|
|
||||||
REQUIRE_GLOBAL(ui);
|
|
||||||
REQUIRE_GLOBAL(world);
|
|
||||||
|
|
||||||
#ifndef HAVE_NULLPTR
|
|
||||||
#define nullptr 0L
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
|
|
||||||
{
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
df::job *get_suspended_job(df::building *bld)
|
|
||||||
{
|
|
||||||
if (bld->getBuildStage() != 0)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (bld->jobs.size() == 0)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
auto job = bld->jobs[0];
|
|
||||||
if (job->flags.bits.suspend)
|
|
||||||
return job;
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SuspendedBuilding
|
|
||||||
{
|
|
||||||
df::building *bld;
|
|
||||||
df::coord pos;
|
|
||||||
bool was_resumed;
|
|
||||||
bool is_planned;
|
|
||||||
|
|
||||||
SuspendedBuilding(df::building *bld_) : bld(bld_), was_resumed(false), is_planned(false)
|
|
||||||
{
|
|
||||||
pos = df::coord(bld->centerx, bld->centery, bld->z);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValid()
|
|
||||||
{
|
|
||||||
return bld && Buildings::findAtTile(pos) == bld && get_suspended_job(bld);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool is_planned_building(df::building *bld)
|
|
||||||
{
|
|
||||||
auto L = Lua::Core::State;
|
|
||||||
color_ostream_proxy out(Core::getInstance().getConsole());
|
|
||||||
Lua::StackUnwinder top(L);
|
|
||||||
|
|
||||||
if (!lua_checkstack(L, 2) ||
|
|
||||||
!Lua::PushModulePublic(
|
|
||||||
out, L, "plugins.buildingplan", "isPlannedBuilding"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Lua::Push(L, bld);
|
|
||||||
|
|
||||||
if (!Lua::SafeCall(out, L, 1, 1))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return lua_toboolean(L, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
DFHACK_PLUGIN_IS_ENABLED(enabled);
|
|
||||||
static bool buildings_scanned = false;
|
|
||||||
static vector<SuspendedBuilding> suspended_buildings, resumed_buildings;
|
|
||||||
|
|
||||||
void scan_for_suspended_buildings()
|
|
||||||
{
|
|
||||||
if (buildings_scanned)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (auto b = world->buildings.all.begin(); b != world->buildings.all.end(); b++)
|
|
||||||
{
|
|
||||||
auto bld = *b;
|
|
||||||
auto job = get_suspended_job(bld);
|
|
||||||
if (job)
|
|
||||||
{
|
|
||||||
SuspendedBuilding sb(bld);
|
|
||||||
sb.is_planned = is_planned_building(bld);
|
|
||||||
|
|
||||||
auto it = resumed_buildings.begin();
|
|
||||||
|
|
||||||
for (; it != resumed_buildings.end(); ++it)
|
|
||||||
if (it->bld == bld) break;
|
|
||||||
|
|
||||||
sb.was_resumed = it != resumed_buildings.end();
|
|
||||||
|
|
||||||
suspended_buildings.push_back(sb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildings_scanned = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void show_suspended_buildings()
|
|
||||||
{
|
|
||||||
int32_t vx, vy, vz;
|
|
||||||
if (!Gui::getViewCoords(vx, vy, vz))
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto dims = Gui::getDwarfmodeViewDims();
|
|
||||||
int left_margin = vx + dims.map_x2;
|
|
||||||
int bottom_margin = vy + dims.map_y2 - 1;
|
|
||||||
|
|
||||||
for (auto sb = suspended_buildings.begin(); sb != suspended_buildings.end();)
|
|
||||||
{
|
|
||||||
if (!sb->isValid())
|
|
||||||
{
|
|
||||||
sb = suspended_buildings.erase(sb);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sb->bld->z == vz && sb->bld->centerx >= vx && sb->bld->centerx <= left_margin &&
|
|
||||||
sb->bld->centery >= vy && sb->bld->centery <= bottom_margin)
|
|
||||||
{
|
|
||||||
int x = sb->bld->centerx - vx + 1;
|
|
||||||
int y = sb->bld->centery - vy + 1;
|
|
||||||
auto color = COLOR_YELLOW;
|
|
||||||
if (sb->is_planned)
|
|
||||||
color = COLOR_GREEN;
|
|
||||||
else if (sb->was_resumed)
|
|
||||||
color = COLOR_RED;
|
|
||||||
|
|
||||||
OutputString(color, x, y, "X", false, 0, 0, true /* map */);
|
|
||||||
}
|
|
||||||
|
|
||||||
sb++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_scanned()
|
|
||||||
{
|
|
||||||
buildings_scanned = false;
|
|
||||||
suspended_buildings.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void resume_suspended_buildings(color_ostream &out)
|
|
||||||
{
|
|
||||||
out << "Resuming all buildings." << endl;
|
|
||||||
|
|
||||||
for (auto isb = resumed_buildings.begin(); isb != resumed_buildings.end();)
|
|
||||||
{
|
|
||||||
if (isb->isValid())
|
|
||||||
{
|
|
||||||
isb++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
isb = resumed_buildings.erase(isb);
|
|
||||||
}
|
|
||||||
|
|
||||||
scan_for_suspended_buildings();
|
|
||||||
for (auto sb = suspended_buildings.begin(); sb != suspended_buildings.end(); sb++)
|
|
||||||
{
|
|
||||||
if (sb->is_planned)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
resumed_buildings.push_back(*sb);
|
|
||||||
sb->bld->jobs[0]->flags.bits.suspend = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
clear_scanned();
|
|
||||||
|
|
||||||
out << resumed_buildings.size() << " buildings resumed" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//START Viewscreen Hook
|
|
||||||
struct resume_hook : public df::viewscreen_dwarfmodest
|
|
||||||
{
|
|
||||||
//START UI Methods
|
|
||||||
typedef df::viewscreen_dwarfmodest interpose_base;
|
|
||||||
|
|
||||||
DEFINE_VMETHOD_INTERPOSE(void, render, ())
|
|
||||||
{
|
|
||||||
INTERPOSE_NEXT(render)();
|
|
||||||
|
|
||||||
if (enabled && DFHack::World::ReadPauseState() && ui->main.mode == ui_sidebar_mode::Default)
|
|
||||||
{
|
|
||||||
if (*process_jobs)
|
|
||||||
{
|
|
||||||
// something just created some buildings. rescan.
|
|
||||||
clear_scanned();
|
|
||||||
}
|
|
||||||
scan_for_suspended_buildings();
|
|
||||||
show_suspended_buildings();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
clear_scanned();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
IMPLEMENT_VMETHOD_INTERPOSE(resume_hook, render);
|
|
||||||
|
|
||||||
DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable)
|
|
||||||
{
|
|
||||||
if (!gps)
|
|
||||||
return CR_FAILURE;
|
|
||||||
|
|
||||||
if (enabled != enable)
|
|
||||||
{
|
|
||||||
clear_scanned();
|
|
||||||
|
|
||||||
if (!INTERPOSE_HOOK(resume_hook, render).apply(enable))
|
|
||||||
return CR_FAILURE;
|
|
||||||
|
|
||||||
enabled = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static command_result resume_cmd(color_ostream &out, vector <string> & parameters)
|
|
||||||
{
|
|
||||||
bool show_help = false;
|
|
||||||
if (parameters.empty())
|
|
||||||
{
|
|
||||||
show_help = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto cmd = parameters[0][0];
|
|
||||||
if (cmd == 'v')
|
|
||||||
{
|
|
||||||
out << "Resume" << endl << "Version: " << PLUGIN_VERSION << endl;
|
|
||||||
}
|
|
||||||
else if (cmd == 's')
|
|
||||||
{
|
|
||||||
plugin_enable(out, true);
|
|
||||||
out << "Overlay enabled" << endl;
|
|
||||||
}
|
|
||||||
else if (cmd == 'h')
|
|
||||||
{
|
|
||||||
plugin_enable(out, false);
|
|
||||||
out << "Overlay disabled" << endl;
|
|
||||||
}
|
|
||||||
else if (cmd == 'a')
|
|
||||||
{
|
|
||||||
resume_suspended_buildings(out);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
show_help = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (show_help)
|
|
||||||
return CR_WRONG_USAGE;
|
|
||||||
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
|
|
||||||
{
|
|
||||||
commands.push_back(
|
|
||||||
PluginCommand(
|
|
||||||
"resume",
|
|
||||||
"Mark suspended constructions on the map and easily resume them.",
|
|
||||||
resume_cmd));
|
|
||||||
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
|
|
||||||
{
|
|
||||||
switch (event) {
|
|
||||||
case SC_MAP_LOADED:
|
|
||||||
suspended_buildings.clear();
|
|
||||||
resumed_buildings.clear();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
Loading…
Reference in New Issue