Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: 1 ... 8 9 [10] 11 12 ... 243

Author Topic: DFHack 50.13-r1  (Read 810220 times)

Moonshine Fox

  • Bay Watcher
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #135 on: July 05, 2017, 01:09:11 am »

Hmm, problem still persists even though I've removed the Weapon Traps. Mind you, the traps were not completed, they were only planned, so no one could've stepped in them.

Try TWBT 5.xx (not Next). There's a bug in Next that may cause crashes.
After about half an hour of testing, this seems to have done the trick.
Logged

Atkana

  • Bay Watcher
  • [CURIOUSBEAST]
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #136 on: July 05, 2017, 11:48:36 am »

Hey, I made a few of modtools for some features I encountered that didn't have any, and since I don't yet know how to github I figured I should share them here and maybe someone'll be kind enough to github magic them if they're acceptable (may need testing) :P + I have a question relating to them, anyways.
The first is modtools/set-need. Mainly inspired by how Masterwork has recreational workshops to give workers good thoughts, I made this with the intention of mostly being used in conjunction with reaction-trigger to have reactions that can fulfill a worker's needs:
Code: (modtools/set-need.lua) [Select]
-- Change focus level of needs for units

local usage = [====[

modtools/set-need
=====================
This allows for modifying the focus levels for needs on units.

Arguments:

-need id
the id/type of the need to change. Alternatively "all" to apply the value to all.
examples:
1
DrinkAlcohol
all
-value
the value to set focus to. Defaults to 400 if not included (the value focus resets to when normally fulfilled in game).
Negative values need to have a \ before the negative symbol
examples:
250
\-5000
-target id
        the unit id of the target unit. If unspecified, will check for a selected unit.
        examples:
            0
            28
-needlist
displays a list of need ids.

]====]

local utils = require 'utils'

validArgs = validArgs or utils.invert({
'help',
'needlist',
'need',
'value',
'target'
})

local args = utils.processArgs({...}, validArgs)

if args.help then
print(usage)
return
end

if args.needlist then
for i,v in ipairs(df.need_type)do
print(i .. " (" .. v .. ")")
end
return
end

--Find the target
local targ
if not args.target then
if dfhack.gui.getSelectedUnit(true) then
targ =  dfhack.gui.getSelectedUnit(true)
else
error 'Specify a target'
end
else
if df.unit.find(tonumber(args.target)) then
targ = df.unit.find(tonumber(args.target))
else
error ('Could not find target: '.. args.target)
end
end
args.target = targ

--Work out the need
local doAll
if not args.need then
error 'Specify a need'
end

if (args.need):lower() == "all" then
doAll = true
elseif  tonumber(args.need) then
args.need = tonumber(args.need)
elseif df.need_type[args.need] then
args.need = df.need_type[args.need]
else
error 'Invalid need'
end

--Set the value
args.value = tonumber(args.value) or 400

--Doing the thing
local currentNeedTableId
for i, v in ipairs(args.target.status.current_soul.personality.needs) do
if doAll or v.id == args.need then
v.focus_level = args.value
if not doAll then
return
end
end
end

