Petr Mrázek 2011-08-06 21:00:54 +02:00
commit fedb6150f4
51 changed files with 3857 additions and 53 deletions

@ -387,6 +387,7 @@ Core::Core()
hotkey_set = false; hotkey_set = false;
HotkeyMutex = 0; HotkeyMutex = 0;
HotkeyCond = 0; HotkeyCond = 0;
misc_data_mutex=0;
}; };
bool Core::Init() bool Core::Init()
@ -441,6 +442,7 @@ bool Core::Init()
HotkeyMutex = new mutex(); HotkeyMutex = new mutex();
HotkeyCond = new condition_variable(); HotkeyCond = new condition_variable();
thread * HK = new thread(fHKthread, (void *) temp); thread * HK = new thread(fHKthread, (void *) temp);
misc_data_mutex=new mutex();
started = true; started = true;
return true; return true;
} }
@ -473,6 +475,30 @@ std::string Core::getHotkeyCmd( void )
return returner; return returner;
} }
void Core::RegisterData(void *p,std::string key)
{
misc_data_mutex->lock();
misc_data_map[key]=p;
misc_data_mutex->unlock();
}
void *Core::GetData(std::string key)
{
misc_data_mutex->lock();
std::map<std::string,void*>::iterator it=misc_data_map.find(key);
if (it!=misc_data_map.end())
{
void *p=it->second;
misc_data_mutex->unlock();
return p;
}
else
{
misc_data_mutex->unlock();
return 0;// or throw an error.
}
}
void Core::Suspend() void Core::Suspend()
{ {

@ -126,6 +126,11 @@ namespace DFHack
/// removes the hotkey command and gives it to the caller thread /// removes the hotkey command and gives it to the caller thread
std::string getHotkeyCmd( void ); std::string getHotkeyCmd( void );
/// adds a named pointer (for later or between plugins)
void RegisterData(void *p,std::string key);
/// returns a named pointer.
void *GetData(std::string key);
DFHack::Process * p; DFHack::Process * p;
DFHack::VersionInfo * vinfo; DFHack::VersionInfo * vinfo;
DFHack::Console con; DFHack::Console con;
@ -174,5 +179,8 @@ namespace DFHack
tthread::condition_variable * HotkeyCond; tthread::condition_variable * HotkeyCond;
// Very important! // Very important!
bool started; bool started;
tthread::mutex * misc_data_mutex;
std::map<std::string,void*> misc_data_map;
}; };
} }

@ -14,6 +14,8 @@
#include "luamain.h" #include "luamain.h"
#include "lua_Console.h" #include "lua_Console.h"
#include "lua_Process.h" #include "lua_Process.h"
#include "lua_Hexsearch.h"
#include "lua_Misc.h"
#include "functioncall.h" #include "functioncall.h"
using std::vector; using std::vector;
@ -37,6 +39,8 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand>
//maybe remake it to run automaticaly //maybe remake it to run automaticaly
lua::RegisterConsole(lua::glua::Get(),&c->con); lua::RegisterConsole(lua::glua::Get(),&c->con);
lua::RegisterProcess(lua::glua::Get(),c->p); lua::RegisterProcess(lua::glua::Get(),c->p);
lua::RegisterHexsearch(lua::glua::Get());
lua::RegisterMisc(lua::glua::Get());
commands.push_back(PluginCommand("dfusion","Init dfusion system.",dfusion)); commands.push_back(PluginCommand("dfusion","Init dfusion system.",dfusion));
commands.push_back(PluginCommand("lua", "Run interactive interpreter.\ commands.push_back(PluginCommand("lua", "Run interactive interpreter.\
\n Options: <filename> = run <filename> instead",lua_run)); \n Options: <filename> = run <filename> instead",lua_run));
@ -71,6 +75,7 @@ DFhackCExport command_result plugin_onupdate ( Core * c )
catch(lua::exception &e) catch(lua::exception &e)
{ {
c->con.printerr("Error OnTick:%s\n",e.what()); c->con.printerr("Error OnTick:%s\n",e.what());
c->con.printerr("%s",lua::DebugDump(lua::glua::Get()));
c->con.msleep(1000); c->con.msleep(1000);
} }
} }
@ -97,6 +102,7 @@ void InterpreterLoop(Core* c)
catch(lua::exception &e) catch(lua::exception &e)
{ {
con.printerr("Error:%s\n",e.what()); con.printerr("Error:%s\n",e.what());
c->con.printerr("%s",lua::DebugDump(lua::glua::Get()));
s.settop(0); s.settop(0);
} }
con.lineedit(">>",curline); con.lineedit(">>",curline);
@ -117,6 +123,7 @@ DFhackCExport command_result lua_run (Core * c, vector <string> & parameters)
catch(lua::exception &e) catch(lua::exception &e)
{ {
con.printerr("Error:%s\n",e.what()); con.printerr("Error:%s\n",e.what());
c->con.printerr("%s",lua::DebugDump(lua::glua::Get()));
} }
} }
else else
@ -141,6 +148,7 @@ DFhackCExport command_result dfusion (Core * c, vector <string> & parameters)
catch(lua::exception &e) catch(lua::exception &e)
{ {
con.printerr("Error:%s\n",e.what()); con.printerr("Error:%s\n",e.what());
c->con.printerr("%s",lua::DebugDump(lua::glua::Get()));
} }
s.settop(0);// clean up s.settop(0);// clean up
mymutex->unlock(); mymutex->unlock();

@ -0,0 +1,126 @@
#ifndef OUTFILE_H
#define OUTFILE_H
#include <string>
#include <fstream>
#include <iostream>
#include <map>
#include <vector>
namespace OutFile
{
struct Header
{
unsigned short machinetype;
unsigned short sectioncount;
unsigned long time;
unsigned long symbolptr;
unsigned long symbolcount;
unsigned short opthead;
unsigned short flags;
void PrintData()
{
std::cout<<"Symbol start:"<<symbolptr<<"\n";
}
};
struct Section
{
char name[8];
unsigned long Vsize;
unsigned long Vstart;
unsigned long size;
unsigned long start;
unsigned long ptrRel;
unsigned long ptrLine;
unsigned short numRel;
unsigned short numLine;
unsigned long flags;
void PrintData()
{
std::cout<<name<<" size:"<<size<<" start:"<<start<<"\n";
}
};
struct Symbol
{
std::string name;
unsigned long pos;
unsigned short sectnumb;
unsigned short type;
unsigned char storageclass;
unsigned char auxsymbs;
//char unk2[6];
void Read(std::iostream &s,unsigned long strptr)
{
union
{
char buf[8];
struct
{
unsigned long zeros;
unsigned long strptr;
};
}data;
s.read((char*)&data,8);
s.read((char*)&pos,4);
s.read((char*)&sectnumb,2);
s.read((char*)&type,2);
s.read((char*)&storageclass,1);
s.read((char*)&auxsymbs,1);
if(data.zeros!=0)
{
name=data.buf;
name=name.substr(0,8);
}
else
{
//name="";
//std::cout<<"Name in symbol table\n";
char buf[256];
s.seekg(strptr+data.strptr);
s.get(buf,256,'\0');
name=buf;
}
//s.seekp(6,std::ios::cur);
}
void PrintData()
{
std::cout<<name<<" section:"<<sectnumb<<" pos:"<<pos<<"\n";
}
};
struct Relocation
{
unsigned long ptr;
unsigned long tblIndex;
unsigned short type;
};
typedef std::vector<Symbol> vSymbol;
class File
{
public:
File(std::string path);
virtual ~File();
void GetText(char *ptr);
size_t GetTextSize();
void LoadSymbols();
vSymbol GetSymbols(){LoadSymbols();return symbols;};
void PrintSymbols();
void PrintRelocations();
protected:
private:
typedef std::map<std::string,Section> secMap;
secMap sections;
vSymbol symbols;
Section &GetSection(std::string name);
std::fstream mystream;
Header myhead;
// Section Text;
//Section Data;
// Section Bss;
};
}
#endif // OUTFILE_H

@ -0,0 +1,37 @@
#ifndef HEXSEARCH_H
#define HEXSEARCH_H
#include <vector>
#include "dfhack/Core.h" //for some reason process.h needs core
#include "dfhack/Process.h"
//(not yet)implemented using Boyer-Moore algorithm
class Hexsearch
{
public:
typedef std::vector<int> SearchArgType;
enum SearchConst //TODO add more
{
ANYBYTE=0x101,DWORD_,ANYDWORD,ADDRESS
};
Hexsearch(const SearchArgType &args,uint64_t startpos,uint64_t endpos);
~Hexsearch();
void Reset(){pos_=startpos_;};
void SetStart(uint64_t pos){pos_=pos;};
uint64_t FindNext();
std::vector<uint64_t> FindAll();
private:
bool Compare(int a,int b);
void ReparseArgs();
SearchArgType args_;
uint64_t pos_,startpos_,endpos_;
std::vector<int> BadCharShifts,GoodSuffixShift;
void PrepareGoodSuffixTable();
void PrepareBadCharShift();
};
#endif

@ -0,0 +1,33 @@
#ifndef LUA_HEXSEARCH_H
#define LUA_HEXSEARCH_H
#include "hexsearch.h"
#include "luamain.h"
namespace lua
{
class Hexsearch
{
int tblid;
::Hexsearch *p;
public:
Hexsearch(lua_State *L,int id);
~Hexsearch();
int GetTableId(){return tblid;};
int find(lua_State *L);
int findall(lua_State *L);
int reset(lua_State *L);
DEF_LUNE(Hexsearch);
};
void RegisterHexsearch(lua::state &st);
}
#endif

@ -0,0 +1,45 @@
#ifndef LUA_MISC_H
#define LUA_MISC_H
#include <map>
#include <dfhack/Core.h>
#include <dfhack/Process.h>
#include "luamain.h"
#include "OutFile.h"
namespace lua
{
typedef std::map<std::string,void *> mapPlugs;
class PlugManager
{
public:
mapPlugs GetList(){return plugs;};
uint32_t AddNewPlug(std::string name,uint32_t size,uint32_t loc=0);
uint32_t FindPlugin(std::string name);
static PlugManager &GetInst()
{
void *p;
p=DFHack::Core::getInstance().GetData("dfusion_manager");
if(p==0)
{
p=new PlugManager;
DFHack::Core::getInstance().RegisterData(p,"dfusion_manager");
}
return *static_cast<PlugManager*>(p);
};
protected:
private:
PlugManager(){};
mapPlugs plugs;
};
void RegisterMisc(lua::state &st);
}
#endif

@ -11,7 +11,7 @@ extern "C" {
#include "lualib.h" #include "lualib.h"
} }
//#include "lune.h" #include "lune.h"
#include "luaxx.hpp" #include "luaxx.hpp"
namespace lua namespace lua

