mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-12 11:10:39 +00:00
e63874d011
For events and actors, a flag can be now passed whether to chain the new function at the beginning or end of an already existing one, or to replace it entirely. Also, for the translator, add option -fno-error-nostate, disabled by default. git-svn-id: https://svn.eduke32.com/eduke32@3629 1a8010ca-5511-0410-912e-c29ae57300e0
491 lines
16 KiB
Text
491 lines
16 KiB
Text
-- test script for ELua/Lunatic Interpreter
|
|
|
|
--do return end
|
|
|
|
-- error=nil -- must not affect "require"
|
|
local string = require("string")
|
|
local bit = require("bit")
|
|
local math = require("math")
|
|
|
|
local pcall = pcall
|
|
local DBG_ = DBG_
|
|
|
|
print('---=== ELua Test script ===---')
|
|
|
|
local function printf(fmt, ...)
|
|
print(string.format(fmt, ...))
|
|
end
|
|
|
|
local function checkfail(funcstr, expectedmsg)
|
|
local status, errmsg = pcall(DBG_.loadstring(funcstr))
|
|
if (status) then
|
|
print('^21ERROR:^O '..funcstr.." DIDN'T fail")
|
|
else
|
|
if (expectedmsg==nil or string.find(errmsg, expectedmsg, 1, true)) then
|
|
print("^11SUCCESS:^O "..funcstr.." failed: "..errmsg)
|
|
else
|
|
-- XXX: beginning with "^10" is counted as error in OSD_Printf()
|
|
print("^10ERROR*:^O "..funcstr.." failed: "..errmsg..
|
|
", but expected error message was: "..expectedmsg)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
---- check serialization ----
|
|
gamevar("ourvar")
|
|
gamevar("ourvar2")
|
|
|
|
-- test nans, infs, precision, subnorms, booleans
|
|
ourvar2 = { "asd"; 0/0, 1/0, -1/0, 0.12345678901234567, 1e-314, true }
|
|
ourvar = { ourvar2; 1, 2, 3, "qwe"; [true]=0, [false]=1 }
|
|
ourvar[#ourvar+1] = ourvar;
|
|
|
|
local gvstr = DBG_.serializeGamevars()
|
|
ourvar = -1
|
|
|
|
print("========== attempting to load string: ==========")
|
|
print(gvstr)
|
|
print("---------- (end string to load) ----------")
|
|
|
|
-- XXX: need to think about fully restoring state
|
|
DBG_.loadGamevarsString(gvstr)
|
|
print("ourvar[4]="..ourvar[4])
|
|
|
|
|
|
print('tweaking sector pals')
|
|
print('numsectors: ' .. gv.numsectors .. ' of ' .. gv.MAXSECTORS)
|
|
|
|
---[[
|
|
for i = 0, gv.numsectors/2 do
|
|
sector[i].floorpal = 1;
|
|
sector[i].ceilingpal = 2;
|
|
end
|
|
|
|
local vol, lev = gv.currentEpisode()+1, gv.currentLevel()+1
|
|
printf('volume=%d, level=%d', vol, lev)
|
|
|
|
if (vol==1 and lev==1) then -- E1L1
|
|
print('tweaking some sprites 2')
|
|
local i = 562
|
|
spriteext[i].alpha = 0.5;
|
|
sprite[i].cstat = bit.bor(sprite[i].cstat, 2+512);
|
|
spriteext[i].pitch = 128;
|
|
spriteext[i].roll = 256;
|
|
|
|
i = 107 -- pistol ammo at rooftop
|
|
spriteext[i].pitch = 128;
|
|
spriteext[i].roll = 256;
|
|
|
|
for spr in spritesofsect(307) do -- some fence sprites in E1L1
|
|
printf('spr %d', spr)
|
|
sprite[spr].pal = 6
|
|
end
|
|
|
|
--this is a problem
|
|
--actor = {}
|
|
actor[562].flags = bit.bor(actor[562].flags, 2); -- pal 6 with goggles on front SEENINE
|
|
end
|
|
|
|
--[[
|
|
-- TODO: better API for all TROR things?
|
|
if (vol==1 and lev==8) then
|
|
print('tweaking bunch 1');
|
|
-- trueror1.map
|
|
for i in sectorsofbunch(1, gv.CEILING) do
|
|
sector[i].ceilingz = sector[i].ceilingz - 3*1024;
|
|
end
|
|
for i in sectorsofbunch(1, gv.FLOOR) do
|
|
sector[i].floorz = sector[i].floorz - 3*1024;
|
|
end
|
|
end
|
|
--]]
|
|
|
|
local unsafe = pcall(function() string.UNSAFE=true; end)
|
|
|
|
--]]
|
|
--tostring = nil -- REMEMBER
|
|
--DBG_.printkv('_G in test.elua', _G)
|
|
|
|
-- direct gv array access forbidden
|
|
checkfail('gv.sprite[0].yrepeat = 100', "access forbidden")
|
|
|
|
checkfail('print(sprite[100000].ceilingpal)', "out-of-bounds sprite[] read access")
|
|
|
|
checkfail('print(gv.sprite[0])', "access forbidden")
|
|
|
|
-- set metatable forbidden
|
|
checkfail('setmetatable(sprite, {})', "attempt to read undeclared variable 'setmetatable'")
|
|
|
|
-- OOB write access.
|
|
-- Note that indexing ("reading") sector fails, even if the user wants to
|
|
-- assign to a sector member. Potentially confusing error message.
|
|
checkfail('sector[-1].ceilingpal = 4', "out-of-bounds sector[] read access")
|
|
|
|
-- wallnum member is read-only
|
|
checkfail('sector[0].wallnum = 0', "attempt to write to constant location") -- this comes from LJ/FFI
|
|
|
|
-- gv.numsectors is read-only
|
|
checkfail('gv.numsectors = 4', "attempt to write to constant location")
|
|
|
|
-- cannot create new fields in 'gv'
|
|
checkfail('gv.QWE = 4', "write access forbidden")
|
|
|
|
-- direct sector write access forbidden
|
|
checkfail('sector[4] = sector[6]', "cannot write directly to sector[]")
|
|
|
|
-- that would be horrible...
|
|
checkfail('sprite._nextspritesect[4] = -666', "cannot write directly to nextspritesect[]")
|
|
|
|
-- we're indexing a plain array!
|
|
checkfail('print(sprite._nextspritesect[4].whatfield)', "attempt to index a number value")
|
|
|
|
-- creating new keys forbidden... handled by LuaJIT
|
|
checkfail('wall[4].QWE = 123', "has no member named 'QWE'")
|
|
|
|
-- our 'require' has only safe stuff
|
|
--checkfail("require('os')")
|
|
|
|
-- we must declare globals with 'gamevar'
|
|
checkfail("new_global = 345", "attempt to write to undeclared variable 'new_global'")
|
|
|
|
-- can't redefine constants in 'gv'
|
|
checkfail('gv.CEILING = 3', "attempt to write to constant location")
|
|
|
|
-- string.dump is unavailable
|
|
checkfail('local s=require[[string]]; local tmp=s.dump(gameevent)',
|
|
"attempt to call field 'dump' (a nil value)")
|
|
|
|
if (not unsafe) then
|
|
-- changing base module tables is disallowed
|
|
checkfail('local s=require[[string]]; s.format=nil', "modifying base module table forbidden")
|
|
else
|
|
print('WARNING: RUNNING WITH UNPROTECTED BASE MODULES')
|
|
end
|
|
|
|
print('')
|
|
-- This is problematic, even though pretty much every access will yield a
|
|
-- "missing declaration" error.
|
|
-- See http://luajit.org/ext_ffi_api.html#ffi_C about what stuff ffi.C contains.
|
|
checkfail('gv.luaJIT_setmode(nil, 0, 0)', "missing declaration for symbol 'luaJIT_setmode'")
|
|
|
|
checkfail('gv.luaJIT_BC_con_lang', "attempt to call a nil value")
|
|
checkfail('gv.yax_getbunch(0,0)', "access forbidden")
|
|
checkfail('gv.gethitickms = nil', "attempt to write to constant location")
|
|
|
|
-- actor[].t_data[] is not accessible for now
|
|
checkfail('local i = actor[0].t_data[15]', "has no member named 't_data'")
|
|
|
|
-- no pointer arithmetic!
|
|
checkfail('local spr = sprite[0]; local x=spr+1', "attempt to perform arithmetic on")
|
|
|
|
checkfail('gameactor(1680, 0)', "invalid last argument to gameactor: must be a function")
|
|
|
|
checkfail("do local bt=require'bittest'; bt.QWE=1; end", "modifying module table forbidden")
|
|
-- the cdata returned by player[] can't be made into a pointer!
|
|
checkfail("do local pl=player[0]; i=pl[1]; end")
|
|
checkfail("do local ud=gv.ud.camerasprite; end", "access forbidden") -- test for proper decl()
|
|
checkfail("sprite[0]:set_picnum(-10)", "invalid tile number")
|
|
checkfail("gv.g_sizes_of=nil; print(gv.g_sizes_of[0])", "write access forbidden")
|
|
checkfail("gv.cam.sect=-1", "invalid sector number")
|
|
checkfail("local flag=gv.SFLAG_NULL", "missing declaration")
|
|
|
|
printf('ceilingbunch of sector 0: %d', getbunch(0, gv.CEILING))
|
|
|
|
gameevent(gv.EVENT_JUMP,
|
|
function(actori, playeri, dist)
|
|
printf("jump i=%d p=%d d=%d", actori, playeri, dist)
|
|
error("greetings from EVENT_JUMP")
|
|
end
|
|
)
|
|
|
|
gameevent("PROCESSINPUT",
|
|
-- Input test.
|
|
-- NOTE: I don't think that exposing g_player[].sync (aka "input") is a good idea...
|
|
function(actori, playeri, dist)
|
|
local IB = player.INPUT_BITS
|
|
local input = player[playeri]._input
|
|
if (bit.band(input.bits, IB.JUMP) ~= 0) then
|
|
print("JUMPED")
|
|
-- ... because for example this doesn't work
|
|
-- (P_HandleSharedKeys, where the JETPACK bit is tested, runs
|
|
-- before P_ProcessInput):
|
|
input.bits = bit.bor(input.bits, IB.JETPACK)
|
|
end
|
|
end
|
|
)
|
|
|
|
-- test event chaining
|
|
gameevent("JUMP",
|
|
function(actori, playeri, dist)
|
|
local ps = player[playeri]
|
|
print("I'm first!")
|
|
-- DBG_.oom()
|
|
ps.weapon.PISTOL.shoots = 2605 -- RPG
|
|
ps.weapon[gv.PISTOL_WEAPON].firesound = 351 -- thunder
|
|
|
|
-- XXX: provide either named constants or methods?
|
|
ps.pipebombControl = 2
|
|
ps.tripbombControl = 2
|
|
|
|
-- Test of INTERNAL member _pals.
|
|
-- NOTE: setting colors partially is bad! E.g. after an item is
|
|
-- picked up, col[0] and col[1] remain and tint everything greenish.
|
|
ps._pals.col[2] = 20
|
|
ps._pals.f = 30
|
|
end
|
|
)
|
|
|
|
gameevent(gv.EVENT_ENTERLEVEL,
|
|
function()
|
|
if (gv._DEBUG_LUNATIC) then
|
|
DBG_.testmembread()
|
|
end
|
|
|
|
-- NOTE: times are for helixhorned (Core2Duo 3GHz)
|
|
local i
|
|
local N = 1e6
|
|
local t = gv.gethitickms()
|
|
|
|
for i=3,N do
|
|
gv.gethitickms()
|
|
end
|
|
|
|
t = gv.gethitickms()-t
|
|
|
|
-- x86_64: 35ns/call, x86: 280 ns/call
|
|
-- Windows 32-bit: about 1 us/call?
|
|
printf("%d gethitickms() calls took %.03f ms (%.03f us/call)",
|
|
N, t, (t*1000)/N)
|
|
|
|
local sum=0
|
|
t = gv.gethitickms()
|
|
for i=1,N do sum = sum+gv.ksqrt(i) end
|
|
t = gv.gethitickms()-t
|
|
-- x86_64: 14ns/call
|
|
printf("%d ksqrt() calls took %.03f ms (%.03f us/call) [sum=%f]",
|
|
N, t, (t*1000)/N, sum)
|
|
|
|
sum=0
|
|
t = gv.gethitickms()
|
|
for i=1,N do sum = sum+math.sqrt(i) end
|
|
t = gv.gethitickms()-t
|
|
-- x86_64: 7ns/call
|
|
printf("%d math.sqrt() calls took %.03f ms (%.03f us/call) [sum=%f]",
|
|
N, t, (t*1000)/N, sum)
|
|
|
|
printf("sqrt(0xffffffff) = %f(ksqrt) %f(math.sqrt)",
|
|
gv.ksqrt(0xffffffff), math.sqrt(0xffffffff))
|
|
|
|
local pl = player[0]
|
|
-- MAX < current is "allowed"
|
|
pl.max_ammo_amount[gv.RPG_WEAPON] = 17
|
|
pl:give_weapon(gv.RPG_WEAPON)
|
|
pl.ammo_amount[gv.RPG_WEAPON] = 54
|
|
|
|
pl:give_weapon(gv.SHRINKER_WEAPON)
|
|
-- This looks much prettier:
|
|
pl.ammo_amount.SHRINKER = 2
|
|
|
|
-- MORTER2 from test/weaponvars.con
|
|
player[0].weapon.SHOTGUN.shoots = 1653
|
|
local proj = projectile[1653]
|
|
proj.drop = 0
|
|
proj:set_trail(2329) -- SMALLSMOKE
|
|
|
|
t = gv.gethitickms()
|
|
local N=1
|
|
for n=1,N do
|
|
for i=0,gv.MAXSPRITES-1 do
|
|
sprite[i].filler = 1
|
|
end
|
|
for i=gv.MAXSPRITES-1,0,-1 do
|
|
sprite[i].shade = 1
|
|
end
|
|
for i=0,gv.MAXSPRITES-1 do
|
|
sprite[i].xoffset = 0
|
|
end
|
|
for i=gv.MAXSPRITES-1,0,-1 do
|
|
sprite[i].yoffset = 1
|
|
end
|
|
end
|
|
t = gv.gethitickms()-t
|
|
printf("%d x four 0..MAXSPRITES-1 iterations took %.03f us per outer iteration", N, (1000*t)/N)
|
|
-- Results on x86:
|
|
-- N=1: 480-1000 us (too large variance)
|
|
-- N=10: 190-210 us * 10 = 1.9-2.1 ms
|
|
-- N=100: about 160 us * 100 = about 16 ms
|
|
|
|
-- Make the DUKECAR in E1L1 into a zombie actor (temporarily)
|
|
if (sprite[24].picnum==2491) then
|
|
sprite.changestat(24, gv.STAT_ZOMBIEACTOR)
|
|
end
|
|
|
|
checkfail("gameevent('GAME', function() print('qwe') end)",
|
|
"must be called from top level")
|
|
end
|
|
)
|
|
|
|
local geom = require "geom"
|
|
|
|
gameevent("LOADACTOR", function(i)
|
|
local spr = sprite[i]
|
|
if (i==614 and spr.picnum==930) then
|
|
-- "police line" ribbon in E1L1
|
|
-- clear the hitag so that it doesn't spawn as FALLER from premap
|
|
spr.hitag = 0
|
|
end
|
|
end)
|
|
|
|
gameactor(930, nil, 1, function(i) -- "police line" ribbon
|
|
local spr = sprite[i]
|
|
local r = math.random
|
|
local d = 20
|
|
-- NOTE: __add metamethod is called because of the RHS:
|
|
local v = spr + geom.vec3(r(-d,d), r(-d,d))
|
|
spr:setpos(v)
|
|
end)
|
|
|
|
local stat = require("stat")
|
|
local hs = stat.new()
|
|
|
|
local con = require("con")
|
|
local AC, MV = con.AC, con.MV
|
|
con.action("TROOPSTAND",0,1,5,1,1)
|
|
con.action("TROOPFLINTCH", 50, 1, 1, 1, 6)
|
|
con.move("SHRUNKVELS", 32)
|
|
con.ai("AITEMP", AC.TROOPFLINTCH, MV.SHRUNKVELS, 0) -- TODO: test
|
|
-- This should work as well. In fact, it's exactly the same, but I prefer the
|
|
-- above version for clarity. NOTE: we'll need to think whether it's OK to
|
|
-- redefine composites (moves/actions/ais) during gameplay (probably not).
|
|
-- Or will we allow only one definition per label ever?
|
|
con.ai("AITEMP", "TROOPFLINTCH", "SHRUNKVELS", 0)
|
|
|
|
local TROOPSTRENGTH = 30
|
|
|
|
local AF = actor.FLAGS
|
|
|
|
-- Also test actor code chaining: strength is doubled.
|
|
gameactor(1680, AF.chain_end+AF.enemy, 2*TROOPSTRENGTH, "TROOPSTAND", -- LIZTROOP
|
|
function(i, playeri, dist)
|
|
spriteext[i]:make_animated()
|
|
|
|
sprite[i].pal = math.random(32)
|
|
-- sprite[i].ang = bit.band(sprite[i].ang-20, 2047)
|
|
|
|
local spr = sprite[i]
|
|
|
|
local t = gv.gethitickms()
|
|
local hit = hitscan(spr, spr.sectnum, 10, 10, 0, gv.CLIPMASK0)
|
|
|
|
hs:add(1000*(gv.gethitickms()-t))
|
|
|
|
if (hs.n == 300) then
|
|
printf("hitscan: %s", hs:getstatstr())
|
|
hs:reset()
|
|
error("greetings from LIZTROOP actor")
|
|
end
|
|
|
|
if (dist < 4096) then
|
|
-- Duke Vader / Anakin Nukewalker?
|
|
actor[i]:set_action("TROOPFLINTCH")
|
|
actor[i]:set_move("SHRUNKVELS")
|
|
|
|
if (dist < 1024) then
|
|
con.killit()
|
|
end
|
|
end
|
|
end
|
|
)
|
|
|
|
gameevent("DISPLAYROOMS",
|
|
function()
|
|
local cam = gv.cam
|
|
cam.pos.z = cam.pos.z + 64*16*math.sin(gv.totalclock/30)
|
|
|
|
local ps = player[0]
|
|
if (ps.cursectnum >= 0) then
|
|
local hit = sector[ps.cursectnum]:zrangeat(cam.pos)
|
|
if (gv.totalclock%200==0) then
|
|
printf("hit %s %d at z=%d, %s %d at z=%d",
|
|
hit.c.spritep and "sprite" or "sector", hit.c.num, hit.c.z,
|
|
hit.f.spritep and "sprite" or "sector", hit.f.num, hit.f.z)
|
|
end
|
|
end
|
|
end
|
|
)
|
|
|
|
gameevent("DISPLAYREST", function()
|
|
for i=0,10 do
|
|
for j=1,100 do
|
|
-- XXX: This is slower in the Polymodes than with classic!
|
|
-- con._gametext(2822, j, i, 12, 0, 0, 16, 0,0,gv.xdim,gv.ydim,8192)
|
|
end
|
|
end
|
|
end)
|
|
|
|
local CS = sprite.CSTAT
|
|
|
|
gameevent("ANIMATESPRITES",
|
|
function(aci)
|
|
local tspr = atsprite[aci]
|
|
if (tspr:getspr().picnum==1680) then
|
|
local tspr2 = tspr:dup()
|
|
if (tspr2) then
|
|
tspr2.x = tspr2.x + 512*math.cos(gv.totalclock/60)
|
|
tspr2.y = tspr2.y + 512*math.sin(gv.totalclock/60)
|
|
tspr2:set_cstat_bits(CS.TRANSLUCENT_BOTH_BITS)
|
|
end
|
|
end
|
|
end)
|
|
|
|
printf("EVENT_INIT = %d", gv.EVENT_INIT) -- tests default defines
|
|
|
|
local bittest = require "bittest"
|
|
bittest.sieve()
|
|
|
|
require("test/test_geom")
|
|
require("test/test_rotspr")
|
|
|
|
do
|
|
-- Test ksin vs. sinb
|
|
local xmath = require "xmath"
|
|
local sum = 0
|
|
|
|
local N = 1000
|
|
local t = gv.gethitickms()
|
|
for i=0,N*2048-1 do
|
|
sum = sum+xmath.ksin(i)
|
|
end
|
|
t = gv.gethitickms()-t
|
|
sum = sum*1e12
|
|
printf("ksin: sum*1e12=%.03f, %.03fus per 0-2047 cycle", sum, t)
|
|
|
|
sum = 0
|
|
local t = gv.gethitickms()
|
|
for i=0,N*2048-1 do
|
|
sum = sum+xmath.sinb(i)
|
|
end
|
|
t = gv.gethitickms()-t
|
|
sum = sum*1e12
|
|
printf("sinb: sum*1e12=%.03f, %.03fus per 0-2047 cycle", sum, t)
|
|
|
|
-- Results (helixhorned x86):
|
|
-- ksin: sum*1e12=0.000, 3.801us per 0-2047 cycle
|
|
-- sinb: sum*1e12=0.052, 2.886us per 0-2047 cycle
|
|
end
|
|
|
|
print('---=== END TEST SCRIPT ===---')
|
|
|
|
--[[
|
|
function check_sector_idx()
|
|
error("bla")
|
|
end
|
|
spritesofsect(0)
|
|
--]]
|
|
|
|
--DBG_.oom()
|
|
|
|
-- This will complain about wrong usage of 'error'. In particular,
|
|
-- the nil must not propagate to C!
|
|
error(nil)
|