Merge branch 'master' of https://github.com/angavrilov/dfhack into experimental-dontmerge

develop
Warmist 2012-08-31 23:53:31 +03:00
commit 262233aa33
7 changed files with 525 additions and 13 deletions

@ -324,7 +324,7 @@ df::building *Buildings::allocInstance(df::coord pos, df::building_type type, in
{
auto obj = (df::building_trapst*)bld;
if (obj->trap_type == trap_type::PressurePlate)
obj->unk_cc = 500;
obj->ready_timeout = 500;
break;
}
default:

@ -1 +1 @@
Subproject commit 328a8dbdc7d9e1e838798abf79861cc18a387e3f
Subproject commit 9b3ded15848e830784ef2dc4dea6093175669bc9

@ -18,6 +18,7 @@ DFHACK_PLUGIN(stripcaged stripcaged.cpp)
DFHACK_PLUGIN(rprobe rprobe.cpp)
DFHACK_PLUGIN(nestboxes nestboxes.cpp)
DFHACK_PLUGIN(vshook vshook.cpp)
DFHACK_PLUGIN(steam-engine steam-engine.cpp)
IF(UNIX)
DFHACK_PLUGIN(ref-index ref-index.cpp)
ENDIF()

@ -0,0 +1,86 @@
building_zsteam_engine
[OBJECT:BUILDING]
[BUILDING_WORKSHOP:STEAM_ENGINE]
[NAME:Steam Engine]
[NAME_COLOR:4:0:1]
[DIM:3:3]
[WORK_LOCATION:2:3]
[BUILD_LABOR:MECHANIC]
[BUILD_KEY:CUSTOM_ALT_S]
[BLOCK:1:1:1:1]
[BLOCK:2:1:1:1]
[BLOCK:3:1:0:1]
[TILE:0:1:240:' ':254]
[TILE:0:2:' ':' ':128]
[TILE:0:3:246:' ':' ']
[COLOR:0:1:MAT:0:0:0:7:0:0]
[COLOR:0:2:0:0:0:0:0:0:7:0:0]
[COLOR:0:3:6:0:0:0:0:0:0:0:0]
[TILE:1:1:246:128:' ']
[TILE:1:2:' ':' ':254]
[TILE:1:3:254:240:240]
[COLOR:1:1:6:0:0:7:0:0:0:0:0]
[COLOR:1:2:0:0:0:0:0:0:7:0:0]
[COLOR:1:3:7:0:0:MAT:MAT]
[TILE:2:1:21:' ':128]
[TILE:2:2:128:' ':246]
[TILE:2:3:177:19:177]
[COLOR:2:1:6:0:0:0:0:0:7:0:0]
[COLOR:2:2:7:0:0:0:0:0:6:0:0]
[COLOR:2:3:7:0:0:MAT:7:0:0]
[TILE:3:1:15:246:15]
[TILE:3:2:'\':19:'/']
[TILE:3:3:7:' ':7]
[COLOR:3:1:6:0:0:6:0:0:6:0:0]
[COLOR:3:2:6:7:0:0:0:1:6:7:0]
[COLOR:3:3:1:7:1:0:0:0:4:7:1]
[BUILD_ITEM:1:BARREL:NONE:INORGANIC:NONE][EMPTY][CAN_USE_ARTIFACT]
[BUILD_ITEM:1:PIPE_SECTION:NONE:INORGANIC:NONE][CAN_USE_ARTIFACT]
[BUILD_ITEM:1:WEAPON:WEAPON_MACE:INORGANIC:NONE][CAN_USE_ARTIFACT]
[BUILD_ITEM:1:CHAIN:NONE:INORGANIC:NONE][CAN_USE_ARTIFACT]
[BUILD_ITEM:1:TRAPPARTS:NONE:NONE:NONE][CAN_USE_ARTIFACT]
[BUILD_ITEM:2:BLOCKS:NONE:NONE:NONE][BUILDMAT][FIRE_BUILD_SAFE]
[BUILDING_WORKSHOP:MAGMA_STEAM_ENGINE]
[NAME:Magma Steam Engine]
[NAME_COLOR:4:0:1]
[DIM:3:3]
[WORK_LOCATION:2:3]
[BUILD_LABOR:MECHANIC]
[BUILD_KEY:CUSTOM_ALT_E]
[NEEDS_MAGMA]
[BLOCK:1:1:1:1]
[BLOCK:2:1:1:1]
[BLOCK:3:1:0:1]
[TILE:0:1:240:' ':254]
[TILE:0:2:' ':' ':128]
[TILE:0:3:246:' ':' ']
[COLOR:0:1:MAT:0:0:0:7:0:0]
[COLOR:0:2:0:0:0:0:0:0:7:0:0]
[COLOR:0:3:6:0:0:0:0:0:0:0:0]
[TILE:1:1:246:128:' ']
[TILE:1:2:' ':' ':254]
[TILE:1:3:254:240:240]
[COLOR:1:1:6:0:0:7:0:0:0:0:0]
[COLOR:1:2:0:0:0:0:0:0:7:0:0]
[COLOR:1:3:7:0:0:MAT:MAT]
[TILE:2:1:21:' ':128]
[TILE:2:2:128:' ':246]
[TILE:2:3:177:19:177]
[COLOR:2:1:6:0:0:0:0:0:7:0:0]
[COLOR:2:2:7:0:0:0:0:0:6:0:0]
[COLOR:2:3:7:0:0:MAT:7:0:0]
[TILE:3:1:15:246:15]
[TILE:3:2:'\':19:'/']
[TILE:3:3:7:' ':7]
[COLOR:3:1:6:0:0:6:0:0:6:0:0]
[COLOR:3:2:6:7:0:0:0:1:6:7:0]
[COLOR:3:3:1:7:1:0:0:0:4:7:1]
[BUILD_ITEM:1:BARREL:NONE:INORGANIC:NONE][EMPTY][CAN_USE_ARTIFACT]
[BUILD_ITEM:1:PIPE_SECTION:NONE:INORGANIC:NONE][CAN_USE_ARTIFACT]
[BUILD_ITEM:1:WEAPON:WEAPON_MACE:INORGANIC:NONE][CAN_USE_ARTIFACT]
[BUILD_ITEM:1:CHAIN:NONE:INORGANIC:NONE][CAN_USE_ARTIFACT]
[BUILD_ITEM:1:TRAPPARTS:NONE:NONE:NONE][CAN_USE_ARTIFACT]
[BUILD_ITEM:2:BLOCKS:NONE:NONE:NONE][BUILDMAT][MAGMA_BUILD_SAFE]

@ -0,0 +1,12 @@
reaction_other
[OBJECT:REACTION]
[REACTION:STOKE_BOILER]
[NAME:stoke the boiler]
[BUILDING:STEAM_ENGINE:CUSTOM_S]
[BUILDING:MAGMA_STEAM_ENGINE:CUSTOM_S]
[FUEL]
[PRODUCT:100:1:LIQUID_MISC:NONE:WATER][PRODUCT_DIMENSION:333]
[SKILL:SMELT]

@ -0,0 +1,349 @@
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Gui.h>
#include <modules/Screen.h>
#include <vector>
#include <cstdio>
#include <stack>
#include <string>
#include <cmath>
#include <string.h>
#include <VTableInterpose.h>
#include "df/graphic.h"
#include "df/building_workshopst.h"
#include "df/building_def_workshopst.h"
#include "df/item_liquid_miscst.h"
#include "df/power_info.h"
#include "df/workshop_type.h"
#include "df/builtin_mats.h"
#include "df/world.h"
#include "df/buildings_other_id.h"
#include "df/machine.h"
#include "MiscUtils.h"
using std::vector;
using std::string;
using std::stack;
using namespace DFHack;
using namespace df::enums;
using df::global::gps;
using df::global::world;
using df::global::ui_build_selector;
DFHACK_PLUGIN("steam-engine");
struct steam_engine_workshop {
int id;
df::building_def_workshopst *def;
std::vector<df::coord2d> gear_tiles;
df::coord2d hearth_tile;
df::coord2d water_tile;
df::coord2d magma_tile;
};
std::vector<steam_engine_workshop> engines;
struct workshop_hook : df::building_workshopst {
typedef df::building_workshopst interpose_base;
steam_engine_workshop *get_steam_engine()
{
if (type == workshop_type::Custom)
for (size_t i = 0; i < engines.size(); i++)
if (engines[i].id == custom_type)
return &engines[i];
return NULL;
}
int get_steam_amount()
{
int cnt = 0;
for (size_t i = 0; i < contained_items.size(); i++)
{
if (contained_items[i]->use_mode == 0 &&
contained_items[i]->item->flags.bits.in_building)
cnt++;
}
return cnt;
}
int get_power_output(steam_engine_workshop *engine)
{
int maxv = engine->def->needs_magma ? 5 : 3;
return std::min(get_steam_amount(), maxv)*100;
}
df::item_liquid_miscst *collect_steam()
{
df::item_liquid_miscst *first = NULL;
for (int i = contained_items.size()-1; i >= 0; i--)
{
auto item = contained_items[i];
if (item->use_mode != 0)
continue;
auto liquid = strict_virtual_cast<df::item_liquid_miscst>(item->item);
if (!liquid)
continue;
if (!liquid->flags.bits.in_building)
{
if (liquid->mat_type != builtin_mats::WATER ||
liquid->dimension != 333 ||
liquid->wear != 0)
continue;
liquid->flags.bits.in_building = true;
}
first = liquid;
}
return first;
}
DEFINE_VMETHOD_INTERPOSE(bool, needsDesign, ())
{
if (get_steam_engine())
return true;
return INTERPOSE_NEXT(needsDesign)();
}
DEFINE_VMETHOD_INTERPOSE(void, getPowerInfo, (df::power_info *info))
{
if (auto engine = get_steam_engine())
{
info->produced = get_power_output(engine);
info->consumed = 10;
return;
}
INTERPOSE_NEXT(getPowerInfo)(info);
}
DEFINE_VMETHOD_INTERPOSE(df::machine_info*, getMachineInfo, ())
{
if (get_steam_engine())
return &machine;
return INTERPOSE_NEXT(getMachineInfo)();
}
DEFINE_VMETHOD_INTERPOSE(bool, isPowerSource, ())
{
if (get_steam_engine())
return true;
return INTERPOSE_NEXT(isPowerSource)();
}
DEFINE_VMETHOD_INTERPOSE(void, categorize, (bool free))
{
if (get_steam_engine())
{
auto &vec = world->buildings.other[buildings_other_id::ANY_MACHINE];
insert_into_vector(vec, &df::building::id, (df::building*)this);
}
INTERPOSE_NEXT(categorize)(free);
}
DEFINE_VMETHOD_INTERPOSE(void, uncategorize, ())
{
if (get_steam_engine())
{
auto &vec = world->buildings.other[buildings_other_id::ANY_MACHINE];
erase_from_vector(vec, &df::building::id, id);
}
INTERPOSE_NEXT(uncategorize)();
}
DEFINE_VMETHOD_INTERPOSE(bool, canConnectToMachine, (df::machine_tile_set *info))
{
if (auto engine = get_steam_engine())
{
int real_cx = centerx, real_cy = centery;
bool ok = false;
for (size_t i = 0; i < engine->gear_tiles.size(); i++)
{
centerx = x1 + engine->gear_tiles[i].x;
centery = y1 + engine->gear_tiles[i].y;
if (!INTERPOSE_NEXT(canConnectToMachine)(info))
continue;
ok = true;
break;
}
centerx = real_cx; centery = real_cy;
return ok;
}
else
return INTERPOSE_NEXT(canConnectToMachine)(info);
}
DEFINE_VMETHOD_INTERPOSE(void, updateAction, ())
{
if (auto engine = get_steam_engine())
{
int output = get_power_output(engine);
if (auto first = collect_steam())
{
if (first->incWearTimer(output))
{
while (first->wear_timer >= 806400)
{
first->wear_timer -= 806400;
first->wear++;
}
if (first->wear > 3)
{
first->flags.bits.in_building = 0;
first->temperature = first->getBoilingPoint()+50;
}
}
}
int new_out = get_power_output(engine);
if (new_out != output)
{
auto mptr = df::machine::find(machine.machine_id);
if (mptr)
mptr->cur_power += (new_out - output);
}
}
INTERPOSE_NEXT(updateAction)();
}
};
IMPLEMENT_VMETHOD_INTERPOSE(workshop_hook, needsDesign);
IMPLEMENT_VMETHOD_INTERPOSE(workshop_hook, getPowerInfo);
IMPLEMENT_VMETHOD_INTERPOSE(workshop_hook, getMachineInfo);
IMPLEMENT_VMETHOD_INTERPOSE(workshop_hook, isPowerSource);
IMPLEMENT_VMETHOD_INTERPOSE(workshop_hook, categorize);
IMPLEMENT_VMETHOD_INTERPOSE(workshop_hook, uncategorize);
IMPLEMENT_VMETHOD_INTERPOSE(workshop_hook, canConnectToMachine);
IMPLEMENT_VMETHOD_INTERPOSE(workshop_hook, updateAction);
static void find_engines()
{
engines.clear();
auto &wslist = world->raws.buildings.workshops;
for (size_t i = 0; i < wslist.size(); i++)
{
if (strstr(wslist[i]->code.c_str(), "STEAM_ENGINE") == NULL)
continue;
steam_engine_workshop ws;
ws.def = wslist[i];
ws.id = ws.def->id;
int bs = ws.def->build_stages;
for (int x = 0; x < ws.def->dim_x; x++)
{
for (int y = 0; y < ws.def->dim_y; y++)
{
if (ws.def->tile[bs][x][y] == 15)
ws.gear_tiles.push_back(df::coord2d(x,y));
if (ws.def->tile_color[2][bs][x][y])
{
switch (ws.def->tile_color[0][bs][x][y])
{
case 0:
ws.hearth_tile = df::coord2d(x,y);
break;
case 1:
ws.water_tile = df::coord2d(x,y);
break;
case 4:
ws.magma_tile = df::coord2d(x,y);
break;
default:
break;
}
}
}
}
engines.push_back(ws);
}
}
static void enable_hooks()
{
INTERPOSE_HOOK(workshop_hook, needsDesign).apply();
INTERPOSE_HOOK(workshop_hook, getPowerInfo).apply();
INTERPOSE_HOOK(workshop_hook, getMachineInfo).apply();
INTERPOSE_HOOK(workshop_hook, isPowerSource).apply();
INTERPOSE_HOOK(workshop_hook, categorize).apply();
INTERPOSE_HOOK(workshop_hook, uncategorize).apply();
INTERPOSE_HOOK(workshop_hook, canConnectToMachine).apply();
INTERPOSE_HOOK(workshop_hook, updateAction).apply();
}
static void disable_hooks()
{
INTERPOSE_HOOK(workshop_hook, needsDesign).remove();
INTERPOSE_HOOK(workshop_hook, getPowerInfo).remove();
INTERPOSE_HOOK(workshop_hook, getMachineInfo).remove();
INTERPOSE_HOOK(workshop_hook, isPowerSource).remove();
INTERPOSE_HOOK(workshop_hook, categorize).remove();
INTERPOSE_HOOK(workshop_hook, uncategorize).remove();
INTERPOSE_HOOK(workshop_hook, canConnectToMachine).remove();
INTERPOSE_HOOK(workshop_hook, updateAction).remove();
}
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
{
switch (event) {
case SC_MAP_LOADED:
find_engines();
if (!engines.empty())
{
out.print("Detected steam engine workshops - enabling plugin.\n");
enable_hooks();
}
break;
case SC_MAP_UNLOADED:
disable_hooks();
engines.clear();
break;
default:
break;
}
return CR_OK;
}
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
if (Core::getInstance().isMapLoaded())
plugin_onstatechange(out, SC_MAP_LOADED);
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
disable_hooks();
return CR_OK;
}

@ -7,6 +7,7 @@
#include "PluginManager.h"
#include "modules/Gui.h"
#include "modules/Screen.h"
#include "modules/Units.h"
#include "modules/Items.h"
@ -29,6 +30,8 @@
#include "df/unit_inventory_item.h"
#include "df/viewscreen_dwarfmodest.h"
#include "df/squad_order_trainst.h"
#include "df/ui_build_selector.h"
#include "df/building_trapst.h"
#include <stdlib.h>
@ -40,6 +43,9 @@ using namespace df::enums;
using df::global::ui;
using df::global::world;
using df::global::ui_build_selector;
using df::global::ui_menu_width;
using df::global::ui_area_map_width;
using namespace DFHack::Gui;
@ -77,6 +83,8 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector <Plugi
" Causes 'Train' orders to no longer be considered 'patrol duty' so\n"
" soldiers will stop getting unhappy thoughts. Does NOT fix the problem\n"
" when soldiers go off-duty (i.e. civilian).\n"
" tweak readable-build-plate [disable]\n"
" Fixes rendering of creature weight limits in pressure plate build menu.\n"
));
return CR_OK;
}
@ -189,6 +197,8 @@ struct stable_cursor_hook : df::viewscreen_dwarfmodest
}
};
IMPLEMENT_VMETHOD_INTERPOSE(stable_cursor_hook, feed);
struct patrol_duty_hook : df::squad_order_trainst
{
typedef df::squad_order_trainst interpose_base;
@ -199,9 +209,61 @@ struct patrol_duty_hook : df::squad_order_trainst
}
};
IMPLEMENT_VMETHOD_INTERPOSE(stable_cursor_hook, feed);
IMPLEMENT_VMETHOD_INTERPOSE(patrol_duty_hook, isPatrol);
static const int AREA_MAP_WIDTH = 23;
static const int MENU_WIDTH = 30;
struct readable_build_plate_hook : df::viewscreen_dwarfmodest
{
typedef df::viewscreen_dwarfmodest interpose_base;
DEFINE_VMETHOD_INTERPOSE(void, render, ())
{
INTERPOSE_NEXT(render)();
if (ui->main.mode == ui_sidebar_mode::Build &&
ui_build_selector->stage == 1 &&
ui_build_selector->building_type == building_type::Trap &&
ui_build_selector->building_subtype == trap_type::PressurePlate &&
ui_build_selector->plate_info.flags.bits.units)
{
auto wsize = Screen::getWindowSize();
int x = wsize.x - MENU_WIDTH - 1;
if (*ui_menu_width == 1 || *ui_area_map_width == 2)
x -= AREA_MAP_WIDTH + 1;
Screen::Pen pen(' ',COLOR_WHITE);
int minv = ui_build_selector->plate_info.unit_min;
if ((minv % 1000) == 0)
Screen::paintString(pen, x+11, 14, stl_sprintf("%3dK ", minv/1000));
int maxv = ui_build_selector->plate_info.unit_max;
if (maxv < 200000 && (maxv % 1000) == 0)
Screen::paintString(pen, x+24, 14, stl_sprintf("%3dK ", maxv/1000));
}
}
};
IMPLEMENT_VMETHOD_INTERPOSE(readable_build_plate_hook, render);
static void enable_hook(color_ostream &out, VMethodInterposeLinkBase &hook, vector <string> &parameters)
{
if (vector_get(parameters, 1) == "disable")
{
hook.remove();
out.print("Disabled tweak %s\n", parameters[0].c_str());
}
else
{
if (hook.apply())
out.print("Enabled tweak %s\n", parameters[0].c_str());
else
out.printerr("Could not activate tweak %s\n", parameters[0].c_str());
}
}
static command_result tweak(color_ostream &out, vector <string> &parameters)
{
CoreSuspender suspend;
@ -302,19 +364,21 @@ static command_result tweak(color_ostream &out, vector <string> &parameters)
}
else if (cmd == "stable-cursor")
{
auto &hook = INTERPOSE_HOOK(stable_cursor_hook, feed);
if (vector_get(parameters, 1) == "disable")
hook.remove();
else
hook.apply();
enable_hook(out, INTERPOSE_HOOK(stable_cursor_hook, feed), parameters);
}
else if (cmd == "patrol-duty")
{
auto &hook = INTERPOSE_HOOK(patrol_duty_hook, isPatrol);
if (vector_get(parameters, 1) == "disable")
hook.remove();
else
hook.apply();
enable_hook(out, INTERPOSE_HOOK(patrol_duty_hook, isPatrol), parameters);
}
else if (cmd == "readable-build-plate")
{
if (!ui_build_selector || !ui_menu_width || !ui_area_map_width)
{
out.printerr("Necessary globals not known.\n");
return CR_FAILURE;
}
enable_hook(out, INTERPOSE_HOOK(readable_build_plate_hook, render), parameters);
}
else
return CR_WRONG_USAGE;