@ -0,0 +1,361 @@
#ifndef LUNE_H
#define LUNE_H
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
#include "luaxx.hpp"
#include <string>
namespace lua
{
class object
{
state &myst;
int myref;
public:
object(state &myst):myst(myst)
{
myref=luaL_ref(myst,LUA_REGISTRYINDEX);
}
~object()
{
luaL_unref(myst,LUA_REGISTRYINDEX,myref);
}
void Get()
{
lua_rawgeti(myst,LUA_REGISTRYINDEX,myref);
}
state &GetState(){return myst;};
};
class local_object
{
state myst;
int myref;
static object *mytbl;
public:
local_object(lua_State *L)
{
myst=state(L);
//LOG<<"Creating local object...\n";
//StackDump(L);
if(!mytbl)
{
//LOG<<" Metable...\n";
myst.newtable(); //2
if(myst.newmetatable("WEAKTABLE"))//3
{
//StackDump(L);
myst.push("kv"); //4
myst.setfield("__mode");//3
//LOG<<" Setting Metable...\n";
//StackDump(L);
}
//LOG<<" Attaching to holder...\n";
//myst.setfield("__metatable");//2
lua_setmetatable(myst,-1);
mytbl=new object(myst);
//StackDump(L);
//LOG<<" Done Metatable...\n";
}
//StackDump(L);
mytbl->Get();
//LOG<<" Got my table...\n";
//StackDump(L);
myst.insert(-2);
myref=luaL_ref(myst,-2);
//LOG<<"Before pop:";
//StackDump(L);
myst.pop(1);
GetTable();
//LOG<<"========Done...\n"<<"Ref="<<myref<<"\n";
//mytbl->Get();
//StackDump(L);
//LOG<<"===========================\n";
}
~local_object()
{
//LOG<<"Deleting local object...\n";
ReleaseTable();
}
void ReleaseTable()
{
mytbl->Get();
int pos=myst.gettop();
luaL_unref(myst,pos,myref);
myst.remove(pos);
}
state GetState(){return myst;}
void GetTable()
{
//LOG<<"Getting ref="<<myref<<"\n";
//StackDump(myst);
//LOG<<"Tbl preget\n";
mytbl->Get();
int pos=myst.gettop();
//StackDump(myst);
//LOG<<"Tbl get\n";
//int pos=myst.gettop();
lua_rawgeti(myst,pos,myref);
//StackDump(myst);
//LOG<<"Done\n";
myst.remove(pos);
}
protected:
};
};
template <typename T,bool GC=true>
class Lune
{
public:
typedef struct
{
T *pT;
int tableref;
} userdataType;
typedef int (T::*mfp)(lua_State *L);
typedef struct
{
const char *name;
mfp mfunc;
} RegType;
static void Register(lua_State *L)
{
lua_newtable(L);
int methods = lua_gettop(L);
luaL_newmetatable(L, T::className);
int metatable = lua_gettop(L);
// store method table in globals so that
// scripts can add functions written in Lua.
lua_pushstring(L, T::className);
lua_pushvalue(L, methods);
lua_settable(L, LUA_GLOBALSINDEX);
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, methods);
lua_settable(L, metatable); // hide metatable from Lua getmetatable()
lua_pushliteral(L, "__index");
lua_pushcfunction(L, index_T);
lua_settable(L, metatable);
//lua_pushliteral(L, "__name");
//lua_pushstring(L, T::className);
//lua_settable(L, metatable);
lua_pushliteral(L, "__newindex");
lua_pushcfunction(L, newindex_T);
lua_settable(L, metatable);
lua_pushliteral(L, "__instances");
lua_newtable(L);
lua_settable(L, metatable);
if(GC)
{
lua_pushliteral(L, "__gc");
lua_pushcfunction(L, gc_T);
lua_settable(L, metatable);
}
lua_newtable(L); // metatable for method table
int mt = lua_gettop(L);
lua_pushliteral(L, "__call");
lua_pushcfunction(L, new_T);
lua_pushliteral(L, "new");
lua_pushvalue(L, -2); // dup new_T function
lua_settable(L, methods); // add new_T to method table
lua_settable(L, mt); // mt.__call = new_T
lua_setmetatable(L, methods);
//LOG<<"lune: registered class \""<<T::className<<"\"\n";
// fill method table with methods from class T
for (RegType *l = T::methods; l->name; l++)
{
/* edited by Snaily: shouldn't it be const RegType *l ... ? */
lua_pushstring(L, l->name);
lua_pushlightuserdata(L, (void*)l);
lua_pushcclosure(L, thunk, 1);
lua_settable(L, methods);
//LOG<<"lune: method \""<<l->name<<"\"\n";
}
lua_pop(L, 2); // drop metatable and method table
};
static void GetTable(lua_State *L,T *p)
{
GetTableEx(L,p->GetTableId());
}
static void GetTableEx(lua_State *L,int id)
{
lua::state s(L);
s.getmetatable(T::className);
s.getfield("__instances");
int ins=s.gettop();
lua_rawgeti(L, ins, id);
s.insert(-3);
s.pop(2);
}
static T *check(lua_State *L, int narg)
{
userdataType *ud =
static_cast<userdataType*>(luaL_checkudata(L, narg, T::className)); //TODO FIX THIs..
//(lua_touserdata(L, narg));//
if(!ud) luaL_typerror(L, narg, T::className);
return ud->pT; // pointer to T object
}
protected:
private:
static int RegTable(lua_State *L)
{
// LOG<<"Regging....\n";
//lua::StackDump(L);
lua::state s(L);
int ssize=s.gettop();
//s.getglobal(T::className);
s.getmetatable(T::className);
s.getfield("__instances");
int ins=s.gettop();
s.newtable();
int id=luaL_ref(L,ins);
//LOG<<"After reg:\n";
//lua::StackDump(L);
s.settop(ssize);
return id;
}
static void UnregTable(lua_State *L,int id)
{
lua::state s(L);
s.getmetatable(T::className);
s.getfield("__instances");
int ins=s.gettop();
//LOG<<"Unreg table id:"<<id<<"stack dump:\n";
//lua::StackDump(L);
luaL_unref(L,ins,id);
}
static int index_T(lua_State *L) // calls with (table, key), return value
{
lua::state st(L);
string key=st.as<string>(-1);
T *p=check(L,1);
GetTable(L,p);
st.insert(-2);
//LOG<<"Index:\n";
//lua::StackDump(L);
lua_rawget(L,-2); //try getting from normal table
if(st.is<lua::nil>()) //failed
{
st.pop(2);
st.getglobal(T::className); //try class tables then
st.push(key);
st.gettable();
}
return 1;
}
static int newindex_T(lua_State *L)
{
//LOG<<"New index....\n";
//lua::StackDump(L);
lua::state st(L);
T *p=check(L,1);
GetTable(L,p);
//st.insert(-3);
//LOG<<"Before set:\n";
st.insert(-3);
//lua::StackDump(L);
lua_rawset(L,-3);
return 0;
}
static int thunk(lua_State *L)
{
//LOG<<"Size of stack:"<<lua_gettop(L)<<"\n";
//lua::StackDump(L);
if(lua_gettop(L)<1)
luaL_error(L,"Member function called without 'self'");
//LOG<<"Size of stack after:"<<lua_gettop(L)<<"\n";
// stack has userdata, followed by method args
T *obj = check(L, 1); // get 'self', or if you prefer, 'this'
//T *obj=static_cast<userdataType*>(lua_touserdata(L,1))->pT;
lua_remove(L, 1); // remove self so member function args start at index 1
// get member function from upvalue
RegType *l = static_cast<RegType*>(lua_touserdata(L, lua_upvalueindex(1)));
return (obj->*(l->mfunc))(L); // call member function
}
static int gc_T(lua_State *L)
{
//lua_getfield(L,,"__ud");
//LOG<<"Garbage collecting.\n";
//lua::StackDump(L);
userdataType *ud = static_cast<userdataType*>(lua_touserdata(L, 1));
T *obj = ud->pT;
delete obj; // call destructor for T objects
UnregTable(L,ud->tableref);
return 0;
}
static int new_T(lua_State *L)
{
//LOG<<"Pre build:"<<lua_gettop(L)<<"\n";
//lua::StackDump(L);
lua_remove(L, 1); // use classname:new(), instead of classname.new()
//lua_newtable(L);
int id=RegTable(L);
//LOG<<"Registred as:"<<id<<"\n";
//int ssize=lua_gettop(L);
T *obj = new T(L,id); // call constructor for T objects
lua_settop(L,0); //no need for parameters later.
//LOG<<"Post build:"<<lua_gettop(L)<<"\t";
//lua::StackDump(L);
//LOG<<"TSOP\n";
userdataType *ud =
static_cast<userdataType*>(lua_newuserdata(L, sizeof(userdataType)));
//lua::StackDump(L);
luaL_getmetatable(L, T::className); // lookup metatable in Lua registry
lua_setmetatable(L,-2);
//LOG<<"metatable set\n";
//lua::StackDump(L);
GetTable(L,obj);
lua_pushliteral(L,"__obj");
lua_pushvalue(L,-3);
lua_settable(L,-3);
lua_pop(L,1);
//LOG<<"Object referenced\n";
//lua::StackDump(L);
//T *p = new(ud) T(L); // call constructor for T objects
//lua::StackDump(L);
ud->pT = obj; // store pointer to object in userdata
ud->tableref=id;
//luaL_getmetatable(L, T::className); // lookup metatable in Lua registry
//lua_setmetatable(L, tableindex);
//lua::StackDump(L);
//LOG<<"Push done\n";
return 1; // userdata containing pointer to T object
}
Lune() {}; //non constructable...
};
#define method(class, name) {#name, &class::name}
#define DEF_LUNE(class) static const char className[];\
static Lune<class>::RegType methods[];
#define DEF_LUNE_NOGC(class) static const char className[];\
static Lune<class,false>::RegType methods[];
#define IMP_LUNE(class,lua_name) const char class::className[]=#lua_name;
#define LUNE_METHODS_START(class) Lune<class>::RegType class::methods[] = {
#define LUNE_METHODS_START_NOGC(class) Lune<class,false>::RegType class::methods[] = {
#define LUNE_METHODS_END() {0,0}}
#endif // LUNE_H

@ -0,0 +1,87 @@
adv_tools=adv_tools or {}
adv_tools.menu=adv_tools.menu or MakeMenu()
function adv_tools.ressurect()
myoff=offsets.getEx("AdvCreatureVec")
vector=engine.peek(myoff,ptr_vector)
indx=GetCreatureAtPos(getxyz())
if indx<0 then indx=0 end
--print(string.format("%x",vector:getval(indx)))
v2=engine.peek(vector:getval(indx),ptr_Creature.hurt1)
for i=0,v2:size()-1 do
v2:setval(i,0)
end
v2=engine.peek(vector:getval(indx),ptr_Creature.hurt2)
v2.type=DWORD
for i=0,v2:size()-1 do
v2:setval(i,0)
end
engine.poke(vector:getval(indx),ptr_Creature.bloodlvl,60000) --give blood
engine.poke(vector:getval(indx),ptr_Creature.bleedlvl,0) --stop some bleeding...
local flg=engine.peek(vector:getval(indx),ptr_Creature.flags)
flg:set(1,false) --ALIVE
flg:set(39,false) -- leave body yet again
flg:set(37,false) -- something todo with wounds- lets you walk again.
engine.poke(vector:getval(indx),ptr_Creature.flags,flg)
end
function adv_tools.wagonmode() --by rumrusher
--first three lines same as before (because we will need an offset of creature at location x,y,z)
myoff=offsets.getEx("AdvCreatureVec")
vector=engine.peek(myoff,ptr_vector)
indx=GetCreatureAtPos(getxyz())
--indx=0
--print(string.format("%x",vector:getval(indx)))
flg=engine.peek(vector:getval(indx),ptr_Creature.flags) --get flags
flg:set(1,false)
flg:set(74,false)
engine.poke(vector:getval(indx),ptr_Creature.flags,flg)
print("To stay normal press y, else hit Enter turn Wagon mode on.")
r=io.stdin:read() -- repeat for it too work... also creature will be dead.
if r== "y" then
flg=engine.peek(vector:getval(indx),ptr_Creature.flags)
flg:set(1,false)
engine.poke(vector:getval(indx),ptr_Creature.flags,flg)
else
flg=engine.peek(vector:getval(indx),ptr_Creature.flags)
flg:set(1,false)
flg:flip(74)
engine.poke(vector:getval(indx),ptr_Creature.flags,flg)
end
end
function selectall()
local retvec={} --return vector (or a list)
myoff=offsets.getEx("AdvCreatureVec")
vector=engine.peek(myoff,ptr_vector) --standart start
for i=0,vector:size()-1 do --check all creatures
local off
off=vector:getval(i)
local flags=engine.peek(off,ptr_Creature.flags)
if flags:get(1)==true then --if dead ...
table.insert(retvec,off)--... add it to return vector
end
end
return retvec --return the "return vector" :)
end
function adv_tools.hostilate()
vector=engine.peek(offsets.getEx("AdvCreatureVec"),ptr_vector)
id=GetCreatureAtPos(getxyz())
print(string.format("Vec:%d cr:%d",vector:size(),id))
off=vector:getval(id)
crciv=engine.peek(vector:getval(id),ptr_Creature.civ)
curciv=engine.peek(vector:getval(0),ptr_Creature.civ)
if curciv==crciv then
print("Friendly-making enemy")
engine.poke(off,ptr_Creature.civ,-1)
flg=engine.peek(off,ptr_Creature.flags)
flg:set(17,true)
engine.poke(off,ptr_Creature.flags,flg)
else
print("Enemy- making friendly")
engine.poke(off,ptr_Creature.civ,curciv)
flg=engine.peek(off,ptr_Creature.flags)
flg:set(17,false)
flg:set(19,false)
engine.poke(off,ptr_Creature.flags,flg)
end
end

