Add a couple of useful scripts and fix two missing NULL checks.

- A script to unstick jobs trying to build walls from the same tile.
- A devel script for viewing the path a unit is currently following.
develop
Alexander Gavrilov 2014-04-21 09:24:05 +04:00
parent 4b8760815d
commit 6bef167f83
9 changed files with 286 additions and 0 deletions

@ -2157,6 +2157,9 @@ for i = 1,#order do output[i] = data[order[i]] end
way enables applying the same permutation to multiple arrays.
This function is used by the sort plugin.</p>
</li>
<li><p class="first"><tt class="docutils literal">for link,item in utils.listpairs(list)</tt></p>
<p>Iterates a df-list structure, for example <tt class="docutils literal">df.global.world.job_list</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">utils.assign(tgt, src)</tt></p>
<p>Does a recursive assignment of src into tgt.
Uses <tt class="docutils literal">df.assign</tt> if tgt is a native object ref; otherwise

@ -2045,6 +2045,10 @@ utils
way enables applying the same permutation to multiple arrays.
This function is used by the sort plugin.
* ``for link,item in utils.listpairs(list)``
Iterates a df-list structure, for example ``df.global.world.job_list``.
* ``utils.assign(tgt, src)``
Does a recursive assignment of src into tgt.

@ -9,6 +9,7 @@ DFHack future
New scripts:
- gui/mod-manager: allows installing/uninstalling mods into df from df/mods directory.
- gui/clone-uniform: duplicates the currently selected uniform in the military screen.
- fix/build-location: partial work-around for bug 5991 (trying to build wall while standing on it)
New commands:
- move the 'grow', 'extirpate' and 'immolate' commands as 'plant' subcommands

@ -2930,6 +2930,11 @@ in memory and patching up some invalid reference fields. Needs to be run
every time a save game is loaded; putting <tt class="docutils literal"><span class="pre">fix/cloth-stockpile</span> enable</tt>
in <tt class="docutils literal">dfhack.init</tt> makes it run automatically.</p>
</li>
<li><p class="first">fix/build-location</p>
<p>Fixes construction jobs that are stuck trying to build a wall while standing
on the same exact tile (bug 5991), designates the tile restricted traffic to
hopefully avoid jamming it again, and unsuspends them.</p>
</li>
</ul>
</div>
<div class="section" id="gui">

