Merge branch 'develop' of github.com:DFHack/dfhack into develop

Conflicts:
	library/xml
	plugins/stonesense
develop
JapaMala 2014-07-02 23:18:55 +05:30
commit e04ab11659
18 changed files with 278 additions and 39 deletions

@ -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, and it checks periodically to see when buildings change outsideness
DFHack v0.34.11-r5

@ -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
---------------

@ -3,4 +3,3 @@ call "%VS100COMNTOOLS%vsvars32.bat"
cd VC2010
msbuild /m /p:Platform=Win32 /p:Configuration=Release PACKAGE.vcxproj
cd ..
exit %ERRORLEVEL%

@ -59,10 +59,6 @@ keybinding add Ctrl-Shift-Z@dwarfmode/Default "stocks show"
# open an overview window summarising some stocks (dfstatus)
keybinding add Ctrl-Shift-I@dwarfmode/Default dfstatus
# Workflow
keybinding add Ctrl-W@dwarfmode/QueryBuilding/Some "gui/workflow"
keybinding add Ctrl-I "gui/workflow status"
# q->stockpile; p - copy & paste stockpiles
keybinding add Alt-P copystock

@ -811,13 +811,23 @@ bool Core::loadScriptFile(color_ostream &out, string fname, bool silent)
}
}
static void run_dfhack_init(color_ostream &out, Core *core)
{
if (!core->loadScriptFile(out, "dfhack.init", true))
{
core->runCommand(out, "gui/no-dfhack-init");
core->loadScriptFile(out, "dfhack.init-example", true);
}
}
// Load dfhack.init in a dedicated thread (non-interactive console mode)
void fInitthread(void * iodata)
{
IODATA * iod = ((IODATA*) iodata);
Core * core = iod->core;
color_ostream_proxy out(core->getConsole());
core->loadScriptFile(out, "dfhack.init", true);
run_dfhack_init(out, core);
}
// A thread function... for the interactive console.
@ -837,7 +847,7 @@ void fIOthread(void * iodata)
return;
}
core->loadScriptFile(con, "dfhack.init", true);
run_dfhack_init(con, core);
con.print("DFHack is ready. Have a nice day!\n"
"Type in '?' or 'help' for general help, 'ls' to see all commands.\n");

@ -222,7 +222,7 @@ void Process::getMemRanges( vector<t_memrange> & ranges )
uintptr_t Process::getBase()
{
return 0x1000000;
return 0x1000;
}
int Process::adjustOffset(int offset, bool /*to_file*/)