@ -1,25 +1,12 @@
offsets=offsets or {} dofile("dfusion/offsets_misc.lua")
offsets._toff={} STD_STRING=0
offsets.get = function (name) DWORD=1
return offsets._toff[name] WORD=2
end BYTE=3
offsets.getEx = function (name)
return offsets._toff[name]+Process.getBase() function GetTextRegion()
end ranges__=ranges__ or Process.getMemRanges()
offsets.load = function () for k,v in pairs(ranges__) do
local f=io.open("dfusion/offsets.txt")
local line=f:read()
while line~=nil do
--print(line)
local sppliter=string.find(line,":")
offsets._toff[string.sub(line,1,sppliter-2)]=tonumber(string.sub(line,sppliter+2))
line=f:read()
end
end
offsets.load()
function unlockDF()
local ranges=Process.getMemRanges()
for k,v in pairs(ranges) do
--for k2,v2 in pairs(v) do --for k2,v2 in pairs(v) do
-- print(string.format("%d %s->%s",k,tostring(k2),tostring(v2))) -- print(string.format("%d %s->%s",k,tostring(k2),tostring(v2)))
--end --end
@ -30,15 +17,33 @@ function unlockDF()
--if(v["execute"]) then num=num+100 end --if(v["execute"]) then num=num+100 end
--print(string.format("%d %x->%x %s %d",k,v["start"],v["end"],v.name,num)) --print(string.format("%d %x->%x %s %d",k,v["start"],v["end"],v.name,num))
local pos=string.find(v.name,".text") local pos=string.find(v.name,".text")
if pos~=nil then if(pos~=nil) then
v["write"]=true return v;
Process.setPermisions(v,v)
end end
end end
return nil
end end
function lockDF() function GetRegionIn(pos)
local ranges=Process.getMemRanges() ranges__=ranges__ or Process.getMemRanges()
for k,v in pairs(ranges) do for k,v in pairs(ranges__) do
--for k2,v2 in pairs(v) do
-- print(string.format("%d %s->%s",k,tostring(k2),tostring(v2)))
--end
--local num
--num=0
--if(v["read"])then num=num+1 end
--if(v["write"])then num=num+10 end
--if(v["execute"]) then num=num+100 end
--print(string.format("%d %x->%x %s %x",k,v["start"],v["end"],v.name,pos))
if pos>=v.start and pos<=v["end"] then
return v
end
end
return nil
end
function ValidOffset(pos)
ranges__=ranges__ or Process.getMemRanges()
for k,v in pairs(ranges__) do
--for k2,v2 in pairs(v) do --for k2,v2 in pairs(v) do
-- print(string.format("%d %s->%s",k,tostring(k2),tostring(v2))) -- print(string.format("%d %s->%s",k,tostring(k2),tostring(v2)))
--end --end
@ -48,14 +53,423 @@ function lockDF()
--if(v["write"])then num=num+10 end --if(v["write"])then num=num+10 end
--if(v["execute"]) then num=num+100 end --if(v["execute"]) then num=num+100 end
--print(string.format("%d %x->%x %s %d",k,v["start"],v["end"],v.name,num)) --print(string.format("%d %x->%x %s %d",k,v["start"],v["end"],v.name,num))
local pos=string.find(v.name,".text") if pos>=v.start and pos<=v["end"] then
if pos~=nil then return true
v["write"]=false
Process.setPermisions(v,v)
end end
end end
return false
end
function unlockDF()
local reg=GetTextRegion()
reg["write"]=true
Process.setPermisions(reg,reg)
end
function lockDF()
local reg=GetTextRegion()
reg["write"]=false
Process.setPermisions(reg,reg)
end
function SetExecute(pos)
local reg=GetRegionIn(pos)
reg.execute=true
Process.setPermisions(reg,reg) -- TODO maybe make a page with only execute permisions or sth
end end
-- engine bindings -- engine bindings
engine=engine or {} engine=engine or {}
engine.peekd=Process.readDWord engine.peekd=Process.readDWord
engine.poked=Process.writeDWord engine.poked=Process.writeDWord
engine.peekb=Process.readByte
engine.pokeb=Process.writeByte
engine.peekw=Process.readWord
engine.pokew=Process.writeWord
engine.peekstr=Process.readCString
--engine.pokestr=Process.readCString
engine.peekarb=Process.read
engine.pokearb=Process.write
function engine.peek(offset,rtype)
if type(rtype)=="table" then
if rtype.off ==nil then
return engine.peekpattern(offset,rtype)
else
return engine.peek(rtype.off+offset,rtype.rtype)
end
end
if rtype==STD_STRING then
return engine.peekstr(offset)
elseif rtype==DWORD then
return engine.peekd(offset)
elseif rtype==WORD then
return engine.peekw(offset)
elseif rtype==BYTE then
return engine.peekb(offset)
else
error("Invalid peek type")
return
end
end
function engine.poke(offset,rtype,val)
if type(rtype)=="table" then
if rtype.off ==nil then
return engine.pokepattern(offset,rtype,val)
else
return engine.poke(rtype.off+offset,rtype.rtype,val)
end
end
if rtype==STD_STRING then
return engine.pokestr(offset,val)
elseif rtype==DWORD then
return engine.poked(offset,val)
elseif rtype==WORD then
return engine.pokew(offset,val)
elseif rtype==BYTE then
return engine.pokeb(offset,val)
else
error("Invalid poke type:"..tostring(rtype))
return
end
end
function engine.sizeof(rtype)
if rtype==STD_STRING then
error("String has no constant size")
return
elseif rtype==DWORD then
return 4;
elseif rtype==WORD then
return 2;
elseif rtype==BYTE then
return 1;
else
error("Invalid sizeof type")
return
end
end
function engine.peekpattern(offset,pattern)
local ret={}
for k,v in pairs(pattern) do
--print("k:"..k.." v:"..type(v))
if type(v)=="table" then
ret[k]=engine.peek(offset+v.off,v.rtype)
--print(k.." peeked:"..offset+v.off)
else
ret[k]=v
end
end
ret.__offset=offset
return ret
end
function engine.pokepattern(offset,pattern,val)
for k,v in pairs(pattern) do
--print("k:"..k.." v:"..type(v))
if type(v)=="table" then
engine.poke(offset+v.off,v.rtype,val[k])
end
end
end
function engine.LoadModData(file)
local T2={}
T2.symbols={}
T2.data,T2.size=engine.loadobj(file)
data,modsize=engine.loadobj(file)
local T=engine.loadobjsymbols(file)
for k,v in pairs(T) do
if v.pos~=0 then
T2.symbols[v.name]=v.pos
end
end
return T2
end
function engine.FindMarker(moddata,name)
if moddata.symbols[name] ~=nil then
return engine.findmarker(0xDEADBEEF,moddata.data,moddata.size,moddata.symbols[name])
end
end
function engine.installMod(file,name,bonussize)
local T=engine.LoadModData(file)
local modpos,modsize=engine.loadmod(file,name,bonussize)
T.pos=modpos
return T
end
it_menu={}
it_menu.__index=it_menu
function it_menu:add(name,func)
table.insert(self.items,{func,name})
end
function it_menu:display()
print("Select choice (q exits):")
for p,c in pairs(self.items) do
print(p..")."..c[2])
end
local ans
repeat
local r
r=io.stdin:read()
if r=='q' then return end
ans=tonumber(r)
if ans==nil or not(ans<=table.maxn(self.items) and ans>0) then
print("incorrect choice")
end
until ans~=nil and (ans<=table.maxn(self.items) and ans>0)
self.items[ans][1]()
end
function MakeMenu()
local ret={}
ret.items={}
setmetatable(ret,it_menu)
return ret
end
function PrintPattern(loadedpattern)
for k,v in pairs(loadedpattern) do
if type(v)== "string" then
print(k.." "..v)
else
print(string.format("%s %d inhex:%x",k,v,v))
end
end
end
function printPattern(pattern)
local i=0;
local names={}
names[STD_STRING]="std_string (STD_STRING)"
names[DWORD]= "Double word (DWORD)"
names[WORD]= "Word (WORD)"
names[STD_STRING]="Byte (BYTE)"
ret={}
for k,v in pairs(pattern) do
if type(v)=="table" and v.off~=nil then
if names[v.rtype]~=nil then
lname=names[v.rtype]
else
if type(v.rtype)=="table" then
lname="Table (prob subpattern)"
else
lname="Other"
end
end
print(string.format("%d. %s is %s with offset %x",i,k,lname,v.off))
table.insert(ret,k)
else
print(string.format("%d. %s",i,k))
end
i=i+1
end
return ret;
end
function editPattern(offset,pattern,name)
if type(pattern[name].rtype)=="table" then
if pattern[name].rtype.setval~=nil then
print(string.format("%x",offset+pattern[name].off))
local t=engine.peek(offset+pattern[name].off,pattern[name].rtype)
print("Value is now:"..t:getval())
print("Enter new value:")
val=io.stdin:read()
t:setval(val)
else
ModPattern(offset+pattern[name].off,pattern[name].rtype)
end
return
end
val=engine.peek(offset,pattern[name])
print("Value is now:"..val)
print("Enter new value:")
if pattern[name].rtype==STD_STRING then
val=io.stdin:read()
else
val=tonumber(io.stdin:read())
end
engine.poke(offset,pattern[name],val)
end
function ModPattern(itemoffset,pattern)
print("Select what to edit:")
nm=printPattern(pattern)
q=tonumber(io.stdin:read())
if q~=nil and q<#nm then
editPattern(itemoffset,pattern,nm[q+1])
end
end
function findVectors()
local text=GetTextRegion()
local h=hexsearch(text.start,text["end"],0x8b,ANYBYTE,ANYDWORD,0x8b,ANYBYTE,ANYDWORD,0x2b,ANYBYTE)
local pos=h:findall()
local T={}
for k,v in pairs(pos) do
local loc1,loc2
loc1=engine.peekd(v+2)
loc2=engine.peekd(v+8)
--print(string.format("%x - %x=%x",loc1,loc2,loc1-loc2))
if(loc1-loc2==4) then
if T[loc1-4]~=nil then
T[loc1-4]=T[loc1-4]+1
else
T[loc1-4]=1
end
end
end
return T
end
function GetRaceToken(p) --actually gets token...
local vec=engine.peek(offsets.getEx('CreatureGloss'),ptr_vector)
--print("Vector ok")
local off=vec:getval(p)
--print("Offset:"..off)
local crgloss=engine.peek(off,ptr_CrGloss)
--print("Peek ok")
return crgloss.token:getval()
end
function BuildNameTable()
local rtbl={}
local vec=engine.peek(offsets.getEx('CreatureGloss'),ptr_vector)
--print(string.format("Vector start:%x",vec.st))
--print(string.format("Vector end:%x",vec.en))
--local i=0
for p=0,vec:size()-1 do
local off=vec:getval(p)
--print("First member:"..off)
local name=engine.peek(off,ptt_dfstring)
--print("Loading:"..p.."="..name:getval())
rtbl[name:getval()]=p
--i=i+1
--if i>100 then
-- io.stdin:read()
-- i=0
--end
end
return rtbl;
end
function BuildMaterialTable()
local rtbl={}
local vec=engine.peek(offsets.getEx('Materials'),ptr_vector)
--print(string.format("Vector start:%x",vec.st))
--print(string.format("Vector end:%x",vec.en))
--local i=0
for p=0,vec:size()-1 do
local off=vec:getval(p)
--print("First member:"..off)
local name=engine.peek(off,ptt_dfstring)
--print("Loading:"..p.."="..name:getval())
rtbl[name:getval()]=p
--i=i+1
--if i>100 then
-- io.stdin:read()
-- i=0
--end
end
return rtbl;
end
function BuildWordTables()
local names={}
local rnames={}
local vector=engine.peek(offsets.getEx('WordVec'),ptr_vector)
for i =0,vector:size()-1 do
local off=vector:getval(i)
local n=engine.peekstr(off)
names[i]=n
rnames[n]=i
end
return names,rnames
end
function ParseScript(file)
io.input(file)
f=""
first=0
nobraces=0
function updFunction()
if f~="" then
first=0
if nobraces==0 then
f=f.."}"
end
nobraces=0
print("Doing:"..f)
assert(loadstring(f))()
f=""
end
end
while true do
local line = io.read("*line")
if line == nil then break end
if string.sub(line,1,2)==">>" then
updFunction()
if string.find(line,"%b()") then
f=string.sub(line,3)
nobraces=1
else
f=string.sub(line,3).."{"
end
--print(string.sub(line,3)..)
else
if first~=0 then
f=f..","
else
first=1
end
f=f..string.format('%q',line)
end
end
updFunction()
end
function ParseNames(path)
local ret={}
local ff=io.open(path)
for n in ff:lines() do
table.insert(ret,n)
end
return ret
end
function getxyz() -- this will return pointers x,y and z coordinates.
local off=offsets.getEx("Xpointer") -- lets find where in memory its being held
-- now lets read them (they are double words (or unsigned longs or 4 bits each) and go in sucesion
local x=engine.peekd(off)
local y=engine.peekd(off+4) --next is 4 from start
local z=engine.peekd(off+8) --next is 8 from start
--print("Pointer @:"..x..","..y..","..z)
return x,y,z -- return the coords
end
function GetCreatureAtPos(x,y,z) -- gets the creature index @ x,y,z coord
--local x,y,z=getxyz() --get 'X' coords
local vector=engine.peek(offsets.getEx("AdvCreatureVec"),ptr_vector) -- load all creatures
for i = 0, vector:size() do -- look into all creatures offsets
local curoff=vector:getval(i) -- get i-th creatures offset
local cx=engine.peek(curoff,ptr_Creature.x) --get its coordinates
local cy=engine.peek(curoff,ptr_Creature.y)
local cz=engine.peek(curoff,ptr_Creature.z)
if cx==x and cy==y and cz==z then --compare them
return i --return index
end
end
print("Creature not found!")
return -1
end
function Allocate(size)
local ptr=engine.getmod('General_Space')
if ptr==nil then
ptr=engine.newmod("General_Space",4096) -- some time later maybe make some more space
engine.poked(ptr,4)
end
local curptr=engine.peekd(ptr)
curptr=curptr+size
engine.poked(ptr,curptr)
return curptr-size+ptr
end
dofile("dfusion/patterns.lua")
dofile("dfusion/patterns2.lua")
dofile("dfusion/itempatterns.lua")

@ -0,0 +1 @@
as -a --32 -o embark.o embark.asm

@ -0,0 +1,9 @@
.intel_syntax
mov eax , [esp+0x1C]
caste:
movsx eax, word ptr[eax*2+0xdeadbeef]
mov [esp+0x04],eax
mov eax , [esp+0x1C]
race:
movzx eax,word ptr [eax*2+0xDEADBEEF]
ret

@ -0,0 +1,75 @@
function MakeTable(modpos,modsize,names)
count=0
castes={}
--print("Making table")
for _,line in pairs(names) do
--print("Line:"..line)
tpos=string.find(line,":")
if tpos~=nil then
--print("Was line:"..line)
table.insert(castes,tonumber(string.sub(line,tpos+1)))
line=string.sub(line,1,tpos-1)
--print("IS line:"..line)
else
table.insert(castes,-1)
end
if RaceTable[line] == nil then
error("Failure, "..line.." not found!")
end
engine.pokew(modpos+modsize+count*2,RaceTable[line]) -- add race
count = count + 1
end
i=0
for _,caste in pairs(castes) do
engine.pokew(modpos+modsize+count*2+i*2,caste) -- add caste
i= i+1
end
engine.poked(stoff,count)
return count
end
function embark(names)
RaceTable=RaceTable or BuildNameTable()
mypos=engine.getmod('Embark')
stoff=offsets.getEx('StartDwarfs')
if mypos then --if mod already loaded
print("Mod already loaded @:"..mypos.." just updating")
modpos=mypos
_,modsize=engine.loadobj('dfusion/embark/embark.o')
count=MakeTable(modpos,modsize,names) --just remake tables
else
tofind=offsets.getEx('CurrentRace')
loc=offsets.find(stoff,0xa1,DWORD_,tofind)
print("found:"..loc)
if((loc~=0)and(loc-stoff<1000)) then
modpos,modsize=engine.loadmod('dfusion/embark/embark.o','Embark',256)
count=MakeTable(modpos,modsize,names)
engine.poked(modpos+0x18,modpos+modsize) --fix array start for race
engine.poked(modpos+0x08,modpos+modsize+count*2) --fix array start for caste
print("sucess loading mod @:"..modpos)
-- build race vector after module.
--finaly poke in the call!
engine.pokeb(loc,0x6a)
engine.pokeb(loc+1,0xFF)
engine.pokeb(loc+2,0xe8)
engine.poked(loc+3,modpos-loc-7)
--engine.pokeb(loc+5,0x90)
SetExecute(modpos)
else
error("did not find patch location, failing...")
end
end
end
if not(FILE)then
names=ParseNames("dfusion/embark/races.txt")--io.open("plugins/embark/races.txt"):lines()
embark(names)
end

@ -0,0 +1,7 @@
DWARF:1
ELF:0
ELF:0
DWARF:0
DWARF:0
HUMAN:0
HUMAN:0

@ -0,0 +1 @@
as -anl --32 -o friendship.o friendship.asm

@ -0,0 +1,102 @@
.intel_syntax
push eax
mov eax,[esp+0x04]
push ebx
pushfd
mov eax,[eax] # get a byte after the call this procedure to analyze what register holds cr ptr
jmptbl:
cmp al,0x81
jz regC
cmp al,0x82
jz regD
cmp al,0x83
jz regB
cmp al,0x85
jz regBP
cmp al,0x86
jz regESI
cmp al,0x87
jz regEDI
cmp al,0x88
jz regA
cmp al,0x8A
jz regD
cmp al,0x8B
jz regB
cmp al,0x8D
jz regBP
cmp al,0x8E
jz regESI
cmp al,0x8F
jz regEDI
cmp al,0x90
jz regA
cmp al,0x91
jz regC
cmp al,0x93
jz regB
cmp al,0x95
jz regBP
cmp al,0x96
jz regESI
cmp al,0x97
jz regEDI
jmp fail
regA:
mov eax, [esp+0x8]
mov eax, [eax+0x8c]
jmp compare
regC:
mov eax, [ecx+0x8c]
jmp compare
regB:
mov eax, [ebx+0x8c]
jmp compare
regD:
mov eax, [edx+0x8c]
jmp compare
regBP:
mov eax, [ebp+0x8c]
jmp compare
regESI:
mov eax, [esi+0x8c]
jmp compare
regEDI:
mov eax, [edi+0x8c]
#jmp compare
compare:
push ecx
mov ebx,0xDEADBEEF #write a pointer to the list of allowed races
mov ecx,2000 #write a number of allowed races
loop1:
cmp word[ebx+ecx*2],ax
jz endok
dec ecx
cmp ecx ,-1
jnz loop1
pop ecx
popfd
jmp fail
endok:
pop ecx
popfd
cmp eax,eax
jmp endfinal
fail:
xor ebx,ebx
xor eax,eax
inc eax
cmp eax,ebx
endfinal:
pop ebx
pop eax
mov [0xFEEDBEEF],eax #write a pointer to safe location (usually after this)
pop eax
pushfd
inc eax #skip one instruction
popfd
push eax
mov eax,[0xFEEDBEEF] #write a pointer to safe location (same as above)
ret

@ -0,0 +1,35 @@
function friendship_in.install(names)
RaceTable=RaceTable or BuildNameTable()
mypos=engine.getmod("Friendship")
if mypos then
modpos=mypos
_,modsize=engine.loadobj("dfusion/friendship/friendship.o")
_=nil
else
modpos,modsize=engine.loadmod("dfusion/friendship/friendship.o","Friendship",1024)
print(string.format("Loaded module @:%x",modpos))
end
count=0
for _,v in pairs(names) do
if RaceTable[v] == nil then
--print("Failure, "..v.." not found!")
error("Failure, "..v.." not found!")
--break --maybe some indication of failure? and cleanup?
end
engine.pokew(modpos+modsize+count*2+4+2,RaceTable[v]) -- for some reason it compiled strangely
-- cmp word[ebx+ecx*2],ax -> cmp word[ebx+ecx*2+2],ax
count = count + 1
end
engine.poked(modpos+0x8f,modpos+modsize+4) -- set ptr to creatures
engine.poked(modpos+0x94,count) -- set count of creatures
engine.poked(modpos+0xb9,modpos+modsize) -- set safe location
engine.poked(modpos+0xc3,modpos+modsize) -- set safe location
SetExecute(modpos)
end
function pokeCall(off)
engine.pokeb(off,0xe8)
b=engine.peekb(off+1)
engine.poked(off+1,modpos-off-5)
engine.pokeb(off+5,b)
end

@ -0,0 +1,56 @@
function friendship_in.patch()
pos=GetTextRegion().start
local crace=offsets.getEx("CurrentRace")
hits={}
i=1
repeat
--todo make something better/smarter...
pos1=offsets.find(pos+7,0x0f,0xBF,ANYBYTE,DWORD_,crace) -- movsx
pos2=offsets.find(pos+7,0x66,0xa1,DWORD_,crace) -- mov ax,[ptr]
pos3=offsets.find(pos+7,0xa1,DWORD_,crace) -- mov eax,[ptr]
pos4=offsets.find(pos+7,0x66,0x8b,ANYBYTE,DWORD_,crace) -- mov ANYREG,[ptr]
--pos5=offsets.find(pos+7,0x66,0x8b,0x15,DWORD_,crace) -- mov dx,[ptr]
pos=minEx(pos1,pos2,pos3,pos4)
if pos ~=0 then
hits[i]=pos
i=i+1
print(string.format("Found at %x",pos))
end
until pos==0
print("=======================================")
for _,p in pairs(hits) do
myp=p
repeat
--print(string.format("Analyzing %x...",p))
pos1=offsets.find(myp,0x39,ANYBYTE,0x8c,00,00,00) -- compare [reg+08c] (creature race) with any reg
pos2=offsets.find(myp,0x3b,ANYBYTE,0x8c,00,00,00) -- compare any reg with [reg+08c] (creature race)
pos=minEx(pos1,pos2)
if pos ~=0 then
if(pos-p>250) then
--this here does not work yet...
--[[pos =offsets.find(p,CALL)
print(string.format("Distance to call:%x",pos-p))
print(string.format("Call: %x",signDword(engine.peekd(pos+1)+pos)))
pos=analyzeF(signDword(signDword(engine.peekd(pos+1)+pos)))
print(string.format("Cmp @:%x",pos))]]--
print(string.format("skipping %x... Cmp too far away (dist=%i)",p,pos-p))
else
--print(string.format("Found at %x, simple compare",pos))
--print(string.format("Distance =%x",pos-p))
--patch compares
pokeCall(pos)
end
else
break
end
myp=myp+pos+6
if myp-p >250 then break end
until false
end
end

@ -0,0 +1,60 @@
--if(mypos~=0) then
--print("plugin already active")
--maybe set options for reinit?
--return
--end
function analyzeF(off)
pos=offsets.find(off,0x39,ANYBYTE,0x8c,00,00,00)
print(string.format("Compare at:%x",pos))
if pos ==0 then
return 0
end
if(pos-off>0x100) then
print(string.format("Distance to cmp:%x",pos-off))
pos =offsets.find(off,CALL)
print(string.format("Distance to call:%x",pos-off))
return 0
--return analyzeF(pos)
else
return pos
end
end
function minEx(...)
local imin=arg[1]
for _,v in ipairs(arg) do
if imin> v and v~=0 then
imin=v
end
end
return imin
end
function signDword(dw)
if(dw>0xFFFFFFFF) then
return dw-0xFFFFFFFF
end
return dw
end
--[[
Warning: not all mov's are acounted for. Found one: mov EAX,WORD PTR[EBP+1EF4] WTF??
Two more compares are missing. There are calls instead (same function)
]]--
if not(FILE) then
print("race num:"..engine.peekw(offsets.getEx("CurrentRace")))
print("Your current race is:"..GetRaceToken(engine.peekw(offsets.getEx('CurrentRace'))))
print("If this is wrong please quit now (by ctrl+c)")
io.stdin:read()
end
friendship_in={}
dofile("dfusion/friendship/install.lua")
dofile("dfusion/friendship/patch.lua")
if not(FILE) then
names=ParseNames("dfusion/friendship/races.txt")--io.open("plugins/friendship/races.txt"):lines()
friendship_in.install(names)
friendship_in.patch()
end
function friendship(names)
friendship_in.install(names)
friendship_in.patch()
end

@ -0,0 +1,8 @@
DWARF
GOBLIN
ELF
HUMAN
KOBOLD
GREMLIN
TIGERMAN
ANT_MAN

@ -10,24 +10,36 @@ function dofile(filename) --safer dofile, with traceback (very usefull)
print(perr) print(perr)
end end
end end
dofile("dfusion/common.lua")
print("Unlocking Df .text section...")
unlockDF()
print("Done unlock")
lockDF()
dofile("dfusion/simple_embark/plugin.lua")
print("hello world")
Console.print("Hello world in console!\n")
--name=Console.lineedit("Enter name:")
--Console.print("Your name is:"..name)
function OnTick() -- floods the console function mainmenu(t1)
r=Console.get_rows()
c=Console.get_columns()
Console.clear() Console.clear()
Console.gotoxy(math.random(1,r),math.random(1,2)) while true do
Console.color(math.random(0,15)) print("No. Name Desc")
Console.print("*") for k,v in pairs(t1) do
print(string.format("%d %s %s",k,v[1],v[2]))
end
local q=Console.lineedit("Select plugin to run (q to quit):")
if q=='q' then return end
q=tonumber(q)
if q~=nil then
if q>=1 and q<=#t1 then
dofile("dfusion/"..t1[q][1].."/plugin.lua")
end
end
end
end end
OnTick=nil dofile("dfusion/common.lua")
unlockDF()
plugins={}
table.insert(plugins,{"simple_embark","A simple embark dwarf count editor"})
table.insert(plugins,{"items","A collection of item hacking tools"})
table.insert(plugins,{"offsets","Find all offsets"})
table.insert(plugins,{"friendship","Multi race fort enabler"})
table.insert(plugins,{"embark","Multi race embark"})
table.insert(plugins,{"adv_tools","some tools for (mainly) advneturer hacking"})
table.insert(plugins,{"tools","some misc tools"})
table.insert(plugins,{"triggers","a function calling plug (discontinued...)"})
table.insert(plugins,{"migrants","multi race imigrations"})
mainmenu(plugins)

@ -0,0 +1,62 @@
--dofile("patterns2.lua") moved to common.lua
ptr_item={}
ptr_item.RTI={off=0,rtype=DWORD}
ptr_item.x={off=4,rtype=WORD}
ptr_item.y={off=6,rtype=WORD}
ptr_item.z={off=8,rtype=WORD}
ptr_item.ref={off=0x28,rtype=ptr_vector}
ptr_item.mat={off=0x78,rtype=WORD}
ptr_item.submat={off=0x7A,rtype=WORD}
ptr_item.submat2={off=0x7C,rtype=DWORD}
ptr_item.legendid={off=0x80,rtype=DWORD} -- i don't remember writing this...
ptr_item.decorations={off=0x90,rtype=ptr_vector}
ptr_item.flags={off=0xC,rtype=ptt_dfflag.new(8)}
ptr_item.ptr_covering={off=0x64,rtype=DWORD}
ptr_item.stack={off=0x58,rtype=WORD}
function ptr_item.getname(self,RTI)
if RTI == nil then
return string.sub(RTTI_GetName(self.RTI),5,-3)
else
return string.sub(RTTI_GetName(RTI),5,-3)
end
end
ptr_subitems={}
ptr_subitems["item_slabst"]={}
ptr_subitems["item_slabst"].msgptr={off=0xA0,rtype=ptt_dfstring}
ptr_subitems["item_slabst"].signtype={off=0xC0,rtype=DWORD}
ptr_subitems["item_fisthst"]={}
ptr_subitems["item_fisthst"].fisthtype={off=0x78,rtype=WORD}
ptr_subitems["item_eggst"]={}
ptr_subitems["item_eggst"].race={off=0x78,rtype=DWORD}
ptr_subitems["item_eggst"].isfertile={off=0xa0,rtype=DWORD} --0 or 1
ptr_subitems["item_eggst"].hatchtime={off=0xa4,rtype=DWORD}
ptr_decoration_gen={}
ptr_decoration_gen.RTI={off=0,rtype=DWORD}
ptr_decoration_gen.material={off=0x04,rtype=WORD} -- same for all?
ptr_decoration_gen.submat={off=0x08,rtype=DWORD}
function ptr_decoration_gen.getname(self,RTI)
if RTI == nil then
return string.sub(RTTI_GetName(self.RTI),21,-5)
else
return string.sub(RTTI_GetName(RTI),21,-5)
end
end
ptr_decoration={}
ptr_decoration["covered"]={}
ptr_decoration["covered"].material={off=0x04,rtype=WORD}
ptr_decoration["covered"].submat={off=0x08,rtype=DWORD}
ptr_decoration["art_image"]={}
ptr_decoration["art_image"].material={off=0x04,rtype=WORD}
ptr_decoration["art_image"].submat={off=0x08,rtype=DWORD}
ptr_decoration["art_image"].image={off=0x24,rtype=DWORD}
ptr_decoration["bands"]={}
ptr_decoration["bands"].material={off=0x04,rtype=WORD}
ptr_decoration["bands"].submat={off=0x08,rtype=DWORD}
ptr_cover={} --covering of various types (blood, water, etc)
ptr_cover.mat={off=0,rtype=WORD}
ptr_cover.submat={off=4,rtype=DWORD}
ptr_cover.state={off=8,rtype=WORD}

@ -0,0 +1,212 @@
items={} --> first lets make a menu table
items.menu=MakeMenu()
function items.dest()
myoff=offsets.getEx("Items") -- first find out where "item vector" is
vector=engine.peek(myoff,ptr_vector) -- get list of items
for i=0,vector:size()-1 do --look at each item
flg=engine.peek(vector:getval(i),ptr_item.flags)
flg:set(17,1)
engine.poke(vector:getval(i),ptr_item.flags,flg)
end
end
function items.eggs()
myoff=offsets.getEx("Items") -- first find out where "item vector" is
vector=engine.peek(myoff,ptr_vector) -- get list of items
for i=0,vector:size()-1 do --look at each item
rti=engine.peek(vector:getval(i),ptr_item.RTI)
if ptr_item.getname(nil,rti)=="item_eggst" then
egg=engine.peek(vector:getval(i),ptr_subitems["item_eggst"])
egg.isfertile=1
egg.hatchtime=0xffffff
--egg.race=123 -- change race for fun times
engine.poke(vector:getval(i),ptr_subitems["item_eggst"],egg)
end
end
end
function editFlags(offset)
while true do
flags=engine.peek(offset,ptr_item.flags)
for i=0,8*8-1 do
if flags:get(i) then
print(i.." is true")
else
print(i.." is false")
end
end
print(" enter number to switch flag or not a number to quit:")
q=tonumber(io.stdin:read())
if q==nil then return end
flags:flip(q)
engine.poke(offset,ptr_item.flags,flags)
end
end
function editCovering(offset)
off=engine.peek(offset,ptr_item.ptr_covering)
if off == 0 then
print("No coverings found.")
end
vec=engine.peek(off,ptr_vector)
print("Covering list:")
for i=0,vec:size()-1 do
cov=engine.peek(vec:getval(i),ptr_cover)
print(string.format("%d. mat=%d submat=%d state=%d",i,cov.mat,cov.submat,cov.state))
end
print("To edit type number:")
q=tonumber(io.stdin:read())
if q==nil then return end
if q>=vec:size() or q<0 then return end
off=vec:getval(q)
cov=engine.peek(off,ptr_cover)
print("Enter mat:")
q=tonumber(io.stdin:read())
if q==nil then q=0xffff end
print("Enter submat:")
v=tonumber(io.stdin:read())
if v==nil then v=0xffff end
print("Enter state:")
y=tonumber(io.stdin:read())
if y==nil then y=0 end
cov.mat=q
cov.submat=v
cov.state=y
engine.poke(off,ptr_cover,cov)
end
function editMaterial(offset)
print("Mat id 0 to 18 is in normal materials (inorganic, amber etc...) after that creature mat (with submat2 being race)")
print("from 219 with submat2=0xffffffff (type not a number) it reads legends id, from 419 submat2 means plant id")
print("Probably submat is not used :? ")
mat=engine.peek(offset,ptr_item.mat)
submat=engine.peek(offset,ptr_item.submat)
submat2=engine.peek(offset,ptr_item.submat2)
lid=engine.peek(offset,ptr_item.legendid)
print(string.format("Now is mat=%d, submat=%d submat2=%d legend id=%d",mat,submat,submat2,lid))
print("Enter mat:")
q=tonumber(io.stdin:read())
if q==nil then return end
print("Enter submat:")
v=tonumber(io.stdin:read())
if v==nil then v=0xffff end
print("Enter submat2:")
z=tonumber(io.stdin:read())
if z==nil then z=0xffffffff end
print("Enter legendid:")
y=tonumber(io.stdin:read())
if y==nil then y=0xffffffff end
engine.poke(offset,ptr_item.mat,q)
engine.poke(offset,ptr_item.submat,v)
engine.poke(offset,ptr_item.legendid,y)
engine.poke(offset,ptr_item.submat2,z)
print("Done")
end
function items.select()
myoff=offsets.getEx("Items")
vector=engine.peek(myoff,ptr_vector)
tx,ty,tz=getxyz()
T={}
for i=0,vector:size()-1 do --this finds all item offsets that are on pointer
itoff=vector:getval(i)
x=engine.peek(itoff,ptr_item.x)
y=engine.peek(itoff,ptr_item.y)
z=engine.peek(itoff,ptr_item.z)
if x==tx and y==ty and z==tz then
table.insert(T,itoff)
end
end
print("Items under cursor:")
i=1
for _,v in pairs(T) do
RTI=engine.peek(v,ptr_item.RTI)
print(i..". "..ptr_item.getname(nil,RTI))
i=i+1
end
print("Type number to edit or 'q' to exit")
while true do
q=io.stdin:read()
if q=='q' then return end
if tonumber(q) ~=nil and tonumber(q)<i then break end
end
return T[tonumber(q)]
end
function items.select_creature(croff)
vector=engine.peek(croff,ptr_Creature.itemlist2)
print("Vector size:"..vector:size())
T={}
for i=0,vector:size()-1 do
table.insert(T,vector:getval(i)) -- item list is itemptr+location?
end
print("Items in inventory:")
i=1
for _,v in pairs(T) do
RTI=engine.peek(engine.peekd(v),ptr_item.RTI)
print(i..". "..ptr_item.getname(nil,RTI).." locations:"..engine.peekw(v+4).." "..engine.peekw(v+6))
i=i+1
end
print("Type number to edit or 'q' to exit")
while true do
q=io.stdin:read()
if q=='q' then return end
if tonumber(q) ~=nil and tonumber(q)<i then break end
end
return engine.peekd(T[tonumber(q)])
end
function items.edit(itoff)
if itoff==nil then
itoff=items.select()
end
print(string.format("Item offset:%x",itoff))
print("Type what to edit:")
print("1. material")
print("2. flags")
print("3. covering")
Z={}
Z[1]=editMaterial
Z[2]=editFlags
Z[3]=editCovering
name=ptr_item.getname(nil,engine.peek(itoff,ptr_item.RTI))
if name~=nil and ptr_subitems[name]~=nil then
print("4. Item specific edit")
--Z[4]=items.fedit[name]
Z[4]="dummy"
end
while true do
q=io.stdin:read()
if q=='q' then return end
if tonumber(q) ~=nil and tonumber(q)<#Z+1 then break end
end
if Z[tonumber(q)]=="dummy" then
ModPattern(itoff,ptr_subitems[name])
else
Z[tonumber(q)](itoff)
end
end
function items.printref()
itoff=items.select()
vec=engine.peek(itoff,ptr_item.ref)
for i=0, vec:size()-1 do
toff=vec:getval(i)
print(RTTI_GetName(engine.peekd(toff)))
end
print("Decorations:")
vec=engine.peek(itoff,ptr_item.decorations)
for i=0, vec:size()-1 do
toff=vec:getval(i)
print(ptr_decoration_gen.getname(nil,engine.peek(toff,ptr_decoration_gen.RTI)))
end
end
function items.edit_adv()
vec=engine.peek(offsets.getEx("CreatureVec"),ptr_vector)
items.edit(items.select_creature(vec:getval(0)))
end
if not(FILE) then -- if not in script mode
items.menu:add("Destroy all",items.dest)
items.menu:add("Hatch eggs",items.eggs)
items.menu:add("Edit item",items.edit)
items.menu:add("Print ref",items.printref)
items.menu:add("Edit adventurer's items",items.edit_adv)
items.menu:display()
end

@ -0,0 +1 @@
as -anl --32 -o migrants.o migrants.asm

@ -0,0 +1,20 @@
.intel_syntax
pushfd
push ebx
push edx
mov eax,[0xdeadbeef] # get old seed
mov ebx,1103515245
#mul 1103515245
mul ebx
add eax,12345
mov [0xdeadbeef],eax #put seed back...thus generation rnd is complete
xor edx,edx
mov ebx,2000 #put size of array here
div ebx #why oh why there is no div const? compiler prob makes some xor/add magic
movzx eax,word ptr[0xdeadbeef+edx*2]
pop edx
pop ebx
popfd
ret

@ -0,0 +1,65 @@
--install part
function migrants(names)
RaceTable=RaceTable or BuildNameTable()
mypos=engine.getmod("Migrants")
if mypos then
print("Migrant mod is running already @:"..mypos)
modpos=mypos
_,modsize=engine.loadobj("dfusion/migrants/migrants.o")
count=0
for _,v in pairs(names) do
if RaceTable[v] == nil then
print("Failure, "..v.." not found!")
break --maybe some indication of failure? and cleanup?
end
engine.pokew(modpos+modsize+count*2+4,RaceTable[v])
count = count + 1
end
seedpos=modpos+modsize
engine.poked(seedpos,math.random(1234567)) -- seed the generator :)
engine.poked(modpos+0x1c,count) --max size for div
else
modpos,modsize=engine.loadmod("dfusion/migrants/migrants.o","Migrants")
print(string.format("Loaded module @:%x",modpos))
count=0
for _,v in pairs(names) do
if RaceTable[v] == nil then
print("Failure, "..v.." not found!")
break --maybe some indication of failure? and cleanup?
end
engine.pokew(modpos+modsize+count*2+4,RaceTable[v])
count = count + 1
end
seedpos=modpos+modsize
engine.poked(modpos+0x04,seedpos)
engine.poked(modpos+0x15,seedpos)
engine.poked(seedpos,math.random(1234567)) -- seed the generator :)
engine.poked(modpos+0x1c,count) --max size for div
engine.poked(modpos+0x26,seedpos+4) --start of array
--patch part
--pos=62873C+DF
-- pattern: A1,DWORD_,"CURRENTRACE",56,89,ANYBYTE,ANYBYTE,34,e8
pos=offsets.find(offsets.base(),0xa1,DWORD_,offsets.getEx("CurrentRace"),0x56,0x89,ANYBYTE,ANYBYTE,0x34,0xe8)
function pokeCall(off)
engine.pokeb(off,0xe8)
engine.poked(off+1,modpos-off-5)
end
if pos~=0 then
print(string.format("Found @:%x",pos))
pokeCall(pos)
else
print("Not found patch location!!!")
end
end
end
if not(FILE) then
names=ParseNames("dfusion/migrants/races.txt")--io.open("plugins/migrants/races.txt"):lines()
migrants(names)
end

