Merge remote-tracking branch 'origin/develop' into 0.40.24-dev
commit
4d194da530
File diff suppressed because it is too large
Load Diff
@ -1,9 +0,0 @@
|
||||
TODO:
|
||||
copypaste.cpp
|
||||
high value target - a proof of concept plugin to allow copy-pasting in DF; does both terrain and buildings/constructions
|
||||
creaturemanager.cpp
|
||||
modify skills and labors of creatures, kill creatures, etc; impressive but I suspect most functions implemented elsewhere
|
||||
|
||||
In progress:
|
||||
hotkey-notes.lua
|
||||
prints list of hotkeys with name and jump position
|
@ -1,479 +0,0 @@
|
||||
// Console version of DF copy paste, proof of concept
|
||||
// By belal
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
|
||||
#define DFHACK_WANT_MISCUTILS
|
||||
#define DFHACK_WANT_TILETYPES
|
||||
#include <DFHack.h>
|
||||
#include "modules/WindowIO.h"
|
||||
|
||||
using namespace DFHack;
|
||||
//bool waitTillCursorState(DFHack::Context *DF, bool On);
|
||||
//bool waitTillCursorPositionState(DFHack::Context *DF, int32_t x,int32_t y, int32_t z);
|
||||
|
||||
//change this if you are having problems getting correct results, lower if you would like to go faster
|
||||
//const int WAIT_AMT = 25;
|
||||
|
||||
void sort(uint32_t &a,uint32_t &b)
|
||||
{
|
||||
if(a > b){
|
||||
uint32_t c = b;
|
||||
b = a;
|
||||
a = c;
|
||||
}
|
||||
}
|
||||
void sort(int32_t &a,int32_t &b)
|
||||
{
|
||||
if(a > b){
|
||||
int16_t c = b;
|
||||
b = a;
|
||||
a = c;
|
||||
}
|
||||
}
|
||||
void printVecOfVec(ostream &out, vector<vector<vector<string> > >vec,char sep)
|
||||
{
|
||||
for(size_t k=0;k<vec.size();k++)
|
||||
{
|
||||
for(size_t i =0;i<vec[k].size();i++)
|
||||
{
|
||||
for(size_t j=0;j<vec[k][i].size();j++)
|
||||
{
|
||||
out << vec[k][i][j];
|
||||
if(j==vec[k][i].size()-1)
|
||||
{
|
||||
out << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
out << sep;
|
||||
}
|
||||
}
|
||||
}
|
||||
out << "#<\n";
|
||||
}
|
||||
}
|
||||
int main (int numargs, const char ** args)
|
||||
{
|
||||
map<string, string> buildCommands;
|
||||
buildCommands["building_stockpilest"]="";
|
||||
buildCommands["building_zonest"]="";
|
||||
buildCommands["building_construction_blueprintst"]="";
|
||||
buildCommands["building_wagonst"]="";
|
||||
buildCommands["building_armor_standst"]="a";
|
||||
buildCommands["building_bedst"]="b";
|
||||
buildCommands["building_seatst"]="c";
|
||||
buildCommands["building_burial_receptaclest"]="n";
|
||||
buildCommands["building_doorst"]="d";
|
||||
buildCommands["building_floodgatest"]="x";
|
||||
buildCommands["building_floor_hatchst"]="H";
|
||||
buildCommands["building_wall_gratest"]="W";
|
||||
buildCommands["building_floor_gratest"]="G";
|
||||
buildCommands["building_vertical_barsst"]="B";
|
||||
buildCommands["building_floor_barsst"]="alt-b";
|
||||
buildCommands["building_cabinetst"]="f";
|
||||
buildCommands["building_containerst"]="h";
|
||||
buildCommands["building_shopst"]="";
|
||||
buildCommands["building_workshopst"]="";
|
||||
buildCommands["building_alchemists_laboratoryst"]="wa";
|
||||
buildCommands["building_carpenters_workshopst"]="wc";
|
||||
buildCommands["building_farmers_workshopst"]="ww";
|
||||
buildCommands["building_masons_workshopst"]="wm";
|
||||
buildCommands["building_craftdwarfs_workshopst"]="wr";
|
||||
buildCommands["building_jewelers_workshopst"]="wj";
|
||||
buildCommands["building_metalsmiths_workshopst"]="wf";
|
||||
buildCommands["building_magma_forgest"]="";
|
||||
buildCommands["building_bowyers_workshopst"]="wb";
|
||||
buildCommands["building_mechanics_workshopst"]="wt";
|
||||
buildCommands["building_siege_workshopst"]="ws";
|
||||
buildCommands["building_butchers_shopst"]="wU";
|
||||
buildCommands["building_leather_worksst"]="we";
|
||||
buildCommands["building_tanners_shopst"]="wn";
|
||||
buildCommands["building_clothiers_shopst"]="wk";
|
||||
buildCommands["building_fisheryst"]="wh";
|
||||
buildCommands["building_stillst"]="wl";
|
||||
buildCommands["building_loomst"]="wo";
|
||||
buildCommands["building_quernst"]="wq";
|
||||
buildCommands["building_kennelsst"]="k";
|
||||
buildCommands["building_kitchenst"]="wz";
|
||||
buildCommands["building_asheryst"]="wy";
|
||||
buildCommands["building_dyers_shopst"]="wd";
|
||||
buildCommands["building_millstonest"]="wM";
|
||||
buildCommands["building_farm_plotst"]="p";
|
||||
buildCommands["building_weapon_rackst"]="r";
|
||||
buildCommands["building_statuest"]="s";
|
||||
buildCommands["building_tablest"]="t";
|
||||
buildCommands["building_paved_roadst"]="o";
|
||||
buildCommands["building_bridgest"]="g";
|
||||
buildCommands["building_wellst"]="l";
|
||||
buildCommands["building_siege enginest"]="i";
|
||||
buildCommands["building_catapultst"]="ic";
|
||||
buildCommands["building_ballistast"]="ib";
|
||||
buildCommands["building_furnacest"]="";
|
||||
buildCommands["building_wood_furnacest"]="ew";
|
||||
buildCommands["building_smelterst"]="es";
|
||||
buildCommands["building_glass_furnacest"]="ek";
|
||||
buildCommands["building_kilnst"]="ek";
|
||||
buildCommands["building_magma_smelterst"]="es";
|
||||
buildCommands["building_magma_glass_furnacest"]="ek";
|
||||
buildCommands["building_magma_kilnst"]="ek";
|
||||
buildCommands["building_glass_windowst"]="y";
|
||||
buildCommands["building_gem_windowst"]="Y";
|
||||
buildCommands["building_tradedepotst"]="D";
|
||||
buildCommands["building_mechanismst"]="";
|
||||
buildCommands["building_leverst"]="Tl";
|
||||
buildCommands["building_pressure_platest"]="Tp";
|
||||
buildCommands["building_cage_trapst"]="Tc";
|
||||
buildCommands["building_stonefall_trapst"]="Ts";
|
||||
buildCommands["building_weapon_trapst"]="Tw";
|
||||
buildCommands["building_spikest"]="";
|
||||
buildCommands["building_animal_trapst"]="m";
|
||||
buildCommands["building_screw_pumpst"]="Ms";
|
||||
buildCommands["building_water_wheelst"]="Mw";
|
||||
buildCommands["building_windmillst"]="Mm";
|
||||
buildCommands["building_gear_assemblyst"]="Mg";
|
||||
buildCommands["building_horizontal_axlest"]="Mh";
|
||||
buildCommands["building_vertical_axlest"]="Mv";
|
||||
buildCommands["building_supportst"]="S";
|
||||
buildCommands["building_cagest"]="j";
|
||||
buildCommands["building_archery_targetst"]="A";
|
||||
buildCommands["building_restraintst"]="v";
|
||||
|
||||
DFHack::ContextManager DFMgr("Memory.xml");
|
||||
DFHack::Context *DF = DFMgr.getSingleContext();
|
||||
|
||||
try
|
||||
{
|
||||
DF->Attach();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
#ifndef LINUX_BUILD
|
||||
cin.ignore();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
DFHack::Gui *Gui = DF->getGui();
|
||||
DFHack::VersionInfo* mem = DF->getMemoryInfo();
|
||||
DFHack::Process * p = DF->getProcess();
|
||||
OffsetGroup * OG_Maps = mem->getGroup("Maps");
|
||||
OffsetGroup * OG_MapBlock = OG_Maps->getGroup("block");
|
||||
OffsetGroup * OG_LocalFt = OG_Maps->getGroup("features")->getGroup("local");
|
||||
uint32_t designations = OG_MapBlock->getOffset("designation");
|
||||
uint32_t block_feature1 = OG_MapBlock->getOffset("feature_local");
|
||||
uint32_t block_feature2 = OG_MapBlock->getOffset("feature_global");
|
||||
uint32_t region_x_offset = OG_Maps->getAddress("region_x");
|
||||
uint32_t region_y_offset = OG_Maps->getAddress("region_y");
|
||||
uint32_t region_z_offset = OG_Maps->getAddress("region_z");
|
||||
uint32_t feature1_start_ptr = OG_LocalFt->getAddress("start_ptr");
|
||||
int32_t regionX, regionY, regionZ;
|
||||
|
||||
// read position of the region inside DF world
|
||||
p->readDWord (region_x_offset, (uint32_t &)regionX);
|
||||
p->readDWord (region_y_offset, (uint32_t &)regionY);
|
||||
p->readDWord (region_z_offset, (uint32_t &)regionZ);
|
||||
while(1){
|
||||
int32_t cx1,cy1,cz1;
|
||||
cx1 = -30000;
|
||||
while(cx1 == -30000)
|
||||
{
|
||||
DF->ForceResume();
|
||||
cout << "Set cursor at first position, then press any key";
|
||||
cin.ignore();
|
||||
DF->Suspend();
|
||||
Gui->getCursorCoords(cx1,cy1,cz1);
|
||||
}
|
||||
|
||||
uint32_t tx1,ty1,tz1;
|
||||
tx1 = cx1/16;
|
||||
ty1 = cy1/16;
|
||||
tz1 = cz1;
|
||||
|
||||
int32_t cx2,cy2,cz2;
|
||||
cx2 = -30000;
|
||||
while(cx2 == -30000)
|
||||
{
|
||||
DF->Resume();
|
||||
cout << "Set cursor at second position, then press any key";
|
||||
cin.ignore();
|
||||
DF->Suspend();
|
||||
Gui->getCursorCoords(cx2,cy2,cz2);
|
||||
}
|
||||
uint32_t tx2,ty2,tz2;
|
||||
tx2 = cx2/16;
|
||||
ty2 = cy2/16;
|
||||
tz2 = cz2;
|
||||
sort(tx1,tx2);
|
||||
sort(ty1,ty2);
|
||||
sort(tz1,tz2);
|
||||
sort(cx1,cx2);
|
||||
sort(cy1,cy2);
|
||||
sort(cz1,cz2);
|
||||
|
||||
vector <vector<vector<string> > >dig(cz2-cz1+1,vector<vector<string> >(cy2-cy1+1,vector<string>(cx2-cx1+1)));
|
||||
vector <vector<vector<string> > >build(cz2-cz1+1,vector<vector<string> >(cy2-cy1+1,vector<string>(cx2-cx1+1)));
|
||||
mapblock40d block;
|
||||
DFHack::Maps *Maps = DF->getMaps();
|
||||
Maps->Start();
|
||||
for(uint32_t y = ty1;y<=ty2;y++)
|
||||
{
|
||||
for(uint32_t x = tx1;x<=tx2;x++)
|
||||
{
|
||||
for(uint32_t z = tz1;z<=tz2;z++)
|
||||
{
|
||||
if(Maps->isValidBlock(x,y,z))
|
||||
{
|
||||
if(Maps->ReadBlock40d(x,y,z,&block))
|
||||
{
|
||||
int ystart,yend,xstart,xend;
|
||||
ystart=xstart=0;
|
||||
yend=xend=15;
|
||||
if(y == ty2)
|
||||
{
|
||||
yend = cy2 % 16;
|
||||
}
|
||||
if(y == ty1)
|
||||
{
|
||||
ystart = cy1 % 16;
|
||||
}
|
||||
if(x == tx2)
|
||||
{
|
||||
xend = cx2 % 16;
|
||||
}
|
||||
if(x == tx1)
|
||||
{
|
||||
xstart = cx1 % 16;
|
||||
}
|
||||
int zidx = z-tz1;
|
||||
for(int yy = ystart; yy <= yend;yy++)
|
||||
{
|
||||
int yidx = yy+(16*(y-ty1)-(cy1%16));
|
||||
for(int xx = xstart; xx <= xend;xx++)
|
||||
{
|
||||
int xidx = xx+(16*(x-tx1)-(cx1%16));
|
||||
int16_t tt = block.tiletypes[xx][yy];
|
||||
DFHack::TileShape ts = DFHack::tileShape(tt);
|
||||
if(DFHack::isOpenTerrain(tt) || DFHack::isFloorTerrain(tt))
|
||||
{
|
||||
dig[zidx][yidx][xidx] = "d";
|
||||
}
|
||||
else if(DFHack::STAIR_DOWN == ts)
|
||||
{
|
||||
dig [zidx][yidx][xidx] = "j";
|
||||
build [zidx][yidx][xidx] = "Cd";
|
||||
}
|
||||
else if(DFHack::STAIR_UP == ts)
|
||||
{
|
||||
dig [zidx][yidx][xidx] = "u";
|
||||
build [zidx][yidx][xidx] = "Cu";
|
||||
}
|
||||
else if(DFHack::STAIR_UPDOWN == ts)
|
||||
{
|
||||
dig [zidx][yidx][xidx] = "i";
|
||||
build [zidx][yidx][xidx] = "Cx";
|
||||
}
|
||||
else if(DFHack::isRampTerrain(tt))
|
||||
{
|
||||
dig [zidx][yidx][xidx] = "r";
|
||||
build [zidx][yidx][xidx] = "Cr";
|
||||
}
|
||||
else if(DFHack::isWallTerrain(tt))
|
||||
{
|
||||
build [zidx][yidx][xidx] = "Cw";
|
||||
}
|
||||
}
|
||||
yidx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DFHack::Buildings * Bld = DF->getBuildings();
|
||||
std::map <uint32_t, std::string> custom_workshop_types;
|
||||
uint32_t numBuildings;
|
||||
if(Bld->Start(numBuildings))
|
||||
{
|
||||
Bld->ReadCustomWorkshopTypes(custom_workshop_types);
|
||||
for(uint32_t i = 0; i < numBuildings; i++)
|
||||
{
|
||||
DFHack::t_building temp;
|
||||
Bld->Read(i, temp);
|
||||
if(temp.type != 0xFFFFFFFF) // check if type isn't invalid
|
||||
{
|
||||
std::string typestr;
|
||||
mem->resolveClassIDToClassname(temp.type, typestr);
|
||||
if(temp.z == cz1 && cx1 <= temp.x1 && cx2 >= temp.x2 && cy1 <= temp.y1 && cy2 >= temp.y2)
|
||||
{
|
||||
string currStr = build[temp.z-cz1][temp.y1-cy1][temp.x1-cx1];
|
||||
stringstream stream;
|
||||
string newStr = buildCommands[typestr];
|
||||
if(temp.x1 != temp.x2)
|
||||
{
|
||||
stream << "(" << temp.x2-temp.x1+1 << "x" << temp.y2-temp.y1+1 << ")";
|
||||
newStr += stream.str();
|
||||
}
|
||||
build[temp.z-cz1][temp.y1-cy1][temp.x1-cx1] = newStr + currStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// for testing purposes
|
||||
//ofstream outfile("test.txt");
|
||||
// printVecOfVec(outfile, dig,'\t');
|
||||
// outfile << endl;
|
||||
// printVecOfVec(outfile, build,'\t');
|
||||
// outfile << endl;
|
||||
// outfile.close();
|
||||
|
||||
int32_t cx3,cy3,cz3,cx4,cy4,cz4;
|
||||
uint32_t tx3,ty3,tz3,tx4,ty4,tz4;
|
||||
char result;
|
||||
while(1){
|
||||
cx3 = -30000;
|
||||
while(cx3 == -30000){
|
||||
DF->Resume();
|
||||
cout << "Set cursor at new position, then press any key:";
|
||||
result = cin.get();
|
||||
DF->Suspend();
|
||||
Gui->getCursorCoords(cx3,cy3,cz3);
|
||||
}
|
||||
if(result == 'q'){
|
||||
break;
|
||||
}
|
||||
cx4 = cx3+cx2-cx1;
|
||||
cy4 = cy3+cy2-cy1;
|
||||
cz4 = cz3+cz2-cz1;
|
||||
tx3=cx3/16;
|
||||
ty3=cy3/16;
|
||||
tz3=cz3;
|
||||
tx4=cx4/16;
|
||||
ty4=cy4/16;
|
||||
tz4=cz4;
|
||||
DFHack::WindowIO * Win = DF->getWindowIO();
|
||||
designations40d designationBlock;
|
||||
for(uint32_t y = ty3;y<=ty4;y++)
|
||||
{
|
||||
for(uint32_t x = tx3;x<=tx4;x++)
|
||||
{
|
||||
for(uint32_t z = tz3;z<=tz4;z++)
|
||||
{
|
||||
Maps->Start();
|
||||
Maps->ReadBlock40d(x,y,z,&block);
|
||||
Maps->ReadDesignations(x,y,z,&designationBlock);
|
||||
int ystart,yend,xstart,xend;
|
||||
ystart=xstart=0;
|
||||
yend=xend=15;
|
||||
if(y == ty4){
|
||||
yend = cy4 % 16;
|
||||
}
|
||||
if(y == ty3){
|
||||
ystart = cy3 % 16;
|
||||
}
|
||||
if(x == tx4){
|
||||
xend = cx4 % 16;
|
||||
}
|
||||
if(x == tx3){
|
||||
xstart = cx3 % 16;
|
||||
}
|
||||
int zidx = z-tz3;
|
||||
for(int yy = ystart; yy <= yend;yy++){
|
||||
int yidx = yy+(16*(y-ty3)-(cy3%16));
|
||||
for(int xx = xstart; xx <= xend;xx++){
|
||||
int xidx = xx+(16*(x-tx3)-(cx3%16));
|
||||
if(dig[zidx][yidx][xidx] != ""){
|
||||
char test = dig[zidx][yidx][xidx].c_str()[0];
|
||||
switch (test){
|
||||
case 'd':
|
||||
designationBlock[xx][yy].bits.dig = DFHack::designation_default;
|
||||
break;
|
||||
case 'i':
|
||||
designationBlock[xx][yy].bits.dig = DFHack::designation_ud_stair;
|
||||
break;
|
||||
case 'u':
|
||||
designationBlock[xx][yy].bits.dig = DFHack::designation_u_stair;
|
||||
break;
|
||||
case 'j':
|
||||
designationBlock[xx][yy].bits.dig = DFHack::designation_d_stair;
|
||||
break;
|
||||
case 'r':
|
||||
designationBlock[xx][yy].bits.dig = DFHack::designation_ramp;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
yidx++;
|
||||
}
|
||||
Maps->Start();
|
||||
Maps->WriteDesignations(x,y,z,&designationBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DF->Detach();
|
||||
#ifndef LINUX_BUILD
|
||||
std::cout << "Done. Press any key to continue" << std::endl;
|
||||
cin.ignore();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
bool waitTillCursorState(DFHack::Context *DF, bool On)
|
||||
{
|
||||
DFHack::WindowIO * w = DF->getWindowIO();
|
||||
DFHack::Position * p = DF->getPosition();
|
||||
int32_t x,y,z;
|
||||
int tryCount = 0;
|
||||
DF->Suspend();
|
||||
bool cursorResult = p->getCursorCoords(x,y,z);
|
||||
while(tryCount < 50 && On && !cursorResult || !On && cursorResult)
|
||||
{
|
||||
DF->Resume();
|
||||
w->TypeSpecial(DFHack::WAIT,1,WAIT_AMT);
|
||||
tryCount++;
|
||||
DF->Suspend();
|
||||
cursorResult = p->getCursorCoords(x,y,z);
|
||||
}
|
||||
if(tryCount >= 50)
|
||||
{
|
||||
cerr << "Something went wrong, cursor at x: " << x << " y: " << y << " z: " << z << endl;
|
||||
return false;
|
||||
}
|
||||
DF->Resume();
|
||||
return true;
|
||||
}
|
||||
bool waitTillCursorPositionState(DFHack::Context *DF, int32_t x,int32_t y, int32_t z)
|
||||
{
|
||||
DFHack::WindowIO * w = DF->getWindowIO();
|
||||
DFHack::Position * p = DF->getPosition();
|
||||
int32_t x2,y2,z2;
|
||||
int tryCount = 0;
|
||||
DF->Suspend();
|
||||
bool cursorResult = p->getCursorCoords(x2,y2,z2);
|
||||
while(tryCount < 50 && (x != x2 || y != y2 || z != z2))
|
||||
{
|
||||
DF->Resume();
|
||||
w->TypeSpecial(DFHack::WAIT,1,WAIT_AMT);
|
||||
tryCount++;
|
||||
DF->Suspend();
|
||||
cursorResult = p->getCursorCoords(x2,y2,z2);
|
||||
}
|
||||
if(tryCount >= 50)
|
||||
{
|
||||
cerr << "Something went wrong, cursor at x: " << x2 << " y: " << y2 << " z: " << z2 << endl;
|
||||
return false;
|
||||
}
|
||||
DF->Resume();
|
||||
return true;
|
||||
}*/
|
File diff suppressed because it is too large
Load Diff
@ -1,40 +0,0 @@
|
||||
-- prints info on assigned hotkeys to the console
|
||||
|
||||
local hotkeys = {'F1 ', 'F2 ', 'F3 ', 'F4 ', 'F5 ', 'F6 ',
|
||||
'F7 ', 'F8 ', 'F9 ', 'F10', 'F11', 'F12'}
|
||||
|
||||
for i=1, #hotkeys do
|
||||
local hk = hotkeys[i]
|
||||
hk = {id=hk}
|
||||
-- PLACEHOLDER PROPERTIES ONLY!
|
||||
hk.name = '_name'
|
||||
hk.x = df.global.window_x
|
||||
hk.y = df.global.window_y
|
||||
hk.z = df.global.window_z
|
||||
|
||||
print(hk.id..' '..hk.name..' X= '..hk.x..', Y= '..hk.y..', Z= '..hk.z)
|
||||
end
|
||||
|
||||
--[[
|
||||
# the (very) old Python version...
|
||||
from context import Context, ContextManager
|
||||
|
||||
cm = ContextManager("Memory.xml")
|
||||
df = cm.get_single_context()
|
||||
|
||||
df.attach()
|
||||
|
||||
gui = df.gui
|
||||
|
||||
print "Hotkeys"
|
||||
|
||||
hotkeys = gui.read_hotkeys()
|
||||
|
||||
for key in hotkeys:
|
||||
print "x: %d\ny: %d\tz: %d\ttext: %s" % (key.x, key.y, key.z, key.name)
|
||||
|
||||
df.detach()
|
||||
|
||||
print "Done. Press any key to continue"
|
||||
raw_input()
|
||||
]]--
|
@ -0,0 +1,682 @@
|
||||
//Blueprint
|
||||
//By cdombroski
|
||||
//Translates a region of tiles specified by the cursor and arguments/prompts into a series of blueprint files suitable for digfort/buildingplan/quickfort
|
||||
|
||||
#include <Console.h>
|
||||
#include <PluginManager.h>
|
||||
|
||||
#include "modules/Buildings.h"
|
||||
#include "modules/Gui.h"
|
||||
#include "modules/MapCache.h"
|
||||
|
||||
#include "df/building_axle_horizontalst.h"
|
||||
#include "df/building_bridgest.h"
|
||||
#include "df/building_constructionst.h"
|
||||
#include "df/building_furnacest.h"
|
||||
#include "df/building_rollersst.h"
|
||||
#include "df/building_screw_pumpst.h"
|
||||
#include "df/building_siegeenginest.h"
|
||||
#include "df/building_trapst.h"
|
||||
#include "df/building_water_wheelst.h"
|
||||
#include "df/building_workshopst.h"
|
||||
|
||||
using std::string;
|
||||
using std::endl;
|
||||
using std::vector;
|
||||
using std::ofstream;
|
||||
using std::swap;
|
||||
using std::find;
|
||||
using std::pair;
|
||||
using namespace DFHack;
|
||||
using namespace df::enums;
|
||||
|
||||
DFHACK_PLUGIN("blueprint");
|
||||
|
||||
enum phase {DIG=1, BUILD=2, PLACE=4, QUERY=8};
|
||||
|
||||
command_result blueprint(color_ostream &out, vector <string> ¶meters);
|
||||
|
||||
DFhackCExport command_result plugin_init(color_ostream &out, vector<PluginCommand> &commands)
|
||||
{
|
||||
commands.push_back(PluginCommand("blueprint", "Convert map tiles into a blueprint", blueprint, false));
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
DFhackCExport command_result plugin_shutdown(color_ostream &out)
|
||||
{
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
command_result help(color_ostream &out)
|
||||
{
|
||||
out << "blueprint width height depth name [dig] [build] [place] [query]" << endl
|
||||
<< " width, height, depth: area to translate in tiles" << endl
|
||||
<< " name: base name for blueprint files" << endl
|
||||
<< " dig: generate blueprints for digging" << endl
|
||||
<< " build: generate blueprints for building" << endl
|
||||
<< " place: generate blueprints for stockpiles" << endl
|
||||
<< " query: generate blueprints for querying (room designations)" << endl
|
||||
<< " defaults to generating all blueprints" << endl
|
||||
<< endl
|
||||
<< "blueprint translates a portion of your fortress into blueprints suitable for" << endl
|
||||
<< " digfort/fortplan/quickfort. Blueprints are created in the DF folder with names" << endl
|
||||
<< " following a \"name-phase.csv\" pattern. Translation starts at the current" << endl
|
||||
<< " cursor location and includes all tiles in the range specified." << endl;
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
pair<uint32_t, uint32_t> get_building_size(df::building* b)
|
||||
{
|
||||
return pair<uint32_t, uint32_t>(b->x2 - b->x1 + 1, b->y2 - b->y1 + 1);
|
||||
}
|
||||
|
||||
char get_tile_dig(MapExtras::MapCache mc, int32_t x, int32_t y, int32_t z)
|
||||
{
|
||||
df::tiletype tt = mc.tiletypeAt(DFCoord(x, y, z));
|
||||
df::tiletype_shape ts = tileShape(tt);
|
||||
switch (ts)
|
||||
{
|
||||
case tiletype_shape::EMPTY:
|
||||
case tiletype_shape::RAMP_TOP:
|
||||
return 'h';
|
||||
case tiletype_shape::FLOOR:
|
||||
case tiletype_shape::BOULDER:
|
||||
case tiletype_shape::PEBBLES:
|
||||
case tiletype_shape::BROOK_TOP:
|
||||
return 'd';
|
||||
case tiletype_shape::FORTIFICATION:
|
||||
return 'F';
|
||||
case tiletype_shape::STAIR_UP:
|
||||
return 'u';
|
||||
case tiletype_shape::STAIR_DOWN:
|
||||
return 'j';
|
||||
case tiletype_shape::STAIR_UPDOWN:
|
||||
return 'i';
|
||||
case tiletype_shape::RAMP:
|
||||
return 'r';
|
||||
default:
|
||||
return ' ';
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
string get_tile_build(uint32_t x, uint32_t y, df::building* b)
|
||||
{
|
||||
if (! b)
|
||||
return " ";
|
||||
bool at_nw_corner = x == b->x1 && y == b->y1;
|
||||
bool at_se_corner = x == b->x2 && y == b->y2;
|
||||
bool at_center = x == b->centerx && y == b->centery;
|
||||
pair<uint32_t, uint32_t> size = get_building_size(b);
|
||||
stringstream out;// = stringstream();
|
||||
switch(b->getType())
|
||||
{
|
||||
case building_type::Armorstand:
|
||||
return "a";
|
||||
case building_type::Bed:
|
||||
return "b";
|
||||
case building_type::Chair:
|
||||
return "c";
|
||||
case building_type::Door:
|
||||
return "d";
|
||||
case building_type::Floodgate:
|
||||
return "x";
|
||||
case building_type::Cabinet:
|
||||
return "f";
|
||||
case building_type::Box:
|
||||
return "h";
|
||||
//case building_type::Kennel is missing
|
||||
case building_type::FarmPlot:
|
||||
if(!at_nw_corner)
|
||||
return "`";
|
||||
out << "p(" << size.first << "x" << size.second << ")";
|
||||
return out.str();
|
||||
case building_type::Weaponrack:
|
||||
return "r";
|
||||
case building_type::Statue:
|
||||
return "s";
|
||||
case building_type::Table:
|
||||
return "t";
|
||||
case building_type::RoadPaved:
|
||||
if(! at_nw_corner)
|
||||
return "`";
|
||||
out << "o(" << size.first << "x" << size.second << ")";
|
||||
return out.str();
|
||||
case building_type::RoadDirt:
|
||||
if(! at_nw_corner)
|
||||
return "`";
|
||||
out << "O(" << size.first << "x" << size.second << ")";
|
||||
return out.str();
|
||||
case building_type::Bridge:
|
||||
if(! at_nw_corner)
|
||||
return "`";
|
||||
switch(((df::building_bridgest*) b)->direction)
|
||||
{
|
||||
case df::building_bridgest::T_direction::Down:
|
||||
out << "gx";
|
||||
break;
|
||||
case df::building_bridgest::T_direction::Left:
|
||||
out << "ga";
|
||||
break;
|
||||
case df::building_bridgest::T_direction::Up:
|
||||
out << "gw";
|
||||
break;
|
||||
case df::building_bridgest::T_direction::Right:
|
||||
out << "gd";
|
||||
break;
|
||||
case df::building_bridgest::T_direction::Retracting:
|
||||
out << "gs";
|
||||
break;
|
||||
}
|
||||
out << "(" << size.first << "x" << size.second << ")";
|
||||
return out.str();
|
||||
case building_type::Well:
|
||||
return "l";
|
||||
case building_type::SiegeEngine:
|
||||
if (! at_center)
|
||||
return "`";
|
||||
return ((df::building_siegeenginest*) b)->type == df::siegeengine_type::Ballista ? "ib" : "ic";
|
||||
case building_type::Workshop:
|
||||
if (! at_center)
|
||||
return "`";
|
||||
switch (((df::building_workshopst*) b)->type)
|
||||
{
|
||||
case workshop_type::Leatherworks:
|
||||
return "we";
|
||||
case workshop_type::Quern:
|
||||
return "wq";
|
||||
case workshop_type::Millstone:
|
||||
return "wM";
|
||||
case workshop_type::Loom:
|
||||
return "wo";
|
||||
case workshop_type::Clothiers:
|
||||
return "wk";
|
||||
case workshop_type::Bowyers:
|
||||
return "wb";
|
||||
case workshop_type::Carpenters:
|
||||
return "wc";
|
||||
case workshop_type::MetalsmithsForge:
|
||||
return "wf";
|
||||
case workshop_type::MagmaForge:
|
||||
return "wv";
|
||||
case workshop_type::Jewelers:
|
||||
return "wj";
|
||||
case workshop_type::Masons:
|
||||
return "wm";
|
||||
case workshop_type::Butchers:
|
||||
return "wu";
|
||||
case workshop_type::Tanners:
|
||||
return "wn";
|
||||
case workshop_type::Craftsdwarfs:
|
||||
return "wr";
|
||||
case workshop_type::Siege:
|
||||
return "ws";
|
||||
case workshop_type::Mechanics:
|
||||
return "wt";
|
||||
case workshop_type::Still:
|
||||
return "wl";
|
||||
case workshop_type::Farmers:
|
||||
return "ww";
|
||||
case workshop_type::Kitchen:
|
||||
return "wz";
|
||||
case workshop_type::Fishery:
|
||||
return "wh";
|
||||
case workshop_type::Ashery:
|
||||
return "wy";
|
||||
case workshop_type::Dyers:
|
||||
return "wd";
|
||||
case workshop_type::Custom:
|
||||
//can't do anything with custom workshop
|
||||
return "`";
|
||||
}
|
||||
case building_type::Furnace:
|
||||
if (! at_center)
|
||||
return "`";
|
||||
switch (((df::building_furnacest*) b)->type)
|
||||
{
|
||||
case furnace_type::WoodFurnace:
|
||||
return "ew";
|
||||
case furnace_type::Smelter:
|
||||
return "es";
|
||||
case furnace_type::GlassFurnace:
|
||||
return "eg";
|
||||
case furnace_type::Kiln:
|
||||
return "ek";
|
||||
case furnace_type::MagmaSmelter:
|
||||
return "el";
|
||||
case furnace_type::MagmaGlassFurnace:
|
||||
return "ea";
|
||||
case furnace_type::MagmaKiln:
|
||||
return "en";
|
||||
case furnace_type::Custom:
|
||||
//can't do anything with custom furnace
|
||||
return "`";
|
||||
}
|
||||
case building_type::WindowGlass:
|
||||
return "y";
|
||||
case building_type::WindowGem:
|
||||
return "Y";
|
||||
case building_type::Construction:
|
||||
switch (((df::building_constructionst*) b)->type)
|
||||
{
|
||||
case construction_type::Fortification:
|
||||
return "CF";
|
||||
case construction_type::Wall:
|
||||
return "CW";
|
||||
case construction_type::Floor:
|
||||
return "Cf";
|
||||
case construction_type::UpStair:
|
||||
return "Cu";
|
||||
case construction_type::DownStair:
|
||||
return "Cj";
|
||||
case construction_type::UpDownStair:
|
||||
return "Cx";
|
||||
case construction_type::Ramp:
|
||||
return "Cr";
|
||||
case construction_type::TrackN:
|
||||
return "trackN";
|
||||
case construction_type::TrackS:
|
||||
return "trackS";
|
||||
case construction_type::TrackE:
|
||||
return "trackE";
|
||||
case construction_type::TrackW:
|
||||
return "trackW";
|
||||
case construction_type::TrackNS:
|
||||
return "trackNS";
|
||||
case construction_type::TrackNE:
|
||||
return "trackNE";
|
||||
case construction_type::TrackNW:
|
||||
return "trackNW";
|
||||
case construction_type::TrackSE:
|
||||
return "trackSE";
|
||||
case construction_type::TrackSW:
|
||||
return "trackSW";
|
||||
case construction_type::TrackEW:
|
||||
return "trackEW";
|
||||
case construction_type::TrackNSE:
|
||||
return "trackNSE";
|
||||
case construction_type::TrackNSW:
|
||||
return "trackNSW";
|
||||
case construction_type::TrackNEW:
|
||||
return "trackNEW";
|
||||
case construction_type::TrackSEW:
|
||||
return "trackSEW";
|
||||
case construction_type::TrackNSEW:
|
||||
return "trackNSEW";
|
||||
case construction_type::TrackRampN:
|
||||
return "trackrampN";
|
||||
case construction_type::TrackRampS:
|
||||
return "trackrampS";
|
||||
case construction_type::TrackRampE:
|
||||
return "trackrampE";
|
||||
case construction_type::TrackRampW:
|
||||
return "trackrampW";
|
||||
case construction_type::TrackRampNS:
|
||||
return "trackrampNS";
|
||||
case construction_type::TrackRampNE:
|
||||
return "trackrampNE";
|
||||
case construction_type::TrackRampNW:
|
||||
return "trackrampNW";
|
||||
case construction_type::TrackRampSE:
|
||||
return "trackrampSE";
|
||||
case construction_type::TrackRampSW:
|
||||
return "trackrampSW";
|
||||
case construction_type::TrackRampEW:
|
||||
return "trackrampEW";
|
||||
case construction_type::TrackRampNSE:
|
||||
return "trackrampNSE";
|
||||
case construction_type::TrackRampNSW:
|
||||
return "trackrampNSW";
|
||||
case construction_type::TrackRampNEW:
|
||||
return "trackrampNEW";
|
||||
case construction_type::TrackRampSEW:
|
||||
return "trackrampSEW";
|
||||
case construction_type::TrackRampNSEW:
|
||||
return "trackrampNSEW";
|
||||
}
|
||||
case building_type::Shop:
|
||||
if (! at_center)
|
||||
return "`";
|
||||
return "z";
|
||||
case building_type::AnimalTrap:
|
||||
return "m";
|
||||
case building_type::Chain:
|
||||
return "v";
|
||||
case building_type::Cage:
|
||||
return "j";
|
||||
case building_type::TradeDepot:
|
||||
if (! at_center)
|
||||
return "`";
|
||||
return "D";
|
||||
case building_type::Trap:
|
||||
switch (((df::building_trapst*) b)->trap_type)
|
||||
{
|
||||
case trap_type::StoneFallTrap:
|
||||
return "Ts";
|
||||
case trap_type::WeaponTrap:
|
||||
return "Tw";
|
||||
case trap_type::Lever:
|
||||
return "Tl";
|
||||
case trap_type::PressurePlate:
|
||||
return "Tp";
|
||||
case trap_type::CageTrap:
|
||||
return "Tc";
|
||||
case trap_type::TrackStop:
|
||||
df::building_trapst* ts = (df::building_trapst*) b;
|
||||
out << "CS";
|
||||
if (ts->use_dump)
|
||||
{
|
||||
if (ts->dump_x_shift == 0)
|
||||
{
|
||||
if (ts->dump_y_shift > 0)
|
||||
out << "dd";
|
||||
else
|
||||
out << "d";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ts->dump_x_shift > 0)
|
||||
out << "ddd";
|
||||
else
|
||||
out << "dddd";
|
||||
}
|
||||
}
|
||||
switch (ts->friction)
|
||||
{
|
||||
case 10:
|
||||
out << "a";
|
||||
case 50:
|
||||
out << "a";
|
||||
case 500:
|
||||
out << "a";
|
||||
case 10000:
|
||||
out << "a";
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
case building_type::ScrewPump:
|
||||
if (! at_se_corner) //screw pumps anchor at bottom/right
|
||||
return "`";
|
||||
switch (((df::building_screw_pumpst*) b)->direction)
|
||||
{
|
||||
case screw_pump_direction::FromNorth:
|
||||
return "Msu";
|
||||
case screw_pump_direction::FromEast:
|
||||
return "Msk";
|
||||
case screw_pump_direction::FromSouth:
|
||||
return "Msm";
|
||||
case screw_pump_direction::FromWest:
|
||||
return "Msh";
|
||||
}
|
||||
case building_type::WaterWheel:
|
||||
if (! at_center)
|
||||
return "`";
|
||||
//s swaps orientation which defaults to vertical
|
||||
return ((df::building_water_wheelst*) b)->is_vertical ? "Mw" : "Mws";
|
||||
case building_type::Windmill:
|
||||
if (! at_center)
|
||||
return "`";
|
||||
return "Mm";
|
||||
case building_type::GearAssembly:
|
||||
return "Mg";
|
||||
case building_type::AxleHorizontal:
|
||||
if (! at_nw_corner) //a guess based on how constructions work
|
||||
return "`";
|
||||
//same as water wheel but reversed
|
||||
out << "Mh" << (((df::building_axle_horizontalst*) b)->is_vertical ? "s" : "")
|
||||
<< "(" << size.first << "x" << size.second << ")";
|
||||
return out.str();
|
||||
case building_type::AxleVertical:
|
||||
return "Mv";
|
||||
case building_type::Rollers:
|
||||
if (! at_nw_corner)
|
||||
return "`";
|
||||
out << "Mr";
|
||||
switch (((df::building_rollersst*) b)->direction)
|
||||
{
|
||||
case screw_pump_direction::FromNorth:
|
||||
break;
|
||||
case screw_pump_direction::FromEast:
|
||||
out << "s";
|
||||
case screw_pump_direction::FromSouth:
|
||||
out << "s";
|
||||
case screw_pump_direction::FromWest:
|
||||
out << "s";
|
||||
}
|
||||
out << "(" << size.first << "x" << size.second << ")";
|
||||
return out.str();
|
||||
case building_type::Support:
|
||||
return "S";
|
||||
case building_type::ArcheryTarget:
|
||||
return "A";
|
||||
case building_type::TractionBench:
|
||||
return "R";
|
||||
case building_type::Hatch:
|
||||
return "H";
|
||||
case building_type::Slab:
|
||||
//how to mine alt key?!?
|
||||
//alt+s
|
||||
return " ";
|
||||
case building_type::NestBox:
|
||||
return "N";
|
||||
case building_type::Hive:
|
||||
//alt+h
|
||||
return " ";
|
||||
case building_type::GrateWall:
|
||||
return "W";
|
||||
case building_type::GrateFloor:
|
||||
return "G";
|
||||
case building_type::BarsVertical:
|
||||
return "B";
|
||||
case building_type::BarsFloor:
|
||||
//alt+b
|
||||
return " ";
|
||||
default:
|
||||
return " ";
|
||||
}
|
||||
}
|
||||
|
||||
string get_tile_place(uint32_t x, uint32_t y, df::building* b)
|
||||
{
|
||||
if (! b || b->getType() != building_type::Stockpile)
|
||||
return " ";
|
||||
if (b->x1 != x || b->y1 != y)
|
||||
return "`";
|
||||
pair<uint32_t, uint32_t> size = get_building_size(b);
|
||||
df::building_stockpilest* sp = (df::building_stockpilest*) b;
|
||||
stringstream out;// = stringstream();
|
||||
switch (sp->settings.flags.whole)
|
||||
{
|
||||
case df::stockpile_group_set::mask_animals:
|
||||
out << "a";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_food:
|
||||
out << "f";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_furniture:
|
||||
out << "u";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_corpses:
|
||||
out << "y";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_refuse:
|
||||
out << "r";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_wood:
|
||||
out << "w";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_stone:
|
||||
out << "s";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_gems:
|
||||
out << "e";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_bars_blocks:
|
||||
out << "b";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_cloth:
|
||||
out << "h";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_leather:
|
||||
out << "l";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_ammo:
|
||||
out << "z";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_coins:
|
||||
out << "n";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_finished_goods:
|
||||
out << "g";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_weapons:
|
||||
out << "p";
|
||||
break;
|
||||
case df::stockpile_group_set::mask_armor:
|
||||
out << "d";
|
||||
break;
|
||||
default: //multiple stockpile type
|
||||
return "`";
|
||||
}
|
||||
out << "("<< size.first << "x" << size.second << ")";
|
||||
return out.str();
|
||||
}
|
||||
|
||||
string get_tile_query(df::building* b)
|
||||
{
|
||||
if (b && b->is_room)
|
||||
return "r+";
|
||||
return " ";
|
||||
}
|
||||
|
||||
command_result do_transform(DFCoord start, DFCoord end, string name, uint32_t phases)
|
||||
{
|
||||
ofstream dig, build, place, query;
|
||||
if (phases & QUERY)
|
||||
{
|
||||
//query = ofstream((name + "-query.csv").c_str(), ofstream::trunc);
|
||||
query.open(name+"-query.csv", ofstream::trunc);
|
||||
query << "#query" << endl;
|
||||
}
|
||||
if (phases & PLACE)
|
||||
{
|
||||
//place = ofstream(name + "-place.csv", ofstream::trunc);
|
||||
place.open(name+"-place.csv", ofstream::trunc);
|
||||
place << "#place" << endl;
|
||||
}
|
||||
if (phases & BUILD)
|
||||
{
|
||||
//build = ofstream(name + "-build.csv", ofstream::trunc);
|
||||
build.open(name+"-build.csv", ofstream::trunc);
|
||||
build << "#build" << endl;
|
||||
}
|
||||
if (phases & DIG)
|
||||
{
|
||||
//dig = ofstream(name + "-dig.csv", ofstream::trunc);
|
||||
dig.open(name+"-dig.csv", ofstream::trunc);
|
||||
dig << "#dig" << endl;
|
||||
}
|
||||
if (start.x > end.x)
|
||||
{
|
||||
swap(start.x, end.x);
|
||||
start.x++;
|
||||
end.x++;
|
||||
}
|
||||
if (start.y > end.y)
|
||||
{
|
||||
swap(start.y, end.y);
|
||||
start.y++;
|
||||
end.y++;
|
||||
}
|
||||
if (start.z > end.z)
|
||||
{
|
||||
swap(start.z, end.z);
|
||||
start.z++;
|
||||
end.z++;
|
||||
}
|
||||
|
||||
MapExtras::MapCache mc;
|
||||
for (int32_t z = start.z; z < end.z; z++)
|
||||
{
|
||||
for (int32_t y = start.y; y < end.y; y++)
|
||||
{
|
||||
for (int32_t x = start.x; x < end.x; x++)
|
||||
{
|
||||
df::building* b = DFHack::Buildings::findAtTile(DFCoord(x, y, z));
|
||||
if (phases & QUERY)
|
||||
query << get_tile_query(b) << ',';
|
||||
if (phases & PLACE)
|
||||
place << get_tile_place(x, y, b) << ',';
|
||||
if (phases & BUILD)
|
||||
build << get_tile_build(x, y, b) << ',';
|
||||
if (phases & DIG)
|
||||
dig << get_tile_dig(mc, x, y, z) << ',';
|
||||
}
|
||||
if (phases & QUERY)
|
||||
query << "#" << endl;
|
||||
if (phases & PLACE)
|
||||
place << "#" << endl;
|
||||
if (phases & BUILD)
|
||||
build << "#" << endl;
|
||||
if (phases & DIG)
|
||||
dig << "#" << endl;
|
||||
}
|
||||
if (z < end.z - 1)
|
||||
{
|
||||
if (phases & QUERY)
|
||||
query << "#<" << endl;
|
||||
if (phases & PLACE)
|
||||
place << "#<" << endl;
|
||||
if (phases & BUILD)
|
||||
build << "#<" << endl;
|
||||
if (phases & DIG)
|
||||
dig << "#<" << endl;
|
||||
}
|
||||
}
|
||||
if (phases & QUERY)
|
||||
query.close();
|
||||
if (phases & PLACE)
|
||||
place.close();
|
||||
if (phases & BUILD)
|
||||
build.close();
|
||||
if (phases & DIG)
|
||||
dig.close();
|
||||
return CR_OK;
|
||||
}
|
||||
|
||||
bool cmd_option_exists(vector<string>& parameters, const string& option)
|
||||
{
|
||||
return find(parameters.begin(), parameters.end(), option) != parameters.end();
|
||||
}
|
||||
|
||||
command_result blueprint(color_ostream &out, vector<string> ¶meters)
|
||||
{
|
||||
if (parameters.size() < 4 || parameters.size() > 8)
|
||||
return help(out);
|
||||
CoreSuspender suspend;
|
||||
if (!Maps::IsValid())
|
||||
{
|
||||
out.printerr("Map is not available!\n");
|
||||
return CR_FAILURE;
|
||||
}
|
||||
int32_t x, y, z;
|
||||
if (!Gui::getCursorCoords(x, y, z))
|
||||
{
|
||||
out.printerr("Can't get cursor coords! Make sure you have an active cursor in DF.\n");
|
||||
return CR_FAILURE;
|
||||
}
|
||||
DFCoord start (x, y, z);
|
||||
DFCoord end (x + stoi(parameters[0]), y + stoi(parameters[1]), z + stoi(parameters[2]));
|
||||
if (parameters.size() == 4)
|
||||
return do_transform(start, end, parameters[3], DIG | BUILD | PLACE | QUERY);
|
||||
uint32_t option = 0;
|
||||
if (cmd_option_exists(parameters, "dig"))
|
||||
option |= DIG;
|
||||
if (cmd_option_exists(parameters, "build"))
|
||||
option |= BUILD;
|
||||
if (cmd_option_exists(parameters, "place"))
|
||||
option |= PLACE;
|
||||
if (cmd_option_exists(parameters, "query"))
|
||||
option |= QUERY;
|
||||
return do_transform(start, end, parameters[3], option);
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
-- prints info on assigned hotkeys to the console
|
||||
|
||||
for i=1, #df.global.ui.main.hotkeys do
|
||||
local hk = df.global.ui.main.hotkeys[i-1]
|
||||
local key = dfhack.screen.getKeyDisplay(df.interface_key.D_HOTKEY1 + i - 1)
|
||||
if hk.cmd ~= -1 then
|
||||
print(key..': '..hk.name..': x='..hk.x..' y='..hk.y..' z='..hk.z)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue