Merge remote-tracking branch 'PeridexisErrant/needs_porting-cleanup'
Conflicts: NEWSdevelop
commit
ad6b19f1b2
@ -1,543 +0,0 @@
|
||||
#ifndef SEGMENTED_FINDER_H
|
||||
#define SEGMENTED_FINDER_H
|
||||
#include <malloc.h>
|
||||
#include <iosfwd>
|
||||
#include <iterator>
|
||||
|
||||
class SegmentedFinder;
|
||||
class SegmentFinder
|
||||
{
|
||||
public:
|
||||
SegmentFinder(DFHack::t_memrange & mr, DFHack::Context * DF, SegmentedFinder * SF)
|
||||
{
|
||||
_DF = DF;
|
||||
mr_ = mr;
|
||||
valid=false;
|
||||
if(mr.valid)
|
||||
{
|
||||
mr_.buffer = (uint8_t *)malloc (mr_.end - mr_.start);
|
||||
_SF = SF;
|
||||
try
|
||||
{
|
||||
DF->ReadRaw(mr_.start,(mr_.end - mr_.start),mr_.buffer);
|
||||
valid = true;
|
||||
}
|
||||
catch (DFHack::Error::MemoryAccessDenied &)
|
||||
{
|
||||
free(mr_.buffer);
|
||||
valid = false;
|
||||
mr.valid = false; // mark the range passed in as bad
|
||||
cout << "Range 0x" << hex << mr_.start << " - 0x" << mr_.end;
|
||||
|
||||
if (strlen(mr_.name) != 0)
|
||||
cout << " (" << mr_.name << ")";
|
||||
|
||||
cout << dec << " not readable." << endl;
|
||||
cout << "Skipping this range on future scans." << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
~SegmentFinder()
|
||||
{
|
||||
if(valid)
|
||||
free(mr_.buffer);
|
||||
}
|
||||
bool isValid()
|
||||
{
|
||||
return valid;
|
||||
}
|
||||
template <class needleType, class hayType, typename comparator >
|
||||
bool Find (needleType needle, const uint8_t increment , vector <uint64_t> &newfound, comparator oper)
|
||||
{
|
||||
if(!valid) return !newfound.empty();
|
||||
//loop
|
||||
for(uint64_t offset = 0; offset < (mr_.end - mr_.start) - sizeof(hayType); offset += increment)
|
||||
{
|
||||
if( oper(_SF,(hayType *)(mr_.buffer + offset), needle) )
|
||||
newfound.push_back(mr_.start + offset);
|
||||
}
|
||||
return !newfound.empty();
|
||||
}
|
||||
|
||||
template < class needleType, class hayType, typename comparator >
|
||||
uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length)
|
||||
{
|
||||
if(!valid) return 0;
|
||||
uint64_t stopper = min((mr_.end - mr_.start) - sizeof(hayType), (start - mr_.start) - sizeof(hayType) + length);
|
||||
//loop
|
||||
for(uint64_t offset = start - mr_.start; offset < stopper; offset +=1)
|
||||
{
|
||||
if( oper(_SF,(hayType *)(mr_.buffer + offset), needle) )
|
||||
return mr_.start + offset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class needleType, class hayType, typename comparator >
|
||||
bool Filter (needleType needle, vector <uint64_t> &found, vector <uint64_t> &newfound, comparator oper)
|
||||
{
|
||||
if(!valid) return !newfound.empty();
|
||||
for( uint64_t i = 0; i < found.size(); i++)
|
||||
{
|
||||
if(mr_.isInRange(found[i]))
|
||||
{
|
||||
uint64_t corrected = found[i] - mr_.start;
|
||||
if( oper(_SF,(hayType *)(mr_.buffer + corrected), needle) )
|
||||
newfound.push_back(found[i]);
|
||||
}
|
||||
}
|
||||
return !newfound.empty();
|
||||
}
|
||||
private:
|
||||
friend class SegmentedFinder;
|
||||
SegmentedFinder * _SF;
|
||||
DFHack::Context * _DF;
|
||||
DFHack::t_memrange mr_;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
class SegmentedFinder
|
||||
{
|
||||
public:
|
||||
SegmentedFinder(vector <DFHack::t_memrange>& ranges, DFHack::Context * DF)
|
||||
{
|
||||
_DF = DF;
|
||||
for(size_t i = 0; i < ranges.size(); i++)
|
||||
{
|
||||
segments.push_back(new SegmentFinder(ranges[i], DF, this));
|
||||
}
|
||||
}
|
||||
~SegmentedFinder()
|
||||
{
|
||||
for(size_t i = 0; i < segments.size(); i++)
|
||||
{
|
||||
delete segments[i];
|
||||
}
|
||||
}
|
||||
SegmentFinder * getSegmentForAddress (uint64_t addr)
|
||||
{
|
||||
for(size_t i = 0; i < segments.size(); i++)
|
||||
{
|
||||
if(segments[i]->mr_.isInRange(addr))
|
||||
{
|
||||
return segments[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
template <class needleType, class hayType, typename comparator >
|
||||
bool Find (const needleType needle, const uint8_t increment, vector <uint64_t> &found, comparator oper)
|
||||
{
|
||||
found.clear();
|
||||
for(size_t i = 0; i < segments.size(); i++)
|
||||
{
|
||||
segments[i]->Find<needleType,hayType,comparator>(needle, increment, found, oper);
|
||||
}
|
||||
return !(found.empty());
|
||||
}
|
||||
|
||||
template < class needleType, class hayType, typename comparator >
|
||||
uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length)
|
||||
{
|
||||
SegmentFinder * sf = getSegmentForAddress(start);
|
||||
if(sf)
|
||||
{
|
||||
return sf->FindInRange<needleType,hayType,comparator>(needle, oper, start, length);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class needleType, class hayType, typename comparator >
|
||||
bool Filter (const needleType needle, vector <uint64_t> &found, comparator oper)
|
||||
{
|
||||
vector <uint64_t> newfound;
|
||||
for(size_t i = 0; i < segments.size(); i++)
|
||||
{
|
||||
segments[i]->Filter<needleType,hayType,comparator>(needle, found, newfound, oper);
|
||||
}
|
||||
found.clear();
|
||||
found = newfound;
|
||||
return !(found.empty());
|
||||
}
|
||||
|
||||
template <class needleType, class hayType, typename comparator >
|
||||
bool Incremental (needleType needle, const uint8_t increment ,vector <uint64_t> &found, comparator oper)
|
||||
{
|
||||
if(found.empty())
|
||||
{
|
||||
return Find <needleType, hayType, comparator>(needle,increment,found,oper);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Filter <needleType, hayType, comparator>(needle,found,oper);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T * Translate(uint64_t address)
|
||||
{
|
||||
for(size_t i = 0; i < segments.size(); i++)
|
||||
{
|
||||
if(segments[i]->mr_.isInRange(address))
|
||||
{
|
||||
return (T *) (segments[i]->mr_.buffer + address - segments[i]->mr_.start);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Read(uint64_t address)
|
||||
{
|
||||
return *Translate<T>(address);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Read(uint64_t address, T& target)
|
||||
{
|
||||
T * test = Translate<T>(address);
|
||||
if(test)
|
||||
{
|
||||
target = *test;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
DFHack::Context * _DF;
|
||||
vector <SegmentFinder *> segments;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool equalityP (SegmentedFinder* s, T *x, T y)
|
||||
{
|
||||
return (*x) == y;
|
||||
}
|
||||
|
||||
struct vecTriplet
|
||||
{
|
||||
uint32_t start;
|
||||
uint32_t finish;
|
||||
uint32_t alloc_finish;
|
||||
};
|
||||
|
||||
template <typename Needle>
|
||||
bool vectorLength (SegmentedFinder* s, vecTriplet *x, Needle &y)
|
||||
{
|
||||
if(x->start <= x->finish && x->finish <= x->alloc_finish)
|
||||
if((x->finish - x->start) == y)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// find a vector of 32bit pointers, where an object pointed to has a string 'y' as the first member
|
||||
bool vectorString (SegmentedFinder* s, vecTriplet *x, const char *y)
|
||||
{
|
||||
uint32_t object_ptr;
|
||||
// iterate over vector of pointers
|
||||
for(uint32_t idx = x->start; idx < x->finish; idx += sizeof(uint32_t))
|
||||
{
|
||||
// deref ptr idx, get ptr to object
|
||||
if(!s->Read(idx,object_ptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// deref ptr to first object, get ptr to string
|
||||
uint32_t string_ptr;
|
||||
if(!s->Read(object_ptr,string_ptr))
|
||||
return false;
|
||||
// get string location in our local cache
|
||||
char * str = s->Translate<char>(string_ptr);
|
||||
if(!str)
|
||||
return false;
|
||||
if(strcmp(y, str) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// find a vector of 32bit pointers, where the first object pointed to has a string 'y' as the first member
|
||||
bool vectorStringFirst (SegmentedFinder* s, vecTriplet *x, const char *y)
|
||||
{
|
||||
uint32_t object_ptr;
|
||||
uint32_t idx = x->start;
|
||||
// deref ptr idx, get ptr to object
|
||||
if(!s->Read(idx,object_ptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// deref ptr to first object, get ptr to string
|
||||
uint32_t string_ptr;
|
||||
if(!s->Read(object_ptr,string_ptr))
|
||||
return false;
|
||||
// get string location in our local cache
|
||||
char * str = s->Translate<char>(string_ptr);
|
||||
if(!str)
|
||||
return false;
|
||||
if(strcmp(y, str) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// test if the address is between vector.start and vector.finish
|
||||
// not very useful alone, but could be a good step to filter some things
|
||||
bool vectorAddrWithin (SegmentedFinder* s, vecTriplet *x, uint32_t address)
|
||||
{
|
||||
if(address < x->finish && address >= x->start)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// test if an object address is within the vector of pointers
|
||||
//
|
||||
bool vectorOfPtrWithin (SegmentedFinder* s, vecTriplet *x, uint32_t address)
|
||||
{
|
||||
uint32_t object_ptr;
|
||||
for(uint32_t idx = x->start; idx < x->finish; idx += sizeof(uint32_t))
|
||||
{
|
||||
if(!s->Read(idx,object_ptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(object_ptr == address)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool vectorAll (SegmentedFinder* s, vecTriplet *x, int )
|
||||
{
|
||||
if(x->start <= x->finish && x->finish <= x->alloc_finish)
|
||||
{
|
||||
if(s->getSegmentForAddress(x->start) == s->getSegmentForAddress(x->finish)
|
||||
&& s->getSegmentForAddress(x->finish) == s->getSegmentForAddress(x->alloc_finish))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class Bytestreamdata
|
||||
{
|
||||
public:
|
||||
void * object;
|
||||
uint32_t length;
|
||||
uint32_t allocated;
|
||||
uint32_t n_used;
|
||||
};
|
||||
|
||||
class Bytestream
|
||||
{
|
||||
public:
|
||||
Bytestream(void * obj, uint32_t len, bool alloc = false)
|
||||
{
|
||||
d = new Bytestreamdata();
|
||||
d->allocated = alloc;
|
||||
d->object = obj;
|
||||
d->length = len;
|
||||
d->n_used = 1;
|
||||
constant = false;
|
||||
}
|
||||
Bytestream()
|
||||
{
|
||||
d = new Bytestreamdata();
|
||||
d->allocated = false;
|
||||
d->object = 0;
|
||||
d->length = 0;
|
||||
d->n_used = 1;
|
||||
constant = false;
|
||||
}
|
||||
Bytestream( Bytestream & bs)
|
||||
{
|
||||
d =bs.d;
|
||||
d->n_used++;
|
||||
constant = false;
|
||||
}
|
||||
Bytestream( const Bytestream & bs)
|
||||
{
|
||||
d =bs.d;
|
||||
d->n_used++;
|
||||
constant = true;
|
||||
}
|
||||
~Bytestream()
|
||||
{
|
||||
d->n_used --;
|
||||
if(d->allocated && d->object && d->n_used == 0)
|
||||
{
|
||||
free (d->object);
|
||||
free (d);
|
||||
}
|
||||
}
|
||||
bool Allocate(size_t bytes)
|
||||
{
|
||||
if(constant)
|
||||
return false;
|
||||
if(d->allocated)
|
||||
{
|
||||
d->object = realloc(d->object, bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
d->object = malloc( bytes );
|
||||
}
|
||||
|
||||
if(d->object)
|
||||
{
|
||||
d->allocated = bytes;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
d->allocated = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
template < class T >
|
||||
bool insert( T what )
|
||||
{
|
||||
if(constant)
|
||||
return false;
|
||||
if(d->length+sizeof(T) >= d->allocated)
|
||||
Allocate((d->length+sizeof(T)) * 2);
|
||||
(*(T *)( (uint64_t)d->object + d->length)) = what;
|
||||
d->length += sizeof(T);
|
||||
return true;
|
||||
}
|
||||
Bytestreamdata * d;
|
||||
bool constant;
|
||||
};
|
||||
std::ostream& operator<< ( std::ostream& out, Bytestream& bs )
|
||||
{
|
||||
if(bs.d->object)
|
||||
{
|
||||
out << "bytestream " << dec << bs.d->length << "/" << bs.d->allocated << " bytes" << endl;
|
||||
for(size_t i = 0; i < bs.d->length; i++)
|
||||
{
|
||||
out << hex << (int) ((uint8_t *) bs.d->object)[i] << " ";
|
||||
}
|
||||
out << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "empty bytestresm" << endl;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::istream& operator>> ( std::istream& out, Bytestream& bs )
|
||||
{
|
||||
string read;
|
||||
while(!out.eof())
|
||||
{
|
||||
string tmp;
|
||||
out >> tmp;
|
||||
read.append(tmp);
|
||||
}
|
||||
cout << read << endl;
|
||||
bs.d->length = 0;
|
||||
size_t first = read.find_first_of("\"");
|
||||
size_t last = read.find_last_of("\"");
|
||||
size_t start = first + 1;
|
||||
if(first == read.npos)
|
||||
{
|
||||
std::transform(read.begin(), read.end(), read.begin(), (int(*)(int)) tolower);
|
||||
bs.Allocate(read.size()); // overkill. size / 2 should be good, but this is safe
|
||||
int state = 0;
|
||||
char big = 0;
|
||||
char small = 0;
|
||||
string::iterator it = read.begin();
|
||||
// iterate through string, construct a bytestream out of 00-FF bytes
|
||||
while(it != read.end())
|
||||
{
|
||||
char reads = *it;
|
||||
if((reads >='0' && reads <= '9'))
|
||||
{
|
||||
if(state == 0)
|
||||
{
|
||||
big = reads - '0';
|
||||
state = 1;
|
||||
}
|
||||
else if(state == 1)
|
||||
{
|
||||
small = reads - '0';
|
||||
state = 0;
|
||||
bs.insert<char>(big*16 + small);
|
||||
}
|
||||
}
|
||||
if((reads >= 'a' && reads <= 'f'))
|
||||
{
|
||||
if(state == 0)
|
||||
{
|
||||
big = reads - 'a' + 10;
|
||||
state = 1;
|
||||
}
|
||||
else if(state == 1)
|
||||
{
|
||||
small = reads - 'a' + 10;
|
||||
state = 0;
|
||||
bs.insert<char>(big*16 + small);
|
||||
}
|
||||
}
|
||||
it++;
|
||||
}
|
||||
// we end in state= 1. should we add or should we trim... or throw errors?
|
||||
// I decided on adding
|
||||
if (state == 1)
|
||||
{
|
||||
small = 0;
|
||||
bs.insert<char>(big*16 + small);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(last == first)
|
||||
{
|
||||
// only one "
|
||||
last = read.size();
|
||||
}
|
||||
size_t length = last - start;
|
||||
// construct bytestream out of stuff between ""
|
||||
bs.d->length = length;
|
||||
if(length)
|
||||
{
|
||||
// todo: Bytestream should be able to handle this without external code
|
||||
bs.Allocate(length);
|
||||
bs.d->length = length;
|
||||
const char* strstart = read.c_str();
|
||||
memcpy(bs.d->object, strstart + start, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
bs.d->object = 0;
|
||||
}
|
||||
}
|
||||
cout << bs;
|
||||
return out;
|
||||
}
|
||||
|
||||
bool findBytestream (SegmentedFinder* s, void *addr, Bytestream compare )
|
||||
{
|
||||
if(memcmp(addr, compare.d->object, compare.d->length) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool findString (SegmentedFinder* s, uint32_t *addr, const char * compare )
|
||||
{
|
||||
// read string pointer, translate to local scheme
|
||||
char *str = s->Translate<char>(*addr);
|
||||
// verify
|
||||
if(!str)
|
||||
return false;
|
||||
if(strcmp(str, compare) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool findStrBuffer (SegmentedFinder* s, uint32_t *addr, const char * compare )
|
||||
{
|
||||
if(memcmp((const char *)addr, compare, strlen(compare)) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // SEGMENTED_FINDER_H
|
@ -1,30 +1,9 @@
|
||||
Notes by PeridexisErrant, on the needs_porting scripts and plugins:
|
||||
|
||||
I deleted:
|
||||
attachtest.py obsolete
|
||||
digger.cpp less useful than digger2, replaced by autochop
|
||||
digger2.cpp replaced by digfort
|
||||
dfstatus.cpp replaced by dfstatus.lua
|
||||
drawtile.cpp replaced by tiletypes
|
||||
fix-3708.cpp obsolete, bug fixed in vanilla
|
||||
lair.cpp replaced by lair
|
||||
reveal.py replaced by reveal
|
||||
treedump.py replaced by prospect & autochop
|
||||
veinlook.cpp replaced by prospect
|
||||
veinswap.cpp replaced by changevein
|
||||
|
||||
|
||||
To investigate further:
|
||||
creaturemanager.cpp modify skills and labors of creatures, kill creatures, etc; impressive but I suspect most functions implemented elsewhere
|
||||
digpattern.cpp allows multi-Z designations. Obsolete, or is there more here?
|
||||
incrementalsearch.cpp linux-only memory stuff; unqualified to judge
|
||||
SegementedFinder.h more memory stuff
|
||||
|
||||
|
||||
To port:
|
||||
copypaste.cpp high value target - a proof of concept plugin to allow copy-pasting in DF; does both terrain and buildings/constructions
|
||||
dfbauxtite.cpp changes material of mechanisms to bauxtite (ie magma-safe)
|
||||
hellhole.cpp instantly creates a hole to the HFS
|
||||
hotkeynotedump.py outputs a list of hotkeys and names; most useful before keybindings were possible. Trival to port but low value.
|
||||
itemdesignator.cpp mostly replaced by Falconne's enhanced stocks, but could port the interesting 'set fire to things' function
|
||||
position.py outputs very detailed time& place info
|
||||
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,161 +0,0 @@
|
||||
/*
|
||||
DFBauxite - Converts all your mechanisms to bauxite (for use in magma).
|
||||
Author: Alex Legg
|
||||
|
||||
Based on code from and uses DFHack - www.sourceforge.net/projects/dfhack
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <cstdlib>
|
||||
#include <assert.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
|
||||
#include <DFIntegers.h>
|
||||
#include <DFExport.h>
|
||||
#include <DFError.h>
|
||||
#include <DFVector.h>
|
||||
#include <DFMemInfo.h>
|
||||
#include <DFProcess.h>
|
||||
#include <DFTypes.h>
|
||||
using namespace DFHack;
|
||||
|
||||
|
||||
int main ()
|
||||
{
|
||||
DFHack::Process *proc;
|
||||
DFHack::memory_info *meminfo;
|
||||
DFHack::DfVector <uint32_t> *items_vector;
|
||||
DFHack::t_item_df40d item_40d;
|
||||
DFHack::t_matglossPair item_40d_material;
|
||||
vector<DFHack::t_matgloss> stoneMat;
|
||||
uint32_t item_material_offset;
|
||||
uint32_t temp;
|
||||
int32_t type;
|
||||
int items;
|
||||
int found = 0, converted = 0;
|
||||
|
||||
DFHack::ContextManager DF("Memory.xml");
|
||||
try
|
||||
{
|
||||
DF.Attach();
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
cerr << e.what() << endl;
|
||||
#ifndef LINUX_BUILD
|
||||
cin.ignore();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Find out which material is bauxite
|
||||
if(!DF.ReadStoneMatgloss(stoneMat))
|
||||
{
|
||||
cout << "Materials not supported for this version of DF, exiting." << endl;
|
||||
#ifndef LINUX_BUILD
|
||||
cin.ignore();
|
||||
#endif
|
||||
DF.Detach();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
int bauxiteIndex = -1;
|
||||
for (int i = 0; i < stoneMat.size();i++)
|
||||
{
|
||||
if(strcmp(stoneMat[i].id, "BAUXITE") == 0)
|
||||
{
|
||||
bauxiteIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(bauxiteIndex == -1)
|
||||
{
|
||||
cout << "Cannot locate bauxite in the DF raws, exiting" << endl;
|
||||
#ifndef LINUX_BUILD
|
||||
cin.ignore();
|
||||
#endif
|
||||
DF.Detach();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Get some basics needed for full access
|
||||
proc = DF.getProcess();
|
||||
meminfo = proc->getDescriptor();
|
||||
|
||||
// Get the object name/ID mapping
|
||||
//FIXME: work on the 'supported features' system required
|
||||
|
||||
// Check availability of required addresses and offsets (doing custom stuff here)
|
||||
|
||||
items = meminfo->getAddress("items");
|
||||
item_material_offset = meminfo->getOffset("item_materials");
|
||||
if( !items || ! item_material_offset)
|
||||
{
|
||||
cout << "Items not supported for this DF version, exiting" << endl;
|
||||
#ifndef LINUX_BUILD
|
||||
cin.ignore();
|
||||
#endif
|
||||
DF.Detach();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
items_vector = new DFHack::DfVector <uint32_t> (proc, items);
|
||||
for(uint32_t i = 0; i < items_vector->size(); i++)
|
||||
{
|
||||
// get pointer to object
|
||||
temp = items_vector->at (i);
|
||||
// read object
|
||||
proc->read (temp, sizeof (DFHack::t_item_df40d), (uint8_t *) &item_40d);
|
||||
|
||||
// resolve object type
|
||||
type = -1;
|
||||
|
||||
// skip things we can't identify
|
||||
if(!meminfo->resolveObjectToClassID (temp, type))
|
||||
continue;
|
||||
string classname;
|
||||
if(!meminfo->resolveClassIDToClassname (type, classname))
|
||||
continue;
|
||||
|
||||
if(classname == "item_trapparts")
|
||||
{
|
||||
proc->read (temp + item_material_offset, sizeof (DFHack::t_matglossPair), (uint8_t *) &item_40d_material);
|
||||
|
||||
cout << dec << "Mechanism at x:" << item_40d.x << " y:" << item_40d.y << " z:" << item_40d.z << " ID:" << item_40d.ID << endl;
|
||||
|
||||
if (item_40d_material.index != bauxiteIndex)
|
||||
{
|
||||
item_40d_material.index = bauxiteIndex;
|
||||
proc->write (temp + item_material_offset, sizeof (DFHack::t_matglossPair), (uint8_t *) &item_40d_material);
|
||||
converted++;
|
||||
}
|
||||
|
||||
found++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (found == 0)
|
||||
{
|
||||
cout << "No mechanisms to convert" << endl;
|
||||
} else {
|
||||
cout << found << " mechanisms found" << endl;
|
||||
cout << converted << " mechanisms converted" << endl;
|
||||
}
|
||||
|
||||
DF.Resume();
|
||||
DF.Detach();
|
||||
|
||||
delete items_vector;
|
||||
|
||||
#ifndef LINUX_BUILD
|
||||
cout << "Done. Press any key to continue" << endl;
|
||||
cin.ignore();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,259 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <string.h> // for memset
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
#include <map>
|
||||
#include <stdio.h>
|
||||
#include <cstdlib>
|
||||
using namespace std;
|
||||
|
||||
#include <DFHack.h>
|
||||
#include <extra/MapExtras.h>
|
||||
using namespace MapExtras;
|
||||
//#include <argstream.h>
|
||||
|
||||
void usage(int argc, const char * argv[])
|
||||
{
|
||||
cout
|
||||
<< "Usage:" << endl
|
||||
<< argv[0] << " [option 1] [option 2] [...]" << endl
|
||||
<< "-q : Suppress \"Press any key to continue\" at program termination" << endl
|
||||
<< "-u <n> : Dig upwards <n> times (default 5)" << endl
|
||||
<< "-d <n> : Dig downwards <n> times (default 5)" << endl
|
||||
;
|
||||
}
|
||||
|
||||
void digat(MapCache * MCache, DFHack::DFCoord xy)
|
||||
{
|
||||
int16_t tt;
|
||||
tt = MCache->tiletypeAt(xy);
|
||||
if(!DFHack::isWallTerrain(tt))
|
||||
return;
|
||||
|
||||
// found a good tile, dig+unset material
|
||||
DFHack::t_designation des = MCache->designationAt(xy);
|
||||
|
||||
if(MCache->testCoord(xy))
|
||||
{
|
||||
MCache->clearMaterialAt(xy);
|
||||
|
||||
if(des.bits.dig == DFHack::designation_no)
|
||||
des.bits.dig = DFHack::designation_default;
|
||||
MCache->setDesignationAt(xy,des);
|
||||
}
|
||||
}
|
||||
|
||||
int strtoint(const string &str)
|
||||
{
|
||||
stringstream ss(str);
|
||||
int result;
|
||||
return ss >> result ? result : -1;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
} pos;
|
||||
|
||||
int main (int argc, const char* argv[])
|
||||
{
|
||||
// Command line options
|
||||
bool updown = false;
|
||||
bool quiet = true;
|
||||
// let's be more useful when double-clicked on windows
|
||||
#ifndef LINUX_BUILD
|
||||
quiet = false;
|
||||
#endif
|
||||
int dig_up_n = 5;
|
||||
int dig_down_n = 5;
|
||||
|
||||
for(int i = 1; i < argc; i++)
|
||||
{
|
||||
string arg_cur = argv[i];
|
||||
string arg_next = "";
|
||||
int arg_next_int = -99999;
|
||||
/* Check if argv[i+1] is a number >= 0 */
|
||||
if (i < argc-1) {
|
||||
arg_next = argv[i+1];
|
||||
arg_next_int = strtoint(arg_next);
|
||||
if (arg_next != "0" && arg_next_int == 0) {
|
||||
arg_next_int = -99999;
|
||||
}
|
||||
}
|
||||
if (arg_cur == "-x")
|
||||
{
|
||||
updown = true;
|
||||
}
|
||||
else if (arg_cur == "-q")
|
||||
{
|
||||
quiet = true;
|
||||
}
|
||||
else if(arg_cur == "-u" && i < argc-1)
|
||||
{
|
||||
if (arg_next_int < 0 || arg_next_int >= 99999) {
|
||||
usage(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
dig_up_n = arg_next_int;
|
||||
i++;
|
||||
}
|
||||
else if(arg_cur == "-d" && i < argc-1)
|
||||
{
|
||||
if (arg_next_int < 0 || arg_next_int >= 99999) {
|
||||
usage(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
dig_down_n = arg_next_int;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
usage(argc, argv);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
DFHack::ContextManager DFMgr("Memory.xml");
|
||||
DFHack::Context * DF;
|
||||
try
|
||||
{
|
||||
DF = DFMgr.getSingleContext();
|
||||
DF->Attach();
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
cerr << "Error getting context: " << e.what() << endl;
|
||||
if (!quiet)
|
||||
cin.ignore();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t x_max,y_max,z_max;
|
||||
DFHack::Maps * Maps = DF->getMaps();
|
||||
DFHack::Gui * Gui = DF->getGui();
|
||||
|
||||
// init the map
|
||||
if(!Maps->Start())
|
||||
{
|
||||
cerr << "Can't init map. Make sure you have a map loaded in DF." << endl;
|
||||
DF->Detach();
|
||||
if (!quiet)
|
||||
cin.ignore();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t cx, cy, cz;
|
||||
Maps->getSize(x_max,y_max,z_max);
|
||||
uint32_t tx_max = x_max * 16;
|
||||
uint32_t ty_max = y_max * 16;
|
||||
|
||||
Gui->getCursorCoords(cx,cy,cz);
|
||||
if (cx == -30000)
|
||||
{
|
||||
cerr << "Cursor is not active. Point the cursor at the position to dig at." << endl;
|
||||
DF->Detach();
|
||||
if (!quiet)
|
||||
{
|
||||
cin.ignore();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
DFHack::DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz);
|
||||
if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1)
|
||||
{
|
||||
cerr << "I won't dig the borders. That would be cheating!" << endl;
|
||||
DF->Detach();
|
||||
if (!quiet)
|
||||
{
|
||||
cin.ignore();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
MapCache * MCache = new MapCache(Maps);
|
||||
|
||||
DFHack::t_designation des = MCache->designationAt(xy);
|
||||
int16_t tt = MCache->tiletypeAt(xy);
|
||||
int16_t veinmat = MCache->veinMaterialAt(xy);
|
||||
|
||||
/*
|
||||
if( veinmat == -1 )
|
||||
{
|
||||
cerr << "This tile is non-vein. Bye :)" << endl;
|
||||
delete MCache;
|
||||
DF->Detach();
|
||||
if (!quiet) {
|
||||
cin.ignore();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
printf("Digging at (%d/%d/%d), tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole);
|
||||
|
||||
// 1 < xy.x < tx_max - 1
|
||||
// 1 < xy.y < ty_max - 1
|
||||
// xy.z
|
||||
|
||||
// X____
|
||||
// X_XXX
|
||||
// XXXXX
|
||||
// __XXX
|
||||
// __XXX
|
||||
// _____
|
||||
pos map[] =
|
||||
{
|
||||
{ 0,0 }
|
||||
, { 0,1 }
|
||||
, { 0,2 } , { 2,2 }, { 3,2 }, { 4,2 }
|
||||
, { 0,3 }, { 1,3 }, { 2,3 }, { 3,3 }, { 4,3 }
|
||||
, { 2,4 }, { 3,4 }, { 4,4 }
|
||||
// this is mirrored, goes left instead of right
|
||||
, {-2,2 }, {-3,2 }, {-4,2 }
|
||||
, {-1,3 }, {-2,3 }, {-3,3 }, {-4,3 }
|
||||
, {-2,4 }, {-3,4 }, {-4,4 }
|
||||
};
|
||||
|
||||
DFHack::DFCoord npos = xy;
|
||||
|
||||
if (dig_up_n > 0)
|
||||
{
|
||||
for (int j = 0; j < dig_up_n; j++)
|
||||
{
|
||||
for (int i = 0; i < sizeof(map)/sizeof(map[0]); i++)
|
||||
{
|
||||
npos=xy;
|
||||
npos.x += map[i].x;
|
||||
npos.y -= 4*j + map[i].y;
|
||||
printf("Digging at (%d/%d/%d)\n", npos.x, npos.y, npos.z);
|
||||
digat(MCache, npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dig_down_n > 0)
|
||||
{
|
||||
for (int j = 0; j < dig_down_n; j++)
|
||||
{
|
||||
for (int i = 0; i < sizeof(map)/sizeof(map[0]); i++)
|
||||
{
|
||||
npos=xy;
|
||||
npos.x += map[i].x;
|
||||
npos.y += 4*j + map[i].y;
|
||||
printf("Digging at (%d/%d/%d)\n", npos.x, npos.y, npos.z);
|
||||
digat(MCache, npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MCache->WriteAll();
|
||||
delete MCache;
|
||||
DF->Detach();
|
||||
if (!quiet) {
|
||||
cout << "Done. Press any key to continue" << endl;
|
||||
cin.ignore();
|
||||
}
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,40 @@
|
||||
-- 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()
|
||||
]]--
|
@ -1,20 +0,0 @@
|
||||
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()
|
File diff suppressed because it is too large
Load Diff
@ -1,148 +0,0 @@
|
||||
// Item designator
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
|
||||
#include <DFHack.h>
|
||||
#include <DFVector.h>
|
||||
using namespace DFHack;
|
||||
|
||||
int main ()
|
||||
{
|
||||
|
||||
DFHack::ContextManager CM ("Memory.xml");
|
||||
DFHack::Context * DF;
|
||||
DFHack::VersionInfo *mem;
|
||||
DFHack::Gui * Gui;
|
||||
DFHack::Materials * Mats;
|
||||
DFHack::Items * Items;
|
||||
cout << "This utility lets you mass-designate items by type and material." << endl
|
||||
<< "Like set on fire all MICROCLINE item_stone..." << endl
|
||||
<< "Some unusual combinations might be untested and cause the program to crash..."<< endl
|
||||
<< "so, watch your step and backup your fort" << endl;
|
||||
try
|
||||
{
|
||||
DF = CM.getSingleContext();
|
||||
DF->Attach();
|
||||
mem = DF->getMemoryInfo();
|
||||
Gui = DF->getGui();
|
||||
Mats = DF->getMaterials();
|
||||
Mats->ReadAllMaterials();
|
||||
Items = DF->getItems();
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
cerr << e.what() << endl;
|
||||
#ifndef LINUX_BUILD
|
||||
cin.ignore();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
DFHack::Process * p = DF->getProcess();
|
||||
DFHack::OffsetGroup* itemGroup = mem->getGroup("Items");
|
||||
unsigned vector_addr = itemGroup->getAddress("items_vector");
|
||||
DFHack::DfVector <uint32_t> p_items (p, vector_addr);
|
||||
uint32_t numItems = p_items.size();
|
||||
|
||||
map< string, map<string,vector< dfh_item > > > itemmap;
|
||||
map< string, map< string, vector< dfh_item > > >::iterator it1;
|
||||
int failedItems = 0;
|
||||
map <string, int > bad_mat_items;
|
||||
for(uint32_t i=0; i< numItems; i++)
|
||||
{
|
||||
DFHack::dfh_item temp;
|
||||
Items->readItem(p_items[i],temp);
|
||||
string typestr = Items->getItemClass(temp);
|
||||
string material = Mats->getDescription(temp.matdesc);
|
||||
itemmap[typestr][material].push_back(temp);
|
||||
}
|
||||
|
||||
int i =0;
|
||||
for( it1 = itemmap.begin(); it1!=itemmap.end();it1++)
|
||||
{
|
||||
cout << i << ": " << it1->first << "\n";
|
||||
i++;
|
||||
}
|
||||
if(i == 0)
|
||||
{
|
||||
cout << "No items found" << endl;
|
||||
DF->Detach();
|
||||
return 0;
|
||||
}
|
||||
cout << endl << "Select an item type from the list:";
|
||||
int number;
|
||||
string in;
|
||||
stringstream ss;
|
||||
getline(cin, in);
|
||||
ss.str(in);
|
||||
ss >> number;
|
||||
int j = 0;
|
||||
it1 = itemmap.begin();
|
||||
while(j < number && it1!=itemmap.end())
|
||||
{
|
||||
it1++;
|
||||
j++;
|
||||
}
|
||||
cout << it1->first << "\n";
|
||||
map<string,vector<dfh_item> >::iterator it2;
|
||||
i=0;
|
||||
for(it2 = it1->second.begin();it2!=it1->second.end();it2++){
|
||||
cout << i << ":\t" << it2->first << " [" << it2->second.size() << "]" << endl;
|
||||
i++;
|
||||
}
|
||||
cout << endl << "Select a material type: ";
|
||||
int number2;
|
||||
ss.clear();
|
||||
getline(cin, in);
|
||||
ss.str(in);
|
||||
ss >> number2;
|
||||
|
||||
decideAgain:
|
||||
cout << "Select a designation - (d)ump, (f)orbid, (m)melt, set on fi(r)e :" << flush;
|
||||
string designationType;
|
||||
getline(cin,designationType);
|
||||
DFHack::t_itemflags changeFlag = {0};
|
||||
if(designationType == "d" || designationType == "dump")
|
||||
{
|
||||
changeFlag.dump = 1;
|
||||
}
|
||||
else if(designationType == "f" || designationType == "forbid")
|
||||
{
|
||||
changeFlag.forbid = 1;
|
||||
}
|
||||
else if(designationType == "m" || designationType == "melt")
|
||||
{
|
||||
changeFlag.melt = 1;
|
||||
}
|
||||
else if(designationType == "r" || designationType == "fire")
|
||||
{
|
||||
changeFlag.on_fire = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto decideAgain;
|
||||
}
|
||||
j=0;
|
||||
it2= it1->second.begin();
|
||||
while(j < number2 && it2!=it1->second.end())
|
||||
{
|
||||
it2++;
|
||||
j++;
|
||||
}
|
||||
for(uint32_t k = 0;k< it2->second.size();k++)
|
||||
{
|
||||
DFHack::dfh_item & t = it2->second[k];
|
||||
t.base.flags.whole |= changeFlag.whole;
|
||||
Items->writeItem(t);
|
||||
}
|
||||
DF->Detach();
|
||||
#ifndef LINUX_BUILD
|
||||
cout << "Done. Press any key to continue" << endl;
|
||||
cin.ignore();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
import sys
|
||||
from pydfhack import ContextManager
|
||||
|
||||
df_cm = ContextManager("Memory.xml")
|
||||
df = df_cm.get_single_context()
|
||||
|
||||
if not df.attach():
|
||||
print "Unable to attach!"
|
||||
print "Press any key to continue"
|
||||
|
||||
raw_input()
|
||||
sys.exit(1)
|
||||
|
||||
gui = df.gui
|
||||
|
||||
if gui is not None:
|
||||
maps = df.maps
|
||||
world = df.world
|
||||
|
||||
have_maps = maps.start()
|
||||
world.start()
|
||||
|
||||
gm = world.read_game_mode()
|
||||
|
||||
if gm is not None:
|
||||
print gm
|
||||
|
||||
date_tuple = (world.read_current_year(), world.read_current_month(), world.read_current_day(), world.read_current_tick())
|
||||
|
||||
print "Year: %d Month: %d Day: %d Tick: %d" % date_tuple
|
||||
|
||||
v_coords = gui.get_view_coords()
|
||||
c_coords = gui.get_cursor_coords()
|
||||
w_coords = (-1, -1, -1)
|
||||
world_pos_string = ""
|
||||
|
||||
if have_maps is True:
|
||||
w_coords = maps.getPosition()
|
||||
|
||||
x = (v_coords[0] + w_coords[0]) * 48
|
||||
y = (v_coords[1] + w_coords[1]) * 48
|
||||
z = (v_coords[2] + w_coords[2])
|
||||
|
||||
world_pos_string = " world: %d/%d/%d" % (x, y, z)
|
||||
|
||||
print "Map world offset: %d/%d/%d embark squares" % w_coords
|
||||
|
||||
if v_coords != (-1, -1, -1):
|
||||
print "view coords: %d/%d/%d" % v_coords
|
||||
|
||||
if have_maps is True:
|
||||
print world_pos_string
|
||||
|
||||
if c_coords != (-1, -1, -1):
|
||||
print "cursor coords: %d/%d/%d" % c_coords
|
||||
|
||||
if have_maps is True:
|
||||
print world_pos_string
|
||||
|
||||
window_size = gui.get_window_size()
|
||||
|
||||
if window_size != (-1, -1):
|
||||
print "window size : %d %d" % window_size
|
||||
else:
|
||||
print "cursor and window parameters are unsupported on your version of DF"
|
||||
|
||||
if not df.detach():
|
||||
print "Unable to detach!"
|
||||
|
||||
print "Done. Press any key to continue"
|
||||
raw_input()
|
@ -0,0 +1,88 @@
|
||||
-- Creates a pit under the target leading straight to the Underworld. Type '?' for help.
|
||||
-- Based on script by IndigoFenix, @ https://gist.github.com/IndigoFenix/8776696
|
||||
|
||||
args={...}
|
||||
|
||||
if args[1] == '?' then
|
||||
print("Example usage: 'hfs-pit 2 1 1'")
|
||||
print("First parameter is size of the pit in all directions.")
|
||||
print("Second parameter is 1 to wall off the sides of the pit on all layers except the underworld, or anything else to leave them open.")
|
||||
print("Third parameter is 1 to add stairs. Stairs are buggy; they will not reveal the bottom until you dig somewhere, but underworld creatures will path in.")
|
||||
print("If no arguments are given, the default is 'hfs-pit 1 0 0', ie single-tile wide with no walls or stairs.")
|
||||
return
|
||||
end
|
||||
|
||||
pos = copyall(df.global.cursor)
|
||||
size = tonumber(args[1])
|
||||
if size == nil or size < 1 then size = 1 end
|
||||
|
||||
wallOff = tonumber(args[2])
|
||||
stairs = tonumber(args[3])
|
||||
|
||||
--Get the layer of the underworld
|
||||
for index,value in ipairs(df.global.world.cur_savegame.map_features) do
|
||||
local featureType=value:getType()
|
||||
if featureType==9 then --Underworld
|
||||
underworldLayer = value.layer
|
||||
end
|
||||
end
|
||||
|
||||
if pos.x==-30000 then
|
||||
qerror("Select a location by placing the cursor")
|
||||
end
|
||||
local x = 0
|
||||
local y = 0
|
||||
for x=pos.x-size,pos.x+size,1 do
|
||||
for y=pos.y-size,pos.y+size,1 do
|
||||
z=1
|
||||
local hitAir = false
|
||||
local hitCeiling = false
|
||||
while z <= pos.z do
|
||||
local block = dfhack.maps.ensureTileBlock(x,y,z)
|
||||
if block then
|
||||
if block.tiletype[x%16][y%16] ~= 335 then
|
||||
hitAir = true
|
||||
end
|
||||
if hitAir == true then
|
||||
if not hitCeiling then
|
||||
if block.global_feature ~= underworldLayer or z > 10 then hitCeiling = true end
|
||||
if stairs == 1 and x == pos.x and y == pos.y then
|
||||
if block.tiletype[x%16][y%16] == 32 then
|
||||
if z == pos.z then
|
||||
block.tiletype[x%16][y%16] = 56
|
||||
else
|
||||
block.tiletype[x%16][y%16] = 55
|
||||
end
|
||||
else
|
||||
block.tiletype[x%16][y%16] = 57
|
||||
end
|
||||
end
|
||||
end
|
||||
if hitCeiling == true then
|
||||
if block.designation[x%16][y%16].flow_size > 0 or wallOff == 1 then needsWall = true else needsWall = false end
|
||||
if (x == pos.x-size or x == pos.x+size or y == pos.y-size or y == pos.y+size) and z==pos.z then
|
||||
--Do nothing, this is the lip of the hole
|
||||
elseif x == pos.x-size and y == pos.y-size then if needsWall == true then block.tiletype[x%16][y%16]=320 end
|
||||
elseif x == pos.x-size and y == pos.y+size then if needsWall == true then block.tiletype[x%16][y%16]=321 end
|
||||
elseif x == pos.x+size and y == pos.y+size then if needsWall == true then block.tiletype[x%16][y%16]=322 end
|
||||
elseif x == pos.x+size and y == pos.y-size then if needsWall == true then block.tiletype[x%16][y%16]=323 end
|
||||
elseif x == pos.x-size or x == pos.x+size then if needsWall == true then block.tiletype[x%16][y%16]=324 end
|
||||
elseif y == pos.y-size or y == pos.y+size then if needsWall == true then block.tiletype[x%16][y%16]=325 end
|
||||
elseif stairs == 1 and x == pos.x and y == pos.y then
|
||||
if z == pos.z then block.tiletype[x%16][y%16]=56
|
||||
else block.tiletype[x%16][y%16]=55 end
|
||||
else block.tiletype[x%16][y%16]=32
|
||||
end
|
||||
block.designation[x%16][y%16].hidden = false
|
||||
--block.designation[x%16][y%16].liquid_type = true -- if true, magma. if false, water.
|
||||
block.designation[x%16][y%16].flow_size = 0
|
||||
dfhack.maps.enableBlockUpdates(block)
|
||||
block.designation[x%16][y%16].flow_forbid = false
|
||||
end
|
||||
end
|
||||
block.designation[x%16][y%16].hidden = false
|
||||
end
|
||||
z = z+1
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,43 @@
|
||||
--prints current time and position
|
||||
|
||||
local months = {
|
||||
'Granite, in early Spring.',
|
||||
'Slate, in mid Spring.',
|
||||
'Felsite, in late Spring.',
|
||||
'Hematite, in early Summer.',
|
||||
'Malachite, in mid Summer.',
|
||||
'Galena, in late Summer.',
|
||||
'Limestone, in early Autumn.',
|
||||
'Sandstone, in mid Autumn.',
|
||||
'Timber, in late Autumn.',
|
||||
'Moonstone, in early Winter.',
|
||||
'Opal, in mid Winter.',
|
||||
'Obsidian, in late Winter.',
|
||||
}
|
||||
|
||||
--Fortress mode counts 1200 ticks per day and 403200 per year
|
||||
--Adventurer mode counts 86400 ticks to a day and 29030400 ticks per year
|
||||
--Twelve months per year, 28 days to every month, 336 days per year
|
||||
|
||||
local julian_day = math.floor(df.global.cur_year_tick / 1200) + 1
|
||||
local month = math.floor(julian_day / 28) + 1 --days and months are 1-indexed
|
||||
local day = julian_day % 28
|
||||
|
||||
local time_of_day = math.floor(df.global.cur_year_tick_advmode / 336)
|
||||
local second = time_of_day % 60
|
||||
local minute = math.floor(time_of_day / 60) % 60
|
||||
local hour = math.floor(time_of_day / 3600) % 24
|
||||
|
||||
print('Time:')
|
||||
print(' The time is '..string.format('%02d:%02d:%02d', hour, minute, second))
|
||||
print(' The date is '..string.format('%05d-%02d-%02d', df.global.cur_year, month, day))
|
||||
print(' It is the month of '..months[month])
|
||||
--TODO: print(' It is the Age of '..age_name)
|
||||
|
||||
print('Place:')
|
||||
print(' The z-level is z='..df.global.window_z)
|
||||
print(' The cursor is at x='..df.global.cursor.x..', y='..df.global.cursor.y)
|
||||
print(' The window is '..df.global.gps.dimx..' tiles wide and '..df.global.gps.dimy..' tiles high')
|
||||
if df.global.gps.mouse_x == -1 then print(' The mouse is not in the DF window') else
|
||||
print(' The mouse is at x='..df.global.gps.mouse_x..', y='..df.global.gps.mouse_y..' within the window') end
|
||||
--TODO: print(' The fortress is at '..x, y..' on the world map ('..worldsize..' square)')
|
Loading…
Reference in New Issue