@ -0,0 +1,29 @@
DWARF
DWARF
DWARF
DWARF
DWARF
DWARF
DWARF
DWARF
DWARF
ELF
HUMAN
DWARF
GREMLIN
KOBOLD
DWARF
DWARF
DWARF
DWARF
DWARF
DWARF
DWARF
DWARF
DWARF
ELF
HUMAN
DWARF
GREMLIN
KOBOLD
DEMON_13

@ -0,0 +1,320 @@
function f_dwarves()
pos=offsets.find(0,0x24,0x14,0x07,0,0,0,0xeb,0x08,0x8d) --search pattern
if pos~=0 then
return pos+2-offsets.base();
else
return 0;
end
end
offsets.new("StartDwarfs",f_dwarves) -- finds the starting dwarf count
function f_creatures()
--01C48034-base=0x1258034
local val=0
--print("Enter creature count:");
--local r=io.stdin:read()
for k,v in pairs(offsets.getvectors()) do
if (v>60) and (v<100) then --used count changed some time ago... two hits second one is the right one. Maybe some smarter way could be better?
--new version first one is right?? needs more testing thou...
val= k-offsets.base()
print(string.format("%x",val))
break;
end
--vec=engine.peek(k,ptr_vector);
--[[if(vec:size()==tonumber(r)) then
val=k-offsets.base()
print(string.format("off:%x",k))
end--]]
end
offsets.new("AdvCreatureVec",val)
return val
end
offsets.new("CreatureVec",f_creatures)
function f_words()
local val=0
for k,v in pairs(offsets.getvectors()) do
local toff=engine.peekd(engine.peekd(k))
if(engine.peekstr(toff)=="ABBEY") then
val=k-offsets.base()
end
end
return val
end
offsets.newlazy("WordVec",f_words)
function f_creatureptr() --a creature number under the pointer
pos=offsets.find(0,0xa1,ANYDWORD,0x83,0xf8,0xff,0x75)
print("Offset="..pos)
if pos~=0 then
pos=engine.peekd(pos+1)
return pos-offsets.base()
else
return 0
end
end
offsets.new("CreaturePtr",f_creatureptr)
function f_creaturegloss() --creature race vector
for k,v in pairs(offsets.getvectors()) do
local reg
reg=GetRegionIn(k)
if reg ~=nil then
print(string.format("looking into %x wich is in %s",k,reg.name or ""))
else
print(string.format("looking into %x in nil region",k))
end
if ValidOffset(k) then
print("Looking into:"..string.format("%x",k).." used:"..v)
local vec=engine.peek(k,ptr_vector)
if vec:size()>0 and vec:size()<100000 and vec:getval(0)~=0 then
local toff=vec:getval(0)
if ValidOffset(toff) then
print("\tval:"..string.format("%x",vec:getval(0)))
local token=engine.peek(toff,ptt_dfstring)
--print("\t\tval:".. token:getval())
if token:getval()=="TOAD" then -- more offsets could be found this way
return k-offsets.base()
end
end
end
end
end
return 0
end
offsets.new("CreatureGloss",f_creaturegloss)
--reaction vec: search for TAN_A_HIDE
function f_racevec() --current race
--find all movsx anyreg,address
local den={}
local pos=offsets.findall(0,0x0f,0xbf,ANYBYTE,ADDRESS)
for k,v in pairs(pos) do
local add
if v~=0 then
add=engine.peekd(v+3)
if den[add]~=nil then
den[add]= den[add]+1
else
den[add]=1
end
end
end
for k,v in pairs(den) do
if v <60 then
den[k]=nil
end
end
for k,v in pairs(den) do
print("Looking into:"..string.format("%x",k).." used:"..v.." Race:"..engine.peekw(k))
if engine.peekw(k) >0 and engine.peekw(k)<1000 then
return k-offsets.base()
end
end
return 0
end
offsets.new("CurrentRace",f_racevec)
function f_pointer() --adventure (not only?) pointer x,y,z
print("\n")
local den={}
local pos=0
repeat
pos=offsets.find(pos+3,0x0f,0xb7,ANYBYTE,ADDRESS)
local add=engine.peekd(pos+3)
local add2=engine.peekd(pos+13)
local add3=engine.peekd(pos+23)
if( math.abs(add-add2)==4 or math.abs(add-add3)==4) then
if den[add]~=nil then
den[add]= den[add]+1
else
den[add]=1
end
end
until pos==0
for k,v in pairs(den) do
print("Looking into:"..string.format("%x",k).." used:"..v)
return k-offsets.base()-4
end
return 0
end
offsets.new("Xpointer",f_pointer)
function f_adventure()
RaceTable=RaceTable or BuildNameTable() -- this gets all the races' numbers
--[[print("input chars race:")
repeat
r=io.stdin:read()
if RaceTable[r]==nil then print("Incorrect race...") end
until RaceTable[r]~=nil -- query till correct race is inputed
rnum=RaceTable[r] --get its num
print("Race:"..rnum)]]--
myoff=0
print("input player's creature's name (lowercaps):")
r=io.stdin:read()
for k,v in pairs(offsets.getvectors()) do -- now lets look through all vector offsets
off=engine.peekd(k) --get vector start
off=engine.peekd(off) --get 0 element (or first) in adventurer mode its our hero
name=engine.peekstr(off)
if(name==r) then
--if engine.peek(off+140)==rnum then -- creature start+140 is the place where race is kept
print(string.format("%x race:%x",k,engine.peekw(off+140)))
myoff=k -- ok found it
break
end
end
if myoff~=0 then
crvec=engine.peek(myoff,ptr_vector)
print(string.format("player offset:%x",crvec:getval(0)))
local legidVec=engine.peek(crvec:getval(0),ptr_Creature.legends)
print(string.format("legends offset:%x",legidVec:getval(0)))
local vtable=engine.peekd(legidVec:getval(0))
print(string.format("vtable offset:%x",vtable))
offsets.new("vtableLegends",vtable-offsets.base())
return myoff-offsets.base() --save the offset for laters
else
return 0 --indicate failure
end
end
offsets.newlazy("AdvCreatureVec",f_adventure) -- register a way to find this offset
--7127F0
function f_legends()
pos=1
T={}
repeat
pos=offsets.find(pos+1,0x50,0xb8,ANYDWORD,0xe8,ANYDWORD,0x8b,0xf0)
off=engine.peekd(pos+2)
vec=engine.peek(off,ptr_vector)
if vec:size()~=0 then
if T[off]~=nil then
T[off].c=T[off].c+1
else
T[off]={c=1,vsize=vec:size()}
end
end
until pos==0
for k,v in pairs(T) do
vec=engine.peek(k,ptr_vector)
print(string.format("off:%x used:%i size:%d",k,v.c,v.vsize))
print(string.format("fith elements id:%d",engine.peekd(vec:getval(5))))
if engine.peekd(vec:getval(5))==5 then
--if v.c==2 and v.vsize>1000 then
return k-offsets.base()
end
end
return 0
end
offsets.newlazy("Legends",f_legends)
function f_playerlegendid()
local off=offsets.getEx("Legends")
local pos=1
repeat
pos=offsets.find(pos+1,0xa1,DWORD_,off+4,0x2b,0x05,DWORD_,off)
val=engine.peekd(pos+16)
if engine.peekd(val)~=0 then
--if val >offsets.base() then
return val-offsets.base()
end
--print(string.format("%x",val))
until pos==0
return 0
end
offsets.newlazy("PlayerLegend",f_playerlegendid)
function f_world()
local pos=offsets.base()
T={}
while pos~=0 do
--pos=offsets.find(pos+6,0xa1,DWORD_,mapoffset,0x8b,0x4c,0x88,0xFC)
pos=offsets.find(pos+6,0x8b,0x35,ANYDWORD,0x85,0xf6)--,0x8b,0x4c,0x88,0xFC)
--pos2=offsets.find(pos,0x8b,0x34,0x88)
if pos~=0 then
add=engine.peekd(pos+2);
--if pos2 ~=0 and pos2-pos<25 then
-- print(string.format("Address:%x dist:%d Map:%x",pos2,pos2-pos,add))
--
--end
if add~=0 then
if T[add]~=nil then
T[add]=T[add]+1
else
T[add]=1
end
end
end
end
local kk,vv
vv=0
for k,v in pairs(T) do
if v>vv then
vv=v
kk=k
end
--print(string.format("Address:%x, times used:%d",k,v))
end
return kk-offsets.base()
end
offsets.new("WorldData",f_world)
function f_sites()
local pos=offsets.base()
T={}
while pos~=0 do
pos=offsets.find(pos+17,0xA1,ANYDWORD, --mov eax, ptr to some biger thing
0x8B,0x90,0x24,0x01,0x00,0x00, --mov edx [eax+0x124]
0x2b,0x90,0x20,0x01,0x00,0x00, --sub edx [eax+0x120]
EOL)
if pos~=0 then
add=engine.peekd(pos+1)
return add-offsets.base()
end
end
return 0
end
offsets.newlazy("SiteData",f_sites) --actually has a lot more data...
function f_items()
local pos=offsets.base()
while pos~= 0 do
pos=offsets.find(pos+17,0x8b,0x0d,ANYDWORD, --mov eax, ptr to some biger thing
0x8B,0x54,0x24,0x34)
if pos~=0 then
--print(string.format("%x",engine.peekd(pos+2)))
local ret=engine.peekd(pos+2)-offsets.base()
return ret
end
end
return 0
end
offsets.new("Items",f_items)
function f_materials()
for k,v in pairs(offsets.getvectors()) do
--print("Looking into:"..string.format("%x",k).." used:"..v)
local vec=engine.peek(k,ptr_vector)
if vec:getval(0)~=0 then
--print("\tval:"..string.format("%x",vec:getval(0)))
local token=engine.peek(vec:getval(0),ptt_dfstring)
if token:getval()~=""then
--print("\t\tval:".. token:getval())
if token:getval()=="IRON" then
--print("Found:"..string.format("%x",k).." used:"..v)
return k-offsets.base()
end
end
end
end
return 0
end
offsets.new("Materials",f_materials)

