2012-08-02 10:52:32 +00:00
|
|
|
#!/usr/bin/env luajit
|
2012-07-08 21:47:06 +00:00
|
|
|
|
|
|
|
-- Generic map iterator.
|
|
|
|
|
|
|
|
-- The first cmdline arg is a name of a lua file (may be sans .lua) which must
|
|
|
|
-- be a module and is `require'd into this script, e.g. "stats" or "stats.lua".
|
2012-07-08 21:47:11 +00:00
|
|
|
-- First, a key named .init is looked up in the loaded module and if it exists,
|
|
|
|
-- it is run like .init(arg) (thus allowing it to parse the command-line
|
|
|
|
-- arguments and then potentially remove the ones it used).
|
|
|
|
-- If .init returns non-nil, this script aborts.
|
|
|
|
-- Otherwise, for each 2nd and following argument, if map loading succeeds,
|
|
|
|
-- .success(map, filename) is run, otherwise
|
|
|
|
-- .failure(filename, errmsg) is run if that key exists, or a standard error
|
|
|
|
-- message is printed to stderr.
|
|
|
|
-- Finally, if there is a .finish field in the module, it is run with no args.
|
2012-07-08 21:47:06 +00:00
|
|
|
|
2013-05-06 19:43:34 +00:00
|
|
|
-- forxcode example: print sprite numbers with lotag < -1 (lotag is signed for us),
|
2012-11-15 21:09:48 +00:00
|
|
|
-- and for each matching sprite also print its lotag and picnum:
|
2013-10-16 19:43:01 +00:00
|
|
|
-- $ ./findmaps.sh ~/.eduke32/ "sprite: .lotag < -1 :: io.write(', '.. .lotag .. ' ' .. .picnum)"
|
2012-07-08 21:47:06 +00:00
|
|
|
|
2012-11-18 19:01:39 +00:00
|
|
|
-- The local 'd' provides defs loaded from ../../names.h, example:
|
2013-10-16 19:43:01 +00:00
|
|
|
-- $ ./findmaps.sh ~/.eduke32/ "sprite: .picnum>=d.CRACK1 and .picnum<=d.CRACK4"
|
|
|
|
-- (Now: no space between "d." and "CRACK" is necessary ".xxx" is translated to
|
|
|
|
-- "sprite[<current>].xxx" only if it's the name of a sprite member.)
|
2014-06-01 20:50:14 +00:00
|
|
|
-- The local 'rdefs' provides the reverse mapping: from picnums to tile names
|
|
|
|
-- (or nil).
|
2013-04-12 11:59:32 +00:00
|
|
|
|
|
|
|
-- Print all V9 maps along with their number of bunches and max(ceilings of a bunch)
|
|
|
|
-- $ prog='if (map.version==9) then print(map.numbunches.." ".. math.max(unpack(map.sectsperbunch[0],0)) .." "..fn) end'
|
|
|
|
-- $ ./findmaps.sh ~/.eduke32 "$prog" |sort -n -k 2
|
2012-11-18 19:01:39 +00:00
|
|
|
|
2013-09-21 13:38:07 +00:00
|
|
|
-- Print all MUSICANDSFX sprites that play sounds with bit 1 set.
|
2013-10-16 19:43:01 +00:00
|
|
|
-- ./findmaps.sh /g/Games/Eduke32c/grp 'sprite: .picnum==5 and eq(.lotag, {170, 186, 187, 279, 382, 347}) :: io.write(" ".. tostring(.lotag))'
|
2013-09-21 13:38:07 +00:00
|
|
|
|
2013-11-16 18:47:19 +00:00
|
|
|
-- Print all maps that have floor-aligned blockable sprites in underwater sectors.
|
|
|
|
-- ./findmaps.sh ~/.eduke32 'sprite:: bit.band(.cstat,49)==33 and .sectnum>=0 and .sectnum < map.numsectors and sector[.sectnum].lotag==2
|
|
|
|
|
2012-07-08 21:47:11 +00:00
|
|
|
local B = require "build"
|
|
|
|
local string = require "string"
|
|
|
|
local io = require "io"
|
|
|
|
local os = require "os"
|
2012-07-08 21:47:06 +00:00
|
|
|
|
|
|
|
if (#arg < 1) then
|
2012-08-26 22:12:51 +00:00
|
|
|
local wr = function(s) io.stdout:write(s) end
|
2012-11-15 21:09:48 +00:00
|
|
|
wr("Usage: ./foreachmap.lua <module[.lua]> [init args...] <filename.map> ...\n")
|
|
|
|
wr(" ./foreachmap.lua -e\"some_lua_code ...\" <filename.map> ...\n")
|
|
|
|
wr(" ./foreachmap.lua -e\"[sector|wall|sprite]: <condition on .<field>>\" <fn.map> ...\n\n")
|
2012-08-26 22:12:51 +00:00
|
|
|
wr("In the second form, the code is run as body of a function(map, fn)\n")
|
|
|
|
wr("and num{sectors,walls,sprites} and {sector,wall,sprite} do not\n")
|
2012-09-24 21:09:22 +00:00
|
|
|
wr("need to be qualified with the \"map.\" prefix.\n")
|
|
|
|
wr("The third form is a shortcut for quickly finding sectors/walls/sprites\n")
|
|
|
|
wr("satisfying a certain condition (see example below)\n\n")
|
|
|
|
wr("Examples: ./foreachmap.lua -e\"if map.numbunches==1 then print(fn) end\" ~/.eduke32/*.map\n")
|
2012-09-26 22:54:01 +00:00
|
|
|
wr(" ./foreachmap.lua -e\"sprite: .picnum==10 and .lotag==2563\" *.map\n")
|
2012-11-15 21:09:48 +00:00
|
|
|
wr(" ./foreachmap.lua -e\"sprite:: ... -- (only prints the file names)\n")
|
|
|
|
wr("(See foreachmap.lua for an example of the \"forxcode\" feature.)\n\n")
|
2012-07-08 21:47:11 +00:00
|
|
|
return
|
2012-07-08 21:47:06 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
local modname = string.gsub(arg[1], "%.lua$", "")
|
2012-08-26 22:12:51 +00:00
|
|
|
|
2013-04-12 11:59:32 +00:00
|
|
|
function sum(tab, initidx)
|
|
|
|
local s = 0
|
|
|
|
for i=(initidx or 1),#tab do
|
|
|
|
s = s + tab[i]
|
|
|
|
end
|
|
|
|
return s
|
|
|
|
end
|
|
|
|
|
2013-10-16 19:43:01 +00:00
|
|
|
local g_what
|
|
|
|
-- Maybe replace e.g. .nextwall --> wall[i].nextwall.
|
|
|
|
-- <what>: one of "sector", "wall" or "sprite"
|
2013-11-16 18:47:19 +00:00
|
|
|
-- <maybechar>: the char before <maybememb>, or ""
|
2013-10-16 19:43:01 +00:00
|
|
|
-- <maybememb>: a potential member name prefixed by "."
|
2013-11-16 18:47:19 +00:00
|
|
|
local function maybe_complete_member(maybechar, maybememb)
|
|
|
|
if (maybechar~="]" and B.ismember(g_what, maybememb:sub(2))) then
|
|
|
|
return maybechar..g_what.."[i]"..maybememb
|
2013-10-16 19:43:01 +00:00
|
|
|
else
|
2013-11-16 18:47:19 +00:00
|
|
|
return maybechar..maybememb
|
2013-10-16 19:43:01 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-08-26 22:12:51 +00:00
|
|
|
local mod
|
|
|
|
if (modname:sub(1,2) == "-e") then
|
|
|
|
local body = modname:sub(3)
|
2012-09-24 21:09:22 +00:00
|
|
|
|
|
|
|
-- sector/wall/sprite finder shortcut
|
2012-09-26 22:54:01 +00:00
|
|
|
local b, e, what = body:find("^([a-z]+)::?")
|
2012-09-24 21:09:22 +00:00
|
|
|
if (what) then
|
2013-10-16 19:43:01 +00:00
|
|
|
g_what = what
|
2012-09-26 22:54:01 +00:00
|
|
|
local onlyfiles = (body:sub(e-1,e)=="::") -- "::" means "only list files" (like grep -l)
|
2012-11-15 21:09:48 +00:00
|
|
|
body = body:sub(e+1) -- clip off "bla::"
|
2013-11-16 18:47:19 +00:00
|
|
|
body = body:gsub("(.?)(%.[a-z][a-z0-9]*)", maybe_complete_member) -- e.g. .lotag --> sprite[i].lotag
|
2012-11-15 21:09:48 +00:00
|
|
|
|
|
|
|
local perxcode
|
|
|
|
-- look for additional "print" code to be executed for each match
|
|
|
|
b, e, perxcode = body:find("::(.*)")
|
|
|
|
if (perxcode) then
|
|
|
|
body = body:sub(1,b-1)
|
|
|
|
if (onlyfiles) then
|
|
|
|
error("Per-x code can only be used with the ':' syntax (list each match)")
|
|
|
|
end
|
|
|
|
else
|
|
|
|
perxcode = ""
|
|
|
|
end
|
|
|
|
|
2013-04-12 11:59:32 +00:00
|
|
|
assert(what=="sector" or what=="wall" or what=="sprite")
|
|
|
|
|
2012-09-24 21:09:22 +00:00
|
|
|
body =
|
2012-09-26 22:54:01 +00:00
|
|
|
"for i=0,num"..what.."s-1 do\n"..
|
|
|
|
" if ("..body..") then\n"..
|
2012-11-15 21:09:48 +00:00
|
|
|
(onlyfiles and "io.write(fn); return\n" or "io.write(fn..': '..i)\n") ..
|
2013-04-12 11:59:32 +00:00
|
|
|
perxcode .. "io.write('\\n')\n"..
|
|
|
|
" end\n"..
|
2012-09-26 22:54:01 +00:00
|
|
|
"end\n"
|
2012-09-24 21:09:22 +00:00
|
|
|
end
|
|
|
|
|
2013-04-12 11:59:32 +00:00
|
|
|
local successfunc, errmsg = loadstring([[
|
2013-09-21 13:38:07 +00:00
|
|
|
local function eq(x, tab)
|
|
|
|
for i=1,#tab do
|
|
|
|
if (x==tab[i]) then return true end
|
|
|
|
end
|
|
|
|
end
|
2014-06-01 20:50:14 +00:00
|
|
|
local d,rdefs = require('build').readdefs('../../names.h',true)
|
|
|
|
if (not d) then error('Need ../../names.h') end -- XXX
|
2013-04-12 11:59:32 +00:00
|
|
|
local numsectors, numwalls, numsprites, sector, wall, sprite
|
|
|
|
return function (map, fn)
|
|
|
|
numsectors, numwalls, numsprites = map.numsectors, map.numwalls, map.numsprites
|
|
|
|
sector, wall, sprite = map.sector, map.wall, map.sprite
|
|
|
|
]]..body
|
|
|
|
.." end")
|
2012-08-26 22:12:51 +00:00
|
|
|
|
|
|
|
if (successfunc==nil) then
|
|
|
|
io.stderr:write("Error loading string: "..errmsg.."\n")
|
2013-11-16 18:47:19 +00:00
|
|
|
io.stderr:write("Function body:\n", body)
|
2012-08-26 22:12:51 +00:00
|
|
|
os.exit(1)
|
|
|
|
end
|
|
|
|
|
|
|
|
mod = { success=successfunc() }
|
|
|
|
else
|
|
|
|
mod = require(modname)
|
|
|
|
end
|
2012-07-08 21:47:06 +00:00
|
|
|
|
2013-08-11 15:28:50 +00:00
|
|
|
-- The return value from the module's .init().
|
|
|
|
local initret
|
|
|
|
|
2012-07-08 21:47:11 +00:00
|
|
|
if (mod.init) then
|
2013-08-11 15:28:50 +00:00
|
|
|
initret = mod.init(arg)
|
|
|
|
if (type(initret)=="number" and initret < 0) then
|
|
|
|
-- A negative return value from .init() is taken as a request to exit,
|
|
|
|
-- e.g. because an error occurred.
|
2012-07-08 21:47:11 +00:00
|
|
|
os.exit(1)
|
|
|
|
end
|
|
|
|
end
|
2012-07-08 21:47:06 +00:00
|
|
|
|
2013-08-11 15:28:50 +00:00
|
|
|
-- A positive return value from .init() is taken to start counting map names
|
|
|
|
-- from that 'arg' index.
|
|
|
|
local startargi = (type(initret)=="number" and initret > 0 and initret) or 2
|
|
|
|
|
|
|
|
for i=startargi,#arg do
|
2012-07-08 21:47:06 +00:00
|
|
|
local fn = arg[i]
|
|
|
|
local map, errmsg = B.loadboard(fn)
|
|
|
|
|
|
|
|
if (map ~= nil) then
|
|
|
|
mod.success(map, fn)
|
|
|
|
else
|
2012-07-08 21:47:11 +00:00
|
|
|
if (mod.failure) then
|
|
|
|
mod.failure(fn, errmsg)
|
|
|
|
else
|
|
|
|
io.stderr:write(string.format("--- %s: %s\n", fn, errmsg))
|
|
|
|
end
|
2012-07-08 21:47:06 +00:00
|
|
|
end
|
|
|
|
end
|
2012-07-08 21:47:11 +00:00
|
|
|
|
|
|
|
if (mod.finish) then
|
|
|
|
mod.finish()
|
|
|
|
end
|