The second and third are similar scripts I made as part of setting up a groundwork for when I eventually get around to making a values/personality GUI editor: modtools/set-belief and modtools/set-personality.
Code: (modtools/set-belief) [Select]
-- Change beliefs value of a unit
--[[ Issues/Potential changes
- Doesn't cause needs to change
- Changes don't respect creature's cultural weights (not sure how you'd model that, anyway)
- Step sets to a particular value rather than a random range
]]

local usage = [====[

modtools/set-belief
=====================
This allows for altering the beliefs of units.

Arguments:

-belief #
the id/token of the belief to change. Alternatively "all" to apply the value to all... if you want to do that for some reason.
examples:
1
LOYALTY
all
-value #
the value to set the belief strength to. Defaults to 0
examples:
-15
45
-step #
alternative to value. Increase/decrease along description levels by #.
Negative values need to have a \ before the negative symbol.
examples:
2
\-1
-add #
alternative to value. Adds to current value.
Negative values need to have a \ before the negative symbol.
examples:
15
\-20
Without valid value/step/add, defaults to value style at 0.
-target #
        the unit id of the target unit. If unspecified, will check for a selected unit.
        examples:
            0
            28
-belieflist
displays a list of need ids.

]====]

local utils = require 'utils'

validArgs = validArgs or utils.invert({
'help',
'belieflist',
'belief',
'value',
'target',
'step',
'add'
})

local args = utils.processArgs({...}, validArgs)

if args.help then
print(usage)
return
end

if args.belieflist then
for i,v in ipairs(df.value_type)do
print(i .. " (" .. v .. ")")
end
return
end

--Find the target
local targ
if not args.target then
if dfhack.gui.getSelectedUnit(true) then
targ =  dfhack.gui.getSelectedUnit(true)
else
error 'Specify a target'
end
else
if df.unit.find(tonumber(args.target)) then
targ = df.unit.find(tonumber(args.target))
else
error ('Could not find target: '.. args.target)
end
end
args.target = targ

--Checks has a soul, probably
if not targ.status.current_soul then
error 'Unit has no soul'
end

--Store shorthand for use later
local beliefs = args.target.status.current_soul.personality.values

--Work out the trait
local doAll
if not args.belief then
error 'Specify a belief'
end

if (args.belief):lower() == "all" then
doAll = true
elseif  tonumber(args.belief) then
args.belief = tonumber(args.belief)
elseif df.value_type[args.belief] then
args.belief = df.value_type[args.belief]
else
error 'Invalid belief'
end

local ranges = {
[1] = {["low"] = -50, ["high"] = -41, ["mid"] = -45},
[2] = {["low"] = -40, ["high"] = -26, ["mid"] = -33},
[3] = {["low"] = -25, ["high"] = -11, ["mid"] = -18},
[4] = {["low"] = -10, ["high"] = 10, ["mid"] = 0},
[5] = {["low"] = 11, ["high"] = 25, ["mid"] = 18},
[6] = {["low"] = 26, ["high"] = 40, ["mid"] = 33},
[7] = {["low"] = 41, ["high"] = 50, ["mid"] = 45}
}

local function clamp(val, low, high)
if val < low then
return low
elseif val > high then
return high
end
return val
end

local function getStep(value)
for i,v in ipairs(ranges) do
if (value >= v.low) and (value <= v.high) then
return i
end
end
end

local pointers = {}
--[[ Structure: pointers[#1] = #2
#1 is the value's type
#2 is the index entry for unit.status.current_soul.personality.values
]]
local function buildPointers()
for i, v in ipairs(beliefs) do
pointers[v.type] = i
end
end

--Returns unit's current value for given belief
local function getCurBeliefValue(unit, beliefId)
local upers = unit.status.current_soul.personality
if pointers[beliefId] then
return upers.values[pointers[beliefId]].strength
elseif upers.cultural_identity ~= -1 then
return df.cultural_identity.find(upers.cultural_identity).values[beliefId]
else
return 0 --outsiders have no culture
end
end

--Ultimately changes value strength. Changes an existing entry if possible, otherwise creates a new one. Uses pointers.
local function changeBelief(beliefId, value)
local upers = args.target.status.current_soul.personality
local value = clamp(value, -50, 50)
if pointers[beliefId] then --belief already exists on unit
upers.values[pointers[beliefId]].strength = value
--Done!
else --Makes new belief (assumes it's fine to have a personal value entry that's technically the same step as their culture's)
upers.values:insert("#", {new = df.unit_personality.T_values, type = beliefId, strength = value})
--Add this new info to pointers, in case of doAll
pointers[beliefId] = #upers.values-1
--Done!
end
end

local function stepUp(beliefId)
local curStep = getStep(getCurBeliefValue(args.target, beliefId))
local changed = clamp(curStep + args.step, 1, 7)
changeBelief(beliefId, ranges[changed].mid)
end

--Setup for add changes
local function doAdd(beliefId)
changeBelief(beliefId, getCurBeliefValue(args.target, beliefId) + args.add) --No need to check if new value would be beyond range, value is clamped during changeBelief()
end

--Before making changes, make a table that records the unit's individual beliefs
buildPointers()

--Both check for a valid value/alternative and do the thing
if tonumber(args.step) then --Do steps
if doAll then
for i,v in ipairs(df.value_type) do
stepUp(i)
end
else
stepUp(args.belief)
end
return
elseif tonumber(args.add) then --Do adds
if doAll then
for i,v in ipairs(df.value_type) do
doAdd(i)
end
else
doAdd(args.belief)
end
return
else --Doing value or defaulting to value
if not tonumber(args.value) then --If value is missing or invalid, set to 0
args.value = 0
end
--Do values
if doAll then
for i,v in ipairs(df.value_type) do
changeBelief(i, args.value)
end
else
changeBelief(args.belief, args.value)
end
return
end
Code: (modtools/set-personality) [Select]
-- Change personality trait value of a unit
--[[ Issues/Potential changes
- Doesn't cause needs to change
- Changes don't respect target creature's natural limits
- Step sets to a particular value rather than a random range
]]


local usage = [====[

modtools/set-personality
=====================
This allows for altering the personality of units.

Arguments:

-trait #
the id/token of the trait to change. Alternatively "all" to apply the value to all... if you want to do that for some reason.
examples:
1
HATE_PROPENSITY
all
-value #
the value to set the personality to. Defaults to 50
examples:
0
75
-step #
alternative to value. Increase/decrease along description levels by #.
Negative values need to have a \ before the negative symbol
examples:
2
\-1
-add #
alternative to value. Adds to current value.
Negative values need to have a \ before the negative symbol.
examples:
15
\-20
Without valid value/step/add, defaults to value style at 50.
-target #
        the unit id of the target unit. If unspecified, will check for a selected unit.
        examples:
            0
            28
-traitlist
displays a list of need ids.

]====]

local utils = require 'utils'

validArgs = validArgs or utils.invert({
'help',
'traitlist',
'trait',
'value',
'target',
'step',
'add'
})

local args = utils.processArgs({...}, validArgs)

if args.help then
print(usage)
return
end

if args.traitlist then
for i,v in ipairs(df.personality_facet_type)do
print(i .. " (" .. v .. ")")
end
return
end

--Find the target
local targ
if not args.target then
if dfhack.gui.getSelectedUnit(true) then
targ =  dfhack.gui.getSelectedUnit(true)
else
error 'Specify a target'
end
else
if df.unit.find(tonumber(args.target)) then
targ = df.unit.find(tonumber(args.target))
else
error ('Could not find target: '.. args.target)
end
end
args.target = targ

--Checks has a soul, probably
if not targ.status.current_soul then
error 'Unit has no soul'
end

--Store shorthand for use later
local traits = args.target.status.current_soul.personality.traits

--Work out the trait
local doAll
if not args.trait then
error 'Specify a trait'
end

if (args.trait):lower() == "all" then
doAll = true
elseif  tonumber(args.trait) then
args.trait = tonumber(args.trait)
elseif df.personality_facet_type[args.trait] then
args.trait = df.personality_facet_type[args.trait]
else
error 'Invalid trait'
end

local ranges = {
[1] = {["low"] = 0, ["high"] = 9, ["mid"] = 5},
[2] = {["low"] = 10, ["high"] = 24, ["mid"] = 17},
[3] = {["low"] = 25, ["high"] = 39, ["mid"] = 32},
[4] = {["low"] = 40, ["high"] = 60, ["mid"] = 50},
[5] = {["low"] = 61, ["high"] = 75, ["mid"] = 68},
[6] = {["low"] = 76, ["high"] = 90, ["mid"] = 83},
[7] = {["low"] = 91, ["high"] = 100, ["mid"] = 95}
}

local function clamp(val, low, high)
if val < low then
return low
elseif val > high then
return high
end
return val
end

local function getStep(value)
for i,v in ipairs(ranges) do
if (value >= v.low) and (value <= v.high) then
return i
end
end
end

--Ultimately change the trait
local function setValue(traitId, value)
traits[traitId] = clamp(value, 0, 100)
end

--Changes the trait value using step style
local function stepUp(traitId)
local curStep = getStep(traits[traitId])
local changed = clamp(curStep + args.step, 1, 7)
setValue(traitId, ranges[changed].mid) --In theory could instead have a random number between low and high
end

local function doAdd(traitId)
setValue(traitId, traits[traitId] + args.add)
end

--Both check for a valid value/alternative and do the thing
if tonumber(args.step) then
--Do step
if doAll then
for i,v in ipairs(traits) do
stepUp(i)
end
else
stepUp(args.trait)
end
return
elseif tonumber(args.add) then
--Do add
if doAll then
for i,v in ipairs(traits) do
doAdd(i)
end
else
doAdd(args.trait)
end
return
else --Doing value or defaulting to value
if not tonumber(args.value) then
args.value = 50
end
if doAll then
for i,v in ipairs(traits) do
setValue(i, args.value)
end
else
setValue(args.trait, args.value)
end
return
end

These two have a problem, however - while they successfully change the unit's values/personality, the unit's needs don't update to reflect the changes. Does anyone know how to make DF recalculate a unit's needs, or am I going to have to make a script to do it?
« Last Edit: July 06, 2017, 01:39:56 am by Atkana »
Logged

Max™

  • Bay Watcher
  • [CULL:SQUARE]
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #137 on: July 06, 2017, 12:11:05 am »

I could swear there was something that did a recalculation of unit status somewhere, and that beliefs script is handy, can't believe I didn't think about the lack of one before, I've just done it manually with gm-editor when I wanted to change them.
Logged

lethosor

  • Bay Watcher
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #138 on: July 06, 2017, 12:13:55 pm »

Some Python experiments (with Python 3.6):

Spoiler (click to show/hide)

It doesn't support much yet, and there are some stability issues. It doesn't support accessing DF memory or running scripts directly from the console (it uses a "pyscript" command for that right now, but I'm working on a better way to allow plugins to register their own script types). I've come up with some ways that could make most of the Lua API available to Python, though, so that should be an improvement over the Ruby plugin.
Logged
DFHack - Dwarf Manipulator (Lua) - DF Wiki talk

There was a typo in the siegers' campfire code. When the fires went out, so did the game.

Atkana

  • Bay Watcher
  • [CURIOUSBEAST]
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #139 on: July 07, 2017, 01:24:05 pm »

Quick update on a couple of the modtools I posted earlier: a fix to a problem that came up when I was trying to use it via script, as well as adding the ability to set beliefs to the culture's default + the ability to set personality traits to the caste's average. Still have no idea regarding the updating needs, though :(
Spoiler (click to show/hide)

PeridexisErrant

  • Bay Watcher
  • Dai stihó, Hrasht.
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #140 on: July 07, 2017, 06:19:05 pm »

Some Python experiments (with Python 3.6):

Spoiler (click to show/hide)

It doesn't support much yet, and there are some stability issues. It doesn't support accessing DF memory or running scripts directly from the console (it uses a "pyscript" command for that right now, but I'm working on a better way to allow plugins to register their own script types). I've come up with some ways that could make most of the Lua API available to Python, though, so that should be an improvement over the Ruby plugin.

I just want to say that this is super exciting and I hope it continues  :D
Logged
I maintain the DF Starter Pack - over a million downloads and still counting!
 Donations here.

lethosor

  • Bay Watcher
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #141 on: July 07, 2017, 09:56:23 pm »

I managed to fix the crash that was happening when reloading the plugin, with help from Quietust (it was an issue with PyImport_AppendInittab appending to a global table that didn't get cleared when the plugin was unloaded/reloaded). That seems to be the only major stability issue so far, although there are likely some memory leaks and threading issues due to me not figuring out entirely how the Python API works.

Anyway, I can call everything from Lua's dfhack.world module in Python now (since those all take primitive types - it only supports transferring None/nil, floats, integers, strings, and bools between Lua and Python for now).
Code: (test.py) [Select]
print(f"""\
save path: {dfhack.world.ReadWorldFolder()}
weather: {dfhack.world.ReadCurrentWeather()}
date: {dfhack.world.ReadCurrentDay()}-{dfhack.world.ReadCurrentMonth()}-{dfhack.world.ReadCurrentYear()}
""")
Code: (console output) [Select]
save path: arena1
weather: 0
date: 2-0-1
About the only useful things it can do are pausing and unpausing the game (dfhack.world.SetPauseState()) and setting the current weather (dfhack.world.SetCurrentWeather()). There are also some functions in the dfhack.internal module that work, but not all of them (some take pointers, some return tables, etc.).

I did manage to use the struct identities used by the Lua API to make isinstance() and issubclass() work properly. Note that creating instances of any DF classes doesn't do anything yet, but things like isinstance(df.viewscreen_titlest(), df.viewscreen) work as you'd expect.
Logged
DFHack - Dwarf Manipulator (Lua) - DF Wiki talk

There was a typo in the siegers' campfire code. When the fires went out, so did the game.

Roses

  • Bay Watcher
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #142 on: July 07, 2017, 11:48:16 pm »

So here's a question for an idea I had a little while ago. Currently DF has structures for accessing data, would it be possible to create our own structures that would be accessible through DFHack? For example, currently if I want to get the strength and willpower of a unit I need to type in (away from my DF right now so the exact location might be wrong);
Code: [Select]
strength = df.global.world.units.active[x].body.physical_attributes.STRENGTH.value
willpower = df.global.world.units.active[x].status.current_soul.mental_attributes.WILLPOWER.value
But what if I could just have all of my scripts reference a single location
Code: [Select]
strength = unit[x].attribute.STRENGTH.value
willpower = unit[x].attribute.WILLPOWER.value
And then have a different script that links the two. This way if Toady ever changes how the data are structured I only need to change a single location (the link between the two) instead of changing every single script. It would also allow linking of things that are separate in DF (like unit and histfig) and putting them together so that you can reference them both with a single unit.x declaration.

I was thinking it would just be simpler to code scripts if we had a constant scheme that didn't depend on how Toady structures his data.
Logged

lethosor

  • Bay Watcher
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #143 on: July 08, 2017, 07:51:55 am »

It's possible to add structures/enums/bitfields/etc. that aren't actually in DF - there are a few things like that in df-structures already. You're describing making some fields of structures available through other structures, though, which is more complicated and harder to maintain.

If you really want to access unit traits like that, you could make your own wrapper tables and use metatables (with __index and __newindex) to implement something similar to that. Here's an example of something similar I did to attach extra data to units. (It won't do exactly what you want, since adding a "skills" table with the data you want won't update the unit's skills when you change the table, unless you set up a metatable on it too.)
Logged
DFHack - Dwarf Manipulator (Lua) - DF Wiki talk

There was a typo in the siegers' campfire code. When the fires went out, so did the game.

Mrandom

  • Bay Watcher
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #144 on: July 09, 2017, 12:46:00 am »

Hello, I've been playing adventure mode recently and wrote a couple of scripts I feel is needed. I do have questions however:

1) Is there a way to trigger some specific interaction between a character and an object? In my case, the "read" interaction to read slabs. I wrote a script that copies all the secret slabs to player's location. This allows quick access to all secrets and is super fun with mods like Masterwork. It is slow, however, because the player needs to manually pick up and read every slab. Is there a way I can just let the player learn the secrets (represented as "topic" fields of the slabs)?

2) Another script is long-distance teleport. It teleports the player by cells on the big map. e.g. "teleport-long [delta-x] [delta-y] [delta-z]". However, when teleporting near places that fast travel is prohibited, usually next to rivers or camps, it sometimes loses the reference to the player's unit and change it to another random unit. Is there any way that we can throw an exception if the player is in a position that may cause errors?

3) Also for the long-distance teleport, is there a way to check the new player position so I can loop thru z positions to make sure the player is positioned on the surface, not in the air or under the surface? i.e. check if the new position is open space or a wall.
Logged

Max™

  • Bay Watcher
  • [CULL:SQUARE]
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #145 on: July 09, 2017, 02:03:17 pm »

When you say long distance teleport, you mean from the adventurer screen right? Cause https://github.com/maxthyme/maxthyme-scripts/blob/master/questport.lua works even if you're not on the travel map (by kicking you into it briefly) but it puts you at the top left corner of a given block. If you wanted you could use a similar trick to bump you into travel mode, then grab the army with flags[0] set and alter the x/y pos directly, it'll handle moving the z pos for you.

If you wrote a script to grab the relevant secrets you could dfhack a book up and add the secrets as improvements. Under the improvement link there's a field for the written content, under written content you can set them to be secrets and such.
Logged

Clément

  • Bay Watcher
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #146 on: July 09, 2017, 02:49:54 pm »

Hi, while studying Dwarf Therapist source code, I got few problems with the devel/export-dt-ini script.

It does not seems to give the value that DT is expecting: DT add the value from the ini file to the base address, but the script print the difference between the actual address and "rebase delta" that is, if understand correctly, the difference between DEFAULT_BASE_ADDR and the actual base address. I though of a quick and dirty fix by replacing "addr = addr - rdelta" by "addr = addr - 0x140000000 - rdelta" (0x140000000 being DEFAULT_BASE_ADDR on win64), but I actually needed to use 0x13fc00000 instead. Are DT and DFHack disagreeing on the base address? I am not sure I understand everything right about either DFHack or DT.

Note: I am also discussing this problem on the DT thread.
Logged

Quietust

  • Bay Watcher
  • Does not suffer fools gladly
    • View Profile
    • QMT Productions
Re: DFHack 0.43.05-r1
« Reply #147 on: July 09, 2017, 03:34:33 pm »

32-bit versions of Dwarf Therapist all expected "default absolute offsets" (i.e. the absolute addresses you get when DF loads at its default base address, with ASLR disabled) in its layout INI files, and that's what export-dt-ini.lua generates for 32-bit and 64-bit. For example, the proper offset for "cur_year_tick" in 0.43.05 Win64 should be 0x141904240.
Logged
P.S. If you don't get this note, let me know and I'll write you another.
It's amazing how dwarves can make a stack of bones completely waterproof and magmaproof.
It's amazing how they can make an entire floodgate out of the bones of 2 cats.

Roses

  • Bay Watcher
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #148 on: July 09, 2017, 04:12:44 pm »

It's possible to add structures/enums/bitfields/etc. that aren't actually in DF - there are a few things like that in df-structures already. You're describing making some fields of structures available through other structures, though, which is more complicated and harder to maintain.

If you really want to access unit traits like that, you could make your own wrapper tables and use metatables (with __index and __newindex) to implement something similar to that. Here's an example of something similar I did to attach extra data to units. (It won't do exactly what you want, since adding a "skills" table with the data you want won't update the unit's skills when you change the table, unless you set up a metatable on it too.)

Hmm, well the reason I thought about it in the first place was to attach extra data to units, the rest was just an afterthought really.
Logged

Clément

  • Bay Watcher
    • View Profile
Re: DFHack 0.43.05-r1
« Reply #149 on: July 09, 2017, 05:44:29 pm »

32-bit versions of Dwarf Therapist all expected "default absolute offsets" (i.e. the absolute addresses you get when DF loads at its default base address, with ASLR disabled) in its layout INI files, and that's what export-dt-ini.lua generates for 32-bit and 64-bit. For example, the proper offset for "cur_year_tick" in 0.43.05 Win64 should be 0x141904240.

I think I understand now. What DT calls "base_addr" is actually the base address difference (same as rebase_delta from dfhack). I found that DT has hard-coded the default base address for win32, that explains the value 0x13fc00000: it is actually the difference between the default base addresses for win32 and win64. If I change this value, it should work with layout from the script.
Logged
Pages: 1 ... 8 9 [10] 11 12 ... 243