@ -0,0 +1,2 @@
offsets.searchoffsets()
offsets.save()

@ -0,0 +1,104 @@
offsets=offsets or {}
offsets._toff={}
offsets._foff={}
offsets.get = function (name)
if offsets._toff[name] == nil then
offsets.searchoffset(name,true)
end
return offsets._toff[name]
end
offsets.getEx = function (name)
--return offsets._toff[name]+Process.getBase()
return offsets.get(name)+Process.getBase()
end
offsets.load = function ()
local f=io.open("dfusion/offsets.txt")
local line=f:read()
while line~=nil do
--print(line)
local sppliter=string.find(line,":")
offsets._toff[string.sub(line,1,sppliter-2)]=tonumber(string.sub(line,sppliter+2))
line=f:read()
end
end
offsets.save = function ()
local f=io.open("dfusion/offsets.txt","w")
for k,v in pairs(offsets._toff) do
f:write(string.format("%s : 0x%x\n",k,v))
end
f:close()
end
function offsets.new(name, func)
if type(func)=="function" then
table.insert(offsets._foff,{name,func,false})
else
offsets._toff[name]=func
end
--offsets._foff[name]={func,false}
end
function offsets.newlazy(name, func)
table.insert(offsets._foff,{name,func,true})
--offsets._foff[name]={func,true}
end
function offsets.searchoffset(num,forcelazy)
v=offsets._foff[num]
print("Finding offset:"..v[1])
if (v[3] and focelazy) or not v[3] then
local pos=v[2]()
if pos== 0 then
error("Offset not found for:"..v[1])
else
offsets._toff[v[1]]=pos
end
end
end
function offsets.searchoffsets(forcelazy)
for k,v in pairs(offsets._foff) do
offsets.searchoffset(k,forcelazy)
end
end
function offsets.find(startoffset,...)
local endadr;
if startoffset== 0 then
local text=GetTextRegion()
--print("searching in:"..text.name)
startoffset=text.start
endadr=text["end"]
else
local reg=GetRegionIn(startoffset)
--print("searching in:"..reg.name)
endadr=reg["end"]
end
--print(string.format("Searching (%x->%x)",startoffset,endadr))
local h=hexsearch(startoffset,endadr,...)
local pos=h:find()
h=nil
return pos
end
function offsets.findall(startoffset,...)
local endadr;
if startoffset== 0 then
local text=GetTextRegion()
--print("searching in:"..text.name)
startoffset=text.start
endadr=text["end"]
else
local reg=GetRegionIn(startoffset)
--print("searching in:"..reg.name)
endadr=reg["end"]
end
local h=hexsearch(startoffset,endadr,...)
local pos=h:findall()
h=nil
return pos
end
function offsets.base()
return Process.getBase()
end
function offsets.getvectors()
return findVectors()
end
offsets.load()
ADDRESS=ANYDWORD
dofile("dfusion/offsets.lua")

@ -0,0 +1,246 @@
ptt_dfstring={}
if(COMPATMODE) then
ptt_dfstring.ptr={off=4,rtype=DWORD}
ptt_dfstring.size={off=20,rtype=DWORD}
else
ptt_dfstring.ptr={off=0,rtype=DWORD}
ptt_dfstring.size={off=16,rtype=DWORD}
ptt_dfstring.alloc={off=20,rtype=DWORD}
end
function ptt_dfstring:getval()
--print(string.format("GETTING FROM:%x",self.__offset))
if self.size<16 then
--print(string.format("GETTING FROM:%x",self.__offset))
return string.sub(engine.peekstr(self.__offset),1,self.size)
else
--print(string.format("GETTING FROM:%x",self.ptr))
return string.sub(engine.peekstr(self.ptr),1,self.size)
end
end
function ptt_dfstring:setval(newstring)
local offset=self.__offset
local strl=string.len(newstring)
if strl<16 then
--print(string.format("GETTING FROM:%x",self.__offset))
engine.poked(offset+ptt_dfstring.size.off,strl)
engine.poked(offset+ptt_dfstring.alloc.off,15)
engine.pokestr(offset,newstring)
else
local loc
if engine.peekd(offset+ptt_dfstring.alloc.off) > strl then
loc=engine.peekd(offset)
print("Will fit:"..loc.." len:"..strl)
else
loc=Allocate(strl+1)
engine.poked(offset+ptt_dfstring.alloc.off,strl)
print("Will not fit:"..loc.." len:"..strl)
end
--print(string.format("GETTING FROM:%x",self.ptr))
engine.poked(self.__offset+ptt_dfstring.size.off,strl)
engine.pokestr(loc,newstring)
engine.poked(self.__offset,loc)
end
end
--if(COMPATMODE) then
--ptr_vector={}
--ptr_vector.st={off=4,rtype=DWORD}
--ptr_vector.en={off=8,rtype=DWORD}
--else
ptr_vector={}
ptr_vector.st={off=0,rtype=DWORD}
ptr_vector.en={off=4,rtype=DWORD}
ptr_vector.alloc={off=8,rtype=DWORD}
--end
function ptr_vector:clone(settype)
local ret={}
for k,v in pairs(self) do
ret[k]=v
end
ret.type=settype
return ret
end
function ptr_vector:size()
return (self.en-self.st)/engine.sizeof(self.type)
end
ptr_vector.type=DWORD
function ptr_vector:getval(num)
if self.st==0 then return error("Vector empty.") end
--print("Wants:"..num.." size:"..self:size())
if num>=self:size() then error("Index out of bounds in vector.") end
return engine.peek(self.st+engine.sizeof(self.type)*num,self.type)
end
function ptr_vector:setval(num,val)
return engine.poke(self.st+engine.sizeof(self.type)*num,self.type,val)
end
function ptr_vector:append(val)
if self.alloc - self.en > 0 then
local num=self:size()
self.en=self.en+engine.sizeof(self.type)
self:setval(val,num)
else
error("larger than allocated arrays not implemented yet")
local num=self:size()
local ptr=Allocate(num*2)
end
end
ptt_dfflag={}
function ptt_dfflag.flip(self,num) --flip one bit in flags
local of=math.floor (num/8);
self[of]=bit.bxor(self[of],bit.lshift(1,num%8))
end
function ptt_dfflag.get(self,num) -- get one bit in flags
local of=math.floor (num/8);
if bit.band(self[of],bit.lshift(1,num%8))~=0 then
return true
else
return false
end
end
function ptt_dfflag.set(self,num,val) --set to on or off one bit in flags
if (self:get(num)~=val) then
self:flip(num)
end
end
function ptt_dfflag.new(size) -- create new flag pattern of size(in bytes)
local ret={}
for i=0,size-1 do
ret[i]={off=i,rtype=BYTE};
end
ret.flip=ptt_dfflag.flip --change to metatable stuff...
ret.get=ptt_dfflag.get
ret.set=ptt_dfflag.set
return ret;
end
--[[
Creature:
0 name (df_string) 28
28 nick (df_string) 56
56 surname- namearray(7*dword(4)) 84 ...
140 race (dword) 144
224 flags
264 civ (dword)
252 ID
592 following ID
904 bleed vector? hurt vector or sth...
0x790 legends id?
2128 known names? or knowledge?
flags:
0 Can the dwarf move or are they waiting for their movement timer
1 Dead (might also be set for incoming/leaving critters that are alive)
2 Currently in mood
3 Had a mood
4 "marauder" -- wide class of invader/inside creature attackers
5 Drowning
6 Active merchant
7 "forest" (used for units no longer linked to merchant/diplomacy, they just try to leave mostly)
8 Left (left the map)
9 Rider
10 Incoming
11 Diplomat
12 Zombie
13 Skeleton
14 Can swap tiles during movement (prevents multiple swaps)
15 On the ground (can be conscious)
16 Projectile
17 Active invader (for organized ones)
18 Hidden in ambush
19 Invader origin (could be inactive and fleeing)
20 Will flee if invasion turns around
21 Active marauder/invader moving inward
22 Marauder resident/invader moving in all the way
23 Check against flows next time you get a chance
24 Ridden
25 Caged
26 Tame
27 Chained
28 Royal guard
29 Fortress guard
30 Suppress wield for beatings/etc
31 Is an important historical figure
32 swiming
]]--
ptr_Creature={}
ptr_Creature.x={off=144,rtype=WORD} --ok
ptr_Creature.y={off=146,rtype=WORD} --ok
ptr_Creature.z={off=148,rtype=WORD} --ok
ptr_Creature.flags={off=224,rtype=ptt_dfflag.new(10)}
ptr_Creature.name={off=0,rtype=ptt_dfstring}
ptr_Creature.ID={off=252,rtype=DWORD} --ok i guess
ptr_Creature.followID={off=592,rtype=DWORD} --ok
ptr_Creature.race={off=140,rtype=DWORD} --ok
ptr_Creature.civ={off=264,rtype=DWORD}
ptr_Creature.legends={off=344,rtype=ptr_vector} --ok
ptr_Creature.hurt1={off=0x308,rtype=ptr_vector:clone(BYTE)} --byte vector...
ptr_Creature.hurt2={off=0x338,rtype=ptr_vector}
ptr_Creature.wounds={off=0x388,rtype=ptr_vector}
ptr_Creature.itemlist1={off=0x1D0,rtype=ptr_vector}
ptr_Creature.itemlist2={off=0x288,rtype=ptr_vector}
ptr_Creature.bloodlvl={off=0x490,rtype=DWORD}
ptr_Creature.bleedlvl={off=0x494,rtype=DWORD}
ptr_CrGloss={}
ptr_CrGloss.token={off=0,rtype=ptt_dfstring}
ptr_CrGloss.castes={off=296,rtype=ptr_vector}
ptr_CrCaste={}
ptr_CrCaste.name={off=0,rtype=ptt_dfstring}
ptr_CrCaste.flags_ptr={off=0x524,rtype=DWORD} --size 17?
--[=[
Flags:
57 - is sentient (allows setting labours)
--]=]
ptr_LEntry={} -- all size 256
ptr_LEntry.name={off=36,rtype=ptt_dfstring}
ptr_LEntry.id1={off=160,rtype=DWORD}
ptr_LEntry.id2={off=164,rtype=DWORD}
ptr_LEntry.somlist={off=220,rtype=DWORD}
ptr_dfname={}
for i=0,6 do
ptr_dfname[i]={off=i*4,rtype=DWORD}
end
--[[
Site docs:
0x38 name struct todo...
0x78 type:
0 - mountain halls (yours)
1 - dark fort
2 - cave
3 - mountain hall (other)
4 - forest
5 - hamlet
6 - imp location
7 - lair
8 - fort
9 - camp
0x7a some sort of id?
0x84 some vec (ids)
0x94 some other vec (ids)
0xa4 some vec (prts)
0x118 ptr to sth
0x14c ptr to mapdata
]]--
ptr_site={}
ptr_site.type={off=0x78,rtype=WORD}
ptr_site.id={off=0x7a,rtype=DWORD}
ptr_site.name={off=0x38,rtype=ptr_dfname}
ptr_site.flagptr={off=0x118,rtype=DWORD}
ptr_legends2={}
ptr_legends2.id={off=0,rtype=DWORD}
ptr_legends2.follow={off=0x18,rtype=DWORD}
ptr_material={}
ptr_material.token={off=0,rtype=ptt_dfstring}

@ -0,0 +1,29 @@
ptr_COL={} -- complete object locator...
ptr_COL.sig={off=0,rtype=DWORD}
ptr_COL.offset={off=4,rtype=DWORD} --offset of this vtable in the complete class
ptr_COL.cdoffset={off=8,rtype=DWORD} -- constructor displacement
ptr_COL.typePointer={off=12,rtype=DWORD}
ptr_COL.hierarchyPointer={off=16,rtype=DWORD}
ptr_RTTI_Type={}
ptr_RTTI_Type.vftPointer={off=0,rtype=DWORD}
ptr_RTTI_Type.name={off=8,rtype=STD_STRING}
function RTTI_GetName(vtable)
local COLoff=engine.peek(vtable-4,DWORD)
--print(string.format("Look:%x vtable:%x",vtable,engine.peek(vtable-4,DWORD)))
COL=engine.peek(COLoff,ptr_COL)
--print(string.format("COL:%x Typeptr:%x Type:%s",COLoff,COL.typePointer,engine.peek(COL.typePointer,ptr_RTTI_Type.name)))
return engine.peek(COL.typePointer,ptr_RTTI_Type.name)
end
ptr_RTTI_Hierarchy={}
ptr_RTTI_Hierarchy.sig={off=0,rtype=DWORD}
ptr_RTTI_Hierarchy.attributes={off=4,rtype=DWORD}
ptr_RTTI_Hierarchy.numBaseClasses={off=8,rtype=DWORD}
ptr_RTTI_Hierarchy.ptrBases={off=12,rtype=DWORD}
ptr_RTTI_BaseClass={}
ptr_RTTI_BaseClass.typePointer={off=0,rtype=DWORD}
ptr_RTTI_BaseClass.numContained={off=4,rtype=DWORD}
--todo PMD
--todo flags