@ -2049,6 +2049,13 @@ Scripts in this subdirectory fix various bugs and issues, some of them obscure.
every time a save game is loaded; putting ``fix/cloth-stockpile enable``
in ``dfhack.init`` makes it run automatically.
* fix/build-location
Fixes construction jobs that are stuck trying to build a wall while standing
on the same exact tile (bug 5991), designates the tile restricted traffic to
hopefully avoid jamming it again, and unsuspends them.
gui/*
=====

@ -147,6 +147,21 @@ function make_sort_order(data,ordering)
return index
end
--[[
Iterate a 'list' structure, e.g. df.global.world.job_list
--]]
local function next_df_list(s,link)
link = link.next
if link then
return link, link.item
end
end
function listpairs(list)
return next_df_list, nil, list
end
--[[
Recursively assign data into a table.
--]]

@ -1368,6 +1368,8 @@ bool DFHack::Units::getNoblePositions(std::vector<NoblePosition> *pvec, df::unit
std::string DFHack::Units::getProfessionName(df::unit *unit, bool ignore_noble, bool plural)
{
CHECK_NULL_POINTER(unit);
std::string prof = unit->custom_profession;
if (!prof.empty())
return prof;
@ -1514,6 +1516,8 @@ std::string DFHack::Units::getCasteProfessionName(int race, int casteid, df::pro
int8_t DFHack::Units::getProfessionColor(df::unit *unit, bool ignore_noble)
{
CHECK_NULL_POINTER(unit);
std::vector<NoblePosition> np;
if (!ignore_noble && getNoblePositions(&np, unit))

@ -0,0 +1,210 @@
-- Show the internal path a unit is currently following.
local utils = require 'utils'
local gui = require 'gui'
local guidm = require 'gui.dwarfmode'
local dlg = require 'gui.dialogs'
local tile_attrs = df.tiletype.attrs
UnitPathUI = defclass(UnitPathUI, guidm.MenuOverlay)
UnitPathUI.focus_path = 'unit-path'
UnitPathUI.ATTRS {
unit = DEFAULT_NIL,
}
function UnitPathUI:init()
self.saved_mode = df.global.ui.main.mode
end
function UnitPathUI:onShow()
-- with cursor, but without those ugly lines from native hauling mode
df.global.ui.main.mode = df.ui_sidebar_mode.Stockpiles
end
function UnitPathUI:onDestroy()
self:moveCursorTo(copyall(self.unit.pos))
df.global.ui.main.mode = self.saved_mode
end
local function getTileType(cursor)
local block = dfhack.maps.getTileBlock(cursor)
if block then
return block.tiletype[cursor.x%16][cursor.y%16]
else
return 0
end
end
local function getTileWalkable(cursor)
local block = dfhack.maps.getTileBlock(cursor)
if block then
return block.walkable[cursor.x%16][cursor.y%16]
else
return 0
end
end
local function paintMapTile(dc, vp, cursor, pos, ...)
if not same_xyz(cursor, pos) then
local stile = vp:tileToScreen(pos)
if stile.z == 0 then
dc:seek(stile.x,stile.y):char(...)
end
end
end
local function get_path_point(gpath,i)
return xyz2pos(gpath.x[i], gpath.y[i], gpath.z[i])
end
function UnitPathUI:renderPath(dc,vp,cursor)
local gpath = self.unit.path.path
local startp = self.unit.pos
local endp = self.unit.path.dest
local visible = gui.blink_visible(500)
if visible then
paintMapTile(dc, vp, cursor, endp, '+', COLOR_LIGHTGREEN)
end
local ok = nil
local pcnt = #gpath.x
if pcnt > 0 then
ok = true
for i = 0,pcnt-1 do
local pt = get_path_point(gpath, i)
if i == 0 and not same_xyz(startp,pt) then
ok = false
end
if i == pcnt-1 and not same_xyz(endp,pt) then
ok = false
end
--[[local tile = getTileType(pt)
if not isTrackTile(tile) then
ok = false
end]]
if visible then
local char = '+'
if i < pcnt-1 then
local npt = get_path_point(gpath, i+1)
if npt.z == pt.z+1 then
char = 30
elseif npt.z == pt.z-1 then
char = 31
elseif npt.x == pt.x+1 then
char = 26
elseif npt.x == pt.x-1 then
char = 27
elseif npt.y == pt.y+1 then
char = 25
elseif npt.y == pt.y-1 then
char = 24
end
end
local color = COLOR_LIGHTGREEN
if getTileWalkable(pt) == 0 then color = COLOR_LIGHTRED end
paintMapTile(dc, vp, cursor, pt, char, color)
end
end
end
if gui.blink_visible(120) then
paintMapTile(dc, vp, cursor, startp, 240, COLOR_LIGHTGREEN, COLOR_GREEN)
end
return ok
end
function UnitPathUI:onRenderBody(dc)
dc:clear():seek(1,1):pen(COLOR_WHITE):string("Unit Path")
local prof = dfhack.units.getProfessionName(self.unit)
local name = dfhack.units.getVisibleName(self.unit)
dc:seek(2,3):pen(COLOR_BLUE):string(prof)
if name and name.has_name then
dc:seek(2,4):pen(COLOR_BLUE):string(dfhack.TranslateName(name))
end
local cursor = guidm.getCursorPos()
local has_path = #self.unit.path.path.x>0
local vp = self:getViewport()
local mdc = gui.Painter.new(self.df_layout.map)
if not has_path then
if gui.blink_visible(120) then
paintMapTile(mdc, vp, cursor, self.unit.pos, 15, COLOR_LIGHTRED, COLOR_RED)
end
dc:seek(1,6):pen(COLOR_RED):string('Not following path')
else
self:renderPath(mdc,vp,cursor)
dc:seek(1,6):pen(COLOR_GREEN):string(df.unit_path_goal[self.unit.path.goal])
end
dc:newline():pen(COLOR_GREY)
dc:newline(2):string('Speed: '..dfhack.units.computeMovementSpeed(self.unit))
dc:newline(2):string('Slowdown: '..dfhack.units.computeSlowdownFactor(self.unit))
dc:newline():newline(1)
local has_station = self.unit.idle_area_type >= 0
if has_station then
if gui.blink_visible(250) then
paintMapTile(mdc, vp, cursor, self.unit.idle_area, 21, COLOR_LIGHTCYAN)
end
dc:pen(COLOR_GREEN):string(df.unit_station_type[self.unit.idle_area_type])
dc:newline():newline(2):pen(COLOR_GREY):string('Threshold: '..self.unit.idle_area_threshold)
else
dc:pen(COLOR_RED):string('No station'):newline():newline(2)
end
dc:newline():newline(1):string('At cursor:')
dc:newline():newline(2)
local tile = getTileType(cursor)
dc:string(df.tiletype[tile],COLOR_CYAN)
dc:newline():newline(1):pen(COLOR_WHITE)
dc:key('CUSTOM_Z'):string(": Zoom unit, ")
dc:key('CUSTOM_G'):string(": Zoom goal",COLOR_GREY,nil,has_path)
dc:newline(1)
dc:key('CUSTOM_N'):string(": Zoom station",COLOR_GREY,nil,has_station)
dc:newline():newline(1)
dc:key('LEAVESCREEN'):string(": Back")
end
function UnitPathUI:onInput(keys)
if keys.CUSTOM_Z then
self:moveCursorTo(copyall(self.unit.pos))
elseif keys.CUSTOM_G then
if #self.unit.path.path.x > 0 then
self:moveCursorTo(copyall(self.unit.path.dest))
end
elseif keys.CUSTOM_N then
if self.unit.idle_area_type > 0 then
self:moveCursorTo(copyall(self.unit.idle_area))
end
elseif keys.LEAVESCREEN then
self:dismiss()
elseif self:propagateMoveKeys(keys) then
return
end
end
local unit = dfhack.gui.getSelectedUnit(true)
if not unit or not string.match(dfhack.gui.getCurFocus(), '^dwarfmode/ViewUnits/Some/') then
qerror("This script requires the main dwarfmode view in 'v' mode with a unit selected")
end
UnitPathUI{ unit = unit }:show()

@ -0,0 +1,37 @@
-- Lets constructions reconsider the build location.
-- Partial work-around for http://www.bay12games.com/dwarves/mantisbt/view.php?id=5991
local utils = require('utils')
local count = 0
for link,job in utils.listpairs(df.global.world.job_list) do
local job = link.item
local place = dfhack.job.getHolder(job)
if job.job_type == df.job_type.ConstructBuilding
and place and place:isImpassableAtCreation()
and job.item_category[0]
then
local cpos = utils.getBuildingCenter(place)
if same_xyz(cpos, job.pos) then
-- Reset the flag
job.item_category[0] = false
job.flags.suspend = false
-- Mark the tile restricted traffic
local dsgn,occ = dfhack.maps.getTileFlags(cpos)
dsgn.traffic = df.tile_traffic.Restricted
count = count + 1
end
end
end
print('Found and unstuck '..count..' construct building jobs.')
if count > 0 then
df.global.process_jobs = true
end