@ -109,7 +109,7 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem)
{
mem->setOS(OS_APPLE);
// this is wrong... I'm not going to do base image relocation on linux though.
mem->setBase(0x1000000);
mem->setBase(0x1000);
}
else
{

@ -83,7 +83,27 @@ dfhack.exception.__index = dfhack.exception
-- Module loading
local function find_required_module_arg()
-- require -> module code -> mkmodule -> find_...
if debug.getinfo(4,'f').func == require then
return debug.getlocal(4, 1)
end
-- reload -> dofile -> module code -> mkmodule -> find_...
if debug.getinfo(5,'f').func == reload then
return debug.getlocal(5, 1)
end
end
function mkmodule(module,env)
-- Verify that the module name is correct
local _, rq_modname = find_required_module_arg()
if not rq_modname then
error('The mkmodule function must be used at the start of a module')
end
if rq_modname ~= module then
error('Found module '..module..' during require '..rq_modname)
end
-- Reuse the already loaded module table
local pkg = package.loaded[module]
if pkg == nil then
pkg = {}
@ -92,6 +112,7 @@ function mkmodule(module,env)
error("Not a table in package.loaded["..module.."]")
end
end
-- Inject the plugin-exported functions when appropriate
local plugname = string.match(module,'^plugins%.([%w%-]+)$')
if plugname then
dfhack.open_plugin(pkg,plugname)

@ -1 +1 @@
Subproject commit f74eeb5f705afa0d1e766d31090e62d4706126e5
Subproject commit c66ab33071842bcfb7d37c3993f6a024923ca358

@ -0,0 +1,20 @@
see linux patch for info
- .text:00111776 jnz loc_111750
+ .text:00111776 nop
+ .text:00111777 nop
sub_660360
osx stores pointer in edi instead of ebx
- .text:006612C3 mov eax, [eax+edx*4]
+ .text:006612C3 mov edi, [eax+edx*4]
- .text:006612CD mov eax, [eax+74h]
+ .text:006612CD mov eax, [edi+74h]
---8<---
Dwarf_Fortress
00110776: 75 90
00110777: D8 90
006602C4: 04 3C
006602CE: 40 47

@ -169,6 +169,8 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(building-hacks building-hacks.cpp LINK_LIBRARIES lua)
DFHACK_PLUGIN(embark-tools embark-tools.cpp)
DFHACK_PLUGIN(petcapRemover petcapRemover.cpp)
add_subdirectory(rendermax)
endif()
# this is the skeleton plugin. If you want to make your own, make a copy and then change it
@ -176,7 +178,3 @@ OPTION(BUILD_SKELETON "Build the skeleton plugin." OFF)
if(BUILD_SKELETON)
add_subdirectory(skeleton)
endif()
OPTION(BUILD_RENDERMAX "Build the rendermax alt-renderers plugin." OFF)
if(BUILD_RENDERMAX)
add_subdirectory(rendermax)
endif()

@ -191,6 +191,11 @@ void sticky_save (df::viewscreen_choose_start_sitest * screen)
void sticky_apply (df::viewscreen_choose_start_sitest * screen)
{
if (screen->finder.finder_state != -1)
{
// Site finder is active - don't override default local position
return;
}
screen->embark_pos_min.x = sticky_pos[0];
screen->embark_pos_max.x = sticky_pos[1];
screen->embark_pos_min.y = sticky_pos[2];

@ -1 +1 @@
Subproject commit 29fad1ef8e7e2aceb2e68c93a3993933168fe885
Subproject commit aa3b1bd51f269c07b3235392fd7ed21fe9171f3f

@ -26,6 +26,8 @@
#include "df/creature_graphics_role.h"
#include "df/creature_raw.h"
#include "df/caste_raw.h"
#include "df/historical_entity.h"
#include "df/entity_raw.h"
using std::set;
using std::vector;
@ -82,6 +84,14 @@ struct SkillColumn
df::job_skill skill; // displayed rating
char label[3]; // column header
bool special; // specified labor is mutually exclusive with all other special labors
bool isValidLabor (df::historical_entity *entity = NULL) const
{
if (labor == unit_labor::NONE)
return false;
if (entity && entity->entity_raw && !entity->entity_raw->jobs.permitted_labor[labor])
return false;
return true;
}
};
#define NUM_COLUMNS (sizeof(columns) / sizeof(SkillColumn))
@ -851,7 +861,7 @@ void viewscreen_unitlaborsst::feed(set<df::interface_key> *events)
}
UnitInfo *cur = units[input_row];
if (events->count(interface_key::SELECT) && (cur->allowEdit) && (columns[input_column].labor != unit_labor::NONE))
if (events->count(interface_key::SELECT) && (cur->allowEdit) && columns[input_column].isValidLabor(ui->main.fortress_entity))
{
df::unit *unit = cur->unit;
const SkillColumn &col = columns[input_column];
@ -870,15 +880,17 @@ void viewscreen_unitlaborsst::feed(set<df::interface_key> *events)
}
unit->status.labors[col.labor] = newstatus;
}
if (events->count(interface_key::SELECT_ALL) && (cur->allowEdit))
if (events->count(interface_key::SELECT_ALL) && (cur->allowEdit) && columns[input_column].isValidLabor(ui->main.fortress_entity))
{
df::unit *unit = cur->unit;
const SkillColumn &col = columns[input_column];
bool newstatus = (col.labor == unit_labor::NONE) ? true : !unit->status.labors[col.labor];
bool newstatus = !unit->status.labors[col.labor];
for (int i = 0; i < NUM_COLUMNS; i++)
{
if (columns[i].group != col.group)
continue;
if (!columns[i].isValidLabor(ui->main.fortress_entity))
continue;
if (columns[i].special)
{
if (newstatus)
@ -912,7 +924,7 @@ void viewscreen_unitlaborsst::feed(set<df::interface_key> *events)
std::sort(units.begin(), units.end(), sortByName);
break;
case ALTSORT_PROFESSION_OR_SQUAD:
std::sort(units.begin(), units.end(), show_squad ? sortBySquad : sortByProfession);
std::sort(units.begin(), units.end(), show_squad ? sortBySquad : sortByProfession);
break;
case ALTSORT_HAPPINESS:
std::sort(units.begin(), units.end(), sortByHappiness);
@ -1175,7 +1187,7 @@ void viewscreen_unitlaborsst::render()
}
canToggle = (cur->allowEdit) && (columns[sel_column].labor != unit_labor::NONE);
canToggle = (cur->allowEdit) && columns[sel_column].isValidLabor(ui->main.fortress_entity);
}
int x = 2, y = dim.y - 3;
@ -1213,7 +1225,7 @@ void viewscreen_unitlaborsst::render()
OutputString(15, x, y, "Name");
break;
case ALTSORT_PROFESSION_OR_SQUAD:
OutputString(15, x, y, show_squad ? "Squad" : "Profession");
OutputString(15, x, y, show_squad ? "Squad" : "Profession");
break;
case ALTSORT_HAPPINESS:
OutputString(15, x, y, "Happiness");

@ -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,155 @@
#include "df/map_block.h"
#include "df/tile_designation.h"
#include <map>
#include <string>
//TODO: check if building becomes inside/outside later
using namespace DFHack;
using namespace std;
DFHACK_PLUGIN_IS_ENABLED(enabled);
DFHACK_PLUGIN("outsideOnly");
static map<std::string, int32_t> 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<string>& parameters);
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &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 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;
}
// 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_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<df::building*>& 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<string>& 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;
}
@ -45,19 +176,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);
}
}
}