@ -0,0 +1,529 @@
--local bit = require("bit")
tools={}
tools.menu=MakeMenu()
function tools.setrace()
RaceTable=RaceTable or BuildNameTable() --slow.If loaded don't load again
print("Your current race is:"..GetRaceToken(engine.peekw(offsets.getEx('CurrentRace'))))
print("Type new race's token name in full caps:")
repeat
entry=io.stdin:read()
id=RaceTable[entry]
until id~=nil
engine.pokew(offsets.getEx('CurrentRace'),id)
end
tools.menu:add("Set current race",tools.setrace)
function tools.GiveSentience(names) --TODO make pattern...
RaceTable=RaceTable or BuildNameTable() --slow.If loaded don't load again
if names ==nil then
ids={}
print("Type race's token name in full caps to give sentience to:")
repeat
entry=io.stdin:read()
id=RaceTable[entry]
until id~=nil
table.insert(ids,id)
else
ids={}
for _,name in pairs(names) do
id=RaceTable[name]
table.insert(ids,id)
end
end
for _,id in pairs(ids) do
local off=offsets.getEx('CreatureGloss')
local races=engine.peek(off,ptr_vector)
--print("Vector start:"..off)
off=races:getval(id)
print(string.format("race location:%x",off))
local castes=engine.peek(off,ptr_CrGloss.castes)
print(string.format("Caste count:%i",castes:size()))
local flagPattern=ptt_dfflag.new(17)
for i =0,castes:size()-1 do
local offCaste=castes:getval(i)
print("Caste name:"..engine.peek(offCaste,ptr_CrCaste.name):getval().."...")
local flagoffset=engine.peek(offCaste,ptr_CrCaste.flags_ptr)
local flags=engine.peek(flagoffset,flagPattern)
--print(string.format("%x",flagoffset))
if flags:get(57) then
print("\tis sentient.")
else
print("\tnon sentient. Allocating IQ...")
flags:set(57,1)
engine.poke(flagoffset,flagPattern,flags)
end
end
end
end
tools.menu:add("Give Sentience",tools.GiveSentience)
function tools.embark()
off=offsets.find(0,0x66, 0x83, 0x7F ,0x1A ,0xFF,0x74,0x04)
if off~=0 then
engine.pokeb(off+5,0x90)
engine.pokeb(off+6,0x90)
print("Found and patched")
else
print("not found")
end
end
tools.menu:add("Embark anywhere",tools.embark)
function tools.getlegendsid(croff)
local vec=engine.peek(croff,ptr_Creature.legends)
if vec:size()==0 then
return 0
end
for i =0,vector:size()-1 do
--if engine.peekd(vec:getval(i))~=0 then
-- print(string.format("%x",engine.peekd(vec:getval(i))-offsets.base()))
--end
if(engine.peekd(vec:getval(i))==offsets.getEx("vtableLegends")) then --easy to get.. just copy from player's-base
return engine.peekd(vec:getval(i)+4)
end
end
return 0
end
function tools.getCreatureId(vector)
tnames={}
rnames={}
--[[print("vector1 size:"..vector:size())
print("vector2 size:"..vector2:size())]]--
for i=0,vector:size()-1 do
--print(string.format("%x",vector:getval(i)))
local name=engine.peek(vector:getval(i),ptt_dfstring):getval()
local lid= tools.getlegendsid(vector:getval(i))
if lid ~=0 then
print(i..")*Creature Name:"..name.." race="..engine.peekw(vector:getval(i)+ptr_Creature.race.off).." legendid="..lid)
else
print(i..") Creature Name:"..name.." race="..engine.peekw(vector:getval(i)+ptr_Creature.race.off))
end
if name ~="" and name~=nil then
tnames[i]=name
rnames[name]=i
end
end
print("=====================================")
print("type in name or number:")
r=io.stdin:read()
if tonumber(r) ==nil then
indx=rnames[r]
if indx==nil then return end
else
r=tonumber(r)
if r<vector:size() then indx=r else return end
end
return indx
end
function tools.change_adv()
myoff=offsets.getEx("AdvCreatureVec")
vector=engine.peek(myoff,ptr_vector)
indx=tools.getCreatureId(vector)
print("Swaping, press enter when done or 'q' to stay, 's' to stay with legends id change")
tval=vector:getval(0)
vector:setval(0,vector:getval(indx))
vector:setval(indx,tval)
r=io.stdin:read()
if r=='q' then
return
end
if r~='s' then
tval=vector:getval(0)
vector:setval(0,vector:getval(indx))
vector:setval(indx,tval)
end
local lid=tools.getlegendsid(vector:getval(0))
if lid~=0 then
engine.poked(offsets.getEx("PlayerLegend"),lid)
else
print("Warning target does not have a valid legends id!")
end
end
tools.menu:add("Change Adventurer",tools.change_adv)
function tools.MakeFollow()
myoff=offsets.getEx("AdvCreatureVec")
vector=engine.peek(myoff,ptr_vector)
indx=tools.getCreatureId(vector)
print(string.format("current creature:%x",vector:getval(indx)))
trgid=engine.peek(vector:getval(0)+ptr_Creature.ID.off,DWORD)
lfollow=engine.peek(vector:getval(indx)+ptr_Creature.followID.off,DWORD)
if lfollow ~=0xFFFFFFFF then
print("Already following, unfollow? y/N")
r=io.stdin:read()
if r== "y" then
engine.poke(vector:getval(indx)+ptr_Creature.followID.off,DWORD,0)
end
else
engine.poke(vector:getval(indx)+ptr_Creature.followID.off,DWORD,trgid)
end
end
tools.menu:add("Make creature follow",tools.MakeFollow)
function tools.runscript(files)
if files==nil then
files={}
table.insert(files,io.stdin:read())
end
for _,v in pairs(files) do
print("Running script:"..v)
ParseScript(v)
end
end
function tools.getsite(names)
if words==nil then --do once its slow.
words,rwords=BuildWordTables()
end
if names==nil then
print("Type words that are in the site name, FULLCAPS, no modifiers (lovely->LOVE), q to quit:")
names={}
repeat
w=io.stdin:read();
if rwords[w]~=nil then
table.insert(names,w)
print("--added--")
end
until w=='q'
end
tnames={}
for _,v in pairs(names) do
if rwords[v] ~=nil then
table.insert(tnames,rwords[v]) --get word numbers
end
end
local offsites=engine.peekd(offsets.getEx("SiteData"))+0x120
snames={" pfort"," dfort"," cave","mohall","forest","hamlet","imploc"," lair"," fort"," camp"}
vector=engine.peek(offsites,ptr_vector)
print("Number of sites:"..vector:size())
print("List of hits:")
for i =0,vector:size()-1 do
off=vector:getval(i)
good=true
r=""
hits=0
sname=engine.peek(off,ptr_site.name)
for k=0,6 do
vnum=sname[k]--engine.peekd(off+0x38+k*4)
tgood=false
if vnum~=0xFFFFFFFF then
--print(string.format("%x",vnum))
if names[vnum]~=nil then
r=r..names[vnum].." "
end
for _,v in pairs(tnames) do
if vnum==v then
tgood=true
--print("Match")
hits=hits+1
break
end
end
if not tgood then
good=false
end
end
end
if(good) and (hits>0)then
--if true then
--print("=====================")
typ=engine.peek(off,ptr_site.type)--engine.peekw(off+0x78)
flg=engine.peekd(engine.peek(off,ptr_site.flagptr))
--flg=engine.peekd(off+224)
--flg2=engine.peekw(off)
--tv=engine.peek(off+0x84,ptr_vector)
--tv2=engine.peek(off+0xA4,ptr_vector)
print(string.format("%d)%s off=%x type=%s\t flags=%x",i,r,off,snames[typ+1],flg))
if i%100==99 then
r=io.stdin:read()
end
end
end
print("Type which to change (q cancels):")
repeat
r=io.stdin:read()
n=tonumber(r)
if(r=='q') then return end
until n~=nil
return vector:getval(n)
end
function tools.changesite(names)
off=tools.getsite(names)
snames={"Mountain halls (yours)","Dark fort","Cave","Mountain hall (NPC)","Forest retreat","Hamlet","Important location","Lair","Fort","Camp"}
print("Type in the site type (q cancels):")
for k,v in pairs(snames) do
print((k-1).."->"..v)
end
repeat
r=io.stdin:read()
n2=tonumber(r)
if(r=='q') then return end
until n2~=nil
--off=vector:getval(n)
print(string.format("%x->%d",off,n2))
engine.poke(off,ptr_site.type,n2)
end
function tools.changeflags(names)
myflag_pattern=ptt_dfflag.new(3*8)
off=tools.getsite(names)
offflgs=engine.peek(off,ptr_site.flagptr)
q=''
print(string.format("Site offset %x flags offset %x",off,offflgs))
repeat
print("flags:")
--off=vector:getval(n)
flg=engine.peek(offflgs,myflag_pattern)
r=""
for i=0,3*8-1 do
if flg:get(i)==1 then
r=r.."x"
else
r=r.."o"
end
if i%8==7 then
print(i-7 .."->"..r)
r=""
end
end
print("Type number to flip, or 'q' to quit.")
q=io.stdin:read()
n2=tonumber(q)
if n2~=nil then
flg:flip(n2)
engine.poke(offflgs,myflag_pattern,flg)
end
until q=='q'
end
function tools.hostilate()
vector=engine.peek(offsets.getEx("CreatureVec"),ptr_vector)
id=engine.peekd(offsets.getEx("CreaturePtr"))
print(string.format("Vec:%d cr:%d",vector:size(),id))
off=vector:getval(id)
crciv=engine.peek(off,ptr_Creature.civ)
print("Creatures civ:"..crciv)
curciv=engine.peekd(offsets.getEx("CurrentRace")-12)
print("My civ:"..curciv)
if curciv==crciv then
print("Friendly-making enemy")
engine.poke(off,ptr_Creature.civ,-1)
flg=engine.peek(off,ptr_Creature.flags)
flg:set(17,0)
print("flag 51:"..tostring(flg:get(51)))
engine.poke(off,ptr_Creature.flags,flg)
else
print("Enemy- making friendly")
engine.poke(off,ptr_Creature.civ,curciv)
flg=engine.peek(off,ptr_Creature.flags)
flg:set(17,1)
flg:set(19,0)
engine.poke(off,ptr_Creature.flags,flg)
end
end
function tools.mouseBlock()
local xs,ys,zs
xs,ys,zs=getxyz()
xs=math.floor(xs/16)
ys=math.floor(ys/16)
print("Mouse block is:"..xs.." "..ys.." "..zs)
end
function tools.protectsite()
local mapoffset=offsets.getEx("WorldData")--0x131C128+offsets.base()
local x=engine.peek(mapoffset+24,DWORD)
local y=engine.peek(mapoffset+28,DWORD)
local z=engine.peek(mapoffset+32,DWORD)
--vec=engine.peek(mapoffset,ptr_vector)
print("Blocks loaded:"..x.." "..y.." "..z)
print("Select type:")
print("1. All (SLOW)")
print("2. range (x0 x1 y0 y1 z0 z1)")
print("3. One block around pointer")
print("anything else- quit")
q=io.stdin:read()
n2=tonumber(q)
if n2==nil then return end
if n2>3 or n2<1 then return end
local xs,xe,ys,ye,zs,ze
if n2==1 then
xs=0
xe=x-1
ys=0
ye=y-1
zs=0
ze=z-1
elseif n2==2 then
print("enter x0:")
xs=tonumber(io.stdin:read())
print("enter x1:")
xe=tonumber(io.stdin:read())
print("enter y0:")
ys=tonumber(io.stdin:read())
print("enter y1:")
ye=tonumber(io.stdin:read())
print("enter z0:")
zs=tonumber(io.stdin:read())
print("enter z1:")
ze=tonumber(io.stdin:read())
function clamp(t,vmin,vmax)
if t> vmax then return vmax end
if t< vmin then return vmin end
return t
end
xs=clamp(xs,0,x-1)
ys=clamp(ys,0,y-1)
zs=clamp(zs,0,z-1)
xe=clamp(xe,xs,x-1)
ye=clamp(ye,ys,y-1)
ze=clamp(ze,zs,z-1)
else
xs,ys,zs=getxyz()
xs=math.floor(xs/16)
ys=math.floor(ys/16)
xe=xs
ye=ys
ze=zs
end
local xblocks=engine.peek(mapoffset,DWORD)
local flg=bit.lshift(1,14)
for xx=xs,xe do
local yblocks=engine.peek(xblocks+xx*4,DWORD)
for yy=ys,ye do
local zblocks=engine.peek(yblocks+yy*4,DWORD)
for zz=zs,ze do
local myblock=engine.peek(zblocks+zz*4,DWORD)
if myblock~=0 then
for i=0,255 do
local ff=engine.peek(myblock+0x67c+i*4,DWORD)
ff=bit.bor(ff,flg) --set 14 flag to 1
engine.poke(myblock+0x67c+i*4,DWORD,ff)
end
end
end
print("Blocks done:"..xx.." "..yy)
end
end
end
function tools.fixwarp()
local mapoffset=offsets.getEx("WorldData")--0x131C128+offsets.base()
local x=engine.peek(mapoffset+24,DWORD)
local y=engine.peek(mapoffset+28,DWORD)
local z=engine.peek(mapoffset+32,DWORD)
--vec=engine.peek(mapoffset,ptr_vector)
print("Blocks loaded:"..x.." "..y.." "..z)
print("Select type:")
print("1. All (SLOW)")
print("2. range (x0 x1 y0 y1 z0 z1)")
print("3. One block around pointer")
print("anything else- quit")
q=io.stdin:read()
n2=tonumber(q)
if n2==nil then return end
if n2>3 or n2<1 then return end
local xs,xe,ys,ye,zs,ze
if n2==1 then
xs=0
xe=x-1
ys=0
ye=y-1
zs=0
ze=z-1
elseif n2==2 then
print("enter x0:")
xs=tonumber(io.stdin:read())
print("enter x1:")
xe=tonumber(io.stdin:read())
print("enter y0:")
ys=tonumber(io.stdin:read())
print("enter y1:")
ye=tonumber(io.stdin:read())
print("enter z0:")
zs=tonumber(io.stdin:read())
print("enter z1:")
ze=tonumber(io.stdin:read())
function clamp(t,vmin,vmax)
if t> vmax then return vmax end
if t< vmin then return vmin end
return t
end
xs=clamp(xs,0,x-1)
ys=clamp(ys,0,y-1)
zs=clamp(zs,0,z-1)
xe=clamp(xe,xs,x-1)
ye=clamp(ye,ys,y-1)
ze=clamp(ze,zs,z-1)
else
xs,ys,zs=getxyz()
xs=math.floor(xs/16)
ys=math.floor(ys/16)
xe=xs
ye=ys
ze=zs
end
local xblocks=engine.peek(mapoffset,DWORD)
local flg=bit.bnot(bit.lshift(1,3))
for xx=xs,xe do
local yblocks=engine.peek(xblocks+xx*4,DWORD)
for yy=ys,ye do
local zblocks=engine.peek(yblocks+yy*4,DWORD)
for zz=zs,ze do
local myblock=engine.peek(zblocks+zz*4,DWORD)
if myblock~=0 then
for i=0,255 do
local ff=engine.peek(myblock+0x67c+i*4,DWORD)
ff=bit.band(ff,flg) --set 14 flag to 1
engine.poke(myblock+0x67c+i*4,DWORD,ff)
end
end
end
print("Blocks done:"..xx.." "..yy)
end
end
end
if not(FILE) then
tools.menu:add("Change site type",tools.changesite)
tools.menu:add("Change site flags",tools.changeflags)
tools.menu:add("Run script file",tools.runscript)
tools.menu:add("Hostilate creature",tools.hostilate)
tools.menu:add("Protect site from item scattering",tools.protectsite)
tools.menu:add("Print current mouse block",tools.mouseBlock)
--tools.menu:add("XXX",tools.fixwarp)
tools.menu:display()
--[[choices={
{tools.setrace,"Change race"},
{tools.GiveSentience,"Give Sentience"},
{tools.embark,"Embark anywhere"},
{tools.change_adv,"Change Adventurer"},
{tools.changesite,"Change site type"},
{tools.runscript,"Run script file"},
{tools.MakeFollow,"Make creature follow"},
{function () return end,"Quit"}}
print("Select choice:")
for p,c in pairs(choices) do
print(p..")."..c[2])
end
repeat
ans=tonumber(io.stdin:read())
if ans==nil or not(ans<=table.maxn(choices) and ans>0) then
print("incorrect choice")
end
until ans~=nil and (ans<=table.maxn(tdir) and ans>0)
choices[ans][1]()]]--
end

@ -0,0 +1 @@
as -anl --32 -o triggers.o triggers.asm

@ -0,0 +1,20 @@
function func.Find_Print()
pos=offsets.find(offsets.base(),0x73,0x02,0x8b,0xce,0x53,0x6a,0x01,0x6a,0x06,CALL) -- a hack for now...
return engine.peekd(pos+10)+pos+14-offsets.base()
end
function func.PrintMessage(msg,color1,color2)
func.f_print_pos= func.f_print_pos or func.Find_Print()
--print(string.format("%x",func.f_print_pos))
debuger.suspend()
d=NewCallTable() -- make a call table
t=Allocate(string.len(msg))
engine.pokestr(t,msg)
--print(string.format("Message location:%x",t))
d["ECX"]=t --set ecx to message location
d["STACK5"]=color1 -- push to stack color1
d["STACK4"]=color2 -- push to stack color2
d["STACK3"]=0 -- this is usually 0 maybe a struct pointing to location of this message?
PushFunction(func.f_print_pos+offsets.base(),d) -- prep to call function
-- was 0x27F030
debuger.resume()
end

@ -0,0 +1,12 @@
func={}
dofile("dfusion/triggers/functions.lua")
func.menu=MakeMenu()
function func.PrintMessage_()
print("Type a message:")
msg=io.stdin:read()
func.PrintMessage(msg,6,1)
end
if not(FILE) then -- if not in script mode
func.menu:add("Print message",func.PrintMessage_)
func.menu:display()
end

@ -0,0 +1,107 @@
if FILE then
return
end
callinfo={}
callinfo.regs={}
callinfo.regs["EAX"]=0
callinfo.regs["EBX"]=1
callinfo.regs["ECX"]=2
callinfo.regs["EDX"]=3
callinfo.regs["ESI"]=4
callinfo.regs["EDI"]=5
callinfo.regs["STACK1"]=6
callinfo.regs["STACK2"]=7
callinfo.regs["STACK3"]=8
callinfo.regs["STACK4"]=9
callinfo.regs["STACK5"]=10
mypos=engine.getmod("triggers_main")
function GetCount()
return engine.peek(0,triggers.count)
end
function SetCount(val)
engine.poke(0,triggers.count,val)
end
function NewCallTable(tbl)
ret=tbl or {}
for k,v in pairs(callinfo.regs) do
ret[k]=0
end
return ret
end
function PushFunction(off,data)
local i=GetCount()
engine.poked(triggers.table.off+i*44,off) -- add function to table
engine.poked(triggers.data.off+0,data["EAX"]) --set register data...
engine.poked(triggers.data.off+4,data["EBX"])
engine.poked(triggers.data.off+8,data["ECX"])
engine.poked(triggers.data.off+12,data["EDX"])
engine.poked(triggers.data.off+16,data["ESI"])
engine.poked(triggers.data.off+20,data["EDI"])
engine.poked(triggers.data.off+24,data["STACK1"])
engine.poked(triggers.data.off+28,data["STACK2"])
engine.poked(triggers.data.off+32,data["STACK3"])
engine.poked(triggers.data.off+36,data["STACK4"])
engine.poked(triggers.data.off+40,data["STACK5"])
SetCount(i+1)
end
function loadTriggers()
if triggers then return end
triggers={}
p=engine.getmod("triggerdata")
triggers.count={off=engine.peekd(p),rtype=DWORD}
triggers.table={off=engine.peekd(p+4),rtype=DWORD}
triggers.ret={off=engine.peekd(p+8),rtype=DWORD}
triggers.data={off=engine.peekd(p+12),rtype=DWORD}
end
if mypos then
loadTriggers()
dofile("dfusion/triggers/functions_menu.lua")
--return
else
triggers={}
off=0x56D345+offsets.base()
print(string.format("Function start %x",off))
ModData=engine.installMod("dfusion/triggers/triggers.o","triggers_main")
print("installed")
modpos=ModData.pos
modsize=ModData.size
fdata=engine.newmod("function_body",256)
engine.poked(modpos+engine.FindMarker(ModData,"trigercount"),modpos+modsize) -- count of functions
engine.poked(modpos+engine.FindMarker(ModData,"f_loc"),modpos+modsize+4) -- function table start
engine.poked(modpos+engine.FindMarker(ModData,"f_data"),fdata) -- function data start
engine.poked(modpos+engine.FindMarker(ModData,"saveplace31"),modpos+modsize+260) -- save function loc
engine.poked(modpos+engine.FindMarker(ModData,"saveplace32"),modpos+modsize+260) -- save function loc
engine.poked(modpos+engine.FindMarker(ModData,"saveplace33"),modpos+modsize+260) -- save function loc
engine.poked(modpos+engine.FindMarker(ModData,"saveplace"),modpos+modsize+256) -- save function loc
engine.poked(modpos+engine.FindMarker(ModData,"trigcount2"),modpos+modsize) -- count of functions (for zeroing)
engine.poked(modpos+engine.FindMarker(ModData,"saveplace2"),modpos+modsize+256) -- save function loc
engine.poked(modpos+engine.FindMarker(ModData,"results"),modpos+modsize+256) --overwrite function call with results
triggers.count={off=modpos+modsize,rtype=DWORD}
triggers.table={off=modpos+modsize+4,rtype=DWORD}
triggers.ret={off=modpos+modsize+256,rtype=DWORD}
triggers.data={off=fdata,rtype=DWORD}
pp=Allocate(4*4)
engine.poked(pp,triggers.count.off)
engine.poked(pp+4,triggers.table.off)
engine.poked(pp+8,triggers.ret.off)
engine.poked(pp+12,triggers.data.off)
engine.newmod("triggerdata",0,pp)
function pokeCall(off)
engine.pokeb(off,0xe8)
--b=engine.peekb(off+1)
engine.poked(off+1,modpos-off-5)
--engine.pokeb(off+5,b)
end
print(string.format("Mod @:%x",modpos))
dat=engine.peekarb(off,5)
engine.pokearb(modpos,dat,5)
pokeCall(off)
end

