-
Notifications
You must be signed in to change notification settings - Fork 198
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
reinstate startdwarf and add scrollbar overlay
- Loading branch information
Showing
4 changed files
with
103 additions
and
108 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,79 @@ | ||
-- change number of dwarves on initial embark | ||
--@ module=true | ||
|
||
local addr = dfhack.internal.getAddress('start_dwarf_count') | ||
if not addr then | ||
qerror('start_dwarf_count address not available - cannot patch') | ||
local argparse = require('argparse') | ||
local overlay = require('plugins.overlay') | ||
local widgets = require('gui.widgets') | ||
|
||
StartDwarfOverlay = defclass(StartDwarfOverlay, overlay.OverlayWidget) | ||
StartDwarfOverlay.ATTRS{ | ||
default_pos={x=5, y=9}, | ||
default_enabled=true, | ||
viewscreens='setupdwarfgame/Dwarves', | ||
frame={w=5, h=10}, | ||
} | ||
|
||
function StartDwarfOverlay:init() | ||
self:addviews{ | ||
widgets.Scrollbar{ | ||
view_id='scrollbar', | ||
frame={r=0, t=0, w=2, b=0}, | ||
on_scroll=self:callback('on_scrollbar'), | ||
}, | ||
} | ||
end | ||
|
||
function StartDwarfOverlay:on_scrollbar(scroll_spec) | ||
local scr = dfhack.gui.getDFViewscreen(true) | ||
local _, sh = dfhack.screen.getWindowSize() | ||
local list_height = sh - 17 | ||
local num_units = #scr.s_unit | ||
local units_per_page = list_height // 3 | ||
|
||
local v = 0 | ||
if tonumber(scroll_spec) then | ||
v = tonumber(scroll_spec) - 1 | ||
elseif scroll_spec == 'down_large' then | ||
v = scr.selected_u + units_per_page // 2 | ||
elseif scroll_spec == 'up_large' then | ||
v = scr.selected_u - units_per_page // 2 | ||
elseif scroll_spec == 'down_small' then | ||
v = scr.selected_u + 1 | ||
elseif scroll_spec == 'up_small' then | ||
v = scr.selected_u - 1 | ||
end | ||
|
||
scr.selected_u = math.max(0, math.min(num_units-1, v)) | ||
end | ||
|
||
function StartDwarfOverlay:render(dc) | ||
local sw, sh = dfhack.screen.getWindowSize() | ||
local list_height = sh - 17 | ||
local scr = dfhack.gui.getDFViewscreen(true) | ||
local num_units = #scr.s_unit | ||
local units_per_page = list_height // 3 | ||
local scrollbar = self.subviews.scrollbar | ||
self.frame.w = sw // 2 - 4 | ||
self.frame.h = list_height | ||
self:updateLayout() | ||
|
||
local top = math.min(scr.selected_u + 1, num_units - units_per_page + 1) | ||
scrollbar:update(top, units_per_page, num_units) | ||
|
||
StartDwarfOverlay.super.render(self, dc) | ||
end | ||
|
||
OVERLAY_WIDGETS = { | ||
overlay=StartDwarfOverlay, | ||
} | ||
|
||
if dfhack_flags.module then | ||
return | ||
end | ||
|
||
local num = tonumber(({...})[1]) | ||
if not num or num < 7 then | ||
qerror('argument must be a number no less than 7') | ||
local num = argparse.positiveInt(({...})[1]) | ||
if num > 32767 then | ||
qerror(('value must be no more than 32,767: %d'):format(num)) | ||
end | ||
df.global.start_dwarf_count = num | ||
|
||
dfhack.with_temp_object(df.new('uint32_t'), function(temp) | ||
temp.value = num | ||
local temp_size, temp_addr = temp:sizeof() | ||
dfhack.internal.patchMemory(addr, temp_addr, temp_size) | ||
end) | ||
print(('starting dwarf count set to %d. good luck!'):format(num)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,104 +1,22 @@ | ||
local utils = require('utils') | ||
|
||
local function with_patches(callback, custom_mocks) | ||
dfhack.with_temp_object(df.new('uint32_t'), function(temp_out) | ||
local originalPatchMemory = dfhack.internal.patchMemory | ||
local function safePatchMemory(target, source, length) | ||
-- only allow patching the expected address - otherwise a buggy | ||
-- script could corrupt the test environment | ||
if target ~= utils.addressof(temp_out) then | ||
return expect.fail(('attempted to patch invalid address 0x%x: expected 0x%x'):format(target, utils.addressof(temp_out))) | ||
end | ||
return originalPatchMemory(target, source, length) | ||
end | ||
local mocks = { | ||
getAddress = mock.func(utils.addressof(temp_out)), | ||
patchMemory = mock.observe_func(safePatchMemory), | ||
} | ||
if custom_mocks then | ||
for k, v in pairs(custom_mocks) do | ||
mocks[k] = v | ||
end | ||
end | ||
mock.patch({ | ||
{dfhack.internal, 'getAddress', mocks.getAddress}, | ||
{dfhack.internal, 'patchMemory', mocks.patchMemory}, | ||
}, function() | ||
callback(mocks, temp_out) | ||
end) | ||
end) | ||
end | ||
config.target = 'startdwarf' | ||
|
||
local function run_startdwarf(...) | ||
return dfhack.run_script('startdwarf', ...) | ||
end | ||
|
||
local function test_early_error(args, expected_message, custom_mocks) | ||
with_patches(function(mocks, temp_out) | ||
temp_out.value = 12345 | ||
|
||
expect.error_match(expected_message, function() | ||
run_startdwarf(table.unpack(args)) | ||
end) | ||
|
||
expect.eq(mocks.getAddress.call_count, 1, 'getAddress was not called') | ||
expect.table_eq(mocks.getAddress.call_args[1], {'start_dwarf_count'}) | ||
|
||
expect.eq(mocks.patchMemory.call_count, 0, 'patchMemory was called unexpectedly') | ||
|
||
-- make sure the script didn't attempt to write in some other way | ||
expect.eq(temp_out.value, 12345, 'memory was changed unexpectedly') | ||
end, custom_mocks) | ||
end | ||
|
||
local function test_invalid_args(args, expected_message) | ||
test_early_error(args, expected_message) | ||
end | ||
|
||
local function test_patch_successful(expected_value) | ||
with_patches(function(mocks, temp_out) | ||
run_startdwarf(tostring(expected_value)) | ||
expect.eq(temp_out.value, expected_value) | ||
|
||
expect.eq(mocks.getAddress.call_count, 1, 'getAddress was not called') | ||
expect.table_eq(mocks.getAddress.call_args[1], {'start_dwarf_count'}) | ||
|
||
expect.eq(mocks.patchMemory.call_count, 1, 'patchMemory was not called') | ||
expect.eq(mocks.patchMemory.call_args[1][1], utils.addressof(temp_out), | ||
'patchMemory called with wrong destination') | ||
-- skip checking source (arg 2) because it has already been freed by the script | ||
expect.eq(mocks.patchMemory.call_args[1][3], df.sizeof(temp_out), | ||
'patchMemory called with wrong length') | ||
end) | ||
end | ||
|
||
function test.no_arg() | ||
test_invalid_args({}, 'must be a number') | ||
expect.error_match('expected positive integer', run_startdwarf) | ||
end | ||
|
||
function test.not_number() | ||
test_invalid_args({'a'}, 'must be a number') | ||
expect.error_match('expected positive integer', curry(run_startdwarf, 'a')) | ||
end | ||
|
||
function test.too_small() | ||
test_invalid_args({'4'}, 'less than 7') | ||
test_invalid_args({'6'}, 'less than 7') | ||
test_invalid_args({'-1'}, 'less than 7') | ||
end | ||
|
||
function test.missing_address() | ||
test_early_error({}, 'address not available', {getAddress = mock.func(nil)}) | ||
test_early_error({'8'}, 'address not available', {getAddress = mock.func(nil)}) | ||
end | ||
|
||
function test.exactly_7() | ||
test_patch_successful(7) | ||
end | ||
|
||
function test.above_7() | ||
test_patch_successful(10) | ||
expect.error_match('expected positive integer', curry(run_startdwarf, '0')) | ||
expect.error_match('expected positive integer', curry(run_startdwarf, '-1')) | ||
end | ||
|
||
function test.uint8_overflow() | ||
test_patch_successful(257) | ||
function test.too_big() | ||
expect.error_match('value must be no more than', curry(run_startdwarf, '32768')) | ||
end |