mirror of
https://github.com/DrBeef/Raze.git
synced 2024-11-16 17:31:27 +00:00
3697842bc5
The map iterator now has init/finish capability, making it possible to write scripts that aggregate data over multiple map files. One such example calculates some statistics, the other loads art metadata and looks for red walls with non-pow2 ysize tiles. git-svn-id: https://svn.eduke32.com/eduke32@2814 1a8010ca-5511-0410-912e-c29ae57300e0
296 lines
7.2 KiB
Lua
296 lines
7.2 KiB
Lua
|
|
-- Loaders for various BUILD structures for LuaJIT
|
|
|
|
|
|
local ffi = require "ffi"
|
|
local io = require "io"
|
|
|
|
local error = error
|
|
local assert = assert
|
|
local print = print
|
|
local setmetatable = setmetatable
|
|
|
|
module(...)
|
|
|
|
ffi.cdef[[
|
|
#pragma pack(push,1)
|
|
typedef struct
|
|
{
|
|
int16_t wallptr, wallnum;
|
|
int32_t ceilingz, floorz;
|
|
int16_t ceilingstat, floorstat;
|
|
int16_t ceilingpicnum, ceilingheinum;
|
|
int8_t ceilingshade;
|
|
uint8_t ceilingpal, ceilingxpanning, ceilingypanning;
|
|
int16_t floorpicnum, floorheinum;
|
|
int8_t floorshade;
|
|
uint8_t floorpal, floorxpanning, floorypanning;
|
|
uint8_t visibility, filler;
|
|
int16_t lotag, hitag, extra;
|
|
} sectortype;
|
|
|
|
typedef struct
|
|
{
|
|
int32_t x, y;
|
|
int16_t point2, nextwall, nextsector;
|
|
int16_t cstat;
|
|
int16_t picnum, overpicnum;
|
|
int8_t shade;
|
|
uint8_t pal, xrepeat, yrepeat, xpanning, ypanning;
|
|
int16_t lotag, hitag, extra;
|
|
} walltype;
|
|
|
|
typedef struct
|
|
{
|
|
int32_t x, y, z;
|
|
int16_t cstat, picnum;
|
|
int8_t shade;
|
|
uint8_t pal, clipdist, filler;
|
|
uint8_t xrepeat, yrepeat;
|
|
int8_t xoffset, yoffset;
|
|
int16_t sectnum, statnum;
|
|
int16_t ang, owner, xvel, yvel, zvel;
|
|
int16_t lotag, hitag, extra;
|
|
} spritetype;
|
|
]]
|
|
|
|
local C = ffi.C
|
|
|
|
|
|
local MAX =
|
|
{
|
|
SECTORS = { [7]=1024, [8]=4096, [9]=4096 },
|
|
WALLS = { [7]=8192, [8]=16384, [9]=16384 },
|
|
SPRITES = { [7]=4096, [8]=16384, [9]=16384 },
|
|
|
|
TILES = 30720,
|
|
}
|
|
|
|
local function doread(fh, basectype, numelts)
|
|
local cd = ffi.new(basectype.."[?]", numelts)
|
|
local size = ffi.sizeof(cd)
|
|
|
|
if (numelts==0) then
|
|
return nil
|
|
end
|
|
|
|
assert(size % numelts == 0)
|
|
local datstr = fh:read(size)
|
|
|
|
if (datstr == nil or #datstr < size) then
|
|
fh:close()
|
|
return nil
|
|
end
|
|
|
|
ffi.copy(cd, datstr, size)
|
|
|
|
return cd
|
|
end
|
|
|
|
local function set_secwalspr_mt(structar, maxidx)
|
|
local mt = {
|
|
__index = function(tab, idx)
|
|
if (idx < 0 or idx >= maxidx) then
|
|
error("Invalid structure array read access", 2)
|
|
end
|
|
return structar[idx]
|
|
end,
|
|
|
|
__newindex = function(tab, idx, newval)
|
|
error('cannot write directly to structure array', 2)
|
|
end,
|
|
}
|
|
|
|
return setmetatable({}, mt)
|
|
end
|
|
|
|
--== LOADBOARD ==--
|
|
-- returns:
|
|
-- on failure, nil, errmsg
|
|
-- on success, a table
|
|
-- {
|
|
-- version = <num>,
|
|
-- numsectors=<num>, numwalls=<num>, numsprites=<num>,
|
|
-- sector=<cdata (array of sectortype)>,
|
|
-- wall=<cdata (array of walltype)>,
|
|
-- sprite=nil or <cdata> (array of spritetype),
|
|
-- start =
|
|
-- { x=<num>, y=<num>, z=<num>, ang=<num>, sectnum=<num> }
|
|
-- }
|
|
function loadboard(filename)
|
|
local fh, errmsg = io.open(filename)
|
|
|
|
if (fh==nil) then
|
|
return nil, errmsg
|
|
end
|
|
|
|
-- The table we'll return on success
|
|
local map = { start={} }
|
|
|
|
local cd = doread(fh, "int32_t", 4)
|
|
if (cd==nil) then
|
|
return nil, "Couldn't read header"
|
|
end
|
|
|
|
map.version = cd[0]
|
|
map.start.x = cd[1]
|
|
map.start.y = cd[2]
|
|
map.start.z = cd[3]
|
|
|
|
if (map.version < 7 or map.version > 9) then
|
|
fh:close()
|
|
return nil, "Invalid map version"
|
|
end
|
|
|
|
cd = doread(fh, "int16_t", 3)
|
|
if (cd==nil) then
|
|
return nil, "Couldn't read header (2)"
|
|
end
|
|
|
|
map.start.ang = cd[0]
|
|
map.start.sectnum = cd[1]
|
|
|
|
-- sectors
|
|
map.numsectors = cd[2]
|
|
if (map.numsectors == nil) then
|
|
return nil, "Couldn't read number of sectors"
|
|
end
|
|
if (map.numsectors <= 0 or map.numsectors > MAX.SECTORS[map.version]) then
|
|
fh:close()
|
|
return nil, "Invalid number of sectors"
|
|
end
|
|
|
|
map.sector = doread(fh, "sectortype", map.numsectors)
|
|
if (map.sector == nil) then
|
|
return nil, "Couldn't read sectors"
|
|
end
|
|
|
|
-- walls
|
|
cd = doread(fh, "int16_t", 1)
|
|
if (cd == nil) then
|
|
return nil, "Couldn't read number of walls"
|
|
end
|
|
map.numwalls = cd[0]
|
|
if (map.numwalls <= 0 or map.numwalls > MAX.WALLS[map.version]) then
|
|
fh:close()
|
|
return nil, "Invalid number of walls"
|
|
end
|
|
|
|
map.wall = doread(fh, "walltype", map.numwalls)
|
|
if (map.wall == nil) then
|
|
return nil, "Couldn't read walls"
|
|
end
|
|
|
|
-- sprites
|
|
cd = doread(fh, "int16_t", 1)
|
|
if (cd == nil) then
|
|
return nil, "Couldn't read number of sprites"
|
|
end
|
|
map.numsprites = cd[0]
|
|
if (map.numsprites < 0 or map.numsprites > MAX.SPRITES[map.version]) then
|
|
fh:close()
|
|
return nil, "Invalid number of sprites"
|
|
end
|
|
|
|
map.sprite = doread(fh, "spritetype", map.numsprites)
|
|
if (map.numsprites~=0 and map.sprite == nil) then
|
|
return nil, "Couldn't read sprites"
|
|
end
|
|
|
|
map.sector = set_secwalspr_mt(map.sector, map.numsectors)
|
|
map.wall = set_secwalspr_mt(map.wall, map.numwalls)
|
|
map.sprite = set_secwalspr_mt(map.sprite, map.numsprites)
|
|
|
|
-- done
|
|
fh:close()
|
|
return map
|
|
end
|
|
|
|
|
|
local function set_sizarray_mt(sizar)
|
|
local mt = {
|
|
__index = function(tab, idx)
|
|
if (idx < 0 or idx >= MAX.TILES) then
|
|
error("Invalid tile size array read access", 2)
|
|
end
|
|
return sizar[idx]
|
|
end,
|
|
|
|
__newindex = function(tab, idx, newval)
|
|
if (idx < 0 or idx >= MAX.TILES) then
|
|
error("Invalid tile size array write access", 2)
|
|
end
|
|
sizar[idx] = newval
|
|
end,
|
|
}
|
|
|
|
return setmetatable({}, mt)
|
|
end
|
|
|
|
|
|
--== LOADARTS (currently tilesizx and tilesizy only) ==--
|
|
-- filenames: a table with ART file names
|
|
-- returns:
|
|
-- on failure, nil, errmsg
|
|
-- on success, a table
|
|
-- {
|
|
-- sizx = <cdata (array of length MAXTILES)>
|
|
-- sizy = <cdata (array of length MAXTILES)>
|
|
-- }
|
|
function loadarts(filenames)
|
|
local tile = {
|
|
sizx = ffi.new("int16_t [?]", MAX.TILES),
|
|
sizy = ffi.new("int16_t [?]", MAX.TILES),
|
|
}
|
|
|
|
for fni=1,#filenames do
|
|
local fn = filenames[fni]
|
|
local fh, errmsg = io.open(fn)
|
|
|
|
if (fh==nil) then
|
|
return nil, errmsg
|
|
end
|
|
|
|
local cd = doread(fh, "int32_t", 4)
|
|
-- artversion, numtiles, localtilestart, localtileend
|
|
if (cd==nil) then
|
|
fh:close()
|
|
return nil, fn..": Couldn't read header"
|
|
end
|
|
|
|
local localtilestart = cd[2]
|
|
local numtileshere = cd[3]-localtilestart
|
|
|
|
if (numtileshere < 0 or localtilestart+numtileshere >= MAX.TILES) then
|
|
fh:close()
|
|
return nil, fn..": Invalid tile start/end"
|
|
end
|
|
|
|
if (numtileshere==0) then
|
|
fh:close()
|
|
else
|
|
-- X sizes
|
|
cd = doread(fh, "int16_t", numtileshere)
|
|
if (cd == nil) then
|
|
fh:close()
|
|
return nil, fn..": Couldn't read tilesizx array"
|
|
end
|
|
|
|
ffi.copy(tile.sizx+localtilestart, cd, numtileshere*2)
|
|
|
|
-- Y sizes
|
|
cd = doread(fh, "int16_t", numtileshere)
|
|
if (cd == nil) then
|
|
fh:close()
|
|
return nil, fn..": Couldn't read tilesizy array"
|
|
end
|
|
|
|
ffi.copy(tile.sizy+localtilestart, cd, numtileshere*2)
|
|
end
|
|
end
|
|
|
|
tile.sizx = set_sizarray_mt(tile.sizx)
|
|
tile.sizy = set_sizarray_mt(tile.sizy)
|
|
|
|
return tile
|
|
end
|