@ -0,0 +1,68 @@
.intel_syntax
nop #5 nops for instruction thats replaced by call
nop
nop
nop
nop
pushad
pushfd
saveplace31:
mov [0xDEADBEEF], esp
trigercount:
mov eax, [0xDEADBEEF] #mov count of triggers.
f_loc:
mov esi, 0xdeadbeef #mov location of functions.
f_data:
mov ebx, 0xDEADBEEF #mov a start of function data
test eax,eax
jz lend
lstart:
dec eax
push ebx
push eax
mov eax,[esi+eax*4]
saveplace:
mov [0xDEADBEEF],eax #save function for later
pop eax
push eax
mov edx,44
mul edx
add eax,ebx
#stack preparation
mov ebx,[eax+24]
push ebx
mov ebx,[eax+28]
push ebx
mov ebx,[eax+32]
push ebx
mov ebx,[eax+36]
push ebx
mov ebx,[eax+40]
push ebx
mov ebx,[eax+4]
mov ecx,[eax+8]
mov edx,[eax+12]
mov esi,[eax+16]
mov edi,[eax+20]
mov eax,[eax]
saveplace2:
call [0xdeadbeef] #same save loc
results:
mov [0xDEADBEEF],eax #get result
saveplace33:
mov esp, [0xDEADBEEF]
add esp, -8
pop eax
pop ebx
cmp eax,0
jnz lstart
lend:
xor eax,eax
trigcount2:
mov dword ptr [0xDEADBEEF], eax # zero triggers
saveplace32:
mov esp, [0xDEADBEEF]
popfd
popad
ret

@ -0,0 +1,14 @@
.intel_syntax
#eax - num of function
#ebx -start of data
mov ecx,eax
mul 10
add ebx
mov ebx,[eax+4]
mov ecx,[eax+8]
mov edx,[eax+12]
mov esi,[eax+16]
mov edi,[eax+20]
mov eax,[eax]
retn

@ -13,7 +13,28 @@ Other than std lua commands supported:
get_rows() get_rows()
lineedit(string) //text input through console lineedit(string) //text input through console
history_add(string) // adds string to console history history_add(string) // adds string to console history
* Process.
readDWord
writeDWord
readFloat
readWord
writeWord
readByte
writeByte
read
write
read/writeSTLString
copySTLString
doReadClassName
readClassName
readCString
isSuspended
isIdentified
getThreadIDs
getMemRanges
getBase
getPath
setPermisions
Functions searched: Functions searched:
OnTick() OnTick()
If defined is called each DFHack tick. If defined is called each DFHack tick.

@ -0,0 +1,100 @@
#include "OutFile.h"
using namespace OutFile;
File::File(std::string path)
{
//mystream.exceptions ( std::fstream::eofbit | std::fstream::failbit | std::fstream::badbit );
mystream.open(path.c_str(),std::fstream::binary|std::ios::in|std::ios::out);
mystream.read((char*)&myhead,sizeof(myhead));
for(unsigned i=0;i<myhead.sectioncount;i++)
{
Section x;
mystream.read((char*)&x,sizeof(Section));
sections[x.name]=x;
}
if(mystream)
{
//std::cout<<"Sizeof:"<<sizeof(Section)<<"\n";
/*myhead.PrintData();
for(auto it=sections.begin();it!=sections.end();it++)
{
it->second.PrintData();
}*/
}
else
{
std::cout<<"Error opening file!"<<std::endl;
}
}
Section &File::GetSection(std::string name)
{
return sections[name];
}
void File::GetText(char *ptr)
{
Section &s=GetSection(".text");
mystream.seekg(s.start);
mystream.read(ptr,s.size);
}
size_t File::GetTextSize()
{
Section &s=GetSection(".text");
return s.size;
}
void File::PrintRelocations()
{
for(auto it=sections.begin();it!=sections.end();it++)
{
std::cout<<it->first<<":\n";
for(unsigned i=0;i<it->second.numRel;i++)
{
Relocation r;
mystream.seekg(it->second.ptrRel+10*i);
mystream.read((char*)&r,10);
std::cout<<r.ptr<<" -- "<<r.tblIndex<<":"<</*symbols[r.tblIndex].name<<*/" type:"<<r.type<<"\n";
}
}
}
void File::PrintSymbols()
{
std::cout<<"Sizeof symbol:"<<sizeof(Symbol)<<std::endl;
std::cout<<"Symbol count:"<<myhead.symbolcount<<std::endl;
for(unsigned i=0;i<myhead.symbolcount;i++)
{
mystream.seekg(myhead.symbolptr+i*18);
Symbol s;
std::cout<<i<<"\t";
s.Read(mystream,myhead.symbolptr+18*myhead.symbolcount);
//mystream.read((char*)&s,sizeof(Symbol));
s.PrintData();
symbols.push_back(s);
if(s.auxsymbs>0)
{
i+=s.auxsymbs;
}
}
}
void File::LoadSymbols()
{
symbols.clear();
for(unsigned i=0;i<myhead.symbolcount;i++)
{
mystream.seekg(myhead.symbolptr+i*18);
Symbol s;
s.Read(mystream,myhead.symbolptr+18*myhead.symbolcount);
symbols.push_back(s);
if(s.auxsymbs>0)
{
i+=s.auxsymbs;
}
}
}
File::~File()
{
}

@ -0,0 +1,116 @@
#include "hexsearch.h"
Hexsearch::Hexsearch(const SearchArgType &args,uint64_t startpos,uint64_t endpos):args_(args),pos_(startpos),startpos_(startpos),endpos_(endpos)
{
ReparseArgs();
}
Hexsearch::~Hexsearch()
{
}
inline bool Hexsearch::Compare(int a,int b)
{
if(b==Hexsearch::ANYBYTE)
return true;
if(a==b)
return true;
return false;
}
void Hexsearch::ReparseArgs()
{
union
{
uint32_t val;
uint8_t bytes[4];
}B;
SearchArgType targ;
targ=args_;
args_.clear();
for(size_t i=0;i<targ.size();)
{
if(targ[i]==DWORD_)
{
i++;
B.val=targ[i];
for(int j=0;j<4;j++)
{
args_.push_back(B.bytes[j]);
}
i++;
}
else if (targ[i]==ANYDWORD)
{
i++;
for(int j=0;j<4;j++)
args_.push_back(ANYBYTE);
}
else
{
args_.push_back(targ[i]);
i++;
}
}
}
uint64_t Hexsearch::FindNext() //TODO rewrite using Boyer-Moore algorithm
{
DFHack::Core &inst=DFHack::Core::getInstance();
DFHack::Process *p=inst.p;
uint8_t *buf;
buf=new uint8_t[args_.size()];
while(pos_<endpos_)
{
bool found=true;
p->readByte(pos_,buf[0]);
if(Compare(buf[0],args_[0]))
{
p->read(pos_,args_.size(),buf);
for(size_t i=0;i<args_.size();i++)
{
if(!Compare(buf[i],args_[i]))
{
pos_+=i;
found=false;
break;
}
}
if(found)
{
pos_+=args_.size();
delete [] buf;
return pos_-args_.size();
}
}
pos_++;
}
delete [] buf;
return 0;
}
std::vector<uint64_t> Hexsearch::FindAll()
{
std::vector<uint64_t> ret;
uint64_t cpos=pos_;
while(cpos!=0)
{
cpos=FindNext();
if(cpos!=0)
ret.push_back(cpos);
}
return ret;
}
void Hexsearch::PrepareBadCharShift()
{
BadCharShifts.resize(256,-1);
int i=0;
for(SearchArgType::reverse_iterator it=args_.rbegin();it!=args_.rend();it++)
{
BadCharShifts[*it]=i;
i++;
}
}
void Hexsearch::PrepareGoodSuffixTable()
{
GoodSuffixShift.resize(args_.size()+1,0);
}

@ -0,0 +1,61 @@
#include "lua_Hexsearch.h"
int lua::Hexsearch::find(lua_State *L)
{
lua::state st(L);
uint64_t pos=p->FindNext();
st.push(pos);
return 1;
}
int lua::Hexsearch::findall(lua_State *L)
{
lua::state st(L);
std::vector<uint64_t> pos=p->FindAll();
st.newtable();
for(unsigned i=0;i<pos.size();i++)
{
st.push(i+1);
st.push(pos[i]);
st.settable();
}
return 1;
}
lua::Hexsearch::Hexsearch(lua_State *L,int id):tblid(id)
{
lua::state st(L);
uint64_t start,end;
::Hexsearch::SearchArgType args;
start=st.as<uint32_t>(1);
end=st.as<uint32_t>(2);
for(int i=3;i<=st.gettop();i++)
{
args.push_back(st.as<int>(i));
}
p=new ::Hexsearch(args,start,end);
}
lua::Hexsearch::~Hexsearch()
{
delete p;
}
int lua::Hexsearch::reset(lua_State *L)
{
lua::state st(L);
p->Reset();
return 0;
}
IMP_LUNE(lua::Hexsearch,hexsearch);
LUNE_METHODS_START(lua::Hexsearch)
method(lua::Hexsearch,find),
method(lua::Hexsearch,findall),
method(lua::Hexsearch,reset),
LUNE_METHODS_END();
#define __ADDCONST(name) st.push(::Hexsearch:: ## name); st.setglobal(#name)
void lua::RegisterHexsearch(lua::state &st)
{
Lune<lua::Hexsearch>::Register(st);
__ADDCONST(ANYBYTE);
__ADDCONST(ANYDWORD);
__ADDCONST(DWORD_);
}
#undef __ADDCONST

@ -0,0 +1,152 @@
#include "lua_Misc.h"
uint32_t lua::PlugManager::AddNewPlug(std::string name,uint32_t size,uint32_t loc)
{
void *p;
if(size!=0)
p=new unsigned char[size];
else
p=(void*)loc;
plugs[name]=p;
return (uint32_t)p;
}
uint32_t lua::PlugManager::FindPlugin(std::string name)
{
mapPlugs::iterator it=plugs.find(name);
if(it!=plugs.end())
return (uint32_t)it->second;
else
return 0;
}
static int LoadMod(lua_State *L)
{
lua::state st(L);
std::string modfile=st.as<std::string>(1);
std::string modname=st.as<std::string>(2);
uint32_t size_add=st.as<uint32_t>(0,3);
OutFile::File f(modfile);
uint32_t size=f.GetTextSize();
uint32_t pos=lua::PlugManager::GetInst().AddNewPlug(modname,size+size_add);
char *buf;
buf=new char[size];
f.GetText(buf);
//std::cout<<"poking @:"<<std::hex<<pos<<"size :"<<size<<std::endl;
DFHack::Core::getInstance().p->write(pos,size,(uint8_t*)buf);
delete [] buf;
st.push(pos);
st.push(size);
return 2;
}
static int LoadObj(lua_State *L)
{
lua::state st(L);
std::string modfile=st.as<std::string>(1);
OutFile::File f(modfile);
size_t s=f.GetTextSize();
void *p=st.newuserdata(s); //TODO does it leak memory??
f.GetText((char*)p);
st.push(s);
return 2;
}
static int FindMarker(lua_State *L) // marker, void ptr, size, start
{
lua::state st(L);
union
{
unsigned char bytes[4];
size_t mark;
}M;
M.mark=st.as<size_t>(1);
unsigned char *p=(unsigned char *)lua_touserdata(L, 2);//st.as<lua::userdata>(2);
size_t size=st.as<size_t>(3);
size_t start=st.as<size_t>(4);
for(size_t i=start;i<size;i++)
{
bool ok;
ok=true;
if(p[i]==M.bytes[0])
{
for(size_t j=0;j<4;j++)
{
if(p[i+j]!=M.bytes[j])
{
ok=false;
break;
}
}
if(ok)
{
st.push(i);
return 1;
}
}
}
return 0;
}
static int LoadObjSymbols(lua_State *L)
{
lua::state st(L);
std::string modfile=st.as<std::string>(1);
OutFile::File f(modfile);
OutFile::vSymbol vec=f.GetSymbols();
OutFile::Symbol S;
st.newtable();
for(size_t i=0;i<vec.size();i++)
{
st.push(i);
S=vec[i];
st.newtable();
st.push(S.name);
st.setfield("name");
st.push(S.pos);
st.setfield("pos");
st.settable();
}
return 1;
}
static int NewMod(lua_State *L)
{
lua::state st(L);
std::string modname=st.as<std::string>(1);
size_t size=st.as<size_t>(2);
size_t loc=st.as<size_t>(3,0);
uint32_t pos=lua::PlugManager::GetInst().AddNewPlug(modname,size,loc);
st.push(pos);
return 1;
}
static int GetMod(lua_State *L)
{
lua::state st(L);
std::string modname=st.as<std::string>(1);
uint32_t pos=lua::PlugManager::GetInst().FindPlugin(modname);
if(pos==0)
st.push();
else
st.push(pos);
return 1;
}
const luaL_Reg lua_misc_func[]=
{
{"loadmod",LoadMod},
{"getmod",GetMod},
{"loadobj",LoadObj},
{"loadobjsymbols",LoadObjSymbols},
{"findmarker",FindMarker},
{"newmod",NewMod},
{NULL,NULL}
};
void lua::RegisterMisc(lua::state &st)
{
st.getglobal("engine");
if(st.is<lua::nil>())
{
st.pop();
st.newtable();
}
lua::RegFunctionsLocal(st, lua_misc_func);
st.setglobal("engine");
}

@ -0,0 +1,2 @@
#include "lune.h"
lua::object *lua::local_object::mytbl=0;