@ -1 +1 @@
Subproject commit a3cbb54efd12873f9815ce8133665808566e8560
Subproject commit 0d19548402932c970c8a0d45404808cbe8fe1bcd

@ -13,6 +13,8 @@
#include "modules/Gui.h"
#include "TileTypes.h"
#include "df/deep_vein_hollow.h"
using namespace DFHack;
using namespace df::enums;
using df::global::world;

@ -0,0 +1,31 @@
-- Shows the warning about missing configuration file.
local gui = require 'gui'
local dlg = require 'gui.dialogs'
local dfhack_init = { text = 'dfhack.init', pen = COLOR_LIGHTCYAN }
local dfhack_init_example = { text = 'dfhack.init-example', pen = COLOR_LIGHTCYAN }
local message = {
'The ', dfhack_init, ' configuration file is missing. To customize', NEWLINE,
'your DFHack installation, rename the ', dfhack_init_example, ' file', NEWLINE,
'to ', dfhack_init, ' and edit it to suit your needs.', NEWLINE, NEWLINE,
'For now, ', dfhack_init_example, ' will be used instead.'
}
dfhack.print('\n')
for k,v in ipairs(message) do
if type(v) == 'table' then
dfhack.color(v.pen)
dfhack.print(v.text)
else
dfhack.color(COLOR_YELLOW)
dfhack.print(v)
end
end
dfhack.color(COLOR_RESET)
dfhack.print('\n\n')
dlg.showMessage('DFHack is not configured', message, COLOR_YELLOW)