Removed dfusion lua files. Updated plugins.

develop
Warmist 2012-11-11 12:33:54 +02:00
parent f1d4eac700
commit 33f674eee2
37 changed files with 36 additions and 1958 deletions

@ -9,6 +9,3 @@ set(
FILE(GLOB DFUSION_HS include/*)
SET_SOURCE_FILES_PROPERTIES( ${DFUSION_HS} PROPERTIES HEADER_FILE_ONLY TRUE )
DFHACK_PLUGIN(dfusion ${DFUSION_CPPS_ALL} ${DFUSION_HS} LINK_LIBRARIES lua dfhack-tinythread)
# installs into DF root
install(DIRECTORY luafiles/ DESTINATION dfusion)

@ -1,3 +0,0 @@
if not(FILE) then
adv_tools.menu:display()
end

@ -1,514 +0,0 @@
dofile("dfusion/offsets_misc.lua")
STD_STRING=0
DWORD=1
WORD=2
BYTE=3
QWORD=4
DOUBLE=5
FLOAT=6
getline=function (inp)
return dfhack.lineedit(inp or "")
end
io.stdin=nil
function printd(...)
if DEBUG then
print(...)
end
end
function GetTextRegion()
if __TEXT ~=nil then --Chache this, not going to change.
return __TEXT
end
ranges__=Process.getMemRanges()
--print("Ranges:"..#ranges__)
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
--flgs=""
--if(v["read"])then flgs=flgs..'r' end
--if(v["write"])then flgs=flgs..'w' end
--if(v["execute"]) then flgs=flgs..'e' end
--if num>=100 then
--print(string.format("%d %x->%x %s %s",k,v["start"],v["end"],v.name or "",flgs))
--end
local pos=string.find(v.name,"Dwarf Fortress.exe") or string.find(v.name,"libs/Dwarf_Fortress")
if(pos~=nil) and v["execute"] then
__TEXT=v;
return v;
end
end
error(".Text region not found!")
end
function UpdateRanges()
ranges__=Process.getMemRanges()
end
function GetRegionIn(pos)
ranges__=ranges__ or Process.getMemRanges()
for k,v in pairs(ranges__) do
if pos>=v.start and pos<v["end"] then
return v
end
end
return nil
end
function GetRegionIn2(pos)
ranges__=ranges__ or Process.getMemRanges()
local cr=nil
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 then --This is a hack to counter .text region suddenly shrinking.
if cr~=nil then
if v.start < cr.start then -- find region that start is closest
cr=v
end
else
cr=v
end
end
end
return cr
end
function ValidOffset(pos)
ranges__=ranges__ or Process.getMemRanges()
return GetRegionIn(pos)~=nil
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)
UpdateRanges()
local reg=GetRegionIn(pos)
reg.execute=true
reg["write"]=true
Process.setPermisions(reg,reg) -- TODO maybe make a page with only execute permisions or sth
end
-- engine bindings
engine=engine or {}
--[=[ use default peek/pokes for now
engine.peekd=Process.readDWord
engine.poked=Process.writeDWord
engine.peekb=Process.readByte
engine.pokeb=Process.writeByte
engine.peekw=Process.readWord
engine.pokew=Process.writeWord
engine.peekstr_stl=Process.readSTLString
engine.pokestr_stl=Process.writeSTLString
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.peekstr2(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)
elseif rtype==QWORD then
return engine.peekq(offset)
elseif rtype==FLOAT then
return engine.peekfloat(offset)
elseif rtype==DOUBLE then
return engine.peekdouble(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.pokestr2(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)
elseif rtype==QWORD then
return engine.pokeq(offset,val)
elseif rtype==FLOAT then
return engine.pokefloat(offset,val)
elseif rtype==DOUBLE then
return engine.pokedouble(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.FindMarkerCall(moddata,name)
if moddata.symbols[name] ~=nil then
return moddata.symbols[name]+1
end
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
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()
if __VECTORS ~=nil then --chache
return __VECTORS
end
local text=GetTextRegion()
local h=hexsearch(text.start,text["end"],0x8b,ANYBYTE,ANYDWORD,0x8b,ANYBYTE,ANYDWORD,0x2b)
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
__VECTORS=T
return T
end
function GetRaceToken(p) --actually gets token...
local vec=df.global.world.raws.creatures.all
return vec[p].creature_id
end
function BuildNameTable()
local rtbl={}
local vec=df.global.world.raws.creatures.all
--print(string.format("Vector start:%x",vec.st))
--print(string.format("Vector end:%x",vec.en))
--print("Creature count:"..vec.size)
for k=0,#vec-1 do
local name=vec[k].creature_id
--print(k.." "..tostring(name))
rtbl[name]=k
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 getSelectedUnit()
if df.global.ui.main.mode~=23 then
return nil
end
local unit_indx=df.global.ui_selected_unit
if unit_indx<#df.global.world.units.active-1 then
return df.global.world.units.active[unit_indx]
else
return nil
end
end
function getxyz() -- this will return pointers x,y and z coordinates.
local x=df.global.cursor.x
local y=df.global.cursor.y
local z=df.global.cursor.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=df.global.world.units.all -- load all creatures
for i = 0, #vector-1 do -- look into all creatures offsets
local curpos=vector[i].pos --get its coordinates
local cx=curpos.x
local cy=curpos.y
local cz=curpos.z
if cx==x and cy==y and cz==z then --compare them
return vector[i] --return index
end
end
--print("Creature not found!")
return nil
end
function getCreatureAtPointer()
return getCreatureAtPos(getxyz())
end
function getCreature()
local unit=getSelectedUnit()
if unit==nil then
unit=getCreatureAtPointer()
end
--any other selection methods...
return unit
end
function getNemesisId(unit)
for k,v in pairs(unit.refs) do
if df.general_ref_is_nemesisst:is_instance(v) then
return v.nemesis_id
end
end
end
function getNemesis(unit)
local id=getNemesisId(unit)
if id then
return df.nemesis_record.find(id)
end
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

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

@ -1,7 +0,0 @@
.intel_syntax
mov eax , [esp+0x1C] # loop counter
mark_caste:
movsx ecx, word ptr[eax*2+0xdeadbeef]
mark_race:
movzx eax,word ptr [eax*2+0xDEADBEEF]
ret

@ -1,95 +0,0 @@
local dfu=require("plugins.dfusion")
local ms=require("memscan")
local MAX_RACES=100
CustomEmbark=defclass(CustomEmbark,dfu.BinaryPlugin)
local myos=dfhack.getOSType()
if myos=="windows" then
CustomEmbark.ATTRS{filename="dfusion/embark/embark.o",name="CustomEmbark",race_caste_data=DEFAULT_NIL}
CustomEmbark.class_status="valid, not installed"
function CustomEmbark:install()
local stoff=dfhack.internal.getAddress('start_dwarf_count')
if #self.race_caste_data<7 then
error("caste and race count must be bigger than 6")
end
if #self.race_caste_data>MAX_RACES then
error("caste and race count must be less then "..MAX_RACES)
end
if stoff==nil then
error("address for start_dwarf_count not found!")
end
local _,race_id_offset=df.sizeof(df.global.ui:_field("race_id"))
print(string.format("start=%08x",stoff))
local needle={0x0f,0xb7,0x0d} --movzx eax,dword ptr [race_id]
local tmp_table=dfu.dwordToTable(race_id_offset)
for k,v in ipairs(tmp_table) do
table.insert(needle,v)
end
local mem=ms.get_code_segment()
print(mem.uint8_t:addr2idx(stoff))
print(mem.uint8_t:find(needle,mem.uint8_t:addr2idx(stoff)))
local _,trg_offset=mem.uint8_t:find(needle,mem.uint8_t:addr2idx(stoff),nil)--maybe endoff=stoff+bignumber
if trg_offset==nil then
error("address for race_load not found")
end
local call_data={0x90,0x90}
local _,data_offset=df.sizeof(self.data)
dfu.concatTables(call_data,dfu.makeCall(trg_offset+2,data_offset))
self.call_patch=dfu.BinaryPatch{pre_data=needle,data=call_data,address=trg_offset,name="custom_embark_call_patch"}
needle={0x83,0xc8,0xff} -- or eax, 0xFF
local _,caste_offset=mem.uint8_t:find(needle,mem.uint8_t:addr2idx(trg_offset),nil)
if caste_offset==nil or caste_offset-stoff>1000 then
error("Caste change code not found or found too far!")
end
self.disable_castes=dfu.BinaryPatch{pre_data={0x83,0xc8,0xff},data={0x90,0x90,0x90},address=caste_offset,name="custom_embark_caste_disable"}
self.disable_castes:apply()
self.dwarfcount=dfu.BinaryPatch{pre_data=dfu.dwordToTable(7),data=dfu.dwordToTable(#self.race_caste_data),address=stoff,name="custom_embark_embarkcount"}
self.dwarfcount:apply()
local caste_array=self:allocate("caste_array","uint16_t",#self.race_caste_data)
local race_array=self:allocate("race_array","uint16_t",#self.race_caste_data)
self:setEmbarkParty(self.race_caste_data)
for k,v in ipairs(self.race_caste_data) do
caste_array[k-1]=v[2]
race_array[k-1]=v[1]
end
local race_array_off,caste_array_off
local _
_,race_array_off=df.sizeof(race_array)
_,caste_array_off=df.sizeof(caste_array)
self:set_marker_dword("race",caste_array_off) --hehe... mixed them up i guess...
self:set_marker_dword("caste",race_array_off)
self:move_to_df()
self.call_patch:apply()
self.installed=true
end
function CustomEmbark:setEmbarkParty(racesAndCastes)
self.race_caste_data=racesAndCastes
if self.dwarfcount== nil then
self.dwarfcount=dfu.BinaryPatch{pre_data=dfu.dwordToTable(7),data=dfu.dwordToTable(#self.race_caste_data),address=stoff,name="custom_embark_embarkcount"}
self.dwarfcount:apply()
else
self.dwarfcount:repatch(dfu.dwordToTable(#self.race_caste_data))
end
end
function CustomEmbark:status()
if self.installed then
return "valid, installed"
else
return "valid, not installed"
end
end
function CustomEmbark:uninstall()
if self.installed then
self.call_patch:remove()
self.disable_castes:remove()
self.dwarfcount:remove()
end
end
else
CustomEmbark.class_status="invalid, os not supported"
end

@ -1,5 +0,0 @@
if not(FILE)then
names=ParseNames("dfusion/embark/races.txt")--io.open("plugins/embark/races.txt"):lines()
embark(names)
end

@ -1,9 +0,0 @@
ANT_MAN:0
ANT_MAN:0
ANT_MAN:0
ANT_MAN:1
ANT_MAN:1
ANT_MAN:0
ANT_MAN:0
ANT_MAN:2
ANT_MAN:3

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

@ -1,106 +0,0 @@
.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
mark_racepointer:
mov ebx,0xDEADBEEF #write a pointer to the list of allowed races
mark_racecount:
mov ecx,0xDEADBEEF #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
mark_safeloc1:
mov [0xDEADBEEF],eax #write a pointer to safe location (usually after this)
pop eax
pushfd
inc eax #skip one instruction
popfd
push eax
mark_safeloc2:
mov eax,[0xDEADBEEF] #write a pointer to safe location (same as above)
ret

@ -1,45 +0,0 @@
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(list)
local imin=list[1]
for _,v in ipairs(list) 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)
]]--
friendship_in={}
dofile("dfusion/friendship/install.lua")
dofile("dfusion/friendship/patch.lua")
function friendship(names)
friendship_in.install(names)
friendship_in.patch()
end

@ -1,35 +0,0 @@
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

@ -1,57 +0,0 @@
function friendship_in.patch()
UpdateRanges()
pos=GetTextRegion().start
local _,crace=df.sizeof(df.global.ui:_field("race_id"))
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))
--TODO read offset from memory.xml
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

@ -1,18 +0,0 @@
if not(FILE) then
--sanity test
--print("race num:"..engine.peekw(offsets.getEx("CurrentRace")))
--print(string.format("%x vs %x",offsets.getEx("CurrentRace"),VersionInfo.getGroup("Creatures"):getAddress("current_race")))
print("Race num:"..df.global.ui.race_id)
print("Your current race is:"..GetRaceToken(df.global.ui.race_id))
print("If this is wrong please type 'q'")
if(getline()=='q') then
return
end
end
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

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

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

@ -1,41 +0,0 @@
.intel_syntax
eaxpart:
push eax
push ecx
jmp compare
ecxpart:
push eax
push ecx
mov eax,ecx
compare:
push ebx
mov ebx,0xDEADBEEF #write a pointer to the list of allowed civs
mov ecx,2000 #write a number of allowed civs
loop1:
cmp [ebx+ecx*4],eax
jnz endok
dec ecx
cmp ecx ,-1
jnz loop1
pop ebx
jmp fail
endok:
pop ebx
cmp eax,eax
jmp endfinal
fail:
xor ecx,ecx
xor eax,eax
inc eax
cmp eax,ebx
endfinal:
pop ecx
pop eax
ret

@ -1,89 +0,0 @@
friendship_civ={}
function friendship_civ.init()
friendship_civ.count=0x0f
friendship_civ.firsttime=true
local mypos=engine.getmod("Friendship_civ")
local modpos=0
if mypos then
modpos=mypos
_,modsize=engine.loadobj("dfusion/friendship_civ/friendship_c.o")
_=nil
friendship_civ.firsttime=false
else
modpos,modsize=engine.loadmod("dfusion/friendship_civ/friendship_c.o","Friendship_civ",1024)
print(string.format("Loaded module @:%x",modpos))
end
friendship_civ.modpos=modpos
friendship_civ.modsize=modsize
end
function friendship_civ.install(civs)
friendship_civ.init()
local count=0
for _,v in pairs(civs) do
engine.poked(friendship_civ.modpos+friendship_civ.modsize+count*4,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(friendship_civ.modpos+0x0a,friendship_civ.modpos+friendship_civ.modsize) -- set ptr to civ ids
engine.poked(friendship_civ.modpos+friendship_civ.count,count-1) -- set count of civs
SetExecute(friendship_civ.modpos)
if(friendship_civ.firsttime) then
friendship_civ.patch()
end
end
function friendship_civ.getcivs()
if(friendship_civ.firsttime==nil)then
return nil
end
friendship_civ.init()
local count=engine.peekd(friendship_civ.modpos+friendship_civ.count)+1
local ret={}
for i=0, count-1 do
table.insert(ret,engine.peekd(friendship_civ.modpos+friendship_civ.modsize+i*4))
end
return ret
end
function friendship_civ.addciv(civ) --if called with nil add current civ :)
if civ==nil then
local cciv=engine.peekd(VersionInfo.getGroup("Creatures"):getAddress("current_civ"))
friendship_civ.install({cciv})
return
end
local oldcivs=friendship_civ.getcivs()
oldcivs=oldcivs or {}
if type(civ)=="table" then
for k,v in ipairs(civ) do
table.insert(oldcivs,v)
end
else
table.insert(oldcivs,civ)
end
friendship_civ.install(oldcivs)
end
function friendship_civ.patch_call(off,iseax)
local calltrg=friendship_civ.modpos
if not iseax then
calltrg=calltrg+4
end
engine.pokeb(off,0xe8) --this is a call
engine.poked(off+1,calltrg-off-5) --offset to call to (relative)
engine.pokeb(off+5,0x90) --nop
end
function friendship_civ.patch()
--UpdateRanges()
local civloc= VersionInfo.getGroup("Creatures"):getAddress("current_civ")
local pos1=offsets.findall(0,0x3B,0x05,DWORD_,civloc) --eax
for k,v in pairs(pos1) do print(string.format("%d %x",k,v)) end
local pos2=offsets.findall(0,0x3B,0x0D,DWORD_,civloc) --ecx
for k,v in pairs(pos2) do print(string.format("%d %x",k,v)) end
for k,v in pairs(pos1) do
print(string.format("Patching eax compare %d: %x",k,v))
friendship_civ.patch_call(v,true)
end
for k,v in pairs(pos2) do
print(string.format("Patching ecx compare %d: %x",k,v))
friendship_civ.patch_call(v,false)
end
end

@ -1,57 +0,0 @@
fc_ui={}
fc_ui.menu=MakeMenu()
function fc_ui.get()
local mycivs=friendship_civ.getcivs()
if mycivs~= nil then
print(" Currently friendly civs:")
for k,v in pairs(mycivs) do
print(string.format("%d. %d",k,v))
end
else
print(" Plugin no yet activated.")
end
end
function fc_ui.add()
print("Type in civ id to add (leave empty to add current, q cancels):")
local r
while r==nil and r~='q' do
r=io.stdin:read()
if r=="" then
r=nil
break
end
if r~='q' then r=tonumber(r) else
return
end
end
friendship_civ.addciv(r)
end
function fc_ui.remove()
local mycivs=friendship_civ.getcivs()
if mycivs~= nil then
print(" Currently friendly civs:")
for k,v in pairs(mycivs) do
print(string.format("%d. %d",k,v))
end
else
print(" Plugin no yet activated, nothing to remove.")
return
end
print("Type in civ id to remove( q cancels):")
local r
while r==nil and r~='q' do
r=io.stdin:read()
if r~='q' then
r=tonumber(r)
if r>#mycivs then r=nil end
else
return
end
end
table.remove(mycivs,r)
friendship_civ.install(mycivs)
end
fc_ui.menu:add("Add civ",fc_ui.add)
fc_ui.menu:add("Get civs",fc_ui.get)
fc_ui.menu:add("Remove civ",fc_ui.remove)
fc_ui.menu:display()

@ -1,92 +0,0 @@
function dofile(filename) --safer dofile, with traceback (very usefull)
f,perr=loadfile(filename)
if f~=nil then
return safecall(f)
else
print(perr)
end
end
function dofile_silent(filename) --safer dofile, with traceback, no file not found error
f,perr=loadfile(filename)
if f~=nil then
return safecall(f)
else
if(string.sub(perr,1,11)~="cannot open") then --ugly hack
print(perr)
end
end
end
function loadall(t1) --loads all non interactive plugin parts, so that later they could be used
for k,v in pairs(t1) do
dofile_silent("dfusion/"..v[1].."/init.lua")
end
end
function mainmenu(t1)
while true do
print("No. Name Desc")
for k,v in pairs(t1) do
print(string.format("%3d %15s %s",k,v[1],v[2]))
end
local q=dfhack.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
if t1[q][3]==nil then
dofile("dfusion/"..t1[q][1].."/plugin.lua")
else
t1[q][3]()
end
end
end
end
end
function RunSaved()
print("Locating saves...")
local str=df.global.world.cur_savegame.save_dir
print("Current region:"..str)
str="data/save/"..str.."/dfusion/init.lua"
print("Trying to run:"..str)
dofile_silent(str)
end
dofile("dfusion/common.lua")
dofile("dfusion/utils.lua")
dofile("dfusion/offsets_misc.lua")
dofile("dfusion/editor.lua")
unlockDF()
plugins={}
table.insert(plugins,{"simple_embark","A simple embark dwarf count editor"})
table.insert(plugins,{"tools","some misc tools"})
table.insert(plugins,{"embark","Multi race embark"})
table.insert(plugins,{"friendship","Multi race fort enabler"})
--[=[table.insert(plugins,{"items","A collection of item hacking tools"})
table.insert(plugins,{"offsets","Find all offsets"})
table.insert(plugins,{"friendship_civ","Multi civ fort enabler"})
table.insert(plugins,{"triggers","a function calling plug (discontinued...)"})
table.insert(plugins,{"migrants","multi race imigrations"})
--]=]
--table.insert(plugins,{"onfunction","run lua on some df function"})
--table.insert(plugins,{"editor","edit internals of df",EditDF})
table.insert(plugins,{"saves","run current worlds's init.lua",RunSaved})
table.insert(plugins,{"adv_tools","some tools for (mainly) adventurer hacking"})
loadall(plugins)
dofile_silent("dfusion/initcustom.lua")
local args={...}
local f,err=load(table.concat(args,' '))
if f then
f()
else
dfhack.printerr(err)
end
if not INIT then
mainmenu(plugins)
end

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

@ -1,62 +0,0 @@
--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",400)
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
_,raceoff=df.sizeof(df.global.ui:_field('race_id'))
pos=offsets.find(offsets.base(),0xa1,DWORD_,raceoff,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

@ -1,20 +0,0 @@
.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

@ -1,5 +0,0 @@
if not(FILE) then
names=ParseNames("dfusion/migrants/races.txt")--io.open("plugins/migrants/races.txt"):lines()
migrants(names)
end

@ -1,29 +0,0 @@
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

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

@ -1,48 +0,0 @@
offsets=offsets or {}
function offsets.find(startoffset,...)
-- [=[
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)
if reg==nil then
print(string.format("Warning: memory range for search @:%x not found!",startoffset))
return 0
end
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
ADDRESS=ANYDWORD

@ -1,23 +0,0 @@
function simple_embark(num)
local stoff=dfhack.internal.getAddress('start_dwarf_count')
print("Starting dwarves found:"..df.reinterpret_cast('int32_t', stoff).value)
local tmp_val=df.new('int32_t')
local size,pos=tmp_val:sizeof()
tmp_val.value=num
local ret=dfhack.internal.patchMemory(stoff,tmp_val,size)
if ret then
print("Success!")
else
qerror("Failed to patch in number")
end
end
if not(FILE) then
print("Type in new amount (more than 6, less than 15000):")
repeat
ans=tonumber(io.read())
if ans==nil or not(ans<=15000 and ans>0) then
print("incorrect choice")
end
until ans~=nil and (ans<=15000 and ans>0)
simple_embark(ans)
end

@ -1,511 +0,0 @@
local ms=require "memscan"
tools={}
tools.menu=MakeMenu()
function tools.setrace(name)
RaceTable=BuildNameTable()
print("Your current race is:"..GetRaceToken(df.global.ui.race_id))
local id
if name == nil then
print("Type new race's token name in full caps (q to quit):")
repeat
entry=getline()
if entry=="q" then
return
end
id=RaceTable[entry]
until id~=nil
else
id=RaceTable[name]
if id==nil then
error("Name not found!")
end
end
df.global.ui.race_id=id
end
tools.menu:add("Set current race",tools.setrace)
function tools.GiveSentience(names)
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=getline()
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 races=df.global.world.raws.creatures.all
local castes=races[id].caste
print(string.format("Caste count:%i",castes.size))
for i =0,#castes-1 do
print("Caste name:"..castes[i].caste_id.."...")
local flags=castes[i].flags
--print(string.format("%x",flagoffset))
if flags.CAN_SPEAK then
print("\tis sentient.")
else
print("\tnon sentient. Allocating IQ...")
flags.CAN_SPEAK=true
end
end
end
end
tools.menu:add("Give Sentience",tools.GiveSentience)
function tools.embark() --windows only?
local seg=ms.get_code_segment()
local idx,off
idx,off=seg.uint8_t:find_one{0x66, 0x83, 0x7F ,0x1A ,0xFF,0x74,0x04}
if idx then
local tmp_val=df.new('uint8_t',2)
tmp_val[0]=0x90
tmp_val[1]=0x90
local size,pos=tmp_val:sizeof()
local ret=dfhack.internal.patchMemory(off+5,pos,size*2)
if ret then
print("Found and patched:",off+5)
else
print("Patching failed at:",off+5)
end
tmp_val:delete()
else
qerror("Offset for embark patch not found!")
end
end
if WINDOWS then
tools.menu:add("Embark anywhere",tools.embark)
end
function tools.getCreatureId(vector) --redo it to getcreature by name/id or something
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=getline()
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(unit,nemesis)
if nemesis==nil then
nemesis=true --default value is nemesis switch too.
end
if unit==nil then
unit=getCreatureAtPointer()
end
if unit==nil then
error("Invalid unit!")
end
local other=df.global.world.units.active
local unit_indx
for k,v in pairs(other) do
if v==unit then
unit_indx=k
break
end
end
if unit_indx==nil then
error("Unit not found in array?!") --should not happen
end
other[unit_indx]=other[0]
other[0]=unit
if nemesis then --basicly copied from advtools plugin...
local nem=getNemesis(unit)
local other_nem=getNemesis(other[unit_indx])
if other_nem then
other_nem.flags[0]=false
other_nem.flags[1]=true
end
if nem then
nem.flags[0]=true
nem.flags[2]=true
for k,v in pairs(df.global.world.nemesis.all) do
if v.id==nem.id then
df.global.ui_advmode.player_id=k
end
end
else
error("Current unit does not have nemesis record, further working not guaranteed")
end
end
end
tools.menu:add("Change Adventurer",tools.change_adv)
function tools.MakeFollow(unit,trgunit)
if unit == nil then
unit=getCreature()
end
if unit== nil then
error("Invalid creature")
end
if trgunit==nil then
trgunit=df.global.world.units.active[0]
end
unit.relations.group_leader_id=trgunit.id
local u_nem=getNemesis(unit)
local t_nem=getNemesis(trgunit)
if u_nem then
u_nem.group_leader_id=t_nem.id
end
if t_nem and u_nem then
t_nem.companions:insert(#t_nem.companions,u_nem.id)
end
end
tools.menu:add("Make creature follow",tools.MakeFollow)
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=getline();
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=getline()
end
end
end
print("Type which to change (q cancels):")
repeat
r=getline()
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=getline()
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.project(unit,trg)
if unit==nil then
unit=getCreatureAtPointer()
end
if unit==nil then
error("Failed to project unit. Unit not selected/valid")
end
-- todo: add projectile to world, point to unit, add flag to unit, add gen-ref to projectile.
local p=df.proj_unitst:new()
local startpos={x=unit.pos.x,y=unit.pos.y,z=unit.pos.z}
p.origin_pos=startpos
p.target_pos=trg
p.cur_pos=startpos
p.prev_pos=startpos
p.unit=unit
--- wtf stuff
p.unk14=100
p.unk16=-1
p.unk23=-1
p.fall_delay=5
p.fall_counter=5
p.collided=true
-- end wtf
local citem=df.global.world.proj_list
local maxid=1
local newlink=df.proj_list_link:new()
newlink.item=p
while citem.item~= nil do
if citem.item.id>maxid then maxid=citem.item.id end
if citem.next ~= nil then
citem=citem.next
else
break
end
end
p.id=maxid+1
newlink.prev=citem
citem.next=newlink
local proj_ref=df.general_ref_projectile:new()
proj_ref.projectile_id=p.id
unit.refs:insert(#unit.refs,proj_ref)
unit.flags1.projectile=true
end
function tools.empregnate(unit)
if unit==nil then
unit=getSelectedUnit()
end
if unit==nil then
unit=getCreatureAtPos(getxyz())
end
if unit==nil then
error("Failed to empregnate. Unit not selected/valid")
end
if unit.curse then
unit.curse.add_tags2.STERILE=false
end
local genes = unit.appearance.genes
if unit.relations.pregnancy_ptr == nil then
print("creating preg ptr.")
if false then
print(string.format("%x %x",df.sizeof(unit.relations:_field("pregnancy_ptr"))))
return
end
unit.relations.pregnancy_ptr = { new = true, assign = genes }
end
local ngenes = unit.relations.pregnancy_ptr
if #ngenes.appearance ~= #genes.appearance or #ngenes.colors ~= #genes.colors then
print("Array sizes incorrect, fixing.")
ngenes:assign(genes);
end
print("Setting preg timer.")
unit.relations.pregnancy_timer=10
unit.relations.pregnancy_mystery=1
end
tools.menu:add("Empregnate",tools.empregnate)
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=getline()
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.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=getline()
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(getline())
print("enter x1:")
xe=tonumber(getline())
print("enter y0:")
ys=tonumber(getline())
print("enter y1:")
ye=tonumber(getline())
print("enter z0:")
zs=tonumber(getline())
print("enter z1:")
ze=tonumber(getline())
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

@ -1,8 +0,0 @@
if not(FILE) then
--tools.menu:add("Change site type",tools.changesite)
--tools.menu:add("Change site flags",tools.changeflags)
--tools.menu:add("Hostilate creature",tools.hostilate)
--tools.menu:add("Print current mouse block",tools.mouseBlock)
tools.menu:display()
end

@ -1 +0,0 @@
function findVectorsSized(size) local ret={} local text=GetTextRegion() for k,v in pairs(offsets.getvectors()) do if GetRegionIn2(k)~=nil then --if v>4 then local tv=engine.peek(k,ptr_vector) if tv:size() == size then print(string.format("%x is size %d",k,size)) table.insert(ret,k) end end end return ret end function findMaterial(mattype,matname) --currently only stones local tbl=BuildMaterialTable() return tbl[matname] end function iter(tbl) if getmetatable(tbl) ~=nil then if getmetatable(tbl).__next~= nil then return getmetatable(tbl).__next,tbl else return getmetatable(tbl).__pairs(tbl) or pairs(tbl) end else return pairs(tbl) end end

@ -3,22 +3,34 @@ local dfu=require("plugins.dfusion")
local ms=require("memscan")
local MAX_RACES=100
CustomEmbark=defclass(CustomEmbark,dfu.BinaryPlugin)
CustomEmbark.name="CustomEmbark"
print(t)
local myos=dfhack.getOSType()
if myos=="windows" then
CustomEmbark.ATTRS{filename="hack/lua/plugins/dfusion/embark.o",name="CustomEmbark",race_caste_data=DEFAULT_NIL}
CustomEmbark.class_status="valid, not installed"
function CustomEmbark:install()
local stoff=dfhack.internal.getAddress('start_dwarf_count')
if #self.race_caste_data<7 then
function CustomEmbark:parseRaces(races)
if #races<7 then
error("caste and race count must be bigger than 6")
end
if #self.race_caste_data>MAX_RACES then
if #races>MAX_RACES then
error("caste and race count must be less then "..MAX_RACES)
end
local n_to_id=require("plugins.dfusion.tools").build_race_names()
local ids={}
for k,v in pairs(races) do
local race=v[1] or v
ids[k]={}
ids[k][1]=n_to_id[race]
if ids[k][1]==nil then qerror(race.." not found!") end
ids[k][2]=v[2] or -1
end
self.race_caste_data=ids
end
function CustomEmbark:install(race_caste_data)
local stoff=dfhack.internal.getAddress('start_dwarf_count')
if race_caste_data~=nil then
self:parseRaces(race_caste_data)
end
if stoff==nil then
error("address for start_dwarf_count not found!")
end
@ -40,14 +52,14 @@ if myos=="windows" then
local call_data={0x90,0x90}
local _,data_offset=df.sizeof(self.data)
dfu.concatTables(call_data,dfu.makeCall(trg_offset+2,data_offset))
self.call_patch=dfu.BinaryPatch{pre_data=needle,data=call_data,address=trg_offset,name="custom_embark_call_patch"}
self.call_patch=self.call_patch or dfu.BinaryPatch{pre_data=needle,data=call_data,address=trg_offset,name="custom_embark_call_patch"}
needle={0x83,0xc8,0xff} -- or eax, 0xFF
local _,caste_offset=mem.uint8_t:find(needle,mem.uint8_t:addr2idx(trg_offset),nil)
if caste_offset==nil or caste_offset-stoff>1000 then
error("Caste change code not found or found too far!")
end
self.disable_castes=dfu.BinaryPatch{pre_data={0x83,0xc8,0xff},data={0x90,0x90,0x90},address=caste_offset,name="custom_embark_caste_disable"}
self.disable_castes=self.disable_castes or dfu.BinaryPatch{pre_data={0x83,0xc8,0xff},data={0x90,0x90,0x90},address=caste_offset,name="custom_embark_caste_disable"}
self.disable_castes:apply()
@ -66,16 +78,11 @@ if myos=="windows" then
self.call_patch:apply()
self.installed=true
end
function CustomEmbark:setEmbarkParty(racesAndCastes)
local stoff=dfhack.internal.getAddress('start_dwarf_count')
if #racesAndCastes<7 then
error("caste and race count must be bigger than 6")
end
if #racesAndCastes>MAX_RACES then
error("caste and race count must be less then "..MAX_RACES)
end
self.race_caste_data=racesAndCastes
if self.dwarfcount== nil then
self.dwarfcount=dfu.BinaryPatch{pre_data=dfu.dwordToTable(7),data=dfu.dwordToTable(#self.race_caste_data),address=stoff,name="custom_embark_embarkcount"}
self.dwarfcount:apply()
@ -84,8 +91,9 @@ if myos=="windows" then
end
local caste_array=self:get_or_alloc("caste_array","uint16_t",MAX_RACES)
local race_array=self:get_or_alloc("race_array","uint16_t",MAX_RACES)
for k,v in ipairs(self.race_caste_data) do
caste_array[k-1]=v[2]
caste_array[k-1]=v[2] or -1
race_array[k-1]=v[1]
end
end
@ -103,48 +111,14 @@ if myos=="windows" then
self.dwarfcount:remove()
end
end
function CustomEmbark:edit()
local data=self.race_caste_data or {}
print(string.format("Old race count:%d",#data))
local endthis=false
print("current:")
while(not endthis) do
print(" # RaceId Race name Caste num")
for k,v in pairs(data) do
local name=df.creature_raw.find(v[1]).creature_id or ""
print(string.format("%3d. %6d %20s %d",k,v[1],name,v[2]))
end
print("a- add, r-remove, c-cancel, s-save and update")
local choice=io.stdin:read()
if choice=='a' then
print("Enter new race then caste ids:")
local race=tonumber(io.stdin:read())
local caste=tonumber(io.stdin:read())
if race and caste then
table.insert(data,{race,caste})
else
print("input parse error")
end
elseif choice=='r' then
print("enter number to remove:")
local num_rem=tonumber(io.stdin:read())
if num_rem~=nil then
table.remove(data,num_rem)
end
elseif choice=='c' then
endthis=true
elseif choice=='s' then
endthis=true
if self.installed then
self:setEmbarkParty(data)
else
self.race_caste_data=data
self:install()
end
end
function CustomEmbark:unload()
self:uninstall()
if Embark~=nil then
Embark=nil
end
end
Embark=Embark or CustomEmbark()
else
CustomEmbark.class_status="invalid, os not supported"
CustomEmbark.status=function() return"invalid, os not supported" end
end
return _ENV

@ -35,7 +35,7 @@ function FriendshipRainbow:find_all()
dfu.concatTables(locations,self:find_one(code,{0x0f,0xbf,reg},crace)) --movsx reg,[ptr]
dfu.concatTables(locations,self:find_one(code,{0x66,0x8b,reg},crace)) --mov reg,[ptr]
end
printall(locations)
return self:filter_locations(code,locations)
end
function FriendshipRainbow:filter_locations(codesg,locations)
@ -107,5 +107,6 @@ function FriendshipRainbow:install(races)
local addr=self:move_to_df()
self:patchCalls(addr)
self.installed=true
end
end
Friendship=Friendship or FriendshipRainbow()
return _ENV